fmt.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #include <u.h>
  2. #include <libc.h>
  3. #include "fmtdef.h"
  4. enum
  5. {
  6. Maxfmt = 64
  7. };
  8. typedef struct Convfmt Convfmt;
  9. struct Convfmt
  10. {
  11. int c;
  12. volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */
  13. };
  14. struct
  15. {
  16. /* lock by calling _fmtlock, _fmtunlock */
  17. int nfmt;
  18. Convfmt fmt[Maxfmt];
  19. } fmtalloc;
  20. static Convfmt knownfmt[] = {
  21. ' ', _flagfmt,
  22. '#', _flagfmt,
  23. '%', _percentfmt,
  24. '+', _flagfmt,
  25. ',', _flagfmt,
  26. '-', _flagfmt,
  27. 'C', _runefmt,
  28. 'E', _efgfmt,
  29. 'G', _efgfmt,
  30. 'S', _runesfmt,
  31. 'X', _ifmt,
  32. 'b', _ifmt,
  33. 'c', _charfmt,
  34. 'd', _ifmt,
  35. 'e', _efgfmt,
  36. 'f', _efgfmt,
  37. 'g', _efgfmt,
  38. 'h', _flagfmt,
  39. 'l', _flagfmt,
  40. 'n', _countfmt,
  41. 'o', _ifmt,
  42. 'p', _ifmt,
  43. 'r', errfmt,
  44. 's', _strfmt,
  45. 'u', _flagfmt,
  46. 'x', _ifmt,
  47. 0, nil,
  48. };
  49. int (*doquote)(int);
  50. /*
  51. * _fmtlock() must be set
  52. */
  53. static int
  54. _fmtinstall(int c, Fmts f)
  55. {
  56. Convfmt *p, *ep;
  57. if(c<=0 || c>=65536)
  58. return -1;
  59. if(!f)
  60. f = _badfmt;
  61. ep = &fmtalloc.fmt[fmtalloc.nfmt];
  62. for(p=fmtalloc.fmt; p<ep; p++)
  63. if(p->c == c)
  64. break;
  65. if(p == &fmtalloc.fmt[Maxfmt])
  66. return -1;
  67. p->fmt = f;
  68. if(p == ep){ /* installing a new format character */
  69. fmtalloc.nfmt++;
  70. p->c = c;
  71. }
  72. return 0;
  73. }
  74. int
  75. fmtinstall(int c, Fmts f)
  76. {
  77. int ret;
  78. _fmtlock();
  79. ret = _fmtinstall(c, f);
  80. _fmtunlock();
  81. return ret;
  82. }
  83. static Fmts
  84. fmtfmt(int c)
  85. {
  86. Convfmt *p, *ep;
  87. ep = &fmtalloc.fmt[fmtalloc.nfmt];
  88. for(p=fmtalloc.fmt; p<ep; p++)
  89. if(p->c == c){
  90. while(p->fmt == nil) /* loop until value is updated */
  91. ;
  92. return p->fmt;
  93. }
  94. /* is this a predefined format char? */
  95. _fmtlock();
  96. for(p=knownfmt; p->c; p++)
  97. if(p->c == c){
  98. _fmtinstall(p->c, p->fmt);
  99. _fmtunlock();
  100. return p->fmt;
  101. }
  102. _fmtunlock();
  103. return _badfmt;
  104. }
  105. void*
  106. _fmtdispatch(Fmt *f, void *fmt, int isrunes)
  107. {
  108. Rune rune, r;
  109. int i, n;
  110. f->flags = 0;
  111. f->width = f->prec = 0;
  112. for(;;){
  113. if(isrunes){
  114. r = *(Rune*)fmt;
  115. fmt = (Rune*)fmt + 1;
  116. }else{
  117. fmt = (char*)fmt + chartorune(&rune, fmt);
  118. r = rune;
  119. }
  120. f->r = r;
  121. switch(r){
  122. case '\0':
  123. return nil;
  124. case '.':
  125. f->flags |= FmtWidth|FmtPrec;
  126. continue;
  127. case '0':
  128. if(!(f->flags & FmtWidth)){
  129. f->flags |= FmtZero;
  130. continue;
  131. }
  132. /* fall through */
  133. case '1': case '2': case '3': case '4':
  134. case '5': case '6': case '7': case '8': case '9':
  135. i = 0;
  136. while(r >= '0' && r <= '9'){
  137. i = i * 10 + r - '0';
  138. if(isrunes){
  139. r = *(Rune*)fmt;
  140. fmt = (Rune*)fmt + 1;
  141. }else{
  142. r = *(char*)fmt;
  143. fmt = (char*)fmt + 1;
  144. }
  145. }
  146. if(isrunes)
  147. fmt = (Rune*)fmt - 1;
  148. else
  149. fmt = (char*)fmt - 1;
  150. numflag:
  151. if(f->flags & FmtWidth){
  152. f->flags |= FmtPrec;
  153. f->prec = i;
  154. }else{
  155. f->flags |= FmtWidth;
  156. f->width = i;
  157. }
  158. continue;
  159. case '*':
  160. i = va_arg(f->args, int);
  161. if(i < 0){
  162. i = -i;
  163. f->flags |= FmtLeft;
  164. }
  165. goto numflag;
  166. }
  167. n = (*fmtfmt(r))(f);
  168. if(n < 0)
  169. return nil;
  170. if(n == 0)
  171. return fmt;
  172. }
  173. }