#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libintl.h>
#include "pkglib.h"
#define ERR_CS_ALLOC "ERROR: Cannot allocate control structure for %s array."
#define ERR_MEM_ALLOC "ERROR: Cannot allocate memory for %s array."
#define MAX_ARRAYS 50
#define ARRAY_END(x) (bl_cs_array[x]->cur_segment->avail_ptr)
#define REC_SIZE(x) (bl_cs_array[x]->struct_size)
#define EOSEG(x) (bl_cs_array[x]->cur_segment->eoseg_ptr)
#define GET_AVAIL(x) (ARRAY_END(x) + REC_SIZE(x))
struct alloc_seg {
char *seg_ptr;
char *avail_ptr;
char *eoseg_ptr;
int full;
struct alloc_seg *next;
};
struct blk_list_cs {
int struct_size;
int count_per_block;
int block_size;
int data_handle;
struct alloc_seg *alloc_segs;
struct alloc_seg *cur_segment;
int total_elem;
int contiguous;
char *desc;
};
static struct blk_list_cs *bl_cs_array[MAX_ARRAYS];
static int next_array_elem;
static int
invalid_handle(int list_handle)
{
if (list_handle < 0 || list_handle >= next_array_elem)
return (1);
return (0);
}
static int
invalid_record(int list_handle, int recno)
{
if (invalid_handle(list_handle))
return (1);
if (recno < 0 || recno > bl_cs_array[list_handle]->total_elem)
return (1);
return (0);
}
static void
free_list(int list_handle)
{
struct blk_list_cs *bl_ptr;
struct alloc_seg *segstr_ptr, *nextstr_ptr;
if (bl_cs_array[list_handle] == NULL)
return;
bl_ptr = bl_cs_array[list_handle];
segstr_ptr = bl_ptr->alloc_segs;
if (segstr_ptr) {
do {
nextstr_ptr = segstr_ptr->next;
free((void *)segstr_ptr->seg_ptr);
free((void *)segstr_ptr);
segstr_ptr = nextstr_ptr;
} while (segstr_ptr);
}
free((void *)bl_ptr->desc);
free((void *)bl_ptr);
bl_cs_array[list_handle] = NULL;
}
static int
alloc_next_seg(struct blk_list_cs *bl_ptr)
{
struct alloc_seg *new_alloc_cs;
if (bl_ptr->contiguous) {
int offset_to_avail, seg_size, new_size;
struct alloc_seg *alloc_segment;
if (bl_ptr->alloc_segs) {
alloc_segment = bl_ptr->alloc_segs;
offset_to_avail = (alloc_segment->avail_ptr -
alloc_segment->seg_ptr);
seg_size = (alloc_segment->eoseg_ptr -
alloc_segment->seg_ptr);
new_size = (seg_size + bl_ptr->block_size);
} else {
if ((bl_ptr->alloc_segs =
(struct alloc_seg *)calloc(1,
sizeof (struct alloc_seg))) == NULL) {
logerr(gettext(ERR_CS_ALLOC), (bl_ptr->desc ?
bl_ptr->desc : "an unknown"));
return (0);
}
alloc_segment = bl_ptr->alloc_segs;
offset_to_avail = 0;
seg_size = 0;
new_size = bl_ptr->block_size;
}
bl_ptr->cur_segment = alloc_segment;
if ((alloc_segment->seg_ptr =
(char *)realloc((void *)alloc_segment->seg_ptr,
(unsigned)new_size)) == NULL) {
logerr(gettext(ERR_MEM_ALLOC), (bl_ptr->desc ?
bl_ptr->desc : "an unknown"));
return (0);
}
alloc_segment->next = NULL;
alloc_segment->full = 0;
alloc_segment->avail_ptr = alloc_segment->seg_ptr +
offset_to_avail;
alloc_segment->eoseg_ptr = alloc_segment->seg_ptr + new_size;
(void) memset(alloc_segment->avail_ptr, '\000',
bl_ptr->block_size);
} else {
if ((new_alloc_cs = (struct alloc_seg *)malloc(
sizeof (struct alloc_seg))) == NULL) {
logerr(gettext(ERR_CS_ALLOC), (bl_ptr->desc ?
bl_ptr->desc : "an unknown"));
return (0);
}
if (bl_ptr->alloc_segs == NULL) {
bl_ptr->alloc_segs = new_alloc_cs;
} else {
bl_ptr->cur_segment->next = new_alloc_cs;
}
new_alloc_cs->next = NULL;
bl_ptr->cur_segment = new_alloc_cs;
new_alloc_cs->full = 0;
if ((new_alloc_cs->seg_ptr = calloc(bl_ptr->count_per_block,
bl_ptr->struct_size)) == NULL) {
logerr(gettext(ERR_MEM_ALLOC), (bl_ptr->desc ?
bl_ptr->desc : "an unknown"));
return (0);
}
new_alloc_cs->avail_ptr = new_alloc_cs->seg_ptr;
new_alloc_cs->eoseg_ptr = (new_alloc_cs->seg_ptr +
bl_ptr->block_size);
}
return (1);
}
int
bl_create(int count_per_block, int struct_size, char *desc)
{
struct blk_list_cs *bl_ptr;
int retval;
if ((bl_cs_array[next_array_elem] =
(struct blk_list_cs *)calloc(1, sizeof (struct blk_list_cs))) ==
NULL) {
logerr(gettext(ERR_CS_ALLOC), (desc ? desc : "an unknown"));
return (-1);
}
bl_ptr = bl_cs_array[next_array_elem];
retval = next_array_elem++;
bl_ptr->data_handle = -1;
bl_ptr->struct_size = struct_size;
bl_ptr->count_per_block = count_per_block;
bl_ptr->block_size = (count_per_block * struct_size);
bl_ptr->desc = strdup((desc ? desc : "unknown"));
return (retval);
}
char *
bl_next_avail(int list_handle)
{
struct blk_list_cs *bl_ptr;
char *retval;
if (invalid_handle(list_handle))
return (NULL);
bl_ptr = bl_cs_array[list_handle];
if (bl_ptr->cur_segment == NULL || bl_ptr->cur_segment->full)
if (!alloc_next_seg(bl_ptr))
return (NULL);
retval = bl_ptr->cur_segment->avail_ptr;
bl_ptr->cur_segment->avail_ptr += bl_ptr->struct_size;
bl_ptr->total_elem++;
if (bl_ptr->cur_segment->avail_ptr >= bl_ptr->cur_segment->eoseg_ptr)
bl_ptr->cur_segment->full = 1;
return (retval);
}
char *
bl_get_record(int list_handle, int recno)
{
struct blk_list_cs *bl_ptr;
struct alloc_seg *cur_as_ptr;
int cur_rec = 0;
if (invalid_record(list_handle, recno))
return (NULL);
bl_ptr = bl_cs_array[list_handle];
cur_as_ptr = bl_ptr->alloc_segs;
while (recno > (cur_rec + bl_ptr->count_per_block)) {
cur_as_ptr = cur_as_ptr->next;
if (cur_as_ptr == NULL)
return (NULL);
cur_rec += bl_ptr->count_per_block;
}
return ((char *)cur_as_ptr + ((recno - cur_rec) * bl_ptr->struct_size));
}
void
bl_free(int list_handle)
{
int cur_handle;
if (list_handle == -1) {
for (cur_handle = 0; cur_handle < next_array_elem;
cur_handle++) {
free_list(cur_handle);
}
} else {
if (invalid_handle(list_handle))
return;
free_list(list_handle);
}
}
int
ar_create(int count_per_block, int struct_size, char *desc)
{
int data_handle, retval;
char ar_desc[60];
struct blk_list_cs *array_ptr;
if ((data_handle = bl_create(count_per_block, struct_size, desc)) == -1)
return (-1);
sprintf(ar_desc, "%s pointer", desc);
if ((retval = bl_create(count_per_block, sizeof (char *),
ar_desc)) == -1)
return (-1);
array_ptr = bl_cs_array[retval];
array_ptr->contiguous = 1;
array_ptr->data_handle = data_handle;
return (retval);
}
char **
ar_get_head(int list_handle)
{
if (invalid_handle(list_handle) ||
bl_cs_array[list_handle]->alloc_segs == NULL)
return (NULL);
return ((char **)bl_cs_array[list_handle]->alloc_segs->seg_ptr);
}
int
ar_delete(int list_handle, int index)
{
char **array;
char *deleted_rec;
int i;
struct blk_list_cs *list_ptr, *data_ptr;
if ((array = ar_get_head(list_handle)) == NULL)
return (0);
if (invalid_record(list_handle, index))
return (0);
list_ptr = bl_cs_array[list_handle];
if (!(list_ptr->contiguous))
return (0);
data_ptr = bl_cs_array[list_ptr->data_handle];
deleted_rec = array[index];
for (i = index; array[i] != NULL; i++)
array[i] = array[i+1];
array[i] = deleted_rec;
list_ptr->alloc_segs->avail_ptr -= list_ptr->struct_size;
list_ptr->alloc_segs->full = 0;
list_ptr->total_elem -= 1;
(void) memset(deleted_rec, '\000', data_ptr->struct_size);
return (1);
}
char **
ar_next_avail(int list_handle)
{
struct blk_list_cs *array_ptr;
char *data_area, **pointer_area;
if (invalid_handle(list_handle) ||
!(bl_cs_array[list_handle]->contiguous) ||
invalid_handle(bl_cs_array[list_handle]->data_handle))
return (NULL);
array_ptr = bl_cs_array[list_handle];
if ((bl_cs_array[list_handle]->cur_segment != NULL) &&
(ARRAY_END(list_handle) + REC_SIZE(list_handle) <
EOSEG(list_handle)) &&
(*(pointer_area = (char **) GET_AVAIL(list_handle)) != NULL)) {
data_area = *pointer_area;
*(char **)(ARRAY_END(list_handle)) = data_area;
*pointer_area-- = NULL;
array_ptr->cur_segment->avail_ptr += array_ptr->struct_size;
array_ptr->total_elem++;
} else {
data_area = bl_next_avail(array_ptr->data_handle);
pointer_area = (char **) bl_next_avail(list_handle);
*pointer_area = data_area;
if (bl_cs_array[list_handle]->alloc_segs->full) {
char **old_list_pointer, **new_list_pointer;
old_list_pointer = ar_get_head(list_handle);
if (!alloc_next_seg(array_ptr))
return (NULL);
new_list_pointer = ar_get_head(list_handle);
if (old_list_pointer != new_list_pointer) {
pointer_area += (new_list_pointer -
old_list_pointer);
}
}
}
return (pointer_area);
}
void
ar_free(int list_handle)
{
if (invalid_handle(list_handle))
return;
bl_free(bl_cs_array[list_handle]->data_handle);
bl_free(list_handle);
}