Coverage Report

Created: 2026-10-28 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/plan9port/src/lib9/fmt/dofmt.c
Line
Count
Source
1
/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
2
/* Copyright (c) 2004 Google Inc.; see LICENSE */
3
4
#include <stdarg.h>
5
#include <string.h>
6
#include "plan9.h"
7
#include "fmt.h"
8
#include "fmtdef.h"
9
10
/* format the output into f->to and return the number of characters fmted  */
11
int
12
dofmt(Fmt *f, char *fmt)
13
39.2k
{
14
39.2k
  Rune rune, *rt, *rs;
15
39.2k
  int r;
16
39.2k
  char *t, *s;
17
39.2k
  int n, nfmt;
18
19
39.2k
  nfmt = f->nfmt;
20
63.4k
  for(;;){
21
63.4k
    if(f->runes){
22
0
      rt = (Rune*)f->to;
23
0
      rs = (Rune*)f->stop;
24
0
      while((r = *(uchar*)fmt) && r != '%'){
25
0
        if(r < Runeself)
26
0
          fmt++;
27
0
        else{
28
0
          fmt += chartorune(&rune, fmt);
29
0
          r = rune;
30
0
        }
31
0
        FMTRCHAR(f, rt, rs, r);
32
0
      }
33
0
      fmt++;
34
0
      f->nfmt += rt - (Rune *)f->to;
35
0
      f->to = rt;
36
0
      if(!r)
37
0
        return f->nfmt - nfmt;
38
0
      f->stop = rs;
39
63.4k
    }else{
40
63.4k
      t = (char*)f->to;
41
63.4k
      s = (char*)f->stop;
42
194k
      while((r = *(uchar*)fmt) && r != '%'){
43
131k
        if(r < Runeself){
44
131k
          FMTCHAR(f, t, s, r);
45
131k
          fmt++;
46
131k
        }else{
47
0
          n = chartorune(&rune, fmt);
48
0
          if(t + n > s){
49
0
            t = (char*)__fmtflush(f, t, n);
50
0
            if(t != nil)
51
0
              s = (char*)f->stop;
52
0
            else
53
0
              return -1;
54
0
          }
55
0
          while(n--)
56
0
            *t++ = *fmt++;
57
0
        }
58
131k
      }
59
63.4k
      fmt++;
60
63.4k
      f->nfmt += t - (char *)f->to;
61
63.4k
      f->to = t;
62
63.4k
      if(!r)
63
39.2k
        return f->nfmt - nfmt;
64
24.1k
      f->stop = s;
65
24.1k
    }
66
67
24.1k
    fmt = (char*)__fmtdispatch(f, fmt, 0);
68
24.1k
    if(fmt == nil)
69
0
      return -1;
70
24.1k
  }
71
39.2k
}
72
73
void *
74
__fmtflush(Fmt *f, void *t, int len)
75
5.82k
{
76
5.82k
  if(f->runes)
77
0
    f->nfmt += (Rune*)t - (Rune*)f->to;
78
5.82k
  else
79
5.82k
    f->nfmt += (char*)t - (char *)f->to;
80
5.82k
  f->to = t;
81
5.82k
  if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
82
0
    f->stop = f->to;
83
0
    return nil;
84
0
  }
85
5.82k
  return f->to;
86
5.82k
}
87
88
/*
89
 * put a formatted block of memory sz bytes long of n runes into the output buffer,
90
 * left/right justified in a field of at least f->width characters (if FmtWidth is set)
91
 */
