16527Sache%{ 26527Sache/*- 36527Sache * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua> 46527Sache * at Electronni Visti IA, Kiev, Ukraine. 56527Sache * All rights reserved. 66527Sache * 76527Sache * Redistribution and use in source and binary forms, with or without 86527Sache * modification, are permitted provided that the following conditions 96527Sache * are met: 106527Sache * 1. Redistributions of source code must retain the above copyright 116527Sache * notice, this list of conditions and the following disclaimer. 126527Sache * 2. Redistributions in binary form must reproduce the above copyright 136527Sache * notice, this list of conditions and the following disclaimer in the 146527Sache * documentation and/or other materials provided with the distribution. 156527Sache * 166527Sache * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 176527Sache * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 186527Sache * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 196527Sache * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 206527Sache * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 216527Sache * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 226527Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 236527Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 246527Sache * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 256527Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 266527Sache * SUCH DAMAGE. 276527Sache */ 286527Sache 2987243Smarkm#include <sys/cdefs.h> 3087243Smarkm__FBSDID("$FreeBSD$"); 3187243Smarkm 32175038Simp#include <sys/types.h> 33102659Sache#include <arpa/inet.h> 346527Sache#include <err.h> 3518950Sache#include <stdarg.h> 366527Sache#include <stdio.h> 376527Sache#include <string.h> 3823706Speter#include <unistd.h> 396527Sache#include <sysexits.h> 406527Sache#include "collate.h" 4187012Sache#include "common.h" 426527Sache 436527Sacheextern FILE *yyin; 4487243Smarkmvoid yyerror(const char *fmt, ...) __printflike(1, 2); 4541568Sarchieint yyparse(void); 4641568Sarchieint yylex(void); 4787243Smarkmstatic void usage(void); 4887243Smarkmstatic void collate_print_tables(void); 496527Sache 5018950Sachechar map_name[FILENAME_MAX] = "."; 51102299Sachechar curr_chain[STR_LEN]; 5218950Sache 5318950Sachechar __collate_version[STR_LEN]; 5487012Sacheu_char charmap_table[UCHAR_MAX + 1][CHARMAP_SYMBOL_LEN]; 55101866Sache 56101866Sache#undef __collate_substitute_table 576527Sacheu_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN]; 58101866Sache#undef __collate_char_pri_table 596527Sachestruct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1]; 60102640Sachestruct __collate_st_chain_pri *__collate_chain_pri_table; 61101866Sache 62142686Sruint chain_index = 0; 636527Sacheint prim_pri = 1, sec_pri = 1; 646527Sache#ifdef COLLATE_DEBUG 656527Sacheint debug; 666527Sache#endif 676527Sache 6887243Smarkmconst char *out_file = "LC_COLLATE"; 696527Sache%} 706527Sache%union { 716527Sache u_char ch; 7287052Sache u_char str[BUFSIZE]; 736527Sache} 746527Sache%token SUBSTITUTE WITH ORDER RANGE 756527Sache%token <str> STRING 7618950Sache%token <str> DEFN 776527Sache%token <ch> CHAR 786527Sache%% 796527Sachecollate : statment_list 806527Sache; 816527Sachestatment_list : statment 826527Sache | statment_list '\n' statment 836527Sache; 846527Sachestatment : 856527Sache | charmap 866527Sache | substitute 876527Sache | order 886527Sache; 8918950Sachecharmap : DEFN CHAR { 9087015Sache if (strlen($1) + 1 > CHARMAP_SYMBOL_LEN) 9187015Sache yyerror("Charmap symbol name '%s' is too long", $1); 9218950Sache strcpy(charmap_table[$2], $1); 936527Sache} 946527Sache; 9543967Sachesubstitute : SUBSTITUTE CHAR WITH STRING { 9643967Sache if ($2 == '\0') 9743943Sache yyerror("NUL character can't be substituted"); 9843967Sache if (strchr($4, $2) != NULL) 9943967Sache yyerror("Char 0x%02x substitution is recursive", $2); 10087052Sache if (strlen($4) + 1 > STR_LEN) 10187052Sache yyerror("Char 0x%02x substitution is too long", $2); 10243967Sache strcpy(__collate_substitute_table[$2], $4); 1036527Sache} 1046527Sache; 1056527Sacheorder : ORDER order_list { 10619128Sache FILE *fp; 10743943Sache int ch, substed, ordered; 108102659Sache uint32_t u32; 1096527Sache 11043943Sache for (ch = 0; ch < UCHAR_MAX + 1; ch++) { 11143943Sache substed = (__collate_substitute_table[ch][0] != ch); 11243943Sache ordered = !!__collate_char_pri_table[ch].prim; 11343943Sache if (!ordered && !substed) 11443940Sache yyerror("Char 0x%02x not found", ch); 11543943Sache if (substed && ordered) 11643943Sache yyerror("Char 0x%02x can't be ordered since substituted", ch); 11743943Sache } 11819128Sache 119102659Sache if ((__collate_chain_pri_table = realloc(__collate_chain_pri_table, 120102659Sache sizeof(*__collate_chain_pri_table) * (chain_index + 1))) == NULL) 121102659Sache yyerror("can't grow chain table"); 122142649Sru (void)memset(&__collate_chain_pri_table[chain_index], 0, 123142649Sru sizeof(__collate_chain_pri_table[0])); 124102659Sache chain_index++; 125102659Sache 126142686Sru#ifdef COLLATE_DEBUG 127142686Sru if (debug) 128142686Sru collate_print_tables(); 129142686Sru#endif 130102640Sache if ((fp = fopen(out_file, "w")) == NULL) 13118950Sache err(EX_UNAVAILABLE, "can't open destination file %s", 1326527Sache out_file); 1336527Sache 134142686Sru strcpy(__collate_version, COLLATE_VERSION1_2); 135102640Sache if (fwrite(__collate_version, sizeof(__collate_version), 1, fp) != 1) 136102640Sache err(EX_IOERR, 137102640Sache "IO error writting collate version to destination file %s", 13818950Sache out_file); 139102659Sache u32 = htonl(chain_index); 140102659Sache if (fwrite(&u32, sizeof(u32), 1, fp) != 1) 141102659Sache err(EX_IOERR, 142102659Sache "IO error writting chains number to destination file %s", 143102659Sache out_file); 144102640Sache if (fwrite(__collate_substitute_table, 145102640Sache sizeof(__collate_substitute_table), 1, fp) != 1) 146102640Sache err(EX_IOERR, 147102640Sache "IO error writting substitute table to destination file %s", 148102640Sache out_file); 149142686Sru for (ch = 0; ch < UCHAR_MAX + 1; ch++) { 150142686Sru __collate_char_pri_table[ch].prim = 151142686Sru htonl(__collate_char_pri_table[ch].prim); 152142686Sru __collate_char_pri_table[ch].sec = 153142686Sru htonl(__collate_char_pri_table[ch].sec); 154142686Sru } 155102640Sache if (fwrite(__collate_char_pri_table, 156102640Sache sizeof(__collate_char_pri_table), 1, fp) != 1) 157102640Sache err(EX_IOERR, 158102640Sache "IO error writting char table to destination file %s", 159102640Sache out_file); 160142686Sru for (ch = 0; ch < chain_index; ch++) { 161142686Sru __collate_chain_pri_table[ch].prim = 162142686Sru htonl(__collate_chain_pri_table[ch].prim); 163142686Sru __collate_chain_pri_table[ch].sec = 164142686Sru htonl(__collate_chain_pri_table[ch].sec); 165142686Sru } 166102640Sache if (fwrite(__collate_chain_pri_table, 167102659Sache sizeof(*__collate_chain_pri_table), chain_index, fp) != 168102942Sdwmalone (size_t)chain_index) 169102640Sache err(EX_IOERR, 170102640Sache "IO error writting chain table to destination file %s", 171102640Sache out_file); 172102640Sache if (fclose(fp) != 0) 173102640Sache err(EX_IOERR, "IO error closing destination file %s", 174102640Sache out_file); 1756527Sache exit(EX_OK); 1766527Sache} 1776527Sache; 1786527Sacheorder_list : item 1796527Sache | order_list ';' item 1806527Sache; 181102299Sachechain : CHAR CHAR { 182102299Sache curr_chain[0] = $1; 183102299Sache curr_chain[1] = $2; 184102299Sache if (curr_chain[0] == '\0' || curr_chain[1] == '\0') 185102299Sache yyerror("\\0 can't be chained"); 186102299Sache curr_chain[2] = '\0'; 187102299Sache} 188102299Sache | chain CHAR { 189102299Sache static char tb[2]; 190102299Sache 191102299Sache tb[0] = $2; 192102299Sache if (tb[0] == '\0') 193102299Sache yyerror("\\0 can't be chained"); 194102299Sache if (strlen(curr_chain) + 2 > STR_LEN) 195102299Sache yyerror("Chain '%s' grows too long", curr_chain); 196102299Sache (void)strcat(curr_chain, tb); 197102299Sache} 198102299Sache; 19919128Sacheitem : CHAR { 20019128Sache if (__collate_char_pri_table[$1].prim) 20119163Sache yyerror("Char 0x%02x duplicated", $1); 20219128Sache __collate_char_pri_table[$1].prim = prim_pri++; 20319128Sache} 204102299Sache | chain { 205102659Sache if ((__collate_chain_pri_table = realloc(__collate_chain_pri_table, 206102659Sache sizeof(*__collate_chain_pri_table) * (chain_index + 1))) == NULL) 207102659Sache yyerror("can't grow chain table"); 208142649Sru (void)memset(&__collate_chain_pri_table[chain_index], 0, 209142649Sru sizeof(__collate_chain_pri_table[0])); 210102299Sache (void)strcpy(__collate_chain_pri_table[chain_index].str, curr_chain); 211102659Sache __collate_chain_pri_table[chain_index].prim = prim_pri++; 212102659Sache chain_index++; 2136527Sache} 2146527Sache | CHAR RANGE CHAR { 2156527Sache u_int i; 2166527Sache 2176527Sache if ($3 <= $1) 21818950Sache yyerror("Illegal range 0x%02x -- 0x%02x", $1, $3); 2196527Sache 22019128Sache for (i = $1; i <= $3; i++) { 22119128Sache if (__collate_char_pri_table[(u_char)i].prim) 22219163Sache yyerror("Char 0x%02x duplicated", (u_char)i); 2236527Sache __collate_char_pri_table[(u_char)i].prim = prim_pri++; 22419128Sache } 2256527Sache} 2266527Sache | '{' prim_order_list '}' { 2276527Sache prim_pri++; 2286527Sache} 2296527Sache | '(' sec_order_list ')' { 2306527Sache prim_pri++; 2316527Sache sec_pri = 1; 2326527Sache} 2336527Sache; 2346527Sacheprim_order_list : prim_sub_item 2356527Sache | prim_order_list ',' prim_sub_item 2366527Sache; 2376527Sachesec_order_list : sec_sub_item 2386527Sache | sec_order_list ',' sec_sub_item 2396527Sache; 2406527Sacheprim_sub_item : CHAR { 24119128Sache if (__collate_char_pri_table[$1].prim) 24219163Sache yyerror("Char 0x%02x duplicated", $1); 2436527Sache __collate_char_pri_table[$1].prim = prim_pri; 2446527Sache} 2456527Sache | CHAR RANGE CHAR { 2466527Sache u_int i; 2476527Sache 2486527Sache if ($3 <= $1) 24918950Sache yyerror("Illegal range 0x%02x -- 0x%02x", 25018950Sache $1, $3); 2516527Sache 25219128Sache for (i = $1; i <= $3; i++) { 25319128Sache if (__collate_char_pri_table[(u_char)i].prim) 25419163Sache yyerror("Char 0x%02x duplicated", (u_char)i); 2556527Sache __collate_char_pri_table[(u_char)i].prim = prim_pri; 25619128Sache } 2576527Sache} 258102299Sache | chain { 259102659Sache if ((__collate_chain_pri_table = realloc(__collate_chain_pri_table, 260102659Sache sizeof(*__collate_chain_pri_table) * (chain_index + 1))) == NULL) 261102659Sache yyerror("can't grow chain table"); 262142649Sru (void)memset(&__collate_chain_pri_table[chain_index], 0, 263142649Sru sizeof(__collate_chain_pri_table[0])); 264102299Sache (void)strcpy(__collate_chain_pri_table[chain_index].str, curr_chain); 265102659Sache __collate_chain_pri_table[chain_index].prim = prim_pri; 266102659Sache chain_index++; 2676527Sache} 2686527Sache; 2696527Sachesec_sub_item : CHAR { 27019128Sache if (__collate_char_pri_table[$1].prim) 27119163Sache yyerror("Char 0x%02x duplicated", $1); 2726527Sache __collate_char_pri_table[$1].prim = prim_pri; 2736527Sache __collate_char_pri_table[$1].sec = sec_pri++; 2746527Sache} 2756527Sache | CHAR RANGE CHAR { 2766527Sache u_int i; 2776527Sache 2786527Sache if ($3 <= $1) 27918950Sache yyerror("Illegal range 0x%02x -- 0x%02x", 28018950Sache $1, $3); 2816527Sache 2826527Sache for (i = $1; i <= $3; i++) { 28319128Sache if (__collate_char_pri_table[(u_char)i].prim) 28419163Sache yyerror("Char 0x%02x duplicated", (u_char)i); 2856527Sache __collate_char_pri_table[(u_char)i].prim = prim_pri; 2866527Sache __collate_char_pri_table[(u_char)i].sec = sec_pri++; 2876527Sache } 2886527Sache} 289102299Sache | chain { 290102659Sache if ((__collate_chain_pri_table = realloc(__collate_chain_pri_table, 291102659Sache sizeof(*__collate_chain_pri_table) * (chain_index + 1))) == NULL) 292102659Sache yyerror("can't grow chain table"); 293142649Sru (void)memset(&__collate_chain_pri_table[chain_index], 0, 294142649Sru sizeof(__collate_chain_pri_table[0])); 295102299Sache (void)strcpy(__collate_chain_pri_table[chain_index].str, curr_chain); 2966527Sache __collate_chain_pri_table[chain_index].prim = prim_pri; 297102659Sache __collate_chain_pri_table[chain_index].sec = sec_pri++; 298102659Sache chain_index++; 2996527Sache} 3006527Sache; 3016527Sache%% 30241568Sarchieint 303100816Sdwmalonemain(int ac, char **av) 3046527Sache{ 3056527Sache int ch; 3066527Sache 3076527Sache#ifdef COLLATE_DEBUG 308105237Scharnier while((ch = getopt(ac, av, ":do:I:")) != -1) { 3096527Sache#else 310105237Scharnier while((ch = getopt(ac, av, ":o:I:")) != -1) { 3116527Sache#endif 3126527Sache switch (ch) 3136527Sache { 3146527Sache#ifdef COLLATE_DEBUG 3156527Sache case 'd': 3166527Sache debug++; 3176527Sache break; 3186527Sache#endif 3196527Sache case 'o': 3206527Sache out_file = optarg; 3216527Sache break; 3226527Sache 32318950Sache case 'I': 32485026Ssobomax strlcpy(map_name, optarg, sizeof(map_name)); 32518950Sache break; 32618950Sache 3276527Sache default: 32826959Scharnier usage(); 3296527Sache } 3306527Sache } 3316527Sache ac -= optind; 3326527Sache av += optind; 333102640Sache if (ac > 0) { 334102640Sache if ((yyin = fopen(*av, "r")) == NULL) 3356527Sache err(EX_UNAVAILABLE, "can't open source file %s", *av); 3366527Sache } 337102640Sache for (ch = 0; ch <= UCHAR_MAX; ch++) 3386527Sache __collate_substitute_table[ch][0] = ch; 3396527Sache yyparse(); 3406527Sache return 0; 3416527Sache} 3426527Sache 34326959Scharnierstatic void 344100816Sdwmaloneusage(void) 34526959Scharnier{ 346146466Sru fprintf(stderr, "usage: colldef [-I map_dir] [-o out_file] [filename]\n"); 34727109Scharnier exit(EX_USAGE); 34826959Scharnier} 34926959Scharnier 35087243Smarkmvoid 35187243Smarkmyyerror(const char *fmt, ...) 3526527Sache{ 35318950Sache va_list ap; 35418950Sache char msg[128]; 35518950Sache 35618950Sache va_start(ap, fmt); 35769194Skris vsnprintf(msg, sizeof(msg), fmt, ap); 35818950Sache va_end(ap); 3596527Sache errx(EX_UNAVAILABLE, "%s near line %d", msg, line_no); 3606527Sache} 36119128Sache 36219128Sache#ifdef COLLATE_DEBUG 36387243Smarkmstatic void 36487243Smarkmcollate_print_tables(void) 36519128Sache{ 36619128Sache int i; 36719128Sache 36819128Sache printf("Substitute table:\n"); 36919128Sache for (i = 0; i < UCHAR_MAX + 1; i++) 37019128Sache if (i != *__collate_substitute_table[i]) 37119128Sache printf("\t'%c' --> \"%s\"\n", i, 37219128Sache __collate_substitute_table[i]); 37319128Sache printf("Chain priority table:\n"); 374142686Sru for (i = 0; i < chain_index - 1; i++) 375142686Sru printf("\t\"%s\" : %d %d\n", 376142686Sru __collate_chain_pri_table[i].str, 377142686Sru __collate_chain_pri_table[i].prim, 378142686Sru __collate_chain_pri_table[i].sec); 37919128Sache printf("Char priority table:\n"); 38019128Sache for (i = 0; i < UCHAR_MAX + 1; i++) 38119128Sache printf("\t'%c' : %d %d\n", i, __collate_char_pri_table[i].prim, 38219128Sache __collate_char_pri_table[i].sec); 38319128Sache} 38419128Sache#endif 385