78 lines
3.2 KiB
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;
|
||
|
}
|