1*5c51f124SMoriah Waterland /*
2*5c51f124SMoriah Waterland  * CDDL HEADER START
3*5c51f124SMoriah Waterland  *
4*5c51f124SMoriah Waterland  * The contents of this file are subject to the terms of the
5*5c51f124SMoriah Waterland  * Common Development and Distribution License (the "License").
6*5c51f124SMoriah Waterland  * You may not use this file except in compliance with the License.
7*5c51f124SMoriah Waterland  *
8*5c51f124SMoriah Waterland  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5c51f124SMoriah Waterland  * or http://www.opensolaris.org/os/licensing.
10*5c51f124SMoriah Waterland  * See the License for the specific language governing permissions
11*5c51f124SMoriah Waterland  * and limitations under the License.
12*5c51f124SMoriah Waterland  *
13*5c51f124SMoriah Waterland  * When distributing Covered Code, include this CDDL HEADER in each
14*5c51f124SMoriah Waterland  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5c51f124SMoriah Waterland  * If applicable, add the following below this CDDL HEADER, with the
16*5c51f124SMoriah Waterland  * fields enclosed by brackets "[]" replaced with your own identifying
17*5c51f124SMoriah Waterland  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5c51f124SMoriah Waterland  *
19*5c51f124SMoriah Waterland  * CDDL HEADER END
20*5c51f124SMoriah Waterland  */
21*5c51f124SMoriah Waterland 
22*5c51f124SMoriah Waterland /*
23*5c51f124SMoriah Waterland  * Copyright 1996 Sun Microsystems, Inc.  All rights reserved.
24*5c51f124SMoriah Waterland  * Use is subject to license terms.
25*5c51f124SMoriah Waterland  */
26*5c51f124SMoriah Waterland 
27*5c51f124SMoriah Waterland 
28*5c51f124SMoriah Waterland #include <stdio.h>
29*5c51f124SMoriah Waterland #include <string.h>
30*5c51f124SMoriah Waterland #include <stdlib.h>
31*5c51f124SMoriah Waterland #include <libintl.h>
32*5c51f124SMoriah Waterland #include "pkglib.h"
33*5c51f124SMoriah Waterland 
34*5c51f124SMoriah Waterland /*
35*5c51f124SMoriah Waterland  * This is the module responsible for allocating and maintaining lists that
36*5c51f124SMoriah Waterland  * require allocation of memory. For certain lists, large chunks are
37*5c51f124SMoriah Waterland  * allocated once to contain a large number of entries in each chunk (bl_*
38*5c51f124SMoriah Waterland  * for block list). The other approach involves the augmentation of linked
39*5c51f124SMoriah Waterland  * lists, each entry of which is alloc'd individually.
40*5c51f124SMoriah Waterland  */
41*5c51f124SMoriah Waterland #define	ERR_CS_ALLOC	"ERROR: Cannot allocate control structure for %s array."
42*5c51f124SMoriah Waterland #define	ERR_MEM_ALLOC	"ERROR: Cannot allocate memory for %s array."
43*5c51f124SMoriah Waterland 
44*5c51f124SMoriah Waterland #define	MAX_ARRAYS	50
45*5c51f124SMoriah Waterland 
46*5c51f124SMoriah Waterland #define	ARRAY_END(x)	(bl_cs_array[x]->cur_segment->avail_ptr)
47*5c51f124SMoriah Waterland #define	REC_SIZE(x)	(bl_cs_array[x]->struct_size)
48*5c51f124SMoriah Waterland #define	EOSEG(x)	(bl_cs_array[x]->cur_segment->eoseg_ptr)
49*5c51f124SMoriah Waterland #define	GET_AVAIL(x)	(ARRAY_END(x) + REC_SIZE(x))
50*5c51f124SMoriah Waterland 
51*5c51f124SMoriah Waterland struct alloc_seg {
52*5c51f124SMoriah Waterland 	char *seg_ptr;		/* ptr to the allocated block */
53*5c51f124SMoriah Waterland 	char *avail_ptr;	/* ptr to the next available list element */
54*5c51f124SMoriah Waterland 	char *eoseg_ptr;	/* last byte in the segment */
55*5c51f124SMoriah Waterland 	int full;		/* segment has no available space */
56*5c51f124SMoriah Waterland 	struct alloc_seg *next;	/* next record */
57*5c51f124SMoriah Waterland };
58*5c51f124SMoriah Waterland 
59*5c51f124SMoriah Waterland struct blk_list_cs {
60*5c51f124SMoriah Waterland 	int struct_size;		/* size of a single list element */
61*5c51f124SMoriah Waterland 	int count_per_block;		/* number of list elements per block */
62*5c51f124SMoriah Waterland 	int block_size;			/* just to save time - alloc size */
63*5c51f124SMoriah Waterland 	int data_handle;		/* list_handle for pointer array */
64*5c51f124SMoriah Waterland 	struct alloc_seg *alloc_segs;	/* memory pool */
65*5c51f124SMoriah Waterland 
66*5c51f124SMoriah Waterland 	struct alloc_seg *cur_segment;	/* the current allocated segment */
67*5c51f124SMoriah Waterland 	int total_elem;			/* total elements stored */
68*5c51f124SMoriah Waterland 	int contiguous;			/* use realloc to grow */
69*5c51f124SMoriah Waterland 	char *desc;			/* description of the list */
70*5c51f124SMoriah Waterland };
71*5c51f124SMoriah Waterland 
72*5c51f124SMoriah Waterland static struct blk_list_cs *bl_cs_array[MAX_ARRAYS];
73*5c51f124SMoriah Waterland static int next_array_elem;
74*5c51f124SMoriah Waterland 
75*5c51f124SMoriah Waterland /* Support functions */
76*5c51f124SMoriah Waterland static int
invalid_handle(int list_handle)77*5c51f124SMoriah Waterland invalid_handle(int list_handle)
78*5c51f124SMoriah Waterland {
79*5c51f124SMoriah Waterland 	if (list_handle < 0 || list_handle >= next_array_elem)
80*5c51f124SMoriah Waterland 		return (1);
81*5c51f124SMoriah Waterland 
82*5c51f124SMoriah Waterland 	return (0);
83*5c51f124SMoriah Waterland }
84*5c51f124SMoriah Waterland 
85*5c51f124SMoriah Waterland static int
invalid_record(int list_handle,int recno)86*5c51f124SMoriah Waterland invalid_record(int list_handle, int recno)
87*5c51f124SMoriah Waterland {
88*5c51f124SMoriah Waterland 	if (invalid_handle(list_handle))
89*5c51f124SMoriah Waterland 		return (1);
90*5c51f124SMoriah Waterland 
91*5c51f124SMoriah Waterland 	if (recno < 0 || recno > bl_cs_array[list_handle]->total_elem)
92*5c51f124SMoriah Waterland 		return (1);
93*5c51f124SMoriah Waterland 
94*5c51f124SMoriah Waterland 	return (0);
95*5c51f124SMoriah Waterland }
96*5c51f124SMoriah Waterland 
97*5c51f124SMoriah Waterland static void
free_list(int list_handle)98*5c51f124SMoriah Waterland free_list(int list_handle)
99*5c51f124SMoriah Waterland {
100*5c51f124SMoriah Waterland 	struct blk_list_cs *bl_ptr;
101*5c51f124SMoriah Waterland 	struct alloc_seg *segstr_ptr, *nextstr_ptr;
102*5c51f124SMoriah Waterland 
103*5c51f124SMoriah Waterland 	/* Make sure this wasn't free'd earlier */
104*5c51f124SMoriah Waterland 	if (bl_cs_array[list_handle] == NULL)
105*5c51f124SMoriah Waterland 		return;
106*5c51f124SMoriah Waterland 
107*5c51f124SMoriah Waterland 	bl_ptr = bl_cs_array[list_handle];
108*5c51f124SMoriah Waterland 
109*5c51f124SMoriah Waterland 	/* First free the alloc_seg list. */
110*5c51f124SMoriah Waterland 	segstr_ptr = bl_ptr->alloc_segs;
111*5c51f124SMoriah Waterland 
112*5c51f124SMoriah Waterland 	if (segstr_ptr) {
113*5c51f124SMoriah Waterland 		do {
114*5c51f124SMoriah Waterland 			nextstr_ptr = segstr_ptr->next;
115*5c51f124SMoriah Waterland 
116*5c51f124SMoriah Waterland 			/* Free the memory block. */
117*5c51f124SMoriah Waterland 			free((void *)segstr_ptr->seg_ptr);
118*5c51f124SMoriah Waterland 
119*5c51f124SMoriah Waterland 			/* Free the control structure. */
120*5c51f124SMoriah Waterland 			free((void *)segstr_ptr);
121*5c51f124SMoriah Waterland 			segstr_ptr = nextstr_ptr;
122*5c51f124SMoriah Waterland 		} while (segstr_ptr);
123*5c51f124SMoriah Waterland 	}
124*5c51f124SMoriah Waterland 
125*5c51f124SMoriah Waterland 	/* Free the block control structure. */
126*5c51f124SMoriah Waterland 	free((void *)bl_ptr->desc);
127*5c51f124SMoriah Waterland 	free((void *)bl_ptr);
128*5c51f124SMoriah Waterland 
129*5c51f124SMoriah Waterland 	bl_cs_array[list_handle] = NULL;
130*5c51f124SMoriah Waterland }
131*5c51f124SMoriah Waterland 
132*5c51f124SMoriah Waterland /* Allocate another alloc_seg structure. */
133*5c51f124SMoriah Waterland static int
alloc_next_seg(struct blk_list_cs * bl_ptr)134*5c51f124SMoriah Waterland alloc_next_seg(struct blk_list_cs *bl_ptr)
135*5c51f124SMoriah Waterland {
136*5c51f124SMoriah Waterland 	struct alloc_seg *new_alloc_cs;
137*5c51f124SMoriah Waterland 
138*5c51f124SMoriah Waterland 	if (bl_ptr->contiguous) {
139*5c51f124SMoriah Waterland 		int offset_to_avail, seg_size, new_size;
140*5c51f124SMoriah Waterland 		struct alloc_seg *alloc_segment;
141*5c51f124SMoriah Waterland 
142*5c51f124SMoriah Waterland 		if (bl_ptr->alloc_segs) {
143*5c51f124SMoriah Waterland 			alloc_segment = bl_ptr->alloc_segs;
144*5c51f124SMoriah Waterland 
145*5c51f124SMoriah Waterland 			offset_to_avail = (alloc_segment->avail_ptr -
146*5c51f124SMoriah Waterland 			    alloc_segment->seg_ptr);
147*5c51f124SMoriah Waterland 			seg_size = (alloc_segment->eoseg_ptr -
148*5c51f124SMoriah Waterland 			    alloc_segment->seg_ptr);
149*5c51f124SMoriah Waterland 			new_size = (seg_size + bl_ptr->block_size);
150*5c51f124SMoriah Waterland 		} else {
151*5c51f124SMoriah Waterland 			if ((bl_ptr->alloc_segs =
152*5c51f124SMoriah Waterland 			    (struct alloc_seg *)calloc(1,
153*5c51f124SMoriah Waterland 			    sizeof (struct alloc_seg))) == NULL) {
154*5c51f124SMoriah Waterland 				logerr(gettext(ERR_CS_ALLOC), (bl_ptr->desc ?
155*5c51f124SMoriah Waterland 				    bl_ptr->desc : "an unknown"));
156*5c51f124SMoriah Waterland 				return (0);
157*5c51f124SMoriah Waterland 			}
158*5c51f124SMoriah Waterland 
159*5c51f124SMoriah Waterland 			alloc_segment = bl_ptr->alloc_segs;
160*5c51f124SMoriah Waterland 
161*5c51f124SMoriah Waterland 			offset_to_avail = 0;
162*5c51f124SMoriah Waterland 			seg_size = 0;
163*5c51f124SMoriah Waterland 			new_size = bl_ptr->block_size;
164*5c51f124SMoriah Waterland 		}
165*5c51f124SMoriah Waterland 
166*5c51f124SMoriah Waterland 		bl_ptr->cur_segment = alloc_segment;
167*5c51f124SMoriah Waterland 
168*5c51f124SMoriah Waterland 		if ((alloc_segment->seg_ptr =
169*5c51f124SMoriah Waterland 		    (char *)realloc((void *)alloc_segment->seg_ptr,
170*5c51f124SMoriah Waterland 		    (unsigned)new_size)) == NULL) {
171*5c51f124SMoriah Waterland 			logerr(gettext(ERR_MEM_ALLOC), (bl_ptr->desc ?
172*5c51f124SMoriah Waterland 			    bl_ptr->desc : "an unknown"));
173*5c51f124SMoriah Waterland 			return (0);
174*5c51f124SMoriah Waterland 		}
175*5c51f124SMoriah Waterland 
176*5c51f124SMoriah Waterland 		alloc_segment->next = NULL;
177*5c51f124SMoriah Waterland 
178*5c51f124SMoriah Waterland 		/* reset the status */
179*5c51f124SMoriah Waterland 		alloc_segment->full = 0;
180*5c51f124SMoriah Waterland 
181*5c51f124SMoriah Waterland 		/* readjust the original pointers */
182*5c51f124SMoriah Waterland 		alloc_segment->avail_ptr = alloc_segment->seg_ptr +
183*5c51f124SMoriah Waterland 		    offset_to_avail;
184*5c51f124SMoriah Waterland 		alloc_segment->eoseg_ptr = alloc_segment->seg_ptr + new_size;
185*5c51f124SMoriah Waterland 
186*5c51f124SMoriah Waterland 		(void) memset(alloc_segment->avail_ptr, '\000',
187*5c51f124SMoriah Waterland 		    bl_ptr->block_size);
188*5c51f124SMoriah Waterland 	} else {
189*5c51f124SMoriah Waterland 		/* Allocate the control structure and link it into the list. */
190*5c51f124SMoriah Waterland 		if ((new_alloc_cs = (struct alloc_seg *)malloc(
191*5c51f124SMoriah Waterland 		    sizeof (struct alloc_seg))) == NULL) {
192*5c51f124SMoriah Waterland 			logerr(gettext(ERR_CS_ALLOC), (bl_ptr->desc ?
193*5c51f124SMoriah Waterland 			    bl_ptr->desc : "an unknown"));
194*5c51f124SMoriah Waterland 			return (0);
195*5c51f124SMoriah Waterland 		}
196*5c51f124SMoriah Waterland 
197*5c51f124SMoriah Waterland 		if (bl_ptr->alloc_segs == NULL) {
198*5c51f124SMoriah Waterland 			/*
199*5c51f124SMoriah Waterland 			 * If this is the first allocation, then initialize
200*5c51f124SMoriah Waterland 			 * the head pointer and set cur_segment to this first
201*5c51f124SMoriah Waterland 			 * block of memory.
202*5c51f124SMoriah Waterland 			 */
203*5c51f124SMoriah Waterland 			bl_ptr->alloc_segs = new_alloc_cs;
204*5c51f124SMoriah Waterland 		} else {
205*5c51f124SMoriah Waterland 			/*
206*5c51f124SMoriah Waterland 			 * Otherwise, point the current cur_segment to the
207*5c51f124SMoriah Waterland 			 * next one and then point to the new one.
208*5c51f124SMoriah Waterland 			 */
209*5c51f124SMoriah Waterland 			bl_ptr->cur_segment->next = new_alloc_cs;
210*5c51f124SMoriah Waterland 		}
211*5c51f124SMoriah Waterland 
212*5c51f124SMoriah Waterland 		new_alloc_cs->next = NULL;
213*5c51f124SMoriah Waterland 		bl_ptr->cur_segment = new_alloc_cs;
214*5c51f124SMoriah Waterland 
215*5c51f124SMoriah Waterland 		new_alloc_cs->full = 0;
216*5c51f124SMoriah Waterland 
217*5c51f124SMoriah Waterland 		/* Now allocate the block of memory that this controls. */
218*5c51f124SMoriah Waterland 		if ((new_alloc_cs->seg_ptr = calloc(bl_ptr->count_per_block,
219*5c51f124SMoriah Waterland 		    bl_ptr->struct_size)) == NULL) {
220*5c51f124SMoriah Waterland 			logerr(gettext(ERR_MEM_ALLOC), (bl_ptr->desc ?
221*5c51f124SMoriah Waterland 			    bl_ptr->desc : "an unknown"));
222*5c51f124SMoriah Waterland 			return (0);
223*5c51f124SMoriah Waterland 		}
224*5c51f124SMoriah Waterland 
225*5c51f124SMoriah Waterland 		new_alloc_cs->avail_ptr = new_alloc_cs->seg_ptr;
226*5c51f124SMoriah Waterland 		new_alloc_cs->eoseg_ptr = (new_alloc_cs->seg_ptr +
227*5c51f124SMoriah Waterland 		    bl_ptr->block_size);
228*5c51f124SMoriah Waterland 	}
229*5c51f124SMoriah Waterland 
230*5c51f124SMoriah Waterland 	return (1);
231*5c51f124SMoriah Waterland }
232*5c51f124SMoriah Waterland 
233*5c51f124SMoriah Waterland /*
234*5c51f124SMoriah Waterland  * These first functions (beginning with bl_*) manage simple block lists. The
235*5c51f124SMoriah Waterland  * pointers returned, may get lost if they aren't assigned to an array or
236*5c51f124SMoriah Waterland  * something. While individual records can be obtained by record number, the
237*5c51f124SMoriah Waterland  * process isn't very efficient. Look to the array management section
238*5c51f124SMoriah Waterland  * (ar_*)for an easily administrable list.
239*5c51f124SMoriah Waterland  */
240*5c51f124SMoriah Waterland 
241*5c51f124SMoriah Waterland /*
242*5c51f124SMoriah Waterland  * Create a block list. Allocate memory for a block list structure and
243*5c51f124SMoriah Waterland  * initialize that structure. This doesn't actually allocate memory for the
244*5c51f124SMoriah Waterland  * list yet, just the controlling data structure. Returns -1 on failure and a
245*5c51f124SMoriah Waterland  * valid block list handle otherwise.
246*5c51f124SMoriah Waterland  *
247*5c51f124SMoriah Waterland  * NOTE: At the time of writing, it was not seen as important to recover block
248*5c51f124SMoriah Waterland  * pointers made available with a bl_free() (two of these at most in
249*5c51f124SMoriah Waterland  * pkginstall). If this became important later, we could trade efficiency for
250*5c51f124SMoriah Waterland  * speed by ignoring next_array_elem and actually scanning through the array
251*5c51f124SMoriah Waterland  * for a NULL pointer and then return that.
252*5c51f124SMoriah Waterland  */
253*5c51f124SMoriah Waterland int
bl_create(int count_per_block,int struct_size,char * desc)254*5c51f124SMoriah Waterland bl_create(int count_per_block, int struct_size, char *desc)
255*5c51f124SMoriah Waterland {
256*5c51f124SMoriah Waterland 	struct blk_list_cs *bl_ptr;
257*5c51f124SMoriah Waterland 	int retval;
258*5c51f124SMoriah Waterland 
259*5c51f124SMoriah Waterland 	if ((bl_cs_array[next_array_elem] =
260*5c51f124SMoriah Waterland 	    (struct blk_list_cs *)calloc(1, sizeof (struct blk_list_cs))) ==
261*5c51f124SMoriah Waterland 	    NULL) {
262*5c51f124SMoriah Waterland 		logerr(gettext(ERR_CS_ALLOC), (desc ? desc : "an unknown"));
263*5c51f124SMoriah Waterland 		return (-1);
264*5c51f124SMoriah Waterland 	}
265*5c51f124SMoriah Waterland 
266*5c51f124SMoriah Waterland 	bl_ptr = bl_cs_array[next_array_elem];
267*5c51f124SMoriah Waterland 	retval = next_array_elem++;
268*5c51f124SMoriah Waterland 
269*5c51f124SMoriah Waterland 	bl_ptr->data_handle = -1;
270*5c51f124SMoriah Waterland 	bl_ptr->struct_size = struct_size;
271*5c51f124SMoriah Waterland 	bl_ptr->count_per_block = count_per_block;
272*5c51f124SMoriah Waterland 	bl_ptr->block_size = (count_per_block * struct_size);
273*5c51f124SMoriah Waterland 	bl_ptr->desc = strdup((desc ? desc : "unknown"));
274*5c51f124SMoriah Waterland 
275*5c51f124SMoriah Waterland 	return (retval);
276*5c51f124SMoriah Waterland }
277*5c51f124SMoriah Waterland 
278*5c51f124SMoriah Waterland /*
279*5c51f124SMoriah Waterland  * Get the next available entry in the list. This will allocate memory as
280*5c51f124SMoriah Waterland  * required based on the initialization values in bl_create(). Returns a
281*5c51f124SMoriah Waterland  * pointer to the allocated memory segment or NULL if operation was not
282*5c51f124SMoriah Waterland  * possible.
283*5c51f124SMoriah Waterland  */
284*5c51f124SMoriah Waterland char *
bl_next_avail(int list_handle)285*5c51f124SMoriah Waterland bl_next_avail(int list_handle)
286*5c51f124SMoriah Waterland {
287*5c51f124SMoriah Waterland 	struct blk_list_cs *bl_ptr;
288*5c51f124SMoriah Waterland 	char *retval;
289*5c51f124SMoriah Waterland 
290*5c51f124SMoriah Waterland 	if (invalid_handle(list_handle))
291*5c51f124SMoriah Waterland 		return (NULL);
292*5c51f124SMoriah Waterland 
293*5c51f124SMoriah Waterland 	bl_ptr = bl_cs_array[list_handle];
294*5c51f124SMoriah Waterland 
295*5c51f124SMoriah Waterland 	/*
296*5c51f124SMoriah Waterland 	 * Allocate more memory if none is allocated yet or our last access
297*5c51f124SMoriah Waterland 	 * filled the allotted segment.
298*5c51f124SMoriah Waterland 	 */
299*5c51f124SMoriah Waterland 	if (bl_ptr->cur_segment == NULL || bl_ptr->cur_segment->full)
300*5c51f124SMoriah Waterland 		if (!alloc_next_seg(bl_ptr))
301*5c51f124SMoriah Waterland 			return (NULL);
302*5c51f124SMoriah Waterland 
303*5c51f124SMoriah Waterland 	/* Get the correct pointer. */
304*5c51f124SMoriah Waterland 	retval = bl_ptr->cur_segment->avail_ptr;
305*5c51f124SMoriah Waterland 
306*5c51f124SMoriah Waterland 	/* Advance it and mark if full. */
307*5c51f124SMoriah Waterland 	bl_ptr->cur_segment->avail_ptr += bl_ptr->struct_size;
308*5c51f124SMoriah Waterland 	bl_ptr->total_elem++;
309*5c51f124SMoriah Waterland 
310*5c51f124SMoriah Waterland 	if (bl_ptr->cur_segment->avail_ptr >= bl_ptr->cur_segment->eoseg_ptr)
311*5c51f124SMoriah Waterland 		bl_ptr->cur_segment->full = 1;
312*5c51f124SMoriah Waterland 
313*5c51f124SMoriah Waterland 	return (retval);
314*5c51f124SMoriah Waterland }
315*5c51f124SMoriah Waterland 
316*5c51f124SMoriah Waterland char *
bl_get_record(int list_handle,int recno)317*5c51f124SMoriah Waterland bl_get_record(int list_handle, int recno)
318*5c51f124SMoriah Waterland {
319*5c51f124SMoriah Waterland 	struct blk_list_cs *bl_ptr;
320*5c51f124SMoriah Waterland 	struct alloc_seg *cur_as_ptr;
321*5c51f124SMoriah Waterland 	int cur_rec = 0;
322*5c51f124SMoriah Waterland 
323*5c51f124SMoriah Waterland 	if (invalid_record(list_handle, recno))
324*5c51f124SMoriah Waterland 		return (NULL);
325*5c51f124SMoriah Waterland 
326*5c51f124SMoriah Waterland 	bl_ptr = bl_cs_array[list_handle];
327*5c51f124SMoriah Waterland 
328*5c51f124SMoriah Waterland 	cur_as_ptr = bl_ptr->alloc_segs;
329*5c51f124SMoriah Waterland 
330*5c51f124SMoriah Waterland 	while (recno > (cur_rec + bl_ptr->count_per_block)) {
331*5c51f124SMoriah Waterland 		cur_as_ptr = cur_as_ptr->next;
332*5c51f124SMoriah Waterland 
333*5c51f124SMoriah Waterland 		if (cur_as_ptr == NULL)
334*5c51f124SMoriah Waterland 			return (NULL);
335*5c51f124SMoriah Waterland 
336*5c51f124SMoriah Waterland 		cur_rec += bl_ptr->count_per_block;
337*5c51f124SMoriah Waterland 	}
338*5c51f124SMoriah Waterland 
339*5c51f124SMoriah Waterland 	/*
340*5c51f124SMoriah Waterland 	 * Now cur_as_ptr points to the allocated segment bearing the
341*5c51f124SMoriah Waterland 	 * intended record and all we do now is move down that by the
342*5c51f124SMoriah Waterland 	 * remaining record lengths.
343*5c51f124SMoriah Waterland 	 */
344*5c51f124SMoriah Waterland 
345*5c51f124SMoriah Waterland 	return ((char *)cur_as_ptr + ((recno - cur_rec) * bl_ptr->struct_size));
346*5c51f124SMoriah Waterland }
347*5c51f124SMoriah Waterland 
348*5c51f124SMoriah Waterland void
bl_free(int list_handle)349*5c51f124SMoriah Waterland bl_free(int list_handle)
350*5c51f124SMoriah Waterland {
351*5c51f124SMoriah Waterland 	int cur_handle;
352*5c51f124SMoriah Waterland 
353*5c51f124SMoriah Waterland 	if (list_handle == -1) {
354*5c51f124SMoriah Waterland 		for (cur_handle = 0; cur_handle < next_array_elem;
355*5c51f124SMoriah Waterland 		    cur_handle++) {
356*5c51f124SMoriah Waterland 			free_list(cur_handle);
357*5c51f124SMoriah Waterland 		}
358*5c51f124SMoriah Waterland 	} else {
359*5c51f124SMoriah Waterland 		if (invalid_handle(list_handle))
360*5c51f124SMoriah Waterland 			return;
361*5c51f124SMoriah Waterland 
362*5c51f124SMoriah Waterland 		free_list(list_handle);
363*5c51f124SMoriah Waterland 	}
364*5c51f124SMoriah Waterland }
365*5c51f124SMoriah Waterland 
366*5c51f124SMoriah Waterland /*
367*5c51f124SMoriah Waterland  * These are the array management functions. They insert into (and can return
368*5c51f124SMoriah Waterland  * a pointer to) a contiguous list of pointers to stuff. This keeps
369*5c51f124SMoriah Waterland  * everything together in a very handy package and is very similar in
370*5c51f124SMoriah Waterland  * appearance to the arrays created by the old AT&T code. The method for
371*5c51f124SMoriah Waterland  * presenting the interface is entirely different, however.
372*5c51f124SMoriah Waterland  */
373*5c51f124SMoriah Waterland 
374*5c51f124SMoriah Waterland /*
375*5c51f124SMoriah Waterland  * This constructs, maintains and returns pointers into a growable array of
376*5c51f124SMoriah Waterland  * pointers to structures of the form
377*5c51f124SMoriah Waterland  *	struct something *array[n]
378*5c51f124SMoriah Waterland  * The last element in the array is always NULL.
379*5c51f124SMoriah Waterland  */
380*5c51f124SMoriah Waterland int
ar_create(int count_per_block,int struct_size,char * desc)381*5c51f124SMoriah Waterland ar_create(int count_per_block, int struct_size, char *desc)
382*5c51f124SMoriah Waterland {
383*5c51f124SMoriah Waterland 	int data_handle, retval;
384*5c51f124SMoriah Waterland 	char ar_desc[60];
385*5c51f124SMoriah Waterland 	struct blk_list_cs *array_ptr;
386*5c51f124SMoriah Waterland 
387*5c51f124SMoriah Waterland 	if ((data_handle = bl_create(count_per_block, struct_size, desc)) == -1)
388*5c51f124SMoriah Waterland 		return (-1);
389*5c51f124SMoriah Waterland 
390*5c51f124SMoriah Waterland 	sprintf(ar_desc, "%s pointer", desc);
391*5c51f124SMoriah Waterland 	if ((retval = bl_create(count_per_block, sizeof (char *),
392*5c51f124SMoriah Waterland 	    ar_desc)) == -1)
393*5c51f124SMoriah Waterland 		return (-1);
394*5c51f124SMoriah Waterland 
395*5c51f124SMoriah Waterland 	array_ptr = bl_cs_array[retval];
396*5c51f124SMoriah Waterland 
397*5c51f124SMoriah Waterland 	array_ptr->contiguous = 1;
398*5c51f124SMoriah Waterland 	array_ptr->data_handle = data_handle;
399*5c51f124SMoriah Waterland 
400*5c51f124SMoriah Waterland 	return (retval);
401*5c51f124SMoriah Waterland }
402*5c51f124SMoriah Waterland 
403*5c51f124SMoriah Waterland /* Return a pointer to the first element in the array. */
404*5c51f124SMoriah Waterland char **
ar_get_head(int list_handle)405*5c51f124SMoriah Waterland ar_get_head(int list_handle)
406*5c51f124SMoriah Waterland {
407*5c51f124SMoriah Waterland 	if (invalid_handle(list_handle) ||
408*5c51f124SMoriah Waterland 	    bl_cs_array[list_handle]->alloc_segs == NULL)
409*5c51f124SMoriah Waterland 		return (NULL);
410*5c51f124SMoriah Waterland 
411*5c51f124SMoriah Waterland 	return ((char **)bl_cs_array[list_handle]->alloc_segs->seg_ptr);
412*5c51f124SMoriah Waterland }
413*5c51f124SMoriah Waterland 
414*5c51f124SMoriah Waterland /*
415*5c51f124SMoriah Waterland  * Free up the entry in the array indicated by index, but hold onto it for
416*5c51f124SMoriah Waterland  * future use.
417*5c51f124SMoriah Waterland  */
418*5c51f124SMoriah Waterland int
ar_delete(int list_handle,int index)419*5c51f124SMoriah Waterland ar_delete(int list_handle, int index)
420*5c51f124SMoriah Waterland {
421*5c51f124SMoriah Waterland 	char **array;
422*5c51f124SMoriah Waterland 	char *deleted_rec;
423*5c51f124SMoriah Waterland 	int i;
424*5c51f124SMoriah Waterland 	struct blk_list_cs *list_ptr, *data_ptr;
425*5c51f124SMoriah Waterland 
426*5c51f124SMoriah Waterland 	if ((array = ar_get_head(list_handle)) == NULL)
427*5c51f124SMoriah Waterland 		return (0);
428*5c51f124SMoriah Waterland 
429*5c51f124SMoriah Waterland 	if (invalid_record(list_handle, index))
430*5c51f124SMoriah Waterland 		return (0);
431*5c51f124SMoriah Waterland 
432*5c51f124SMoriah Waterland 	/* Get the pointer to the array control structure. */
433*5c51f124SMoriah Waterland 	list_ptr = bl_cs_array[list_handle];
434*5c51f124SMoriah Waterland 
435*5c51f124SMoriah Waterland 	if (!(list_ptr->contiguous))
436*5c51f124SMoriah Waterland 		return (0);	/* This isn't an array. */
437*5c51f124SMoriah Waterland 
438*5c51f124SMoriah Waterland 	data_ptr = bl_cs_array[list_ptr->data_handle];
439*5c51f124SMoriah Waterland 
440*5c51f124SMoriah Waterland 	/*
441*5c51f124SMoriah Waterland 	 * Since this looks just like an array. Record the pointer being
442*5c51f124SMoriah Waterland 	 * deleted for insertion into the avail list at the end and move all
443*5c51f124SMoriah Waterland 	 * elements below it up one.
444*5c51f124SMoriah Waterland 	 */
445*5c51f124SMoriah Waterland 	deleted_rec = array[index];
446*5c51f124SMoriah Waterland 
447*5c51f124SMoriah Waterland 	for (i = index; array[i] != NULL; i++)
448*5c51f124SMoriah Waterland 		array[i] = array[i+1];
449*5c51f124SMoriah Waterland 
450*5c51f124SMoriah Waterland 	/*
451*5c51f124SMoriah Waterland 	 * Now insert the deleted entry into the avails list after the NULL
452*5c51f124SMoriah Waterland 	 * and adjust the avail_ptr to point to the NULL again.
453*5c51f124SMoriah Waterland 	 */
454*5c51f124SMoriah Waterland 	array[i] = deleted_rec;
455*5c51f124SMoriah Waterland 	list_ptr->alloc_segs->avail_ptr -= list_ptr->struct_size;
456*5c51f124SMoriah Waterland 
457*5c51f124SMoriah Waterland 	/* Adjust other entries in the control structure. */
458*5c51f124SMoriah Waterland 	list_ptr->alloc_segs->full = 0;
459*5c51f124SMoriah Waterland 	list_ptr->total_elem -= 1;
460*5c51f124SMoriah Waterland 
461*5c51f124SMoriah Waterland 	/* Clear the deleted data area. */
462*5c51f124SMoriah Waterland 	(void) memset(deleted_rec, '\000', data_ptr->struct_size);
463*5c51f124SMoriah Waterland 
464*5c51f124SMoriah Waterland 	return (1);
465*5c51f124SMoriah Waterland }
466*5c51f124SMoriah Waterland 
467*5c51f124SMoriah Waterland /*
468*5c51f124SMoriah Waterland  * Return a new pointer to a structure pointer. Find an available element in
469*5c51f124SMoriah Waterland  * the array and point it at an available element in the data pool
470*5c51f124SMoriah Waterland  * constructed of block lists. Allocate new memory as necessary.
471*5c51f124SMoriah Waterland  */
472*5c51f124SMoriah Waterland char **
ar_next_avail(int list_handle)473*5c51f124SMoriah Waterland ar_next_avail(int list_handle)
474*5c51f124SMoriah Waterland {
475*5c51f124SMoriah Waterland 	struct blk_list_cs *array_ptr;
476*5c51f124SMoriah Waterland 	char *data_area, **pointer_area;
477*5c51f124SMoriah Waterland 
478*5c51f124SMoriah Waterland 	if (invalid_handle(list_handle) ||
479*5c51f124SMoriah Waterland 	    !(bl_cs_array[list_handle]->contiguous) ||
480*5c51f124SMoriah Waterland 	    invalid_handle(bl_cs_array[list_handle]->data_handle))
481*5c51f124SMoriah Waterland 		return (NULL);
482*5c51f124SMoriah Waterland 
483*5c51f124SMoriah Waterland 	array_ptr = bl_cs_array[list_handle];
484*5c51f124SMoriah Waterland 
485*5c51f124SMoriah Waterland 	/*
486*5c51f124SMoriah Waterland 	 * First see if an avail has already been allocated (it will be right
487*5c51f124SMoriah Waterland 	 * after the NULL termination of the array if it exists). Return
488*5c51f124SMoriah Waterland 	 * that, if found.
489*5c51f124SMoriah Waterland 	 */
490*5c51f124SMoriah Waterland 	if ((bl_cs_array[list_handle]->cur_segment != NULL) &&
491*5c51f124SMoriah Waterland 	    (ARRAY_END(list_handle) + REC_SIZE(list_handle) <
492*5c51f124SMoriah Waterland 	    EOSEG(list_handle)) &&
493*5c51f124SMoriah Waterland 	    (*(pointer_area = (char **) GET_AVAIL(list_handle)) != NULL)) {
494*5c51f124SMoriah Waterland 		/* We can reclaim a previous deletion. */
495*5c51f124SMoriah Waterland 		data_area = *pointer_area;
496*5c51f124SMoriah Waterland 
497*5c51f124SMoriah Waterland 		*(char **)(ARRAY_END(list_handle)) = data_area;	/* reactivate */
498*5c51f124SMoriah Waterland 		*pointer_area-- = NULL;	/* new end */
499*5c51f124SMoriah Waterland 
500*5c51f124SMoriah Waterland 		array_ptr->cur_segment->avail_ptr += array_ptr->struct_size;
501*5c51f124SMoriah Waterland 		array_ptr->total_elem++;
502*5c51f124SMoriah Waterland 	} else {
503*5c51f124SMoriah Waterland 		/*
504*5c51f124SMoriah Waterland 		 * Get the data area first. This is the record we're pointing
505*5c51f124SMoriah Waterland 		 * to from the array.
506*5c51f124SMoriah Waterland 		 */
507*5c51f124SMoriah Waterland 		data_area = bl_next_avail(array_ptr->data_handle);
508*5c51f124SMoriah Waterland 
509*5c51f124SMoriah Waterland 		/* Now get the next pointer from the pointer array. */
510*5c51f124SMoriah Waterland 		pointer_area = (char **) bl_next_avail(list_handle);
511*5c51f124SMoriah Waterland 
512*5c51f124SMoriah Waterland 		*pointer_area = data_area;
513*5c51f124SMoriah Waterland 
514*5c51f124SMoriah Waterland 		/*
515*5c51f124SMoriah Waterland 		 * The array must be NULL terminated. So, if the block list
516*5c51f124SMoriah Waterland 		 * structure is full, we have to grow it without resetting
517*5c51f124SMoriah Waterland 		 * the avail pointer. NOTE: This will only work for a
518*5c51f124SMoriah Waterland 		 * contiguous list!
519*5c51f124SMoriah Waterland 		 */
520*5c51f124SMoriah Waterland 		if (bl_cs_array[list_handle]->alloc_segs->full) {
521*5c51f124SMoriah Waterland 			char **old_list_pointer, **new_list_pointer;
522*5c51f124SMoriah Waterland 
523*5c51f124SMoriah Waterland 			/*
524*5c51f124SMoriah Waterland 			 * First grab the old numbers in case realloc() moves
525*5c51f124SMoriah Waterland 			 * everything.
526*5c51f124SMoriah Waterland 			 */
527*5c51f124SMoriah Waterland 			old_list_pointer = ar_get_head(list_handle);
528*5c51f124SMoriah Waterland 
529*5c51f124SMoriah Waterland 			/*
530*5c51f124SMoriah Waterland 			 * Now allocate additional contiguous memory, moving
531*5c51f124SMoriah Waterland 			 * the original block if necessary.
532*5c51f124SMoriah Waterland 			 */
533*5c51f124SMoriah Waterland 			if (!alloc_next_seg(array_ptr))
534*5c51f124SMoriah Waterland 				return (NULL);
535*5c51f124SMoriah Waterland 
536*5c51f124SMoriah Waterland 			/*
537*5c51f124SMoriah Waterland 			 * Now determine if everything moved and readjust the
538*5c51f124SMoriah Waterland 			 * pointer_area if required.
539*5c51f124SMoriah Waterland 			 */
540*5c51f124SMoriah Waterland 			new_list_pointer = ar_get_head(list_handle);
541*5c51f124SMoriah Waterland 
542*5c51f124SMoriah Waterland 			if (old_list_pointer != new_list_pointer) {
543*5c51f124SMoriah Waterland 				pointer_area += (new_list_pointer -
544*5c51f124SMoriah Waterland 				    old_list_pointer);
545*5c51f124SMoriah Waterland 			}
546*5c51f124SMoriah Waterland 		}
547*5c51f124SMoriah Waterland 	}
548*5c51f124SMoriah Waterland 
549*5c51f124SMoriah Waterland 	return (pointer_area);
550*5c51f124SMoriah Waterland }
551*5c51f124SMoriah Waterland 
552*5c51f124SMoriah Waterland /*
553*5c51f124SMoriah Waterland  * Relinquish the array back to the memory pool. Note that there is no method
554*5c51f124SMoriah Waterland  * provided to free *all* arrays.
555*5c51f124SMoriah Waterland  */
556*5c51f124SMoriah Waterland void
ar_free(int list_handle)557*5c51f124SMoriah Waterland ar_free(int list_handle)
558*5c51f124SMoriah Waterland {
559*5c51f124SMoriah Waterland 	if (invalid_handle(list_handle))
560*5c51f124SMoriah Waterland 		return;
561*5c51f124SMoriah Waterland 
562*5c51f124SMoriah Waterland 	bl_free(bl_cs_array[list_handle]->data_handle);
563*5c51f124SMoriah Waterland 	bl_free(list_handle);
564*5c51f124SMoriah Waterland }
565