123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650 |
- /*
- * This file is part of the zlog Library.
- *
- * Copyright (C) 2011 by Hardy Simpson <HardySimpson1984@gmail.com>
- *
- * Licensed under the LGPL v2.1, see the file COPYING in base directory.
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <pthread.h>
- #include <errno.h>
- #include <stdint.h>
- #include "zc_defs.h"
- #include "buf.h"
- /*******************************************************************************/
- /* Author's Note
- * This buf.c is base on C99, that is, if buffer size is not enough,
- * the return value of vsnprintf(3) is a number tell how many character should
- * be output. vsnprintf in glibc 2.1 conforms to C99 , but glibc 2.0 doesn't.
- * see manpage of vsnprintf(3) on you platform for more detail.
- * So, what should you do if you want to using zlog on the platform that doesn't
- * conform C99? My Answer is, crack zlog with a portable C99-vsnprintf, like this
- * http://sourceforge.net/projects/ctrio/
- * http://www.jhweiss.de/software/snprintf.html
- * If you can see this note, you can fix it yourself? Aren't you? ^_^
- * Oh, I put the snprintf in C99 standard here,
- * vsnprintf is the same on return value.
- 7.19.6.5 The snprintf function
- Synopsis
- [#1]
- #include <stdio.h>
- int snprintf(char * restrict s, size_t n,
- const char * restrict format, ...);
- Description
- [#2] The snprintf function is equivalent to fprintf, except
- that the output is written into an array (specified by
- argument s) rather than to a stream. If n is zero, nothing
- is written, and s may be a null pointer. Otherwise, output
- characters beyond the n-1st are discarded rather than being
- written to the array, and a null character is written at the
- end of the characters actually written into the array. If
- copying takes place between objects that overlap, the
- behavior is undefined.
- Returns
- [#3] The snprintf function returns the number of characters
- that would have been written had n been sufficiently large,
- not counting the terminating null character, or a negative
- value if an encoding error occurred. Thus, the null-
- terminated output has been completely written if and only if
- the returned value is nonnegative and less than n.
- */
- /*******************************************************************************/
- void zlog_buf_profile(zlog_buf_t * a_buf, int flag)
- {
- //zc_assert(a_buf,);
- zc_profile(flag, "---buf[%p][%ld-%ld][%ld][%s][%p:%ld]---",
- a_buf,
- a_buf->size_min, a_buf->size_max,
- a_buf->size_real,
- a_buf->truncate_str,
- a_buf->start, a_buf->tail - a_buf->start);
- return;
- }
- /*******************************************************************************/
- void zlog_buf_del(zlog_buf_t * a_buf)
- {
- //zc_assert(a_buf,);
- if (a_buf->start) free(a_buf->start);
- zc_debug("zlog_buf_del[%p]", a_buf);
- free(a_buf);
- return;
- }
- zlog_buf_t *zlog_buf_new(size_t buf_size_min, size_t buf_size_max, const char *truncate_str)
- {
- zlog_buf_t *a_buf;
- if (buf_size_min == 0) {
- zc_error("buf_size_min == 0, not allowed");
- return NULL;
- }
- if (buf_size_max != 0 && buf_size_max < buf_size_min) {
- zc_error("buf_size_max[%lu] < buf_size_min[%lu] && buf_size_max != 0",
- (unsigned long)buf_size_max, (unsigned long)buf_size_min);
- return NULL;
- }
- a_buf = calloc(1, sizeof(*a_buf));
- if (!a_buf) {
- zc_error("calloc fail, errno[%d]", errno);
- return NULL;
- }
- if (truncate_str) {
- if (strlen(truncate_str) > sizeof(a_buf->truncate_str) - 1) {
- zc_error("truncate_str[%s] overflow", truncate_str);
- goto err;
- } else {
- strcpy(a_buf->truncate_str, truncate_str);
- }
- a_buf->truncate_str_len = strlen(truncate_str);
- }
- a_buf->size_min = buf_size_min;
- a_buf->size_max = buf_size_max;
- a_buf->size_real = a_buf->size_min;
- a_buf->start = calloc(1, a_buf->size_real);
- if (!a_buf->start) {
- zc_error("calloc fail, errno[%d]", errno);
- goto err;
- }
- a_buf->tail = a_buf->start;
- a_buf->end_plus_1 = a_buf->start + a_buf->size_real;
- a_buf->end = a_buf->end_plus_1 - 1;
- //zlog_buf_profile(a_buf, ZC_DEBUG);
- return a_buf;
- err:
- zlog_buf_del(a_buf);
- return NULL;
- }
- /*******************************************************************************/
- static void zlog_buf_truncate(zlog_buf_t * a_buf)
- {
- char *p;
- size_t len;
- if ((a_buf->truncate_str)[0] == '\0') return;
- p = (a_buf->tail - a_buf->truncate_str_len);
- if (p < a_buf->start) p = a_buf->start;
- len = a_buf->tail - p;
- memcpy(p, a_buf->truncate_str, len);
- return;
- }
- /*******************************************************************************/
- /* return 0: success
- * return <0: fail, set size_real to -1;
- * return >0: by conf limit, can't extend size
- * increment must > 0
- */
- static int zlog_buf_resize(zlog_buf_t * a_buf, size_t increment)
- {
- int rc = 0;
- size_t new_size = 0;
- size_t len = 0;
- char *p = NULL;
- if (a_buf->size_max != 0 && a_buf->size_real >= a_buf->size_max) {
- zc_error("a_buf->size_real[%ld] >= a_buf->size_max[%ld]",
- a_buf->size_real, a_buf->size_max);
- return 1;
- }
- if (a_buf->size_max == 0) {
- /* unlimit */
- new_size = a_buf->size_real + 1.5 * increment;
- } else {
- /* limited */
- if (a_buf->size_real + increment <= a_buf->size_max) {
- new_size = a_buf->size_real + increment;
- } else {
- new_size = a_buf->size_max;
- rc = 1;
- }
- }
- len = a_buf->tail - a_buf->start;
- p = realloc(a_buf->start, new_size);
- if (!p) {
- zc_error("realloc fail, errno[%d]", errno);
- free(a_buf->start);
- a_buf->start = NULL;
- a_buf->tail = NULL;
- a_buf->end = NULL;
- a_buf->end_plus_1 = NULL;
- return -1;
- } else {
- a_buf->start = p;
- a_buf->tail = p + len;
- a_buf->size_real = new_size;
- a_buf->end_plus_1 = a_buf->start + new_size;
- a_buf->end = a_buf->end_plus_1 - 1;
- }
- return rc;
- }
- int zlog_buf_vprintf(zlog_buf_t * a_buf, const char *format, va_list args)
- {
- va_list ap;
- size_t size_left;
- int nwrite;
- if (!a_buf->start) {
- zc_error("pre-use of zlog_buf_resize fail, so can't convert");
- return -1;
- }
- va_copy(ap, args);
- size_left = a_buf->end_plus_1 - a_buf->tail;
- nwrite = vsnprintf(a_buf->tail, size_left, format, ap);
- if (nwrite >= 0 && nwrite < size_left) {
- a_buf->tail += nwrite;
- //*(a_buf->tail) = '\0';
- return 0;
- } else if (nwrite < 0) {
- zc_error("vsnprintf fail, errno[%d]", errno);
- zc_error("nwrite[%d], size_left[%ld], format[%s]", nwrite, size_left, format);
- return -1;
- } else if (nwrite >= size_left) {
- int rc;
- //zc_debug("nwrite[%d]>=size_left[%ld],format[%s],resize", nwrite, size_left, format);
- rc = zlog_buf_resize(a_buf, nwrite - size_left + 1);
- if (rc > 0) {
- zc_error("conf limit to %ld, can't extend, so truncate", a_buf->size_max);
- va_copy(ap, args);
- size_left = a_buf->end_plus_1 - a_buf->tail;
- vsnprintf(a_buf->tail, size_left, format, ap);
- a_buf->tail += size_left - 1;
- //*(a_buf->tail) = '\0';
- zlog_buf_truncate(a_buf);
- return 1;
- } else if (rc < 0) {
- zc_error("zlog_buf_resize fail");
- return -1;
- } else {
- //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
- va_copy(ap, args);
- size_left = a_buf->end_plus_1 - a_buf->tail;
- nwrite = vsnprintf(a_buf->tail, size_left, format, ap);
- if (nwrite < 0) {
- zc_error("vsnprintf fail, errno[%d]", errno);
- zc_error("nwrite[%d], size_left[%ld], format[%s]", nwrite, size_left, format);
- return -1;
- } else {
- a_buf->tail += nwrite;
- //*(a_buf->tail) = '\0';
- return 0;
- }
- }
- }
- return 0;
- }
- /*******************************************************************************/
- /* if width > num_len, 0 padding, else output num */
- int zlog_buf_printf_dec32(zlog_buf_t * a_buf, uint32_t ui32, int width)
- {
- unsigned char *p;
- char *q;
- unsigned char tmp[ZLOG_INT32_LEN + 1];
- size_t num_len, zero_len, out_len;
- if (!a_buf->start) {
- zc_error("pre-use of zlog_buf_resize fail, so can't convert");
- return -1;
- }
- p = tmp + ZLOG_INT32_LEN;
- do {
- *--p = (unsigned char) (ui32 % 10 + '0');
- } while (ui32 /= 10);
- /* zero or space padding */
- num_len = (tmp + ZLOG_INT32_LEN) - p;
- if (width > num_len) {
- zero_len = width - num_len;
- out_len = width;
- } else {
- zero_len = 0;
- out_len = num_len;
- }
- if ((q = a_buf->tail + out_len) > a_buf->end) {
- int rc;
- //zc_debug("size_left not enough, resize");
- rc = zlog_buf_resize(a_buf, out_len - (a_buf->end - a_buf->tail));
- if (rc > 0) {
- size_t len_left;
- zc_error("conf limit to %ld, can't extend, so output", a_buf->size_max);
- len_left = a_buf->end - a_buf->tail;
- if (len_left <= zero_len) {
- zero_len = len_left;
- num_len = 0;
- } else if (len_left > zero_len) {
- /* zero_len not changed */
- num_len = len_left - zero_len;
- }
- if (zero_len) memset(a_buf->tail, '0', zero_len);
- memcpy(a_buf->tail + zero_len, p, num_len);
- a_buf->tail += len_left;
- //*(a_buf->tail) = '\0';
- zlog_buf_truncate(a_buf);
- return 1;
- } else if (rc < 0) {
- zc_error("zlog_buf_resize fail");
- return -1;
- } else {
- //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
- q = a_buf->tail + out_len; /* re-calculate p*/
- }
- }
- if (zero_len) memset(a_buf->tail, '0', zero_len);
- memcpy(a_buf->tail + zero_len, p, num_len);
- a_buf->tail = q;
- //*(a_buf->tail) = '\0';
- return 0;
- }
- /*******************************************************************************/
- int zlog_buf_printf_dec64(zlog_buf_t * a_buf, uint64_t ui64, int width)
- {
- unsigned char *p;
- char *q;
- unsigned char tmp[ZLOG_INT64_LEN + 1];
- size_t num_len, zero_len, out_len;
- uint32_t ui32;
- if (!a_buf->start) {
- zc_error("pre-use of zlog_buf_resize fail, so can't convert");
- return -1;
- }
- p = tmp + ZLOG_INT64_LEN;
- if (ui64 <= ZLOG_MAX_UINT32_VALUE) {
- /*
- * To divide 64-bit numbers and to find remainders
- * on the x86 platform gcc and icc call the libc functions
- * [u]divdi3() and [u]moddi3(), they call another function
- * in its turn. On FreeBSD it is the qdivrem() function,
- * its source code is about 170 lines of the code.
- * The glibc counterpart is about 150 lines of the code.
- *
- * For 32-bit numbers and some divisors gcc and icc use
- * a inlined multiplication and shifts. For example,
- * unsigned "i32 / 10" is compiled to
- *
- * (i32 * 0xCCCCCCCD) >> 35
- */
- ui32 = (uint32_t) ui64;
- do {
- *--p = (unsigned char) (ui32 % 10 + '0');
- } while (ui32 /= 10);
- } else {
- do {
- *--p = (unsigned char) (ui64 % 10 + '0');
- } while (ui64 /= 10);
- }
- /* zero or space padding */
- num_len = (tmp + ZLOG_INT64_LEN) - p;
- if (width > num_len) {
- zero_len = width - num_len;
- out_len = width;
- } else {
- zero_len = 0;
- out_len = num_len;
- }
- if ((q = a_buf->tail + out_len) > a_buf->end) {
- int rc;
- //zc_debug("size_left not enough, resize");
- rc = zlog_buf_resize(a_buf, out_len - (a_buf->end - a_buf->tail));
- if (rc > 0) {
- size_t len_left;
- zc_error("conf limit to %ld, can't extend, so output", a_buf->size_max);
- len_left = a_buf->end - a_buf->tail;
- if (len_left <= zero_len) {
- zero_len = len_left;
- num_len = 0;
- } else if (len_left > zero_len) {
- /* zero_len not changed */
- num_len = len_left - zero_len;
- }
- if (zero_len) memset(a_buf->tail, '0', zero_len);
- memcpy(a_buf->tail + zero_len, p, num_len);
- a_buf->tail += len_left;
- //*(a_buf->tail) = '\0';
- zlog_buf_truncate(a_buf);
- return 1;
- } else if (rc < 0) {
- zc_error("zlog_buf_resize fail");
- return -1;
- } else {
- //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
- q = a_buf->tail + out_len; /* re-calculate p*/
- }
- }
- if (zero_len) memset(a_buf->tail, '0', zero_len);
- memcpy(a_buf->tail + zero_len, p, num_len);
- a_buf->tail = q;
- //*(a_buf->tail) = '\0';
- return 0;
- }
- /*******************************************************************************/
- int zlog_buf_printf_hex(zlog_buf_t * a_buf, uint32_t ui32, int width)
- {
- unsigned char *p;
- char *q;
- unsigned char tmp[ZLOG_INT32_LEN + 1];
- size_t num_len, zero_len, out_len;
- static unsigned char hex[] = "0123456789abcdef";
- //static unsigned char HEX[] = "0123456789ABCDEF";
- if (!a_buf->start) {
- zc_error("pre-use of zlog_buf_resize fail, so can't convert");
- return -1;
- }
- p = tmp + ZLOG_INT32_LEN;
- do {
- /* the "(uint32_t)" cast disables the BCC's warning */
- *--p = hex[(uint32_t) (ui32 & 0xf)];
- } while (ui32 >>= 4);
- #if 0
- } else { /* is_hex == 2 */
- do {
- /* the "(uint32_t)" cast disables the BCC's warning */
- *--p = HEX[(uint32_t) (ui64 & 0xf)];
- } while (ui64 >>= 4);
- }
- #endif
- /* zero or space padding */
- num_len = (tmp + ZLOG_INT32_LEN) - p;
- if (width > num_len) {
- zero_len = width - num_len;
- out_len = width;
- } else {
- zero_len = 0;
- out_len = num_len;
- }
- if ((q = a_buf->tail + out_len) > a_buf->end) {
- int rc;
- //zc_debug("size_left not enough, resize");
- rc = zlog_buf_resize(a_buf, out_len - (a_buf->end - a_buf->tail));
- if (rc > 0) {
- size_t len_left;
- zc_error("conf limit to %ld, can't extend, so output", a_buf->size_max);
- len_left = a_buf->end - a_buf->tail;
- if (len_left <= zero_len) {
- zero_len = len_left;
- num_len = 0;
- } else if (len_left > zero_len) {
- /* zero_len not changed */
- num_len = len_left - zero_len;
- }
- if (zero_len) memset(a_buf->tail, '0', zero_len);
- memcpy(a_buf->tail + zero_len, p, num_len);
- a_buf->tail += len_left;
- //*(a_buf->tail) = '\0';
- zlog_buf_truncate(a_buf);
- return 1;
- } else if (rc < 0) {
- zc_error("zlog_buf_resize fail");
- return -1;
- } else {
- //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
- q = a_buf->tail + out_len; /* re-calculate p*/
- }
- }
- if (zero_len) memset(a_buf->tail, '0', zero_len);
- memcpy(a_buf->tail + zero_len, p, num_len);
- a_buf->tail = q;
- //*(a_buf->tail) = '\0';
- return 0;
- }
- /*******************************************************************************/
- int zlog_buf_append(zlog_buf_t * a_buf, const char *str, size_t str_len)
- {
- char *p;
- #if 0
- if (str_len <= 0 || str == NULL) {
- return 0;
- }
- if (!a_buf->start) {
- zc_error("pre-use of zlog_buf_resize fail, so can't convert");
- return -1;
- }
- #endif
- if ((p = a_buf->tail + str_len) > a_buf->end) {
- int rc;
- //zc_debug("size_left not enough, resize");
- rc = zlog_buf_resize(a_buf, str_len - (a_buf->end - a_buf->tail));
- if (rc > 0) {
- size_t len_left;
- zc_error("conf limit to %ld, can't extend, so output",
- a_buf->size_max);
- len_left = a_buf->end - a_buf->tail;
- memcpy(a_buf->tail, str, len_left);
- a_buf->tail += len_left;
- //*(a_buf->tail) = '\0';
- zlog_buf_truncate(a_buf);
- return 1;
- } else if (rc < 0) {
- zc_error("zlog_buf_resize fail");
- return -1;
- } else {
- //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
- p = a_buf->tail + str_len; /* re-calculate p*/
- }
- }
- memcpy(a_buf->tail, str, str_len);
- a_buf->tail = p;
- // *(a_buf->tail) = '\0';
- return 0;
- }
- /*******************************************************************************/
- int zlog_buf_adjust_append(zlog_buf_t * a_buf, const char *str, size_t str_len,
- int left_adjust, int zero_pad, size_t in_width, size_t out_width)
- {
- size_t append_len = 0;
- size_t source_len = 0;
- size_t space_len = 0;
- #if 0
- if (str_len <= 0 || str == NULL) {
- return 0;
- }
- #endif
- if (!a_buf->start) {
- zc_error("pre-use of zlog_buf_resize fail, so can't convert");
- return -1;
- }
- /* calculate how many character will be got from str */
- if (out_width == 0 || str_len < out_width) {
- source_len = str_len;
- } else {
- source_len = out_width;
- }
- /* calculate how many character will be output */
- if (in_width == 0 || source_len >= in_width ) {
- append_len = source_len;
- space_len = 0;
- } else {
- append_len = in_width;
- space_len = in_width - source_len;
- }
- /* |-----append_len-----------| */
- /* |-source_len---|-space_len-| left_adjust */
- /* |-space_len---|-source_len-| right_adjust */
- /* |-(size_real-1)---| size not enough */
- if (append_len > a_buf->end - a_buf->tail) {
- int rc = 0;
- //zc_debug("size_left not enough, resize");
- rc = zlog_buf_resize(a_buf, append_len - (a_buf->end -a_buf->tail));
- if (rc > 0) {
- zc_error("conf limit to %ld, can't extend, so output", a_buf->size_max);
- append_len = (a_buf->end - a_buf->tail);
- if (left_adjust) {
- if (source_len < append_len) {
- space_len = append_len - source_len;
- } else {
- source_len = append_len;
- space_len = 0;
- }
- if (space_len) memset(a_buf->tail + source_len, ' ', space_len);
- memcpy(a_buf->tail, str, source_len);
- } else {
- if (space_len < append_len) {
- source_len = append_len - space_len;
- } else {
- space_len = append_len;
- source_len = 0;
- }
- if (space_len) {
- if (zero_pad) {
- memset(a_buf->tail, '0', space_len);
- } else {
- memset(a_buf->tail, ' ', space_len);
- }
- }
- memcpy(a_buf->tail + space_len, str, source_len);
- }
- a_buf->tail += append_len;
- //*(a_buf->tail) = '\0';
- zlog_buf_truncate(a_buf);
- return 1;
- } else if (rc < 0) {
- zc_error("zlog_buf_resize fail");
- return -1;
- } else {
- //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
- }
- }
- if (left_adjust) {
- if (space_len) memset(a_buf->tail + source_len, ' ', space_len);
- memcpy(a_buf->tail, str, source_len);
- } else {
- if (space_len) {
- if (zero_pad) {
- memset(a_buf->tail, '0', space_len);
- } else {
- memset(a_buf->tail, ' ', space_len);
- }
- }
- memcpy(a_buf->tail + space_len, str, source_len);
- }
- a_buf->tail += append_len;
- //*(a_buf->tail) = '\0';
- return 0;
- }
- /*******************************************************************************/
|