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