strftime.c revision 15923
11553Srgrimes/* 21553Srgrimes * Copyright (c) 1989 The Regents of the University of California. 31553Srgrimes * All rights reserved. 41553Srgrimes * 51553Srgrimes * Redistribution and use in source and binary forms are permitted 61553Srgrimes * provided that the above copyright notice and this paragraph are 71553Srgrimes * duplicated in all such forms and that any documentation, 81553Srgrimes * advertising materials, and other materials related to such 91553Srgrimes * distribution and use acknowledge that the software was developed 101553Srgrimes * by the University of California, Berkeley. The name of the 111553Srgrimes * University may not be used to endorse or promote products derived 121553Srgrimes * from this software without specific prior written permission. 131553Srgrimes * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 141553Srgrimes * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 151553Srgrimes * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 161553Srgrimes * 171553Srgrimes * $Id:$ 181553Srgrimes */ 191553Srgrimes 201553Srgrimes#ifdef LIBC_RCS 211553Srgrimesstatic const char rcsid[] = 221553Srgrimes "$Id: strftime.c,v 1.6 1995/10/23 19:52:43 ache Exp $"; 231553Srgrimes#endif 241553Srgrimes 251553Srgrimes#ifndef lint 261553Srgrimes#ifndef NOID 271553Srgrimesstatic const char elsieid[] = "@(#)strftime.c 7.38"; 281553Srgrimes/* 291553Srgrimes** Based on the UCB version with the ID appearing below. 301553Srgrimes** This is ANSIish only when "multibyte character == plain character". 3130380Scharnier*/ 321553Srgrimes#endif /* !defined NOID */ 331553Srgrimes#endif /* !defined lint */ 341553Srgrimes 351553Srgrimes#include "private.h" 36117278Scharnier 371553Srgrimes#ifndef LIBC_SCCS 381553Srgrimes#ifndef lint 39117278Scharnierstatic const char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89"; 4030380Scharnier#endif /* !defined lint */ 411553Srgrimes#endif /* !defined LIBC_SCCS */ 42117278Scharnier 43117278Scharnier#include "tzfile.h" 44117278Scharnier#include <fcntl.h> 451553Srgrimes#include <locale.h> 461553Srgrimes#include <rune.h> /* for _PATH_LOCALE */ 471553Srgrimes#include <sys/stat.h> 481553Srgrimes 491553Srgrimes#define LOCALE_HOME _PATH_LOCALE 501553Srgrimes 511553Srgrimesstruct lc_time_T { 521553Srgrimes const char * mon[12]; 531553Srgrimes const char * month[12]; 541553Srgrimes const char * wday[7]; 551553Srgrimes const char * weekday[7]; 5670284Siedowse const char * X_fmt; 571553Srgrimes const char * x_fmt; 581553Srgrimes const char * c_fmt; 591553Srgrimes const char * am; 6030380Scharnier const char * pm; 611553Srgrimes const char * date_fmt; 621553Srgrimes}; 631553Srgrimes 641553Srgrimesstatic struct lc_time_T localebuf; 651553Srgrimesstatic struct lc_time_T * _loc P((void)); 661553Srgrimesstatic int using_locale; 671553Srgrimes 681553Srgrimes#define Locale (using_locale ? &localebuf : &C_time_locale) 6999825Salfred 70201060Sedstatic const struct lc_time_T C_time_locale = { 71201060Sed { 721553Srgrimes "Jan", "Feb", "Mar", "Apr", "May", "Jun", 7317829Spst "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 7418092Speter }, { 751553Srgrimes "January", "February", "March", "April", "May", "June", 761553Srgrimes "July", "August", "September", "October", "November", "December" 7710087Sjkh }, { 7810087Sjkh "Sun", "Mon", "Tue", "Wed", 7910087Sjkh "Thu", "Fri", "Sat" 8010087Sjkh }, { 8110087Sjkh "Sunday", "Monday", "Tuesday", "Wednesday", 8210087Sjkh "Thursday", "Friday", "Saturday" 8310087Sjkh }, 8410087Sjkh 8510087Sjkh /* X_fmt */ 8610087Sjkh "%H:%M:%S", 8710087Sjkh 8810087Sjkh /* 8910087Sjkh ** x_fmt 9010087Sjkh ** Since the C language standard calls for 9110087Sjkh ** "date, using locale's date format," anything goes. 9210087Sjkh ** Using just numbers (as here) makes Quakers happier; 9310087Sjkh ** it's also compatible with SVR4. 9410087Sjkh */ 9510087Sjkh "%m/%d/%y", 9610087Sjkh 9710087Sjkh /* 9810087Sjkh ** c_fmt (ctime-compatible) 9910087Sjkh ** Note that 10010087Sjkh ** "%a %b %d %H:%M:%S %Y" 10110087Sjkh ** is used by Solaris 2.3. 10210087Sjkh */ 10310087Sjkh "%a %b %e %X %Y", 10410087Sjkh 10510087Sjkh /* am */ 10617832Spst "AM", 10717829Spst 10817829Spst /* pm */ 10910087Sjkh "PM", 11010087Sjkh 11110087Sjkh /* date_fmt */ 11210087Sjkh "%a %b %e %X %Z %Y" 11310087Sjkh}; 11410087Sjkh 11510087Sjkhstatic char * _add P((const char *, char *, const char *)); 11610087Sjkhstatic char * _conv P((int, const char *, char *, const char *)); 11710087Sjkhstatic char * _fmt P((const char *, const struct tm *, char *, const char *)); 11841895Sdesstatic char * _secs P((const struct tm *, char *, const char *)); 11942508Ssteve 12047963Sbriansize_t strftime P((char *, size_t, const char *, const struct tm *)); 12110087Sjkh 12210087Sjkhextern char * tzname[]; 12399825Salfred 12499825Salfredsize_t 12510087Sjkhstrftime(s, maxsize, format, t) 12610087Sjkh char *const s; 1271553Srgrimes const size_t maxsize; 1281553Srgrimes const char *const format; 1291553Srgrimes const struct tm *const t; 1301553Srgrimes{ 1311553Srgrimes char *p; 1321553Srgrimes 1331553Srgrimes tzset(); 1341553Srgrimes p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize); 1351553Srgrimes if (p == s + maxsize) 1361553Srgrimes return 0; 1371553Srgrimes *p = '\0'; 1381553Srgrimes return p - s; 1391553Srgrimes} 1401553Srgrimes 1411553Srgrimesstatic char * 1421553Srgrimes_fmt(format, t, pt, ptlim) 1431553Srgrimes const char *format; 1441553Srgrimes const struct tm *const t; 1451553Srgrimes char *pt; 1461553Srgrimes const char *const ptlim; 1471553Srgrimes{ 1481553Srgrimes for ( ; *format; ++format) { 1491553Srgrimes if (*format == '%') { 150201060Sedlabel: 1511553Srgrimes switch (*++format) { 15299825Salfred case '\0': 1531553Srgrimes --format; 15499825Salfred break; 15599825Salfred case 'A': 15699825Salfred pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ? 15799825Salfred "?" : Locale->weekday[t->tm_wday], 15899825Salfred pt, ptlim); 15999825Salfred continue; 16099825Salfred case 'a': 16199825Salfred pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ? 1621553Srgrimes "?" : Locale->wday[t->tm_wday], 16399825Salfred pt, ptlim); 164117278Scharnier continue; 1651553Srgrimes case 'B': 1661553Srgrimes pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ? 1671553Srgrimes "?" : Locale->month[t->tm_mon], 1681553Srgrimes pt, ptlim); 16999825Salfred continue; 1701553Srgrimes case 'b': 1711553Srgrimes case 'h': 1721553Srgrimes pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ? 1731553Srgrimes "?" : Locale->mon[t->tm_mon], 1741553Srgrimes pt, ptlim); 1751553Srgrimes continue; 17699825Salfred case 'C': 17717829Spst /* 17817829Spst ** %C used to do a... 1791553Srgrimes ** _fmt("%a %b %e %X %Y", t); 18030380Scharnier ** ...whereas now POSIX 1003.2 calls for 18130380Scharnier ** something completely different. 18217829Spst ** (ado, 5/24/93) 18317829Spst */ 18417829Spst pt = _conv((t->tm_year + TM_YEAR_BASE) / 100, 18510087Sjkh "%02d", pt, ptlim); 18610087Sjkh continue; 18710087Sjkh case 'c': 18810087Sjkh pt = _fmt(Locale->c_fmt, t, pt, ptlim); 18910087Sjkh continue; 19010087Sjkh case 'D': 19110087Sjkh pt = _fmt("%m/%d/%y", t, pt, ptlim); 19230380Scharnier continue; 19330380Scharnier case 'd': 19410087Sjkh pt = _conv(t->tm_mday, "%02d", pt, ptlim); 19510087Sjkh continue; 19610087Sjkh case 'E': 19710087Sjkh case 'O': 19841895Sdes /* 19942508Ssteve ** POSIX locale extensions, a la 20042508Ssteve ** Arnold Robbins' strftime version 3.0. 20142508Ssteve ** The sequences 20247963Sbrian ** %Ec %EC %Ex %Ey %EY 20347963Sbrian ** %Od %oe %OH %OI %Om %OM 20430380Scharnier ** %OS %Ou %OU %OV %Ow %OW %Oy 20530380Scharnier ** are supposed to provide alternate 20610087Sjkh ** representations. 20710087Sjkh ** (ado, 5/24/93) 20830380Scharnier */ 20930380Scharnier goto label; 2101553Srgrimes case 'e': 2111553Srgrimes pt = _conv(t->tm_mday, "%2d", pt, ptlim); 2121553Srgrimes continue; 21310087Sjkh case 'H': 21410087Sjkh pt = _conv(t->tm_hour, "%02d", pt, ptlim); 21510087Sjkh continue; 21610087Sjkh case 'I': 217117278Scharnier pt = _conv((t->tm_hour % 12) ? 21810087Sjkh (t->tm_hour % 12) : 12, 21910087Sjkh "%02d", pt, ptlim); 2201553Srgrimes continue; 22153770Scharnier case 'j': 2221553Srgrimes pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim); 2231553Srgrimes continue; 2241553Srgrimes case 'k': 2251553Srgrimes /* 2261553Srgrimes ** This used to be... 2271553Srgrimes ** _conv(t->tm_hour % 12 ? 2281553Srgrimes ** t->tm_hour % 12 : 12, 2, ' '); 2291553Srgrimes ** ...and has been changed to the below to 2301553Srgrimes ** match SunOS 4.1.1 and Arnold Robbins' 2311553Srgrimes ** strftime version 3.0. That is, "%k" and 2321553Srgrimes ** "%l" have been swapped. 23319303Simp ** (ado, 5/24/93) 23419303Simp */ 2351553Srgrimes pt = _conv(t->tm_hour, "%2d", pt, ptlim); 2361553Srgrimes continue; 2371553Srgrimes#ifdef KITCHEN_SINK 2381553Srgrimes case 'K': 2391553Srgrimes /* 2401553Srgrimes ** After all this time, still unclaimed! 2411553Srgrimes */ 2421553Srgrimes pt = _add("kitchen sink", pt, ptlim); 2431553Srgrimes continue; 24499825Salfred#endif /* defined KITCHEN_SINK */ 24599825Salfred case 'l': 24699825Salfred /* 24799825Salfred ** This used to be... 24899825Salfred ** _conv(t->tm_hour, 2, ' '); 2491553Srgrimes ** ...and has been changed to the below to 2501553Srgrimes ** match SunOS 4.1.1 and Arnold Robbin's 2511553Srgrimes ** strftime version 3.0. That is, "%k" and 25217829Spst ** "%l" have been swapped. 25318092Speter ** (ado, 5/24/93) 25417829Spst */ 2551553Srgrimes pt = _conv((t->tm_hour % 12) ? 2561553Srgrimes (t->tm_hour % 12) : 12, 25742508Ssteve "%2d", pt, ptlim); 25842508Ssteve continue; 25942508Ssteve case 'M': 26042508Ssteve pt = _conv(t->tm_min, "%02d", pt, ptlim); 2611553Srgrimes continue; 2621553Srgrimes case 'm': 263141918Sstefanf pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim); 264141918Sstefanf continue; 26585640Sdillon case 'n': 2661553Srgrimes pt = _add("\n", pt, ptlim); 2671553Srgrimes continue; 2681553Srgrimes case 'p': 2691553Srgrimes pt = _add((t->tm_hour >= 12) ? 2701553Srgrimes Locale->pm : 2711553Srgrimes Locale->am, 2721553Srgrimes pt, ptlim); 2731553Srgrimes continue; 27441895Sdes case 'R': 27570284Siedowse pt = _fmt("%H:%M", t, pt, ptlim); 27670284Siedowse continue; 2771553Srgrimes case 'r': 2781553Srgrimes pt = _fmt("%I:%M:%S %p", t, pt, ptlim); 27970284Siedowse continue; 28070284Siedowse case 'S': 28170284Siedowse pt = _conv(t->tm_sec, "%02d", pt, ptlim); 28270284Siedowse continue; 28370284Siedowse case 's': 2841553Srgrimes pt = _secs(t, pt, ptlim); 2851553Srgrimes continue; 2861553Srgrimes case 'T': 2871553Srgrimes pt = _fmt("%H:%M:%S", t, pt, ptlim); 28817829Spst continue; 28970284Siedowse case 't': 29070284Siedowse pt = _add("\t", pt, ptlim); 2911553Srgrimes continue; 2921553Srgrimes case 'U': 29330380Scharnier pt = _conv((t->tm_yday + 7 - t->tm_wday) / 7, 2941553Srgrimes "%02d", pt, ptlim); 2951553Srgrimes continue; 2961553Srgrimes case 'u': 2971553Srgrimes /* 2981553Srgrimes ** From Arnold Robbins' strftime version 3.0: 2991553Srgrimes ** "ISO 8601: Weekday as a decimal number 3001553Srgrimes ** [1 (Monday) - 7]" 3011553Srgrimes ** (ado, 5/24/93) 3021553Srgrimes */ 3031553Srgrimes pt = _conv((t->tm_wday == 0) ? 7 : t->tm_wday, 3041553Srgrimes "%d", pt, ptlim); 3051553Srgrimes continue; 3061553Srgrimes case 'V': 3071553Srgrimes /* 3081553Srgrimes ** From Arnold Robbins' strftime version 3.0: 3091553Srgrimes ** "the week number of the year (the first 3101553Srgrimes ** Monday as the first day of week 1) as a 3111553Srgrimes ** decimal number (01-53). The method for 3121553Srgrimes ** determining the week number is as specified 3131553Srgrimes ** by ISO 8601 (to wit: if the week containing 3141553Srgrimes ** January 1 has four or more days in the new 3151553Srgrimes ** year, then it is week 1, otherwise it is 3161553Srgrimes ** week 53 of the previous year and the next 3171553Srgrimes ** week is week 1)." 3181553Srgrimes ** (ado, 5/24/93) 3191553Srgrimes */ 3201553Srgrimes /* 3211553Srgrimes ** XXX--If January 1 falls on a Friday, 32285640Sdillon ** January 1-3 are part of week 53 of the 32389572Sdillon ** previous year. By analogy, if January 3241553Srgrimes ** 1 falls on a Thursday, are December 29-31 3251553Srgrimes ** of the PREVIOUS year part of week 1??? 3261553Srgrimes ** (ado 5/24/93) 3271553Srgrimes */ 3281553Srgrimes /* 3291553Srgrimes ** You are understood not to expect this. 3301553Srgrimes */ 33130380Scharnier { 33230380Scharnier int i; 33330380Scharnier 33448229Sbrian i = (t->tm_yday + 10 - (t->tm_wday ? 33530380Scharnier (t->tm_wday - 1) : 6)) / 7; 33630380Scharnier if (i == 0) { 33717829Spst /* 33817829Spst ** What day of the week does 33917829Spst ** January 1 fall on? 34017829Spst */ 34117829Spst i = t->tm_wday - 34217829Spst (t->tm_yday - 1); 34317829Spst /* 34418092Speter ** Fri Jan 1: 53 34517829Spst ** Sun Jan 1: 52 34617829Spst ** Sat Jan 1: 53 if previous 34717829Spst ** year a leap 34817829Spst ** year, else 52 34917829Spst */ 35017829Spst if (i == TM_FRIDAY) 35117829Spst i = 53; 35217829Spst else if (i == TM_SUNDAY) 35318092Speter i = 52; 35418092Speter else i = isleap(t->tm_year + 35518092Speter TM_YEAR_BASE) ? 35617829Spst 53 : 52; 35717829Spst#ifdef XPG4_1994_04_09 35818092Speter /* 35917829Spst ** As of 4/9/94, though, 36017829Spst ** XPG4 calls for 53 3611553Srgrimes ** unconditionally. 3621553Srgrimes */ 3631553Srgrimes i = 53; 3641553Srgrimes#endif /* defined XPG4_1994_04_09 */ 3651553Srgrimes } 3661553Srgrimes pt = _conv(i, "%02d", pt, ptlim); 36717829Spst } 3681553Srgrimes continue; 36917829Spst case 'v': 3701553Srgrimes /* 3711553Srgrimes ** From Arnold Robbins' strftime version 3.0: 3721553Srgrimes ** "date as dd-bbb-YYYY" 37319303Simp ** (ado, 5/24/93) 3741553Srgrimes */ 3751553Srgrimes pt = _fmt("%e-%b-%Y", t, pt, ptlim); 3761553Srgrimes continue; 3771553Srgrimes case 'W': 37817829Spst pt = _conv((t->tm_yday + 7 - 3791553Srgrimes (t->tm_wday ? 3801553Srgrimes (t->tm_wday - 1) : 6)) / 7, 3811553Srgrimes "%02d", pt, ptlim); 3821553Srgrimes continue; 383201060Sed case 'w': 3841553Srgrimes pt = _conv(t->tm_wday, "%d", pt, ptlim); 385201060Sed continue; 386201060Sed case 'X': 3871553Srgrimes pt = _fmt(Locale->X_fmt, t, pt, ptlim); 388201060Sed continue; 389201060Sed case 'x': 3901553Srgrimes pt = _fmt(Locale->x_fmt, t, pt, ptlim); 3911553Srgrimes continue; 392201060Sed case 'y': 3931553Srgrimes pt = _conv((t->tm_year + TM_YEAR_BASE) % 100, 3941553Srgrimes "%02d", pt, ptlim); 3951553Srgrimes continue; 3961553Srgrimes case 'Y': 3971553Srgrimes pt = _conv(t->tm_year + TM_YEAR_BASE, "%04d", 398201060Sed pt, ptlim); 399201060Sed continue; 400201060Sed case 'Z': 401201060Sed if (t->tm_zone != NULL) 402201060Sed pt = _add(t->tm_zone, pt, ptlim); 403201060Sed else 404201060Sed if (t->tm_isdst == 0 || t->tm_isdst == 1) { 405201060Sed pt = _add(tzname[t->tm_isdst], 406201060Sed pt, ptlim); 407201060Sed } else pt = _add("?", pt, ptlim); 408201060Sed continue; 409201060Sed case '+': 4101553Srgrimes pt = _fmt(Locale->date_fmt, t, pt, ptlim); 411201060Sed continue; 4121553Srgrimes case '%': 413201060Sed /* 4141553Srgrimes * X311J/88-090 (4.12.3.5): if conversion char is 4151553Srgrimes * undefined, behavior is undefined. Print out the 4161553Srgrimes * character itself as printf(3) also does. 417201060Sed */ 418201060Sed default: 4191553Srgrimes break; 4201553Srgrimes } 4211553Srgrimes } 4221553Srgrimes if (pt == ptlim) 4231553Srgrimes break; 4241553Srgrimes *pt++ = *format; 4251553Srgrimes } 426201060Sed return pt; 42789572Sdillon} 4281553Srgrimes 4291553Srgrimesstatic char * 43010087Sjkh_conv(n, format, pt, ptlim) 43110087Sjkh const int n; 43210087Sjkh const char *const format; 43310087Sjkh char *const pt; 43410087Sjkh const char *const ptlim; 43510087Sjkh{ 43610087Sjkh char buf[INT_STRLEN_MAXIMUM(int) + 1]; 43710087Sjkh 43810087Sjkh (void) sprintf(buf, format, n); 43910087Sjkh return _add(buf, pt, ptlim); 44010087Sjkh} 44110087Sjkh 44210087Sjkhstatic char * 44310087Sjkh_secs(t, pt, ptlim) 44410087Sjkh const struct tm *t; 44510087Sjkh char *pt; 44610087Sjkh const char *ptlim; 44710087Sjkh{ 44810087Sjkh char buf[INT_STRLEN_MAXIMUM(int) + 1]; 44910087Sjkh register time_t s; 45010087Sjkh struct tm tmp; 45110087Sjkh 45210087Sjkh /* Make a copy, mktime(3) modifies the tm struct. */ 45310087Sjkh tmp = *t; 454201060Sed s = mktime(&tmp); 4551553Srgrimes (void) sprintf(buf, "%ld", s); 4561553Srgrimes return _add(buf, pt, ptlim); 4571553Srgrimes} 4581553Srgrimes 4591553Srgrimesstatic char * 4601553Srgrimes_add(str, pt, ptlim) 4611553Srgrimes const char *str; 4621553Srgrimes char *pt; 46399825Salfred const char *const ptlim; 4641553Srgrimes{ 4651553Srgrimes while (pt < ptlim && (*pt = *str++) != '\0') 4661553Srgrimes ++pt; 4671553Srgrimes return pt; 4681553Srgrimes} 4691553Srgrimes 4701553Srgrimesextern char *_PathLocale; 4711553Srgrimes 4721553Srgrimesint 4731553Srgrimes__time_load_locale(const char *name) 4741553Srgrimes{ 4751553Srgrimes static const char lc_time[] = "LC_TIME"; 47689572Sdillon static char * locale_buf; 4771553Srgrimes static char locale_buf_C[] = "C"; 4781553Srgrimes 4791553Srgrimes int fd; 4801553Srgrimes char * lbuf; 48199825Salfred char * p; 4821553Srgrimes const char ** ap; 48362989Skris const char * plim; 4841553Srgrimes char filename[FILENAME_MAX]; 4851553Srgrimes struct stat st; 4861553Srgrimes size_t namesize; 4871553Srgrimes size_t bufsize; 4881553Srgrimes int save_using_locale; 4891553Srgrimes 4901553Srgrimes save_using_locale = using_locale; 4911553Srgrimes using_locale = 0; 4921553Srgrimes 4931553Srgrimes if (name == NULL) 4941553Srgrimes goto no_locale; 4951553Srgrimes 4961553Srgrimes if (!*name || !strcmp(name, "C") || !strcmp(name, "POSIX")) 4971553Srgrimes return 0; 4981553Srgrimes 4991553Srgrimes /* 500128186Sluigi ** If the locale name is the same as our cache, use the cache. 5011553Srgrimes */ 5021553Srgrimes lbuf = locale_buf; 5031553Srgrimes if (lbuf != NULL && strcmp(name, lbuf) == 0) { 5041553Srgrimes p = lbuf; 5051553Srgrimes for (ap = (const char **) &localebuf; 5061553Srgrimes ap < (const char **) (&localebuf + 1); 5071553Srgrimes ++ap) 5081553Srgrimes *ap = p += strlen(p) + 1; 50999825Salfred using_locale = 1; 51099825Salfred return 0; 5111553Srgrimes } 5121553Srgrimes /* 5131553Srgrimes ** Slurp the locale file into the cache. 5141553Srgrimes */ 5151553Srgrimes namesize = strlen(name) + 1; 5161553Srgrimes 5171553Srgrimes snprintf(filename, sizeof filename, 5181553Srgrimes "%s/%s/%s", 5191553Srgrimes _PathLocale, name, lc_time); 5201553Srgrimes fd = open(filename, O_RDONLY); 52110087Sjkh if (fd < 0) 52210087Sjkh goto no_locale; 52310087Sjkh if (fstat(fd, &st) != 0) 52410087Sjkh goto bad_locale; 52510087Sjkh if (st.st_size <= 0) 52610087Sjkh goto bad_locale; 52710087Sjkh bufsize = namesize + st.st_size; 52810087Sjkh locale_buf = NULL; 52910087Sjkh lbuf = (lbuf == NULL || lbuf == locale_buf_C) ? 53010087Sjkh malloc(bufsize) : realloc(lbuf, bufsize); 53110087Sjkh if (lbuf == NULL) 53299825Salfred goto bad_locale; 53310087Sjkh (void) strcpy(lbuf, name); 53410087Sjkh p = lbuf + namesize; 53510087Sjkh plim = p + st.st_size; 53610087Sjkh if (read(fd, p, (size_t) st.st_size) != st.st_size) 53710087Sjkh goto bad_lbuf; 53810087Sjkh if (close(fd) != 0) 53999825Salfred goto bad_lbuf; 54010087Sjkh /* 54110087Sjkh ** Parse the locale file into localebuf. 54210087Sjkh */ 54310087Sjkh if (plim[-1] != '\n') 54410087Sjkh goto bad_lbuf; 54510087Sjkh for (ap = (const char **) &localebuf; 54610087Sjkh ap < (const char **) (&localebuf + 1); 54710087Sjkh ++ap) { 5481553Srgrimes if (p == plim) 5491553Srgrimes goto reset_locale; 5501553Srgrimes *ap = p; 5511553Srgrimes while (*p != '\n') 5521553Srgrimes ++p; 5531553Srgrimes *p++ = '\0'; 5541553Srgrimes } 5551553Srgrimes /* 5561553Srgrimes ** Record the successful parse in the cache. 5571553Srgrimes */ 5581553Srgrimes locale_buf = lbuf; 5591553Srgrimes 5601553Srgrimes using_locale = 1; 5611553Srgrimes return 0; 5621553Srgrimes 5631553Srgrimesreset_locale: 5641553Srgrimes /* 5651553Srgrimes * XXX - This may not be the correct thing to do in this case. 5661553Srgrimes * setlocale() assumes that we left the old locale alone. 5671553Srgrimes */ 5681553Srgrimes locale_buf = locale_buf_C; 5691553Srgrimes localebuf = C_time_locale; 5701553Srgrimes save_using_locale = 0; 57110087Sjkhbad_lbuf: 57210087Sjkh free(lbuf); 57347963Sbrianbad_locale: 5741553Srgrimes (void) close(fd); 5751553Srgrimesno_locale: 5761553Srgrimes using_locale = save_using_locale; 5771553Srgrimes return -1; 5781553Srgrimes} 5791553Srgrimes