strbuf.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. #include "cache.h"
  2. #include <linux/kernel.h>
  3. int prefixcmp(const char *str, const char *prefix)
  4. {
  5. for (; ; str++, prefix++)
  6. if (!*prefix)
  7. return 0;
  8. else if (*str != *prefix)
  9. return (unsigned char)*prefix - (unsigned char)*str;
  10. }
  11. /*
  12. * Used as the default ->buf value, so that people can always assume
  13. * buf is non NULL and ->buf is NUL terminated even for a freshly
  14. * initialized strbuf.
  15. */
  16. char strbuf_slopbuf[1];
  17. void strbuf_init(struct strbuf *sb, ssize_t hint)
  18. {
  19. sb->alloc = sb->len = 0;
  20. sb->buf = strbuf_slopbuf;
  21. if (hint)
  22. strbuf_grow(sb, hint);
  23. }
  24. void strbuf_release(struct strbuf *sb)
  25. {
  26. if (sb->alloc) {
  27. zfree(&sb->buf);
  28. strbuf_init(sb, 0);
  29. }
  30. }
  31. char *strbuf_detach(struct strbuf *sb, size_t *sz)
  32. {
  33. char *res = sb->alloc ? sb->buf : NULL;
  34. if (sz)
  35. *sz = sb->len;
  36. strbuf_init(sb, 0);
  37. return res;
  38. }
  39. void strbuf_grow(struct strbuf *sb, size_t extra)
  40. {
  41. if (sb->len + extra + 1 <= sb->len)
  42. die("you want to use way too much memory");
  43. if (!sb->alloc)
  44. sb->buf = NULL;
  45. ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
  46. }
  47. static void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
  48. const void *data, size_t dlen)
  49. {
  50. if (pos + len < pos)
  51. die("you want to use way too much memory");
  52. if (pos > sb->len)
  53. die("`pos' is too far after the end of the buffer");
  54. if (pos + len > sb->len)
  55. die("`pos + len' is too far after the end of the buffer");
  56. if (dlen >= len)
  57. strbuf_grow(sb, dlen - len);
  58. memmove(sb->buf + pos + dlen,
  59. sb->buf + pos + len,
  60. sb->len - pos - len);
  61. memcpy(sb->buf + pos, data, dlen);
  62. strbuf_setlen(sb, sb->len + dlen - len);
  63. }
  64. void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
  65. {
  66. strbuf_splice(sb, pos, len, NULL, 0);
  67. }
  68. void strbuf_add(struct strbuf *sb, const void *data, size_t len)
  69. {
  70. strbuf_grow(sb, len);
  71. memcpy(sb->buf + sb->len, data, len);
  72. strbuf_setlen(sb, sb->len + len);
  73. }
  74. void strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap)
  75. {
  76. int len;
  77. va_list ap_saved;
  78. if (!strbuf_avail(sb))
  79. strbuf_grow(sb, 64);
  80. va_copy(ap_saved, ap);
  81. len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
  82. if (len < 0)
  83. die("your vsnprintf is broken");
  84. if (len > strbuf_avail(sb)) {
  85. strbuf_grow(sb, len);
  86. len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved);
  87. va_end(ap_saved);
  88. if (len > strbuf_avail(sb)) {
  89. die("this should not happen, your vsnprintf is broken");
  90. }
  91. }
  92. strbuf_setlen(sb, sb->len + len);
  93. }
  94. void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
  95. {
  96. va_list ap;
  97. va_start(ap, fmt);
  98. strbuf_addv(sb, fmt, ap);
  99. va_end(ap);
  100. }
  101. ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
  102. {
  103. size_t oldlen = sb->len;
  104. size_t oldalloc = sb->alloc;
  105. strbuf_grow(sb, hint ? hint : 8192);
  106. for (;;) {
  107. ssize_t cnt;
  108. cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
  109. if (cnt < 0) {
  110. if (oldalloc == 0)
  111. strbuf_release(sb);
  112. else
  113. strbuf_setlen(sb, oldlen);
  114. return -1;
  115. }
  116. if (!cnt)
  117. break;
  118. sb->len += cnt;
  119. strbuf_grow(sb, 8192);
  120. }
  121. sb->buf[sb->len] = '\0';
  122. return sb->len - oldlen;
  123. }