e3b0ea7e87e91a09ed468c2f358f465f27d9e0b0
[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 #include <tzfile.h>
27 #include <string.h>
28
29 static char *afmt[] = {
30         "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
31 };
32 static char *Afmt[] = {
33         "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
34         "Saturday",
35 };
36 static char *bfmt[] = {
37         "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
38         "Oct", "Nov", "Dec",
39 };
40 static char *Bfmt[] = {
41         "January", "February", "March", "April", "May", "June", "July",
42         "August", "September", "October", "November", "December",
43 };
44
45 static size_t gsize;
46 static char *pt;
47
48 size_t
49 strftime(s, maxsize, format, t)
50         char *s;
51         char *format;
52         size_t maxsize;
53         struct tm *t;
54 {
55         size_t _fmt();
56
57         pt = s;
58         if ((gsize = maxsize) < 1)
59                 return(0);
60         if (_fmt(format, t)) {
61                 *pt = '\0';
62                 return(maxsize - gsize);
63         }
64         return(0);
65 }
66
67 static size_t
68 _fmt(format, t)
69         register char *format;
70         struct tm *t;
71 {
72         for (; *format; ++format) {
73                 if (*format == '%')
74                         switch(*++format) {
75                         case '\0':
76                                 --format;
77                                 break;
78                         case 'A':
79                                 if (t->tm_wday < 0 || t->tm_wday > 6)
80                                         return(0);
81                                 if (!_add(Afmt[t->tm_wday]))
82                                         return(0);
83                                 continue;
84                         case 'a':
85                                 if (t->tm_wday < 0 || t->tm_wday > 6)
86                                         return(0);
87                                 if (!_add(afmt[t->tm_wday]))
88                                         return(0);
89                                 continue;
90                         case 'B':
91                                 if (t->tm_mon < 0 || t->tm_mon > 11)
92                                         return(0);
93                                 if (!_add(Bfmt[t->tm_mon]))
94                                         return(0);
95                                 continue;
96                         case 'b':
97                         case 'h':
98                                 if (t->tm_mon < 0 || t->tm_mon > 11)
99                                         return(0);
100                                 if (!_add(bfmt[t->tm_mon]))
101                                         return(0);
102                                 continue;
103                         case 'C':
104                                 if (!_fmt("%a %b %e %H:%M:%S %Y", t))
105                                         return(0);
106                                 continue;
107                         case 'c':
108                                 if (!_fmt("%m/%d/%y %H:%M:%S", t))
109                                         return(0);
110                                 continue;
111                         case 'e':
112                                 if (!_conv(t->tm_mday, 2, ' '))
113                                         return(0);
114                                 continue;
115                         case 'D':
116                                 if (!_fmt("%m/%d/%y", t))
117                                         return(0);
118                                 continue;
119                         case 'd':
120                                 if (!_conv(t->tm_mday, 2, '0'))
121                                         return(0);
122                                 continue;
123                         case 'H':
124                                 if (!_conv(t->tm_hour, 2, '0'))
125                                         return(0);
126                                 continue;
127                         case 'I':
128                                 if (!_conv(t->tm_hour % 12 ?
129                                     t->tm_hour % 12 : 12, 2, '0'))
130                                         return(0);
131                                 continue;
132                         case 'j':
133                                 if (!_conv(t->tm_yday + 1, 3, '0'))
134                                         return(0);
135                                 continue;
136                         case 'k':
137                                 if (!_conv(t->tm_hour, 2, ' '))
138                                         return(0);
139                                 continue;
140                         case 'l':
141                                 if (!_conv(t->tm_hour % 12 ?
142                                     t->tm_hour % 12 : 12, 2, ' '))
143                                         return(0);
144                                 continue;
145                         case 'M':
146                                 if (!_conv(t->tm_min, 2, '0'))
147                                         return(0);
148                                 continue;
149                         case 'm':
150                                 if (!_conv(t->tm_mon + 1, 2, '0'))
151                                         return(0);
152                                 continue;
153                         case 'n':
154                                 if (!_add("\n"))
155                                         return(0);
156                                 continue;
157                         case 'p':
158                                 if (!_add(t->tm_hour >= 12 ? "PM" : "AM"))
159                                         return(0);
160                                 continue;
161                         case 'R':
162                                 if (!_fmt("%H:%M", t))
163                                         return(0);
164                                 continue;
165                         case 'r':
166                                 if (!_fmt("%I:%M:%S %p", t))
167                                         return(0);
168                                 continue;
169                         case 'S':
170                                 if (!_conv(t->tm_sec, 2, '0'))
171                                         return(0);
172                                 continue;
173                         case 'T':
174                         case 'X':
175                                 if (!_fmt("%H:%M:%S", t))
176                                         return(0);
177                                 continue;
178                         case 't':
179                                 if (!_add("\t"))
180                                         return(0);
181                                 continue;
182                         case 'U':
183                                 if (!_conv((t->tm_yday + 7 - t->tm_wday) / 7,
184                                     2, '0'))
185                                         return(0);
186                                 continue;
187                         case 'W':
188                                 if (!_conv((t->tm_yday + 7 -
189                                     (t->tm_wday ? (t->tm_wday - 1) : 6))
190                                     / 7, 2, '0'))
191                                         return(0);
192                                 continue;
193                         case 'w':
194                                 if (!_conv(t->tm_wday, 1, '0'))
195                                         return(0);
196                                 continue;
197                         case 'x':
198                                 if (!_fmt("%m/%d/%y", t))
199                                         return(0);
200                                 continue;
201                         case 'y':
202                                 if (!_conv((t->tm_year + TM_YEAR_BASE)
203                                     % 100, 2, '0'))
204                                         return(0);
205                                 continue;
206                         case 'Y':
207                                 if (!_conv(t->tm_year + TM_YEAR_BASE, 4, '0'))
208                                         return(0);
209                                 continue;
210                         case 'Z':
211                                 if (!t->tm_zone || !_add(t->tm_zone))
212                                         return(0);
213                                 continue;
214                         case '%':
215                         /*
216                          * X311J/88-090 (4.12.3.5): if conversion char is
217                          * undefined, behavior is undefined.  Print out the
218                          * character itself as printf(3) does.
219                          */
220                         default:
221                                 break;
222                 }
223                 if (!gsize--)
224                         return(0);
225                 *pt++ = *format;
226         }
227         return(gsize);
228 }
229
230 static
231 _conv(n, digits, pad)
232         int n, digits;
233         char pad;
234 {
235         static char buf[10];
236         register char *p;
237
238         for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits)
239                 *p-- = n % 10 + '0';
240         while (p > buf && digits-- > 0)
241                 *p-- = pad;
242         return(_add(++p));
243 }
244
245 static
246 _add(str)
247         register char *str;
248 {
249         for (;; ++pt, --gsize) {
250                 if (!gsize)
251                         return(0);
252                 if (!(*pt = *str++))
253                         return(1);
254         }
255 }