1%{ 2/*- 3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 4 * 5 * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua> 6 * at Electronni Visti IA, Kiev, Ukraine. 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 ``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 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__FBSDID("$FreeBSD$"); 33 34#include <sys/types.h> 35#include <arpa/inet.h> 36#include <err.h> 37#include <limits.h> 38#include <stdarg.h> 39#include <stdio.h> 40#include <stdlib.h> 41#include <string.h> 42#include <unistd.h> 43#include <sysexits.h> 44#include "common.h" 45 46extern FILE *yyin; 47void yyerror(const char *fmt, ...) __printflike(1, 2); 48int yyparse(void); 49int yylex(void); 50static void usage(void); 51static void collate_print_tables(void); 52 53#undef STR_LEN 54#define STR_LEN 10 55#undef TABLE_SIZE 56#define TABLE_SIZE 100 57#undef COLLATE_VERSION 58#define COLLATE_VERSION "1.0\n" 59#undef COLLATE_VERSION_2 60#define COLLATE_VERSION1_2 "1.2\n" 61 62struct __collate_st_char_pri { 63 int prim, sec; 64}; 65 66struct __collate_st_chain_pri { 67 u_char str[STR_LEN]; 68 int prim, sec; 69}; 70 71char map_name[FILENAME_MAX] = "."; 72char curr_chain[STR_LEN]; 73 74char __collate_version[STR_LEN]; 75u_char charmap_table[UCHAR_MAX + 1][CHARMAP_SYMBOL_LEN]; 76 77#undef __collate_substitute_table 78u_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN]; 79#undef __collate_char_pri_table 80struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1]; 81struct __collate_st_chain_pri *__collate_chain_pri_table; 82 83int chain_index = 0; 84int prim_pri = 1, sec_pri = 1; 85#ifdef COLLATE_DEBUG 86int debug; 87#endif 88 89const char *out_file = "LC_COLLATE"; 90%} 91%union { 92 u_char ch; 93 u_char str[BUFSIZE]; 94} 95%token SUBSTITUTE WITH ORDER RANGE 96%token <str> STRING 97%token <str> DEFN 98%token <ch> CHAR 99%% 100collate : statment_list 101; 102statment_list : statment 103 | statment_list '\n' statment 104; 105statment : 106 | charmap 107 | substitute 108 | order 109; 110charmap : DEFN CHAR { 111 if (strlen($1) + 1 > CHARMAP_SYMBOL_LEN) 112 yyerror("Charmap symbol name '%s' is too long", $1); 113 strcpy(charmap_table[$2], $1); 114} 115; 116substitute : SUBSTITUTE CHAR WITH STRING { 117 if ($2 == '\0') 118 yyerror("NUL character can't be substituted"); 119 if (strchr($4, $2) != NULL) 120 yyerror("Char 0x%02x substitution is recursive", $2); 121 if (strlen($4) + 1 > STR_LEN) 122 yyerror("Char 0x%02x substitution is too long", $2); 123 strcpy(__collate_substitute_table[$2], $4); 124} 125; 126order : ORDER order_list { 127 FILE *fp; 128 int ch, substed, ordered; 129 uint32_t u32; 130 131 for (ch = 0; ch < UCHAR_MAX + 1; ch++) { 132 substed = (__collate_substitute_table[ch][0] != ch); 133 ordered = !!__collate_char_pri_table[ch].prim; 134 if (!ordered && !substed) 135 yyerror("Char 0x%02x not found", ch); 136 if (substed && ordered) 137 yyerror("Char 0x%02x can't be ordered since substituted", ch); 138 } 139 140 if ((__collate_chain_pri_table = realloc(__collate_chain_pri_table, 141 sizeof(*__collate_chain_pri_table) * (chain_index + 1))) == NULL) 142 yyerror("can't grow chain table"); 143 (void)memset(&__collate_chain_pri_table[chain_index], 0, 144 sizeof(__collate_chain_pri_table[0])); 145 chain_index++; 146 147#ifdef COLLATE_DEBUG 148 if (debug) 149 collate_print_tables(); 150#endif 151 if ((fp = fopen(out_file, "w")) == NULL) 152 err(EX_UNAVAILABLE, "can't open destination file %s", 153 out_file); 154 155 strcpy(__collate_version, COLLATE_VERSION1_2); 156 if (fwrite(__collate_version, sizeof(__collate_version), 1, fp) != 1) 157 err(EX_IOERR, 158 "I/O error writing collate version to destination file %s", 159 out_file); 160 u32 = htonl(chain_index); 161 if (fwrite(&u32, sizeof(u32), 1, fp) != 1) 162 err(EX_IOERR, 163 "I/O error writing chains number to destination file %s", 164 out_file); 165 if (fwrite(__collate_substitute_table, 166 sizeof(__collate_substitute_table), 1, fp) != 1) 167 err(EX_IOERR, 168 "I/O error writing substitution table to destination file %s", 169 out_file); 170 for (ch = 0; ch < UCHAR_MAX + 1; ch++) { 171 __collate_char_pri_table[ch].prim = 172 htonl(__collate_char_pri_table[ch].prim); 173 __collate_char_pri_table[ch].sec = 174 htonl(__collate_char_pri_table[ch].sec); 175 } 176 if (fwrite(__collate_char_pri_table, 177 sizeof(__collate_char_pri_table), 1, fp) != 1) 178 err(EX_IOERR, 179 "I/O error writing char table to destination file %s", 180 out_file); 181 for (ch = 0; ch < chain_index; ch++) { 182 __collate_chain_pri_table[ch].prim = 183 htonl(__collate_chain_pri_table[ch].prim); 184 __collate_chain_pri_table[ch].sec = 185 htonl(__collate_chain_pri_table[ch].sec); 186 } 187 if (fwrite(__collate_chain_pri_table, 188 sizeof(*__collate_chain_pri_table), chain_index, fp) != 189 (size_t)chain_index) 190 err(EX_IOERR, 191 "I/O error writing chain table to destination file %s", 192 out_file); 193 if (fclose(fp) != 0) 194 err(EX_IOERR, "I/O error closing destination file %s", 195 out_file); 196 exit(EX_OK); 197} 198; 199order_list : item 200 | order_list ';' item 201; 202chain : CHAR CHAR { 203 curr_chain[0] = $1; 204 curr_chain[1] = $2; 205 if (curr_chain[0] == '\0' || curr_chain[1] == '\0') 206 yyerror("\\0 can't be chained"); 207 curr_chain[2] = '\0'; 208} 209 | chain CHAR { 210 static char tb[2]; 211 212 tb[0] = $2; 213 if (tb[0] == '\0') 214 yyerror("\\0 can't be chained"); 215 if (strlen(curr_chain) + 2 > STR_LEN) 216 yyerror("Chain '%s' grows too long", curr_chain); 217 (void)strcat(curr_chain, tb); 218} 219; 220item : CHAR { 221 if (__collate_char_pri_table[$1].prim) 222 yyerror("Char 0x%02x duplicated", $1); 223 __collate_char_pri_table[$1].prim = prim_pri++; 224} 225 | chain { 226 if ((__collate_chain_pri_table = realloc(__collate_chain_pri_table, 227 sizeof(*__collate_chain_pri_table) * (chain_index + 1))) == NULL) 228 yyerror("can't grow chain table"); 229 (void)memset(&__collate_chain_pri_table[chain_index], 0, 230 sizeof(__collate_chain_pri_table[0])); 231 (void)strcpy(__collate_chain_pri_table[chain_index].str, curr_chain); 232 __collate_chain_pri_table[chain_index].prim = prim_pri++; 233 chain_index++; 234} 235 | CHAR RANGE CHAR { 236 u_int i; 237 238 if ($3 <= $1) 239 yyerror("Illegal range 0x%02x -- 0x%02x", $1, $3); 240 241 for (i = $1; i <= $3; i++) { 242 if (__collate_char_pri_table[(u_char)i].prim) 243 yyerror("Char 0x%02x duplicated", (u_char)i); 244 __collate_char_pri_table[(u_char)i].prim = prim_pri++; 245 } 246} 247 | '{' prim_order_list '}' { 248 prim_pri++; 249} 250 | '(' sec_order_list ')' { 251 prim_pri++; 252 sec_pri = 1; 253} 254; 255prim_order_list : prim_sub_item 256 | prim_order_list ',' prim_sub_item 257; 258sec_order_list : sec_sub_item 259 | sec_order_list ',' sec_sub_item 260; 261prim_sub_item : CHAR { 262 if (__collate_char_pri_table[$1].prim) 263 yyerror("Char 0x%02x duplicated", $1); 264 __collate_char_pri_table[$1].prim = prim_pri; 265} 266 | CHAR RANGE CHAR { 267 u_int i; 268 269 if ($3 <= $1) 270 yyerror("Illegal range 0x%02x -- 0x%02x", 271 $1, $3); 272 273 for (i = $1; i <= $3; i++) { 274 if (__collate_char_pri_table[(u_char)i].prim) 275 yyerror("Char 0x%02x duplicated", (u_char)i); 276 __collate_char_pri_table[(u_char)i].prim = prim_pri; 277 } 278} 279 | chain { 280 if ((__collate_chain_pri_table = realloc(__collate_chain_pri_table, 281 sizeof(*__collate_chain_pri_table) * (chain_index + 1))) == NULL) 282 yyerror("can't grow chain table"); 283 (void)memset(&__collate_chain_pri_table[chain_index], 0, 284 sizeof(__collate_chain_pri_table[0])); 285 (void)strcpy(__collate_chain_pri_table[chain_index].str, curr_chain); 286 __collate_chain_pri_table[chain_index].prim = prim_pri; 287 chain_index++; 288} 289; 290sec_sub_item : CHAR { 291 if (__collate_char_pri_table[$1].prim) 292 yyerror("Char 0x%02x duplicated", $1); 293 __collate_char_pri_table[$1].prim = prim_pri; 294 __collate_char_pri_table[$1].sec = sec_pri++; 295} 296 | CHAR RANGE CHAR { 297 u_int i; 298 299 if ($3 <= $1) 300 yyerror("Illegal range 0x%02x -- 0x%02x", 301 $1, $3); 302 303 for (i = $1; i <= $3; i++) { 304 if (__collate_char_pri_table[(u_char)i].prim) 305 yyerror("Char 0x%02x duplicated", (u_char)i); 306 __collate_char_pri_table[(u_char)i].prim = prim_pri; 307 __collate_char_pri_table[(u_char)i].sec = sec_pri++; 308 } 309} 310 | chain { 311 if ((__collate_chain_pri_table = realloc(__collate_chain_pri_table, 312 sizeof(*__collate_chain_pri_table) * (chain_index + 1))) == NULL) 313 yyerror("can't grow chain table"); 314 (void)memset(&__collate_chain_pri_table[chain_index], 0, 315 sizeof(__collate_chain_pri_table[0])); 316 (void)strcpy(__collate_chain_pri_table[chain_index].str, curr_chain); 317 __collate_chain_pri_table[chain_index].prim = prim_pri; 318 __collate_chain_pri_table[chain_index].sec = sec_pri++; 319 chain_index++; 320} 321; 322%% 323int 324main(int ac, char **av) 325{ 326 int ch; 327 328#ifdef COLLATE_DEBUG 329 while((ch = getopt(ac, av, ":do:I:")) != -1) { 330#else 331 while((ch = getopt(ac, av, ":o:I:")) != -1) { 332#endif 333 switch (ch) 334 { 335#ifdef COLLATE_DEBUG 336 case 'd': 337 debug++; 338 break; 339#endif 340 case 'o': 341 out_file = optarg; 342 break; 343 344 case 'I': 345 strlcpy(map_name, optarg, sizeof(map_name)); 346 break; 347 348 default: 349 usage(); 350 } 351 } 352 ac -= optind; 353 av += optind; 354 if (ac > 0) { 355 if ((yyin = fopen(*av, "r")) == NULL) 356 err(EX_UNAVAILABLE, "can't open source file %s", *av); 357 } 358 for (ch = 0; ch <= UCHAR_MAX; ch++) 359 __collate_substitute_table[ch][0] = ch; 360 yyparse(); 361 return 0; 362} 363 364static void 365usage(void) 366{ 367 fprintf(stderr, "usage: colldef [-I map_dir] [-o out_file] [filename]\n"); 368 exit(EX_USAGE); 369} 370 371void 372yyerror(const char *fmt, ...) 373{ 374 va_list ap; 375 char msg[128]; 376 377 va_start(ap, fmt); 378 vsnprintf(msg, sizeof(msg), fmt, ap); 379 va_end(ap); 380 errx(EX_UNAVAILABLE, "%s near line %d", msg, line_no); 381} 382 383#ifdef COLLATE_DEBUG 384static void 385collate_print_tables(void) 386{ 387 int i; 388 389 printf("Substitute table:\n"); 390 for (i = 0; i < UCHAR_MAX + 1; i++) 391 if (i != *__collate_substitute_table[i]) 392 printf("\t'%c' --> \"%s\"\n", i, 393 __collate_substitute_table[i]); 394 printf("Chain priority table:\n"); 395 for (i = 0; i < chain_index - 1; i++) 396 printf("\t\"%s\" : %d %d\n", 397 __collate_chain_pri_table[i].str, 398 __collate_chain_pri_table[i].prim, 399 __collate_chain_pri_table[i].sec); 400 printf("Char priority table:\n"); 401 for (i = 0; i < UCHAR_MAX + 1; i++) 402 printf("\t'%c' : %d %d\n", i, __collate_char_pri_table[i].prim, 403 __collate_char_pri_table[i].sec); 404} 405#endif 406