92
int
93
__fmtpad(Fmt *f, int n)
94
24.1k
{
95
24.1k
  char *t, *s;
96
24.1k
  int i;
97
98
24.1k
  t = (char*)f->to;
99
24.1k
  s = (char*)f->stop;
100
24.1k
  for(i = 0; i < n; i++)
101
0
    FMTCHAR(f, t, s, ' ');
102
24.1k
  f->nfmt += t - (char *)f->to;
103
24.1k
  f->to = t;
104
24.1k
  return 0;
105
24.1k
}
106
107
int
108
__rfmtpad(Fmt *f, int n)
109
0
{
110
0
  Rune *t, *s;
111
0
  int i;
112
113
0
  t = (Rune*)f->to;
114
0
  s = (Rune*)f->stop;
115
0
  for(i = 0; i < n; i++)
116
0
    FMTRCHAR(f, t, s, ' ');
117
0
  f->nfmt += t - (Rune *)f->to;
118
0
  f->to = t;
119
0
  return 0;
120
0
}
121
122
int
123
__fmtcpy(Fmt *f, const void *vm, int n, int sz)
124
24.1k
{
125
24.1k
  Rune *rt, *rs, r;
126
24.1k
  char *t, *s, *m, *me;
127
24.1k
  ulong fl;
128
24.1k
  int nc, w;
129
130
24.1k
  m = (char*)vm;
131
24.1k
  me = m + sz;
132
24.1k
  fl = f->flags;
133
24.1k
  w = 0;
134
24.1k
  if(fl & FmtWidth)
135
2.41k
    w = f->width;
136
24.1k
  if((fl & FmtPrec) && n > f->prec)
137
0
    n = f->prec;
138
24.1k
  if(f->runes){
139
0
    if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
140
0
      return -1;
141
0
    rt = (Rune*)f->to;
142
0
    rs = (Rune*)f->stop;
143
0
    for(nc = n; nc > 0; nc--){
144
0
      r = *(uchar*)m;
145
0
      if(r < Runeself)
146
0
        m++;
147
0
      else if((me - m) >= UTFmax || fullrune(m, me-m))
148
0
        m += chartorune(&r, m);
149
0
      else
150
0
        break;
151
0
      FMTRCHAR(f, rt, rs, r);
152
0
    }
153
0
    f->nfmt += rt - (Rune *)f->to;
154
0
    f->to = rt;
155
0
    if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
156
0
      return -1;
157
24.1k
  }else{
158
24.1k
    if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
159
0
      return -1;
160
24.1k
    t = (char*)f->to;
161
24.1k
    s = (char*)f->stop;
162
843k
    for(nc = n; nc > 0; nc--){
163
819k
      r = *(uchar*)m;
164
819k
      if(r < Runeself)
165
410k
        m++;
166
409k
      else if((me - m) >= UTFmax || fullrune(m, me-m))
167
409k
        m += chartorune(&r, m);
168
317
      else
169
317
        break;
170
819k
      FMTRUNE(f, t, s, r);
171
819k
    }
172
24.1k
    f->nfmt += t - (char *)f->to;
173
24.1k
    f->to = t;
174
24.1k
    if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
175
0
      return -1;
176
24.1k
  }
177
24.1k
  return 0;
178
24.1k
}
179
180
int
181
__fmtrcpy(Fmt *f, const void *vm, int n)
182
0
{
183
0
  Rune r, *m, *me, *rt, *rs;
184
0
  char *t, *s;
185
0
  ulong fl;
186
0
  int w;
187
188
0
  m = (Rune*)vm;
189
0
  fl = f->flags;
190
0
  w = 0;
191
0
  if(fl & FmtWidth)
192
0
    w = f->width;
193
0
  if((fl & FmtPrec) && n > f->prec)
194
0
    n = f->prec;
195
0
  if(f->runes){
196
0
    if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
197
0
      return -1;
198
0
    rt = (Rune*)f->to;
199
0
    rs = (Rune*)f->stop;
200
0
    for(me = m + n; m < me; m++)
201
0
      FMTRCHAR(f, rt, rs, *m);
202
0
    f->nfmt += rt - (Rune *)f->to;
203
0
    f->to = rt;
204
0
    if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
205
0
      return -1;
206
0
  }else{
207
0
    if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
208
0
      return -1;
209
0
    t = (char*)f->to;
210
0
    s = (char*)f->stop;
211
0
    for(me = m + n; m < me; m++){
212
0
      r = *m;
213
0
      FMTRUNE(f, t, s, r);
214
0
    }
215
0
    f->nfmt += t - (char *)f->to;
216
0
    f->to = t;
217
0
    if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
218
0
      return -1;
219
0
  }
220
0
  return 0;
221
0
}
222
223
/* fmt out one character */
224
int
225
__charfmt(Fmt *f)
226
0
{
227
0
  char x[1];
228
229
0
  x[0] = va_arg(f->args, int);
230
0
  f->prec = 1;
231
0
  return __fmtcpy(f, (const char*)x, 1, 1);
232
0
}
233
234
/* fmt out one rune */
235
int
236
__runefmt(Fmt *f)
237
0
{
238
0
  Rune x[1];
239
240
0
  x[0] = va_arg(f->args, int);
241
0
  return __fmtrcpy(f, (const void*)x, 1);
242
0
}
243
244
/* public helper routine: fmt out a null terminated string already in hand */
245
int
246
fmtstrcpy(Fmt *f, char *s)
247
12.1k
{
248
12.1k
  int i, j;
249
250
12.1k
  if(!s)
251
0
    return __fmtcpy(f, "<nil>", 5, 5);
252
  /* if precision is specified, make sure we don't wander off the end */
253
12.1k
  if(f->flags & FmtPrec){
254
0
#ifdef PLAN9PORT
255
0
    Rune r;
256
0
    i = 0;
257
0
    for(j=0; j<f->prec && s[i]; j++)
258
0
      i += chartorune(&r, s+i);
259
#else
260
    /* ANSI requires precision in bytes, not Runes */
261
    for(i=0; i<f->prec; i++)
262
      if(s[i] == 0)
263
        break;
264
    j = utfnlen(s, i);  /* won't print partial at end */
265
#endif
266
0
    return __fmtcpy(f, s, j, i);
267
0
  }
268
12.1k
  return __fmtcpy(f, s, utflen(s), strlen(s));
269
12.1k
}
270
271
/* fmt out a null terminated utf string */
272
int
273
__strfmt(Fmt *f)
274
12.1k
{
275
12.1k
  char *s;
276
277
12.1k
  s = va_arg(f->args, char *);
278
12.1k
  return fmtstrcpy(f, s);
279
12.1k
}
280
281
/* public helper routine: fmt out a null terminated rune string already in hand */
282
int
283
fmtrunestrcpy(Fmt *f, Rune *s)
284
0
{
285
0
  Rune *e;
286
0
  int n, p;
287
288
0
  if(!s)
289
0
    return __fmtcpy(f, "<nil>", 5, 5);
290
  /* if precision is specified, make sure we don't wander off the end */
291
0
  if(f->flags & FmtPrec){
292
0
    p = f->prec;
293
0
    for(n = 0; n < p; n++)
294
0
      if(s[n] == 0)
295
0
        break;
296
0
  }else{
297
0
    for(e = s; *e; e++)
298
0
      ;
299
0
    n = e - s;
300
0
  }
301
0
  return __fmtrcpy(f, s, n);
302
0
}
303
304
/* fmt out a null terminated rune string */
305
int
306
__runesfmt(Fmt *f)
307
0
{
308
0
  Rune *s;
309
310
0
  s = va_arg(f->args, Rune *);
311
0
  return fmtrunestrcpy(f, s);
312
0
}
313
314
/* fmt a % */
315
int
316
__percentfmt(Fmt *f)
317
0
{
318
0
  Rune x[1];
319
320
0
  x[0] = f->r;
321
0
  f->prec = 1;
322
0
  return __fmtrcpy(f, (const void*)x, 1);
323
0
}
324
325
/* fmt an integer */
326
int
327
__ifmt(Fmt *f)
328
11.9k
{
329
11.9k
  char buf[140], *p, *conv;
330
  /* 140: for 64 bits of binary + 3-byte sep every 4 digits */
331
11.9k
  uvlong vu;
332
11.9k
  ulong u;
333
11.9k
  int neg, base, i, n, fl, w, isv;
334
11.9k
  int ndig, len, excess, bytelen;
335
11.9k
  char *grouping;
336
11.9k
  char *thousands;
337
338
11.9k
  neg = 0;
339
11.9k
  fl = f->flags;
340
11.9k
  isv = 0;
341
11.9k
  vu = 0;
342
11.9k
  u = 0;
343
#ifndef PLAN9PORT
344
  /*
345
   * Unsigned verbs for ANSI C
346
   */
347
  switch(f->r){
348
  case 'o':
349
  case 'p':
350
  case 'u':
351
  case 'x':
352
  case 'X':
353
    fl |= FmtUnsigned;
354
    fl &= ~(FmtSign|FmtSpace);
355
    break;
356
  }
357
#endif
358
11.9k
  if(f->r == 'p'){
359
0
    u = (ulong)va_arg(f->args, void*);
360
0
    f->r = 'x';
361
0
    fl |= FmtUnsigned;
362
11.9k
  }else if(fl & FmtVLong){
363
0
    isv = 1;
364
0
    if(fl & FmtUnsigned)
365
0
      vu = va_arg(f->args, uvlong);
366
0
    else
367
0
      vu = va_arg(f->args, vlong);
368
11.9k
  }else if(fl & FmtLong){
369
0
    if(fl & FmtUnsigned)
370
0
      u = va_arg(f->args, ulong);
371
0
    else
372
0
      u = va_arg(f->args, long);
373
11.9k
  }else if(fl & FmtByte){
374
0
    if(fl & FmtUnsigned)
375
0
      u = (uchar)va_arg(f->args, int);
376
0
    else
377
0
      u = (char)va_arg(f->args, int);
378
11.9k
  }else if(fl & FmtShort){
379
0
    if(fl & FmtUnsigned)
380
0
      u = (ushort)va_arg(f->args, int);
381
0
    else
382
0
      u = (short)va_arg(f->args, int);
383
11.9k
  }else{
384
11.9k
    if(fl & FmtUnsigned)
385
0
      u = va_arg(f->args, uint);
386
11.9k
    else
387
11.9k
      u = va_arg(f->args, int);
388
11.9k
  }
389
11.9k
  conv = "0123456789abcdef";
390
11.9k
  grouping = "\4";  /* for hex, octal etc. (undefined by spec but nice) */
391
11.9k
  thousands = f->thousands;
392
11.9k
  switch(f->r){
393
9.57k
  case 'd':
394
9.57k
  case 'i':
395
9.57k
  case 'u':
396
9.57k
    base = 10;
397
9.57k
    grouping = f->grouping;
398
9.57k
    break;
399
0
  case 'X':
400
0
    conv = "0123456789ABCDEF";
401
    /* fall through */
402
2.41k
  case 'x':
403
2.41k
    base = 16;
404
2.41k
    thousands = ":";
405
2.41k
    break;
406
0
  case 'b':
407
0
    base = 2;
408
0
    thousands = ":";
409
0
    break;
410
0
  case 'o':
411
0
    base = 8;
412
0
    break;
413
0
  default:
414
0
    return -1;
415
11.9k
  }
416
11.9k
  if(!(fl & FmtUnsigned)){
417
11.9k
    if(isv && (vlong)vu < 0){
418
0
      vu = -(vlong)vu;
419
0
      neg = 1;
420
11.9k
    }else if(!isv && (long)u < 0){
421
145
      u = -(long)u;
422
145
      neg = 1;
423
145
    }
424
11.9k
  }
425
11.9k
  p = buf + sizeof buf - 1;
426
11.9k
  n = 0;  /* in runes */
427
11.9k
  excess = 0; /* number of bytes > number runes */
428
11.9k
  ndig = 0;
429
11.9k
  len = utflen(thousands);
430
11.9k
  bytelen = strlen(thousands);
431
11.9k
  if(isv){
432
0
    while(vu){
433
0
      i = vu % base;
434
0
      vu /= base;
435
0
      if((fl & FmtComma) && n % 4 == 3){
436
0
        *p-- = ',';
437
0
        n++;
438
0
      }
439
0
      if((fl & FmtApost) && __needsep(&ndig, &grouping)){
440
0
        n += len;
441
0
        excess += bytelen - len;
442
0
        p -= bytelen;
443
0
        memmove(p+1, thousands, bytelen);
444
0
      }
445
0
      *p-- = conv[i];
446
0
      n++;
447
0
    }
448
11.9k
  }else{
449
31.3k
    while(u){
450
19.3k
      i = u % base;
451
19.3k
      u /= base;
452
19.3k
      if((fl & FmtComma) && n % 4 == 3){
453
0
        *p-- = ',';
454
0
        n++;
455
0
      }
456
19.3k
      if((fl & FmtApost) && __needsep(&ndig, &grouping)){
457
0
        n += len;
458
0
        excess += bytelen - len;
459
0
        p -= bytelen;
460
0
        memmove(p+1, thousands, bytelen);
461
0
      }
462
19.3k
      *p-- = conv[i];
463
19.3k
      n++;
464
19.3k
    }
465
11.9k
  }
466
11.9k
  if(n == 0){
467
    /*
468
     * "The result of converting a zero value with
469
     * a precision of zero is no characters."  - ANSI
470
     *
471
     * "For o conversion, # increases the precision, if and only if
472
     * necessary, to force the first digit of the result to be a zero
473
     * (if the value and precision are both 0, a single 0 is printed)." - ANSI
474
     */
475
1.13k
    if(!(fl & FmtPrec) || f->prec != 0 || (f->r == 'o' && (fl & FmtSharp))){
476
1.13k
      *p-- = '0';
477
1.13k
      n = 1;
478
1.13k
      if(fl & FmtApost)
479
0
        __needsep(&ndig, &grouping);
480
1.13k
    }
481
482
    /*
483
     * Zero values don't get 0x.
484
     */
485
1.13k
    if(f->r == 'x' || f->r == 'X')
486
118
      fl &= ~FmtSharp;
487
1.13k
  }
488
12.7k
  for(w = f->prec; n < w && p > buf+3; n++){
489
793
    if((fl & FmtApost) && __needsep(&ndig, &grouping)){
490
0
      n += len;
491
0
      excess += bytelen - len;
492
0
      p -= bytelen;
493
0
      memmove(p+1, thousands, bytelen);
494
0
    }
495
793
    *p-- = '0';
496
793
  }
497
11.9k
  if(neg || (fl & (FmtSign|FmtSpace)))
498
145
    n++;
499
11.9k
  if(fl & FmtSharp){
500
0
    if(base == 16)
501
0
      n += 2;
502
0
    else if(base == 8){
503
0
      if(p[1] == '0')
504
0
        fl &= ~FmtSharp;
505
0
      else
506
0
        n++;
507
0
    }
508
0
  }
509
11.9k
  if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
510
0
    w = 0;
511
0
    if(fl & FmtWidth)
512
0
      w = f->width;
513
0
    for(; n < w && p > buf+3; n++){
514
0
      if((fl & FmtApost) && __needsep(&ndig, &grouping)){
515
0
        n += len;
516
0
        excess += bytelen - len;
517
0
        p -= bytelen;
518
0
        memmove(p+1, thousands, bytelen);
519
0
      }
520
0
      *p-- = '0';
521
0
    }
522
0
    f->flags &= ~FmtWidth;
523
0
  }
