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