1 /*
  2  *  This program is free software; you can redistribute it and/or modify
  3  *  it under the terms of the GNU General Public License as published by
  4  *  the Free Software Foundation; either version 2 of the License, or
  5  *  (at your option) any later version.
  6  *
  7  *  This program is distributed in the hope that it will be useful,
  8  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 10  *  GNU Library General Public License for more details.
 11  *
 12  *  You should have received a copy of the GNU General Public License
 13  *  along with this program; if not, write to the Free Software
 14  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 15  *
 16  * Copyright (C) 2005-2006 Ralf Huesing <ralf@stormbind.net>
 17  *
 18  */
 19 
 20 #include "rh_string.h"
 21 #include "rh_gmtime.h"
 22 
 23 #define rh_gmtime_write_wday(tm, b)                     \
 24 switch ((tm)->tm_wday) {                                \
 25         case 0: RH_MEMCPY4((b), "Sun,"); break;         \
 26         case 1: RH_MEMCPY4((b), "Mon,"); break;         \
 27         case 2: RH_MEMCPY4((b), "Tue,"); break;         \
 28         case 3: RH_MEMCPY4((b), "Wed,"); break;         \
 29         case 4: RH_MEMCPY4((b), "Thu,"); break;         \
 30         case 5: RH_MEMCPY4((b), "Fri,"); break;         \
 31         case 6: RH_MEMCPY4((b), "Sat,"); break;         \
 32 }
 33 
 34 #define rh_gmtime_write_mday(tm,b)                      \
 35 {                                                       \
 36         (b)[5] = '0' + ((tm)->tm_mday / 10);            \
 37         (b)[6] = '0' + ((tm)->tm_mday % 10);            \
 38 }
 39 
 40 #define rh_gmtime_write_mon(tm, b)                      \
 41 switch ((tm)->tm_mon) {                                 \
 42         case  0: RH_MEMCPY4(&(b)[8], "Jan "); break;    \
 43         case  1: RH_MEMCPY4(&(b)[8], "Feb "); break;    \
 44         case  2: RH_MEMCPY4(&(b)[8], "Mar "); break;    \
 45         case  3: RH_MEMCPY4(&(b)[8], "Apr "); break;    \
 46         case  4: RH_MEMCPY4(&(b)[8], "May "); break;    \
 47         case  5: RH_MEMCPY4(&(b)[8], "Jun "); break;    \
 48         case  6: RH_MEMCPY4(&(b)[8], "Jul "); break;    \
 49         case  7: RH_MEMCPY4(&(b)[8], "Aug "); break;    \
 50         case  8: RH_MEMCPY4(&(b)[8], "Sep "); break;    \
 51         case  9: RH_MEMCPY4(&(b)[8], "Oct "); break;    \
 52         case 10: RH_MEMCPY4(&(b)[8], "Nov "); break;    \
 53         case 11: RH_MEMCPY4(&(b)[8], "Dec "); break;    \
 54 }
 55 
 56 #define rh_gmtime_write_year(tm, b)                     \
 57 {                                                       \
 58         int y = (tm)->tm_year+1900;                     \
 59         (b)[15] = '0' + (y % 10); y /= 10;              \
 60         (b)[14] = '0' + (y % 10); y /= 10;              \
 61         (b)[13] = '0' + (y % 10); y /= 10;              \
 62         (b)[12] = '0' + y;                              \
 63 }
 64 
 65 #define rh_gmtime_write_hour(tm,b)                      \
 66 {                                                       \
 67         (b)[17] = '0' + ((tm)->tm_hour / 10);           \
 68         (b)[18] = '0' + ((tm)->tm_hour % 10);           \
 69 }
 70 
 71 #define rh_gmtime_write_min(tm, b)                      \
 72 {                                                       \
 73         (b)[20] = '0' + ((tm)->tm_min / 10);            \
 74         (b)[21] = '0' + ((tm)->tm_min % 10);            \
 75 }
 76 
 77 #define rh_gmtime_write_sec(tm, b)                      \
 78 {                                                       \
 79         (b)[23] = '0' + ((tm)->tm_sec / 10);            \
 80         (b)[24] = '0' + ((tm)->tm_sec % 10);            \
 81 }
 82 
 83 #if defined(OS_WIN32) || defined(WIN32)
 84 static struct tm * gmtime_r (const time_t *t, struct tm *tm)
 85 {
 86         struct tm *res;
 87         
 88         res = gmtime(t);
 89 
 90         if (res)
 91                 *tm = *res;
 92 
 93         return res;
 94 }
 95 #endif
 96 
 97 void rh_gmtime_init (rh_gmtime_t *gmt, time_t t)
 98 {
 99         if (!gmtime_r (&t, &gmt->tm))
100                 return;
101 
102         gmt->used = GMT_LEN;
103 
104         rh_gmtime_write_wday(&gmt->tm, gmt->data);
105 
106         RH_MEMCPY4(&gmt->data[4], " ?? ");
107         
108         rh_gmtime_write_mday(&gmt->tm, gmt->data);
109 
110         rh_gmtime_write_mon(&gmt->tm, gmt->data);
111 
112         rh_gmtime_write_year(&gmt->tm, gmt->data);
113         
114         gmt->data[16] = ' ';
115         rh_gmtime_write_hour(&gmt->tm, gmt->data);
116         
117         RH_MEMCPY4(&gmt->data[19], ":??:");
118         rh_gmtime_write_min(&gmt->tm, gmt->data);
119         rh_gmtime_write_sec(&gmt->tm, gmt->data);
120 
121         RH_MEMCPY4(&gmt->data[25], " GMT");
122         gmt->data[29]='\0';
123 
124         gmt->t=t;
125 }
126 
127 void rh_gmtime_update (rh_gmtime_t *gmt, time_t t)
128 {
129         struct tm tm; 
130         
131         if (t == gmt->t)
132                 return;
133         
134         gmt->t = t;
135         
136         if (!gmtime_r (&t, &tm))
137                 return;
138         
139         if (tm.tm_wday != gmt->tm.tm_wday) {
140                 rh_gmtime_write_wday(&tm, gmt->data);
141                 gmt->tm.tm_wday = tm.tm_wday;
142         }
143         
144         if (tm.tm_mday != gmt->tm.tm_mday) {
145                 rh_gmtime_write_mday(&tm, gmt->data);
146                 gmt->tm.tm_mday = tm.tm_mday;
147         }
148         
149         if (tm.tm_mon != gmt->tm.tm_mon) {
150                 rh_gmtime_write_mon(&tm, gmt->data);
151                 gmt->tm.tm_mon = tm.tm_mon;
152         }
153                 
154         if (tm.tm_year != gmt->tm.tm_year) {
155                 rh_gmtime_write_year(&tm, gmt->data);
156                 gmt->tm.tm_year = tm.tm_year;
157         }
158 
159         if (tm.tm_hour != gmt->tm.tm_hour) {
160                 rh_gmtime_write_hour(&tm, gmt->data);
161                 gmt->tm.tm_hour = tm.tm_hour;
162         }
163         
164         if (tm.tm_min != gmt->tm.tm_min) {
165                 rh_gmtime_write_min(&tm, gmt->data);
166                 gmt->tm.tm_min = tm.tm_min;
167         }
168         
169         if (tm.tm_sec != gmt->tm.tm_sec) {
170                 rh_gmtime_write_sec(&tm, gmt->data);
171                 gmt->tm.tm_sec = tm.tm_sec;
172         }
173 }
174 
175 int rh_gmtime_reverse (const char *src, size_t nsrc, rh_gmtime_t *out)
176 {
177         if (nsrc != GMT_LEN)
178                 return -1;
179 
180         /*
181          * decode time string into a binary form for comparing
182          *
183          *  01234567890123456789012345678
184          *  0         1         2
185          * 
186          * "Sat, 04 Nov 2006 13:19:58 GMT"
187          *
188          *
189          * how it works:
190          *
191          * - convert the needed parts (month, year, ..) into a struct tm 
192          *   (dont test the values of correctness)
193          * - call mktime() with this tm
194          * - generate a gmtime string with this time
195          * - lowercased compare the strings
196          *   (to test if the genereted gmt matches the given)
197          *
198          */
199 
200 #if 0
201         DEBUGLOG("current[%.*s] header_in[%.*s]",
202                         gmtime->used, gmtime->data,
203                         entry->value.used, entry->value.data);
204 #endif
205 
206         
207         /* not needed because later memcasecmp is called */
208 #if 0
209         if (    ',' != src[ 3] ||
210                 ' ' != src[ 4] ||
211                 ' ' != src[ 7] ||
212                 ' ' != src[11] ||
213                 ' ' != src[16] ||
214                 ':' != src[19] ||
215                 ':' != src[22] )
216         {
217                 return 1;
218         }
219         
220         if (!RH_EQUAL4((src+25)," GMT"))
221                 return 1;
222 #endif  
223         TYPE_ZERO(out);
224 
225 #define DSRC(_off)      (src[(_off)] - '0')
226         
227         out->tm.tm_hour =       DSRC(17) * 10 + DSRC(18);
228         out->tm.tm_min  =       DSRC(20) * 10 + DSRC(21);
229         out->tm.tm_sec  =       DSRC(23) * 10 + DSRC(24);
230 
231         out->tm.tm_mday =       DSRC(5 ) * 10 + DSRC(6);
232         
233         out->tm.tm_year =       (DSRC(12) * 1000 +
234                                  DSRC(13) * 100  +
235                                  DSRC(14) * 10   +
236                                  DSRC(15) * 1     ) - 1900;
237 
238 #undef DSRC
239 
240         /* the easy way to get the month
241          *
242          * the last character is the best one to do this
243          *
244          */
245         switch (src[10]) {
246         case 'n': case 'N':
247                 /* "Jan " "Jun " */
248                 if (src[9] == 'a' || src[9] == 'A')
249                         out->tm.tm_mon = 0;
250                 else
251                         out->tm.tm_mon = 5;
252                 break;
253         case 'b': case 'B':
254                 /* "Feb" */
255                 out->tm.tm_mon = 2;
256                 break;
257         case 'r': case 'R':
258                 /* "Mar " "Apr " */
259                 if (src[9] == 'a' || src[9] == 'A')
260                         out->tm.tm_mon = 2;
261                 else
262                         out->tm.tm_mon = 3;
263                 break;
264         case 'y': case 'Y':
265                 /* "May " */
266                 out->tm.tm_mon = 4;
267                 break;
268         case 'l': case 'L':
269                 /* "Jul " */
270                 out->tm.tm_mon = 6;
271                 break;
272         case 'g': case 'G':
273                 /* "Aug " */
274                 out->tm.tm_mon = 7;
275                 break;
276         case 'p': case 'P':
277                 /* "Sep " */
278                 out->tm.tm_mon = 8;
279                 break;
280         case 't': case 'T':
281                 /* "Oct " */
282                 out->tm.tm_mon = 9;
283         case 'v': case 'V':
284                 /* "Nov " */
285                 out->tm.tm_mon = 10;
286                 break;
287         case 'c': case 'C':
288                 /* "Dec " */
289                 out->tm.tm_mon = 11;
290                 break;
291         default:
292                 return -1;
293         }
294 
295         out->t = mktime(&out->tm);
296         if ((time_t)-1 == out->t)
297                 return -1;
298 
299         rh_gmtime_write_wday(&out->tm, out->data);
300         
301         RH_MEMCPY4(&out->data[4], " ?? ");
302         
303         rh_gmtime_write_mday(&out->tm, out->data);
304         rh_gmtime_write_mon(&out->tm, out->data);
305         rh_gmtime_write_year(&out->tm, out->data);
306         
307         out->data[16] = ' ';
308         rh_gmtime_write_hour(&out->tm, out->data);
309         
310         RH_MEMCPY4(&out->data[19], ":??:");
311         rh_gmtime_write_min(&out->tm, out->data);
312         rh_gmtime_write_sec(&out->tm, out->data);
313 
314         RH_MEMCPY4(&out->data[25], " GMT");
315         out->data[29]='\0';
316         
317         out->used = GMT_LEN;
318 
319         if (0 != rh_memcasecmp(src, out->data, GMT_LEN))
320                 return -1;
321 
322         return 0;
323 }


syntax highlighted by Code2HTML, v. 0.9.1