aboutsummaryrefslogtreecommitdiff
path: root/src/fmt.cff
blob: 885ea5048638e11570c134a87e3e97aeccbaaefd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import "all.hff";

extern fn vpfmt(proc *fn(u8, *void) void, parg *void, fmt *const u8, ap va_list) void {
   defmacro p(x) [ proc(x, parg) ]
   defmacro ps(s) [
      for let $i = 0; (s)[$i] != 0; ++$i {
         p(s[$i]);
      }
   ]
   let buf [100]u8 = {};
   for let c u8 = *fmt; c != 0; c = *++fmt {
      assert(c != 0, "?");
      if c != '%' {
         p(c);
         if fmt[1] == 0 { break; }
         continue;      
      }
      let quote = #f;
      #'fmt do {
         switch (c = *++fmt) {
         case 'i';
            sprintf(buf, "%d", ap->arg(int));
            ps(buf);
         case 'q';
            quote = #t;
            continue #'fmt;
         case 'c';
            let ch u32 = ap->arg(int);
            if quote {
               extern fn isprint(int) int;
               p('\'');
               for ch = bswap32(ch); ch != 0; ch >>= 8 {
                  if ch & 0xFF != 0 {
                     if isprint(ch) != 0 { p(ch); }
                     else {
                        p('\\');
                        p('0' + (ch % 8));
                        p('0' + ((ch / 8) % 8));
                        p('0' + ((ch / 8 / 8) % 8));
                     }
                  }
               }
               p('\'');
            } else {
               if ch == 0 { p(0); }
               else {
                  for ch = bswap32(ch); ch != 0; ch >>= 8 {
                     if ch & 0xFF != 0 {
                        p(ch & 0xFF);
                     }
                  }
               }
            }
         case 's';
            let s = ap->arg(*const u8);
            if quote {
               extern fn isprint(int) int;
               p('\"');
               for let c u8 #?; (c = *s++) != 0; {
                  if isprint(c) != 0 {
                     p(c);
                  } else {
                     p('\\');
                     p('0' + (c % 8));
                     p('0' + ((c / 8) % 8));
                     p('0' + ((c / 8 / 8) % 8));
                  }
               }
               p('\"');
            } else {
               ps(s);
            }
         case else
            // assert(#f, "bad fmt '%c' @ %d", c, i);
         }
      } while #f;
   }
}

extern fn vefmt(fmt *const u8, ap va_list) void {
   fn epri(c u8, *void) void {
      fputc(c, stderr);
   }

   vpfmt(&epri, #null, fmt, ap);
}

extern fn efmt(fmt *const u8, ...) void {
   let ap va_list #?;
   ap->start(fmt);

   vefmt(fmt, ap);
   ap->end();
}