diff options
author | Roland McGrath <roland@gnu.org> | 1995-02-18 01:27:10 +0000 |
---|---|---|
committer | Roland McGrath <roland@gnu.org> | 1995-02-18 01:27:10 +0000 |
commit | 28f540f45bbacd939bfd07f213bcad2bf730b1bf (patch) | |
tree | 15f07c4c43d635959c6afee96bde71fb1b3614ee /time/strftime.c | |
download | glibc-28f540f45bbacd939bfd07f213bcad2bf730b1bf.tar.gz glibc-28f540f45bbacd939bfd07f213bcad2bf730b1bf.tar.xz glibc-28f540f45bbacd939bfd07f213bcad2bf730b1bf.zip |
initial import
Diffstat (limited to 'time/strftime.c')
-rw-r--r-- | time/strftime.c | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/time/strftime.c b/time/strftime.c new file mode 100644 index 0000000000..ccc19c72b0 --- /dev/null +++ b/time/strftime.c @@ -0,0 +1,296 @@ +/* Extensions for GNU date that are still missing here: + - + _ +*/ + +/* Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <localeinfo.h> +#include <ctype.h> +#include <limits.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#ifndef HAVE_GNU_LD +#define __tzname tzname +#define __daylight daylight +#define __timezone timezone +#endif + + +#define add(n, f) \ + do \ + { \ + i += (n); \ + if (i >= maxsize) \ + return 0; \ + else \ + if (p != NULL) \ + { \ + f; \ + p += (n); \ + } \ + } while (0) +#define cpy(n, s) add((n), memcpy((PTR) p, (PTR) (s), (n))) +#define fmt(n, args) add((n), if (sprintf args != (n)) return 0) + +/* Return the week in the year specified by TP, + with weeks starting on STARTING_DAY. */ +#ifdef __GNUC__ +inline +#endif +static unsigned int +DEFUN(week, (tp, starting_day), + CONST struct tm *CONST tp AND int starting_day) +{ + int wday, dl; + + wday = tp->tm_wday - starting_day; + if (wday < 0) + wday += 7; + + /* Set DL to the day in the year of the last day of the week previous to the + one containing the day specified in TP. If DL is negative or zero, the + day specified in TP is in the first week of the year. Otherwise, + calculate the number of complete weeks before our week (DL / 7) and + add any partial week at the start of the year (DL % 7). */ + dl = tp->tm_yday - wday; + return dl <= 0 ? 0 : ((dl / 7) + ((dl % 7) == 0 ? 0 : 1)); +} + + +/* Write information from TP into S according to the format + string FORMAT, writing no more that MAXSIZE characters + (including the terminating '\0') and returning number of + characters written. If S is NULL, nothing will be written + anywhere, so to determine how many characters would be + written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */ +size_t +DEFUN(strftime, (s, maxsize, format, tp), + char *s AND size_t maxsize AND + CONST char *format AND register CONST struct tm *tp) +{ + CONST char *CONST a_wkday = _time_info->abbrev_wkday[tp->tm_wday]; + CONST char *CONST f_wkday = _time_info->full_wkday[tp->tm_wday]; + CONST char *CONST a_month = _time_info->abbrev_month[tp->tm_mon]; + CONST char *CONST f_month = _time_info->full_month[tp->tm_mon]; + size_t aw_len = strlen(a_wkday); + size_t am_len = strlen(a_month); + size_t wkday_len = strlen(f_wkday); + size_t month_len = strlen(f_month); + int hour12 = tp->tm_hour; + CONST char *CONST ampm = _time_info->ampm[hour12 >= 12]; + size_t ap_len = strlen(ampm); + CONST unsigned int y_week0 = week(tp, 0); + CONST unsigned int y_week1 = week(tp, 1); + CONST char *zone; + size_t zonelen; + register size_t i = 0; + register char *p = s; + register CONST char *f; + + if (tp->tm_isdst < 0) + { + zone = ""; + zonelen = 0; + } + else + { + zone = __tzname[tp->tm_isdst]; + zonelen = strlen(zone); + } + + if (hour12 > 12) + hour12 -= 12; + else + if (hour12 == 0) hour12 = 12; + + for (f = format; *f != '\0'; ++f) + { + CONST char *subfmt; + + if (!isascii(*f)) + { + /* Non-ASCII, may be a multibyte. */ + int len = mblen(f, strlen(f)); + if (len > 0) + { + cpy(len, f); + continue; + } + } + + if (*f != '%') + { + add(1, *p = *f); + continue; + } + + ++f; + switch (*f) + { + case '\0': + case '%': + add(1, *p = *f); + break; + + case 'a': + cpy(aw_len, a_wkday); + break; + + case 'A': + cpy(wkday_len, f_wkday); + break; + + case 'b': + case 'h': /* GNU extension. */ + cpy(am_len, a_month); + break; + + case 'B': + cpy(month_len, f_month); + break; + + case 'c': + subfmt = _time_info->date_time; + subformat: + { + size_t len = strftime (p, maxsize - i, subfmt, tp); + add(len, ); + } + break; + + case 'C': + fmt (2, (p, "%.2d", (1900 + tp->tm_year) / 100)); + break; + + case 'D': /* GNU extension. */ + subfmt = "%m/%d/%y"; + goto subformat; + + case 'd': + fmt(2, (p, "%.2d", tp->tm_mday)); + break; + + case 'e': /* GNU extension: %d, but blank-padded. */ + fmt(2, (p, "%2d", tp->tm_mday)); + break; + + case 'H': + fmt(2, (p, "%.2d", tp->tm_hour)); + break; + + case 'I': + fmt(2, (p, "%.2d", hour12)); + break; + + case 'k': /* GNU extension. */ + fmt(2, (p, "%2d", tp->tm_hour)); + break; + + case 'l': /* GNU extension. */ + fmt(2, (p, "%2d", hour12)); + break; + + case 'j': + fmt(3, (p, "%.3d", 1 + tp->tm_yday)); + break; + + case 'M': + fmt(2, (p, "%.2d", tp->tm_min)); + break; + + case 'm': + fmt(2, (p, "%.2d", tp->tm_mon + 1)); + break; + + case 'n': /* GNU extension. */ + add (1, *p = '\n'); + break; + + case 'p': + cpy(ap_len, ampm); + break; + + case 'R': /* GNU extension. */ + subfmt = "%H:%M"; + goto subformat; + + case 'r': /* GNU extension. */ + subfmt = "%I:%M:%S %p"; + goto subformat; + + case 'S': + fmt(2, (p, "%.2d", tp->tm_sec)); + break; + + case 'T': /* GNU extenstion. */ + subfmt = "%H:%M:%S"; + goto subformat; + + case 't': /* GNU extenstion. */ + add (1, *p = '\t'); + break; + + case 'U': + fmt(2, (p, "%.2u", y_week0)); + break; + + case 'W': + fmt(2, (p, "%.2u", y_week1)); + break; + + case 'w': + fmt(2, (p, "%.2d", tp->tm_wday)); + break; + + case 'X': + subfmt = _time_info->time; + goto subformat; + + case 'x': + subfmt = _time_info->date; + goto subformat; + + case 'Y': + fmt(4, (p, "%.4d", 1900 + tp->tm_year)); + break; + + case 'y': + fmt(2, (p, "%.2d", tp->tm_year)); + break; + + case 'Z': + cpy(zonelen, zone); + break; + + default: + /* Bad format. */ + break; + } + } + + if (p != NULL) + *p = '\0'; + return i; +} |