1 /* $NetBSD: citrus_pivot_factory.c,v 1.7 2009/04/12 14:20:19 lukem Exp $ */
2 
3 /*-
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c)2003 Citrus Project,
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 #include <sys/queue.h>
33 
34 #include <assert.h>
35 #include <ctype.h>
36 #include <errno.h>
37 #include <limits.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 
42 #include "citrus_namespace.h"
43 #include "citrus_region.h"
44 #include "citrus_bcs.h"
45 #include "citrus_db_factory.h"
46 #include "citrus_db_hash.h"
47 #include "citrus_pivot_file.h"
48 #include "citrus_pivot_factory.h"
49 
50 struct src_entry {
51 	char				*se_name;
52 	struct _citrus_db_factory	*se_df;
53 	STAILQ_ENTRY(src_entry)		 se_entry;
54 };
55 STAILQ_HEAD(src_head, src_entry);
56 
57 static int
58 find_src(struct src_head *sh, struct src_entry **rse, const char *name)
59 {
60 	int ret;
61 	struct src_entry *se;
62 
63 	STAILQ_FOREACH(se, sh, se_entry) {
64 		if (_bcs_strcasecmp(se->se_name, name) == 0) {
65 			*rse = se;
66 			return (0);
67 		}
68 	}
69 	se = malloc(sizeof(*se));
70 	if (se == NULL)
71 		return (errno);
72 	se->se_name = strdup(name);
73 	if (se->se_name == NULL) {
74 		ret = errno;
75 		free(se);
76 		return (ret);
77 	}
78 	ret = _db_factory_create(&se->se_df, &_db_hash_std, NULL);
79 	if (ret) {
80 		free(se->se_name);
81 		free(se);
82 		return (ret);
83 	}
84 	STAILQ_INSERT_TAIL(sh, se, se_entry);
85 	*rse = se;
86 
87 	return (0);
88 }
89 
90 static void
91 free_src(struct src_head *sh)
92 {
93 	struct src_entry *se;
94 
95 	while ((se = STAILQ_FIRST(sh)) != NULL) {
96 		STAILQ_REMOVE_HEAD(sh, se_entry);
97 		_db_factory_free(se->se_df);
98 		free(se->se_name);
99 		free(se);
100 	}
101 }
102 
103 
104 #define T_COMM '#'
105 static int
106 convert_line(struct src_head *sh, const char *line, size_t len)
107 {
108 	struct src_entry *se;
109 	const char *p;
110 	char key1[LINE_MAX], key2[LINE_MAX], data[LINE_MAX];
111 	char *ep;
112 	uint32_t val;
113 	int ret;
114 
115 	se = NULL;
116 
117 	/* cut off trailing comment */
118 	p = memchr(line, T_COMM, len);
119 	if (p)
120 		len = p - line;
121 
122 	/* key1 */
123 	line = _bcs_skip_ws_len(line, &len);
124 	if (len == 0)
125 		return (0);
126 	p = _bcs_skip_nonws_len(line, &len);
127 	if (p == line)
128 		return (0);
129 	snprintf(key1, sizeof(key1), "%.*s", (int)(p - line), line);
130 
131 	/* key2 */
132 	line = _bcs_skip_ws_len(p, &len);
133 	if (len == 0)
134 		return (0);
135 	p = _bcs_skip_nonws_len(line, &len);
136 	if (p == line)
137 		return (0);
138 	snprintf(key2, sizeof(key2), "%.*s", (int)(p - line), line);
139 
140 	/* data */
141 	line = _bcs_skip_ws_len(p, &len);
142 	_bcs_trunc_rws_len(line, &len);
143 	snprintf(data, sizeof(data), "%.*s", (int)len, line);
144 	val = strtoul(data, &ep, 0);
145 	if (*ep != '\0')
146 		return (EFTYPE);
147 
148 	/* insert to DB */
149 	ret = find_src(sh, &se, key1);
150 	if (ret)
151 		return (ret);
152 
153 	return (_db_factory_add32_by_s(se->se_df, key2, val));
154 }
155 
156 static int
157 dump_db(struct src_head *sh, struct _region *r)
158 {
159 	struct _db_factory *df;
160 	struct src_entry *se;
161 	struct _region subr;
162 	void *ptr;
163 	size_t size;
164 	int ret;
165 
166 	ret = _db_factory_create(&df, &_db_hash_std, NULL);
167 	if (ret)
168 		return (ret);
169 
170 	STAILQ_FOREACH(se, sh, se_entry) {
171 		size = _db_factory_calc_size(se->se_df);
172 		ptr = malloc(size);
173 		if (ptr == NULL)
174 			goto quit;
175 		_region_init(&subr, ptr, size);
176 		ret = _db_factory_serialize(se->se_df, _CITRUS_PIVOT_SUB_MAGIC,
177 		    &subr);
178 		if (ret)
179 			goto quit;
180 		ret = _db_factory_add_by_s(df, se->se_name, &subr, 1);
181 		if (ret)
182 			goto quit;
183 	}
184 
185 	size = _db_factory_calc_size(df);
186 	ptr = malloc(size);
187 	if (ptr == NULL)
188 		goto quit;
189 	_region_init(r, ptr, size);
190 
191 	ret = _db_factory_serialize(df, _CITRUS_PIVOT_MAGIC, r);
192 	ptr = NULL;
193 
194 quit:
195 	free(ptr);
196 	_db_factory_free(df);
197 	return (ret);
198 }
199 
200 int
201 _citrus_pivot_factory_convert(FILE *out, FILE *in)
202 {
203 	struct src_head sh;
204 	struct _region r;
205 	char *line;
206 	size_t size;
207 	int ret;
208 
209 	STAILQ_INIT(&sh);
210 
211 	while ((line = fgetln(in, &size)) != NULL)
212 		if ((ret = convert_line(&sh, line, size))) {
213 			free_src(&sh);
214 			return (ret);
215 		}
216 
217 	ret = dump_db(&sh, &r);
218 	free_src(&sh);
219 	if (ret)
220 		return (ret);
221 
222 	if (fwrite(_region_head(&r), _region_size(&r), 1, out) != 1)
223 		return (errno);
224 
225 	return (0);
226 }
227