gencat.c revision 199236
1142662Sphantom/* ex:ts=4 2142662Sphantom */ 3142662Sphantom 4142662Sphantom/* $NetBSD: gencat.c,v 1.18 2003/10/27 00:12:43 lukem Exp $ */ 5142662Sphantom 6142662Sphantom/* 7142662Sphantom * Copyright (c) 1996 The NetBSD Foundation, Inc. 8142662Sphantom * All rights reserved. 9142662Sphantom * 10142662Sphantom * This code is derived from software contributed to The NetBSD Foundation 11142662Sphantom * by J.T. Conklin. 12142662Sphantom * 13142662Sphantom * Redistribution and use in source and binary forms, with or without 14142662Sphantom * modification, are permitted provided that the following conditions 15142662Sphantom * are met: 16142662Sphantom * 1. Redistributions of source code must retain the above copyright 17142662Sphantom * notice, this list of conditions and the following disclaimer. 18142662Sphantom * 2. Redistributions in binary form must reproduce the above copyright 19142662Sphantom * notice, this list of conditions and the following disclaimer in the 20142662Sphantom * documentation and/or other materials provided with the distribution. 21142662Sphantom * 3. All advertising materials mentioning features or use of this software 22142662Sphantom * must display the following acknowledgement: 23142662Sphantom * This product includes software developed by the NetBSD 24142662Sphantom * Foundation, Inc. and its contributors. 25142662Sphantom * 4. Neither the name of The NetBSD Foundation nor the names of its 26142662Sphantom * contributors may be used to endorse or promote products derived 27142662Sphantom * from this software without specific prior written permission. 28142662Sphantom * 29142662Sphantom * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 30142662Sphantom * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 31142662Sphantom * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 32142662Sphantom * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 33142662Sphantom * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 34142662Sphantom * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 35142662Sphantom * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 36142662Sphantom * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 37142662Sphantom * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 38142662Sphantom * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 39142662Sphantom * POSSIBILITY OF SUCH DAMAGE. 40142662Sphantom */ 41142662Sphantom 427496Sjkh/*********************************************************** 437496SjkhCopyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts. 447496Sjkh 457496Sjkh All Rights Reserved 467496Sjkh 477496SjkhPermission to use, copy, modify, and distribute this software and its 487496Sjkhdocumentation for any purpose and without fee is hereby granted, 497496Sjkhprovided that the above copyright notice appear in all copies and that 507496Sjkhboth that copyright notice and this permission notice appear in 517496Sjkhsupporting documentation, and that Alfalfa's name not be used in 527496Sjkhadvertising or publicity pertaining to distribution of the software 537496Sjkhwithout specific, written prior permission. 547496Sjkh 557496SjkhALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 567496SjkhALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 577496SjkhALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 587496SjkhANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 597496SjkhWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 607496SjkhARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 617496SjkhSOFTWARE. 627496Sjkh 637496SjkhIf you make any modifications, bugfixes or other changes to this software 647496Sjkhwe'd appreciate it if you could send a copy to us so we can keep things 657496Sjkhup-to-date. Many thanks. 667496Sjkh Kee Hinckley 677496Sjkh Alfalfa Software, Inc. 687496Sjkh 267 Allston St., #3 697496Sjkh Cambridge, MA 02139 USA 707496Sjkh nazgul@alfalfa.com 718874Srgrimes 727496Sjkh******************************************************************/ 737496Sjkh 7493218Scharnier#include <sys/cdefs.h> 7593218Scharnier__FBSDID("$FreeBSD: head/usr.bin/gencat/gencat.c 199236 2009-11-12 21:51:01Z edwin $"); 7693218Scharnier 77142662Sphantom#define _NLS_PRIVATE 78142662Sphantom 79142662Sphantom#include <sys/types.h> 80142662Sphantom#include <sys/queue.h> 81142662Sphantom 82142662Sphantom#include <arpa/inet.h> /* for htonl() */ 83142662Sphantom 84142662Sphantom#include <ctype.h> 8527274Scharnier#include <err.h> 86142662Sphantom#include <fcntl.h> 87142662Sphantom#include <limits.h> 88142662Sphantom#include <nl_types.h> 897496Sjkh#include <stdio.h> 9078717Sdd#include <stdlib.h> 9178717Sdd#include <string.h> 929251Sache#include <unistd.h> 937496Sjkh 94142662Sphantomstruct _msgT { 95142662Sphantom long msgId; 96142662Sphantom char *str; 97199236Sedwin LIST_ENTRY(_msgT) entries; 98142662Sphantom}; 997496Sjkh 100142662Sphantomstruct _setT { 101142662Sphantom long setId; 102199236Sedwin LIST_HEAD(msghead, _msgT) msghead; 103199236Sedwin LIST_ENTRY(_setT) entries; 104142662Sphantom}; 1057496Sjkh 106142662SphantomLIST_HEAD(sethead, _setT) sethead; 107142662Sphantomstatic struct _setT *curSet; 108142662Sphantom 109142662Sphantomstatic char *curline = NULL; 110142662Sphantomstatic long lineno = 0; 111142662Sphantom 112142662Sphantomstatic char *cskip(char *); 113142662Sphantomstatic void error(const char *); 114142662Sphantomstatic char *getline(int); 115142662Sphantomstatic char *getmsg(int, char *, char); 116142662Sphantomstatic void warning(const char *, const char *); 117142662Sphantomstatic char *wskip(char *); 118142662Sphantomstatic char *xstrdup(const char *); 119142662Sphantomstatic void *xmalloc(size_t); 120142662Sphantomstatic void *xrealloc(void *, size_t); 121142662Sphantom 122142662Sphantomvoid MCParse(int); 123142662Sphantomvoid MCReadCat(int); 124142662Sphantomvoid MCWriteCat(int); 125142662Sphantomvoid MCDelMsg(int); 126142662Sphantomvoid MCAddMsg(int, const char *); 127142662Sphantomvoid MCAddSet(int); 128142662Sphantomvoid MCDelSet(int); 129142662Sphantomvoid usage(void); 130142662Sphantomint main(int, char **); 131142662Sphantom 132142662Sphantomvoid 133142662Sphantomusage() 13427274Scharnier{ 135142662Sphantom fprintf(stderr, "usage: %s catfile msgfile ...\n", getprogname()); 136199236Sedwin exit(1); 1377496Sjkh} 1387496Sjkh 13972164Sphantomint 140142662Sphantommain(int argc, char **argv) 1417496Sjkh{ 142142662Sphantom int ofd, ifd; 143199236Sedwin char *catfile = NULL; 144142662Sphantom int c; 1458874Srgrimes 146142662Sphantom#define DEPRECATEDMSG 1 147142662Sphantom 148142662Sphantom#ifdef DEPRECATEDMSG 149142662Sphantom while ((c = getopt(argc, argv, "new")) != -1) { 150142662Sphantom#else 151142662Sphantom while ((c = getopt(argc, argv, "")) != -1) { 152142662Sphantom#endif 153142662Sphantom switch (c) { 154142662Sphantom#ifdef DEPRECATEDMSG 155142662Sphantom case 'n': 156142662Sphantom fprintf(stderr, "WARNING: Usage of \"-new\" argument is deprecated.\n"); 157142662Sphantom case 'e': 158142662Sphantom case 'w': 159142662Sphantom break; 160142662Sphantom#endif 161142662Sphantom case '?': 162142662Sphantom default: 163142662Sphantom usage(); 164142662Sphantom /* NOTREACHED */ 165142662Sphantom } 166142662Sphantom } 167142662Sphantom argc -= optind; 168142662Sphantom argv += optind; 169142662Sphantom 170142662Sphantom if (argc < 2) { 171142662Sphantom usage(); 172142662Sphantom /* NOTREACHED */ 173142662Sphantom } 174142662Sphantom catfile = *argv++; 175142662Sphantom 176142662Sphantom for (; *argv; argv++) { 177142662Sphantom if ((ifd = open(*argv, O_RDONLY)) < 0) 178142662Sphantom err(1, "Unable to read %s", *argv); 179142662Sphantom MCParse(ifd); 180142662Sphantom close(ifd); 181142662Sphantom } 182142662Sphantom 183142662Sphantom if ((ofd = open(catfile, O_WRONLY | O_TRUNC | O_CREAT, 0666)) < 0) 184142662Sphantom err(1, "Unable to create a new %s", catfile); 185142662Sphantom MCWriteCat(ofd); 186142662Sphantom exit(0); 187142662Sphantom} 188142662Sphantom 189142662Sphantomstatic void 190142662Sphantomwarning(const char *cptr, const char *msg) 191142662Sphantom{ 192142662Sphantom fprintf(stderr, "%s: %s on line %ld\n", getprogname(), msg, lineno); 193142662Sphantom fprintf(stderr, "%s\n", curline); 194142662Sphantom if (cptr) { 195142662Sphantom char *tptr; 196142662Sphantom for (tptr = curline; tptr < cptr; ++tptr) 197142662Sphantom putc(' ', stderr); 198142662Sphantom fprintf(stderr, "^\n"); 199142662Sphantom } 200142662Sphantom} 201142662Sphantom 202142662Sphantom#define CORRUPT() { error("corrupt message catalog"); } 203142662Sphantom#define NOMEM() { error("out of memory"); } 204142662Sphantom 205142662Sphantomstatic void 206142662Sphantomerror(const char *msg) 207142662Sphantom{ 208142662Sphantom warning(NULL, msg); 209142662Sphantom exit(1); 210142662Sphantom} 211142662Sphantom 212142662Sphantomstatic void * 213142662Sphantomxmalloc(size_t len) 214142662Sphantom{ 215142662Sphantom void *p; 216142662Sphantom 217142662Sphantom if ((p = malloc(len)) == NULL) 218142662Sphantom NOMEM(); 219142662Sphantom return (p); 220142662Sphantom} 221142662Sphantom 222142662Sphantomstatic void * 223142662Sphantomxrealloc(void *ptr, size_t size) 224142662Sphantom{ 225142662Sphantom if ((ptr = realloc(ptr, size)) == NULL) 226142662Sphantom NOMEM(); 227142662Sphantom return (ptr); 228142662Sphantom} 229142662Sphantom 230142662Sphantomstatic char * 231142662Sphantomxstrdup(const char *str) 232142662Sphantom{ 233142662Sphantom char *nstr; 234142662Sphantom 235142662Sphantom if ((nstr = strdup(str)) == NULL) 236142662Sphantom NOMEM(); 237142662Sphantom return (nstr); 238142662Sphantom} 239142662Sphantom 240142662Sphantomstatic char * 241142662Sphantomgetline(int fd) 242142662Sphantom{ 243142662Sphantom static long curlen = BUFSIZ; 244142662Sphantom static char buf[BUFSIZ], *bptr = buf, *bend = buf; 245142662Sphantom char *cptr, *cend; 246142662Sphantom long buflen; 247142662Sphantom 248142662Sphantom if (!curline) { 249142662Sphantom curline = xmalloc(curlen); 250142662Sphantom } 251142662Sphantom ++lineno; 252142662Sphantom 253142662Sphantom cptr = curline; 254142662Sphantom cend = curline + curlen; 255142662Sphantom for (;;) { 256142662Sphantom for (; bptr < bend && cptr < cend; ++cptr, ++bptr) { 257142662Sphantom if (*bptr == '\n') { 258142662Sphantom *cptr = '\0'; 259142662Sphantom ++bptr; 260142662Sphantom return (curline); 261142662Sphantom } else 262142662Sphantom *cptr = *bptr; 263142662Sphantom } 264142662Sphantom if (cptr == cend) { 265142662Sphantom cptr = curline = xrealloc(curline, curlen *= 2); 266142662Sphantom cend = curline + curlen; 267142662Sphantom } 268142662Sphantom if (bptr == bend) { 269142662Sphantom buflen = read(fd, buf, BUFSIZ); 270142662Sphantom if (buflen <= 0) { 271142662Sphantom if (cptr > curline) { 272142662Sphantom *cptr = '\0'; 273142662Sphantom return (curline); 274142662Sphantom } 275142662Sphantom return (NULL); 276142662Sphantom } 277142662Sphantom bend = buf + buflen; 278142662Sphantom bptr = buf; 279142662Sphantom } 280142662Sphantom } 281142662Sphantom} 282142662Sphantom 283142662Sphantomstatic char * 284142662Sphantomwskip(char *cptr) 285142662Sphantom{ 286142662Sphantom if (!*cptr || !isspace((unsigned char) *cptr)) { 287142662Sphantom warning(cptr, "expected a space"); 288142662Sphantom return (cptr); 289142662Sphantom } 290142662Sphantom while (*cptr && isspace((unsigned char) *cptr)) 291142662Sphantom ++cptr; 292142662Sphantom return (cptr); 293142662Sphantom} 294142662Sphantom 295142662Sphantomstatic char * 296142662Sphantomcskip(char *cptr) 297142662Sphantom{ 298142662Sphantom if (!*cptr || isspace((unsigned char) *cptr)) { 299142662Sphantom warning(cptr, "wasn't expecting a space"); 300142662Sphantom return (cptr); 301142662Sphantom } 302142662Sphantom while (*cptr && !isspace((unsigned char) *cptr)) 303142662Sphantom ++cptr; 304142662Sphantom return (cptr); 305142662Sphantom} 306142662Sphantom 307142662Sphantomstatic char * 308142662Sphantomgetmsg(int fd, char *cptr, char quote) 309142662Sphantom{ 310142662Sphantom static char *msg = NULL; 311142662Sphantom static long msglen = 0; 312142662Sphantom long clen, i; 313142662Sphantom char *tptr; 314142662Sphantom 315142662Sphantom if (quote && *cptr == quote) { 316142662Sphantom ++cptr; 317142662Sphantom } 318142662Sphantom 319142662Sphantom clen = strlen(cptr) + 1; 320142662Sphantom if (clen > msglen) { 321142662Sphantom if (msglen) 322142662Sphantom msg = xrealloc(msg, clen); 323142662Sphantom else 324142662Sphantom msg = xmalloc(clen); 325142662Sphantom msglen = clen; 326142662Sphantom } 327142662Sphantom tptr = msg; 328142662Sphantom 329142662Sphantom while (*cptr) { 330142662Sphantom if (quote && *cptr == quote) { 331142662Sphantom char *tmp; 332142662Sphantom tmp = cptr + 1; 333142662Sphantom if (*tmp && (!isspace((unsigned char) *tmp) || *wskip(tmp))) { 334142662Sphantom warning(cptr, "unexpected quote character, ignoring"); 335142662Sphantom *tptr++ = *cptr++; 336142662Sphantom } else { 337142662Sphantom *cptr = '\0'; 338142662Sphantom } 339142662Sphantom } else 340142662Sphantom if (*cptr == '\\') { 341142662Sphantom ++cptr; 342142662Sphantom switch (*cptr) { 343142662Sphantom case '\0': 344142662Sphantom cptr = getline(fd); 345142662Sphantom if (!cptr) 346142662Sphantom error("premature end of file"); 347142662Sphantom msglen += strlen(cptr); 348142662Sphantom i = tptr - msg; 349142662Sphantom msg = xrealloc(msg, msglen); 350142662Sphantom tptr = msg + i; 351142662Sphantom break; 352142662Sphantom 353142662Sphantom #define CASEOF(CS, CH) \ 354142662Sphantom case CS: \ 355142662Sphantom *tptr++ = CH; \ 356142662Sphantom ++cptr; \ 357142662Sphantom break; \ 358142662Sphantom 359142662Sphantom CASEOF('n', '\n'); 360142662Sphantom CASEOF('t', '\t'); 361142662Sphantom CASEOF('v', '\v'); 362142662Sphantom CASEOF('b', '\b'); 363142662Sphantom CASEOF('r', '\r'); 364142662Sphantom CASEOF('f', '\f'); 365142662Sphantom CASEOF('"', '"'); 366142662Sphantom CASEOF('\\', '\\'); 367142662Sphantom 368142662Sphantom default: 369142662Sphantom if (quote && *cptr == quote) { 370142662Sphantom *tptr++ = *cptr++; 371142662Sphantom } else if (isdigit((unsigned char) *cptr)) { 372142662Sphantom *tptr = 0; 373142662Sphantom for (i = 0; i < 3; ++i) { 374142662Sphantom if (!isdigit((unsigned char) *cptr)) 375142662Sphantom break; 376142662Sphantom if (*cptr > '7') 377142662Sphantom warning(cptr, "octal number greater than 7?!"); 378142662Sphantom *tptr *= 8; 379142662Sphantom *tptr += (*cptr - '0'); 380142662Sphantom ++cptr; 381142662Sphantom } 382142662Sphantom } else { 383142662Sphantom warning(cptr, "unrecognized escape sequence"); 384142662Sphantom } 385142662Sphantom break; 386142662Sphantom } 387142662Sphantom } else { 388142662Sphantom *tptr++ = *cptr++; 389142662Sphantom } 390142662Sphantom } 391142662Sphantom *tptr = '\0'; 392142662Sphantom return (msg); 393142662Sphantom} 394142662Sphantom 395142662Sphantomvoid 396142662SphantomMCParse(int fd) 397142662Sphantom{ 398142662Sphantom char *cptr, *str; 399142662Sphantom int setid, msgid = 0; 400142662Sphantom char quote = 0; 401142662Sphantom 402142662Sphantom /* XXX: init sethead? */ 403142662Sphantom 404142662Sphantom while ((cptr = getline(fd))) { 405142662Sphantom if (*cptr == '$') { 406142662Sphantom ++cptr; 407142662Sphantom if (strncmp(cptr, "set", 3) == 0) { 408142662Sphantom cptr += 3; 409142662Sphantom cptr = wskip(cptr); 410142662Sphantom setid = atoi(cptr); 411142662Sphantom MCAddSet(setid); 412142662Sphantom msgid = 0; 413142662Sphantom } else if (strncmp(cptr, "delset", 6) == 0) { 414142662Sphantom cptr += 6; 415142662Sphantom cptr = wskip(cptr); 416142662Sphantom setid = atoi(cptr); 417142662Sphantom MCDelSet(setid); 418142662Sphantom } else if (strncmp(cptr, "quote", 5) == 0) { 419142662Sphantom cptr += 5; 420142662Sphantom if (!*cptr) 421142662Sphantom quote = 0; 422199236Sedwin else { 423142662Sphantom cptr = wskip(cptr); 424142662Sphantom if (!*cptr) 425142662Sphantom quote = 0; 426142662Sphantom else 427142662Sphantom quote = *cptr; 428199236Sedwin } 429142662Sphantom } else if (isspace((unsigned char) *cptr)) { 430142662Sphantom ; 431199236Sedwin } else { 432142662Sphantom if (*cptr) { 433142662Sphantom cptr = wskip(cptr); 434142662Sphantom if (*cptr) 435142662Sphantom warning(cptr, "unrecognized line"); 436142662Sphantom } 437199236Sedwin } 438199236Sedwin } else { 439142662Sphantom /* 440142662Sphantom * First check for (and eat) empty lines.... 441142662Sphantom */ 442142662Sphantom if (!*cptr) 443142662Sphantom continue; 444142662Sphantom /* 445142662Sphantom * We have a digit? Start of a message. Else, 446142662Sphantom * syntax error. 447142662Sphantom */ 448142662Sphantom if (isdigit((unsigned char) *cptr)) { 449142662Sphantom msgid = atoi(cptr); 450142662Sphantom cptr = cskip(cptr); 451142662Sphantom cptr = wskip(cptr); 452142662Sphantom /* if (*cptr) ++cptr; */ 453142662Sphantom } else { 454142662Sphantom warning(cptr, "neither blank line nor start of a message id"); 455142662Sphantom continue; 456199236Sedwin } 457142662Sphantom /* 458142662Sphantom * If we have a message ID, but no message, 459142662Sphantom * then this means "delete this message id 460142662Sphantom * from the catalog". 461142662Sphantom */ 462142662Sphantom if (!*cptr) { 463142662Sphantom MCDelMsg(msgid); 464199236Sedwin } else { 465142662Sphantom str = getmsg(fd, cptr, quote); 466142662Sphantom MCAddMsg(msgid, str); 467199236Sedwin } 468199236Sedwin } 4697496Sjkh } 470142662Sphantom} 471142662Sphantom 472142662Sphantomvoid 473142662SphantomMCReadCat(int fd) 474142662Sphantom{ 475142662Sphantom fd = 0; 476142662Sphantom#if 0 477142662Sphantom MCHeaderT mcHead; 478142662Sphantom MCMsgT mcMsg; 479142662Sphantom MCSetT mcSet; 480142662Sphantom msgT *msg; 481142662Sphantom setT *set; 482142662Sphantom int i; 483142662Sphantom char *data; 484142662Sphantom 485142662Sphantom /* XXX init sethead? */ 486142662Sphantom 487142662Sphantom if (read(fd, &mcHead, sizeof(mcHead)) != sizeof(mcHead)) 488142662Sphantom CORRUPT(); 489142662Sphantom if (strncmp(mcHead.magic, MCMagic, MCMagicLen) != 0) 490142662Sphantom CORRUPT(); 491142662Sphantom if (mcHead.majorVer != MCMajorVer) 492142662Sphantom error("unrecognized catalog version"); 493142662Sphantom if ((mcHead.flags & MCGetByteOrder()) == 0) 494142662Sphantom error("wrong byte order"); 495142662Sphantom 496142662Sphantom if (lseek(fd, mcHead.firstSet, SEEK_SET) == -1) 497142662Sphantom CORRUPT(); 498142662Sphantom 499142662Sphantom for (;;) { 500142662Sphantom if (read(fd, &mcSet, sizeof(mcSet)) != sizeof(mcSet)) 501142662Sphantom CORRUPT(); 502142662Sphantom if (mcSet.invalid) 503142662Sphantom continue; 504142662Sphantom 505142662Sphantom set = xmalloc(sizeof(setT)); 506142662Sphantom memset(set, '\0', sizeof(*set)); 507142662Sphantom if (cat->first) { 508142662Sphantom cat->last->next = set; 509142662Sphantom set->prev = cat->last; 510142662Sphantom cat->last = set; 511142662Sphantom } else 512142662Sphantom cat->first = cat->last = set; 513142662Sphantom 514142662Sphantom set->setId = mcSet.setId; 515142662Sphantom 516142662Sphantom /* Get the data */ 517142662Sphantom if (mcSet.dataLen) { 518142662Sphantom data = xmalloc(mcSet.dataLen); 519142662Sphantom if (lseek(fd, mcSet.data.off, SEEK_SET) == -1) 520142662Sphantom CORRUPT(); 521142662Sphantom if (read(fd, data, mcSet.dataLen) != mcSet.dataLen) 522142662Sphantom CORRUPT(); 523142662Sphantom if (lseek(fd, mcSet.u.firstMsg, SEEK_SET) == -1) 524142662Sphantom CORRUPT(); 525142662Sphantom 526142662Sphantom for (i = 0; i < mcSet.numMsgs; ++i) { 527142662Sphantom if (read(fd, &mcMsg, sizeof(mcMsg)) != sizeof(mcMsg)) 528142662Sphantom CORRUPT(); 529142662Sphantom if (mcMsg.invalid) { 530142662Sphantom --i; 531142662Sphantom continue; 532142662Sphantom } 533142662Sphantom msg = xmalloc(sizeof(msgT)); 534142662Sphantom memset(msg, '\0', sizeof(*msg)); 535142662Sphantom if (set->first) { 536142662Sphantom set->last->next = msg; 537142662Sphantom msg->prev = set->last; 538142662Sphantom set->last = msg; 539142662Sphantom } else 540142662Sphantom set->first = set->last = msg; 541142662Sphantom 542142662Sphantom msg->msgId = mcMsg.msgId; 543142662Sphantom msg->str = xstrdup((char *) (data + mcMsg.msg.off)); 544142662Sphantom } 545142662Sphantom free(data); 546142662Sphantom } 547142662Sphantom if (!mcSet.nextSet) 548142662Sphantom break; 549142662Sphantom if (lseek(fd, mcSet.nextSet, SEEK_SET) == -1) 550142662Sphantom CORRUPT(); 551142662Sphantom } 552142662Sphantom#endif 553142662Sphantom} 554142662Sphantom 555142662Sphantom/* 556142662Sphantom * Write message catalog. 557142662Sphantom * 558142662Sphantom * The message catalog is first converted from its internal to its 559142662Sphantom * external representation in a chunk of memory allocated for this 560142662Sphantom * purpose. Then the completed catalog is written. This approach 561142662Sphantom * avoids additional housekeeping variables and/or a lot of seeks 562142662Sphantom * that would otherwise be required. 563142662Sphantom */ 564142662Sphantomvoid 565142662SphantomMCWriteCat(int fd) 566142662Sphantom{ 567142662Sphantom int nsets; /* number of sets */ 568142662Sphantom int nmsgs; /* number of msgs */ 569142662Sphantom int string_size; /* total size of string pool */ 570142662Sphantom int msgcat_size; /* total size of message catalog */ 571142662Sphantom void *msgcat; /* message catalog data */ 572142662Sphantom struct _nls_cat_hdr *cat_hdr; 573142662Sphantom struct _nls_set_hdr *set_hdr; 574142662Sphantom struct _nls_msg_hdr *msg_hdr; 575142662Sphantom char *strings; 576142662Sphantom struct _setT *set; 577142662Sphantom struct _msgT *msg; 578142662Sphantom int msg_index; 579142662Sphantom int msg_offset; 580142662Sphantom 581142662Sphantom /* determine number of sets, number of messages, and size of the 582142662Sphantom * string pool */ 583142662Sphantom nsets = 0; 584142662Sphantom nmsgs = 0; 585142662Sphantom string_size = 0; 586142662Sphantom 587142662Sphantom for (set = sethead.lh_first; set != NULL; 588142662Sphantom set = set->entries.le_next) { 589142662Sphantom nsets++; 590142662Sphantom 591142662Sphantom for (msg = set->msghead.lh_first; msg != NULL; 592142662Sphantom msg = msg->entries.le_next) { 593142662Sphantom nmsgs++; 594142662Sphantom string_size += strlen(msg->str) + 1; 595142662Sphantom } 596142662Sphantom } 597142662Sphantom 598142662Sphantom#ifdef DEBUG 599142662Sphantom printf("number of sets: %d\n", nsets); 600142662Sphantom printf("number of msgs: %d\n", nmsgs); 601142662Sphantom printf("string pool size: %d\n", string_size); 602142662Sphantom#endif 603142662Sphantom 604142662Sphantom /* determine size and then allocate buffer for constructing external 605142662Sphantom * message catalog representation */ 606142662Sphantom msgcat_size = sizeof(struct _nls_cat_hdr) 607142662Sphantom + (nsets * sizeof(struct _nls_set_hdr)) 608142662Sphantom + (nmsgs * sizeof(struct _nls_msg_hdr)) 609142662Sphantom + string_size; 610142662Sphantom 611142662Sphantom msgcat = xmalloc(msgcat_size); 612142662Sphantom memset(msgcat, '\0', msgcat_size); 613142662Sphantom 614142662Sphantom /* fill in msg catalog header */ 615142662Sphantom cat_hdr = (struct _nls_cat_hdr *) msgcat; 616142662Sphantom cat_hdr->__magic = htonl(_NLS_MAGIC); 617142662Sphantom cat_hdr->__nsets = htonl(nsets); 618142662Sphantom cat_hdr->__mem = htonl(msgcat_size - sizeof(struct _nls_cat_hdr)); 619142662Sphantom cat_hdr->__msg_hdr_offset = 620142662Sphantom htonl(nsets * sizeof(struct _nls_set_hdr)); 621142662Sphantom cat_hdr->__msg_txt_offset = 622142662Sphantom htonl(nsets * sizeof(struct _nls_set_hdr) + 623142662Sphantom nmsgs * sizeof(struct _nls_msg_hdr)); 624142662Sphantom 625142662Sphantom /* compute offsets for set & msg header tables and string pool */ 626142684Sru set_hdr = (struct _nls_set_hdr *)(void *)((char *)msgcat + 627142662Sphantom sizeof(struct _nls_cat_hdr)); 628142684Sru msg_hdr = (struct _nls_msg_hdr *)(void *)((char *)msgcat + 629142662Sphantom sizeof(struct _nls_cat_hdr) + 630142662Sphantom nsets * sizeof(struct _nls_set_hdr)); 631142662Sphantom strings = (char *) msgcat + 632142662Sphantom sizeof(struct _nls_cat_hdr) + 633142662Sphantom nsets * sizeof(struct _nls_set_hdr) + 634142662Sphantom nmsgs * sizeof(struct _nls_msg_hdr); 635142662Sphantom 636142662Sphantom msg_index = 0; 637142662Sphantom msg_offset = 0; 638142662Sphantom for (set = sethead.lh_first; set != NULL; 639142662Sphantom set = set->entries.le_next) { 640142662Sphantom 641142662Sphantom nmsgs = 0; 642142662Sphantom for (msg = set->msghead.lh_first; msg != NULL; 643142662Sphantom msg = msg->entries.le_next) { 644142662Sphantom int msg_len = strlen(msg->str) + 1; 645142662Sphantom 646142662Sphantom msg_hdr->__msgno = htonl(msg->msgId); 647142662Sphantom msg_hdr->__msglen = htonl(msg_len); 648142662Sphantom msg_hdr->__offset = htonl(msg_offset); 649142662Sphantom 650142662Sphantom memcpy(strings, msg->str, msg_len); 651142662Sphantom strings += msg_len; 652142662Sphantom msg_offset += msg_len; 653142662Sphantom 654142662Sphantom nmsgs++; 655142662Sphantom msg_hdr++; 656142662Sphantom } 657142662Sphantom 658142662Sphantom set_hdr->__setno = htonl(set->setId); 659142662Sphantom set_hdr->__nmsgs = htonl(nmsgs); 660142662Sphantom set_hdr->__index = htonl(msg_index); 661142662Sphantom msg_index += nmsgs; 662142662Sphantom set_hdr++; 663142662Sphantom } 664142662Sphantom 665142662Sphantom /* write out catalog. XXX: should this be done in small chunks? */ 666142662Sphantom write(fd, msgcat, msgcat_size); 667142662Sphantom} 668142662Sphantom 669142662Sphantomvoid 670142662SphantomMCAddSet(int setId) 671142662Sphantom{ 672142662Sphantom struct _setT *p, *q; 673142662Sphantom 674142662Sphantom if (setId <= 0) { 675142662Sphantom error("setId's must be greater than zero"); 676142662Sphantom /* NOTREACHED */ 677142662Sphantom } 678142662Sphantom if (setId > NL_SETMAX) { 679142662Sphantom error("setId exceeds limit"); 680142662Sphantom /* NOTREACHED */ 681142662Sphantom } 682142662Sphantom 683142662Sphantom p = sethead.lh_first; 684142662Sphantom q = NULL; 685142662Sphantom for (; p != NULL && p->setId < setId; q = p, p = p->entries.le_next); 686142662Sphantom 687142662Sphantom if (p && p->setId == setId) { 688142662Sphantom ; 689199236Sedwin } else { 690142662Sphantom p = xmalloc(sizeof(struct _setT)); 691142662Sphantom memset(p, '\0', sizeof(struct _setT)); 692142662Sphantom LIST_INIT(&p->msghead); 693142662Sphantom 694142662Sphantom p->setId = setId; 695142662Sphantom 696142662Sphantom if (q == NULL) { 697142662Sphantom LIST_INSERT_HEAD(&sethead, p, entries); 698142662Sphantom } else { 699142662Sphantom LIST_INSERT_AFTER(q, p, entries); 700199236Sedwin } 701199236Sedwin } 7027496Sjkh 703142662Sphantom curSet = p; 704142662Sphantom} 705142662Sphantom 706142662Sphantomvoid 707142662SphantomMCAddMsg(int msgId, const char *str) 7087496Sjkh{ 709142662Sphantom struct _msgT *p, *q; 7107496Sjkh 711142662Sphantom if (!curSet) 712142662Sphantom error("can't specify a message when no set exists"); 713142662Sphantom 714142662Sphantom if (msgId <= 0) { 715142662Sphantom error("msgId's must be greater than zero"); 716142662Sphantom /* NOTREACHED */ 717142662Sphantom } 718142662Sphantom if (msgId > NL_MSGMAX) { 719142662Sphantom error("msgID exceeds limit"); 720142662Sphantom /* NOTREACHED */ 721199236Sedwin } 7227496Sjkh 723142662Sphantom p = curSet->msghead.lh_first; 724142662Sphantom q = NULL; 725142662Sphantom for (; p != NULL && p->msgId < msgId; q = p, p = p->entries.le_next); 7267496Sjkh 727142662Sphantom if (p && p->msgId == msgId) { 728142662Sphantom free(p->str); 729142662Sphantom } else { 730142662Sphantom p = xmalloc(sizeof(struct _msgT)); 731142662Sphantom memset(p, '\0', sizeof(struct _msgT)); 7327496Sjkh 733142662Sphantom if (q == NULL) { 734142662Sphantom LIST_INSERT_HEAD(&curSet->msghead, p, entries); 735142662Sphantom } else { 736142662Sphantom LIST_INSERT_AFTER(q, p, entries); 737142662Sphantom } 738142662Sphantom } 7397496Sjkh 740142662Sphantom p->msgId = msgId; 741142662Sphantom p->str = xstrdup(str); 742199236Sedwin} 7437496Sjkh 744142662Sphantomvoid 745142662SphantomMCDelSet(int setId) 746142662Sphantom{ 747142662Sphantom struct _setT *set; 748142662Sphantom struct _msgT *msg; 749142662Sphantom 750142662Sphantom set = sethead.lh_first; 751142662Sphantom for (; set != NULL && set->setId < setId; set = set->entries.le_next); 752142662Sphantom 753142662Sphantom if (set && set->setId == setId) { 754142662Sphantom 755142662Sphantom msg = set->msghead.lh_first; 756142662Sphantom while (msg) { 757142662Sphantom free(msg->str); 758142662Sphantom LIST_REMOVE(msg, entries); 759199236Sedwin } 760142662Sphantom 761142662Sphantom LIST_REMOVE(set, entries); 762142662Sphantom return; 763199236Sedwin } 764142662Sphantom warning(NULL, "specified set doesn't exist"); 765199236Sedwin} 766142662Sphantom 767142662Sphantomvoid 768142662SphantomMCDelMsg(int msgId) 769142662Sphantom{ 770142662Sphantom struct _msgT *msg; 771142662Sphantom 772142662Sphantom if (!curSet) 773142662Sphantom error("you can't delete a message before defining the set"); 774142662Sphantom 775142662Sphantom msg = curSet->msghead.lh_first; 776142662Sphantom for (; msg != NULL && msg->msgId < msgId; msg = msg->entries.le_next); 777142662Sphantom 778142662Sphantom if (msg && msg->msgId == msgId) { 779142662Sphantom free(msg->str); 780142662Sphantom LIST_REMOVE(msg, entries); 781142662Sphantom return; 782199236Sedwin } 783142662Sphantom warning(NULL, "specified msg doesn't exist"); 7847496Sjkh} 785