1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include "sun_msgfmt.h" 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate static void read_psffm(char *); 32*0Sstevel@tonic-gate static void sortit(char *, char *); 33*0Sstevel@tonic-gate static wchar_t *consume_whitespace(wchar_t *); 34*0Sstevel@tonic-gate static char expand_meta(wchar_t **); 35*0Sstevel@tonic-gate static struct domain_struct *find_domain_node(char *); 36*0Sstevel@tonic-gate static void insert_message(struct domain_struct *, char *, char *); 37*0Sstevel@tonic-gate static void output_all_mo_files(void); 38*0Sstevel@tonic-gate static void output_one_mo_file(struct domain_struct *); 39*0Sstevel@tonic-gate static size_t _mbsntowcs(wchar_t **, char **, size_t *); 40*0Sstevel@tonic-gate 41*0Sstevel@tonic-gate #ifdef DEBUG 42*0Sstevel@tonic-gate static void printlist(void); 43*0Sstevel@tonic-gate #endif 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate static char gcurrent_domain[TEXTDOMAINMAX+1]; 46*0Sstevel@tonic-gate static char *gmsgid; /* Stores msgid when read po file */ 47*0Sstevel@tonic-gate static char *gmsgstr; /* Stores msgstr when read po file */ 48*0Sstevel@tonic-gate static int gmsgid_size; /* The current size of msgid buffer */ 49*0Sstevel@tonic-gate static int gmsgstr_size; /* The current size of msgstr buffer */ 50*0Sstevel@tonic-gate static char *outfile = NULL; 51*0Sstevel@tonic-gate static int linenum; /* The line number in the file */ 52*0Sstevel@tonic-gate static int msgid_linenum; /* The last msgid token line number */ 53*0Sstevel@tonic-gate static int msgstr_linenum; /* The last msgstr token line number */ 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate static int oflag = 0; 56*0Sstevel@tonic-gate static int sun_p = 0; 57*0Sstevel@tonic-gate int verbose = 0; 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate static struct domain_struct *first_domain = NULL; 60*0Sstevel@tonic-gate static struct domain_struct *last_used_domain = NULL; 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate static int mbcurmax; 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate static char **oargv; 65*0Sstevel@tonic-gate static char *inputdir; 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate extern void check_gnu(char *, size_t); 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate #define GNU_MSGFMT "/usr/lib/gmsgfmt" 70*0Sstevel@tonic-gate void 71*0Sstevel@tonic-gate invoke_gnu_msgfmt(void) 72*0Sstevel@tonic-gate { 73*0Sstevel@tonic-gate /* 74*0Sstevel@tonic-gate * Transferring to /usr/lib/gmsgfmt 75*0Sstevel@tonic-gate */ 76*0Sstevel@tonic-gate char *gnu_msgfmt; 77*0Sstevel@tonic-gate #ifdef DEBUG_MSGFMT 78*0Sstevel@tonic-gate gnu_msgfmt = getenv("GNU_MSGFMT"); 79*0Sstevel@tonic-gate if (!gnu_msgfmt) 80*0Sstevel@tonic-gate gnu_msgfmt = GNU_MSGFMT; 81*0Sstevel@tonic-gate #else 82*0Sstevel@tonic-gate gnu_msgfmt = GNU_MSGFMT; 83*0Sstevel@tonic-gate #endif 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate if (verbose) { 86*0Sstevel@tonic-gate diag(gettext(DIAG_INVOKING_GNU)); 87*0Sstevel@tonic-gate } 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate (void) execv(gnu_msgfmt, oargv); 90*0Sstevel@tonic-gate /* exec failed */ 91*0Sstevel@tonic-gate error(gettext(ERR_EXEC_FAILED), gnu_msgfmt); 92*0Sstevel@tonic-gate /* NOTREACHED */ 93*0Sstevel@tonic-gate } 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate static void 96*0Sstevel@tonic-gate usage(void) 97*0Sstevel@tonic-gate { 98*0Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERR_USAGE)); 99*0Sstevel@tonic-gate exit(2); 100*0Sstevel@tonic-gate } 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate /* 103*0Sstevel@tonic-gate * msgfmt - Generate binary tree for runtime gettext() using psffm: "Portable 104*0Sstevel@tonic-gate * Source File Format for Messages" file template. This file may have 105*0Sstevel@tonic-gate * previously been generated by the xgettext filter for c source files. 106*0Sstevel@tonic-gate */ 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate int 109*0Sstevel@tonic-gate main(int argc, char **argv) 110*0Sstevel@tonic-gate { 111*0Sstevel@tonic-gate int ret; 112*0Sstevel@tonic-gate static struct flags flag; 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 115*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 116*0Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 117*0Sstevel@tonic-gate #endif 118*0Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate oargv = argv; 121*0Sstevel@tonic-gate ret = parse_option(&argc, &argv, &flag); 122*0Sstevel@tonic-gate if (ret == -1) { 123*0Sstevel@tonic-gate usage(); 124*0Sstevel@tonic-gate /* NOTREACHED */ 125*0Sstevel@tonic-gate } 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate if (flag.sun_p) { 128*0Sstevel@tonic-gate /* never invoke gnu msgfmt */ 129*0Sstevel@tonic-gate if (flag.gnu_p) { 130*0Sstevel@tonic-gate error(gettext(ERR_GNU_ON_SUN)); 131*0Sstevel@tonic-gate /* NOTREACHED */ 132*0Sstevel@tonic-gate } 133*0Sstevel@tonic-gate sun_p = flag.sun_p; 134*0Sstevel@tonic-gate } 135*0Sstevel@tonic-gate if (flag.idir) { 136*0Sstevel@tonic-gate inputdir = flag.idir; 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate if (flag.ofile) { 139*0Sstevel@tonic-gate oflag = 1; 140*0Sstevel@tonic-gate outfile = flag.ofile; 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate if (flag.verbose) { 143*0Sstevel@tonic-gate verbose = 1; 144*0Sstevel@tonic-gate } 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate if (flag.gnu_p) { 147*0Sstevel@tonic-gate /* invoke /usr/lib/gmsgfmt */ 148*0Sstevel@tonic-gate invoke_gnu_msgfmt(); 149*0Sstevel@tonic-gate /* NOTREACHED */ 150*0Sstevel@tonic-gate } 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate /* 153*0Sstevel@tonic-gate * read all portable object files specified in command arguments. 154*0Sstevel@tonic-gate * Allocate initial size for msgid and msgstr. If it needs more 155*0Sstevel@tonic-gate * spaces, realloc later. 156*0Sstevel@tonic-gate */ 157*0Sstevel@tonic-gate gmsgid = (char *)Xmalloc(MAX_VALUE_LEN); 158*0Sstevel@tonic-gate gmsgstr = (char *)Xmalloc(MAX_VALUE_LEN); 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate gmsgid_size = gmsgstr_size = MAX_VALUE_LEN; 161*0Sstevel@tonic-gate (void) memset(gmsgid, 0, gmsgid_size); 162*0Sstevel@tonic-gate (void) memset(gmsgstr, 0, gmsgstr_size); 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate mbcurmax = MB_CUR_MAX; 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate while (argc-- > 0) { 167*0Sstevel@tonic-gate if (verbose) { 168*0Sstevel@tonic-gate diag(gettext(DIAG_START_PROC), *argv); 169*0Sstevel@tonic-gate } 170*0Sstevel@tonic-gate read_psffm(*argv++); 171*0Sstevel@tonic-gate } 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate output_all_mo_files(); 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate #ifdef DEBUG 176*0Sstevel@tonic-gate printlist(); 177*0Sstevel@tonic-gate #endif 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate return (0); 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate } /* main */ 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate /* 186*0Sstevel@tonic-gate * read_psffm - read in "psffm" format file, check syntax, printing error 187*0Sstevel@tonic-gate * messages as needed, output binary tree to file <domain> 188*0Sstevel@tonic-gate */ 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate static void 191*0Sstevel@tonic-gate read_psffm(char *file) 192*0Sstevel@tonic-gate { 193*0Sstevel@tonic-gate int fd; 194*0Sstevel@tonic-gate static char msgfile[MAXPATHLEN]; 195*0Sstevel@tonic-gate wchar_t *linebufptr, *p; 196*0Sstevel@tonic-gate char *bufptr = 0; 197*0Sstevel@tonic-gate int quotefound; /* double quote was seen */ 198*0Sstevel@tonic-gate int inmsgid = 0; /* indicates "msgid" was seen */ 199*0Sstevel@tonic-gate int inmsgstr = 0; /* indicates "msgstr" was seen */ 200*0Sstevel@tonic-gate int indomain = 0; /* indicates "domain" was seen */ 201*0Sstevel@tonic-gate wchar_t wc; 202*0Sstevel@tonic-gate char mb; 203*0Sstevel@tonic-gate int n; 204*0Sstevel@tonic-gate char token_found; /* Boolean value */ 205*0Sstevel@tonic-gate unsigned int bufptr_index = 0; /* current index of bufptr */ 206*0Sstevel@tonic-gate char *mbuf, *addr; 207*0Sstevel@tonic-gate size_t fsize, ln_size, ll; 208*0Sstevel@tonic-gate wchar_t *linebufhead = NULL; 209*0Sstevel@tonic-gate struct stat64 statbuf; 210*0Sstevel@tonic-gate char *filename; 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate /* 213*0Sstevel@tonic-gate * For each po file to be read, 214*0Sstevel@tonic-gate * 1) set domain to default and 215*0Sstevel@tonic-gate * 2) set linenumer to 0. 216*0Sstevel@tonic-gate */ 217*0Sstevel@tonic-gate (void) strcpy(gcurrent_domain, DEFAULT_DOMAIN); 218*0Sstevel@tonic-gate linenum = 0; 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate if (!inputdir) { 221*0Sstevel@tonic-gate filename = Xstrdup(file); 222*0Sstevel@tonic-gate } else { 223*0Sstevel@tonic-gate size_t dirlen, filelen, len; 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate dirlen = strlen(inputdir); 226*0Sstevel@tonic-gate filelen = strlen(file); 227*0Sstevel@tonic-gate len = dirlen + 1 + filelen + 1; 228*0Sstevel@tonic-gate filename = (char *)Xmalloc(len); 229*0Sstevel@tonic-gate (void) memcpy(filename, inputdir, dirlen); 230*0Sstevel@tonic-gate *(filename + dirlen) = '/'; 231*0Sstevel@tonic-gate (void) memcpy(filename + dirlen + 1, file, filelen); 232*0Sstevel@tonic-gate *(filename + dirlen + 1 + filelen) = '\0'; 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate fd = open(filename, O_RDONLY); 236*0Sstevel@tonic-gate if (fd == -1) { 237*0Sstevel@tonic-gate error(gettext(ERR_OPEN_FAILED), filename); 238*0Sstevel@tonic-gate /* NOTREACHED */ 239*0Sstevel@tonic-gate } 240*0Sstevel@tonic-gate if (fstat64(fd, &statbuf) == -1) { 241*0Sstevel@tonic-gate error(gettext(ERR_STAT_FAILED), filename); 242*0Sstevel@tonic-gate /* NOTREACHED */ 243*0Sstevel@tonic-gate } 244*0Sstevel@tonic-gate fsize = (size_t)statbuf.st_size; 245*0Sstevel@tonic-gate if (fsize == 0) { 246*0Sstevel@tonic-gate /* 247*0Sstevel@tonic-gate * The size of the specified po file is 0. 248*0Sstevel@tonic-gate * In Solaris 8 and earlier, msgfmt was silent 249*0Sstevel@tonic-gate * for the null po file. So, just returns 250*0Sstevel@tonic-gate * without generating an error message. 251*0Sstevel@tonic-gate */ 252*0Sstevel@tonic-gate (void) close(fd); 253*0Sstevel@tonic-gate free(filename); 254*0Sstevel@tonic-gate return; 255*0Sstevel@tonic-gate } 256*0Sstevel@tonic-gate addr = mmap(NULL, fsize, PROT_READ, MAP_SHARED, fd, 0); 257*0Sstevel@tonic-gate if (addr == MAP_FAILED) { 258*0Sstevel@tonic-gate error(gettext(ERR_MMAP_FAILED), filename); 259*0Sstevel@tonic-gate /* NOTREACHED */ 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate (void) close(fd); 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate if (!sun_p) 264*0Sstevel@tonic-gate check_gnu(addr, fsize); 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate mbuf = addr; 267*0Sstevel@tonic-gate for (;;) { 268*0Sstevel@tonic-gate if (linebufhead) { 269*0Sstevel@tonic-gate free(linebufhead); 270*0Sstevel@tonic-gate linebufhead = NULL; 271*0Sstevel@tonic-gate } 272*0Sstevel@tonic-gate ln_size = _mbsntowcs(&linebufhead, &mbuf, &fsize); 273*0Sstevel@tonic-gate if (ln_size == (size_t)-1) { 274*0Sstevel@tonic-gate error(gettext(ERR_READ_FAILED), filename); 275*0Sstevel@tonic-gate /* NOTREACHED */ 276*0Sstevel@tonic-gate } else if (ln_size == 0) { 277*0Sstevel@tonic-gate break; /* End of File. */ 278*0Sstevel@tonic-gate } 279*0Sstevel@tonic-gate linenum++; 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate linebufptr = linebufhead; 282*0Sstevel@tonic-gate quotefound = 0; 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate switch (*linebufptr) { 285*0Sstevel@tonic-gate case L'#': /* comment */ 286*0Sstevel@tonic-gate case L'\n': /* empty line */ 287*0Sstevel@tonic-gate continue; 288*0Sstevel@tonic-gate case L'\"': /* multiple lines of msgid and msgstr */ 289*0Sstevel@tonic-gate quotefound = 1; 290*0Sstevel@tonic-gate break; 291*0Sstevel@tonic-gate } 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate /* 294*0Sstevel@tonic-gate * Process MSGID Tokens. 295*0Sstevel@tonic-gate */ 296*0Sstevel@tonic-gate token_found = (wcsncmp(MSGID_TOKEN, linebufptr, 297*0Sstevel@tonic-gate MSGID_LEN) == 0) ? 1 : 0; 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate if (token_found || (quotefound && inmsgid)) { 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate if (token_found) { 302*0Sstevel@tonic-gate if (!CK_NXT_CH(linebufptr, MSGID_LEN+1)) { 303*0Sstevel@tonic-gate diag(gettext(ERR_NOSPC), linenum); 304*0Sstevel@tonic-gate error(gettext(ERR_EXITING)); 305*0Sstevel@tonic-gate /* NOTREACHED */ 306*0Sstevel@tonic-gate } 307*0Sstevel@tonic-gate } 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate if (inmsgid && !quotefound) { 310*0Sstevel@tonic-gate warning(gettext(WARN_NO_MSGSTR), msgid_linenum); 311*0Sstevel@tonic-gate continue; 312*0Sstevel@tonic-gate } 313*0Sstevel@tonic-gate if (inmsgstr) { 314*0Sstevel@tonic-gate sortit(gmsgid, gmsgstr); 315*0Sstevel@tonic-gate (void) memset(gmsgid, 0, gmsgid_size); 316*0Sstevel@tonic-gate (void) memset(gmsgstr, 0, gmsgstr_size); 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate if (inmsgid) { 320*0Sstevel@tonic-gate /* multiple lines of msgid */ 321*0Sstevel@tonic-gate /* cancel the previous null termination */ 322*0Sstevel@tonic-gate bufptr_index--; 323*0Sstevel@tonic-gate } else { 324*0Sstevel@tonic-gate /* 325*0Sstevel@tonic-gate * The first line of msgid. 326*0Sstevel@tonic-gate * Save linenum of msgid to be used when 327*0Sstevel@tonic-gate * printing warning or error message. 328*0Sstevel@tonic-gate */ 329*0Sstevel@tonic-gate msgid_linenum = linenum; 330*0Sstevel@tonic-gate p = linebufptr; 331*0Sstevel@tonic-gate linebufptr = consume_whitespace( 332*0Sstevel@tonic-gate linebufptr + MSGID_LEN); 333*0Sstevel@tonic-gate ln_size -= linebufptr - p; 334*0Sstevel@tonic-gate bufptr = gmsgid; 335*0Sstevel@tonic-gate bufptr_index = 0; 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate inmsgid = 1; 339*0Sstevel@tonic-gate inmsgstr = 0; 340*0Sstevel@tonic-gate indomain = 0; 341*0Sstevel@tonic-gate goto load_buffer; 342*0Sstevel@tonic-gate } 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate /* 345*0Sstevel@tonic-gate * Process MSGSTR Tokens. 346*0Sstevel@tonic-gate */ 347*0Sstevel@tonic-gate token_found = (wcsncmp(MSGSTR_TOKEN, linebufptr, 348*0Sstevel@tonic-gate MSGSTR_LEN) == 0) ? 1 : 0; 349*0Sstevel@tonic-gate if (token_found || (quotefound && inmsgstr)) { 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate if (token_found) { 352*0Sstevel@tonic-gate if (!CK_NXT_CH(linebufptr, MSGSTR_LEN+1)) { 353*0Sstevel@tonic-gate diag(gettext(ERR_NOSPC), linenum); 354*0Sstevel@tonic-gate error(gettext(ERR_EXITING)); 355*0Sstevel@tonic-gate /* NOTREACHED */ 356*0Sstevel@tonic-gate } 357*0Sstevel@tonic-gate } 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate if (inmsgstr && !quotefound) { 361*0Sstevel@tonic-gate warning(gettext(WARN_NO_MSGID), msgstr_linenum); 362*0Sstevel@tonic-gate continue; 363*0Sstevel@tonic-gate } 364*0Sstevel@tonic-gate if (inmsgstr) { 365*0Sstevel@tonic-gate /* multiple lines of msgstr */ 366*0Sstevel@tonic-gate /* cancel the previous null termination */ 367*0Sstevel@tonic-gate bufptr_index--; 368*0Sstevel@tonic-gate } else { 369*0Sstevel@tonic-gate /* 370*0Sstevel@tonic-gate * The first line of msgstr. 371*0Sstevel@tonic-gate * Save linenum of msgid to be used when 372*0Sstevel@tonic-gate * printing warning or error message. 373*0Sstevel@tonic-gate */ 374*0Sstevel@tonic-gate msgstr_linenum = linenum; 375*0Sstevel@tonic-gate p = linebufptr; 376*0Sstevel@tonic-gate linebufptr = consume_whitespace( 377*0Sstevel@tonic-gate linebufptr + MSGSTR_LEN); 378*0Sstevel@tonic-gate ln_size -= linebufptr - p; 379*0Sstevel@tonic-gate bufptr = gmsgstr; 380*0Sstevel@tonic-gate bufptr_index = 0; 381*0Sstevel@tonic-gate } 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate inmsgstr = 1; 384*0Sstevel@tonic-gate inmsgid = 0; 385*0Sstevel@tonic-gate indomain = 0; 386*0Sstevel@tonic-gate goto load_buffer; 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate /* 390*0Sstevel@tonic-gate * Process DOMAIN Tokens. 391*0Sstevel@tonic-gate * Add message id and message string to sorted list 392*0Sstevel@tonic-gate * if msgstr was processed last time. 393*0Sstevel@tonic-gate */ 394*0Sstevel@tonic-gate token_found = (wcsncmp(DOMAIN_TOKEN, linebufptr, 395*0Sstevel@tonic-gate DOMAIN_LEN) == 0) ? 1 : 0; 396*0Sstevel@tonic-gate if ((token_found) || (quotefound && indomain)) { 397*0Sstevel@tonic-gate if (token_found) { 398*0Sstevel@tonic-gate if (!CK_NXT_CH(linebufptr, DOMAIN_LEN+1)) { 399*0Sstevel@tonic-gate diag(gettext(ERR_NOSPC), linenum); 400*0Sstevel@tonic-gate error(gettext(ERR_EXITING)); 401*0Sstevel@tonic-gate /* NOTREACHED */ 402*0Sstevel@tonic-gate } 403*0Sstevel@tonic-gate } 404*0Sstevel@tonic-gate 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate /* 407*0Sstevel@tonic-gate * process msgid and msgstr pair for previous domain 408*0Sstevel@tonic-gate */ 409*0Sstevel@tonic-gate if (inmsgstr) { 410*0Sstevel@tonic-gate sortit(gmsgid, gmsgstr); 411*0Sstevel@tonic-gate } 412*0Sstevel@tonic-gate 413*0Sstevel@tonic-gate /* refresh msgid and msgstr buffer */ 414*0Sstevel@tonic-gate if (inmsgstr || inmsgid) { 415*0Sstevel@tonic-gate (void) memset(gmsgid, 0, gmsgid_size); 416*0Sstevel@tonic-gate (void) memset(gmsgstr, 0, gmsgstr_size); 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate if (indomain) { 420*0Sstevel@tonic-gate /* multiple lines of domain */ 421*0Sstevel@tonic-gate /* cancel the previous null termination */ 422*0Sstevel@tonic-gate bufptr_index--; 423*0Sstevel@tonic-gate } else { 424*0Sstevel@tonic-gate p = linebufptr; 425*0Sstevel@tonic-gate linebufptr = consume_whitespace( 426*0Sstevel@tonic-gate linebufptr + DOMAIN_LEN); 427*0Sstevel@tonic-gate (void) memset(gcurrent_domain, 0, 428*0Sstevel@tonic-gate sizeof (gcurrent_domain)); 429*0Sstevel@tonic-gate ln_size -= linebufptr - p; 430*0Sstevel@tonic-gate bufptr = gcurrent_domain; 431*0Sstevel@tonic-gate bufptr_index = 0; 432*0Sstevel@tonic-gate } 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate indomain = 1; 435*0Sstevel@tonic-gate inmsgid = 0; 436*0Sstevel@tonic-gate inmsgstr = 0; 437*0Sstevel@tonic-gate } /* if */ 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate load_buffer: 440*0Sstevel@tonic-gate /* 441*0Sstevel@tonic-gate * Now, fill up the buffer pointed by bufptr. 442*0Sstevel@tonic-gate * At this point bufptr should point to one of 443*0Sstevel@tonic-gate * msgid, msgptr, or current_domain. 444*0Sstevel@tonic-gate * Otherwise, the entire line is ignored. 445*0Sstevel@tonic-gate */ 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate if (!bufptr) { 448*0Sstevel@tonic-gate warning(gettext(WARN_SYNTAX_ERR), linenum); 449*0Sstevel@tonic-gate continue; 450*0Sstevel@tonic-gate } 451*0Sstevel@tonic-gate 452*0Sstevel@tonic-gate if (*linebufptr++ != L'\"') { 453*0Sstevel@tonic-gate warning(gettext(WARN_MISSING_QUOTE), linenum); 454*0Sstevel@tonic-gate --linebufptr; 455*0Sstevel@tonic-gate } 456*0Sstevel@tonic-gate quotefound = 0; 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate /* 459*0Sstevel@tonic-gate * If there is not enough space in the buffer, 460*0Sstevel@tonic-gate * increase buffer by ln_size by realloc. 461*0Sstevel@tonic-gate */ 462*0Sstevel@tonic-gate ll = ln_size * mbcurmax; 463*0Sstevel@tonic-gate if (bufptr == gmsgid) { 464*0Sstevel@tonic-gate if (gmsgid_size < (bufptr_index + ll)) { 465*0Sstevel@tonic-gate gmsgid = (char *)Xrealloc(gmsgid, 466*0Sstevel@tonic-gate bufptr_index + ll); 467*0Sstevel@tonic-gate bufptr = gmsgid; 468*0Sstevel@tonic-gate gmsgid_size = bufptr_index + ll; 469*0Sstevel@tonic-gate } 470*0Sstevel@tonic-gate } else if (bufptr == gmsgstr) { 471*0Sstevel@tonic-gate if (gmsgstr_size < (bufptr_index + ll)) { 472*0Sstevel@tonic-gate gmsgstr = (char *)Xrealloc(gmsgstr, 473*0Sstevel@tonic-gate bufptr_index + ll); 474*0Sstevel@tonic-gate bufptr = gmsgstr; 475*0Sstevel@tonic-gate gmsgstr_size = bufptr_index + ll; 476*0Sstevel@tonic-gate } 477*0Sstevel@tonic-gate } 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate while (wc = *linebufptr++) { 480*0Sstevel@tonic-gate switch (wc) { 481*0Sstevel@tonic-gate case L'\n': 482*0Sstevel@tonic-gate if (!quotefound) { 483*0Sstevel@tonic-gate warning(gettext(WARN_MISSING_QUOTE_AT_EOL), linenum); 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate break; 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate case L'\"': 488*0Sstevel@tonic-gate quotefound = 1; 489*0Sstevel@tonic-gate break; 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate case L'\\': 492*0Sstevel@tonic-gate if ((mb = expand_meta(&linebufptr)) != NULL) 493*0Sstevel@tonic-gate bufptr[bufptr_index++] = mb; 494*0Sstevel@tonic-gate break; 495*0Sstevel@tonic-gate 496*0Sstevel@tonic-gate default: 497*0Sstevel@tonic-gate if ((n = wctomb(&bufptr[bufptr_index], wc)) > 0) 498*0Sstevel@tonic-gate bufptr_index += n; 499*0Sstevel@tonic-gate } /* switch */ 500*0Sstevel@tonic-gate if (quotefound) { 501*0Sstevel@tonic-gate /* 502*0Sstevel@tonic-gate * Check if any remaining characters 503*0Sstevel@tonic-gate * after closing quote. 504*0Sstevel@tonic-gate */ 505*0Sstevel@tonic-gate linebufptr = consume_whitespace(linebufptr); 506*0Sstevel@tonic-gate if (*linebufptr != L'\n') { 507*0Sstevel@tonic-gate warning(gettext(WARN_INVALID_STRING), 508*0Sstevel@tonic-gate linenum); 509*0Sstevel@tonic-gate } 510*0Sstevel@tonic-gate break; 511*0Sstevel@tonic-gate } 512*0Sstevel@tonic-gate } /* while */ 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate bufptr[bufptr_index++] = '\0'; 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate (void) strcpy(msgfile, gcurrent_domain); 517*0Sstevel@tonic-gate (void) strcat(msgfile, ".mo"); 518*0Sstevel@tonic-gate } /* for(;;) */ 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate if (inmsgstr) { 521*0Sstevel@tonic-gate sortit(gmsgid, gmsgstr); 522*0Sstevel@tonic-gate } 523*0Sstevel@tonic-gate 524*0Sstevel@tonic-gate if (linebufhead) 525*0Sstevel@tonic-gate free(linebufhead); 526*0Sstevel@tonic-gate if (munmap(addr, statbuf.st_size) == -1) { 527*0Sstevel@tonic-gate error(gettext(ERR_MUNMAP_FAILED), filename); 528*0Sstevel@tonic-gate /* NOTREACHED */ 529*0Sstevel@tonic-gate } 530*0Sstevel@tonic-gate 531*0Sstevel@tonic-gate free(filename); 532*0Sstevel@tonic-gate return; 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate } /* read_psffm */ 535*0Sstevel@tonic-gate 536*0Sstevel@tonic-gate 537*0Sstevel@tonic-gate /* 538*0Sstevel@tonic-gate * Skip leading white spaces and tabs. 539*0Sstevel@tonic-gate */ 540*0Sstevel@tonic-gate static wchar_t * 541*0Sstevel@tonic-gate consume_whitespace(wchar_t *buf) 542*0Sstevel@tonic-gate { 543*0Sstevel@tonic-gate wchar_t *bufptr = buf; 544*0Sstevel@tonic-gate wchar_t c; 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate /* 547*0Sstevel@tonic-gate * Skip leading white spaces. 548*0Sstevel@tonic-gate */ 549*0Sstevel@tonic-gate while ((c = *bufptr) != L'\0') { 550*0Sstevel@tonic-gate if (c == L' ' || c == L'\t') { 551*0Sstevel@tonic-gate bufptr++; 552*0Sstevel@tonic-gate continue; 553*0Sstevel@tonic-gate } 554*0Sstevel@tonic-gate break; 555*0Sstevel@tonic-gate } 556*0Sstevel@tonic-gate return (bufptr); 557*0Sstevel@tonic-gate } /* consume_white_space */ 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate /* 561*0Sstevel@tonic-gate * handle escape sequences. 562*0Sstevel@tonic-gate */ 563*0Sstevel@tonic-gate static char 564*0Sstevel@tonic-gate expand_meta(wchar_t **buf) 565*0Sstevel@tonic-gate { 566*0Sstevel@tonic-gate wchar_t wc = **buf; 567*0Sstevel@tonic-gate char n; 568*0Sstevel@tonic-gate 569*0Sstevel@tonic-gate switch (wc) { 570*0Sstevel@tonic-gate case L'"': 571*0Sstevel@tonic-gate (*buf)++; 572*0Sstevel@tonic-gate return ('\"'); 573*0Sstevel@tonic-gate case L'\\': 574*0Sstevel@tonic-gate (*buf)++; 575*0Sstevel@tonic-gate return ('\\'); 576*0Sstevel@tonic-gate case L'b': 577*0Sstevel@tonic-gate (*buf)++; 578*0Sstevel@tonic-gate return ('\b'); 579*0Sstevel@tonic-gate case L'f': 580*0Sstevel@tonic-gate (*buf)++; 581*0Sstevel@tonic-gate return ('\f'); 582*0Sstevel@tonic-gate case L'n': 583*0Sstevel@tonic-gate (*buf)++; 584*0Sstevel@tonic-gate return ('\n'); 585*0Sstevel@tonic-gate case L'r': 586*0Sstevel@tonic-gate (*buf)++; 587*0Sstevel@tonic-gate return ('\r'); 588*0Sstevel@tonic-gate case L't': 589*0Sstevel@tonic-gate (*buf)++; 590*0Sstevel@tonic-gate return ('\t'); 591*0Sstevel@tonic-gate case L'v': 592*0Sstevel@tonic-gate (*buf)++; 593*0Sstevel@tonic-gate return ('\v'); 594*0Sstevel@tonic-gate case L'a': 595*0Sstevel@tonic-gate (*buf)++; 596*0Sstevel@tonic-gate return ('\a'); 597*0Sstevel@tonic-gate case L'\'': 598*0Sstevel@tonic-gate (*buf)++; 599*0Sstevel@tonic-gate return ('\''); 600*0Sstevel@tonic-gate case L'?': 601*0Sstevel@tonic-gate (*buf)++; 602*0Sstevel@tonic-gate return ('\?'); 603*0Sstevel@tonic-gate case L'0': 604*0Sstevel@tonic-gate case L'1': 605*0Sstevel@tonic-gate case L'2': 606*0Sstevel@tonic-gate case L'3': 607*0Sstevel@tonic-gate case L'4': 608*0Sstevel@tonic-gate case L'5': 609*0Sstevel@tonic-gate case L'6': 610*0Sstevel@tonic-gate case L'7': 611*0Sstevel@tonic-gate /* 612*0Sstevel@tonic-gate * This case handles \ddd where ddd is octal number. 613*0Sstevel@tonic-gate * There could be one, two, or three octal numbers. 614*0Sstevel@tonic-gate */ 615*0Sstevel@tonic-gate (*buf)++; 616*0Sstevel@tonic-gate n = (char)(wc - L'0'); 617*0Sstevel@tonic-gate wc = **buf; 618*0Sstevel@tonic-gate if (wc >= L'0' && wc <= L'7') { 619*0Sstevel@tonic-gate (*buf)++; 620*0Sstevel@tonic-gate n = 8*n + (char)(wc - L'0'); 621*0Sstevel@tonic-gate wc = **buf; 622*0Sstevel@tonic-gate if (wc >= L'0' && wc <= L'7') { 623*0Sstevel@tonic-gate (*buf)++; 624*0Sstevel@tonic-gate n = 8*n + (char)(wc - L'0'); 625*0Sstevel@tonic-gate } 626*0Sstevel@tonic-gate } 627*0Sstevel@tonic-gate return (n); 628*0Sstevel@tonic-gate default: 629*0Sstevel@tonic-gate return (NULL); 630*0Sstevel@tonic-gate } 631*0Sstevel@tonic-gate } /* expand_meta */ 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate /* 634*0Sstevel@tonic-gate * Finds the head of the current domain linked list and 635*0Sstevel@tonic-gate * call insert_message() to insert msgid and msgstr pair 636*0Sstevel@tonic-gate * to the linked list. 637*0Sstevel@tonic-gate */ 638*0Sstevel@tonic-gate static void 639*0Sstevel@tonic-gate sortit(char *msgid, char *msgstr) 640*0Sstevel@tonic-gate { 641*0Sstevel@tonic-gate struct domain_struct *dom; 642*0Sstevel@tonic-gate 643*0Sstevel@tonic-gate #ifdef DEBUG 644*0Sstevel@tonic-gate (void) fprintf(stderr, 645*0Sstevel@tonic-gate "==> sortit(), domain=<%s> msgid=<%s> msgstr=<%s>\n", 646*0Sstevel@tonic-gate gcurrent_domain, msgid, msgstr); 647*0Sstevel@tonic-gate #endif 648*0Sstevel@tonic-gate 649*0Sstevel@tonic-gate /* 650*0Sstevel@tonic-gate * If "-o filename" is specified, then all "domain" directive 651*0Sstevel@tonic-gate * are ignored and, all messages will be stored in domain 652*0Sstevel@tonic-gate * whose name is filename. 653*0Sstevel@tonic-gate */ 654*0Sstevel@tonic-gate if (oflag) { 655*0Sstevel@tonic-gate dom = find_domain_node(outfile); 656*0Sstevel@tonic-gate } else { 657*0Sstevel@tonic-gate dom = find_domain_node(gcurrent_domain); 658*0Sstevel@tonic-gate } 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate insert_message(dom, msgid, msgstr); 661*0Sstevel@tonic-gate } 662*0Sstevel@tonic-gate 663*0Sstevel@tonic-gate /* 664*0Sstevel@tonic-gate * This routine inserts message in the current domain message list. 665*0Sstevel@tonic-gate * It is inserted in ascending order. 666*0Sstevel@tonic-gate */ 667*0Sstevel@tonic-gate static void 668*0Sstevel@tonic-gate insert_message(struct domain_struct *dom, 669*0Sstevel@tonic-gate char *msgid, char *msgstr) 670*0Sstevel@tonic-gate { 671*0Sstevel@tonic-gate struct msg_chain *p1; 672*0Sstevel@tonic-gate struct msg_chain *node, *prev_node; 673*0Sstevel@tonic-gate int b; 674*0Sstevel@tonic-gate 675*0Sstevel@tonic-gate /* 676*0Sstevel@tonic-gate * Find the optimal starting search position. 677*0Sstevel@tonic-gate * The starting search position is either the first node 678*0Sstevel@tonic-gate * or the current_elem of domain. 679*0Sstevel@tonic-gate * The current_elem is the pointer to the node which 680*0Sstevel@tonic-gate * is most recently accessed in domain. 681*0Sstevel@tonic-gate */ 682*0Sstevel@tonic-gate if (dom->current_elem != NULL) { 683*0Sstevel@tonic-gate b = strcmp(msgid, dom->current_elem->msgid); 684*0Sstevel@tonic-gate if (b == 0) { 685*0Sstevel@tonic-gate if (verbose) 686*0Sstevel@tonic-gate warning(gettext(WARN_DUP_MSG), 687*0Sstevel@tonic-gate msgid, msgid_linenum); 688*0Sstevel@tonic-gate return; 689*0Sstevel@tonic-gate } else if (b > 0) { /* to implement descending order */ 690*0Sstevel@tonic-gate p1 = dom->first_elem; 691*0Sstevel@tonic-gate } else { 692*0Sstevel@tonic-gate p1 = dom->current_elem; 693*0Sstevel@tonic-gate } 694*0Sstevel@tonic-gate } else { 695*0Sstevel@tonic-gate p1 = dom->first_elem; 696*0Sstevel@tonic-gate } 697*0Sstevel@tonic-gate 698*0Sstevel@tonic-gate /* 699*0Sstevel@tonic-gate * search msgid insert position in the list 700*0Sstevel@tonic-gate * Search starts from the node pointed by p1. 701*0Sstevel@tonic-gate */ 702*0Sstevel@tonic-gate prev_node = NULL; 703*0Sstevel@tonic-gate while (p1) { 704*0Sstevel@tonic-gate b = strcmp(msgid, p1->msgid); 705*0Sstevel@tonic-gate if (b == 0) { 706*0Sstevel@tonic-gate if (verbose) 707*0Sstevel@tonic-gate warning(gettext(WARN_DUP_MSG), 708*0Sstevel@tonic-gate msgid, msgid_linenum); 709*0Sstevel@tonic-gate return; 710*0Sstevel@tonic-gate } else if (b < 0) { /* to implement descending order */ 711*0Sstevel@tonic-gate /* move to the next node */ 712*0Sstevel@tonic-gate prev_node = p1; 713*0Sstevel@tonic-gate p1 = p1->next; 714*0Sstevel@tonic-gate } else { 715*0Sstevel@tonic-gate /* insert a new msg node */ 716*0Sstevel@tonic-gate node = (struct msg_chain *) 717*0Sstevel@tonic-gate Xmalloc(sizeof (struct msg_chain)); 718*0Sstevel@tonic-gate node->next = p1; 719*0Sstevel@tonic-gate node->msgid = Xstrdup(msgid); 720*0Sstevel@tonic-gate node->msgstr = Xstrdup(msgstr); 721*0Sstevel@tonic-gate 722*0Sstevel@tonic-gate if (prev_node) { 723*0Sstevel@tonic-gate prev_node->next = node; 724*0Sstevel@tonic-gate } else { 725*0Sstevel@tonic-gate dom->first_elem = node; 726*0Sstevel@tonic-gate } 727*0Sstevel@tonic-gate dom->current_elem = node; 728*0Sstevel@tonic-gate return; 729*0Sstevel@tonic-gate } 730*0Sstevel@tonic-gate } /* while */ 731*0Sstevel@tonic-gate 732*0Sstevel@tonic-gate /* 733*0Sstevel@tonic-gate * msgid is smaller than any of msgid in the list or 734*0Sstevel@tonic-gate * list is empty. 735*0Sstevel@tonic-gate * Therefore, append it. 736*0Sstevel@tonic-gate */ 737*0Sstevel@tonic-gate node = (struct msg_chain *) 738*0Sstevel@tonic-gate Xmalloc(sizeof (struct msg_chain)); 739*0Sstevel@tonic-gate node->next = NULL; 740*0Sstevel@tonic-gate node->msgid = Xstrdup(msgid); 741*0Sstevel@tonic-gate node->msgstr = Xstrdup(msgstr); 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate if (prev_node) { 744*0Sstevel@tonic-gate prev_node->next = node; 745*0Sstevel@tonic-gate } else { 746*0Sstevel@tonic-gate dom->first_elem = node; 747*0Sstevel@tonic-gate } 748*0Sstevel@tonic-gate dom->current_elem = node; 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate return; 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gate } /* insert_message */ 753*0Sstevel@tonic-gate 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate /* 756*0Sstevel@tonic-gate * This routine will find head of the linked list for the given 757*0Sstevel@tonic-gate * domain_name. This looks up cache entry first and if cache misses, 758*0Sstevel@tonic-gate * scans the list. 759*0Sstevel@tonic-gate * If not found, then create a new node. 760*0Sstevel@tonic-gate */ 761*0Sstevel@tonic-gate static struct domain_struct * 762*0Sstevel@tonic-gate find_domain_node(char *domain_name) 763*0Sstevel@tonic-gate { 764*0Sstevel@tonic-gate struct domain_struct *p1; 765*0Sstevel@tonic-gate struct domain_struct *node; 766*0Sstevel@tonic-gate struct domain_struct *prev_node; 767*0Sstevel@tonic-gate int b; 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gate 770*0Sstevel@tonic-gate /* for perfomance, check cache 'last_used_domain' */ 771*0Sstevel@tonic-gate if (last_used_domain) { 772*0Sstevel@tonic-gate b = strcmp(domain_name, last_used_domain->domain); 773*0Sstevel@tonic-gate if (b == 0) { 774*0Sstevel@tonic-gate return (last_used_domain); 775*0Sstevel@tonic-gate } else if (b < 0) { 776*0Sstevel@tonic-gate p1 = first_domain; 777*0Sstevel@tonic-gate } else { 778*0Sstevel@tonic-gate p1 = last_used_domain; 779*0Sstevel@tonic-gate } 780*0Sstevel@tonic-gate } else { 781*0Sstevel@tonic-gate p1 = first_domain; 782*0Sstevel@tonic-gate } 783*0Sstevel@tonic-gate 784*0Sstevel@tonic-gate prev_node = NULL; 785*0Sstevel@tonic-gate while (p1) { 786*0Sstevel@tonic-gate b = strcmp(domain_name, p1->domain); 787*0Sstevel@tonic-gate if (b == 0) { 788*0Sstevel@tonic-gate /* node found */ 789*0Sstevel@tonic-gate last_used_domain = p1; 790*0Sstevel@tonic-gate return (p1); 791*0Sstevel@tonic-gate } else if (b > 0) { 792*0Sstevel@tonic-gate /* move to the next node */ 793*0Sstevel@tonic-gate prev_node = p1; 794*0Sstevel@tonic-gate p1 = p1->next; 795*0Sstevel@tonic-gate } else { 796*0Sstevel@tonic-gate /* insert a new domain node */ 797*0Sstevel@tonic-gate node = (struct domain_struct *) 798*0Sstevel@tonic-gate Xmalloc(sizeof (struct domain_struct)); 799*0Sstevel@tonic-gate node->next = p1; 800*0Sstevel@tonic-gate node->domain = Xstrdup(domain_name); 801*0Sstevel@tonic-gate node->first_elem = NULL; 802*0Sstevel@tonic-gate node->current_elem = NULL; 803*0Sstevel@tonic-gate if (prev_node) { 804*0Sstevel@tonic-gate /* insert the node in the middle */ 805*0Sstevel@tonic-gate prev_node->next = node; 806*0Sstevel@tonic-gate } else { 807*0Sstevel@tonic-gate /* node inserted is the smallest */ 808*0Sstevel@tonic-gate first_domain = node; 809*0Sstevel@tonic-gate } 810*0Sstevel@tonic-gate last_used_domain = node; 811*0Sstevel@tonic-gate return (node); 812*0Sstevel@tonic-gate } 813*0Sstevel@tonic-gate } /* while */ 814*0Sstevel@tonic-gate 815*0Sstevel@tonic-gate /* 816*0Sstevel@tonic-gate * domain_name is larger than any of domain name in the list or 817*0Sstevel@tonic-gate * list is empty. 818*0Sstevel@tonic-gate */ 819*0Sstevel@tonic-gate node = (struct domain_struct *) 820*0Sstevel@tonic-gate Xmalloc(sizeof (struct domain_struct)); 821*0Sstevel@tonic-gate node->next = NULL; 822*0Sstevel@tonic-gate node->domain = Xstrdup(domain_name); 823*0Sstevel@tonic-gate node->first_elem = NULL; 824*0Sstevel@tonic-gate node->current_elem = NULL; 825*0Sstevel@tonic-gate if (prev_node) { 826*0Sstevel@tonic-gate /* domain list is not empty */ 827*0Sstevel@tonic-gate prev_node->next = node; 828*0Sstevel@tonic-gate } else { 829*0Sstevel@tonic-gate /* domain list is empty */ 830*0Sstevel@tonic-gate first_domain = node; 831*0Sstevel@tonic-gate } 832*0Sstevel@tonic-gate last_used_domain = node; 833*0Sstevel@tonic-gate 834*0Sstevel@tonic-gate return (node); 835*0Sstevel@tonic-gate 836*0Sstevel@tonic-gate } /* find_domain_node */ 837*0Sstevel@tonic-gate 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate /* 840*0Sstevel@tonic-gate * binary_compute() is used for pre-computing a binary search. 841*0Sstevel@tonic-gate */ 842*0Sstevel@tonic-gate static int 843*0Sstevel@tonic-gate binary_compute(int i, int j, int *more, int *less) 844*0Sstevel@tonic-gate { 845*0Sstevel@tonic-gate int k; 846*0Sstevel@tonic-gate 847*0Sstevel@tonic-gate if (i > j) { 848*0Sstevel@tonic-gate return (LEAFINDICATOR); 849*0Sstevel@tonic-gate } 850*0Sstevel@tonic-gate k = (i + j) / 2; 851*0Sstevel@tonic-gate 852*0Sstevel@tonic-gate less[k] = binary_compute(i, k - 1, more, less); 853*0Sstevel@tonic-gate more[k] = binary_compute(k + 1, j, more, less); 854*0Sstevel@tonic-gate 855*0Sstevel@tonic-gate return (k); 856*0Sstevel@tonic-gate 857*0Sstevel@tonic-gate } /* binary_compute */ 858*0Sstevel@tonic-gate 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gate /* 861*0Sstevel@tonic-gate * Write all domain data to file. 862*0Sstevel@tonic-gate * Each domain will create one file. 863*0Sstevel@tonic-gate */ 864*0Sstevel@tonic-gate static void 865*0Sstevel@tonic-gate output_all_mo_files(void) 866*0Sstevel@tonic-gate { 867*0Sstevel@tonic-gate struct domain_struct *p; 868*0Sstevel@tonic-gate 869*0Sstevel@tonic-gate p = first_domain; 870*0Sstevel@tonic-gate while (p) { 871*0Sstevel@tonic-gate /* 872*0Sstevel@tonic-gate * generate message object file only if there is 873*0Sstevel@tonic-gate * at least one element. 874*0Sstevel@tonic-gate */ 875*0Sstevel@tonic-gate if (p->first_elem) { 876*0Sstevel@tonic-gate output_one_mo_file(p); 877*0Sstevel@tonic-gate } 878*0Sstevel@tonic-gate p = p->next; 879*0Sstevel@tonic-gate } 880*0Sstevel@tonic-gate return; 881*0Sstevel@tonic-gate 882*0Sstevel@tonic-gate } /* output_all_mo_files */ 883*0Sstevel@tonic-gate 884*0Sstevel@tonic-gate 885*0Sstevel@tonic-gate /* 886*0Sstevel@tonic-gate * Write one domain data list to file. 887*0Sstevel@tonic-gate */ 888*0Sstevel@tonic-gate static void 889*0Sstevel@tonic-gate output_one_mo_file(struct domain_struct *dom) 890*0Sstevel@tonic-gate { 891*0Sstevel@tonic-gate FILE *fp; 892*0Sstevel@tonic-gate struct msg_chain *p; 893*0Sstevel@tonic-gate int message_count; 894*0Sstevel@tonic-gate int string_count_msgid; 895*0Sstevel@tonic-gate int string_count_msg; 896*0Sstevel@tonic-gate int msgid_index = 0; 897*0Sstevel@tonic-gate int msgstr_index = 0; 898*0Sstevel@tonic-gate int *less, *more; 899*0Sstevel@tonic-gate int i; 900*0Sstevel@tonic-gate char fname [TEXTDOMAINMAX+1]; 901*0Sstevel@tonic-gate 902*0Sstevel@tonic-gate if (!dom || !dom->first_elem) 903*0Sstevel@tonic-gate return; 904*0Sstevel@tonic-gate 905*0Sstevel@tonic-gate /* 906*0Sstevel@tonic-gate * If -o flag is specified, then file name is used as domain name. 907*0Sstevel@tonic-gate * If not, ".mo" is appended to the domain name. 908*0Sstevel@tonic-gate */ 909*0Sstevel@tonic-gate (void) strcpy(fname, dom->domain); 910*0Sstevel@tonic-gate if (!oflag) { 911*0Sstevel@tonic-gate (void) strcat(fname, ".mo"); 912*0Sstevel@tonic-gate } 913*0Sstevel@tonic-gate fp = fopen(fname, "w"); 914*0Sstevel@tonic-gate if (fp == NULL) { 915*0Sstevel@tonic-gate error(gettext(ERR_OPEN_FAILED), fname); 916*0Sstevel@tonic-gate /* NOTREACHED */ 917*0Sstevel@tonic-gate } 918*0Sstevel@tonic-gate 919*0Sstevel@tonic-gate /* compute offsets and counts */ 920*0Sstevel@tonic-gate message_count = 0; 921*0Sstevel@tonic-gate p = dom->first_elem; 922*0Sstevel@tonic-gate while (p) { 923*0Sstevel@tonic-gate p->msgid_offset = msgid_index; 924*0Sstevel@tonic-gate p->msgstr_offset = msgstr_index; 925*0Sstevel@tonic-gate msgid_index += strlen(p->msgid) + 1; 926*0Sstevel@tonic-gate msgstr_index += strlen(p->msgstr) + 1; 927*0Sstevel@tonic-gate message_count++; 928*0Sstevel@tonic-gate p = p->next; 929*0Sstevel@tonic-gate } 930*0Sstevel@tonic-gate 931*0Sstevel@tonic-gate /* 932*0Sstevel@tonic-gate * Fill up less and more entries to be used for binary search. 933*0Sstevel@tonic-gate */ 934*0Sstevel@tonic-gate string_count_msgid = msgid_index; 935*0Sstevel@tonic-gate string_count_msg = msgstr_index; 936*0Sstevel@tonic-gate less = (int *)Xcalloc(message_count, sizeof (int)); 937*0Sstevel@tonic-gate more = (int *)Xcalloc(message_count, sizeof (int)); 938*0Sstevel@tonic-gate 939*0Sstevel@tonic-gate (void) binary_compute(0, message_count - 1, more, less); 940*0Sstevel@tonic-gate 941*0Sstevel@tonic-gate #ifdef DEBUG 942*0Sstevel@tonic-gate { 943*0Sstevel@tonic-gate int i; 944*0Sstevel@tonic-gate for (i = 0; i < message_count; i++) { 945*0Sstevel@tonic-gate (void) fprintf(stderr, 946*0Sstevel@tonic-gate " less[%2d]=%2d, more[%2d]=%2d\n", 947*0Sstevel@tonic-gate i, less[i], i, more[i]); 948*0Sstevel@tonic-gate } 949*0Sstevel@tonic-gate } 950*0Sstevel@tonic-gate #endif 951*0Sstevel@tonic-gate 952*0Sstevel@tonic-gate /* 953*0Sstevel@tonic-gate * write out the message object file. 954*0Sstevel@tonic-gate * The middle one is the first message to check by gettext(). 955*0Sstevel@tonic-gate */ 956*0Sstevel@tonic-gate i = (message_count - 1) / 2; 957*0Sstevel@tonic-gate (void) fwrite(&i, sizeof (int), 1, fp); 958*0Sstevel@tonic-gate (void) fwrite(&message_count, sizeof (int), 1, fp); 959*0Sstevel@tonic-gate (void) fwrite(&string_count_msgid, sizeof (int), 1, fp); 960*0Sstevel@tonic-gate (void) fwrite(&string_count_msg, sizeof (int), 1, fp); 961*0Sstevel@tonic-gate i = MSG_STRUCT_SIZE * message_count; 962*0Sstevel@tonic-gate (void) fwrite(&i, sizeof (int), 1, fp); 963*0Sstevel@tonic-gate 964*0Sstevel@tonic-gate /* march through linked list and write out all nodes. */ 965*0Sstevel@tonic-gate i = 0; 966*0Sstevel@tonic-gate p = dom->first_elem; 967*0Sstevel@tonic-gate while (p) { /* put out message struct */ 968*0Sstevel@tonic-gate (void) fwrite(&less[i], sizeof (int), 1, fp); 969*0Sstevel@tonic-gate (void) fwrite(&more[i], sizeof (int), 1, fp); 970*0Sstevel@tonic-gate (void) fwrite(&p->msgid_offset, sizeof (int), 1, fp); 971*0Sstevel@tonic-gate (void) fwrite(&p->msgstr_offset, sizeof (int), 1, fp); 972*0Sstevel@tonic-gate i++; 973*0Sstevel@tonic-gate p = p->next; 974*0Sstevel@tonic-gate } 975*0Sstevel@tonic-gate 976*0Sstevel@tonic-gate /* put out message id strings */ 977*0Sstevel@tonic-gate p = dom->first_elem; 978*0Sstevel@tonic-gate while (p) { 979*0Sstevel@tonic-gate (void) fwrite(p->msgid, strlen(p->msgid)+1, 1, fp); 980*0Sstevel@tonic-gate p = p->next; 981*0Sstevel@tonic-gate } 982*0Sstevel@tonic-gate 983*0Sstevel@tonic-gate /* put out message strings */ 984*0Sstevel@tonic-gate p = dom->first_elem; 985*0Sstevel@tonic-gate while (p) { 986*0Sstevel@tonic-gate (void) fwrite(p->msgstr, strlen(p->msgstr)+1, 1, fp); 987*0Sstevel@tonic-gate p = p->next; 988*0Sstevel@tonic-gate } 989*0Sstevel@tonic-gate 990*0Sstevel@tonic-gate (void) fclose(fp); 991*0Sstevel@tonic-gate free(less); 992*0Sstevel@tonic-gate free(more); 993*0Sstevel@tonic-gate 994*0Sstevel@tonic-gate return; 995*0Sstevel@tonic-gate 996*0Sstevel@tonic-gate } /* output_one_mo_file */ 997*0Sstevel@tonic-gate 998*0Sstevel@tonic-gate 999*0Sstevel@tonic-gate /* 1000*0Sstevel@tonic-gate * read one line from *mbuf, 1001*0Sstevel@tonic-gate * skip preceding whitespaces, 1002*0Sstevel@tonic-gate * convert the line to wide characters, 1003*0Sstevel@tonic-gate * place the wide characters into *bufhead, and 1004*0Sstevel@tonic-gate * return the number of wide characters placed. 1005*0Sstevel@tonic-gate * 1006*0Sstevel@tonic-gate * INPUT: 1007*0Sstevel@tonic-gate * **bufhead - address of a variable that is the pointer 1008*0Sstevel@tonic-gate * to wchar_t. 1009*0Sstevel@tonic-gate * The variable should been initialized to NULL. 1010*0Sstevel@tonic-gate * **mbuf - address of a variable that is the pointer 1011*0Sstevel@tonic-gate * to char. 1012*0Sstevel@tonic-gate * The pointer should point to the memory mmapped to 1013*0Sstevel@tonic-gate * the file to input. 1014*0Sstevel@tonic-gate * **fsize - address of a size_t variable that contains 1015*0Sstevel@tonic-gate * the size of unread bytes in the file to input. 1016*0Sstevel@tonic-gate * OUTPUT: 1017*0Sstevel@tonic-gate * return - the number of wide characters placed. 1018*0Sstevel@tonic-gate * **bufhead - _mbsntowcs allocates the buffer to store 1019*0Sstevel@tonic-gate * one line in wchar_t from *mbuf and sets the address 1020*0Sstevel@tonic-gate * to *bufhead. 1021*0Sstevel@tonic-gate * **mbuf - _mbsntowcs reads one line from *mbuf and sets *mbuf 1022*0Sstevel@tonic-gate * to the beginning of the next line. 1023*0Sstevel@tonic-gate * **fsize - *fsize will be set to the size of the unread 1024*0Sstevel@tonic-gate * bytes in the file. 1025*0Sstevel@tonic-gate */ 1026*0Sstevel@tonic-gate static size_t 1027*0Sstevel@tonic-gate _mbsntowcs(wchar_t **bufhead, char **mbuf, size_t *fsize) 1028*0Sstevel@tonic-gate { 1029*0Sstevel@tonic-gate wchar_t *tp, *th; 1030*0Sstevel@tonic-gate wchar_t wc; 1031*0Sstevel@tonic-gate size_t tbufsize = LINE_SIZE; 1032*0Sstevel@tonic-gate size_t ttbufsize, nc; 1033*0Sstevel@tonic-gate char *pc = *mbuf; 1034*0Sstevel@tonic-gate int nb; 1035*0Sstevel@tonic-gate 1036*0Sstevel@tonic-gate if (*fsize == 0) { 1037*0Sstevel@tonic-gate /* eof */ 1038*0Sstevel@tonic-gate return (0); 1039*0Sstevel@tonic-gate } 1040*0Sstevel@tonic-gate 1041*0Sstevel@tonic-gate th = (wchar_t *)Xmalloc(sizeof (wchar_t) * tbufsize); 1042*0Sstevel@tonic-gate nc = tbufsize; 1043*0Sstevel@tonic-gate 1044*0Sstevel@tonic-gate /* skip preceding whitespaces */ 1045*0Sstevel@tonic-gate while ((*pc != '\0')) { 1046*0Sstevel@tonic-gate if ((*pc == ' ') || (*pc == '\t')) { 1047*0Sstevel@tonic-gate pc++; 1048*0Sstevel@tonic-gate (*fsize)--; 1049*0Sstevel@tonic-gate } else { 1050*0Sstevel@tonic-gate break; 1051*0Sstevel@tonic-gate } 1052*0Sstevel@tonic-gate } 1053*0Sstevel@tonic-gate 1054*0Sstevel@tonic-gate tp = th; 1055*0Sstevel@tonic-gate while (*fsize > 0) { 1056*0Sstevel@tonic-gate nb = mbtowc(&wc, pc, mbcurmax); 1057*0Sstevel@tonic-gate if (nb == -1) { 1058*0Sstevel@tonic-gate return ((size_t)-1); 1059*0Sstevel@tonic-gate } 1060*0Sstevel@tonic-gate 1061*0Sstevel@tonic-gate if (*pc == '\n') { 1062*0Sstevel@tonic-gate /* found eol */ 1063*0Sstevel@tonic-gate if (nc <= 1) { 1064*0Sstevel@tonic-gate /* 1065*0Sstevel@tonic-gate * not enough buffer 1066*0Sstevel@tonic-gate * at least 2 more bytes are required for 1067*0Sstevel@tonic-gate * L'\n' and L'\0' 1068*0Sstevel@tonic-gate */ 1069*0Sstevel@tonic-gate ttbufsize = tbufsize + 2; 1070*0Sstevel@tonic-gate th = (wchar_t *)Xrealloc(th, 1071*0Sstevel@tonic-gate sizeof (wchar_t) * ttbufsize); 1072*0Sstevel@tonic-gate tp = th + tbufsize - nc; 1073*0Sstevel@tonic-gate tbufsize = ttbufsize; 1074*0Sstevel@tonic-gate } 1075*0Sstevel@tonic-gate *tp++ = L'\n'; 1076*0Sstevel@tonic-gate *tp++ = L'\0'; 1077*0Sstevel@tonic-gate pc += nb; 1078*0Sstevel@tonic-gate *fsize -= nb; 1079*0Sstevel@tonic-gate *mbuf = pc; 1080*0Sstevel@tonic-gate *bufhead = th; 1081*0Sstevel@tonic-gate return ((size_t)(tp - th)); 1082*0Sstevel@tonic-gate } 1083*0Sstevel@tonic-gate if (nc == 0) { 1084*0Sstevel@tonic-gate ttbufsize = tbufsize + LINE_SIZE; 1085*0Sstevel@tonic-gate th = (wchar_t *)Xrealloc(th, 1086*0Sstevel@tonic-gate sizeof (wchar_t) * ttbufsize); 1087*0Sstevel@tonic-gate tp = th + tbufsize; 1088*0Sstevel@tonic-gate nc = LINE_SIZE; 1089*0Sstevel@tonic-gate tbufsize = ttbufsize; 1090*0Sstevel@tonic-gate } 1091*0Sstevel@tonic-gate *tp++ = wc; 1092*0Sstevel@tonic-gate nc--; 1093*0Sstevel@tonic-gate pc += nb; 1094*0Sstevel@tonic-gate *fsize -= nb; 1095*0Sstevel@tonic-gate } /* while */ 1096*0Sstevel@tonic-gate 1097*0Sstevel@tonic-gate /* 1098*0Sstevel@tonic-gate * At this point, the input file has been consumed, 1099*0Sstevel@tonic-gate * but there is no ending '\n'; we add it to 1100*0Sstevel@tonic-gate * the output file. 1101*0Sstevel@tonic-gate */ 1102*0Sstevel@tonic-gate if (nc <= 1) { 1103*0Sstevel@tonic-gate /* 1104*0Sstevel@tonic-gate * not enough buffer 1105*0Sstevel@tonic-gate * at least 2 more bytes are required for 1106*0Sstevel@tonic-gate * L'\n' and L'\0' 1107*0Sstevel@tonic-gate */ 1108*0Sstevel@tonic-gate ttbufsize = tbufsize + 2; 1109*0Sstevel@tonic-gate th = (wchar_t *)Xrealloc(th, 1110*0Sstevel@tonic-gate sizeof (wchar_t) * ttbufsize); 1111*0Sstevel@tonic-gate tp = th + tbufsize - nc; 1112*0Sstevel@tonic-gate tbufsize = ttbufsize; 1113*0Sstevel@tonic-gate } 1114*0Sstevel@tonic-gate *tp++ = L'\n'; 1115*0Sstevel@tonic-gate *tp++ = L'\0'; 1116*0Sstevel@tonic-gate *mbuf = pc; 1117*0Sstevel@tonic-gate *bufhead = th; 1118*0Sstevel@tonic-gate return ((size_t)(tp - th)); 1119*0Sstevel@tonic-gate } 1120*0Sstevel@tonic-gate 1121*0Sstevel@tonic-gate 1122*0Sstevel@tonic-gate /* 1123*0Sstevel@tonic-gate * This is debug function. Not compiled in the final executable. 1124*0Sstevel@tonic-gate */ 1125*0Sstevel@tonic-gate #ifdef DEBUG 1126*0Sstevel@tonic-gate static void 1127*0Sstevel@tonic-gate printlist(void) 1128*0Sstevel@tonic-gate { 1129*0Sstevel@tonic-gate struct domain_struct *p; 1130*0Sstevel@tonic-gate struct msg_chain *m; 1131*0Sstevel@tonic-gate 1132*0Sstevel@tonic-gate (void) fprintf(stderr, "\n=== Printing contents of all domains ===\n"); 1133*0Sstevel@tonic-gate p = first_domain; 1134*0Sstevel@tonic-gate while (p) { 1135*0Sstevel@tonic-gate (void) fprintf(stderr, "domain name = <%s>\n", p->domain); 1136*0Sstevel@tonic-gate m = p->first_elem; 1137*0Sstevel@tonic-gate while (m) { 1138*0Sstevel@tonic-gate (void) fprintf(stderr, " msgid=<%s>, msgstr=<%s>\n", 1139*0Sstevel@tonic-gate m->msgid, m->msgstr); 1140*0Sstevel@tonic-gate m = m->next; 1141*0Sstevel@tonic-gate } 1142*0Sstevel@tonic-gate p = p->next; 1143*0Sstevel@tonic-gate } 1144*0Sstevel@tonic-gate } /* printlist */ 1145*0Sstevel@tonic-gate #endif 1146