Imported Debian patch 2.4.4p3-2
[debian/amanda] / common-src / strftime.c
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that: (1) source distributions retain this entire copyright
7  * notice and comment, and (2) distributions including binaries display
8  * the following acknowledgement:  ``This product includes software
9  * developed by the University of California, Berkeley and its contributors''
10  * in the documentation or other materials provided with the distribution
11  * and in all advertising materials mentioning features or use of this
12  * software. Neither the name of the University nor the names of its
13  * contributors may be used to endorse or promote products derived
14  * from this software without specific prior written permission.
15  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18  */
19
20 #if defined(LIBC_SCCS) && !defined(lint)
21 static char sccsid[] = "@(#)strftime.c  5.8 (Berkeley) 6/1/90";
22 #endif /* LIBC_SCCS and not lint */
23
24 #include <sys/types.h>
25 #include <sys/time.h>
26 #ifndef linux
27 # include <tzfile.h>
28 #endif  /* linux */
29 #include <string.h>
30
31 static char *afmt[] = {
32         "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
33 };
34 static char *Afmt[] = {
35         "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
36         "Saturday",
37 };
38 static char *bfmt[] = {
39         "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
40         "Oct", "Nov", "Dec",
41 };
42 static char *Bfmt[] = {
43         "January", "February", "March", "April", "May", "June", "July",
44         "August", "September", "October", "November", "December",
45 };
46
47 static size_t gsize;
48 static char *pt;
49
50 size_t
51 strftime(s, maxsize, format, t)
52         char *s;
53         char *format;
54         size_t maxsize;
55         struct tm *t;
56 {
57         size_t _fmt();
58
59         pt = s;
60         if ((gsize = maxsize) < 1)
61                 return(0);
62         if (_fmt(format, t)) {
63                 *pt = '\0';
64                 return(maxsize - gsize);
65         }
66         return(0);
67 }
68
69 static size_t
70 _fmt(format, t)
71         register char *format;
72         struct tm *t;
73 {
74         for (; *format; ++format) {
75                 if (*format == '%')
76                         switch(*++format) {
77                         case '\0':
78                                 --format;
79                                 break;
80                         case 'A':
81                                 if (t->tm_wday < 0 || t->tm_wday > 6)
82                                         return(0);
83                                 if (!_add(Afmt[t->tm_wday]))
84                                         return(0);
85                                 continue;
86                         case 'a':
87                                 if (t->tm_wday < 0 || t->tm_wday > 6)
88                                         return(0);
89                                 if (!_add(afmt[t->tm_wday]))
90                                         return(0);
91                                 continue;
92                         case 'B':
93                                 if (t->tm_mon < 0 || t->tm_mon > 11)
94                                         return(0);
95                                 if (!_add(Bfmt[t->tm_mon]))
96                                         return(0);
97                                 continue;
98                         case 'b':
99                         case 'h':
100                                 if (t->tm_mon < 0 || t->tm_mon > 11)
101                                         return(0);
102                                 if (!_add(bfmt[t->tm_mon]))
103                                         return(0);
104                                 continue;
105                         case 'C':
106                                 if (!_fmt("%a %b %e %H:%M:%S %Y", t))
107                                         return(0);
108                                 continue;
109                         case 'c':
110                                 if (!_fmt("%m/%d/%y %H:%M:%S", t))
111                                         return(0);
112                                 continue;
113                         case 'e':
114                                 if (!_conv(t->tm_mday, 2, ' '))
115                                         return(0);
116                                 continue;
117                         case 'D':
118                                 if (!_fmt("%m/%d/%y", t))
119                                         return(0);
120                                 continue;
121                         case 'd':
122                                 if (!_conv(t->tm_mday, 2, '0'))
123                                         return(0);
124                                 continue;
125                         case 'H':
126                                 if (!_conv(t->tm_hour, 2, '0'))
127                                         return(0);
128                                 continue;
129                         case 'I':
130                                 if (!_conv(t->tm_hour % 12 ?
131                                     t->tm_hour % 12 : 12, 2, '0'))
132                                         return(0);
133                                 continue;
134                         case 'j':
135                                 if (!_conv(t->tm_yday + 1, 3, '0'))
136                                         return(0);
137                                 continue;
138                         case 'k':
139                                 if (!_conv(t->tm_hour, 2, ' '))
140                                         return(0);
141                                 continue;
142                         case 'l':
143                                 if (!_conv(t->tm_hour % 12 ?
144                                     t->tm_hour % 12 : 12, 2, ' '))
145                                         return(0);
146                                 continue;
147                         case 'M':
148                                 if (!_conv(t->tm_min, 2, '0'))
149                                         return(0);
150                                 continue;
151                         case 'm':
152                                 if (!_conv(t->tm_mon + 1, 2, '0'))
153                                         return(0);
154                                 continue;
155                         case 'n':
156                                 if (!_add("\n"))
157                                         return(0);
158                                 continue;
159                         case 'p':
160                                 if (!_add(t->tm_hour >= 12 ? "PM" : "AM"))
161                                         return(0);
162                                 continue;
163                         case 'R':
164                                 if (!_fmt("%H:%M", t))
165                                         return(0);
166                                 continue;
167                         case 'r':
168                                 if (!_fmt("%I:%M:%S %p", t))
169                                         return(0);
170                                 continue;
171                         case 'S':
172                                 if (!_conv(t->tm_sec, 2, '0'))
173                                         return(0);
174                                 continue;
175                         case 'T':
176                         case 'X':
177                                 if (!_fmt("%H:%M:%S", t))
178                                         return(0);
179                                 continue;
180                         case 't':
181                                 if (!_add("\t"))
182                                         return(0);
183                                 continue;
184                         case 'U':
185                                 if (!_conv((t->tm_yday + 7 - t->tm_wday) / 7,
186                                     2, '0'))
187                                         return(0);
188                                 continue;
189                         case 'W':
190                                 if (!_conv((t->tm_yday + 7 -
191                                     (t->tm_wday ? (t->tm_wday - 1) : 6))
192                                     / 7, 2, '0'))
193                                         return(0);
194                                 continue;
195                         case 'w':
196                                 if (!_conv(t->tm_wday, 1, '0'))
197                                         return(0);
198                                 continue;
199                         case 'x':
200                                 if (!_fmt("%m/%d/%y", t))
201                                         return(0);
202                                 continue;
203                         case 'y':
204                                 if (!_conv((t->tm_year + TM_YEAR_BASE)
205                                     % 100, 2, '0'))
206                                         return(0);
207                                 continue;
208                         case 'Y':
209                                 if (!_conv(t->tm_year + TM_YEAR_BASE, 4, '0'))
210                                         return(0);
211                                 continue;
212                         case 'Z':
213                                 if (!t->tm_zone || !_add(t->tm_zone))
214                                         return(0);
215                                 continue;
216                         case '%':
217                         /*
218                          * X311J/88-090 (4.12.3.5): if conversion char is
219                          * undefined, behavior is undefined.  Print out the
220                          * character itself as printf(3) does.
221                          */
222                         default:
223                                 break;
224                 }
225                 if (!gsize--)
226                         return(0);
227                 *pt++ = *format;
228         }
229         return(gsize);
230 }
231
232 static
233 _conv(n, digits, pad)
234         int n, digits;
235         char pad;
236 {
237         static char buf[10];
238         register char *p;
239
240         for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits)
241                 *p-- = n % 10 + '0';
242         while (p > buf && digits-- > 0)
243                 *p-- = pad;
244         return(_add(++p));
245 }
246
247 static
248 _add(str)
249         register char *str;
250 {
251         for (;; ++pt, --gsize) {
252                 if (!gsize)
253                         return(0);
254                 if (!(*pt = *str++))
255                         return(1);
256         }
257 }