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