1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
14 #undef mprintf_va_list
16 #undef mputprintf_va_list
33 * work-around for missing va_copy() in GCC
35 #if defined(__GNUC__) && !defined(va_copy)
37 # define va_copy(dest, src) __va_copy(dest, src)
39 # define va_copy(dest, src) (dest) = (src)
43 /** Initial buffer size for mprintf */
46 /** @def MEMORY_DEBUG_ADDRESS
48 * If you want to catch memory management functions (malloc, realloc,
49 * free) which operate on a given address, define this macro and set
50 * memory_debug_address to the address you want to monitor.
52 * @note This macro has no effect if \c MEMORY_DEBUG is not defined
54 #ifdef DOXYGEN_SPECIAL
55 /* Make the macro visible to Doxygen */
56 #define MEMORY_DEBUG_ADDRESS
59 #ifdef MEMORY_DEBUG_ADDRESS
60 /** @brief Memory checkpoint address. */
61 void *memory_debug_address
= NULL
;
63 /** @brief Memory checkpoint ordinal. */
64 size_t memory_debug_ordinal
= (size_t)-1;
68 * @name Number of memory allocations and frees performed.
70 * @note These are tracked even without MEMORY_DEBUG.
72 static size_t malloc_count
= 0, free_count
= 0;
76 * If preprocessor symbol \c MEMORY_DEBUG is defined the memory
77 * management routines do some self-checks against improper use. This
78 * implies extra memory usage and significant performance penalty.
82 #define FILENAME_FORMAT "%s:%d: "
84 /* Currently allocated memory amount, peak, and number of allocations */
85 static size_t allocated_size
= 0, peak_size
= 0;
86 static unsigned int alloc_count
= 0;
87 /* Sum of all the allocated amounts */
88 static unsigned long long total_allocated
= 0;
90 typedef struct memory_block_struct
{
92 struct memory_block_struct
*prev
, *next
;
93 const char *filename
; /* pointer to string literal */
95 unsigned int ordinal
; /* The ordinal which uniquely identifies this allocation */
96 void *magic
; /* only to reserve some place for the magic guard */
97 double begin
; /* beginning of useful memory with proper alignment */
100 static memory_block
*list_head
= NULL
, *list_tail
= NULL
;
102 static void add_to_list(memory_block
*block_ptr
)
104 block_ptr
->prev
= list_tail
;
105 block_ptr
->next
= NULL
;
106 if (list_tail
!= NULL
) list_tail
->next
= block_ptr
;
107 else list_head
= block_ptr
;
108 list_tail
= block_ptr
;
111 static void remove_from_list(memory_block
*block_ptr
)
113 if (block_ptr
->prev
!= NULL
)
114 block_ptr
->prev
->next
= block_ptr
->next
;
115 else list_head
= block_ptr
->next
;
116 if (block_ptr
->next
!= NULL
)
117 block_ptr
->next
->prev
= block_ptr
->prev
;
118 else list_tail
= block_ptr
->prev
;
121 /* Layout of memory (allocated in one chunk)
122 * +----------+ <--- block_ptr
134 * +----------+ +-----------+
135 * | begin | | user data |
139 * +-----------+ +-----------+
144 * The magic values initially contain the value of block_ptr.
145 * When the block is freed, a bit-flipped value is written instead.
146 * During realloc and free, the magic values are checked to match block_ptr.
147 * If they don't, the a memory overrun or underrun has occurred
148 * (except if the magic value happens to match the bit-flipped block_ptr,
149 * in which case it's likely a double-free).
152 static void set_magic_values(memory_block
*block_ptr
)
154 unsigned char *ptr
= (unsigned char*)&block_ptr
->begin
;
155 memcpy(&block_ptr
->magic
, &block_ptr
, sizeof(block_ptr
));
156 memcpy(ptr
+ block_ptr
->size
, &block_ptr
, sizeof(block_ptr
));
159 static void check_magic_values(const char *filename
, int line
,
160 memory_block
*block_ptr
, int is_realloc
)
162 void *inv_ptr
= (void*)(~(size_t)block_ptr
);
163 unsigned char *ptr
= (unsigned char*)&block_ptr
->begin
;
164 /* compare the magic */
165 if (memcmp(&block_ptr
->magic
, &block_ptr
, sizeof(block_ptr
))) {
168 if (memcmp(&block_ptr
->magic
, &inv_ptr
, sizeof(inv_ptr
)))
169 err_str
= "memory corruption";
170 else err_str
= "duplicate free/realloc";
172 fprintf(stderr
, FILENAME_FORMAT
, filename
, line
);
174 fprintf(stderr
, "Fatal error: %s detected at block begin when %s "
175 "pointer %p.\n", err_str
, is_realloc
? "reallocating" : "freeing",
177 if (block_ptr
->filename
) fprintf(stderr
,
178 FILENAME_FORMAT
"Last freed here.\n", block_ptr
->filename
, block_ptr
->lineno
);
181 memcpy(&block_ptr
->magic
, &inv_ptr
, sizeof(inv_ptr
));/*invert magic*/
182 if (memcmp(ptr
+ block_ptr
->size
, &block_ptr
, sizeof(block_ptr
))) {
184 fprintf(stderr
, FILENAME_FORMAT
, filename
, line
);
186 fprintf(stderr
, "Fatal error: memory corruption detected "
187 "at block end when %s pointer %p.\n",
188 is_realloc
? "reallocating" : "freeing", ptr
);
189 if (block_ptr
->filename
) fprintf(stderr
,
190 FILENAME_FORMAT
"Last freed here.\n", block_ptr
->filename
, block_ptr
->lineno
);
193 memcpy(ptr
+ block_ptr
->size
, &inv_ptr
, sizeof(inv_ptr
));
194 block_ptr
->filename
= filename
;
195 block_ptr
->lineno
= line
;
198 /** @def MEMORY_DEBUG_FREE
199 * @brief Enable checking for uses of unallocated/deallocated memory areas.
201 * If preprocessor symbol \c MEMORY_DEBUG_FREE is defined the memory
202 * management routines can verify that unused and deallocated memory areas
203 * are not written accidentally by the program after calling \a Free().
204 * This verification can be done using functions \a check_mem_leak() or
205 * \a check_mem_corrupt().
207 * Note: This functionality can significantly increase the memory requirements
208 * of the program since the deallocated blocks cannot be recycled. They are
209 * not returned to the system using \a free() until the end of the program run.
211 #ifdef DOXYGEN_SPECIAL
212 /* Make the macro visible to Doxygen */
213 #define MEMORY_DEBUG_FREE
216 #ifdef MEMORY_DEBUG_FREE
218 static memory_block
*free_list_head
= NULL
, *free_list_tail
= NULL
;
220 static void add_to_free_list(memory_block
*block_ptr
)
222 block_ptr
->prev
= free_list_tail
;
223 block_ptr
->next
= NULL
;
224 if (free_list_tail
!= NULL
) free_list_tail
->next
= block_ptr
;
225 else free_list_head
= block_ptr
;
226 free_list_tail
= block_ptr
;
229 static void check_free_list(void)
231 memory_block
*block_ptr
= free_list_head
;
233 while (block_ptr
!= NULL
) {
234 void *inv_ptr
= (void*)(~(size_t)block_ptr
);
235 unsigned char *ptr
= (unsigned char*)&block_ptr
->begin
;
237 if (memcmp(&block_ptr
->magic
, &inv_ptr
, sizeof(inv_ptr
))) {
238 fprintf(stderr
, "Fatal error: memory corruption detected in front "
239 "of freed pointer %p\n", ptr
);
242 for (i
= 0; i
< block_ptr
->size
; i
++) {
243 if (ptr
[i
] != 0xAA) {
244 fprintf(stderr
, "Fatal error: memory overwriting detected in "
245 "deallocated area: base pointer: %p, offset: %u, data "
246 "written: %02X\n", ptr
, i
, ptr
[i
]);
250 if (memcmp(ptr
+ block_ptr
->size
, &inv_ptr
, sizeof(inv_ptr
))) {
251 fprintf(stderr
, "Fatal error: memory corruption detected at the "
252 "end of freed pointer %p\n", ptr
);
255 block_ptr
= block_ptr
->next
;
258 fprintf(stderr
, "%u deallocated memory block%s OK\n", counter
,
259 counter
> 1 ? "s are" : " is");
262 static void release_free_blocks(void)
264 memory_block
*block_ptr
= free_list_head
;
265 while (block_ptr
!= NULL
) {
266 memory_block
*next_ptr
= block_ptr
->next
;
268 block_ptr
= next_ptr
;
270 free_list_head
= NULL
;
271 free_list_tail
= NULL
;
274 /* MEMORY_DEBUG_FREE */
276 #ifdef MEMORY_DEBUG_ADDRESS
277 /** Check the address and the ordinal of the allocation against the checkpoints
279 * If the address or the ordinal matches, a line is printed to the standard
280 * error. Breakpoints can be set on the printf to trigger when the watched
281 * allocation happens.
283 * @param block_ptr pointer to a memory block structure which is being
284 * allocated/reallocated/freed
285 * @param oper the actual operation: 0=Malloc, 1=Realloc, 2=Free
287 static void check_memory_address(memory_block
*block_ptr
, int oper
)
289 void *ptr
= (unsigned char*)&block_ptr
->begin
;
290 if (ptr
== memory_debug_address
)
292 if (block_ptr
->filename
) {
293 fprintf(stderr
, FILENAME_FORMAT
, block_ptr
->filename
, block_ptr
->lineno
);
295 fprintf(stderr
, "MEMDEBUG: returning pointer %p while %sing memory.\n",
296 ptr
, oper
==0?"allocat":oper
==1?"reallocat":"free");
298 if (block_ptr
->ordinal
== memory_debug_ordinal
) {
299 if (block_ptr
->filename
) {
300 fprintf(stderr
, FILENAME_FORMAT
, block_ptr
->filename
, block_ptr
->lineno
);
302 fprintf(stderr
, "MEMDEBUG: returning ordinal %lu while %sing memory.\n",
303 (unsigned long)block_ptr
->ordinal
,
304 oper
==0 ? "allocat" : (oper
==1 ? "reallocat" : "free"));
308 /* MEMORY_DEBUG_ADDRESS */
310 /*#define FATAL_ERROR_INTERNAL(f,l,s) fatal_error(f,l,s)*/
311 #define MALLOC_INTERNAL(f,l,s) Malloc_dbg(f,l,s)
312 #define MEMPTYSTR_INTERNAL(f,l) memptystr_dbg(f,l)
313 #define MCOPYSTR_INTERNAL(f,l,s) mcopystr_dbg(f,l,s)
314 #define REALLOC_INTERNAL(f,l,p,s) Realloc_dbg(f,l,p,s)
315 #define FREE_INTERNAL(f,l,p) Free_dbg(f,l,p)
316 #define MPRINTF_VA_LIST_INTERNAL(f,l,s,p) mprintf_va_list_dbg(f,l,s,p)
318 static const size_t offset
= (unsigned char*)&(((memory_block
*)NULL
)->begin
)
319 - (unsigned char*)NULL
;
321 static void extract_location(void *p
, const char **fn
, int *ln
)
323 memory_block
*block_ptr
= NULL
;
324 block_ptr
= (memory_block
*)(void*)((unsigned char*)p
- offset
);
325 *fn
= block_ptr
->filename
;
326 *ln
= block_ptr
->lineno
;
330 /* not MEMORY_DEBUG */
332 #define FATAL_ERROR_INTERNAL(f,l,s) fatal_error(s)
333 #define MALLOC_INTERNAL(f,l,s) Malloc(s)
334 #define MEMPTYSTR_INTERNAL(f,l) memptystr()
335 #define MCOPYSTR_INTERNAL(f,l,s) mcopystr(s)
336 #define REALLOC_INTERNAL(f,l,p,s) Realloc(p,s)
337 #define FREE_INTERNAL(f,l,p) Free(p)
338 #define MPRINTF_VA_LIST_INTERNAL(f,l,s,p) mprintf_va_list(s,p)
340 #define extract_location(p,f,l) ((void)p,(void)f,(void)l)
343 /** Report a fatal error.
345 * @param size the number of bytes that could not be allocated
347 * This function does not return.
349 __attribute__ ((__noreturn__
))
350 static void fatal_error(
352 const char *filename
, int line
,
356 const char *err_msg
= strerror(errno
);
358 fprintf(stderr
, FILENAME_FORMAT
"Fatal error: cannot allocate %lu bytes"
359 " of memory after allocating %lu bytes: ", filename
, line
,
360 (unsigned long) size
, (unsigned long) allocated_size
);
362 fprintf(stderr
, "Fatal error: cannot allocate %lu bytes of memory: ",
363 (unsigned long) size
);
365 if (err_msg
!= NULL
) fprintf(stderr
, "%s. Exiting.\n", err_msg
);
366 else fprintf(stderr
, "Unknown error (errno: %d). Exiting.\n", errno
);
371 void *Malloc(size_t size
)
373 return Malloc_dbg(0,0,size
);
376 void *Malloc_dbg(const char *filename
, int line
, size_t size
)
378 void *Malloc(size_t size
)
384 memory_block
*block_ptr
;
385 block_ptr
= (memory_block
*)malloc(sizeof(*block_ptr
) -
386 sizeof(block_ptr
->begin
) + size
+ sizeof(block_ptr
));
387 if (block_ptr
== NULL
) fatal_error(filename
, line
, size
);
388 block_ptr
->filename
= filename
;
389 block_ptr
->lineno
= line
;
390 block_ptr
->size
= size
;
391 add_to_list(block_ptr
);
392 set_magic_values(block_ptr
);
393 ptr
= &block_ptr
->begin
;
394 total_allocated
+= size
;
395 block_ptr
->ordinal
= alloc_count
++;
396 allocated_size
+= size
;
397 #ifdef MEMORY_DEBUG_ADDRESS
398 check_memory_address(block_ptr
, 0);
400 if (peak_size
< allocated_size
) peak_size
= allocated_size
;
403 if (ptr
== NULL
) fatal_error(size
);
412 void *Realloc(void *ptr
, size_t size
)
414 return Realloc_dbg(0,0,ptr
,size
);
417 void *Realloc_dbg(const char *filename
, int line
, void *ptr
, size_t size
)
419 void *Realloc(void *ptr
, size_t size
)
422 if (ptr
== NULL
) return MALLOC_INTERNAL(filename
, line
, size
);
423 else if (size
== 0) {
424 FREE_INTERNAL(filename
, line
, ptr
);
429 memory_block
*block_ptr
= NULL
;
430 block_ptr
= (memory_block
*)(void*)((unsigned char*)ptr
- offset
);
431 check_magic_values(filename
, line
, block_ptr
, 1);
432 remove_from_list(block_ptr
);
433 allocated_size
-= block_ptr
->size
;
434 if (size
< block_ptr
->size
)
435 memset((unsigned char*)ptr
+ size
, 0x55, block_ptr
->size
- size
);
436 block_ptr
= (memory_block
*)realloc(block_ptr
, sizeof(*block_ptr
) -
437 sizeof(block_ptr
->begin
) + sizeof(block_ptr
) + size
);
438 if (block_ptr
== NULL
) fatal_error(filename
, line
, size
);
439 #ifdef MEMORY_DEBUG_ADDRESS
440 check_memory_address(block_ptr
, 1);
442 block_ptr
->filename
= filename
;
443 block_ptr
->lineno
= line
;
444 block_ptr
->size
= size
;
445 add_to_list(block_ptr
);
446 set_magic_values(block_ptr
);
447 new_ptr
= &block_ptr
->begin
;
448 total_allocated
+= size
;
450 allocated_size
+= size
;
451 if (peak_size
< allocated_size
) peak_size
= allocated_size
;
453 new_ptr
= realloc(ptr
, size
);
454 if (new_ptr
== NULL
) FATAL_ERROR_INTERNAL(filename
, line
, size
);
466 extern void Free_dbg(const char *filename
, int line
, void *ptr
)
473 memory_block
*block_ptr
= NULL
;
474 block_ptr
= (memory_block
*)(void*)((unsigned char*)ptr
- offset
);
475 #ifdef MEMORY_DEBUG_ADDRESS
476 check_memory_address(block_ptr
, 2);
478 check_magic_values(filename
, line
, block_ptr
, 0);
479 remove_from_list(block_ptr
);
480 allocated_size
-= block_ptr
->size
;
481 memset(ptr
, 0xAA, block_ptr
->size
);
482 #ifdef MEMORY_DEBUG_FREE
483 add_to_free_list(block_ptr
);
494 static const size_t maxprint
= 32;
496 void check_mem_leak(const char *program_name
)
499 fprintf(stderr
, "%s(%d): memory usage statistics:\n"
500 "total allocations: %lu\n"
501 "malloc/new calls: %lu\n"
502 "free/delete calls: %lu\n"
503 "peak memory usage: %lu bytes\n"
504 "average block size: %g bytes\n",
505 program_name
, (int)getpid(),
506 (unsigned long)alloc_count
, (unsigned long)malloc_count
,
507 (unsigned long) free_count
, (unsigned long) peak_size
,
508 (double)total_allocated
/ (double)alloc_count
);
509 if (list_head
!= NULL
) {
510 memory_block
*block_ptr
= list_head
;
512 fprintf(stderr
, "unallocated blocks:\n");
514 if (block_ptr
->filename
!= 0) {
515 fprintf(stderr
, FILENAME_FORMAT
,
516 block_ptr
->filename
, block_ptr
->lineno
);
518 fprintf(stderr
, "\tMemory leak at %p, size %lu, ord %lu: ",
519 (void*)&block_ptr
->begin
, (unsigned long)block_ptr
->size
,
520 (unsigned long)block_ptr
->ordinal
);
522 const unsigned char * mm
= (const unsigned char*)&block_ptr
->begin
;
523 size_t x
, limit
= (block_ptr
->size
> maxprint
) ? maxprint
525 for (x
= 0; x
< limit
; ++x
) {
526 fputc( isprint(mm
[x
]) ? mm
[x
] : '.', stderr
);
530 block_ptr
= block_ptr
->next
;
532 } while (block_ptr
!= NULL
);
533 fprintf(stderr
, "total unallocated: %lu bytes in %lu blocks\n",
534 (unsigned long) allocated_size
, (unsigned long) counter
);
536 #ifdef MEMORY_DEBUG_FREE
538 release_free_blocks();
541 if (malloc_count
!= free_count
) {
542 fprintf(stderr
, "%s: warning: memory leakage detected.\n"
543 "Total malloc calls: %lu, free calls: %lu\n"
544 "Please submit a bug report including the current input file(s).\n",
546 (unsigned long) malloc_count
, (unsigned long) free_count
);
552 void check_mem_corrupt(const char *program_name
)
555 memory_block
*block_ptr
;
556 fprintf(stderr
, "%s: checking memory blocks for corruption\n",
558 for (block_ptr
= list_head
; block_ptr
!= NULL
; block_ptr
= block_ptr
->next
)
560 unsigned char *ptr
= (unsigned char*)&block_ptr
->begin
;
561 if (memcmp(ptr
- sizeof(block_ptr
), &block_ptr
, sizeof(block_ptr
))) {
562 fprintf(stderr
, "Fatal error: memory corruption detected in front "
563 "of pointer %p\n", ptr
);
566 if (memcmp(ptr
+ block_ptr
->size
, &block_ptr
, sizeof(block_ptr
))) {
567 fprintf(stderr
, "Fatal error: memory corruption detected at the "
568 "end of pointer %p\n", ptr
);
573 fprintf(stderr
, "%s: %lu memory block%s OK\n", program_name
,
574 (unsigned long) counter
, counter
> 1 ? "s are" : " is");
575 #ifdef MEMORY_DEBUG_FREE
581 /** @brief Find the string length of an expstring_t
583 Finds the length of the C string pointed at by \p str, using some assumptions
584 satisfied by an expstring_t.
586 @pre There is an offset from the beginning of the string which is a power
587 of two, is within the buffer allocated for \p str and it contains '\\0'
588 @pre The allocated buffer is at most twice as long as strlen(str)
589 @pre \p bufsize is a valid pointer
591 @param [in] str an expstring_t, must not be null
592 @param [out] bufsize pointer to a location where the minimum buffer size
593 (always a power of two) is deposited.
594 @return the length of \p str as a C string
596 static size_t fast_strlen(const expstring_t str
, size_t *bufsize
)
598 size_t size
, min
, max
;
599 /* Find the 0 byte at the end of the allocated buffer */
600 for (size
= 1; str
[size
- 1] != '\0'; size
*= 2) {}
602 if (size
== 1) return 0;
603 /* Binary search the second half of the buffer */
606 while (max
- min
> 1) {
607 size_t med
= (min
+ max
) / 2;
608 if (str
[med
] != '\0') min
= med
;
614 /** @brief Find the first power of two which is greater than \p len
616 * @param len the desired length
617 * @return a power of 2 greater than \p len
619 * \p len is taken to be the number of characters needed. The returned value
620 * will always be greater than \p len to accommodate the null terminator.
622 static size_t roundup_size(size_t len
)
625 for (size
= 1; len
>= size
; size
*= 2);
630 expstring_t
mprintf_va_list(const char *fmt
, va_list pvar
)
632 return mprintf_va_list_dbg(0,0,fmt
,pvar
);
635 expstring_t
mprintf_va_list_dbg(const char *filename
, int line
, const char *fmt
, va_list pvar
)
637 expstring_t
mprintf_va_list(const char *fmt
, va_list pvar
)
645 va_copy(pvar2
, pvar
);
646 len
= vsnprintf(buf
, BUFSIZE
, fmt
, pvar2
);
649 /* The result does not fit in buf and we have no idea how many bytes
650 * are needed (only old versions of libc may return -1).
651 * Try to double the buffer size until it is large enough. */
652 for (size
= 2 * BUFSIZE
; ; size
*= 2) {
653 ptr
= (expstring_t
)MALLOC_INTERNAL(filename
, line
, size
);
654 va_copy(pvar2
, pvar
);
655 len
= vsnprintf(ptr
, size
, fmt
, pvar2
);
657 if (len
>= 0 && (size_t)len
< size
) break;
658 FREE_INTERNAL(filename
, line
, ptr
);
661 } else if (len
>= BUFSIZE
) {
662 /* The result does not fit in buf, but we know how many bytes we need.
663 * Allocate a buffer that is large enough and repeat vsnprintf() */
665 size
= roundup_size(slen
);
666 ptr
= (expstring_t
)MALLOC_INTERNAL(filename
, line
, size
);
667 /* use the original pvar since this is the last try */
668 if (vsnprintf(ptr
, size
, fmt
, pvar
) != len
) {
669 perror("Fatal error: unexpected vsnprintf() return value");
673 /* the complete result is in buf */
675 size
= roundup_size(slen
);
676 ptr
= (expstring_t
)MALLOC_INTERNAL(filename
, line
, size
);
677 memcpy(ptr
, buf
, slen
);
679 memset(ptr
+ slen
, '\0', size
- slen
);
684 expstring_t
mprintf_dbg(const char *filename
, int line
, const char *fmt
, ...)
689 ptr
= mprintf_va_list_dbg(filename
, line
, fmt
, pvar
);
695 expstring_t
mprintf(const char *fmt
, ...)
700 ptr
= mprintf_va_list(fmt
, pvar
);
705 /* Tracking the origin: extracts the filename/line from the original allocation
706 * of the expstring_t. */
707 expstring_t
mputprintf_va_list(expstring_t str
, const char *fmt
, va_list pvar
)
709 const char *filename
= NULL
;
713 size_t len
= fast_strlen(str
, &size
);
714 size_t rest
= size
- len
;
717 /* make a copy of pvar to allow re-use later */
718 va_copy(pvar2
, pvar
);
719 len2
= vsnprintf(str
+ len
, rest
, fmt
, pvar2
);
721 extract_location(str
, &filename
, &line
);
723 /* the result does not fit in buf and we have no idea how many
724 * bytes are needed (only old versions of libc may return -1)
725 * try to double the buffer size until it is large enough */
729 str
= (expstring_t
)REALLOC_INTERNAL(filename
, line
, str
, size
);
731 va_copy(pvar2
, pvar
);
732 len2
= vsnprintf(str
+ len
, rest
, fmt
, pvar2
);
734 } while (len2
< 0 || (size_t)len2
>= rest
);
735 newlen
= len
+ (size_t)len2
;
736 memset(str
+ newlen
, '\0', size
- newlen
);
737 } else if ((size_t)len2
>= rest
) {
738 /* there isn't enough space in buffer, but we know how many bytes
739 * we need: reallocate the buffer to be large enough and repeat
741 size_t newlen
= len
+ (size_t)len2
;
742 size
= roundup_size(newlen
);
743 str
= (expstring_t
)REALLOC_INTERNAL(filename
, line
, str
, size
);
744 /* use the original pvar since this is the last try */
745 if (vsnprintf(str
+ len
, size
- len
, fmt
, pvar
) != len2
) {
746 perror("Fatal error: unexpected vsnprintf() return value");
749 memset(str
+ newlen
, '\0', size
- newlen
);
751 } else str
= MPRINTF_VA_LIST_INTERNAL(filename
, line
, fmt
, pvar
);
755 expstring_t
mputprintf(expstring_t str
, const char *fmt
, ...)
759 str
= mputprintf_va_list(str
, fmt
, pvar
);
765 expstring_t
memptystr(void)
767 return memptystr_dbg(0,0);
770 expstring_t
memptystr_dbg(const char *filename
, int line
)
772 expstring_t
memptystr(void)
775 expstring_t ptr
= (expstring_t
)MALLOC_INTERNAL(filename
, line
, 1);
781 expstring_t
mcopystr(const char *str
)
783 return mcopystr_dbg(0,0,str
);
786 expstring_t
mcopystr_dbg(const char *filename
, int line
, const char *str
)
788 expstring_t
mcopystr(const char *str
)
792 size_t len
= strlen(str
);
793 size_t size
= roundup_size(len
);
794 expstring_t ptr
= (expstring_t
)MALLOC_INTERNAL(filename
, line
, size
);
795 memcpy(ptr
, str
, len
);
796 memset(ptr
+ len
, '\0', size
- len
);
798 } else return MEMPTYSTR_INTERNAL(filename
, line
);
802 expstring_t
mcopystrn(const char *str
, size_t len
)
804 return mcopystrn_dbg(0,0,str
, len
);
807 expstring_t
mcopystrn_dbg(const char *filename
, int line
, const char *str
,
810 expstring_t
mcopystrn(const char *str
, size_t len
)
813 if (len
!= 0 && str
!= NULL
) {
814 size_t size
= roundup_size(len
);
815 expstring_t ptr
= (expstring_t
)MALLOC_INTERNAL(filename
, line
, size
);
816 memcpy(ptr
, str
, len
);
817 memset(ptr
+ len
, '\0', size
- len
);
819 } else return MEMPTYSTR_INTERNAL(filename
, line
);
822 /* Tracking the origin: extracts the filename/line from the original allocation
823 * of the expstring_t. */
824 expstring_t
mputstr(expstring_t str
, const char *str2
)
826 const char *filename
= NULL
;
831 size_t len
= fast_strlen(str
, &size
);
832 size_t len2
= strlen(str2
);
833 size_t newlen
= len
+ len2
;
834 if (size
<= newlen
) {
835 size_t newsize
= roundup_size(newlen
);
836 extract_location(str
, &filename
, &line
);
837 str
= (expstring_t
)REALLOC_INTERNAL(filename
, line
, str
, newsize
);
838 memset(str
+ newlen
, '\0', newsize
- newlen
);
840 memcpy(str
+ len
, str2
, len2
);
841 } else str
= MCOPYSTR_INTERNAL(filename
, line
, str2
);
846 /* Tracking the origin: extracts the filename/line from the original allocation
847 * of the expstring_t. */
848 expstring_t
mputstrn(expstring_t str
, const char *str2
, size_t len2
)
850 const char *filename
= NULL
;
852 if (len2
!= 0 && str2
!= NULL
) {
855 size_t len
= fast_strlen(str
, &size
);
856 size_t newlen
= len
+ len2
;
857 if (size
<= newlen
) {
858 size_t newsize
= roundup_size(newlen
);
859 extract_location(str
, &filename
, &line
);
860 str
= (expstring_t
)REALLOC_INTERNAL(filename
, line
, str
, newsize
);
861 memset(str
+ newlen
, '\0', newsize
- newlen
);
863 memcpy(str
+ len
, str2
, len2
);
864 } else str
= MCOPYSTR_INTERNAL(filename
, line
, str2
);
869 /* Tracking the origin: extracts the filename/line from the original allocation
870 * of the expstring_t. */
871 expstring_t
mputc(expstring_t str
, char c
)
873 const char *filename
= NULL
;
878 size_t len
= fast_strlen(str
, &size
);
879 if (size
<= len
+ 1) {
880 extract_location(str
, &filename
, &line
);
881 str
= (expstring_t
)REALLOC_INTERNAL(filename
, line
, str
, 2 * size
);
882 memset(str
+ size
, '\0', size
);
888 str
= (expstring_t
)MALLOC_INTERNAL(filename
, line
, 2);
891 } else str
= MEMPTYSTR_INTERNAL(filename
, line
);
896 /* Tracking the origin: extracts the filename/line from the original allocation
897 * of the expstring_t. */
898 expstring_t
mtruncstr(expstring_t str
, size_t newlen
)
900 const char *filename
= NULL
;
904 size_t len
= fast_strlen(str
, &size
);
906 size_t newsize
= roundup_size(newlen
);
907 if (newsize
< size
) {
908 extract_location(str
, &filename
, &line
);
909 str
= (expstring_t
)REALLOC_INTERNAL(filename
, line
, str
, newsize
);
911 memset(str
+ newlen
, '\0', newsize
- newlen
);
917 size_t mstrlen(const expstring_t str
)
921 return fast_strlen(str
, &size
);
925 char * buildstr(int b
) {
926 if (b
< 0 || b
> 99) return NULL
; /* invalid */
927 if (b
== 99) return memptystr(); /* empty string for full version */
928 return mprintf("%02d", b
);
This page took 0.049629 seconds and 6 git commands to generate.