1 /*
2 * This file is part of the zlog Library.
3 *
4 * Copyright (C) 2011 by Hardy Simpson <HardySimpson1984@gmail.com>
5 *
6 * Licensed under the LGPL v2.1, see the file COPYING in base directory.
7 */
8
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <pthread.h>
12 #include <errno.h>
13 #include <stdint.h>
14
15 #include "zc_defs.h"
16 #include "buf.h"
17 /*******************************************************************************/
18 /* Author's Note
19 * This buf.c is base on C99, that is, if buffer size is not enough,
20 * the return value of vsnprintf(3) is a number tell how many character should
21 * be output. vsnprintf in glibc 2.1 conforms to C99 , but glibc 2.0 doesn't.
22 * see manpage of vsnprintf(3) on you platform for more detail.
23
24 * So, what should you do if you want to using zlog on the platform that doesn't
25 * conform C99? My Answer is, crack zlog with a portable C99-vsnprintf, like this
26 * http://sourceforge.net/projects/ctrio/
27 * http://www.jhweiss.de/software/snprintf.html
28 * If you can see this note, you can fix it yourself? Aren't you? ^_^
29
30 * Oh, I put the snprintf in C99 standard here,
31 * vsnprintf is the same on return value.
32
33 7.19.6.5 The snprintf function
34
35 Synopsis
36
37 [#1]
38
39 #include <stdio.h>
40 int snprintf(char * restrict s, size_t n,
41 const char * restrict format, ...);
42
43 Description
44
45 [#2] The snprintf function is equivalent to fprintf, except
46 that the output is written into an array (specified by
47 argument s) rather than to a stream. If n is zero, nothing
48 is written, and s may be a null pointer. Otherwise, output
49 characters beyond the n-1st are discarded rather than being
50 written to the array, and a null character is written at the
51 end of the characters actually written into the array. If
52 copying takes place between objects that overlap, the
53 behavior is undefined.
54
55 Returns
56
57 [#3] The snprintf function returns the number of characters
58 that would have been written had n been sufficiently large,
59 not counting the terminating null character, or a negative
60 value if an encoding error occurred. Thus, the null-
61 terminated output has been completely written if and only if
62 the returned value is nonnegative and less than n.
63 */
64
65 /*******************************************************************************/
zlog_buf_profile(zlog_buf_t * a_buf,int flag)66 void zlog_buf_profile(zlog_buf_t * a_buf, int flag)
67 {
68 //zc_assert(a_buf,);
69 zc_profile(flag, "---buf[%p][%ld-%ld][%ld][%s][%p:%ld]---",
70 a_buf,
71 a_buf->size_min, a_buf->size_max,
72 a_buf->size_real,
73 a_buf->truncate_str,
74 a_buf->start, a_buf->tail - a_buf->start);
75 return;
76 }
77 /*******************************************************************************/
zlog_buf_del(zlog_buf_t * a_buf)78 void zlog_buf_del(zlog_buf_t * a_buf)
79 {
80 //zc_assert(a_buf,);
81 if (a_buf->start) free(a_buf->start);
82 free(a_buf);
83 zc_debug("zlog_buf_del[%p]", a_buf);
84 return;
85 }
86
zlog_buf_new(size_t buf_size_min,size_t buf_size_max,const char * truncate_str)87 zlog_buf_t *zlog_buf_new(size_t buf_size_min, size_t buf_size_max, const char *truncate_str)
88 {
89 zlog_buf_t *a_buf;
90
91 if (buf_size_min == 0) {
92 zc_error("buf_size_min == 0, not allowed");
93 return NULL;
94 }
95
96 if (buf_size_max != 0 && buf_size_max < buf_size_min) {
97 zc_error("buf_size_max[%lu] < buf_size_min[%lu] && buf_size_max != 0",
98 (unsigned long)buf_size_max, (unsigned long)buf_size_min);
99 return NULL;
100 }
101
102 a_buf = calloc(1, sizeof(*a_buf));
103 if (!a_buf) {
104 zc_error("calloc fail, errno[%d]", errno);
105 return NULL;
106 }
107
108 if (truncate_str) {
109 if (strlen(truncate_str) > sizeof(a_buf->truncate_str) - 1) {
110 zc_error("truncate_str[%s] overflow", truncate_str);
111 goto err;
112 } else {
113 strcpy(a_buf->truncate_str, truncate_str);
114 }
115 a_buf->truncate_str_len = strlen(truncate_str);
116 }
117
118 a_buf->size_min = buf_size_min;
119 a_buf->size_max = buf_size_max;
120 a_buf->size_real = a_buf->size_min;
121
122 a_buf->start = calloc(1, a_buf->size_real);
123 if (!a_buf->start) {
124 zc_error("calloc fail, errno[%d]", errno);
125 goto err;
126 }
127
128 a_buf->tail = a_buf->start;
129 a_buf->end_plus_1 = a_buf->start + a_buf->size_real;
130 a_buf->end = a_buf->end_plus_1 - 1;
131
132 //zlog_buf_profile(a_buf, ZC_DEBUG);
133 return a_buf;
134
135 err:
136 zlog_buf_del(a_buf);
137 return NULL;
138 }
139
140 /*******************************************************************************/
zlog_buf_truncate(zlog_buf_t * a_buf)141 static void zlog_buf_truncate(zlog_buf_t * a_buf)
142 {
143 char *p;
144 size_t len;
145
146 if ((a_buf->truncate_str)[0] == '\0') return;
147 p = (a_buf->tail - a_buf->truncate_str_len);
148 if (p < a_buf->start) p = a_buf->start;
149 len = a_buf->tail - p;
150 memcpy(p, a_buf->truncate_str, len);
151 return;
152 }
153
154 /*******************************************************************************/
155 /* return 0: success
156 * return <0: fail, set size_real to -1;
157 * return >0: by conf limit, can't extend size
158 * increment must > 0
159 */
zlog_buf_resize(zlog_buf_t * a_buf,size_t increment)160 static int zlog_buf_resize(zlog_buf_t * a_buf, size_t increment)
161 {
162 int rc = 0;
163 size_t new_size = 0;
164 size_t len = 0;
165 char *p = NULL;
166
167 if (a_buf->size_max != 0 && a_buf->size_real >= a_buf->size_max) {
168 zc_error("a_buf->size_real[%ld] >= a_buf->size_max[%ld]",
169 a_buf->size_real, a_buf->size_max);
170 return 1;
171 }
172
173 if (a_buf->size_max == 0) {
174 /* unlimit */
175 new_size = a_buf->size_real + 1.5 * increment;
176 } else {
177 /* limited */
178 if (a_buf->size_real + increment <= a_buf->size_max) {
179 new_size = a_buf->size_real + increment;
180 } else {
181 new_size = a_buf->size_max;
182 rc = 1;
183 }
184 }
185
186 len = a_buf->tail - a_buf->start;
187 p = realloc(a_buf->start, new_size);
188 if (!p) {
189 zc_error("realloc fail, errno[%d]", errno);
190 free(a_buf->start);
191 a_buf->start = NULL;
192 a_buf->tail = NULL;
193 a_buf->end = NULL;
194 a_buf->end_plus_1 = NULL;
195 return -1;
196 } else {
197 a_buf->start = p;
198 a_buf->tail = p + len;
199 a_buf->size_real = new_size;
200 a_buf->end_plus_1 = a_buf->start + new_size;
201 a_buf->end = a_buf->end_plus_1 - 1;
202 }
203
204 return rc;
205 }
206
zlog_buf_vprintf(zlog_buf_t * a_buf,const char * format,va_list args)207 int zlog_buf_vprintf(zlog_buf_t * a_buf, const char *format, va_list args)
208 {
209 va_list ap;
210 size_t size_left;
211 int nwrite;
212
213 if (!a_buf->start) {
214 zc_error("pre-use of zlog_buf_resize fail, so can't convert");
215 return -1;
216 }
217
218 va_copy(ap, args);
219 size_left = a_buf->end_plus_1 - a_buf->tail;
220 nwrite = vsnprintf(a_buf->tail, size_left, format, ap);
221 if (nwrite >= 0 && nwrite < size_left) {
222 a_buf->tail += nwrite;
223 //*(a_buf->tail) = '\0';
224 return 0;
225 } else if (nwrite < 0) {
226 zc_error("vsnprintf fail, errno[%d]", errno);
227 zc_error("nwrite[%d], size_left[%ld], format[%s]", nwrite, size_left, format);
228 return -1;
229 } else if (nwrite >= size_left) {
230 int rc;
231 //zc_debug("nwrite[%d]>=size_left[%ld],format[%s],resize", nwrite, size_left, format);
232 rc = zlog_buf_resize(a_buf, nwrite - size_left + 1);
233 if (rc > 0) {
234 zc_error("conf limit to %ld, can't extend, so truncate", a_buf->size_max);
235 va_copy(ap, args);
236 size_left = a_buf->end_plus_1 - a_buf->tail;
237 vsnprintf(a_buf->tail, size_left, format, ap);
238 a_buf->tail += size_left - 1;
239 //*(a_buf->tail) = '\0';
240 zlog_buf_truncate(a_buf);
241 return 1;
242 } else if (rc < 0) {
243 zc_error("zlog_buf_resize fail");
244 return -1;
245 } else {
246 //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
247
248 va_copy(ap, args);
249 size_left = a_buf->end_plus_1 - a_buf->tail;
250 nwrite = vsnprintf(a_buf->tail, size_left, format, ap);
251 if (nwrite < 0) {
252 zc_error("vsnprintf fail, errno[%d]", errno);
253 zc_error("nwrite[%d], size_left[%ld], format[%s]", nwrite, size_left, format);
254 return -1;
255 } else {
256 a_buf->tail += nwrite;
257 //*(a_buf->tail) = '\0';
258 return 0;
259 }
260 }
261 }
262
263 return 0;
264 }
265
266 /*******************************************************************************/
267 /* if width > num_len, 0 padding, else output num */
zlog_buf_printf_dec32(zlog_buf_t * a_buf,uint32_t ui32,int width)268 int zlog_buf_printf_dec32(zlog_buf_t * a_buf, uint32_t ui32, int width)
269 {
270 unsigned char *p;
271 char *q;
272 unsigned char tmp[ZLOG_INT32_LEN + 1];
273 size_t num_len, zero_len, out_len;
274
275 if (!a_buf->start) {
276 zc_error("pre-use of zlog_buf_resize fail, so can't convert");
277 return -1;
278 }
279
280 p = tmp + ZLOG_INT32_LEN;
281 do {
282 *--p = (unsigned char) (ui32 % 10 + '0');
283 } while (ui32 /= 10);
284
285 /* zero or space padding */
286 num_len = (tmp + ZLOG_INT32_LEN) - p;
287
288 if (width > num_len) {
289 zero_len = width - num_len;
290 out_len = width;
291 } else {
292 zero_len = 0;
293 out_len = num_len;
294 }
295
296 if ((q = a_buf->tail + out_len) > a_buf->end) {
297 int rc;
298 //zc_debug("size_left not enough, resize");
299 rc = zlog_buf_resize(a_buf, out_len - (a_buf->end - a_buf->tail));
300 if (rc > 0) {
301 size_t len_left;
302 zc_error("conf limit to %ld, can't extend, so output", a_buf->size_max);
303 len_left = a_buf->end - a_buf->tail;
304 if (len_left <= zero_len) {
305 zero_len = len_left;
306 num_len = 0;
307 } else if (len_left > zero_len) {
308 /* zero_len not changed */
309 num_len = len_left - zero_len;
310 }
311 if (zero_len) memset(a_buf->tail, '0', zero_len);
312 memcpy(a_buf->tail + zero_len, p, num_len);
313 a_buf->tail += len_left;
314 //*(a_buf->tail) = '\0';
315 zlog_buf_truncate(a_buf);
316 return 1;
317 } else if (rc < 0) {
318 zc_error("zlog_buf_resize fail");
319 return -1;
320 } else {
321 //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
322 q = a_buf->tail + out_len; /* re-calculate p*/
323 }
324 }
325
326 if (zero_len) memset(a_buf->tail, '0', zero_len);
327 memcpy(a_buf->tail + zero_len, p, num_len);
328 a_buf->tail = q;
329 //*(a_buf->tail) = '\0';
330 return 0;
331 }
332 /*******************************************************************************/
zlog_buf_printf_dec64(zlog_buf_t * a_buf,uint64_t ui64,int width)333 int zlog_buf_printf_dec64(zlog_buf_t * a_buf, uint64_t ui64, int width)
334 {
335 unsigned char *p;
336 char *q;
337 unsigned char tmp[ZLOG_INT64_LEN + 1];
338 size_t num_len, zero_len, out_len;
339 uint32_t ui32;
340
341 if (!a_buf->start) {
342 zc_error("pre-use of zlog_buf_resize fail, so can't convert");
343 return -1;
344 }
345
346 p = tmp + ZLOG_INT64_LEN;
347 if (ui64 <= ZLOG_MAX_UINT32_VALUE) {
348 /*
349 * To divide 64-bit numbers and to find remainders
350 * on the x86 platform gcc and icc call the libc functions
351 * [u]divdi3() and [u]moddi3(), they call another function
352 * in its turn. On FreeBSD it is the qdivrem() function,
353 * its source code is about 170 lines of the code.
354 * The glibc counterpart is about 150 lines of the code.
355 *
356 * For 32-bit numbers and some divisors gcc and icc use
357 * a inlined multiplication and shifts. For example,
358 * unsigned "i32 / 10" is compiled to
359 *
360 * (i32 * 0xCCCCCCCD) >> 35
361 */
362
363 ui32 = (uint32_t) ui64;
364
365 do {
366 *--p = (unsigned char) (ui32 % 10 + '0');
367 } while (ui32 /= 10);
368
369 } else {
370 do {
371 *--p = (unsigned char) (ui64 % 10 + '0');
372 } while (ui64 /= 10);
373 }
374
375
376 /* zero or space padding */
377 num_len = (tmp + ZLOG_INT64_LEN) - p;
378
379 if (width > num_len) {
380 zero_len = width - num_len;
381 out_len = width;
382 } else {
383 zero_len = 0;
384 out_len = num_len;
385 }
386
387 if ((q = a_buf->tail + out_len) > a_buf->end) {
388 int rc;
389 //zc_debug("size_left not enough, resize");
390 rc = zlog_buf_resize(a_buf, out_len - (a_buf->end - a_buf->tail));
391 if (rc > 0) {
392 size_t len_left;
393 zc_error("conf limit to %ld, can't extend, so output", a_buf->size_max);
394 len_left = a_buf->end - a_buf->tail;
395 if (len_left <= zero_len) {
396 zero_len = len_left;
397 num_len = 0;
398 } else if (len_left > zero_len) {
399 /* zero_len not changed */
400 num_len = len_left - zero_len;
401 }
402 if (zero_len) memset(a_buf->tail, '0', zero_len);
403 memcpy(a_buf->tail + zero_len, p, num_len);
404 a_buf->tail += len_left;
405 //*(a_buf->tail) = '\0';
406 zlog_buf_truncate(a_buf);
407 return 1;
408 } else if (rc < 0) {
409 zc_error("zlog_buf_resize fail");
410 return -1;
411 } else {
412 //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
413 q = a_buf->tail + out_len; /* re-calculate p*/
414 }
415 }
416
417 if (zero_len) memset(a_buf->tail, '0', zero_len);
418 memcpy(a_buf->tail + zero_len, p, num_len);
419 a_buf->tail = q;
420 //*(a_buf->tail) = '\0';
421 return 0;
422 }
423 /*******************************************************************************/
zlog_buf_printf_hex(zlog_buf_t * a_buf,uint32_t ui32,int width)424 int zlog_buf_printf_hex(zlog_buf_t * a_buf, uint32_t ui32, int width)
425 {
426 unsigned char *p;
427 char *q;
428 unsigned char tmp[ZLOG_INT32_LEN + 1];
429 size_t num_len, zero_len, out_len;
430 static unsigned char hex[] = "0123456789abcdef";
431 //static unsigned char HEX[] = "0123456789ABCDEF";
432
433 if (!a_buf->start) {
434 zc_error("pre-use of zlog_buf_resize fail, so can't convert");
435 return -1;
436 }
437
438
439 p = tmp + ZLOG_INT32_LEN;
440 do {
441 /* the "(uint32_t)" cast disables the BCC's warning */
442 *--p = hex[(uint32_t) (ui32 & 0xf)];
443 } while (ui32 >>= 4);
444
445 #if 0
446 } else { /* is_hex == 2 */
447
448 do {
449 /* the "(uint32_t)" cast disables the BCC's warning */
450 *--p = HEX[(uint32_t) (ui64 & 0xf)];
451
452 } while (ui64 >>= 4);
453 }
454 #endif
455
456 /* zero or space padding */
457 num_len = (tmp + ZLOG_INT32_LEN) - p;
458
459 if (width > num_len) {
460 zero_len = width - num_len;
461 out_len = width;
462 } else {
463 zero_len = 0;
464 out_len = num_len;
465 }
466
467 if ((q = a_buf->tail + out_len) > a_buf->end) {
468 int rc;
469 //zc_debug("size_left not enough, resize");
470 rc = zlog_buf_resize(a_buf, out_len - (a_buf->end - a_buf->tail));
471 if (rc > 0) {
472 size_t len_left;
473 zc_error("conf limit to %ld, can't extend, so output", a_buf->size_max);
474 len_left = a_buf->end - a_buf->tail;
475 if (len_left <= zero_len) {
476 zero_len = len_left;
477 num_len = 0;
478 } else if (len_left > zero_len) {
479 /* zero_len not changed */
480 num_len = len_left - zero_len;
481 }
482 if (zero_len) memset(a_buf->tail, '0', zero_len);
483 memcpy(a_buf->tail + zero_len, p, num_len);
484 a_buf->tail += len_left;
485 //*(a_buf->tail) = '\0';
486 zlog_buf_truncate(a_buf);
487 return 1;
488 } else if (rc < 0) {
489 zc_error("zlog_buf_resize fail");
490 return -1;
491 } else {
492 //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
493 q = a_buf->tail + out_len; /* re-calculate p*/
494 }
495 }
496
497 if (zero_len) memset(a_buf->tail, '0', zero_len);
498 memcpy(a_buf->tail + zero_len, p, num_len);
499 a_buf->tail = q;
500 //*(a_buf->tail) = '\0';
501 return 0;
502 }
503
504 /*******************************************************************************/
zlog_buf_append(zlog_buf_t * a_buf,const char * str,size_t str_len)505 int zlog_buf_append(zlog_buf_t * a_buf, const char *str, size_t str_len)
506 {
507 char *p;
508 #if 0
509 if (str_len <= 0 || str == NULL) {
510 return 0;
511 }
512 if (!a_buf->start) {
513 zc_error("pre-use of zlog_buf_resize fail, so can't convert");
514 return -1;
515 }
516 #endif
517
518 if ((p = a_buf->tail + str_len) > a_buf->end) {
519 int rc;
520 //zc_debug("size_left not enough, resize");
521 rc = zlog_buf_resize(a_buf, str_len - (a_buf->end - a_buf->tail));
522 if (rc > 0) {
523 size_t len_left;
524 zc_error("conf limit to %ld, can't extend, so output",
525 a_buf->size_max);
526 len_left = a_buf->end - a_buf->tail;
527 memcpy(a_buf->tail, str, len_left);
528 a_buf->tail += len_left;
529 //*(a_buf->tail) = '\0';
530 zlog_buf_truncate(a_buf);
531 return 1;
532 } else if (rc < 0) {
533 zc_error("zlog_buf_resize fail");
534 return -1;
535 } else {
536 //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
537 p = a_buf->tail + str_len; /* re-calculate p*/
538 }
539 }
540
541 memcpy(a_buf->tail, str, str_len);
542 a_buf->tail = p;
543 // *(a_buf->tail) = '\0';
544 return 0;
545 }
546
547 /*******************************************************************************/
zlog_buf_adjust_append(zlog_buf_t * a_buf,const char * str,size_t str_len,int left_adjust,size_t in_width,size_t out_width)548 int zlog_buf_adjust_append(zlog_buf_t * a_buf, const char *str, size_t str_len,
549 int left_adjust, size_t in_width, size_t out_width)
550 {
551 size_t append_len = 0;
552 size_t source_len = 0;
553 size_t space_len = 0;
554
555 #if 0
556 if (str_len <= 0 || str == NULL) {
557 return 0;
558 }
559 #endif
560
561 if (!a_buf->start) {
562 zc_error("pre-use of zlog_buf_resize fail, so can't convert");
563 return -1;
564 }
565
566 /* calculate how many character will be got from str */
567 if (out_width == 0 || str_len < out_width) {
568 source_len = str_len;
569 } else {
570 source_len = out_width;
571 }
572
573 /* calculate how many character will be output */
574 if (in_width == 0 || source_len >= in_width ) {
575 append_len = source_len;
576 space_len = 0;
577 } else {
578 append_len = in_width;
579 space_len = in_width - source_len;
580 }
581
582 /* |-----append_len-----------| */
583 /* |-source_len---|-space_len-| left_adjust */
584 /* |-space_len---|-source_len-| right_adjust */
585 /* |-(size_real-1)---| size not enough */
586
587 if (append_len > a_buf->end - a_buf->tail) {
588 int rc = 0;
589 //zc_debug("size_left not enough, resize");
590 rc = zlog_buf_resize(a_buf, append_len - (a_buf->end -a_buf->tail));
591 if (rc > 0) {
592 zc_error("conf limit to %ld, can't extend, so output", a_buf->size_max);
593 append_len = (a_buf->end - a_buf->tail);
594 if (left_adjust) {
595 if (source_len < append_len) {
596 space_len = append_len - source_len;
597 } else {
598 source_len = append_len;
599 space_len = 0;
600 }
601 if (space_len) memset(a_buf->tail + source_len, ' ', space_len);
602 memcpy(a_buf->tail, str, source_len);
603 } else {
604 if (space_len < append_len) {
605 source_len = append_len - space_len;
606 } else {
607 space_len = append_len;
608 source_len = 0;
609 }
610 if (space_len) memset(a_buf->tail, ' ', space_len);
611 memcpy(a_buf->tail + space_len, str, source_len);
612 }
613 a_buf->tail += append_len;
614 //*(a_buf->tail) = '\0';
615 zlog_buf_truncate(a_buf);
616 return 1;
617 } else if (rc < 0) {
618 zc_error("zlog_buf_resize fail");
619 return -1;
620 } else {
621 //zc_debug("zlog_buf_resize succ, to[%ld]", a_buf->size_real);
622 }
623 }
624
625 if (left_adjust) {
626 if (space_len) memset(a_buf->tail + source_len, ' ', space_len);
627 memcpy(a_buf->tail, str, source_len);
628 } else {
629 if (space_len) memset(a_buf->tail, ' ', space_len);
630 memcpy(a_buf->tail + space_len, str, source_len);
631 }
632 a_buf->tail += append_len;
633 //*(a_buf->tail) = '\0';
634 return 0;
635 }
636 /*******************************************************************************/
637
638