Initial release of Maemo 5 port of gnuplot
[gnuplot] / src / strftime.c
1 #ifndef lint
2 static char *RCSid() { return RCSid("$Id: strftime.c,v 1.7 2004/07/01 17:10:08 broeker Exp $"); }
3 #endif
4
5 /* GNUPLOT - strftime.c */
6
7 /*[
8  * Copyright 1986 - 1993, 1998, 2004   Thomas Williams, Colin Kelley
9  *
10  * Permission to use, copy, and distribute this software and its
11  * documentation for any purpose with or without fee is hereby granted,
12  * provided that the above copyright notice appear in all copies and
13  * that both that copyright notice and this permission notice appear
14  * in supporting documentation.
15  *
16  * Permission to modify the software is granted, but not the right to
17  * distribute the complete modified source code.  Modifications are to
18  * be distributed as patches to the released version.  Permission to
19  * distribute binaries produced by compiling modified sources is granted,
20  * provided you
21  *   1. distribute the corresponding source modifications from the
22  *    released version in the form of a patch file along with the binaries,
23  *   2. add special version identification to distinguish your version
24  *    in addition to the base release version number,
25  *   3. provide your name and address as the primary contact for the
26  *    support of your modified version, and
27  *   4. retain our contact information in regard to use of the base
28  *    software.
29  * Permission to distribute the released version of the source code along
30  * with corresponding source modifications in the form of a patch file is
31  * granted with same provisions 2 through 4 for binary distributions.
32  *
33  * This software is provided "as is" without express or implied warranty
34  * to the extent permitted by applicable law.
35 ]*/
36
37 /*
38  * Implementation of strftime for systems missing this (e.g. vaxctrl)
39  *
40  * This code was written based on the NeXT strftime man-page, sample output of
41  * the function and an ANSI-C quickreference chart. This code does not use
42  * parts of any existing strftime implementation.
43  *
44  * Apparently not all format chars are implemented, but this was all I had in
45  * my documentation.
46  *
47  * (written by Alexander Lehmann)
48  */
49
50 #define NOTIMEZONE
51
52 #include "syscfg.h"             /* for MAX_LINE_LEN */
53 #include "stdfn.h"              /* for safe_strncpy */
54
55 #ifdef TEST_STRFTIME            /* test case; link with stdfn */
56 #define strftime _strftime
57
58
59 #include "national.h"           /* language info for the following, */
60                         /* extracted from set.c */
61
62 char full_month_names[12][32] =
63 {FMON01, FMON02, FMON03, FMON04, FMON05,
64  FMON06, FMON07, FMON08, FMON09, FMON10, FMON11, FMON12};
65 char abbrev_month_names[12][8] =
66 {AMON01, AMON02, AMON03, AMON04, AMON05,
67  AMON06, AMON07, AMON08, AMON09, AMON10, AMON11, AMON12};
68
69 char full_day_names[7][32] =
70 {FDAY0, FDAY1, FDAY2, FDAY3, FDAY4, FDAY5, FDAY6};
71 char abbrev_day_names[7][8] =
72 {ADAY0, ADAY1, ADAY2, ADAY3, ADAY4, ADAY5, ADAY6};
73
74 #endif /* TEST_STRFTIME */
75
76 static void fill __PROTO((char *from, char **pto, size_t *pmaxsize));
77 static void number __PROTO((int num, int pad, char **pto, size_t *pmaxsize));
78
79 static void
80 fill(char *from, char **pto, size_t *pmaxsize)
81 {
82     safe_strncpy(*pto, from, *pmaxsize);
83     if (*pmaxsize < strlen(from)) {
84         (*pto) += *pmaxsize;
85         *pmaxsize = 0;
86     } else {
87         (*pto) += strlen(from);
88         (*pmaxsize) -= strlen(from);
89     }
90 }
91
92 static void
93 number(int num, int pad, char **pto, size_t *pmaxsize)
94 {
95     char str[100];
96
97     sprintf(str, "%0*d", pad, num);
98     fill(str, pto, pmaxsize);
99 }
100
101 size_t
102 strftime(char *s, size_t max, const char *format, const struct tm *tp)
103 {
104     char *start = s;
105     size_t maxsize = max;
106
107     if (max > 0) {
108         while (*format && max > 0) {
109             if (*format != '%') {
110                 *s++ = *format++;
111                 max--;
112             } else {
113                 format++;
114                 switch (*format++) {
115                 case 'a':       /* abbreviated weekday name */
116                     if (tp->tm_wday >= 0 && tp->tm_wday <= 6)
117                         fill(abbrev_day_names[tp->tm_wday], &s, &max);
118                     break;
119                 case 'A':       /* full name of the weekday */
120                     if (tp->tm_wday >= 0 && tp->tm_wday <= 6)
121                         fill(full_day_names[tp->tm_wday], &s, &max);
122                     break;
123                 case 'b':       /* abbreviated month name */
124                     if (tp->tm_mon >= 0 && tp->tm_mon <= 11)
125                         fill(abbrev_month_names[tp->tm_mon], &s, &max);
126                     break;
127                 case 'B':       /* full name of month */
128                     if (tp->tm_mon >= 0 && tp->tm_mon <= 11)
129                         fill(full_month_names[tp->tm_mon], &s, &max);
130                     break;
131                 case 'c':       /* locale's date and time reprensentation */
132                     strftime(s, max, "%a %b %X %Y", tp);
133                     max -= strlen(s);
134                     s += strlen(s);
135                     break;
136                 case 'd':       /* day of the month (01-31) */
137                     number(tp->tm_mday, 2, &s, &max);
138                     break;
139                 case 'H':       /* hour of the day (00-23) */
140                     number(tp->tm_hour, 2, &s, &max);
141                     break;
142                 case 'I':       /* hour of the day (01-12) */
143                     number((tp->tm_hour + 11) % 12 + 1, 2, &s, &max);
144                     break;
145                 case 'j':       /* day of the year (001-366) */
146                     number(tp->tm_yday + 1, 3, &s, &max);
147                     break;
148                 case 'm':       /* month of the year (01-12) */
149                     number(tp->tm_mon + 1, 2, &s, &max);
150                     break;
151                 case 'M':       /* minute (00-59) */
152                     number(tp->tm_min, 2, &s, &max);
153                     break;
154                 case 'p':       /* locale's version of AM or PM */
155                     fill(tp->tm_hour >= 6 ? "PM" : "AM", &s, &max);
156                     break;
157                 case 'S':       /* seconds (00-59) */
158                     number(tp->tm_sec, 2, &s, &max);
159                     break;
160                 case 'U':       /* week number of the year (00-53) with Sunday as the first day of the week */
161                     number((tp->tm_yday - (tp->tm_yday - tp->tm_wday + 7) % 7 + 7) / 7, 1, &s, &max);
162                     break;
163                 case 'w':       /* weekday (Sunday = 0 to Saturday = 6) */
164                     number(tp->tm_wday, 1, &s, &max);
165                     break;
166                 case 'W':       /* week number of the year (00-53) with Monday as the first day of the week */
167                     number((tp->tm_yday - (tp->tm_yday - tp->tm_wday + 8) % 7 + 7) / 7, 2, &s, &max);
168                     break;
169                 case 'x':       /* locale's date representation */
170                     strftime(s, max, "%a %b %d %Y", tp);
171                     max -= strlen(s);
172                     s += strlen(s);
173                     break;
174                 case 'X':       /* locale's time representation */
175 #ifndef NOTIMEZONE
176                     strftime(s, max, "%H:%M:%S %Z", tp);
177 #else
178                     strftime(s, max, "%H:%M:%S", tp);
179 #endif
180                     max -= strlen(s);
181                     s += strlen(s);
182                     break;
183                 case 'y':       /* two-digit year representation (00-99) */
184                     number(tp->tm_year % 100, 2, &s, &max);
185                     break;
186                 case 'Y':       /* four-digit year representation */
187                     number(tp->tm_year + 1900, 2, &s, &max);
188                     break;
189 #ifndef NOTIMEZONE
190                 case 'Z':       /* time zone name */
191                     fill(tp->tm_zone, &s, &max);
192                     break;
193 #endif
194                 case '%':       /* percent sign */
195                 default:
196                     *s++ = *(format - 1);
197                     max--;
198                     break;
199                 }
200             }
201         }
202         if (s - start < maxsize) {
203             *s++ = '\0';
204         } else {
205             *(s - 1) = '\0';
206         }
207     }
208     return s - start;
209 }
210
211 #ifdef TEST_STRFTIME
212
213 #undef strftime
214 #define test(s)                         \
215         printf("%s -> ",s );            \
216         _strftime(str, 100, s, ts);     \
217         printf("%s - ", str);           \
218         strftime(str, 100, s, ts);      \
219         printf("%s\n", str)
220
221 int
222 main()
223 {
224     char str[100];
225     struct tm *ts;
226     time_t t;
227     int i;
228
229     t = time(NULL);
230
231     ts = localtime(&t);
232
233     test("%c");
234     test("test%%test");
235     test("%a %b %d %X %Y");
236     test("%x %X");
237     test("%A %B %U");
238     test("%I:%M %p %j %w");
239
240     t -= 245 * 24 * 60 * 60;
241
242     for (i = 0; i < 366; i++) {
243         ts = localtime(&t);
244         printf("%03d: ", i);
245         test("%a %d %m %W");
246         t += 24 * 60 * 60;
247     }
248
249     return 0;
250 }
251
252 #endif