A dynamic tracer for Linux

printxf.c 2.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. #include <stdarg.h>
  2. #include <stdint.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include "printxf.h"
  7. struct printxf printxf_default;
  8. /* allow domains an easy way to defer standard specifiers to the
  9. * system's implementation. */
  10. int printxf_vfprintf(struct printxf *pxf,
  11. FILE *fp, const char *spec, va_list ap)
  12. {
  13. return vfprintf(fp, spec, ap);
  14. }
  15. int __printxf_wsegment(FILE *fp, const char **fmt, size_t ssize, size_t *tsize)
  16. {
  17. size_t wsize;
  18. wsize = fwrite(*fmt, 1, ssize, fp);
  19. *tsize += wsize;
  20. *fmt += wsize;
  21. return (wsize < ssize) ? EOF : 0;
  22. }
  23. int vfprintxf(struct printxf *pxf, FILE *fp, const char *fmt, va_list ap)
  24. {
  25. size_t tsize = 0, wsize, ssize;
  26. vfprintxf_fn handler;
  27. char spec[16];
  28. pxf = pxf ? : &printxf_default;
  29. if (!fmt)
  30. return 0;
  31. while (*fmt) {
  32. ssize = strcspn(fmt, "%");
  33. /* leading segment containing no format specifiers. */
  34. if (ssize && __printxf_wsegment(fp, &fmt, ssize, &tsize))
  35. break;
  36. if (fmt[0] == '\0') {
  37. /* this was the last segment */
  38. break;
  39. } else if ((fmt[0] == '%')
  40. && ((fmt[1] == '\0') || (fmt[1] == '%'))) {
  41. /* "%" or "%%", write "%" */
  42. if (!fwrite("%", 1, 1, fp))
  43. break;
  44. tsize++;
  45. fmt += fmt[1] ? 2 : 1;
  46. continue;
  47. }
  48. ssize = strspn(fmt + 1, " #$'*+,-.0123456789:;L_hjlqtvz") + 1;
  49. if (!fmt[ssize]) {
  50. /* corner case. fmt ends with an unterminated
  51. * format. e.g. "evilness: 100%" */
  52. __printxf_wsegment(fp, &fmt, ssize, &tsize);
  53. break;
  54. }
  55. handler = pxf->vfprintxf[fmt[ssize] & 0x7f];
  56. if (!handler) {
  57. /* unsupported specifier, write the entire
  58. * specifier unformatted to the output */
  59. if (__printxf_wsegment(fp, &fmt, ssize + 1, &tsize))
  60. break;
  61. continue;
  62. }
  63. ssize++;
  64. memset(spec, '\0', sizeof(spec));
  65. strncpy(spec, fmt, (ssize >= sizeof(spec)) ? sizeof(spec) - 1 : ssize);
  66. fmt += ssize;
  67. tsize += handler(pxf, fp, spec, ap);
  68. }
  69. return tsize;
  70. }
  71. int fprintxf(struct printxf *pxf, FILE *fp, const char *fmt, ...)
  72. {
  73. va_list ap;
  74. int ret;
  75. va_start(ap, fmt);
  76. ret = vfprintxf(pxf, fp, fmt, ap);
  77. va_end(ap);
  78. return ret;
  79. }
  80. int vprintxf(struct printxf *pxf, const char *fmt, va_list ap)
  81. {
  82. return vfprintxf(pxf, stdout, fmt, ap);
  83. }
  84. int printxf(struct printxf *pxf, const char *fmt, ...)
  85. {
  86. va_list ap;
  87. int ret;
  88. va_start(ap, fmt);
  89. ret = vprintxf(pxf, fmt, ap);
  90. va_end(ap);
  91. return ret;
  92. }
  93. __attribute__((constructor))
  94. static void printxf_init(void)
  95. {
  96. const char *std = "aAcdeEfFgGiosuxX";
  97. for (; *std; std++)
  98. printxf_default.vfprintxf[(int)*std] = &printxf_vfprintf;
  99. }