1*4887Schin /*********************************************************************** 2*4887Schin * * 3*4887Schin * This software is part of the ast package * 4*4887Schin * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5*4887Schin * and is licensed under the * 6*4887Schin * Common Public License, Version 1.0 * 7*4887Schin * by AT&T Knowledge Ventures * 8*4887Schin * * 9*4887Schin * A copy of the License is available at * 10*4887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 11*4887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*4887Schin * * 13*4887Schin * Information and Software Systems Research * 14*4887Schin * AT&T Research * 15*4887Schin * Florham Park NJ * 16*4887Schin * * 17*4887Schin * Glenn Fowler <gsf@research.att.com> * 18*4887Schin * David Korn <dgk@research.att.com> * 19*4887Schin * Phong Vo <kpv@research.att.com> * 20*4887Schin * * 21*4887Schin ***********************************************************************/ 22*4887Schin #pragma prototyped 23*4887Schin 24*4887Schin /* 25*4887Schin * Glenn Fowler 26*4887Schin * AT&T Research 27*4887Schin * 28*4887Schin * machine independent binary message catalog implementation 29*4887Schin */ 30*4887Schin 31*4887Schin #include "sfhdr.h" 32*4887Schin #include "lclib.h" 33*4887Schin 34*4887Schin #include <iconv.h> 35*4887Schin 36*4887Schin #define _MC_PRIVATE_ \ 37*4887Schin size_t nstrs; \ 38*4887Schin size_t nmsgs; \ 39*4887Schin iconv_t cvt; \ 40*4887Schin Sfio_t* tmp; \ 41*4887Schin Vmalloc_t* vm; 42*4887Schin 43*4887Schin #include <vmalloc.h> 44*4887Schin #include <error.h> 45*4887Schin #include <mc.h> 46*4887Schin #include <nl_types.h> 47*4887Schin 48*4887Schin /* 49*4887Schin * find the binary message catalog path for <locale,catalog> 50*4887Schin * result placed in path of size PATH_MAX 51*4887Schin * pointer to path returned 52*4887Schin * catalog==0 tests for category directory or file 53*4887Schin * nls!=0 enables NLSPATH+LANG hack (not implemented yet) 54*4887Schin */ 55*4887Schin 56*4887Schin char* 57*4887Schin mcfind(char* path, const char* locale, const char* catalog, int category, int nls) 58*4887Schin { 59*4887Schin register int c; 60*4887Schin register char* s; 61*4887Schin register char* e; 62*4887Schin register char* p; 63*4887Schin register const char* v; 64*4887Schin int i; 65*4887Schin int first; 66*4887Schin int next; 67*4887Schin int last; 68*4887Schin int oerrno; 69*4887Schin Lc_t* lc; 70*4887Schin char file[PATH_MAX]; 71*4887Schin char* paths[5]; 72*4887Schin 73*4887Schin static char lc_messages[] = "LC_MESSAGES"; 74*4887Schin 75*4887Schin if ((category = lcindex(category, 1)) < 0) 76*4887Schin return 0; 77*4887Schin if (!(lc = locale ? lcmake(locale) : locales[category])) 78*4887Schin return 0; 79*4887Schin oerrno = errno; 80*4887Schin if (catalog && *catalog == '/') 81*4887Schin { 82*4887Schin i = eaccess(catalog, R_OK); 83*4887Schin errno = oerrno; 84*4887Schin if (i) 85*4887Schin return 0; 86*4887Schin strncpy(path, catalog, PATH_MAX-1); 87*4887Schin return path; 88*4887Schin } 89*4887Schin i = 0; 90*4887Schin #if !_lib_catopen 91*4887Schin if ((p = getenv("NLSPATH")) && *p) 92*4887Schin paths[i++] = p; 93*4887Schin #endif 94*4887Schin paths[i++] = "share/lib/locale/%l/%C/%N"; 95*4887Schin paths[i++] = "share/locale/%l/%C/%N"; 96*4887Schin paths[i++] = "lib/locale/%l/%C/%N"; 97*4887Schin paths[i] = 0; 98*4887Schin next = 1; 99*4887Schin for (i = 0; p = paths[i]; i += next) 100*4887Schin { 101*4887Schin first = 1; 102*4887Schin last = 0; 103*4887Schin e = &file[elementsof(file) - 1]; 104*4887Schin while (*p) 105*4887Schin { 106*4887Schin s = file; 107*4887Schin for (;;) 108*4887Schin { 109*4887Schin switch (c = *p++) 110*4887Schin { 111*4887Schin case 0: 112*4887Schin p--; 113*4887Schin break; 114*4887Schin case ':': 115*4887Schin break; 116*4887Schin case '%': 117*4887Schin if (s < e) 118*4887Schin { 119*4887Schin switch (c = *p++) 120*4887Schin { 121*4887Schin case 0: 122*4887Schin p--; 123*4887Schin continue; 124*4887Schin case 'N': 125*4887Schin v = catalog; 126*4887Schin break; 127*4887Schin case 'L': 128*4887Schin if (first) 129*4887Schin { 130*4887Schin first = 0; 131*4887Schin if (next) 132*4887Schin { 133*4887Schin v = lc->code; 134*4887Schin if (lc->code != lc->language->code) 135*4887Schin next = 0; 136*4887Schin } 137*4887Schin else 138*4887Schin { 139*4887Schin next = 1; 140*4887Schin v = lc->language->code; 141*4887Schin } 142*4887Schin } 143*4887Schin break; 144*4887Schin case 'l': 145*4887Schin v = lc->language->code; 146*4887Schin break; 147*4887Schin case 't': 148*4887Schin v = lc->territory->code; 149*4887Schin break; 150*4887Schin case 'c': 151*4887Schin v = lc->charset->code; 152*4887Schin break; 153*4887Schin case 'C': 154*4887Schin case_C: 155*4887Schin if (!catalog) 156*4887Schin last = 1; 157*4887Schin v = categories[category].name; 158*4887Schin break; 159*4887Schin default: 160*4887Schin *s++ = c; 161*4887Schin continue; 162*4887Schin } 163*4887Schin if (v) 164*4887Schin while (*v && s < e) 165*4887Schin *s++ = *v++; 166*4887Schin } 167*4887Schin continue; 168*4887Schin case '/': 169*4887Schin if (last) 170*4887Schin break; 171*4887Schin if (category != AST_LC_MESSAGES && strneq(p, lc_messages, sizeof(lc_messages) - 1) && p[sizeof(lc_messages)-1] == '/') 172*4887Schin { 173*4887Schin p += sizeof(lc_messages) - 1; 174*4887Schin goto case_C; 175*4887Schin } 176*4887Schin /*FALLTHROUGH*/ 177*4887Schin default: 178*4887Schin if (s < e) 179*4887Schin *s++ = c; 180*4887Schin continue; 181*4887Schin } 182*4887Schin break; 183*4887Schin } 184*4887Schin if (s > file) 185*4887Schin *s = 0; 186*4887Schin else if (!catalog) 187*4887Schin continue; 188*4887Schin else 189*4887Schin strncpy(file, catalog, elementsof(file)); 190*4887Schin if (ast.locale.set & AST_LC_find) 191*4887Schin sfprintf(sfstderr, "locale find %s\n", file); 192*4887Schin if (s = pathpath(path, file, "", (!catalog && category == AST_LC_MESSAGES) ? PATH_READ : (PATH_REGULAR|PATH_READ|PATH_ABSOLUTE))) 193*4887Schin { 194*4887Schin if (ast.locale.set & (AST_LC_find|AST_LC_setlocale)) 195*4887Schin sfprintf(sfstderr, "locale path %s\n", s); 196*4887Schin errno = oerrno; 197*4887Schin return s; 198*4887Schin } 199*4887Schin } 200*4887Schin } 201*4887Schin errno = oerrno; 202*4887Schin return 0; 203*4887Schin } 204*4887Schin 205*4887Schin /* 206*4887Schin * allocate and read the binary message catalog ip 207*4887Schin * if ip==0 then space is allocated for mcput() 208*4887Schin * 0 returned on any error 209*4887Schin */ 210*4887Schin 211*4887Schin Mc_t* 212*4887Schin mcopen(register Sfio_t* ip) 213*4887Schin { 214*4887Schin register Mc_t* mc; 215*4887Schin register char** mp; 216*4887Schin register char* sp; 217*4887Schin Vmalloc_t* vm; 218*4887Schin char* rp; 219*4887Schin int i; 220*4887Schin int j; 221*4887Schin int oerrno; 222*4887Schin size_t n; 223*4887Schin char buf[MC_MAGIC_SIZE]; 224*4887Schin 225*4887Schin oerrno = errno; 226*4887Schin if (ip) 227*4887Schin { 228*4887Schin /* 229*4887Schin * check the magic 230*4887Schin */ 231*4887Schin 232*4887Schin if (sfread(ip, buf, MC_MAGIC_SIZE) != MC_MAGIC_SIZE) 233*4887Schin { 234*4887Schin errno = oerrno; 235*4887Schin return 0; 236*4887Schin } 237*4887Schin if (memcmp(buf, MC_MAGIC, MC_MAGIC_SIZE)) 238*4887Schin return 0; 239*4887Schin } 240*4887Schin 241*4887Schin /* 242*4887Schin * allocate the region 243*4887Schin */ 244*4887Schin 245*4887Schin if (!(vm = vmopen(Vmdcheap, Vmbest, 0)) || !(mc = vmnewof(vm, 0, Mc_t, 1, 0))) 246*4887Schin { 247*4887Schin errno = oerrno; 248*4887Schin return 0; 249*4887Schin } 250*4887Schin mc->vm = vm; 251*4887Schin mc->cvt = (iconv_t)(-1); 252*4887Schin if (ip) 253*4887Schin { 254*4887Schin /* 255*4887Schin * read the translation record 256*4887Schin */ 257*4887Schin 258*4887Schin if (!(sp = sfgetr(ip, 0, 0)) || !(mc->translation = vmstrdup(vm, sp))) 259*4887Schin goto bad; 260*4887Schin 261*4887Schin /* 262*4887Schin * read the optional header records 263*4887Schin */ 264*4887Schin 265*4887Schin do 266*4887Schin { 267*4887Schin if (!(sp = sfgetr(ip, 0, 0))) 268*4887Schin goto bad; 269*4887Schin } while (*sp); 270*4887Schin 271*4887Schin /* 272*4887Schin * get the component dimensions 273*4887Schin */ 274*4887Schin 275*4887Schin mc->nstrs = sfgetu(ip); 276*4887Schin mc->nmsgs = sfgetu(ip); 277*4887Schin mc->num = sfgetu(ip); 278*4887Schin if (sfeof(ip)) 279*4887Schin goto bad; 280*4887Schin } 281*4887Schin else if (!(mc->translation = vmnewof(vm, 0, char, 1, 0))) 282*4887Schin goto bad; 283*4887Schin 284*4887Schin /* 285*4887Schin * allocate the remaining space 286*4887Schin */ 287*4887Schin 288*4887Schin if (!(mc->set = vmnewof(vm, 0, Mcset_t, mc->num + 1, 0))) 289*4887Schin goto bad; 290*4887Schin if (!ip) 291*4887Schin return mc; 292*4887Schin if (!(mp = vmnewof(vm, 0, char*, mc->nmsgs + mc->num + 1, 0))) 293*4887Schin goto bad; 294*4887Schin if (!(rp = sp = vmalloc(vm, mc->nstrs + 1))) 295*4887Schin goto bad; 296*4887Schin 297*4887Schin /* 298*4887Schin * get the set dimensions and initialize the msg pointers 299*4887Schin */ 300*4887Schin 301*4887Schin while (i = sfgetu(ip)) 302*4887Schin { 303*4887Schin if (i > mc->num) 304*4887Schin goto bad; 305*4887Schin n = sfgetu(ip); 306*4887Schin mc->set[i].num = n; 307*4887Schin mc->set[i].msg = mp; 308*4887Schin mp += n + 1; 309*4887Schin } 310*4887Schin 311*4887Schin /* 312*4887Schin * read the msg sizes and set up the msg pointers 313*4887Schin */ 314*4887Schin 315*4887Schin for (i = 1; i <= mc->num; i++) 316*4887Schin for (j = 1; j <= mc->set[i].num; j++) 317*4887Schin if (n = sfgetu(ip)) 318*4887Schin { 319*4887Schin mc->set[i].msg[j] = sp; 320*4887Schin sp += n; 321*4887Schin } 322*4887Schin 323*4887Schin /* 324*4887Schin * read the string table 325*4887Schin */ 326*4887Schin 327*4887Schin if (sfread(ip, rp, mc->nstrs) != mc->nstrs || sfgetc(ip) != EOF) 328*4887Schin goto bad; 329*4887Schin if (!(mc->tmp = sfstropen())) 330*4887Schin goto bad; 331*4887Schin mc->cvt = iconv_open("", "utf"); 332*4887Schin errno = oerrno; 333*4887Schin return mc; 334*4887Schin bad: 335*4887Schin vmclose(vm); 336*4887Schin errno = oerrno; 337*4887Schin return 0; 338*4887Schin } 339*4887Schin 340*4887Schin /* 341*4887Schin * return the <set,num> message in mc 342*4887Schin * msg returned on error 343*4887Schin * utf message text converted to ucs 344*4887Schin */ 345*4887Schin 346*4887Schin char* 347*4887Schin mcget(register Mc_t* mc, int set, int num, const char* msg) 348*4887Schin { 349*4887Schin char* s; 350*4887Schin size_t n; 351*4887Schin int p; 352*4887Schin 353*4887Schin if (!mc || set < 0 || set > mc->num || num < 1 || num > mc->set[set].num || !(s = mc->set[set].msg[num])) 354*4887Schin return (char*)msg; 355*4887Schin if (mc->cvt == (iconv_t)(-1)) 356*4887Schin return s; 357*4887Schin if ((p = sfstrtell(mc->tmp)) > sfstrsize(mc->tmp) / 2) 358*4887Schin { 359*4887Schin p = 0; 360*4887Schin sfstrseek(mc->tmp, p, SEEK_SET); 361*4887Schin } 362*4887Schin n = strlen(s) + 1; 363*4887Schin iconv_write(mc->cvt, mc->tmp, &s, &n, NiL); 364*4887Schin return sfstrbase(mc->tmp) + p; 365*4887Schin } 366*4887Schin 367*4887Schin /* 368*4887Schin * set message <set,num> to msg 369*4887Schin * msg==0 deletes the message 370*4887Schin * the message and set counts are adjusted 371*4887Schin * 0 returned on success, -1 otherwise 372*4887Schin */ 373*4887Schin 374*4887Schin int 375*4887Schin mcput(register Mc_t* mc, int set, int num, const char* msg) 376*4887Schin { 377*4887Schin register int i; 378*4887Schin register char* s; 379*4887Schin register Mcset_t* sp; 380*4887Schin register char** mp; 381*4887Schin 382*4887Schin /* 383*4887Schin * validate the arguments 384*4887Schin */ 385*4887Schin 386*4887Schin if (!mc || set > MC_SET_MAX || num > MC_NUM_MAX) 387*4887Schin return -1; 388*4887Schin 389*4887Schin /* 390*4887Schin * deletions don't kick in allocations (duh) 391*4887Schin */ 392*4887Schin 393*4887Schin if (!msg) 394*4887Schin { 395*4887Schin if (set <= mc->num && num <= mc->set[set].num && (s = mc->set[set].msg[num])) 396*4887Schin { 397*4887Schin /* 398*4887Schin * decrease the string table size 399*4887Schin */ 400*4887Schin 401*4887Schin mc->set[set].msg[num] = 0; 402*4887Schin mc->nstrs -= strlen(s) + 1; 403*4887Schin if (mc->set[set].num == num) 404*4887Schin { 405*4887Schin /* 406*4887Schin * decrease the max msg num 407*4887Schin */ 408*4887Schin 409*4887Schin mp = mc->set[set].msg + num; 410*4887Schin while (num && !mp[--num]); 411*4887Schin mc->nmsgs -= mc->set[set].num - num; 412*4887Schin if (!(mc->set[set].num = num) && mc->num == set) 413*4887Schin { 414*4887Schin /* 415*4887Schin * decrease the max set num 416*4887Schin */ 417*4887Schin 418*4887Schin while (num && !mc->set[--num].num); 419*4887Schin mc->num = num; 420*4887Schin } 421*4887Schin } 422*4887Schin } 423*4887Schin return 0; 424*4887Schin } 425*4887Schin 426*4887Schin /* 427*4887Schin * keep track of the highest set and allocate if necessary 428*4887Schin */ 429*4887Schin 430*4887Schin if (set > mc->num) 431*4887Schin { 432*4887Schin if (set > mc->gen) 433*4887Schin { 434*4887Schin i = MC_SET_MAX; 435*4887Schin if (!(sp = vmnewof(mc->vm, 0, Mcset_t, i + 1, 0))) 436*4887Schin return -1; 437*4887Schin mc->gen = i; 438*4887Schin for (i = 1; i <= mc->num; i++) 439*4887Schin sp[i] = mc->set[i]; 440*4887Schin mc->set = sp; 441*4887Schin } 442*4887Schin mc->num = set; 443*4887Schin } 444*4887Schin sp = mc->set + set; 445*4887Schin 446*4887Schin /* 447*4887Schin * keep track of the highest msg and allocate if necessary 448*4887Schin */ 449*4887Schin 450*4887Schin if (num > sp->num) 451*4887Schin { 452*4887Schin if (num > sp->gen) 453*4887Schin { 454*4887Schin if (!mc->gen) 455*4887Schin { 456*4887Schin i = (MC_NUM_MAX + 1) / 32; 457*4887Schin if (i <= num) 458*4887Schin i = 2 * num; 459*4887Schin if (i > MC_NUM_MAX) 460*4887Schin i = MC_NUM_MAX; 461*4887Schin if (!(mp = vmnewof(mc->vm, 0, char*, i + 1, 0))) 462*4887Schin return -1; 463*4887Schin mc->gen = i; 464*4887Schin sp->msg = mp; 465*4887Schin for (i = 1; i <= sp->num; i++) 466*4887Schin mp[i] = sp->msg[i]; 467*4887Schin } 468*4887Schin else 469*4887Schin { 470*4887Schin i = 2 * mc->gen; 471*4887Schin if (i > MC_NUM_MAX) 472*4887Schin i = MC_NUM_MAX; 473*4887Schin if (!(mp = vmnewof(mc->vm, sp->msg, char*, i + 1, 0))) 474*4887Schin return -1; 475*4887Schin sp->gen = i; 476*4887Schin sp->msg = mp; 477*4887Schin } 478*4887Schin } 479*4887Schin mc->nmsgs += num - sp->num; 480*4887Schin sp->num = num; 481*4887Schin } 482*4887Schin 483*4887Schin /* 484*4887Schin * decrease the string table size 485*4887Schin */ 486*4887Schin 487*4887Schin if (s = sp->msg[num]) 488*4887Schin { 489*4887Schin /* 490*4887Schin * no-op if no change 491*4887Schin */ 492*4887Schin 493*4887Schin if (streq(s, msg)) 494*4887Schin return 0; 495*4887Schin mc->nstrs -= strlen(s) + 1; 496*4887Schin } 497*4887Schin 498*4887Schin /* 499*4887Schin * allocate, add and adjust the string table size 500*4887Schin */ 501*4887Schin 502*4887Schin if (!(s = vmstrdup(mc->vm, msg))) 503*4887Schin return -1; 504*4887Schin sp->msg[num] = s; 505*4887Schin mc->nstrs += strlen(s) + 1; 506*4887Schin return 0; 507*4887Schin } 508*4887Schin 509*4887Schin /* 510*4887Schin * dump message catalog mc to op 511*4887Schin * 0 returned on success, -1 otherwise 512*4887Schin */ 513*4887Schin 514*4887Schin int 515*4887Schin mcdump(register Mc_t* mc, register Sfio_t* op) 516*4887Schin { 517*4887Schin register int i; 518*4887Schin register int j; 519*4887Schin register int n; 520*4887Schin register char* s; 521*4887Schin register Mcset_t* sp; 522*4887Schin 523*4887Schin /* 524*4887Schin * write the magic 525*4887Schin */ 526*4887Schin 527*4887Schin if (sfwrite(op, MC_MAGIC, MC_MAGIC_SIZE) != MC_MAGIC_SIZE) 528*4887Schin return -1; 529*4887Schin 530*4887Schin /* 531*4887Schin * write the translation record 532*4887Schin */ 533*4887Schin 534*4887Schin sfputr(op, mc->translation, 0); 535*4887Schin 536*4887Schin /* optional header records here */ 537*4887Schin 538*4887Schin /* 539*4887Schin * end of optional header records 540*4887Schin */ 541*4887Schin 542*4887Schin sfputu(op, 0); 543*4887Schin 544*4887Schin /* 545*4887Schin * write the global dimensions 546*4887Schin */ 547*4887Schin 548*4887Schin sfputu(op, mc->nstrs); 549*4887Schin sfputu(op, mc->nmsgs); 550*4887Schin sfputu(op, mc->num); 551*4887Schin 552*4887Schin /* 553*4887Schin * write the set dimensions 554*4887Schin */ 555*4887Schin 556*4887Schin for (i = 1; i <= mc->num; i++) 557*4887Schin if (mc->set[i].num) 558*4887Schin { 559*4887Schin sfputu(op, i); 560*4887Schin sfputu(op, mc->set[i].num); 561*4887Schin } 562*4887Schin sfputu(op, 0); 563*4887Schin 564*4887Schin /* 565*4887Schin * write the message sizes 566*4887Schin */ 567*4887Schin 568*4887Schin for (i = 1; i <= mc->num; i++) 569*4887Schin if (mc->set[i].num) 570*4887Schin { 571*4887Schin sp = mc->set + i; 572*4887Schin for (j = 1; j <= sp->num; j++) 573*4887Schin { 574*4887Schin n = (s = sp->msg[j]) ? (strlen(s) + 1) : 0; 575*4887Schin sfputu(op, n); 576*4887Schin } 577*4887Schin } 578*4887Schin 579*4887Schin /* 580*4887Schin * write the string table 581*4887Schin */ 582*4887Schin 583*4887Schin for (i = 1; i <= mc->num; i++) 584*4887Schin if (mc->set[i].num) 585*4887Schin { 586*4887Schin sp = mc->set + i; 587*4887Schin for (j = 1; j <= sp->num; j++) 588*4887Schin if (s = sp->msg[j]) 589*4887Schin sfputr(op, s, 0); 590*4887Schin } 591*4887Schin 592*4887Schin /* 593*4887Schin * sync and return 594*4887Schin */ 595*4887Schin 596*4887Schin return sfsync(op); 597*4887Schin } 598*4887Schin 599*4887Schin /* 600*4887Schin * parse <set,msg> number from s 601*4887Schin * e!=0 is set to the next char after the parse 602*4887Schin * set!=0 is set to message set number 603*4887Schin * msg!=0 is set to message number 604*4887Schin * the message set number is returned 605*4887Schin * 606*4887Schin * the base 36 hash gives reasonable values for these: 607*4887Schin * 608*4887Schin * "ast" : ((((36#a^36#s^36#t)-9)&63)+1) = 3 609*4887Schin * "gnu" : ((((36#g^36#n^36#u)-9)&63)+1) = 17 610*4887Schin * "sgi" : ((((36#s^36#g^36#i)-9)&63)+1) = 22 611*4887Schin * "sun" : ((((36#s^36#u^36#n)-9)&63)+1) = 13 612*4887Schin */ 613*4887Schin 614*4887Schin int 615*4887Schin mcindex(register const char* s, char** e, int* set, int* msg) 616*4887Schin { 617*4887Schin register int c; 618*4887Schin register int m; 619*4887Schin register int n; 620*4887Schin register int r; 621*4887Schin register unsigned char* cv; 622*4887Schin char* t; 623*4887Schin 624*4887Schin m = 0; 625*4887Schin n = strtol(s, &t, 0); 626*4887Schin if (t == (char*)s) 627*4887Schin { 628*4887Schin SFCVINIT(); 629*4887Schin cv = _Sfcv36; 630*4887Schin for (n = m = 0; (c = cv[*s]) < 36; s++) 631*4887Schin { 632*4887Schin m++; 633*4887Schin n ^= c; 634*4887Schin } 635*4887Schin m = (m <= 3) ? 63 : ((1 << (m + 3)) - 1); 636*4887Schin n = ((n - 9) & m) + 1; 637*4887Schin } 638*4887Schin else 639*4887Schin s = (const char*)t; 640*4887Schin r = n; 641*4887Schin if (*s) 642*4887Schin m = strtol(s + 1, e, 0); 643*4887Schin else 644*4887Schin { 645*4887Schin if (e) 646*4887Schin *e = (char*)s; 647*4887Schin if (m) 648*4887Schin m = 0; 649*4887Schin else 650*4887Schin { 651*4887Schin m = n; 652*4887Schin n = 1; 653*4887Schin } 654*4887Schin } 655*4887Schin if (set) 656*4887Schin *set = n; 657*4887Schin if (msg) 658*4887Schin *msg = m; 659*4887Schin return r; 660*4887Schin } 661*4887Schin 662*4887Schin /* 663*4887Schin * close the message catalog mc 664*4887Schin */ 665*4887Schin 666*4887Schin int 667*4887Schin mcclose(register Mc_t* mc) 668*4887Schin { 669*4887Schin if (!mc) 670*4887Schin return -1; 671*4887Schin if (mc->tmp) 672*4887Schin sfclose(mc->tmp); 673*4887Schin if (mc->cvt != (iconv_t)(-1)) 674*4887Schin iconv_close(mc->cvt); 675*4887Schin vmclose(mc->vm); 676*4887Schin return 0; 677*4887Schin } 678