mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	 798ff850e4
			
		
	
	
		798ff850e4
		
	
	
	
	
		
			
			* include/ruby/missing.h (struct timeval): check HAVE_STRUCT_TIMEVAL properly. and don't include sys/time.h if struct timeval exist. * file.c: include sys/time.h explicitly. * random.c: ditto. * thread_pthread.c: ditto. * time.c: ditto. * ext/date/date_strftime.c: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@39772 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
			
				
	
	
		
			633 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			633 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|   date_strftime.c: based on a public-domain implementation of ANSI C
 | |
|   library routine strftime, which is originally written by Arnold
 | |
|   Robbins.
 | |
|  */
 | |
| 
 | |
| #include "ruby/ruby.h"
 | |
| #include "date_tmx.h"
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <ctype.h>
 | |
| #include <errno.h>
 | |
| 
 | |
| #if defined(HAVE_SYS_TIME_H)
 | |
| #include <sys/time.h>
 | |
| #endif
 | |
| 
 | |
| #undef strchr	/* avoid AIX weirdness */
 | |
| 
 | |
| #define range(low, item, hi)	(item)
 | |
| 
 | |
| #define add(x,y) (rb_funcall((x), '+', 1, (y)))
 | |
| #define sub(x,y) (rb_funcall((x), '-', 1, (y)))
 | |
| #define mul(x,y) (rb_funcall((x), '*', 1, (y)))
 | |
| #define quo(x,y) (rb_funcall((x), rb_intern("quo"), 1, (y)))
 | |
| #define div(x,y) (rb_funcall((x), rb_intern("div"), 1, (y)))
 | |
| #define mod(x,y) (rb_funcall((x), '%', 1, (y)))
 | |
| 
 | |
| static void
 | |
| upcase(char *s, size_t i)
 | |
| {
 | |
|     do {
 | |
| 	if (ISLOWER(*s))
 | |
| 	    *s = TOUPPER(*s);
 | |
|     } while (s++, --i);
 | |
| }
 | |
| 
 | |
| static void
 | |
| downcase(char *s, size_t i)
 | |
| {
 | |
|     do {
 | |
| 	if (ISUPPER(*s))
 | |
| 	    *s = TOLOWER(*s);
 | |
|     } while (s++, --i);
 | |
| }
 | |
| 
 | |
| /* strftime --- produce formatted time */
 | |
| 
 | |
| static size_t
 | |
| date_strftime_with_tmx(char *s, size_t maxsize, const char *format,
 | |
| 		       const struct tmx *tmx)
 | |
| {
 | |
|     char *endp = s + maxsize;
 | |
|     char *start = s;
 | |
|     const char *sp, *tp;
 | |
|     auto char tbuf[100];
 | |
|     ptrdiff_t i;
 | |
|     int v, w;
 | |
|     size_t colons;
 | |
|     int precision, flags;
 | |
|     char padding;
 | |
|     /* LOCALE_[OE] and COLONS are actually modifiers, not flags */
 | |
|     enum {LEFT, CHCASE, LOWER, UPPER, LOCALE_O, LOCALE_E, COLONS};
 | |
| #define BIT_OF(n) (1U<<(n))
 | |
| 
 | |
|     /* various tables for locale C */
 | |
|     static const char days_l[][10] = {
 | |
| 	"Sunday", "Monday", "Tuesday", "Wednesday",
 | |
| 	"Thursday", "Friday", "Saturday",
 | |
|     };
 | |
|     static const char months_l[][10] = {
 | |
| 	"January", "February", "March", "April",
 | |
| 	"May", "June", "July", "August", "September",
 | |
| 	"October", "November", "December",
 | |
|     };
 | |
|     static const char ampm[][3] = { "AM", "PM", };
 | |
| 
 | |
|     if (s == NULL || format == NULL || tmx == NULL || maxsize == 0)
 | |
| 	return 0;
 | |
| 
 | |
|     /* quick check if we even need to bother */
 | |
|     if (strchr(format, '%') == NULL && strlen(format) + 1 >= maxsize) {
 | |
|       err:
 | |
| 	errno = ERANGE;
 | |
| 	return 0;
 | |
|     }
 | |
| 
 | |
|     for (; *format && s < endp - 1; format++) {
 | |
| #define FLAG_FOUND() do {						\
 | |
| 	    if (precision > 0 || flags & (BIT_OF(LOCALE_E) | BIT_OF(LOCALE_O) | BIT_OF(COLONS))) \
 | |
| 		goto unknown;						\
 | |
| 	} while (0)
 | |
| #define NEEDS(n) do if (s >= endp || (n) >= endp - s - 1) goto err; while (0)
 | |
| #define FILL_PADDING(i) do {						\
 | |
| 	    if (!(flags & BIT_OF(LEFT)) && precision > (i)) {		\
 | |
| 		NEEDS(precision);					\
 | |
| 		memset(s, padding ? padding : ' ', precision - (i));	\
 | |
| 		s += precision - (i);					\
 | |
| 	    }								\
 | |
| 	    else {							\
 | |
| 		NEEDS(i);						\
 | |
| 	    }								\
 | |
| 	} while (0);
 | |
