ldpart.c revision 101307
11541Srgrimes/* 21541Srgrimes * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org> 31541Srgrimes * All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 141541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 151541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 181541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241541Srgrimes * SUCH DAMAGE. 251541Srgrimes */ 261541Srgrimes 271541Srgrimes#include <sys/cdefs.h> 281541Srgrimes__FBSDID("$FreeBSD: head/lib/libc/locale/ldpart.c 101307 2002-08-04 09:37:28Z ache $"); 291541Srgrimes 301541Srgrimes#include "namespace.h" 311541Srgrimes#include <sys/types.h> 321541Srgrimes#include <sys/stat.h> 331541Srgrimes#include <sys/syslimits.h> 341541Srgrimes#include <errno.h> 351541Srgrimes#include <fcntl.h> 361541Srgrimes#include <stdlib.h> 371541Srgrimes#include <string.h> 381541Srgrimes#include <unistd.h> 3940435Speter#include "un-namespace.h" 401541Srgrimes 411541Srgrimes#include "setlocale.h" 421541Srgrimes#include "ldpart.h" 431541Srgrimes 442112Swollmanstatic int split_lines(char *, const char *); 452946Swollmanstatic void set_from_buf(const char *, int, const char **); 461541Srgrimes 4738869Sbdeint 481541Srgrimes__part_load_locale(const char *name, 491541Srgrimes int *using_locale, 5029653Sdyson char *locale_buf, 511541Srgrimes const char *category_filename, 5212913Sphk int locale_buf_size_max, 5312577Sbde int locale_buf_size_min, 5410653Sdg const char **dst_localebuf) 5510358Sjulian{ 5610358Sjulian static char locale_buf_C[] = "C"; 5730354Sphk static int num_lines; 5830354Sphk int saverr; 5910358Sjulian int fd; 601541Srgrimes char *lbuf; 611541Srgrimes char *p; 621541Srgrimes const char *plim; 631541Srgrimes char filename[PATH_MAX]; 641541Srgrimes struct stat st; 651541Srgrimes size_t namesize; 661541Srgrimes size_t bufsize; 671541Srgrimes int save_using_locale; 6833181Seivind 692946Swollman save_using_locale = *using_locale; 7040435Speter *using_locale = 0; 712946Swollman 722946Swollman /* 'name' must be already checked. */ 7340435Speter 742946Swollman if (!strcmp(name, "C") || !strcmp(name, "POSIX")) 751541Srgrimes return 0; 761541Srgrimes 771541Srgrimes /* 781541Srgrimes * If the locale name is the same as our cache, use the cache. 7940435Speter */ 8040435Speter lbuf = locale_buf; 8140435Speter if (lbuf != NULL && strcmp(name, lbuf) == 0) { 8240435Speter set_from_buf(lbuf, num_lines, dst_localebuf); 8340435Speter *using_locale = 1; 8440435Speter return 0; 8540435Speter } 8640435Speter 8740435Speter /* 8840435Speter * Slurp the locale file into the cache. 8940435Speter */ 9029653Sdyson namesize = strlen(name) + 1; 9129653Sdyson 9229653Sdyson /* 'PathLocale' must be already set & checked. */ 9329653Sdyson 9429653Sdyson /* Range checking not needed, 'name' size is limited */ 951541Srgrimes strcpy(filename, _PathLocale); 961541Srgrimes strcat(filename, "/"); 971541Srgrimes strcat(filename, name); 981541Srgrimes strcat(filename, "/"); 991541Srgrimes strcat(filename, category_filename); 1001541Srgrimes fd = _open(filename, O_RDONLY); 1011541Srgrimes if (fd < 0) 1021541Srgrimes goto no_locale; 1031541Srgrimes if (_fstat(fd, &st) != 0) 1041541Srgrimes goto bad_locale; 1051541Srgrimes if (st.st_size <= 0) { 1061541Srgrimes errno = EFTYPE; 1071541Srgrimes goto bad_locale; 1081541Srgrimes } 10929290Sphk bufsize = namesize + st.st_size; 11029290Sphk locale_buf = NULL; 11129290Sphk lbuf = (lbuf == NULL || lbuf == locale_buf_C) ? 11229290Sphk malloc(bufsize) : reallocf(lbuf, bufsize); 11329290Sphk if (lbuf == NULL) 11429290Sphk goto bad_locale; 1151541Srgrimes (void) strcpy(lbuf, name); 1161541Srgrimes p = lbuf + namesize; 11740435Speter plim = p + st.st_size; 1181541Srgrimes if (_read(fd, p, (size_t) st.st_size) != st.st_size) 11940435Speter goto bad_lbuf; 12012158Sbde if (_close(fd) != 0) 12112158Sbde goto bad_lbuf; 1221541Srgrimes /* 1231541Srgrimes * Parse the locale file into localebuf. 1241541Srgrimes */ 1251541Srgrimes if (plim[-1] != '\n') { 1261541Srgrimes errno = EFTYPE; 12740435Speter goto bad_lbuf; 12840435Speter } 12940435Speter num_lines = split_lines(p, plim); 13040435Speter if (num_lines >= locale_buf_size_max) 13140435Speter num_lines = locale_buf_size_max; 13240435Speter else if (num_lines >= locale_buf_size_min) 13340435Speter num_lines = locale_buf_size_min; 13440435Speter else { 13540435Speter errno = EFTYPE; 13640435Speter goto reset_locale; 13740435Speter } 13840435Speter set_from_buf(lbuf, num_lines, dst_localebuf); 13940435Speter /* 14040435Speter * Record the successful parse in the cache. 14140435Speter */ 14240435Speter locale_buf = lbuf; 14340435Speter 14440435Speter *using_locale = 1; 14540435Speter return 0; 1461541Srgrimes 14740435Speterreset_locale: 14840435Speter locale_buf = locale_buf_C; 14940435Speter save_using_locale = 0; 15040435Speterbad_lbuf: 15140435Speter saverr = errno; free(lbuf); errno = saverr; 15240435Speterbad_locale: 15340435Speter saverr = errno; (void)_close(fd); errno = saverr; 15440435Speterno_locale: 15540435Speter *using_locale = save_using_locale; 15640435Speter return -1; 15740435Speter} 15840435Speter 15940435Speterstatic int 16040435Spetersplit_lines(char *p, const char *plim) { 16140435Speter 1621541Srgrimes int i; 16340435Speter 16440435Speter for (i = 0; p < plim; i++) { 16540435Speter p = strchr(p, '\n'); 16640435Speter *p++ = '\0'; 16740435Speter } 16840435Speter return i; 16940435Speter} 1701541Srgrimes 17140435Speterstatic void 17240435Speterset_from_buf(const char *p, int num_lines, const char **dst_localebuf) { 17340435Speter 17440435Speter const char **ap; 17540435Speter int i; 1761541Srgrimes 1771541Srgrimes for (ap = dst_localebuf, i = 0; i < num_lines; ++ap, ++i) 1781541Srgrimes *ap = p += strlen(p) + 1; 1791541Srgrimes} 1801541Srgrimes 1811541Srgrimes