1 /* $FreeBSD$ */ 2 /* $NetBSD: yacc.y,v 1.4 2005/06/02 02:09:25 lukem Exp $ */ 3 4 %{ 5 /*- 6 * SPDX-License-Identifier: BSD-2-Clause 7 * 8 * Copyright (c)2003 Citrus Project, 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 #include <sys/types.h> 35 #include <sys/queue.h> 36 37 #include <assert.h> 38 #include <err.h> 39 #include <errno.h> 40 #include <limits.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #include "citrus_namespace.h" 47 #include "citrus_types.h" 48 #include "citrus_region.h" 49 #include "citrus_esdb_file.h" 50 #include "citrus_db_hash.h" 51 #include "citrus_db_factory.h" 52 #include "citrus_lookup_factory.h" 53 54 #include "ldef.h" 55 56 extern FILE *yyin; 57 58 static struct named_csid_list named_csids; 59 static char *encoding, *name, *output = NULL, *variable; 60 static u_int32_t invalid; 61 static int debug = 0, num_csids = 0, use_invalid = 0; 62 63 static void dump_file(void); 64 static void register_named_csid(char *, u_int32_t); 65 static void set_invalid(u_int32_t); 66 static void set_prop_string(const char *, char **, char **); 67 %} 68 %union { 69 u_int32_t i_value; 70 char *s_value; 71 } 72 73 %token R_NAME R_ENCODING R_VARIABLE R_DEFCSID R_INVALID 74 %token R_LN 75 %token <i_value> L_IMM 76 %token <s_value> L_STRING 77 78 %% 79 80 file : property 81 { dump_file(); } 82 83 property : /* empty */ 84 | property R_LN 85 | property name R_LN 86 | property encoding R_LN 87 | property variable R_LN 88 | property defcsid R_LN 89 | property invalid R_LN 90 91 name : R_NAME L_STRING 92 { 93 set_prop_string("NAME", &name, &$2); 94 } 95 96 encoding : R_ENCODING L_STRING 97 { 98 set_prop_string("ENCODING", &encoding, &$2); 99 } 100 variable : R_VARIABLE L_STRING 101 { 102 set_prop_string("VARIABLE", &variable, &$2); 103 } 104 defcsid : R_DEFCSID L_STRING L_IMM 105 { 106 register_named_csid($2, $3); 107 $2 = NULL; 108 } 109 invalid : R_INVALID L_IMM 110 { 111 set_invalid($2); 112 } 113 %% 114 115 int 116 yyerror(const char *s) 117 { 118 119 fprintf(stderr, "%s in %d\n", s, linenumber); 120 121 return (0); 122 } 123 124 #define CHKERR(ret, func, a) \ 125 do { \ 126 ret = func a; \ 127 if (ret) \ 128 errx(EXIT_FAILURE, "%s: %s", #func, strerror(ret)); \ 129 } while (/*CONSTCOND*/0) 130 static void 131 dump_file(void) 132 { 133 struct _db_factory *df; 134 struct _region data; 135 struct named_csid *csid; 136 FILE *fp; 137 char buf[100]; 138 void *serialized; 139 size_t size; 140 int i, ret; 141 142 ret = 0; 143 if (!name) { 144 fprintf(stderr, "NAME is mandatory.\n"); 145 ret = 1; 146 } 147 if (!encoding) { 148 fprintf(stderr, "ENCODING is mandatory.\n"); 149 ret = 1; 150 } 151 if (ret) 152 exit(1); 153 154 /* 155 * build database 156 */ 157 CHKERR(ret, _db_factory_create, (&df, _db_hash_std, NULL)); 158 159 /* store version */ 160 CHKERR(ret, _db_factory_add32_by_s, (df, _CITRUS_ESDB_SYM_VERSION, 161 _CITRUS_ESDB_VERSION)); 162 163 /* store encoding */ 164 CHKERR(ret, _db_factory_addstr_by_s, (df, _CITRUS_ESDB_SYM_ENCODING, 165 encoding)); 166 167 /* store variable */ 168 if (variable) 169 CHKERR(ret, _db_factory_addstr_by_s, 170 (df, _CITRUS_ESDB_SYM_VARIABLE, variable)); 171 172 /* store invalid */ 173 if (use_invalid) 174 CHKERR(ret, _db_factory_add32_by_s, (df, 175 _CITRUS_ESDB_SYM_INVALID, invalid)); 176 177 /* store num of charsets */ 178 CHKERR(ret, _db_factory_add32_by_s, (df, _CITRUS_ESDB_SYM_NUM_CHARSETS, 179 num_csids)); 180 i = 0; 181 STAILQ_FOREACH(csid, &named_csids, ci_entry) { 182 snprintf(buf, sizeof(buf), _CITRUS_ESDB_SYM_CSNAME_PREFIX "%d", 183 i); 184 CHKERR(ret, _db_factory_addstr_by_s, 185 (df, buf, csid->ci_symbol)); 186 snprintf(buf, sizeof(buf), _CITRUS_ESDB_SYM_CSID_PREFIX "%d", 187 i); 188 CHKERR(ret, _db_factory_add32_by_s, (df, buf, csid->ci_csid)); 189 i++; 190 } 191 192 /* 193 * dump database to file 194 */ 195 fp = output ? fopen(output, "wb") : stdout; 196 if (fp == NULL) { 197 perror("fopen"); 198 exit(1); 199 } 200 201 /* dump database body */ 202 size = _db_factory_calc_size(df); 203 serialized = malloc(size); 204 _region_init(&data, serialized, size); 205 CHKERR(ret, _db_factory_serialize, (df, _CITRUS_ESDB_MAGIC, &data)); 206 if (fwrite(serialized, size, 1, fp) != 1) 207 err(EXIT_FAILURE, "fwrite"); 208 209 fclose(fp); 210 } 211 212 static void 213 set_prop_string(const char *res, char **store, char **data) 214 { 215 char buf[256]; 216 217 if (*store) { 218 snprintf(buf, sizeof(buf), 219 "%s is duplicated. ignored the one", res); 220 yyerror(buf); 221 return; 222 } 223 224 *store = *data; 225 *data = NULL; 226 } 227 228 static void 229 set_invalid(u_int32_t inv) 230 { 231 232 invalid = inv; 233 use_invalid = 1; 234 } 235 236 static void 237 register_named_csid(char *sym, u_int32_t val) 238 { 239 struct named_csid *csid; 240 241 STAILQ_FOREACH(csid, &named_csids, ci_entry) { 242 if (strcmp(csid->ci_symbol, sym) == 0) { 243 yyerror("multiply defined CSID"); 244 exit(1); 245 } 246 } 247 248 csid = malloc(sizeof(*csid)); 249 if (csid == NULL) { 250 perror("malloc"); 251 exit(1); 252 } 253 csid->ci_symbol = sym; 254 csid->ci_csid = val; 255 STAILQ_INSERT_TAIL(&named_csids, csid, ci_entry); 256 num_csids++; 257 } 258 259 static void 260 do_mkdb(FILE *in) 261 { 262 FILE *out; 263 int ret; 264 265 /* dump DB to file */ 266 out = output ? fopen(output, "wb") : stdout; 267 if (out == NULL) 268 err(EXIT_FAILURE, "fopen"); 269 270 ret = _lookup_factory_convert(out, in); 271 fclose(out); 272 if (ret && output) 273 unlink(output); /* dump failure */ 274 if (ret) 275 errx(EXIT_FAILURE, "%s\n", strerror(ret)); 276 } 277 278 static void 279 usage(void) 280 { 281 errx(EXIT_FAILURE, 282 "usage:\n" 283 "\t%s [-d] [-o outfile] [infile]\n" 284 "\t%s -m [-d] [-o outfile] [infile]", 285 getprogname(), getprogname()); 286 } 287 288 int 289 main(int argc, char **argv) 290 { 291 FILE *in = NULL; 292 int ch, mkdb = 0; 293 294 while ((ch = getopt(argc, argv, "do:m")) != EOF) { 295 switch (ch) { 296 case 'd': 297 debug = 1; 298 break; 299 case 'o': 300 output = strdup(optarg); 301 break; 302 case 'm': 303 mkdb = 1; 304 break; 305 default: 306 usage(); 307 } 308 } 309 310 argc -= optind; 311 argv += optind; 312 switch (argc) { 313 case 0: 314 in = stdin; 315 break; 316 case 1: 317 in = fopen(argv[0], "r"); 318 if (!in) 319 err(EXIT_FAILURE, "%s", argv[0]); 320 break; 321 default: 322 usage(); 323 } 324 325 if (mkdb) 326 do_mkdb(in); 327 else { 328 STAILQ_INIT(&named_csids); 329 yyin = in; 330 yyparse(); 331 } 332 333 return (0); 334 } 335