1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1997-1999 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * util.c -- low-level utilities used by map*.c
30  */
31 #include <stdio.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <stdlib.h>
35 #include "xlator.h"
36 #include "util.h"
37 #include "errlog.h"
38 
39 /*
40  * String tables -- WARNING!  This uses realloc to recreate tables,
41  *	so always assign table_t * return value to the current
42  *	table pointer, lest the table address change in the
43  *	called function.
44  */
45 static char *strset(char *, char *);
46 
47 table_t *
48 create_stringtable(int size)
49 {
50 	table_t *t;
51 
52 	/* Solaris idiom: malloc && memset. TBD. */
53 	if ((t = calloc((size_t)1, (size_t)(sizeof (table_t) +
54 	    ((sizeof (char *)) * size)))) == NULL) {
55 		errlog(FATAL,
56 		    "\nOut of memory.\n"
57 		    "We wish to hold the whole sky,\n"
58 		    "But we never will.\n");
59 	}
60 	t->nelem = size;
61 	t->used = -1;
62 	return (t);
63 }
64 
65 
66 table_t *
67 add_to_stringtable(table_t *t, char *value)
68 {
69 	table_t *t2;
70 
71 	int i;
72 
73 	if (t == NULL) {
74 		seterrline(__LINE__, __FILE__, NULL, NULL);
75 		errlog(FATAL|PROGRAM, "programmer error: tried to add to "
76 			"a NULL table");
77 	}
78 	if (in_stringtable(t, value)) {
79 		return (t);
80 	}
81 	++t->used;
82 	if (t->used >= t->nelem) {
83 		if ((t2 = realloc(t, (size_t)(sizeof (table_t) +
84 		    ((sizeof (char *)) * (t->nelem + TABLE_INCREMENT)))))
85 		    == NULL) {
86 			print_stringtable(t);
87 			seterrline(__LINE__, __FILE__, NULL, NULL);
88 			errlog(FATAL|PROGRAM, "out of memory extending a "
89 				"string table");
90 		}
91 		t = t2;
92 		t->nelem += TABLE_INCREMENT;
93 		for (i = t->used; i < t->nelem; ++i) {
94 			t->elements[i] = NULL;
95 		}
96 	}
97 	t->elements[t->used] = strset(t->elements[t->used], value);
98 	return (t);
99 }
100 
101 /*
102  * free_stringtable -- really only mark it empty for reuse.
103  */
104 table_t *
105 free_stringtable(table_t *t)
106 {
107 
108 	if (t != NULL) {
109 		t->used = -1;
110 	}
111 	return (t);
112 }
113 
114 
115 char *
116 get_stringtable(table_t *t, int index)
117 {
118 
119 	if (t == NULL) {
120 		return (NULL);
121 	} else if (index > t->used) {
122 		return (NULL);
123 	} else {
124 		return (t->elements[index]);
125 	}
126 }
127 
128 int
129 in_stringtable(table_t *t, const char *value)
130 {
131 	int i;
132 
133 	if (t == NULL) {
134 		return (0);
135 	}
136 	for (i = 0; i <= t->used; ++i) {
137 		if (strcmp(value, t->elements[i]) == 0)
138 			return (1);
139 	}
140 	return (0);
141 }
142 
143 
144 void
145 print_stringtable(table_t *t)
146 {
147 	int i;
148 
149 	if (t == NULL)
150 		return;
151 
152 	errlog(VERBOSE,
153 		"table size = %d elements out of %d elements/%d bytes\n",
154 		t->used + 1, t->nelem,
155 		sizeof (table_t) + (sizeof (char *) * t->nelem));
156 
157 	for (i = 0; i <= t->used; ++i) {
158 		(void) fprintf(stderr, "\t%s\n",
159 			get_stringtable(t, i));
160 	}
161 }
162 
163 static int
164 compare(const void *p, const void *q)
165 {
166 	return (strcmp((char *)p, (char *)q));
167 }
168 
169 void
170 sort_stringtable(table_t *t)
171 {
172 
173 	if (t && t->used > 0) {
174 		qsort((char *)t->elements, (size_t)t->used,
175 			sizeof (char *), compare);
176 	}
177 }
178 
179 
180 /*
181  * strset -- update a dynamically-allocated string or die trying.
182  */
183 /*ARGSUSED*/
184 static char *
185 strset(char *string, char *value)
186 {
187 	size_t vlen;
188 
189 	assert(value != NULL, "passed a null value to strset");
190 	vlen = strlen(value);
191 	if (string == NULL) {
192 		/* It was never allocated, so allocate it. */
193 		if ((string = malloc(vlen + 1)) == NULL) {
194 			seterrline(__LINE__, __FILE__, NULL, NULL);
195 			errlog(FATAL|PROGRAM, "out of memory allocating a "
196 			    "string");
197 		}
198 	} else if (strlen(string) < vlen) {
199 		/* Reallocate bigger. */
200 		if ((string = realloc(string, vlen + 1)) == NULL) {
201 			seterrline(__LINE__, __FILE__, NULL, NULL);
202 			errlog(FATAL|PROGRAM, "out of memory reallocating"
203 			    "a string");
204 		}
205 	}
206 	(void) strcpy(string, value);
207 	return (string);
208 }
209