| #define FMT(def_pad, def_prec, fmt, val)				\
 | |
| 	do {								\
 | |
| 	    int l;							\
 | |
| 	    if (precision <= 0) precision = (def_prec);			\
 | |
| 	    if (flags & BIT_OF(LEFT)) precision = 1;			\
 | |
| 	    l = snprintf(s, endp - s,					\
 | |
| 			 ((padding == '0' || (!padding && (def_pad) == '0')) ? \
 | |
| 			  "%0*"fmt : "%*"fmt),				\
 | |
| 			 precision, (val));				\
 | |
| 	    if (l < 0) goto err;					\
 | |
| 	    s += l;							\
 | |
| 	} while (0)
 | |
| #define STRFTIME(fmt)							\
 | |
| 	do {								\
 | |
| 	    i = date_strftime_with_tmx(s, endp - s, (fmt), tmx);	\
 | |
| 	    if (!i) return 0;						\
 | |
| 	    if (flags & BIT_OF(UPPER))					\
 | |
| 		upcase(s, i);						\
 | |
| 	    if (!(flags & BIT_OF(LEFT)) && precision > i) {		\
 | |
| 		if (start + maxsize < s + precision) {			\
 | |
| 		    errno = ERANGE;					\
 | |
| 		    return 0;						\
 | |
| 		}							\
 | |
| 		memmove(s + precision - i, s, i);			\
 | |
| 		memset(s, padding ? padding : ' ', precision - i);	\
 | |
| 		s += precision;						\
 | |
| 	    }								\
 | |
| 	    else s += i;						\
 | |
| 	} while (0)
 | |
| #define FMTV(def_pad, def_prec, fmt, val)				\
 | |
| 	do {								\
 | |
| 	    VALUE tmp = (val);						\
 | |
| 	    if (FIXNUM_P(tmp)) {					\
 | |
| 		FMT((def_pad), (def_prec), "l"fmt, FIX2LONG(tmp));	\
 | |
| 	    }								\
 | |
| 	    else {							\
 | |
| 		VALUE args[2], result;					\
 | |
| 		size_t l;						\
 | |
| 		if (precision <= 0) precision = (def_prec);		\
 | |
| 		if (flags & BIT_OF(LEFT)) precision = 1;		\
 | |
| 		args[0] = INT2FIX(precision);				\
 | |
| 		args[1] = (val);					\
 | |
| 		if (padding == '0' || (!padding && (def_pad) == '0'))	\
 | |
| 		    result = rb_str_format(2, args, rb_str_new2("%0*"fmt)); \
 | |
| 		else							\
 | |
| 		    result = rb_str_format(2, args, rb_str_new2("%*"fmt)); \
 | |
| 		l = strlcpy(s, StringValueCStr(result), endp - s);	\
 | |
| 		if ((size_t)(endp - s) <= l)				\
 | |
| 		    goto err;						\
 | |
| 		s += l;							\
 | |
| 	    }								\
 | |
| 	} while (0)
 | |
