summaryrefslogtreecommitdiffstats
path: root/mdk-stage1/dietlibc/libugly/strftime.c
blob: b7e750ab1026cc07cd95ac8b40bf94b24836e555 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#include <sys/types.h>
#include <time.h>

static char *sweekdays[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
static char *weekdays[]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
static char *smonths[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
static char *months[]={"January","February","March","April","May","June","July","August","September","October","November","December"};
static char *ampm[]={"am","pm","AM","PM"};

static int i2a(char* dest,unsigned int x) {
  register unsigned int tmp=x;
  register int len=0;
  *dest++=tmp/10+'0'; tmp=tmp%10; ++len;
  *dest++=tmp+'0';
  return 2;
}

static int i2as(char* dest,unsigned int x) {
  int len=i2a(dest,x);
  if (*dest=='0') *dest=' ';
  return len;
}

size_t strftime(char *s, size_t max, const char *format, const struct tm *tm) {
  char *t=s;
  const char *src;
  char buf[5];
  while (*format) {
    switch (*format) {
    case 0: break;
    case '%':
      switch (*++format) {
      case '%': *t='%'; ++t; break;
      case 'a': src=sweekdays[tm->tm_wday]; goto append;
      case 'A': src=weekdays[tm->tm_wday]; goto append;
      case 'h':
      case 'b': src=smonths[tm->tm_mon]; goto append;
      case 'B': src=months[tm->tm_mon]; goto append;
      case 'c': t+=strftime(t,max-(t-s),"%b %a %d %k:%M:%S %Z %Y",tm); break;
      case 'C': buf[i2a(buf,(tm->tm_year+1900)/100)]=0; src=buf; goto append;
      case 'd': buf[i2a(buf,tm->tm_mday)]=0; src=buf; goto append;
      case 'e': buf[i2as(buf,tm->tm_mday)]=0; src=buf; goto append;
      case 'H': buf[i2a(buf,tm->tm_hour)]=0; src=buf; goto append;
      case 'I': buf[i2a(buf,tm->tm_hour%12)]=0; src=buf; goto append;
      case 'j': buf[i2a(buf,tm->tm_yday)]=0; src=buf; goto append;
      case 'k': buf[i2as(buf,tm->tm_hour)]=0; src=buf; goto append;
      case 'l': buf[i2as(buf,tm->tm_hour%12)]=0; src=buf; goto append;
      case 'm': buf[i2a(buf,tm->tm_mon+1)]=0; src=buf; goto append;
      case 'M': buf[i2a(buf,tm->tm_min)]=0; src=buf; goto append;
      case 'n': *t='\n'; break;
      case 'p': src=ampm[tm->tm_hour>11?3:2]; goto append;
      case 'P': src=ampm[tm->tm_hour>11?1:0]; goto append;
      case 'r': t+=strftime(t,max-(t-s),"%I:%M:%S %p",tm); break;
      case 'R': t+=strftime(t,max-(t-s),"%H:%M",tm); break;
      case 'S': buf[i2a(buf,tm->tm_sec)]=0; src=buf; goto append;
      case 't': *t='\t'; break;
      case 'T': t+=strftime(t,max-(t-s),"%H:%M:%S",tm); break;
      case 'u': buf[i2a(buf,tm->tm_wday?tm->tm_wday:7)]=0; src=buf; goto append;
      case 'w': buf[i2a(buf,tm->tm_wday)]=0; src=buf; goto append;
      case 'x': t+=strftime(t,max-(t-s),"%b %a %d",tm); break;
      case 'X': t+=strftime(t,max-(t-s),"%k:%M:%S",tm); break;
      case 'y': buf[i2a(buf,tm->tm_year%100)]=0; src=buf; goto append;
      case 'Y': i2a(buf,(tm->tm_year+1900)/100); buf[i2a(buf+2,(tm->tm_year%100))+2]=0; src=buf; goto append;
      case 'Z': src="GMT"; goto append; /* hehe */
append:
      while (*src && t<s+max) { *t=*src; ++t; ++src; }
      };
      break;
    default:
      *t=*format; ++t;
    }
    ++format;
    if (t>=s+max) break;
    continue;
  }
  *t=0; return t-s;
}



/*
       %u     The day of the week as a decimal,  range  1  to  7,
              Monday being 1.  See also %w. (SU)

       %U     The  week  number  of the current year as a decimal
              number, range 00 to 53,  starting  with  the  first
              Sunday as the first day of week 01. See also %V and
              %W.

       %V     The ISO 8601:1988 week number of the  current  year
              as  a  decimal number, range 01 to 53, where week 1
              is the first week that has at least 4 days  in  the
              current  year,  and with Monday as the first day of
              the week. See also %U and %W. (SU)

       %w     The day of the week as a decimal,  range  0  to  6,
              Sunday being 0.  See also %u.

       %W     The  week  number  of the current year as a decimal
              number, range 00 to 53,  starting  with  the  first
              Monday as the first day of week 01.

       %x     The  preferred  date representation for the current
              locale without the time.

       %X     The preferred time representation for  the  current
              locale without the date.

       %y     The  year  as  a  decimal  number without a century
              (range 00 to 99).

       %Y     The year as a decimal number including the century.

       %z     The time-zone as hour offset from GMT.  Required to
              emit RFC822-conformant dates (using "%a, %d  %b  %Y
              %H:%M:%S %z"). (GNU)

       %Z     The time zone or name or abbreviation.

       %+     The date and time in date(1) format. (TZ)

       %%     A literal `%' character.

       Some  conversion  specifiers  can be modified by preceding
       them by the E or O modifier to indicate that  an  alterna­
       tive  format should be used.  If the alternative format or
       specification does not exist for the current  locale,  the
       behaviour will be as if the unmodified conversion specifi­
       cation were used. (SU) The Single Unix Specification  men­
       tions  %Ec,  %EC,  %Ex, %EX, %Ry, %EY, %Od, %Oe, %OH, %OI,
       %Om, %OM, %OS, %Ou, %OU, %OV, %Ow,  %OW,  %Oy,  where  the
       effect  of  the  O  modifier is to use alternative numeric
       symbols (say, roman numerals), and that of the E  modifier



GNU                       29 March 1999                         3





STRFTIME(3)         Linux Programmer's Manual         STRFTIME(3)


       is to use a locale-dependent alternative representation.

       The  broken-down time structure tm is defined in <time.h>.
       See also ctime(3).


RETURN VALUE
       The strftime() function returns the number  of  characters
       placed  in  the array s, not including the terminating NUL
       character, provided the string, including the  terminating
       NUL,  fits.   Otherwise, it returns 0, and the contents of
       the array is undefined.  (Thus at least since libc  4.4.4;
       very  old  versions  of  libc,  such  as libc 4.4.1, would
       return max if the array was too small.)

       Note that the return value 0 does not necessarily indicate
       an  error; for example, in many locales %p yields an empty
       string.

ENVIRONMENT
       The environment variables TZ and LC_TIME are used.

CONFORMING TO
       ANSI C, SVID 3, ISO 9899.   There  are  strict  inclusions
       between the set of conversions given in ANSI C (unmarked),
       those given in the Single Unix Specification (marked  SU),
       those  given  in Olson's timezone package (marked TZ), and
       those given in glibc (marked GNU), except that %+  is  not
       supported  in glibc2. On the other hand glibc2 has several
       more extensions.  POSIX.1 only refers to ANSI  C;  POSIX.2
       describes  under  date(1)  several  extensions  that could
       apply to strftime as well.

SEE ALSO
       date(1), time(2), ctime(3), setlocale(3), sprintf(3)

*/