#include <string.h> #include <stdlib.h> #include <stdbool.h> #include <stdarg.h> #include <unistd.h> #define MINIMUM_EXTEND_BYTES 63 int extend_buf(char **buf, size_t *buf_len, size_t *buf_filled, size_t extend_len) { ssize_t space_left = *buf_len - *buf_filled - 1; size_t new_size, size_required, size_more_space; char *new_buf; if (space_left >= 0 && space_left >= extend_len) return 0; size_required = *buf_filled + extend_len + 1; size_more_space = size_required + MINIMUM_EXTEND_BYTES; new_size = *buf_len * 2; if (new_size < size_more_space) new_size = size_more_space; new_buf = realloc(*buf, new_size); if (!new_buf) new_buf = realloc(*buf, size_required); if (!new_buf) return -1; *buf = new_buf; *buf_len = new_size; return 0; } int sb_bytes(char **buf, size_t *buf_len, size_t *buf_filled, const unsigned char *bytes, size_t bytes_len) { if (extend_buf(buf, buf_len, buf_filled, bytes_len)) return -1; memcpy(*buf + *buf_filled, bytes, bytes_len); *(*buf + *buf_filled + bytes_len) = '\0'; *buf_filled += bytes_len; return 0; } int sb_string(char **buf, size_t *buf_len, size_t *buf_filled, const char *string) { size_t string_len = strlen(string); return sb_bytes(buf, buf_len, buf_filled, (const unsigned char*) string, string_len); } int sb_char(char **buf, size_t *buf_len, size_t *buf_filled, char c) { return sb_bytes(buf, buf_len, buf_filled, (const unsigned char*) &c, 1); } /* Below is old version */ /* inline static size_t process_fmt(MYSQL *mysql, const char *fmt, */ /* va_list ap, char *dst) */ /* { */ /* size_t len = 0; */ /* const char *in_pos = fmt; */ /* char *out_pos = dst, c; */ /* bool percent = false; */ /* short digits_count; */ /* long power_of_10; */ /* long num_arg; */ /* const char *string_arg; */ /* size_t string_len; */ /* #define WRITE_CHAR(ch) \ */ /* do { \ */ /* if (dst) \ */ /* *(out_pos++) = (ch); \ */ /* else \ */ /* len++; \ */ /* } \ */ /* while (0) \ */ /* while (*in_pos) { */ /* c = *(in_pos++); */ /* if (!percent) { */ /* if (c != '%') */ /* WRITE_CHAR(c); */ /* else */ /* percent = true; */ /* continue; */ /* } */ /* percent = false; */ /* switch (c) { */ /* case 'd': */ /* case 'u': */ /* if (c == 'd') */ /* num_arg = va_arg(ap, int); */ /* else */ /* num_arg = va_arg(ap, unsigned); */ /* if (num_arg < 0) { */ /* WRITE_CHAR('-'); */ /* num_arg = -num_arg; */ /* } */ /* for (digits_count = 1, power_of_10 = 10; */ /* power_of_10 <= num_arg; */ /* digits_count++, power_of_10 *= 10); */ /* power_of_10 /= 10; */ /* while (digits_count--) { */ /* WRITE_CHAR('0' + num_arg / power_of_10); */ /* num_arg = (num_arg % power_of_10) * 10; */ /* } */ /* break; */ /* case 's': */ /* for (string_arg = va_arg(ap, const char*); */ /* *string_arg; string_arg++) */ /* WRITE_CHAR(*string_arg); */ /* break; */ /* case 'm': */ /* string_arg = va_arg(ap, const char*); */ /* string_len = strlen(string_arg); */ /* if (!dst) { */ /* len += 2 * string_len; */ /* break; */ /* } */ /* out_pos += mysql_real_escape_string(mysql, out_pos, */ /* string_arg, */ /* string_len); */ /* break; */ /* case '%': */ /* WRITE_CHAR('%'); */ /* } */ /* } */ /* if (dst) { */ /* *out_pos = '\0'; */ /* return out_pos - dst; */ /* } */ /* return len; */ /* } */ /* int sb_sprintf(char **buf, size_t *buf_len, size_t *buf_filled, */ /* MYSQL *mysql, const char *fmt, ...) */ /* { */ /* size_t extend_len; */ /* va_list ap; */ /* va_start(ap, fmt); */ /* extend_len = process_fmt(NULL, fmt, ap, NULL); */ /* va_end(ap); */ /* if (extend_buf(buf, buf_len, buf_filled, extend_len)) */ /* return -1; */ /* va_start(ap, fmt); */ /* *buf_filled += process_fmt(mysql, fmt, ap, *buf + *buf_filled); */ /* va_end(ap); */ /* return 0; */ /* } */ int sb_num(char **buf, size_t *buf_len, size_t *buf_filled, long num) { unsigned char repr[3 * sizeof(long) + 1]; int i; bool neg = num < 0; for (i = sizeof(repr); num; num /= 10) repr[--i] = '0' + num % 10; if (i == sizeof(repr)) repr[--i] = '0'; else if (neg) repr[--i] = '-'; sb_bytes(buf, buf_len, buf_filled, repr + i, sizeof(repr) - i); return 0; } int sb_vsprintf(char **buf, size_t *buf_len, size_t *buf_filled, const char *fmt, va_list ap) { const unsigned char *in_pos = (const unsigned char*) fmt; char c; size_t i = 0; bool percent = false; long num_arg; int (*sb_cb)(char**, size_t*, size_t*, void*); while (in_pos[i]) { c = in_pos[i++]; if (!percent) { if (c == '%') { percent = true; if (sb_bytes(buf, buf_len, buf_filled, in_pos, i - 1)) return -1; } continue; } percent = false; in_pos += i; i = 0; switch (c) { case 'd': case 'u': num_arg = c == 'd' ? va_arg(ap, int) : va_arg(ap, unsigned); if (sb_num(buf, buf_len, buf_filled, num_arg)) return -1; break; case 's': if (sb_string(buf, buf_len, buf_filled, va_arg(ap, const char*))) return -1; break; case '_': sb_cb = va_arg(ap, int (*)(char**, size_t*, size_t*, void*)); if (sb_cb(buf, buf_len, buf_filled, va_arg(ap, void*))) return -1; break; case '%': in_pos--; i++; } } if (!percent && sb_bytes(buf, buf_len, buf_filled, in_pos, i)) return -1; return 0; } int sb_sprintf(char **buf, size_t *buf_len, size_t *buf_filled, const char *fmt, ...) { va_list ap; int res; va_start(ap, fmt); res = sb_vsprintf(buf, buf_len, buf_filled, fmt, ap); va_end(ap); return res; } int crop_buf(char **buf, size_t *buf_len, size_t *buf_filled) { char *new_buf; if (*buf_len <= *buf_filled + 1) return 0; new_buf = realloc(*buf, *buf_filled + 1); if (!new_buf) return -1; *buf = new_buf; *buf_len = *buf_filled + 1; return 0; }