524
11.9k
  if(fl & FmtSharp){
525
0
    if(base == 16)
526
0
      *p-- = f->r;
527
0
    if(base == 16 || base == 8)
528
0
      *p-- = '0';
529
0
  }
530
11.9k
  if(neg)
531
145
    *p-- = '-';
532
11.8k
  else if(fl & FmtSign)
533
0
    *p-- = '+';
534
11.8k
  else if(fl & FmtSpace)
535
0
    *p-- = ' ';
536
11.9k
  f->flags &= ~FmtPrec;
537
11.9k
  return __fmtcpy(f, p + 1, n, n + excess);
538
11.9k
}
539
540
int
541
__countfmt(Fmt *f)
542
0
{
543
0
  void *p;
544
0
  ulong fl;
545
546
0
  fl = f->flags;
547
0
  p = va_arg(f->args, void*);
548
0
  if(fl & FmtVLong){
549
0
    *(vlong*)p = f->nfmt;
550
0
  }else if(fl & FmtLong){
551
0
    *(long*)p = f->nfmt;
552
0
  }else if(fl & FmtByte){
553
0
    *(char*)p = f->nfmt;
554
0
  }else if(fl & FmtShort){
555
0
    *(short*)p = f->nfmt;
556
0
  }else{
557
0
    *(int*)p = f->nfmt;
558
0
  }
559
0
  return 0;
560
0
}
561
562
int
563
__flagfmt(Fmt *f)
564
0
{
565
0
  switch(f->r){
566
0
  case ',':
567
0
    f->flags |= FmtComma;
568
0
    break;
569
0
  case '-':
570
0
    f->flags |= FmtLeft;
571
0
    break;
572
0
  case '+':
573
0
    f->flags |= FmtSign;
574
0
    break;
575
0
  case '#':
576
0
    f->flags |= FmtSharp;
577
0
    break;
578
0
  case '\'':
579
0
    f->flags |= FmtApost;
580
0
    break;
581
0
  case ' ':
582
0
    f->flags |= FmtSpace;
583
0
    break;
584
0
  case 'u':
585
0
    f->flags |= FmtUnsigned;
586
0
    break;
587
0
  case 'h':
588
0
    if(f->flags & FmtShort)
589
0
      f->flags |= FmtByte;
590
0
    f->flags |= FmtShort;
591
0
    break;
592
0
  case 'L':
593
0
    f->flags |= FmtLDouble;
594
0
    break;
595
0
  case 'l':
596
0
    if(f->flags & FmtLong)
597
0
      f->flags |= FmtVLong;
598
0
    f->flags |= FmtLong;
599
0
    break;
600
0
  }
601
0
  return 1;
602
0
}
603
604
/* default error format */
605
int
606
__badfmt(Fmt *f)
607
0
{
608
0
  char x[2+UTFmax];
609
0
  int n;
610
611
0
  x[0] = '%';
612
0
  n = 1 + runetochar(x+1, &f->r);
613
0
  x[n++] = '%';
614
0
  f->prec = n;
615
0
  __fmtcpy(f, (const void*)x, n, n);
616
0
  return 0;
617
0
}