1/*	$NetBSD: array.c,v 1.3 2022/04/03 01:10:59 christos Exp $	*/
2
3/* listener.c
4
5   Subroutines that support the omapi extensible array type. */
6
7/*
8 * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 2001-2003 by Internet Software Consortium
10 *
11 * This Source Code Form is subject to the terms of the Mozilla Public
12 * License, v. 2.0. If a copy of the MPL was not distributed with this
13 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 *   Internet Systems Consortium, Inc.
24 *   PO Box 360
25 *   Newmarket, NH 03857 USA
26 *   <info@isc.org>
27 *   https://www.isc.org/
28 *
29 */
30
31#include <sys/cdefs.h>
32__RCSID("$NetBSD: array.c,v 1.3 2022/04/03 01:10:59 christos Exp $");
33
34#include "dhcpd.h"
35
36#include <omapip/omapip_p.h>
37
38/* Allocate a new extensible array. */
39
40isc_result_t omapi_array_allocate (omapi_array_t **array,
41				   omapi_array_ref_t ref,
42				   omapi_array_deref_t deref,
43				   const char *file, int line)
44{
45	omapi_array_t *aptr;
46
47	if (!array || *array)
48		return DHCP_R_INVALIDARG;
49	aptr = dmalloc (sizeof (omapi_array_t),file, line);
50	if (!aptr)
51		return ISC_R_NOMEMORY;
52	*array = aptr;
53	aptr -> ref = ref;
54	aptr -> deref = deref;
55	return ISC_R_SUCCESS;
56}
57
58isc_result_t omapi_array_free (omapi_array_t **array,
59			       const char *file, int line)
60{
61	omapi_array_t *aptr;
62	int i;
63
64	if (!array || !*array)
65		return DHCP_R_INVALIDARG;
66	aptr = *array;
67	for (i = 0; i < aptr -> count; i++)
68		if (aptr -> data [i] && aptr -> deref)
69			(*aptr -> deref) (&aptr -> data [i], file, line);
70	dfree (aptr -> data, MDL);
71	dfree (aptr, MDL);
72	*array = (omapi_array_t *)0;
73	return ISC_R_SUCCESS;
74}
75
76/* Extend the size of the array by one entry (we may allocate more than that)
77   and store the specified value in the new array element. */
78
79isc_result_t omapi_array_extend (omapi_array_t *array, char *ptr,
80				 int *index, const char *file, int line)
81{
82	isc_result_t status;
83	int new = array -> count;
84	status = omapi_array_set (array, ptr, new, file, line);
85	if (index && status == ISC_R_SUCCESS)
86		*index = new;
87	return status;
88}
89
90/* Set a value in the specified array, extending it if necessary. */
91
92isc_result_t omapi_array_set (omapi_array_t *array, void *ptr, int index,
93			      const char *file, int line)
94{
95	char **newbuf;
96	int delta;
97	isc_result_t status;
98
99	if (!array)
100		return DHCP_R_INVALIDARG;
101	if (!ptr)
102		return DHCP_R_INVALIDARG;
103	if (index < 0)
104		return DHCP_R_INVALIDARG;
105
106	/* If the proposed index is larger than the current available
107	   space in the array, make more space in the array. */
108	if (array -> max <= index) {
109		delta = index - array -> max + 10;
110		newbuf = dmalloc ((array -> max + delta) * sizeof (char *),
111				  file, line);
112		if (!newbuf)
113			return ISC_R_NOMEMORY;
114		/* Zero the new elements. */
115		memset (&newbuf [array -> max], 0, (sizeof (char *)) * delta);
116		array -> max += delta;
117		/* Copy the old array data into the new buffer. */
118		if (array -> data) {
119		    memcpy (newbuf,
120			    array -> data, array -> count * sizeof (char *));
121		    dfree (array -> data, file, line);
122		}
123		array -> data = newbuf;
124	} else {
125		/* If there's already data there, and this is an array
126		   of references, dereference what's there. */
127		if (array -> data [index]) {
128			status = ((*array -> deref) (&array -> data [index],
129						     file, line));
130
131			if (status != ISC_R_SUCCESS)
132				return status;
133		}
134	}
135
136	/* Store the pointer using the referencer function.  We have
137	   either just memset this to zero or dereferenced what was
138	   there previously, so there is no need to do anything if the
139	   pointer we have been asked to store is null. */
140	if (ptr) {
141		status = (*array -> ref) (&array -> data [index], ptr,
142					  file, line);
143		if (status != ISC_R_SUCCESS)
144			return status;
145	}
146	if (index >= array -> count)
147		array -> count = index + 1;
148	return ISC_R_SUCCESS;
149}
150
151isc_result_t omapi_array_lookup (char **ptr, omapi_array_t *array, int index,
152				 const char *file, int line)
153{
154	if (!array || !ptr || *ptr || index < 0 || index >= array -> count)
155		return DHCP_R_INVALIDARG;
156	if (array -> data [index])
157		return (*array -> ref) (ptr,
158					array -> data [index], file, line);
159	return ISC_R_NOTFOUND;
160}
161