Home | History | Annotate | Line # | Download | only in time
strftime.c revision 1.1.1.3
      1  1.1.1.1   kleink #ifndef lint
      2  1.1.1.1   kleink #ifndef NOID
      3  1.1.1.3  mlelstv static char	elsieid[] = "@(#)strftime.c	8.3";
      4      1.1      mrg /*
      5  1.1.1.1   kleink ** Based on the UCB version with the ID appearing below.
      6  1.1.1.1   kleink ** This is ANSIish only when "multibyte character == plain character".
      7  1.1.1.1   kleink */
      8  1.1.1.1   kleink #endif /* !defined NOID */
      9  1.1.1.1   kleink #endif /* !defined lint */
     10  1.1.1.1   kleink 
     11  1.1.1.1   kleink #include "private.h"
     12  1.1.1.1   kleink 
     13  1.1.1.1   kleink /*
     14  1.1.1.1   kleink ** Copyright (c) 1989 The Regents of the University of California.
     15  1.1.1.1   kleink ** All rights reserved.
     16  1.1.1.1   kleink **
     17  1.1.1.1   kleink ** Redistribution and use in source and binary forms are permitted
     18  1.1.1.1   kleink ** provided that the above copyright notice and this paragraph are
     19  1.1.1.1   kleink ** duplicated in all such forms and that any documentation,
     20  1.1.1.1   kleink ** advertising materials, and other materials related to such
     21  1.1.1.1   kleink ** distribution and use acknowledge that the software was developed
     22  1.1.1.3  mlelstv ** by the University of California, Berkeley. The name of the
     23  1.1.1.1   kleink ** University may not be used to endorse or promote products derived
     24  1.1.1.1   kleink ** from this software without specific prior written permission.
     25  1.1.1.1   kleink ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
     26  1.1.1.1   kleink ** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
     27  1.1.1.1   kleink ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     28  1.1.1.1   kleink */
     29  1.1.1.1   kleink 
     30  1.1.1.1   kleink #ifndef LIBC_SCCS
     31  1.1.1.1   kleink #ifndef lint
     32  1.1.1.1   kleink static const char	sccsid[] = "@(#)strftime.c	5.4 (Berkeley) 3/14/89";
     33  1.1.1.1   kleink #endif /* !defined lint */
     34  1.1.1.1   kleink #endif /* !defined LIBC_SCCS */
     35  1.1.1.1   kleink 
     36  1.1.1.1   kleink #include "tzfile.h"
     37  1.1.1.1   kleink #include "fcntl.h"
     38  1.1.1.1   kleink #include "locale.h"
     39  1.1.1.1   kleink 
     40  1.1.1.1   kleink struct lc_time_T {
     41  1.1.1.1   kleink 	const char *	mon[MONSPERYEAR];
     42  1.1.1.1   kleink 	const char *	month[MONSPERYEAR];
     43  1.1.1.1   kleink 	const char *	wday[DAYSPERWEEK];
     44  1.1.1.1   kleink 	const char *	weekday[DAYSPERWEEK];
     45  1.1.1.1   kleink 	const char *	X_fmt;
     46  1.1.1.1   kleink 	const char *	x_fmt;
     47  1.1.1.1   kleink 	const char *	c_fmt;
     48  1.1.1.1   kleink 	const char *	am;
     49  1.1.1.1   kleink 	const char *	pm;
     50  1.1.1.1   kleink 	const char *	date_fmt;
     51  1.1.1.1   kleink };
     52  1.1.1.1   kleink 
     53  1.1.1.1   kleink #ifdef LOCALE_HOME
     54  1.1.1.1   kleink #include "sys/stat.h"
     55  1.1.1.1   kleink static struct lc_time_T		localebuf;
     56  1.1.1.3  mlelstv static struct lc_time_T *	_loc(void);
     57  1.1.1.1   kleink #define Locale	_loc()
     58  1.1.1.1   kleink #endif /* defined LOCALE_HOME */
     59  1.1.1.1   kleink #ifndef LOCALE_HOME
     60  1.1.1.1   kleink #define Locale	(&C_time_locale)
     61  1.1.1.1   kleink #endif /* !defined LOCALE_HOME */
     62  1.1.1.1   kleink 
     63  1.1.1.1   kleink static const struct lc_time_T	C_time_locale = {
     64  1.1.1.1   kleink 	{
     65  1.1.1.1   kleink 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
     66  1.1.1.1   kleink 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
     67  1.1.1.1   kleink 	}, {
     68  1.1.1.1   kleink 		"January", "February", "March", "April", "May", "June",
     69  1.1.1.1   kleink 		"July", "August", "September", "October", "November", "December"
     70  1.1.1.1   kleink 	}, {
     71  1.1.1.1   kleink 		"Sun", "Mon", "Tue", "Wed",
     72  1.1.1.1   kleink 		"Thu", "Fri", "Sat"
     73  1.1.1.1   kleink 	}, {
     74  1.1.1.1   kleink 		"Sunday", "Monday", "Tuesday", "Wednesday",
     75  1.1.1.1   kleink 		"Thursday", "Friday", "Saturday"
     76  1.1.1.1   kleink 	},
     77  1.1.1.1   kleink 
     78  1.1.1.1   kleink 	/* X_fmt */
     79  1.1.1.1   kleink 	"%H:%M:%S",
     80  1.1.1.1   kleink 
     81  1.1.1.1   kleink 	/*
     82  1.1.1.1   kleink 	** x_fmt
     83  1.1.1.1   kleink 	** C99 requires this format.
     84  1.1.1.1   kleink 	** Using just numbers (as here) makes Quakers happier;
     85  1.1.1.1   kleink 	** it's also compatible with SVR4.
     86  1.1.1.1   kleink 	*/
     87  1.1.1.1   kleink 	"%m/%d/%y",
     88  1.1.1.1   kleink 
     89  1.1.1.1   kleink 	/*
     90  1.1.1.1   kleink 	** c_fmt
     91  1.1.1.1   kleink 	** C99 requires this format.
     92  1.1.1.1   kleink 	** Previously this code used "%D %X", but we now conform to C99.
     93  1.1.1.1   kleink 	** Note that
     94  1.1.1.3  mlelstv 	**	"%a %b %d %H:%M:%S %Y"
     95  1.1.1.1   kleink 	** is used by Solaris 2.3.
     96  1.1.1.1   kleink 	*/
     97  1.1.1.1   kleink 	"%a %b %e %T %Y",
     98  1.1.1.1   kleink 
     99  1.1.1.1   kleink 	/* am */
    100  1.1.1.1   kleink 	"AM",
    101  1.1.1.1   kleink 
    102  1.1.1.1   kleink 	/* pm */
    103  1.1.1.1   kleink 	"PM",
    104  1.1.1.1   kleink 
    105  1.1.1.1   kleink 	/* date_fmt */
    106  1.1.1.1   kleink 	"%a %b %e %H:%M:%S %Z %Y"
    107  1.1.1.1   kleink };
    108  1.1.1.1   kleink 
    109  1.1.1.3  mlelstv static char *	_add(const char *, char *, const char *);
    110  1.1.1.3  mlelstv static char *	_conv(int, const char *, char *, const char *);
    111  1.1.1.3  mlelstv static char *	_fmt(const char *, const struct tm *, char *, const char *,
    112  1.1.1.3  mlelstv 			int *);
    113  1.1.1.3  mlelstv static char *	_yconv(int, int, int, int, char *, const char *);
    114  1.1.1.1   kleink 
    115  1.1.1.1   kleink extern char *	tzname[];
    116  1.1.1.1   kleink 
    117  1.1.1.1   kleink #ifndef YEAR_2000_NAME
    118  1.1.1.1   kleink #define YEAR_2000_NAME	"CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
    119  1.1.1.1   kleink #endif /* !defined YEAR_2000_NAME */
    120  1.1.1.1   kleink 
    121  1.1.1.1   kleink #define IN_NONE	0
    122  1.1.1.1   kleink #define IN_SOME	1
    123  1.1.1.1   kleink #define IN_THIS	2
    124  1.1.1.1   kleink #define IN_ALL	3
    125      1.1      mrg 
    126      1.1      mrg size_t
    127      1.1      mrg strftime(s, maxsize, format, t)
    128  1.1.1.1   kleink char * const		s;
    129  1.1.1.1   kleink const size_t		maxsize;
    130  1.1.1.1   kleink const char * const	format;
    131  1.1.1.1   kleink const struct tm * const	t;
    132      1.1      mrg {
    133  1.1.1.1   kleink 	char *	p;
    134  1.1.1.1   kleink 	int	warn;
    135      1.1      mrg 
    136  1.1.1.1   kleink 	tzset();
    137  1.1.1.1   kleink #ifdef LOCALE_HOME
    138  1.1.1.1   kleink 	localebuf.mon[0] = 0;
    139  1.1.1.1   kleink #endif /* defined LOCALE_HOME */
    140  1.1.1.1   kleink 	warn = IN_NONE;
    141  1.1.1.1   kleink 	p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn);
    142  1.1.1.1   kleink #ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
    143  1.1.1.1   kleink 	if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
    144  1.1.1.1   kleink 		(void) fprintf(stderr, "\n");
    145  1.1.1.1   kleink 		if (format == NULL)
    146  1.1.1.1   kleink 			(void) fprintf(stderr, "NULL strftime format ");
    147  1.1.1.1   kleink 		else	(void) fprintf(stderr, "strftime format \"%s\" ",
    148  1.1.1.1   kleink 				format);
    149  1.1.1.1   kleink 		(void) fprintf(stderr, "yields only two digits of years in ");
    150  1.1.1.1   kleink 		if (warn == IN_SOME)
    151  1.1.1.1   kleink 			(void) fprintf(stderr, "some locales");
    152  1.1.1.1   kleink 		else if (warn == IN_THIS)
    153  1.1.1.1   kleink 			(void) fprintf(stderr, "the current locale");
    154  1.1.1.1   kleink 		else	(void) fprintf(stderr, "all locales");
    155  1.1.1.1   kleink 		(void) fprintf(stderr, "\n");
    156      1.1      mrg 	}
    157  1.1.1.1   kleink #endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
    158  1.1.1.1   kleink 	if (p == s + maxsize)
    159  1.1.1.1   kleink 		return 0;
    160  1.1.1.1   kleink 	*p = '\0';
    161  1.1.1.1   kleink 	return p - s;
    162      1.1      mrg }
    163      1.1      mrg 
    164  1.1.1.1   kleink static char *
    165  1.1.1.1   kleink _fmt(format, t, pt, ptlim, warnp)
    166  1.1.1.1   kleink const char *		format;
    167  1.1.1.1   kleink const struct tm * const	t;
    168  1.1.1.1   kleink char *			pt;
    169  1.1.1.1   kleink const char * const	ptlim;
    170  1.1.1.1   kleink int *			warnp;
    171      1.1      mrg {
    172  1.1.1.1   kleink 	for ( ; *format; ++format) {
    173      1.1      mrg 		if (*format == '%') {
    174  1.1.1.1   kleink label:
    175  1.1.1.1   kleink 			switch (*++format) {
    176      1.1      mrg 			case '\0':
    177      1.1      mrg 				--format;
    178      1.1      mrg 				break;
    179      1.1      mrg 			case 'A':
    180  1.1.1.1   kleink 				pt = _add((t->tm_wday < 0 ||
    181  1.1.1.1   kleink 					t->tm_wday >= DAYSPERWEEK) ?
    182  1.1.1.1   kleink 					"?" : Locale->weekday[t->tm_wday],
    183  1.1.1.1   kleink 					pt, ptlim);
    184      1.1      mrg 				continue;
    185      1.1      mrg 			case 'a':
    186  1.1.1.1   kleink 				pt = _add((t->tm_wday < 0 ||
    187  1.1.1.1   kleink 					t->tm_wday >= DAYSPERWEEK) ?
    188  1.1.1.1   kleink 					"?" : Locale->wday[t->tm_wday],
    189  1.1.1.1   kleink 					pt, ptlim);
    190      1.1      mrg 				continue;
    191      1.1      mrg 			case 'B':
    192  1.1.1.1   kleink 				pt = _add((t->tm_mon < 0 ||
    193  1.1.1.1   kleink 					t->tm_mon >= MONSPERYEAR) ?
    194  1.1.1.1   kleink 					"?" : Locale->month[t->tm_mon],
    195  1.1.1.1   kleink 					pt, ptlim);
    196      1.1      mrg 				continue;
    197      1.1      mrg 			case 'b':
    198      1.1      mrg 			case 'h':
    199  1.1.1.1   kleink 				pt = _add((t->tm_mon < 0 ||
    200  1.1.1.1   kleink 					t->tm_mon >= MONSPERYEAR) ?
    201  1.1.1.1   kleink 					"?" : Locale->mon[t->tm_mon],
    202  1.1.1.1   kleink 					pt, ptlim);
    203      1.1      mrg 				continue;
    204      1.1      mrg 			case 'C':
    205  1.1.1.1   kleink 				/*
    206  1.1.1.1   kleink 				** %C used to do a...
    207  1.1.1.1   kleink 				**	_fmt("%a %b %e %X %Y", t);
    208  1.1.1.1   kleink 				** ...whereas now POSIX 1003.2 calls for
    209  1.1.1.1   kleink 				** something completely different.
    210  1.1.1.1   kleink 				** (ado, 1993-05-24)
    211  1.1.1.1   kleink 				*/
    212  1.1.1.3  mlelstv 				pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0,
    213  1.1.1.3  mlelstv 					pt, ptlim);
    214      1.1      mrg 				continue;
    215      1.1      mrg 			case 'c':
    216  1.1.1.1   kleink 				{
    217  1.1.1.1   kleink 				int warn2 = IN_SOME;
    218  1.1.1.1   kleink 
    219  1.1.1.3  mlelstv 				pt = _fmt(Locale->c_fmt, t, pt, ptlim, &warn2);
    220  1.1.1.1   kleink 				if (warn2 == IN_ALL)
    221  1.1.1.1   kleink 					warn2 = IN_THIS;
    222  1.1.1.1   kleink 				if (warn2 > *warnp)
    223  1.1.1.1   kleink 					*warnp = warn2;
    224  1.1.1.1   kleink 				}
    225      1.1      mrg 				continue;
    226      1.1      mrg 			case 'D':
    227  1.1.1.1   kleink 				pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
    228      1.1      mrg 				continue;
    229      1.1      mrg 			case 'd':
    230  1.1.1.1   kleink 				pt = _conv(t->tm_mday, "%02d", pt, ptlim);
    231      1.1      mrg 				continue;
    232  1.1.1.1   kleink 			case 'E':
    233  1.1.1.1   kleink 			case 'O':
    234  1.1.1.1   kleink 				/*
    235  1.1.1.1   kleink 				** C99 locale modifiers.
    236  1.1.1.1   kleink 				** The sequences
    237  1.1.1.1   kleink 				**	%Ec %EC %Ex %EX %Ey %EY
    238  1.1.1.1   kleink 				**	%Od %oe %OH %OI %Om %OM
    239  1.1.1.1   kleink 				**	%OS %Ou %OU %OV %Ow %OW %Oy
    240  1.1.1.1   kleink 				** are supposed to provide alternate
    241  1.1.1.1   kleink 				** representations.
    242  1.1.1.1   kleink 				*/
    243  1.1.1.1   kleink 				goto label;
    244      1.1      mrg 			case 'e':
    245  1.1.1.1   kleink 				pt = _conv(t->tm_mday, "%2d", pt, ptlim);
    246  1.1.1.1   kleink 				continue;
    247  1.1.1.1   kleink 			case 'F':
    248  1.1.1.1   kleink 				pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
    249      1.1      mrg 				continue;
    250      1.1      mrg 			case 'H':
    251  1.1.1.1   kleink 				pt = _conv(t->tm_hour, "%02d", pt, ptlim);
    252      1.1      mrg 				continue;
    253      1.1      mrg 			case 'I':
    254  1.1.1.1   kleink 				pt = _conv((t->tm_hour % 12) ?
    255  1.1.1.1   kleink 					(t->tm_hour % 12) : 12,
    256  1.1.1.1   kleink 					"%02d", pt, ptlim);
    257      1.1      mrg 				continue;
    258      1.1      mrg 			case 'j':
    259  1.1.1.1   kleink 				pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim);
    260      1.1      mrg 				continue;
    261      1.1      mrg 			case 'k':
    262  1.1.1.1   kleink 				/*
    263  1.1.1.1   kleink 				** This used to be...
    264  1.1.1.1   kleink 				**	_conv(t->tm_hour % 12 ?
    265  1.1.1.1   kleink 				**		t->tm_hour % 12 : 12, 2, ' ');
    266  1.1.1.1   kleink 				** ...and has been changed to the below to
    267  1.1.1.1   kleink 				** match SunOS 4.1.1 and Arnold Robbins'
    268  1.1.1.3  mlelstv 				** strftime version 3.0. That is, "%k" and
    269  1.1.1.1   kleink 				** "%l" have been swapped.
    270  1.1.1.1   kleink 				** (ado, 1993-05-24)
    271  1.1.1.1   kleink 				*/
    272  1.1.1.1   kleink 				pt = _conv(t->tm_hour, "%2d", pt, ptlim);
    273  1.1.1.1   kleink 				continue;
    274  1.1.1.1   kleink #ifdef KITCHEN_SINK
    275  1.1.1.1   kleink 			case 'K':
    276  1.1.1.1   kleink 				/*
    277  1.1.1.1   kleink 				** After all this time, still unclaimed!
    278  1.1.1.1   kleink 				*/
    279  1.1.1.1   kleink 				pt = _add("kitchen sink", pt, ptlim);
    280      1.1      mrg 				continue;
    281  1.1.1.1   kleink #endif /* defined KITCHEN_SINK */
    282      1.1      mrg 			case 'l':
    283  1.1.1.1   kleink 				/*
    284  1.1.1.1   kleink 				** This used to be...
    285  1.1.1.1   kleink 				**	_conv(t->tm_hour, 2, ' ');
    286  1.1.1.1   kleink 				** ...and has been changed to the below to
    287  1.1.1.1   kleink 				** match SunOS 4.1.1 and Arnold Robbin's
    288  1.1.1.3  mlelstv 				** strftime version 3.0. That is, "%k" and
    289  1.1.1.1   kleink 				** "%l" have been swapped.
    290  1.1.1.1   kleink 				** (ado, 1993-05-24)
    291  1.1.1.1   kleink 				*/
    292  1.1.1.1   kleink 				pt = _conv((t->tm_hour % 12) ?
    293  1.1.1.1   kleink 					(t->tm_hour % 12) : 12,
    294  1.1.1.1   kleink 					"%2d", pt, ptlim);
    295      1.1      mrg 				continue;
    296      1.1      mrg 			case 'M':
    297  1.1.1.1   kleink 				pt = _conv(t->tm_min, "%02d", pt, ptlim);
    298      1.1      mrg 				continue;
    299      1.1      mrg 			case 'm':
    300  1.1.1.1   kleink 				pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim);
    301      1.1      mrg 				continue;
    302      1.1      mrg 			case 'n':
    303  1.1.1.1   kleink 				pt = _add("\n", pt, ptlim);
    304      1.1      mrg 				continue;
    305      1.1      mrg 			case 'p':
    306  1.1.1.1   kleink 				pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
    307  1.1.1.1   kleink 					Locale->pm :
    308  1.1.1.1   kleink 					Locale->am,
    309  1.1.1.1   kleink 					pt, ptlim);
    310      1.1      mrg 				continue;
    311      1.1      mrg 			case 'R':
    312  1.1.1.1   kleink 				pt = _fmt("%H:%M", t, pt, ptlim, warnp);
    313      1.1      mrg 				continue;
    314      1.1      mrg 			case 'r':
    315  1.1.1.1   kleink 				pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp);
    316      1.1      mrg 				continue;
    317      1.1      mrg 			case 'S':
    318  1.1.1.1   kleink 				pt = _conv(t->tm_sec, "%02d", pt, ptlim);
    319      1.1      mrg 				continue;
    320      1.1      mrg 			case 's':
    321  1.1.1.1   kleink 				{
    322  1.1.1.1   kleink 					struct tm	tm;
    323  1.1.1.1   kleink 					char		buf[INT_STRLEN_MAXIMUM(
    324  1.1.1.1   kleink 								time_t) + 1];
    325  1.1.1.1   kleink 					time_t		mkt;
    326  1.1.1.1   kleink 
    327  1.1.1.1   kleink 					tm = *t;
    328  1.1.1.1   kleink 					mkt = mktime(&tm);
    329  1.1.1.1   kleink 					if (TYPE_SIGNED(time_t))
    330  1.1.1.1   kleink 						(void) sprintf(buf, "%ld",
    331  1.1.1.1   kleink 							(long) mkt);
    332  1.1.1.1   kleink 					else	(void) sprintf(buf, "%lu",
    333  1.1.1.1   kleink 							(unsigned long) mkt);
    334  1.1.1.1   kleink 					pt = _add(buf, pt, ptlim);
    335  1.1.1.1   kleink 				}
    336      1.1      mrg 				continue;
    337      1.1      mrg 			case 'T':
    338  1.1.1.1   kleink 				pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp);
    339      1.1      mrg 				continue;
    340      1.1      mrg 			case 't':
    341  1.1.1.1   kleink 				pt = _add("\t", pt, ptlim);
    342      1.1      mrg 				continue;
    343      1.1      mrg 			case 'U':
    344  1.1.1.1   kleink 				pt = _conv((t->tm_yday + DAYSPERWEEK -
    345  1.1.1.1   kleink 					t->tm_wday) / DAYSPERWEEK,
    346  1.1.1.1   kleink 					"%02d", pt, ptlim);
    347      1.1      mrg 				continue;
    348      1.1      mrg 			case 'u':
    349  1.1.1.1   kleink 				/*
    350  1.1.1.1   kleink 				** From Arnold Robbins' strftime version 3.0:
    351  1.1.1.1   kleink 				** "ISO 8601: Weekday as a decimal number
    352  1.1.1.1   kleink 				** [1 (Monday) - 7]"
    353  1.1.1.1   kleink 				** (ado, 1993-05-24)
    354  1.1.1.1   kleink 				*/
    355  1.1.1.1   kleink 				pt = _conv((t->tm_wday == 0) ?
    356  1.1.1.1   kleink 					DAYSPERWEEK : t->tm_wday,
    357  1.1.1.1   kleink 					"%d", pt, ptlim);
    358  1.1.1.1   kleink 				continue;
    359  1.1.1.1   kleink 			case 'V':	/* ISO 8601 week number */
    360  1.1.1.1   kleink 			case 'G':	/* ISO 8601 year (four digits) */
    361  1.1.1.1   kleink 			case 'g':	/* ISO 8601 year (two digits) */
    362  1.1.1.1   kleink /*
    363  1.1.1.3  mlelstv ** From Arnold Robbins' strftime version 3.0: "the week number of the
    364  1.1.1.1   kleink ** year (the first Monday as the first day of week 1) as a decimal number
    365  1.1.1.1   kleink ** (01-53)."
    366  1.1.1.1   kleink ** (ado, 1993-05-24)
    367  1.1.1.1   kleink **
    368  1.1.1.1   kleink ** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
    369  1.1.1.1   kleink ** "Week 01 of a year is per definition the first week which has the
    370  1.1.1.1   kleink ** Thursday in this year, which is equivalent to the week which contains
    371  1.1.1.1   kleink ** the fourth day of January. In other words, the first week of a new year
    372  1.1.1.1   kleink ** is the week which has the majority of its days in the new year. Week 01
    373  1.1.1.1   kleink ** might also contain days from the previous year and the week before week
    374  1.1.1.1   kleink ** 01 of a year is the last week (52 or 53) of the previous year even if
    375  1.1.1.1   kleink ** it contains days from the new year. A week starts with Monday (day 1)
    376  1.1.1.3  mlelstv ** and ends with Sunday (day 7). For example, the first week of the year
    377  1.1.1.1   kleink ** 1997 lasts from 1996-12-30 to 1997-01-05..."
    378  1.1.1.1   kleink ** (ado, 1996-01-02)
    379  1.1.1.1   kleink */
    380      1.1      mrg 				{
    381  1.1.1.1   kleink 					int	year;
    382  1.1.1.3  mlelstv 					int	base;
    383  1.1.1.1   kleink 					int	yday;
    384  1.1.1.1   kleink 					int	wday;
    385  1.1.1.1   kleink 					int	w;
    386  1.1.1.1   kleink 
    387  1.1.1.3  mlelstv 					year = t->tm_year;
    388  1.1.1.3  mlelstv 					base = TM_YEAR_BASE;
    389  1.1.1.1   kleink 					yday = t->tm_yday;
    390  1.1.1.1   kleink 					wday = t->tm_wday;
    391  1.1.1.1   kleink 					for ( ; ; ) {
    392  1.1.1.1   kleink 						int	len;
    393  1.1.1.1   kleink 						int	bot;
    394  1.1.1.1   kleink 						int	top;
    395  1.1.1.1   kleink 
    396  1.1.1.3  mlelstv 						len = isleap_sum(year, base) ?
    397  1.1.1.1   kleink 							DAYSPERLYEAR :
    398  1.1.1.1   kleink 							DAYSPERNYEAR;
    399  1.1.1.1   kleink 						/*
    400  1.1.1.1   kleink 						** What yday (-3 ... 3) does
    401  1.1.1.1   kleink 						** the ISO year begin on?
    402  1.1.1.1   kleink 						*/
    403  1.1.1.1   kleink 						bot = ((yday + 11 - wday) %
    404  1.1.1.1   kleink 							DAYSPERWEEK) - 3;
    405  1.1.1.1   kleink 						/*
    406  1.1.1.1   kleink 						** What yday does the NEXT
    407  1.1.1.1   kleink 						** ISO year begin on?
    408  1.1.1.1   kleink 						*/
    409  1.1.1.1   kleink 						top = bot -
    410  1.1.1.1   kleink 							(len % DAYSPERWEEK);
    411  1.1.1.1   kleink 						if (top < -3)
    412  1.1.1.1   kleink 							top += DAYSPERWEEK;
    413  1.1.1.1   kleink 						top += len;
    414  1.1.1.1   kleink 						if (yday >= top) {
    415  1.1.1.3  mlelstv 							++base;
    416  1.1.1.1   kleink 							w = 1;
    417  1.1.1.1   kleink 							break;
    418  1.1.1.1   kleink 						}
    419  1.1.1.1   kleink 						if (yday >= bot) {
    420  1.1.1.1   kleink 							w = 1 + ((yday - bot) /
    421  1.1.1.1   kleink 								DAYSPERWEEK);
    422  1.1.1.1   kleink 							break;
    423  1.1.1.1   kleink 						}
    424  1.1.1.3  mlelstv 						--base;
    425  1.1.1.3  mlelstv 						yday += isleap_sum(year, base) ?
    426  1.1.1.1   kleink 							DAYSPERLYEAR :
    427  1.1.1.1   kleink 							DAYSPERNYEAR;
    428  1.1.1.1   kleink 					}
    429  1.1.1.1   kleink #ifdef XPG4_1994_04_09
    430  1.1.1.3  mlelstv 					if ((w == 52 &&
    431  1.1.1.3  mlelstv 						t->tm_mon == TM_JANUARY) ||
    432  1.1.1.3  mlelstv 						(w == 1 &&
    433  1.1.1.3  mlelstv 						t->tm_mon == TM_DECEMBER))
    434  1.1.1.3  mlelstv 							w = 53;
    435  1.1.1.1   kleink #endif /* defined XPG4_1994_04_09 */
    436  1.1.1.1   kleink 					if (*format == 'V')
    437  1.1.1.1   kleink 						pt = _conv(w, "%02d",
    438  1.1.1.1   kleink 							pt, ptlim);
    439  1.1.1.1   kleink 					else if (*format == 'g') {
    440  1.1.1.1   kleink 						*warnp = IN_ALL;
    441  1.1.1.3  mlelstv 						pt = _yconv(year, base, 0, 1,
    442  1.1.1.1   kleink 							pt, ptlim);
    443  1.1.1.3  mlelstv 					} else	pt = _yconv(year, base, 1, 1,
    444  1.1.1.1   kleink 							pt, ptlim);
    445      1.1      mrg 				}
    446      1.1      mrg 				continue;
    447  1.1.1.1   kleink 			case 'v':
    448  1.1.1.1   kleink 				/*
    449  1.1.1.1   kleink 				** From Arnold Robbins' strftime version 3.0:
    450  1.1.1.1   kleink 				** "date as dd-bbb-YYYY"
    451  1.1.1.1   kleink 				** (ado, 1993-05-24)
    452  1.1.1.1   kleink 				*/
    453  1.1.1.1   kleink 				pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp);
    454  1.1.1.1   kleink 				continue;
    455      1.1      mrg 			case 'W':
    456  1.1.1.1   kleink 				pt = _conv((t->tm_yday + DAYSPERWEEK -
    457  1.1.1.1   kleink 					(t->tm_wday ?
    458  1.1.1.1   kleink 					(t->tm_wday - 1) :
    459  1.1.1.1   kleink 					(DAYSPERWEEK - 1))) / DAYSPERWEEK,
    460  1.1.1.1   kleink 					"%02d", pt, ptlim);
    461      1.1      mrg 				continue;
    462      1.1      mrg 			case 'w':
    463  1.1.1.1   kleink 				pt = _conv(t->tm_wday, "%d", pt, ptlim);
    464      1.1      mrg 				continue;
    465      1.1      mrg 			case 'X':
    466  1.1.1.1   kleink 				pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp);
    467  1.1.1.1   kleink 				continue;
    468  1.1.1.1   kleink 			case 'x':
    469  1.1.1.1   kleink 				{
    470  1.1.1.1   kleink 				int	warn2 = IN_SOME;
    471  1.1.1.1   kleink 
    472  1.1.1.1   kleink 				pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2);
    473  1.1.1.1   kleink 				if (warn2 == IN_ALL)
    474  1.1.1.1   kleink 					warn2 = IN_THIS;
    475  1.1.1.1   kleink 				if (warn2 > *warnp)
    476  1.1.1.1   kleink 					*warnp = warn2;
    477  1.1.1.1   kleink 				}
    478      1.1      mrg 				continue;
    479      1.1      mrg 			case 'y':
    480  1.1.1.1   kleink 				*warnp = IN_ALL;
    481  1.1.1.3  mlelstv 				pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
    482  1.1.1.3  mlelstv 					pt, ptlim);
    483      1.1      mrg 				continue;
    484      1.1      mrg 			case 'Y':
    485  1.1.1.3  mlelstv 				pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,
    486  1.1.1.1   kleink 					pt, ptlim);
    487      1.1      mrg 				continue;
    488      1.1      mrg 			case 'Z':
    489  1.1.1.1   kleink #ifdef TM_ZONE
    490  1.1.1.1   kleink 				if (t->TM_ZONE != NULL)
    491  1.1.1.1   kleink 					pt = _add(t->TM_ZONE, pt, ptlim);
    492  1.1.1.1   kleink 				else
    493  1.1.1.1   kleink #endif /* defined TM_ZONE */
    494  1.1.1.1   kleink 				if (t->tm_isdst >= 0)
    495  1.1.1.1   kleink 					pt = _add(tzname[t->tm_isdst != 0],
    496  1.1.1.1   kleink 						pt, ptlim);
    497  1.1.1.1   kleink 				/*
    498  1.1.1.1   kleink 				** C99 says that %Z must be replaced by the
    499  1.1.1.1   kleink 				** empty string if the time zone is not
    500  1.1.1.1   kleink 				** determinable.
    501  1.1.1.1   kleink 				*/
    502  1.1.1.1   kleink 				continue;
    503  1.1.1.1   kleink 			case 'z':
    504  1.1.1.1   kleink 				{
    505  1.1.1.1   kleink 				int		diff;
    506  1.1.1.1   kleink 				char const *	sign;
    507  1.1.1.1   kleink 
    508  1.1.1.1   kleink 				if (t->tm_isdst < 0)
    509  1.1.1.1   kleink 					continue;
    510  1.1.1.1   kleink #ifdef TM_GMTOFF
    511  1.1.1.1   kleink 				diff = t->TM_GMTOFF;
    512  1.1.1.1   kleink #else /* !defined TM_GMTOFF */
    513  1.1.1.1   kleink 				/*
    514  1.1.1.1   kleink 				** C99 says that the UTC offset must
    515  1.1.1.1   kleink 				** be computed by looking only at
    516  1.1.1.3  mlelstv 				** tm_isdst. This requirement is
    517  1.1.1.1   kleink 				** incorrect, since it means the code
    518  1.1.1.1   kleink 				** must rely on magic (in this case
    519  1.1.1.1   kleink 				** altzone and timezone), and the
    520  1.1.1.1   kleink 				** magic might not have the correct
    521  1.1.1.3  mlelstv 				** offset. Doing things correctly is
    522  1.1.1.1   kleink 				** tricky and requires disobeying C99;
    523  1.1.1.1   kleink 				** see GNU C strftime for details.
    524  1.1.1.1   kleink 				** For now, punt and conform to the
    525  1.1.1.1   kleink 				** standard, even though it's incorrect.
    526  1.1.1.1   kleink 				**
    527  1.1.1.1   kleink 				** C99 says that %z must be replaced by the
    528  1.1.1.1   kleink 				** empty string if the time zone is not
    529  1.1.1.1   kleink 				** determinable, so output nothing if the
    530  1.1.1.1   kleink 				** appropriate variables are not available.
    531  1.1.1.1   kleink 				*/
    532  1.1.1.1   kleink 				if (t->tm_isdst == 0)
    533  1.1.1.1   kleink #ifdef USG_COMPAT
    534  1.1.1.1   kleink 					diff = -timezone;
    535  1.1.1.2   kleink #else /* !defined USG_COMPAT */
    536  1.1.1.1   kleink 					continue;
    537  1.1.1.1   kleink #endif /* !defined USG_COMPAT */
    538  1.1.1.1   kleink 				else
    539  1.1.1.1   kleink #ifdef ALTZONE
    540  1.1.1.1   kleink 					diff = -altzone;
    541  1.1.1.1   kleink #else /* !defined ALTZONE */
    542  1.1.1.1   kleink 					continue;
    543  1.1.1.1   kleink #endif /* !defined ALTZONE */
    544  1.1.1.1   kleink #endif /* !defined TM_GMTOFF */
    545  1.1.1.1   kleink 				if (diff < 0) {
    546  1.1.1.1   kleink 					sign = "-";
    547  1.1.1.1   kleink 					diff = -diff;
    548  1.1.1.1   kleink 				} else	sign = "+";
    549  1.1.1.1   kleink 				pt = _add(sign, pt, ptlim);
    550  1.1.1.3  mlelstv 				diff /= SECSPERMIN;
    551  1.1.1.3  mlelstv 				diff = (diff / MINSPERHOUR) * 100 +
    552  1.1.1.3  mlelstv 					(diff % MINSPERHOUR);
    553  1.1.1.3  mlelstv 				pt = _conv(diff, "%04d", pt, ptlim);
    554  1.1.1.1   kleink 				}
    555  1.1.1.1   kleink 				continue;
    556  1.1.1.1   kleink 			case '+':
    557  1.1.1.1   kleink 				pt = _fmt(Locale->date_fmt, t, pt, ptlim,
    558  1.1.1.1   kleink 					warnp);
    559      1.1      mrg 				continue;
    560      1.1      mrg 			case '%':
    561      1.1      mrg 			/*
    562  1.1.1.1   kleink 			** X311J/88-090 (4.12.3.5): if conversion char is
    563  1.1.1.3  mlelstv 			** undefined, behavior is undefined. Print out the
    564  1.1.1.1   kleink 			** character itself as printf(3) also does.
    565  1.1.1.1   kleink 			*/
    566      1.1      mrg 			default:
    567      1.1      mrg 				break;
    568      1.1      mrg 			}
    569      1.1      mrg 		}
    570  1.1.1.1   kleink 		if (pt == ptlim)
    571  1.1.1.1   kleink 			break;
    572      1.1      mrg 		*pt++ = *format;
    573      1.1      mrg 	}
    574  1.1.1.1   kleink 	return pt;
    575      1.1      mrg }
    576      1.1      mrg 
    577  1.1.1.1   kleink static char *
    578  1.1.1.1   kleink _conv(n, format, pt, ptlim)
    579  1.1.1.1   kleink const int		n;
    580  1.1.1.1   kleink const char * const	format;
    581  1.1.1.1   kleink char * const		pt;
    582  1.1.1.1   kleink const char * const	ptlim;
    583      1.1      mrg {
    584  1.1.1.1   kleink 	char	buf[INT_STRLEN_MAXIMUM(int) + 1];
    585  1.1.1.1   kleink 
    586  1.1.1.1   kleink 	(void) sprintf(buf, format, n);
    587  1.1.1.1   kleink 	return _add(buf, pt, ptlim);
    588      1.1      mrg }
    589      1.1      mrg 
    590  1.1.1.1   kleink static char *
    591  1.1.1.1   kleink _add(str, pt, ptlim)
    592  1.1.1.1   kleink const char *		str;
    593  1.1.1.1   kleink char *			pt;
    594  1.1.1.1   kleink const char * const	ptlim;
    595      1.1      mrg {
    596  1.1.1.1   kleink 	while (pt < ptlim && (*pt = *str++) != '\0')
    597  1.1.1.1   kleink 		++pt;
    598  1.1.1.1   kleink 	return pt;
    599      1.1      mrg }
    600      1.1      mrg 
    601  1.1.1.3  mlelstv /*
    602  1.1.1.3  mlelstv ** POSIX and the C Standard are unclear or inconsistent about
    603  1.1.1.3  mlelstv ** what %C and %y do if the year is negative or exceeds 9999.
    604  1.1.1.3  mlelstv ** Use the convention that %C concatenated with %y yields the
    605  1.1.1.3  mlelstv ** same output as %Y, and that %Y contains at least 4 bytes,
    606  1.1.1.3  mlelstv ** with more only if necessary.
    607  1.1.1.3  mlelstv */
    608  1.1.1.3  mlelstv 
    609  1.1.1.3  mlelstv static char *
    610  1.1.1.3  mlelstv _yconv(a, b, convert_top, convert_yy, pt, ptlim)
    611  1.1.1.3  mlelstv const int		a;
    612  1.1.1.3  mlelstv const int		b;
    613  1.1.1.3  mlelstv const int		convert_top;
    614  1.1.1.3  mlelstv const int		convert_yy;
    615  1.1.1.3  mlelstv char *			pt;
    616  1.1.1.3  mlelstv const char * const	ptlim;
    617  1.1.1.3  mlelstv {
    618  1.1.1.3  mlelstv 	register int	lead;
    619  1.1.1.3  mlelstv 	register int	trail;
    620  1.1.1.3  mlelstv 
    621  1.1.1.3  mlelstv #define DIVISOR	100
    622  1.1.1.3  mlelstv 	trail = a % DIVISOR + b % DIVISOR;
    623  1.1.1.3  mlelstv 	lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR;
    624  1.1.1.3  mlelstv 	trail %= DIVISOR;
    625  1.1.1.3  mlelstv 	if (trail < 0 && lead > 0) {
    626  1.1.1.3  mlelstv 		trail += DIVISOR;
    627  1.1.1.3  mlelstv 		--lead;
    628  1.1.1.3  mlelstv 	} else if (lead < 0 && trail > 0) {
    629  1.1.1.3  mlelstv 		trail -= DIVISOR;
    630  1.1.1.3  mlelstv 		++lead;
    631  1.1.1.3  mlelstv 	}
    632  1.1.1.3  mlelstv 	if (convert_top) {
    633  1.1.1.3  mlelstv 		if (lead == 0 && trail < 0)
    634  1.1.1.3  mlelstv 			pt = _add("-0", pt, ptlim);
    635  1.1.1.3  mlelstv 		else	pt = _conv(lead, "%02d", pt, ptlim);
    636  1.1.1.3  mlelstv 	}
    637  1.1.1.3  mlelstv 	if (convert_yy)
    638  1.1.1.3  mlelstv 		pt = _conv(((trail < 0) ? -trail : trail), "%02d", pt, ptlim);
    639  1.1.1.3  mlelstv 	return pt;
    640  1.1.1.3  mlelstv }
    641  1.1.1.3  mlelstv 
    642  1.1.1.1   kleink #ifdef LOCALE_HOME
    643  1.1.1.1   kleink static struct lc_time_T *
    644  1.1.1.3  mlelstv _loc(void)
    645      1.1      mrg {
    646  1.1.1.1   kleink 	static const char	locale_home[] = LOCALE_HOME;
    647  1.1.1.1   kleink 	static const char	lc_time[] = "LC_TIME";
    648  1.1.1.1   kleink 	static char *		locale_buf;
    649  1.1.1.1   kleink 
    650  1.1.1.1   kleink 	int			fd;
    651  1.1.1.1   kleink 	int			oldsun;	/* "...ain't got nothin' to do..." */
    652  1.1.1.1   kleink 	char *			lbuf;
    653  1.1.1.1   kleink 	char *			name;
    654  1.1.1.1   kleink 	char *			p;
    655  1.1.1.1   kleink 	const char **		ap;
    656  1.1.1.1   kleink 	const char *		plim;
    657  1.1.1.1   kleink 	char			filename[FILENAME_MAX];
    658  1.1.1.1   kleink 	struct stat		st;
    659  1.1.1.1   kleink 	size_t			namesize;
    660  1.1.1.1   kleink 	size_t			bufsize;
    661  1.1.1.1   kleink 
    662  1.1.1.1   kleink 	/*
    663  1.1.1.1   kleink 	** Use localebuf.mon[0] to signal whether locale is already set up.
    664  1.1.1.1   kleink 	*/
    665  1.1.1.1   kleink 	if (localebuf.mon[0])
    666  1.1.1.1   kleink 		return &localebuf;
    667  1.1.1.1   kleink 	name = setlocale(LC_TIME, (char *) NULL);
    668  1.1.1.1   kleink 	if (name == NULL || *name == '\0')
    669  1.1.1.1   kleink 		goto no_locale;
    670  1.1.1.1   kleink 	/*
    671  1.1.1.1   kleink 	** If the locale name is the same as our cache, use the cache.
    672  1.1.1.1   kleink 	*/
    673  1.1.1.1   kleink 	lbuf = locale_buf;
    674  1.1.1.1   kleink 	if (lbuf != NULL && strcmp(name, lbuf) == 0) {
    675  1.1.1.1   kleink 		p = lbuf;
    676  1.1.1.1   kleink 		for (ap = (const char **) &localebuf;
    677  1.1.1.1   kleink 			ap < (const char **) (&localebuf + 1);
    678  1.1.1.1   kleink 				++ap)
    679  1.1.1.1   kleink 					*ap = p += strlen(p) + 1;
    680  1.1.1.1   kleink 		return &localebuf;
    681  1.1.1.1   kleink 	}
    682  1.1.1.1   kleink 	/*
    683  1.1.1.1   kleink 	** Slurp the locale file into the cache.
    684  1.1.1.1   kleink 	*/
    685  1.1.1.1   kleink 	namesize = strlen(name) + 1;
    686  1.1.1.3  mlelstv 	if (sizeof filename <
    687  1.1.1.2   kleink 		((sizeof locale_home) + namesize + (sizeof lc_time)))
    688  1.1.1.1   kleink 			goto no_locale;
    689  1.1.1.1   kleink 	oldsun = 0;
    690  1.1.1.1   kleink 	(void) sprintf(filename, "%s/%s/%s", locale_home, name, lc_time);
    691  1.1.1.1   kleink 	fd = open(filename, O_RDONLY);
    692  1.1.1.1   kleink 	if (fd < 0) {
    693  1.1.1.1   kleink 		/*
    694  1.1.1.1   kleink 		** Old Sun systems have a different naming and data convention.
    695  1.1.1.1   kleink 		*/
    696  1.1.1.1   kleink 		oldsun = 1;
    697  1.1.1.1   kleink 		(void) sprintf(filename, "%s/%s/%s", locale_home,
    698  1.1.1.1   kleink 			lc_time, name);
    699  1.1.1.1   kleink 		fd = open(filename, O_RDONLY);
    700  1.1.1.1   kleink 		if (fd < 0)
    701  1.1.1.1   kleink 			goto no_locale;
    702  1.1.1.1   kleink 	}
    703  1.1.1.1   kleink 	if (fstat(fd, &st) != 0)
    704  1.1.1.1   kleink 		goto bad_locale;
    705  1.1.1.1   kleink 	if (st.st_size <= 0)
    706  1.1.1.1   kleink 		goto bad_locale;
    707  1.1.1.1   kleink 	bufsize = namesize + st.st_size;
    708  1.1.1.1   kleink 	locale_buf = NULL;
    709  1.1.1.3  mlelstv 	lbuf = (lbuf == NULL) ? malloc(bufsize) : realloc(lbuf, bufsize);
    710  1.1.1.1   kleink 	if (lbuf == NULL)
    711  1.1.1.1   kleink 		goto bad_locale;
    712  1.1.1.1   kleink 	(void) strcpy(lbuf, name);
    713  1.1.1.1   kleink 	p = lbuf + namesize;
    714  1.1.1.1   kleink 	plim = p + st.st_size;
    715  1.1.1.1   kleink 	if (read(fd, p, (size_t) st.st_size) != st.st_size)
    716  1.1.1.1   kleink 		goto bad_lbuf;
    717  1.1.1.1   kleink 	if (close(fd) != 0)
    718  1.1.1.1   kleink 		goto bad_lbuf;
    719  1.1.1.1   kleink 	/*
    720  1.1.1.1   kleink 	** Parse the locale file into localebuf.
    721  1.1.1.1   kleink 	*/
    722  1.1.1.1   kleink 	if (plim[-1] != '\n')
    723  1.1.1.1   kleink 		goto bad_lbuf;
    724  1.1.1.1   kleink 	for (ap = (const char **) &localebuf;
    725  1.1.1.1   kleink 		ap < (const char **) (&localebuf + 1);
    726  1.1.1.1   kleink 			++ap) {
    727  1.1.1.1   kleink 				if (p == plim)
    728  1.1.1.1   kleink 					goto bad_lbuf;
    729  1.1.1.1   kleink 				*ap = p;
    730  1.1.1.1   kleink 				while (*p != '\n')
    731  1.1.1.1   kleink 					++p;
    732  1.1.1.1   kleink 				*p++ = '\0';
    733  1.1.1.1   kleink 	}
    734  1.1.1.1   kleink 	if (oldsun) {
    735  1.1.1.1   kleink 		/*
    736  1.1.1.1   kleink 		** SunOS 4 used an obsolescent format; see localdtconv(3).
    737  1.1.1.1   kleink 		** c_fmt had the ``short format for dates and times together''
    738  1.1.1.1   kleink 		** (SunOS 4 date, "%a %b %e %T %Z %Y" in the C locale);
    739  1.1.1.1   kleink 		** date_fmt had the ``long format for dates''
    740  1.1.1.1   kleink 		** (SunOS 4 strftime %C, "%A, %B %e, %Y" in the C locale).
    741  1.1.1.1   kleink 		** Discard the latter in favor of the former.
    742  1.1.1.1   kleink 		*/
    743  1.1.1.1   kleink 		localebuf.date_fmt = localebuf.c_fmt;
    744      1.1      mrg 	}
    745  1.1.1.1   kleink 	/*
    746  1.1.1.1   kleink 	** Record the successful parse in the cache.
    747  1.1.1.1   kleink 	*/
    748  1.1.1.1   kleink 	locale_buf = lbuf;
    749  1.1.1.1   kleink 
    750  1.1.1.1   kleink 	return &localebuf;
    751  1.1.1.1   kleink 
    752  1.1.1.1   kleink bad_lbuf:
    753  1.1.1.1   kleink 	free(lbuf);
    754  1.1.1.1   kleink bad_locale:
    755  1.1.1.1   kleink 	(void) close(fd);
    756  1.1.1.1   kleink no_locale:
    757  1.1.1.1   kleink 	localebuf = C_time_locale;
    758  1.1.1.2   kleink 	locale_buf = NULL;
    759  1.1.1.1   kleink 	return &localebuf;
    760      1.1      mrg }
    761  1.1.1.1   kleink #endif /* defined LOCALE_HOME */
    762