/*
** Copyright (c) 1994, University of Kansas, All Rights Reserved
**
** This code will be used only if LY_FIND_LEAKS is defined.
*/
/*
** Disable the overriding of the memory routines for this file.
*/
#define NO_MEMORY_TRACKING
#include <HTUtils.h>
#include <LYexit.h>
#include <LYLeaks.h>
#include <LYUtils.h>
PRIVATE AllocationList *ALp_RunTimeAllocations = NULL;
PRIVATE void AddToList PARAMS((
AllocationList * ALp_new));
PRIVATE AllocationList *FindInList PARAMS((
void * vp_find));
PRIVATE void RemoveFromList PARAMS((
AllocationList * ALp_del));
/*
** Purpose: Print a report of all memory left unallocated by
** Lynx code or attempted unallocations on
** pointers that are not valid and then free
** all unfreed memory.
** Arguments: void
** Return Value: void
** Remarks/Portability/Dependencies/Restrictions:
** This function should be registered for execution with the
** atexit (stdlib.h) function as the first statement
** in main.
** All output of this function is sent to the file defined in
** the header LYLeaks.h (LEAKAGE_SINK).
** Revision History:
** 05-26-94 created Lynx 2-3-1 Garrett Arch Blythe
** 10-30-97 modified to handle StrAllocCopy() and
** StrAllocCat(). - KW & FM
*/
PUBLIC void LYLeaks NOARGS
{
AllocationList *ALp_head;
size_t st_total = (size_t)0;
FILE *Fp_leakagesink;
/*
* Open the leakage sink to take all the output.
* Recreate the file each time.
* Do nothing if unable to open the file.
*/
Fp_leakagesink = LYNewTxtFile(LEAKAGE_SINK);
if (Fp_leakagesink == NULL) {
return;
}
while (ALp_RunTimeAllocations != NULL) {
/*
* Take the head off of the run time allocation list.
*/
ALp_head = ALp_RunTimeAllocations;
ALp_RunTimeAllocations = ALp_head->ALp_Next;
/*
* Print the type of leak/error.
* Free off memory when we no longer need it.
*/
if (ALp_head->vp_Alloced == NULL) {
/*
* If there is realloc information on the
* bad request, then it was a bad pointer
* value in a realloc statement.
*/
fprintf(Fp_leakagesink, "%s.\n",
gettext("Invalid pointer detected."));
fprintf(Fp_leakagesink, "%s\t%p\n",
gettext("Pointer:"), ALp_head->vp_BadRequest);
/*
* Don't free the bad request, it is an invalid pointer.
* If the free source information is empty, we
* should check the realloc information
* too since it can get passed bad pointer
* values also.
*/
if (ALp_head->SL_memory.cp_FileName == NULL) {
fprintf(Fp_leakagesink, "%s\t%s\n",
gettext("FileName:"),
ALp_head->SL_realloc.cp_FileName);
fprintf(Fp_leakagesink, "%s\t%d\n",
gettext("LineCount:"),
ALp_head->SL_realloc.ssi_LineNumber);
} else {
fprintf(Fp_leakagesink, "%s\t%s\n",
gettext("FileName:"),
ALp_head->SL_memory.cp_FileName);
fprintf(Fp_leakagesink, "%s\t%d\n",
gettext("LineCount:"),
ALp_head->SL_memory.ssi_LineNumber);
}
} else {
size_t i_counter;
char *value = (char *)(ALp_head->vp_Alloced);
/*
* Increment the count of total memory lost and
* then print the information.
*/
st_total += ALp_head->st_Bytes;
fprintf(Fp_leakagesink, "%s\n",
gettext("Memory leak detected."));
fprintf(Fp_leakagesink, "%s\t%p\n",
gettext("Pointer:"),
ALp_head->vp_Alloced);
fprintf(Fp_leakagesink, "%s\t",
gettext("Contains:"));
for (i_counter = 0;
i_counter < ALp_head->st_Bytes &&
i_counter < MAX_CONTENT_LENGTH;
i_counter++) {
if (isprint(value[i_counter])) {
fprintf(Fp_leakagesink, "%c", value[i_counter]);
} else {
fprintf(Fp_leakagesink, "|");
}
}
fprintf(Fp_leakagesink, "\n");
fprintf(Fp_leakagesink, "%s\t%d\n",
gettext("ByteSize:"),
(int)(ALp_head->st_Bytes));
fprintf(Fp_leakagesink, "%s\t%s\n",
gettext("FileName:"),
ALp_head->SL_memory.cp_FileName);
fprintf(Fp_leakagesink, "%s\t%d\n",
gettext("LineCount:"),
ALp_head->SL_memory.ssi_LineNumber);
/*
* Give the last time the pointer was realloced
* if it happened also.
*/
if (ALp_head->SL_realloc.cp_FileName != NULL) {
fprintf(Fp_leakagesink, "%s\t%s\n",
gettext("realloced:"),
ALp_head->SL_realloc.cp_FileName);
fprintf(Fp_leakagesink, "%s\t%d\n",
gettext("LineCount:"),
ALp_head->SL_realloc.ssi_LineNumber);
}
fflush(Fp_leakagesink);
FREE(ALp_head->vp_Alloced);
}
/*
* Create a blank line and release the memory held
* by the item.
*/
fprintf(Fp_leakagesink, "\n");
FREE(ALp_head);
}
/*
* Give a grand total of the leakage.
* Close the output file.
*/
fprintf(Fp_leakagesink, "\n%s\t%u\n",
gettext("Total memory leakage this run:"),
(unsigned)st_total);
fclose(Fp_leakagesink);
HTSYS_purge(LEAKAGE_SINK);
}
/*
** Purpose: Capture allocations using malloc (stdlib.h) and track
** the information in a list.
** Arguments: st_bytes The size of the allocation requested
** in bytes.
** cp_File The file from which the request for
** allocation came from.
** ssi_Line The line number in cp_File where the
** allocation request came from.
** Return Value: void * A pointer to the allocated memory or NULL on
** failure as per malloc (stdlib.h)
** Remarks/Portability/Dependencies/Restrictions:
** If no memory is allocated, then no entry is added to the
** allocation list.
** Revision History:
** 05-26-94 created Lynx 2-3-1 Garrett Arch Blythe
*/
PUBLIC void *LYLeakMalloc ARGS3(
size_t, st_bytes,
CONST char *, cp_File,
CONST short, ssi_Line)
{
/*
* Do the actual allocation.
*/
void *vp_malloc = (void *)malloc(st_bytes);
/*
* Only on successful allocation do we track any information.
*/
if (vp_malloc != NULL) {
/*
* Further allocate memory to store the information.
* Just return on failure to allocate more.
*/
AllocationList *ALp_new =
(AllocationList *)calloc(1, sizeof(AllocationList));
if (ALp_new == NULL) {
return(vp_malloc);
}
/*
* Copy over the relevant information.
* There is no need to allocate more memory for the
* file name as it is a static string anyhow.
*/
ALp_new->vp_Alloced = vp_malloc;
ALp_new->st_Bytes = st_bytes;
ALp_new->SL_memory.cp_FileName = cp_File;
ALp_new->SL_memory.ssi_LineNumber = ssi_Line;
/*
* Add the new item to the allocation list.
*/
AddToList(ALp_new);
}
return(vp_malloc);
}
/*
** Purpose: Add information about new allocation to the list,
** after a call to malloc or calloc or an equivalent
** function which may or may not have already created
** a list entry.
** Arguments: vp_malloc The pointer to newly allocate memory.
** Arguments: st_bytes The size of the allocation requested
** in bytes.
** cp_File The file from which the request for
** allocation came from.
** ssi_Line The line number in cp_File where the
** allocation request came from.
** Return Value: void * A pointer to the allocated memory or NULL on
** failure.
** Remarks/Portability/Dependencies/Restrictions:
** If no memory is allocated, then no entry is added to the
** allocation list.
** Revision History:
** 1999-02-08 created, modelled after LYLeakMalloc - kw
*/
PUBLIC AllocationList *LYLeak_mark_malloced ARGS4(
void *, vp_malloced,
size_t, st_bytes,
CONST char *, cp_File,
CONST short, ssi_Line)
{
AllocationList *ALp_new = NULL;
/*
* The actual allocation has already been done!
*
* Only on successful allocation do we track any information.
*/
if (vp_malloced != NULL) {
/*
* See if there is already an entry. If so, just
* update the source location info.
*/
ALp_new = FindInList(vp_malloced);
if (ALp_new) {
ALp_new->SL_memory.cp_FileName = cp_File;
ALp_new->SL_memory.ssi_LineNumber = ssi_Line;
return(ALp_new);
}
/*
* Further allocate memory to store the information.
* Just return on failure to allocate more.
*/
ALp_new = (AllocationList *)calloc(1, sizeof(AllocationList));
if (ALp_new == NULL) {
return(NULL);
}
/*
* Copy over the relevant information.
*/
ALp_new->vp_Alloced = vp_malloced;
ALp_new->st_Bytes = st_bytes;
ALp_new->SL_memory.cp_FileName = cp_File;
ALp_new->SL_memory.ssi_LineNumber = ssi_Line;
/*
* Add the new item to the allocation list.
*/
AddToList(ALp_new);
}
return(ALp_new);
}
/*
** Purpose: Capture allocations by calloc (stdlib.h) and
** save relevant information in a list.
** Arguments: st_number The number of items to allocate.
** st_bytes The size of each item.
** cp_File The file which wants to allocation.
** ssi_Line The line number in cp_File requesting
** the allocation.
** Return Value: void * The allocated memory, or NULL on failure as
** per calloc (stdlib.h)
** Remarks/Portability/Dependencies/Restrictions:
** If no memory can be allocated, then no entry will be added
** to the list.
** Revision History:
** 05-26-94 created Lynx 2-3-1 Garrett Arch Blythe
*/
PUBLIC void *LYLeakCalloc ARGS4(
size_t, st_number,
size_t, st_bytes,
CONST char *, cp_File,
CONST short, ssi_Line)
{
/*
* Allocate the requested memory.
*/
void *vp_calloc = (void *)calloc(st_number, st_bytes);
/*
* Only if the allocation was a success do we track information.
*/
if (vp_calloc != NULL) {
/*
* Allocate memory for the item to be in the list.
* If unable, just return.
*/
AllocationList *ALp_new =
(AllocationList *)calloc(1, sizeof(AllocationList));
if (ALp_new == NULL) {
return(vp_calloc);
}
/*
* Copy over the relevant information.
* There is no need to allocate memory for the file
* name as it is a static string anyway.
*/
ALp_new->vp_Alloced = vp_calloc;
ALp_new->st_Bytes = (st_number * st_bytes);
ALp_new->SL_memory.cp_FileName = cp_File;
ALp_new->SL_memory.ssi_LineNumber = ssi_Line;
/*
* Add the item to the allocation list.
*/
AddToList(ALp_new);
}
return(vp_calloc);
}
/*
** Purpose: Capture any realloc (stdlib.h) calls in order to
** properly keep track of our run time allocation
** table.
** Arguments: vp_Alloced The previously allocated block of
** memory to resize. If NULL,
** realloc works just like
** malloc.
** st_newBytes The new size of the chunk of memory.
** cp_File The file containing the realloc.
** ssi_Line The line containing the realloc in cp_File.
** Return Value: void * The new pointer value (could be the same) or
** NULL if unable to resize (old block
** still exists).
** Remarks/Portability/Dependencies/Restrictions:
** If unable to resize vp_Alloced, then no change in the
** allocation list will be made.
** If vp_Alloced is an invalid pointer value, the program will
** exit after one last entry is added to the allocation list.
** Revision History:
** 05-26-94 created Lynx 2-3-1 Garrett Arch Blythe
*/
PUBLIC void *LYLeakRealloc ARGS4(
void *, vp_Alloced,
size_t, st_newBytes,
CONST char *, cp_File,
CONST short, ssi_Line)
{
void *vp_realloc;
AllocationList *ALp_renew;
/*
* If we are asked to resize a NULL pointer, this is just a
* malloc call.
*/
if (vp_Alloced == NULL) {
return(LYLeakMalloc(st_newBytes, cp_File, ssi_Line));
}
/*
* Find the current vp_Alloced block in the list.
* If NULL, this is an invalid pointer value.
*/
ALp_renew = FindInList(vp_Alloced);
if (ALp_renew == NULL) {
/*
* Track the invalid pointer value and then exit.
* If unable to allocate, just exit.
*/
auto AllocationList *ALp_new =
(AllocationList *)calloc(1,
sizeof(AllocationList));
if (ALp_new == NULL) {
exit(-1);
}
/*
* Set the information up; no need to allocate file name
* since it is a static string.
*/
ALp_new->vp_Alloced = NULL;
ALp_new->vp_BadRequest = vp_Alloced;
ALp_new->SL_realloc.cp_FileName = cp_File;
ALp_new->SL_realloc.ssi_LineNumber = ssi_Line;
/*
* Add the item to the list.
* Exit.
*/
AddToList(ALp_new);
exit(-1);
}
/*
* Perform the resize.
* If not NULL, record the information.
*/
vp_realloc = (void *)realloc(vp_Alloced, st_newBytes);
if (vp_realloc != NULL) {
ALp_renew->vp_Alloced = vp_realloc;
ALp_renew->st_Bytes = st_newBytes;
/*
* Update the realloc information, too.
* No need to allocate file name, static string.
*/
ALp_renew->SL_realloc.cp_FileName = cp_File;
ALp_renew->SL_realloc.ssi_LineNumber = ssi_Line;
}
return(vp_realloc);
}
/*
** Purpose: Add information about reallocated memory to the list,
** after a call to realloc or an equivalent
** function which has not already created or updated
** a list entry.
** Arguments: ALp_old List entry for previously allocated
** block of memory to resize. If NULL,
** mark_realloced works just like
** mark_malloced.
** vp_realloced The new pointer, after resizing.
** st_newBytes The new size of the chunk of memory.
** cp_File The file to record.
** ssi_Line The line to record.
** Return Value: Pointer to new or updated list entry
** for this memory block.
** NULL on allocation error.
** Revision History:
** 1999-02-11 created kw
*/
#if defined(LY_FIND_LEAKS) && defined(LY_FIND_LEAKS_EXTENDED)
PRIVATE AllocationList *mark_realloced ARGS5(
AllocationList *, ALp_old,
void *, vp_realloced,
size_t, st_newBytes,
CONST char *, cp_File,
CONST short, ssi_Line)
{
/*
* If there is no list entry for the old allocation, treat this
* as if a new allocation had happened.
*/
if (ALp_old == NULL) {
return(LYLeak_mark_malloced(
vp_realloced, st_newBytes, cp_File, ssi_Line));
}
/*
* ALp_old represents the memory block before reallocation.
* Assume that if we get here, there isn't yet a list entry
* for the new, possibly different, address after realloc,
* that is our list hasn't been updated - so we're going to
* do that now.
*/
if (vp_realloced != NULL) {
ALp_old->vp_Alloced = vp_realloced;
ALp_old->st_Bytes = st_newBytes;
ALp_old->SL_realloc.cp_FileName = cp_File;
ALp_old->SL_realloc.ssi_LineNumber = ssi_Line;
}
return(ALp_old);
}
#endif /* not LY_FIND_LEAKS and LY_FIND_LEAKS_EXTENDED */
/*
** Purpose: Capture all requests to free information and also
** remove items from the allocation list.
** Arguments: vp_Alloced The memory to free.
** cp_File The file calling free.
** ssi_Line The line of cp_File calling free.
** Return Value: void
** Remarks/Portability/Dependencies/Restrictions:
** If the pointer value is invalid, then an item will be added
** to the list and nothing else is done.
** I really like the name of this function and one day hope
** that Lynx is Leak Free.
** Revision History:
** 05-26-94 created Lynx 2-3-1 Garrett Arch Blythe
*/
PUBLIC void LYLeakFree ARGS3(
void *, vp_Alloced,
CONST char *, cp_File,
CONST short, ssi_Line)
{
AllocationList *ALp_free;
/*
* Find the pointer in the allocated list.
* If not found, bad pointer.
* If found, free list item and vp_Allloced.
*/
ALp_free = FindInList(vp_Alloced);
if (ALp_free == NULL) {
/*
* Create the final entry before exiting marking this error.
* If unable to allocate more memory just exit.
*/
AllocationList *ALp_new =
(AllocationList *)calloc(1,
sizeof(AllocationList));
if (ALp_new == NULL) {
exit(-1);
}
/*
* Set up the information, no memory need be allocated
* for the file name since it is a static string.
*/
ALp_new->vp_Alloced = NULL;
ALp_new->vp_BadRequest = vp_Alloced;
ALp_new->SL_memory.cp_FileName = cp_File;
ALp_new->SL_memory.ssi_LineNumber = ssi_Line;
/*
* Add the entry to the list and then return.
*/
AddToList(ALp_new);
return;
} else {
/*
* Free off the memory.
* Take entry out of allocation list.
*/
RemoveFromList(ALp_free);
FREE(ALp_free);
FREE(vp_Alloced);
}
}
/*
** Allocates a new copy of a string, and returns it.
** Tracks allocations by using other LYLeakFoo functions.
** Equivalent to HTSACopy in HTUtils.c - KW
*/
PUBLIC char * LYLeakSACopy ARGS4(
char **, dest,
CONST char *, src,
CONST char *, cp_File,
CONST short, ssi_Line)
{
if (src != NULL && src == *dest) {
CTRACE((tfp,
"LYLeakSACopy: *dest equals src, contains \"%s\"\n",
src));
return *dest;
}
if (*dest) {
LYLeakFree(*dest, cp_File, ssi_Line);
*dest = NULL;
}
if (src) {
*dest = (char *)LYLeakMalloc(strlen(src) + 1, cp_File, ssi_Line);
if (*dest == NULL)
outofmem(__FILE__, "LYLeakSACopy");
strcpy (*dest, src);
}
return *dest;
}
/*
** String Allocate and Concatenate.
** Tracks allocations by using other LYLeakFoo functions.
** Equivalent to HTSACat in HTUtils.c - KW
*/
PUBLIC char * LYLeakSACat ARGS4(
char **, dest,
CONST char *, src,
CONST char *, cp_File,
CONST short, ssi_Line)
{
if (src && *src) {
if (src == *dest) {
CTRACE((tfp,
"LYLeakSACat: *dest equals src, contains \"%s\"\n",
src));
return *dest;
}
if (*dest) {
int length = strlen(*dest);
*dest = (char *)LYLeakRealloc(*dest,
(length + strlen(src) + 1),
cp_File,
ssi_Line);
if (*dest == NULL)
outofmem(__FILE__, "LYLeakSACat");
strcpy (*dest + length, src);
} else {
*dest = (char *)LYLeakMalloc((strlen(src) + 1),
cp_File,
ssi_Line);
if (*dest == NULL)
outofmem(__FILE__, "LYLeakSACat");
strcpy (*dest, src);
}
}
return *dest;
}
#if defined(LY_FIND_LEAKS) && defined(LY_FIND_LEAKS_EXTENDED)
PUBLIC CONST char * leak_cp_File_hack = __FILE__;
PUBLIC short leak_ssi_Line_hack = __LINE__;
/*
** Purpose: A wrapper around StrAllocVsprintf (the workhorse of
** HTSprintf/HTSprintf0, implemented in HTString.c) that
** tries to make sure that our allocation list is always
** properly updated, whether StrAllocVsprintf itself was
** compiled with memory tracking or not (or even a mixture,
** like tracking the freeing but not the new allocation).
** Some source files can be compiled with LY_FIND_LEAKS_EXTENDED
** in effect while others only have LY_FIND_LEAKS in effect,
** and as long as HTString.c is complied with memory tracking
** (of either kind) string objects allocated by HTSprintf/
** HTSprintf0 (or otherwise) can be passed around among them and
** manipulated both ways.
** Arguments: dest As for StrAllocVsprintf.
** cp_File The source file of the caller (i.e. the
** caller of HTSprintf/HTSprintf0, hopefully).
** ssi_Line The line of cp_File calling.
** inuse,fmt,ap As for StrAllocVsprintf.
** Return Value: The char pointer to resulting string, as set
** by StrAllocVsprintf, or
** NULL if dest==0 (wrong use!).
** Remarks/Portability/Dependencies/Restrictions:
** The price for generality is severe inefficiency: several
** list lookups are done to be on the safe side.
** We don't get he real allocation size, only a minimum based
** on the string length of the result. So the amount of memory
** leakage may get underestimated.
** If *dest is an invalid pointer value on entry (i.e. was not
** tracked), the program will exit after one last entry is added
** to the allocation list.
** If StrAllocVsprintf fails to return a valid string via the
** indirect string pointer (its first parameter), invalid memory
** access will result and the program will probably terminate
** with a signal. This can happen if, on entry, *dest is NULL
** and fmt is empty or NULL, so just Don't Do That.
** Revision History:
** 1999-02-11 created kw
** 1999-10-15 added comments kw
*/
PRIVATE char * LYLeakSAVsprintf ARGS6(
char **, dest,
CONST char *, cp_File,
CONST short, ssi_Line,
size_t, inuse,
CONST char *, fmt,
va_list *, ap)
{
AllocationList *ALp_old;
void *vp_oldAlloced;
CONST char * old_cp_File = __FILE__;
short old_ssi_Line = __LINE__;
if (!dest)
return NULL;
vp_oldAlloced = *dest;
if (!vp_oldAlloced) {
StrAllocVsprintf(dest, inuse, fmt, ap);
LYLeak_mark_malloced(*dest, strlen(*dest) + 1, cp_File, ssi_Line);
return(*dest);
} else {
void * vp_realloced;
ALp_old = FindInList(vp_oldAlloced);
if (ALp_old == NULL) {
/*
* Track the invalid pointer value and then exit.
* If unable to allocate, just exit.
*/
auto AllocationList *ALp_new =
(AllocationList *)calloc(1,
sizeof(AllocationList));
if (ALp_new == NULL) {
exit(-1);
}
/*
* Set the information up; no need to allocate file name
* since it is a static string.
*/
ALp_new->vp_Alloced = NULL;
ALp_new->vp_BadRequest = vp_oldAlloced;
ALp_new->SL_realloc.cp_FileName = cp_File;
ALp_new->SL_realloc.ssi_LineNumber = ssi_Line;
/*
* Add the item to the list.
* Exit.
*/
AddToList(ALp_new);
exit(-1);
}
old_cp_File = ALp_old->SL_memory.cp_FileName;
old_ssi_Line = ALp_old->SL_memory.ssi_LineNumber;
/*
* DO THE REAL WORK, by calling StrAllocVsprintf.
* If result is not NULL, record the information.
*/
StrAllocVsprintf(dest, inuse, fmt, ap);
vp_realloced = (void *)*dest;
if (vp_realloced != NULL) {
AllocationList *ALp_new = FindInList(vp_realloced);
if (!ALp_new) {
/* Look up again, list may have changed! - kw */
ALp_old = FindInList(vp_oldAlloced);
if (ALp_old == NULL) {
LYLeak_mark_malloced(*dest, strlen(*dest) + 1, cp_File, ssi_Line);
return(*dest);
}
mark_realloced(ALp_old, *dest, strlen(*dest) + 1, cp_File, ssi_Line);
return(*dest);
}
if (vp_realloced == vp_oldAlloced) {
ALp_new->SL_memory.cp_FileName = old_cp_File;
ALp_new->SL_memory.ssi_LineNumber = old_ssi_Line;
ALp_new->SL_realloc.cp_FileName = cp_File;
ALp_new->SL_realloc.ssi_LineNumber = ssi_Line;
return(*dest);
}
/* Look up again, list may have changed! - kw */
ALp_old = FindInList(vp_oldAlloced);
if (ALp_old == NULL) {
ALp_new->SL_memory.cp_FileName = old_cp_File;
ALp_new->SL_memory.ssi_LineNumber = old_ssi_Line;
ALp_new->SL_realloc.cp_FileName = cp_File;
ALp_new->SL_realloc.ssi_LineNumber = ssi_Line;
} else {
ALp_new->SL_memory.cp_FileName = old_cp_File;
ALp_new->SL_memory.ssi_LineNumber = old_ssi_Line;
ALp_new->SL_realloc.cp_FileName = cp_File;
ALp_new->SL_realloc.ssi_LineNumber = ssi_Line;
}
}
return(*dest);
}
}
/* Note: the following may need updating if HTSprintf in HTString.c
* is changed. - kw */
#if ANSI_VARARGS
PRIVATE char * LYLeakHTSprintf (char **pstr, CONST char *fmt, ...)
#else
PRIVATE char * LYLeakHTSprintf (va_alist)
va_dcl
#endif
{
char *str;
size_t inuse = 0;
va_list ap;
LYva_start(ap,fmt);
{
#if !ANSI_VARARGS
char ** pstr = va_arg(ap, char **);
CONST char * fmt = va_arg(ap, CONST char *);
#endif
if (pstr != 0 && *pstr != 0)
inuse = strlen(*pstr);
str = LYLeakSAVsprintf(pstr, leak_cp_File_hack, leak_ssi_Line_hack,
inuse, fmt, &ap);
}
va_end(ap);
return str;
}
/* Note: the following may need updating if HTSprintf0 in HTString.c
* is changed. - kw */
#if ANSI_VARARGS
PRIVATE char * LYLeakHTSprintf0 (char **pstr, CONST char *fmt, ...)
#else
PRIVATE char * LYLeakHTSprintf0 (va_alist)
va_dcl
#endif
{
char *str;
va_list ap;
LYva_start(ap,fmt);
{
#if !ANSI_VARARGS
char ** pstr = va_arg(ap, char **);
CONST char * fmt = va_arg(ap, CONST char *);
#endif
str = LYLeakSAVsprintf(pstr, leak_cp_File_hack, leak_ssi_Line_hack,
0, fmt, &ap);
}
va_end(ap);
return str;
}
/*
* HTSprintf and HTSprintf0 will be defined such that they effectively
* call one of the following two functions that store away a copy to
* the File & Line info in temporary hack variables, and then call
* the real function (which is returned here as a function pointer)
* to the regular HTSprintf/HTSprintf0 arguments.
* It's probably a bit inefficient, but that shouldn't be noticeable
* compared to all the time that memory tracking takes up for list
* traversal. - kw
*/
PUBLIC HTSprintflike *Get_htsprintf_fn ARGS2(
CONST char *, cp_File,
CONST short, ssi_Line)
{
leak_cp_File_hack = cp_File;
leak_ssi_Line_hack = ssi_Line;
return &LYLeakHTSprintf;
}
PUBLIC HTSprintflike *Get_htsprintf0_fn ARGS2(
CONST char *, cp_File,
CONST short, ssi_Line)
{
leak_cp_File_hack = cp_File;
leak_ssi_Line_hack = ssi_Line;
return &LYLeakHTSprintf0;
}
#endif /* not LY_FIND_LEAKS and LY_FIND_LEAKS_EXTENDED */
/*
** Purpose: Add a new allocation item to the list.
** Arguments: ALp_new The new item to add.
** Return Value: void
** Remarks/Portability/Dependencies/Restrictions:
** Static function made to make code reusable in projects beyond
** Lynx (some might ask why not use HTList).
** Revision History:
** 05-26-94 created Lynx 2-3-1 Garrett Arch Blythe
*/
PRIVATE void AddToList ARGS1(
AllocationList *, ALp_new)
{
/*
* Just make this the first item in the list.
*/
ALp_new->ALp_Next = ALp_RunTimeAllocations;
ALp_RunTimeAllocations = ALp_new;
}
/*
** Purpose: Find the place in the list where vp_find is currently
** tracked.
** Arguments: vp_find A pointer to look for in the list.
** Return Value: AllocationList * Either vp_find's place in the
** list or NULL if not found.
** Remarks/Portability/Dependencies/Restrictions:
** Static function made to make code reusable in projects outside
** of Lynx (some might ask why not use HTList).
** Revision History:
** 05-26-94 created Lynx 2-3-1 Garrett Arch Blythe
*/
PRIVATE AllocationList *FindInList ARGS1(
void *, vp_find)
{
AllocationList *ALp_find = ALp_RunTimeAllocations;
/*
* Go through the list of allocated pointers until end of list
* or vp_find is found.
*/
while (ALp_find != NULL) {
if (ALp_find->vp_Alloced == vp_find) {
break;
}
ALp_find = ALp_find->ALp_Next;
}
return(ALp_find);
}
/*
** Purpose: Remove the specified item from the list.
** Arguments: ALp_del The item to remove from the list.
** Return Value: void
** Remarks/Portability/Dependencies/Restrictions:
** Static function made to make code reusable in projects outside
** of Lynx (some might ask why not use HTList).
** Revision History:
** 05-26-94 created Lynx 2-3-1 Garrett Arch Blythe
*/
PRIVATE void RemoveFromList ARGS1(
AllocationList *, ALp_del)
{
AllocationList *ALp_findbefore = ALp_RunTimeAllocations;
/*
* There is one special case, where the item to remove is the
* first in the list.
*/
if (ALp_del == ALp_findbefore) {
ALp_RunTimeAllocations = ALp_del->ALp_Next;
return;
}
/*
* Loop through checking all of the next values, if a match
* don't continue. Always assume the item will be found.
*/
while (ALp_findbefore->ALp_Next != ALp_del) {
ALp_findbefore = ALp_findbefore->ALp_Next;
}
/*
* We are one item before the one to get rid of.
* Get rid of it.
*/
ALp_findbefore->ALp_Next = ALp_del->ALp_Next;
}