| 
 | |
| 	if (*format != '%') {
 | |
| 	    *s++ = *format;
 | |
| 	    continue;
 | |
| 	}
 | |
| 	tp = tbuf;
 | |
| 	sp = format;
 | |
| 	precision = -1;
 | |
| 	flags = 0;
 | |
| 	padding = 0;
 | |
| 	colons = 0;
 | |
|       again:
 | |
| 	switch (*++format) {
 | |
| 	  case '\0':
 | |
| 	    format--;
 | |
| 	    goto unknown;
 | |
| 
 | |
| 	  case 'A':	/* full weekday name */
 | |
| 	  case 'a':	/* abbreviated weekday name */
 | |
| 	    if (flags & BIT_OF(CHCASE)) {
 | |
| 		flags &= ~(BIT_OF(LOWER) | BIT_OF(CHCASE));
 | |
| 		flags |= BIT_OF(UPPER);
 | |
| 	    }
 | |
| 	    {
 | |
| 		int wday = tmx_wday;
 | |
| 		if (wday < 0 || wday > 6)
 | |
| 		    i = 1, tp = "?";
 | |
| 		else {
 | |
| 		    if (*format == 'A')
 | |
| 			i = strlen(tp = days_l[wday]);
 | |
| 		    else
 | |
| 			i = 3, tp = days_l[wday];
 | |
| 		}
 | |
| 	    }
 | |
| 	    break;
 | |
| 
 | |
| 	  case 'B':	/* full month name */
 | |
| 	  case 'b':	/* abbreviated month name */
 | |
| 	  case 'h':	/* same as %b */
 | |
| 	    if (flags & BIT_OF(CHCASE)) {
 | |
| 		flags &= ~(BIT_OF(LOWER) | BIT_OF(CHCASE));
 | |
| 		flags |= BIT_OF(UPPER);
 | |
| 	    }
 | |
| 	    {
 | |
| 		int mon = tmx_mon;
 | |
| 		if (mon < 1 || mon > 12)
 | |
| 		    i = 1, tp = "?";
 | |
| 		else {
 | |
| 		    if (*format == 'B')
 | |
| 			i = strlen(tp = months_l[mon - 1]);
 | |
| 		    else
 | |
| 			i = 3, tp = months_l[mon - 1];
 | |
| 		}
 | |
| 	    }
 | |
| 	    break;
 | |
| 
 | |
| 	  case 'C':	/* century (year/100) */
 | |
| 	    FMTV('0', 2, "d", div(tmx_year, INT2FIX(100)));
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'c':	/* appropriate date and time representation */
 | |
| 	    STRFTIME("%a %b %e %H:%M:%S %Y");
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'D':
 | |
| 	    STRFTIME("%m/%d/%y");
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'd':	/* day of the month, 01 - 31 */
 | |
| 	  case 'e':	/* day of month, blank padded */
 | |
| 	    v = range(1, tmx_mday, 31);
 | |
| 	    FMT((*format == 'd') ? '0' : ' ', 2, "d", v);
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'F':
 | |
| 	    STRFTIME("%Y-%m-%d");
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'G':	/* year of ISO week with century */
 | |
| 	  case 'Y':	/* year with century */
 | |
| 	    {
 | |
| 		VALUE year = (*format == 'G') ? tmx_cwyear : tmx_year;
 | |
| 		if (FIXNUM_P(year)) {
 | |
| 		    long y = FIX2LONG(year);
 | |
| 		    FMT('0', 0 <= y ? 4 : 5, "ld", y);
 | |
| 		}
 | |
| 		else {
 | |
| 		    FMTV('0', 4, "d", year);
 | |
| 		}
 | |
| 	    }
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'g':	/* year of ISO week without a century */
 | |
| 	  case 'y':	/* year without a century */
 | |
| 	    v = NUM2INT(mod((*format == 'g') ? tmx_cwyear : tmx_year, INT2FIX(100)));
 | |
| 	    FMT('0', 2, "d", v);
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'H':	/* hour, 24-hour clock, 00 - 23 */
 | |
| 	  case 'k':	/* hour, 24-hour clock, blank pad */
 | |
| 	    v = range(0, tmx_hour, 23);
 | |
| 	    FMT((*format == 'H') ? '0' : ' ', 2, "d", v);
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'I':	/* hour, 12-hour clock, 01 - 12 */
 | |
| 	  case 'l':	/* hour, 12-hour clock, 1 - 12, blank pad */
 | |
| 	    v = range(0, tmx_hour, 23);
 | |
| 	    if (v == 0)
 | |
| 		v = 12;
 | |
| 	    else if (v > 12)
 | |
| 		v -= 12;
 | |
| 	    FMT((*format == 'I') ? '0' : ' ', 2, "d", v);
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'j':	/* day of the year, 001 - 366 */
 | |
| 	    v = range(1, tmx_yday, 366);
 | |
| 	    FMT('0', 3, "d", v);
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'L':	/* millisecond */
 | |
| 	  case 'N':	/* nanosecond */
 | |
| 	    if (*format == 'L')
 | |
| 		w = 3;
 | |
| 	    else
 | |
| 		w = 9;
 | |
| 	    if (precision <= 0)
 | |
| 		precision = w;
 | |
| 	    NEEDS(precision);
 | |
| 
 | |
| 	    {
 | |
| 		VALUE subsec = tmx_sec_fraction;
 | |
| 		int ww;
 | |
| 		long n;
 | |
| 
 | |
| 		ww = precision;
 | |
| 		while (9 <= ww) {
 | |
| 		    subsec = mul(subsec, INT2FIX(1000000000));
 | |
| 		    ww -= 9;
 | |
| 		}
 | |
| 		n = 1;
 | |
| 		for (; 0 < ww; ww--)
 | |
| 		    n *= 10;
 | |
| 		if (n != 1)
 | |
| 		    subsec = mul(subsec, INT2FIX(n));
 | |
| 		subsec = div(subsec, INT2FIX(1));
 | |
| 
 | |
| 		if (FIXNUM_P(subsec)) {
 | |
| 		    (void)snprintf(s, endp - s, "%0*ld",
 | |
| 				   precision, FIX2LONG(subsec));
 | |
| 		    s += precision;
 | |
| 		}
 | |
| 		else {
 | |
| 		    VALUE args[2], result;
 | |
| 		    args[0] = INT2FIX(precision);
 | |
| 		    args[1] = subsec;
 | |
| 		    result = rb_str_format(2, args, rb_str_new2("%0*d"));
 | |
| 		    (void)strlcpy(s, StringValueCStr(result), endp - s);
 | |
| 		    s += precision;
 | |
| 		}
 | |
| 	    }
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'M':	/* minute, 00 - 59 */
 | |
| 	    v = range(0, tmx_min, 59);
 | |
| 	    FMT('0', 2, "d", v);
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'm':	/* month, 01 - 12 */
 | |
| 	    v = range(1, tmx_mon, 12);
 | |
| 	    FMT('0', 2, "d", v);
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'n':	/* same as \n */
 | |
| 	    FILL_PADDING(1);
 | |
| 	    *s++ = '\n';
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 't':	/* same as \t */
 | |
| 	    FILL_PADDING(1);
 | |
| 	    *s++ = '\t';
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'P':	/* am or pm based on 12-hour clock */
 | |
| 	  case 'p':	/* AM or PM based on 12-hour clock */
 | |
| 	    if ((*format == 'p' && (flags & BIT_OF(CHCASE))) ||
 | |
| 		(*format == 'P' && !(flags & (BIT_OF(CHCASE) | BIT_OF(UPPER))))) {
 | |
| 		flags &= ~(BIT_OF(UPPER) | BIT_OF(CHCASE));
 | |
| 		flags |= BIT_OF(LOWER);
 | |
| 	    }
 | |
| 	    v = range(0, tmx_hour, 23);
 | |
| 	    if (v < 12)
 | |
| 		tp = ampm[0];
 | |
| 	    else
 | |
| 		tp = ampm[1];
 | |
| 	    i = 2;
 | |
| 	    break;
 | |
| 
 | |
| 	  case 'Q':	/* milliseconds since Unix epoch */
 | |
| 	    FMTV('0', 1, "d", tmx_msecs);
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'R':
 | |
| 	    STRFTIME("%H:%M");
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'r':
 | |
| 	    STRFTIME("%I:%M:%S %p");
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'S':	/* second, 00 - 59 */
 | |
| 	    v = range(0, tmx_sec, 59);
 | |
| 	    FMT('0', 2, "d", v);
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 's':	/* seconds since Unix epoch */
 | |
| 	    FMTV('0', 1, "d", tmx_secs);
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'T':
 | |
| 	    STRFTIME("%H:%M:%S");
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'U':	/* week of year, Sunday is first day of week */
 | |
| 	  case 'W':	/* week of year, Monday is first day of week */
 | |
| 	    v = range(0, (*format == 'U') ? tmx_wnum0 : tmx_wnum1, 53);
 | |
| 	    FMT('0', 2, "d", v);
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'u':	/* weekday, Monday == 1, 1 - 7 */
 | |
| 	    v = range(1, tmx_cwday, 7);
 | |
| 	    FMT('0', 1, "d", v);
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'V':	/* week of year according ISO 8601 */
 | |
| 	    v = range(1, tmx_cweek, 53);
 | |
| 	    FMT('0', 2, "d", v);
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'v':
 | |
| 	    STRFTIME("%e-%b-%Y");
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'w':	/* weekday, Sunday == 0, 0 - 6 */
 | |
| 	    v = range(0, tmx_wday, 6);
 | |
| 	    FMT('0', 1, "d", v);
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'X':	/* appropriate time representation */
 | |
| 	    STRFTIME("%H:%M:%S");
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'x':	/* appropriate date representation */
 | |
| 	    STRFTIME("%m/%d/%y");
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'Z':	/* time zone name or abbreviation */
 | |
| 	    if (flags & BIT_OF(CHCASE)) {
 | |
| 		flags &= ~(BIT_OF(UPPER) | BIT_OF(CHCASE));
 | |
| 		flags |= BIT_OF(LOWER);
 | |
| 	    }
 | |
| 	    {
 | |
| 		char *zone = tmx_zone;
 | |
| 		if (zone == NULL)
 | |
| 		    tp = "";
 | |
| 		else
 | |
| 		    tp = zone;
 | |
| 		i = strlen(tp);
 | |
| 	    }
 | |
| 	    break;
 | |
| 
 | |
| 	  case 'z':	/* offset from UTC */
 | |
| 	    {
 | |
| 		long off, aoff;
 | |
| 		int hl, hw;
 | |
| 
 | |
| 		off = tmx_offset;
 | |
| 		aoff = off;
 | |
| 		if (aoff < 0)
 | |
| 		    aoff = -off;
 | |
| 
 | |
| 		if ((aoff / 3600) < 10)
 | |
| 		    hl = 1;
 | |
| 		else
 | |
| 		    hl = 2;
 | |
| 		hw = 2;
 | |
| 		if (flags & BIT_OF(LEFT) && hl == 1)
 | |
| 		    hw = 1;
 | |
| 
 | |
| 		switch (colons) {
 | |
| 		  case 0: /* %z -> +hhmm */
 | |
| 		    precision = precision <= (3 + hw) ? hw : precision - 3;
 | |
| 		    NEEDS(precision + 3);
 | |
| 		    break;
 | |
| 
 | |
| 		  case 1: /* %:z -> +hh:mm */
 | |
| 		    precision = precision <= (4 + hw) ? hw : precision - 4;
 | |
| 		    NEEDS(precision + 4);
 | |
| 		    break;
 | |
| 
 | |
| 		  case 2: /* %::z -> +hh:mm:ss */
 | |
| 		    precision = precision <= (7 + hw) ? hw : precision - 7;
 | |
| 		    NEEDS(precision + 7);
 | |
| 		    break;
 | |
| 
 | |
| 		  case 3: /* %:::z -> +hh[:mm[:ss]] */
 | |
| 		    {
 | |
| 			if (aoff % 3600 == 0) {
 | |
| 			    precision = precision <= (1 + hw) ?
 | |
| 				hw : precision - 1;
 | |
| 			    NEEDS(precision + 3);
 | |
| 			}
 | |
| 			else if (aoff % 60 == 0) {
 | |
| 			    precision = precision <= (4 + hw) ?
 | |
| 				hw : precision - 4;
 | |
| 			    NEEDS(precision + 4);
 | |
| 			}
 | |
| 			else {
 | |
| 			    precision = precision <= (7 + hw) ?
 | |
| 				hw : precision - 7;
 | |
| 			    NEEDS(precision + 7);
 | |
| 			}
 | |
| 		    }
 | |
| 		    break;
 | |
| 
 | |
| 		  default:
 | |
| 		    format--;
 | |
| 		    goto unknown;
 | |
| 		}
 | |
| 		if (padding == ' ' && precision > hl) {
 | |
| 		    i = snprintf(s, endp - s, "%*s", precision - hl, "");
 | |
| 		    precision = hl;
 | |
| 		    if (i < 0) goto err;
 | |
| 		    s += i;
 | |
| 		}
 | |
| 		if (off < 0) {
 | |
| 		    off = -off;
 | |
| 		    *s++ = '-';
 | |
| 		} else {
 | |
| 		    *s++ = '+';
 | |
| 		}
 | |
| 		i = snprintf(s, endp - s, "%.*ld", precision, off / 3600);
 | |
| 		if (i < 0) goto err;
 | |
| 		s += i;
 | |
| 		off = off % 3600;
 | |
| 		if (colons == 3 && off == 0)
 | |
| 		    continue;
 | |
| 		if (1 <= colons)
 | |
| 		    *s++ = ':';
 | |
| 		i = snprintf(s, endp - s, "%02d", (int)(off / 60));
 | |
| 		if (i < 0) goto err;
 | |
| 		s += i;
 | |
| 		off = off % 60;
 | |
| 		if (colons == 3 && off == 0)
 | |
| 		    continue;
 | |
| 		if (2 <= colons) {
 | |
| 		    *s++ = ':';
 | |
| 		    i = snprintf(s, endp - s, "%02d", (int)off);
 | |
| 		    if (i < 0) goto err;
 | |
| 		    s += i;
 | |
| 		}
 | |
| 	    }
 | |
| 	    continue;
 | |
| 
 | |
| 	  case '+':
 | |
| 	    STRFTIME("%a %b %e %H:%M:%S %Z %Y");
 | |
| 	    continue;
 | |
| 
 | |
| 	  case 'E':
 | |
| 	    /* POSIX locale extensions, ignored for now */
 | |
| 	    flags |= BIT_OF(LOCALE_E);
 | |
| 	    if (*(format + 1) && strchr("cCxXyY", *(format + 1)))
 | |
| 		goto again;
 | |
| 	    goto unknown;
 | |
| 	  case 'O':
 | |
| 	    /* POSIX locale extensions, ignored for now */
 | |
| 	    flags |= BIT_OF(LOCALE_O);
 | |
| 	    if (*(format + 1) && strchr("deHkIlmMSuUVwWy", *(format + 1)))
 | |
| 		goto again;
 | |
| 	    goto unknown;
 | |
| 
 | |
| 	  case ':':
 | |
| 	    flags |= BIT_OF(COLONS);
 | |
| 	    {
 | |
| 		size_t l = strspn(format, ":");
 | |
| 		format += l;
 | |
| 		if (*format == 'z') {
 | |
| 		    colons = l;
 | |
| 		    format--;
 | |
| 		    goto again;
 | |
| 		}
 | |
| 		format -= l;
 | |
| 	    }
 | |
| 	    goto unknown;
 | |
| 
 | |
| 	  case '_':
 | |
| 	    FLAG_FOUND();
 | |
| 	    padding = ' ';
 | |
| 	    goto again;
 | |
| 
 | |
| 	  case '-':
 | |
| 	    FLAG_FOUND();
 | |
| 	    flags |= BIT_OF(LEFT);
 | |
| 	    goto again;
 | |
| 
 | |
| 	  case '^':
 | |
| 	    FLAG_FOUND();
 | |
| 	    flags |= BIT_OF(UPPER);
 | |
| 	    goto again;
 | |
| 
 | |
| 	  case '#':
 | |
| 	    FLAG_FOUND();
 | |
| 	    flags |= BIT_OF(CHCASE);
 | |
| 	    goto again;
 | |
| 
 | |
| 	  case '0':
 | |
| 	    FLAG_FOUND();
 | |
| 	    padding = '0';
 | |
| 	  case '1':  case '2': case '3': case '4':
 | |
| 	  case '5': case '6':  case '7': case '8': case '9':
 | |
| 	    {
 | |
| 		char *e;
 | |
| 		precision = (int)strtoul(format, &e, 10);
 | |
| 		format = e - 1;
 | |
| 		goto again;
 | |
| 	    }
 | |
| 
 | |
| 	  case '%':
 | |
| 	    FILL_PADDING(1);
 | |
| 	    *s++ = '%';
 | |
| 	    continue;
 | |
| 
 | |
| 	  default:
 | |
| 	  unknown:
 | |
| 	    i = format - sp + 1;
 | |
| 	    tp = sp;
 | |
| 	    precision = -1;
 | |
| 	    flags = 0;
 | |
| 	    padding = 0;
 | |
| 	    colons = 0;
 | |
| 	    break;
 | |
| 	}
 | |
| 	if (i) {
 | |
| 	    FILL_PADDING(i);
 | |
| 	    memcpy(s, tp, i);
 | |
| 	    switch (flags & (BIT_OF(UPPER) | BIT_OF(LOWER))) {
 | |
| 	      case BIT_OF(UPPER):
 | |
| 		upcase(s, i);
 | |
| 		break;
 | |
| 	      case BIT_OF(LOWER):
 | |
| 		downcase(s, i);
 | |
| 		break;
 | |
| 	    }
 | |
| 	    s += i;
 | |
| 	}
 | |
|     }
 | |
|     if (s >= endp) {
 | |
| 	goto err;
 | |
|     }
 | |
|     if (*format == '\0') {
 | |
| 	*s = '\0';
 | |
| 	return (s - start);
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| size_t
 | |
| date_strftime(char *s, size_t maxsize, const char *format,
 | |
| 	      const struct tmx *tmx)
 | |
| {
 | |
|     return date_strftime_with_tmx(s, maxsize, format, tmx);
 | |
| }
 | |
| 
 | |
| /*
 | |
| Local variables:
 | |
| c-file-style: "ruby"
 | |
| End:
 | |
| */
 |