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