fis-gtm/sr_port/gtm_maxstr.c

78 lines
3.2 KiB
C

/****************************************************************
* *
* Copyright 2001, 2003 Sanchez Computer Associates, Inc. *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
#include "mdef.h"
#include "gtm_string.h"
#include "error.h"
#include "gtm_maxstr.h"
/* GT.M string buffer stack where each entry is allocated geometrically on the need basis */
GBLDEF mstr maxstr_buff[MAXSTR_STACK_SIZE];
GBLDEF int maxstr_stack_level = -1;
/* This handler is to release the heap storage allocated within a function in case of errors.
* The suggested protocol is that after a function is done with using the string buffer, the macro
* MAXSTR_BUFF_FINI used in the function epilog releases the malloc'd storage. But if an error
* occurs within the function body, the function epilog is not executed so this condition handler
* should do the same so that the storage is not kept dangling. */
CONDITION_HANDLER(gtm_maxstr_ch)
{
START_CH;
if (maxstr_buff[maxstr_stack_level].addr)
{
free(maxstr_buff[maxstr_stack_level].addr);
maxstr_buff[maxstr_stack_level].addr = NULL;
}
maxstr_buff[maxstr_stack_level].len = 0;
maxstr_stack_level--;
NEXTCH;
}
/* The routine checks if the currently available buffer (either 32K automatic or >32K malloc'd)
* is sufficient for the new space requirement. If not sufficient, it keeps doubling the buffer size
* and checks until a new buffer size is large enough to accommodate the incoming string. It then
* allocates the new buffer and releases the previously malloc'd buffer.
* Note that if strings fit within 32K, the automating buffer is used and no heap storage is used.
* Parameters:
*
* space_needed - buffer space needed to accommodate the string that is about to be written
* buff - address of the pointer to the beginning of the buffer. If reallocation occurs, buff will be
* modified to point to the reallocated buffer.
* space_occupied - how full is the buffer?
*
* Returns the new allocated buffer size.
*/
int gtm_maxstr_alloc(int space_needed, char** buff, int space_occupied)
{
int new_buff_size;
if (space_needed > (maxstr_buff[maxstr_stack_level].len - space_occupied))
{ /* Existing buffer is not sufficient. reallocate the buffer with the double the size */
new_buff_size = maxstr_buff[maxstr_stack_level].len;
while (space_needed > new_buff_size - space_occupied)
new_buff_size += new_buff_size;
if (NULL != maxstr_buff[maxstr_stack_level].addr)
{
assert(maxstr_buff[maxstr_stack_level].addr == *buff);
maxstr_buff[maxstr_stack_level].addr = (char *)malloc(new_buff_size);
memcpy(maxstr_buff[maxstr_stack_level].addr, *buff, space_occupied);
free(*buff);
} else
{
maxstr_buff[maxstr_stack_level].addr = (char *)malloc(new_buff_size);
memcpy(maxstr_buff[maxstr_stack_level].addr, *buff, space_occupied);
}
*buff = maxstr_buff[maxstr_stack_level].addr;
maxstr_buff[maxstr_stack_level].len = new_buff_size;
}
return maxstr_buff[maxstr_stack_level].len;
}