/source3/lib/cbuf.c

https://gitlab.com/miztake/samba · C · 328 lines · 241 code · 58 blank · 29 comment · 40 complexity · c565173edd332e5afe286225bd138c98 MD5 · raw file

  1. /*
  2. * Samba Unix/Linux SMB client library
  3. *
  4. * Copyright (C) Gregor Beck 2010
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. /**
  20. * @file cbuf.c
  21. * @author Gregor Beck <gb@sernet.de>
  22. * @date Aug 2010
  23. *
  24. * @brief A talloced character buffer.
  25. *
  26. */
  27. #include "replace.h"
  28. #include "system/locale.h"
  29. #include "cbuf.h"
  30. #include <talloc.h>
  31. #include <assert.h>
  32. #include "lib/util/byteorder.h"
  33. struct cbuf {
  34. char* buf;
  35. size_t pos;
  36. size_t size;
  37. };
  38. cbuf* cbuf_clear(cbuf* b)
  39. {
  40. cbuf_setpos(b, 0);
  41. return b;
  42. }
  43. cbuf* cbuf_new(const void* ctx)
  44. {
  45. cbuf* s = talloc(ctx, cbuf);
  46. if (s == NULL)
  47. return NULL;
  48. s->size = 32;
  49. s->buf = (char *)talloc_size(s, s->size);
  50. if (s->size && (s->buf == NULL)) {
  51. talloc_free(s);
  52. return NULL;
  53. }
  54. return cbuf_clear(s);
  55. }
  56. cbuf* cbuf_copy(const cbuf* b)
  57. {
  58. cbuf* s = talloc(talloc_parent(b), cbuf);
  59. if (s == NULL) {
  60. return NULL;
  61. }
  62. s->buf = (char *)talloc_memdup(s, b->buf, b->size); /* only up to pos? */
  63. /* XXX shallow did not work, because realloc */
  64. /* fails with multiple references */
  65. /* s->buf = talloc_reference(s, b->buf); */
  66. if (s->buf == NULL) {
  67. cbuf_delete(s);
  68. return NULL;
  69. }
  70. s->size = b->size;
  71. s->pos = b->pos;
  72. return s;
  73. }
  74. void cbuf_delete(cbuf* b)
  75. {
  76. talloc_free(b);
  77. }
  78. #define SWAP(A,B,T) do { \
  79. T tmp = A; A = B; B = tmp; \
  80. } while(0)
  81. void cbuf_swap(cbuf* b1, cbuf* b2)
  82. {
  83. if (b1 == b2) {
  84. return;
  85. }
  86. talloc_reparent(b1, b2, b1->buf);
  87. talloc_reparent(b2, b1, b2->buf);
  88. SWAP(b1->buf, b2->buf, char*);
  89. SWAP(b1->pos, b2->pos, size_t);
  90. SWAP(b1->size, b2->size, size_t);
  91. }
  92. cbuf* cbuf_takeover(cbuf* b1, cbuf* b2)
  93. {
  94. talloc_reparent(b2, b1, b2->buf);
  95. b1->buf = b2->buf;
  96. b1->pos = b2->pos;
  97. b1->size = b2->size;
  98. cbuf_delete(b2);
  99. return b1;
  100. }
  101. cbuf* cbuf_swapptr(cbuf* b, char** ptr, size_t len)
  102. {
  103. void* p = talloc_parent(*ptr);
  104. SWAP(b->buf, *ptr, char*);
  105. talloc_steal(b, b->buf);
  106. talloc_steal(p, *ptr);
  107. b->size = talloc_get_size(b->buf);
  108. b->pos = (len == -1) ? strlen(b->buf) : len;
  109. assert(b->pos <= b->size);
  110. return b;
  111. }
  112. cbuf* cbuf_resize(cbuf* b, size_t size)
  113. {
  114. char* save_buf = b->buf;
  115. b->buf = talloc_realloc(b, b->buf, char, size);
  116. if (b->buf == NULL) {
  117. talloc_free(save_buf);
  118. b->size = 0;
  119. } else {
  120. b->size = size;
  121. }
  122. b->pos = MIN(b->pos, b->size);
  123. return b->buf ? b : NULL;
  124. }
  125. char* cbuf_reserve(cbuf* b, size_t len)
  126. {
  127. if(b->size < b->pos + len)
  128. cbuf_resize(b, MAX(2*b->size, b->pos + len));
  129. return b->buf ? b->buf + b->pos : NULL;
  130. }
  131. int cbuf_puts(cbuf* b, const char* str, size_t len)
  132. {
  133. char* dst;
  134. if (b == NULL)
  135. return 0;
  136. if (len == -1) {
  137. len=strlen(str);
  138. }
  139. dst = cbuf_reserve(b, len+1);
  140. if (dst == NULL)
  141. return -1;
  142. memcpy(dst, str, len);
  143. dst[len] = '\0'; /* just to ease debugging */
  144. b->pos += len;
  145. assert(b->pos < b->size);
  146. return len;
  147. }
  148. int cbuf_putc(cbuf* b, char c) {
  149. char* dst;
  150. if (b == NULL)
  151. return 0;
  152. dst = cbuf_reserve(b, 2);
  153. if (dst == NULL) {
  154. return -1;
  155. }
  156. dst[0] = c;
  157. dst[1] = '\0'; /* just to ease debugging */
  158. b->pos++;
  159. assert(b->pos < b->size);
  160. return 1;
  161. }
  162. int cbuf_putdw(cbuf* b, uint32_t u) {
  163. char* dst;
  164. static const size_t LEN = sizeof(uint32_t);
  165. if (b == NULL)
  166. return 0;
  167. dst = cbuf_reserve(b, LEN);
  168. if (dst == NULL) {
  169. return -1;
  170. }
  171. SIVAL(dst, 0, u);
  172. b->pos += LEN;
  173. assert(b->pos <= b->size); /* no NULL termination*/
  174. return LEN;
  175. }
  176. size_t cbuf_getpos(const cbuf* b) {
  177. assert(b->pos <= b->size);
  178. return b->pos;
  179. }
  180. void cbuf_setpos(cbuf* b, size_t pos) {
  181. assert(pos <= b->size);
  182. b->pos = pos;
  183. if (pos < b->size)
  184. b->buf[pos] = '\0'; /* just to ease debugging */
  185. }
  186. char* cbuf_gets(cbuf* b, size_t idx) {
  187. assert(idx <= b->pos);
  188. if (cbuf_reserve(b, 1) == NULL)
  189. return NULL;
  190. b->buf[b->pos] = '\0';
  191. return b->buf + idx;
  192. }
  193. int cbuf_printf(cbuf* b, const char* fmt, ...)
  194. {
  195. va_list args, args2;
  196. int len;
  197. char* dst = b->buf + b->pos;
  198. const int avail = b->size - b->pos;
  199. assert(avail >= 0);
  200. va_start(args, fmt);
  201. va_copy(args2, args);
  202. len = vsnprintf(dst, avail, fmt, args);
  203. if (len >= avail) {
  204. dst = cbuf_reserve(b, len+1);
  205. len = (dst != NULL) ? vsnprintf(dst, len+1, fmt, args2) : -1;
  206. }
  207. if (len > 0) {
  208. b->pos += len;
  209. }
  210. va_end(args);
  211. va_end(args2);
  212. assert(b->pos <= b->size);
  213. return len;
  214. }
  215. int cbuf_print_quoted_string(cbuf* ost, const char* s)
  216. {
  217. int n = 1;
  218. cbuf_putc(ost,'"');
  219. while(true) {
  220. switch (*s) {
  221. case '\0':
  222. cbuf_putc(ost, '"');
  223. return n+1;
  224. case '"':
  225. case '\\':
  226. cbuf_putc(ost, '\\');
  227. n++;
  228. FALL_THROUGH;
  229. default:
  230. cbuf_putc(ost, *s);
  231. n++;
  232. }
  233. s++;
  234. }
  235. }
  236. int cbuf_print_quoted(cbuf* ost, const char* s, size_t len)
  237. {
  238. int n = 1;
  239. int ret;
  240. cbuf_reserve(ost, len+2);
  241. cbuf_putc(ost,'"');
  242. while(len--) {
  243. switch (*s) {
  244. case '"':
  245. case '\\':
  246. ret = cbuf_printf(ost, "\\%c", *s);
  247. break;
  248. default:
  249. if (isprint(*s) && ((*s == ' ') || !isspace(*s))) {
  250. ret = cbuf_putc(ost, *s);
  251. } else {
  252. ret = cbuf_printf(ost,
  253. "\\%02x",
  254. (unsigned char)*s);
  255. }
  256. }
  257. s++;
  258. if (ret == -1) {
  259. return -1;
  260. }
  261. n += ret;
  262. }
  263. ret = cbuf_putc(ost,'"');
  264. return (ret == -1) ? -1 : (n + ret);
  265. }