bump to 1.0.0 and clean up spec file
[platform/upstream/libical.git] / src / libical / icalduration.c
1 /* -*- Mode: C -*-
2   ======================================================================
3   FILE: icaltime.c
4   CREATOR: eric 02 June 2000
5   
6   $Id: icalduration.c,v 1.21 2008-01-15 23:17:40 dothebart Exp $
7   $Locker:  $
8     
9  (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
10
11  This program is free software; you can redistribute it and/or modify
12  it under the terms of either: 
13
14     The LGPL as published by the Free Software Foundation, version
15     2.1, available at: http://www.fsf.org/copyleft/lesser.html
16
17   Or:
18
19     The Mozilla Public License Version 1.0. You may obtain a copy of
20     the License at http://www.mozilla.org/MPL/
21
22  The Original Code is eric. The Initial Developer of the Original
23  Code is Eric Busboom
24
25
26  ======================================================================*/
27
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31
32 #include "icalduration.h"
33
34 #include <assert.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38
39 #include "icalerror.h"
40 #include "icalmemory.h"
41 #include "icalvalue.h"
42
43 #if defined(_MSC_VER)
44 #define snprintf _snprintf
45 #endif
46
47 /* From Seth Alves,  <alves@hungry.com>   */
48 struct icaldurationtype icaldurationtype_from_int(int t)
49 {
50     struct icaldurationtype dur;
51     int used = 0;
52
53     dur = icaldurationtype_null_duration();
54
55     if(t < 0){
56         dur.is_neg = 1;
57         t = -t;
58     }
59
60     if (t % (60 * 60 * 24 * 7) == 0) {
61         dur.weeks = t / (60 * 60 * 24 * 7);
62     } else {
63         used += dur.weeks * (60 * 60 * 24 * 7);
64         dur.days = (t - used) / (60 * 60 * 24);
65         used += dur.days * (60 * 60 * 24);
66         dur.hours = (t - used) / (60 * 60);
67         used += dur.hours * (60 * 60);
68         dur.minutes = (t - used) / (60);
69         used += dur.minutes * (60);
70         dur.seconds = (t - used);
71     }
72  
73     return dur;
74 }
75
76 struct icaldurationtype icaldurationtype_from_string(const char* str)
77 {
78
79     int i;
80     int begin_flag = 0;
81     int time_flag = 0;
82     int date_flag = 0;
83     int digits=-1;
84     int scan_size = -1;
85     size_t size = strlen(str);
86     char p;
87     struct icaldurationtype d;
88
89     memset(&d, 0, sizeof(struct icaldurationtype));
90
91     for(i=0;i != size;i++){
92         p = str[i];
93         
94         switch(p) 
95             {
96             case '-': {
97                 if(i != 0 || begin_flag == 1) goto error;
98
99                 d.is_neg = 1;
100                 break;
101             }
102
103             case 'P': {
104                 if (i != 0 && i !=1 ) goto error;
105                 begin_flag = 1;
106                 break;
107             }
108
109             case 'T': {
110                 time_flag = 1;
111                 break;
112             }
113
114             case '0':
115             case '1':
116             case '2':
117             case '3':
118             case '4':
119             case '5':
120             case '6':
121             case '7':
122             case '8':
123             case '9':
124                 { 
125                     
126                     /* HACK. Skip any more digits if the l;ast one
127                        read has not been assigned */
128                     if(digits != -1){
129                         break;
130                     }
131
132                     if (begin_flag == 0) goto error;
133                     /* Get all of the digits, not one at a time */
134                     scan_size = sscanf(&str[i],"%d",&digits);
135                     if(scan_size == 0) goto error;
136                     break;
137                 }
138
139             case 'H': { 
140                 if (time_flag == 0||d.hours !=0||digits ==-1) 
141                     goto error;
142                 d.hours = digits; digits = -1;
143                 break;
144             }
145             case 'M': {
146                 if (time_flag == 0||d.minutes != 0||digits ==-1) 
147                     goto error;
148                 d.minutes = digits; digits = -1;            
149                 break;
150             }
151             case 'S': {
152                 if (time_flag == 0||d.seconds!=0||digits ==-1) 
153                     goto error;
154                 d.seconds = digits; digits = -1;            
155                 break;
156             }
157             case 'W': {
158                 if (time_flag==1||date_flag==1||d.weeks!=0||digits ==-1) 
159                     goto error;
160                 d.weeks = digits; digits = -1;      
161                 break;
162             }
163             case 'D': {
164                 if (time_flag==1||d.days!=0||digits ==-1) 
165                     goto error;
166                 date_flag = 1;
167                 d.days = digits; digits = -1;       
168                 break;
169             }
170             default: {
171                 goto error;
172             }
173
174             }
175     }
176
177     return d;
178         
179
180  error:
181     icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
182     return icaldurationtype_bad_duration();
183 }
184
185 #define TMP_BUF_SIZE 1024
186 static
187 void append_duration_segment(char** buf, char** buf_ptr, size_t* buf_size, 
188                              const char* sep, unsigned int value) {
189
190     char temp[TMP_BUF_SIZE];
191
192     snprintf(temp,sizeof(temp),"%d",value);
193
194     icalmemory_append_string(buf, buf_ptr, buf_size, temp);
195     icalmemory_append_string(buf, buf_ptr, buf_size, sep);
196     
197 }
198
199 char* icaldurationtype_as_ical_string(struct icaldurationtype d) 
200 {
201         char *buf;
202         buf = icaldurationtype_as_ical_string_r(d);
203         icalmemory_add_tmp_buffer(buf);
204         return buf;
205 }
206
207
208 char* icaldurationtype_as_ical_string_r(struct icaldurationtype d) 
209 {
210
211     char *buf;
212     size_t buf_size = 256;
213     char* buf_ptr = 0;
214     int seconds;
215
216     buf = (char*)icalmemory_new_buffer(buf_size);
217     buf_ptr = buf;
218     
219
220     seconds = icaldurationtype_as_int(d);
221
222     if(seconds !=0){
223         
224         if(d.is_neg == 1){
225             icalmemory_append_char(&buf, &buf_ptr, &buf_size, '-'); 
226         }
227
228         icalmemory_append_char(&buf, &buf_ptr, &buf_size, 'P');
229     
230         if (d.weeks != 0 ) {
231             append_duration_segment(&buf, &buf_ptr, &buf_size, "W", d.weeks);
232         }
233         
234         if (d.days != 0 ) {
235             append_duration_segment(&buf, &buf_ptr, &buf_size, "D", d.days);
236         }
237         
238         if (d.hours != 0 || d.minutes != 0 || d.seconds != 0) {
239             
240             icalmemory_append_string(&buf, &buf_ptr, &buf_size, "T");
241             
242             if (d.hours != 0 ) {
243                 append_duration_segment(&buf, &buf_ptr, &buf_size, "H", d.hours);
244             }
245             if (d.minutes != 0 ) {
246                 append_duration_segment(&buf, &buf_ptr, &buf_size, "M", 
247                                         d.minutes);
248             }
249             if (d.seconds != 0 ) {
250                 append_duration_segment(&buf, &buf_ptr, &buf_size, "S", 
251                                         d.seconds);
252             }
253             
254         }
255     } else {
256         icalmemory_append_string(&buf, &buf_ptr, &buf_size, "PT0S");
257     }
258  
259     return buf;
260 }
261
262
263 /* From Russel Steinthal */
264 int icaldurationtype_as_int(struct icaldurationtype dur)
265 {
266     return (int)( (dur.seconds +
267                    (60 * dur.minutes) +
268                    (60 * 60 * dur.hours) +
269                    (60 * 60 * 24 * dur.days) +
270                    (60 * 60 * 24 * 7 * dur.weeks))
271                   * (dur.is_neg==1? -1 : 1) ) ;
272
273
274 struct icaldurationtype icaldurationtype_null_duration(void)
275 {
276     struct icaldurationtype d;
277     
278     memset(&d,0,sizeof(struct icaldurationtype));
279     
280     return d;
281 }
282
283 int icaldurationtype_is_null_duration(struct icaldurationtype d)
284 {
285     if(icaldurationtype_as_int(d) == 0){
286         return 1;
287     } else {
288         return 0;
289     }
290 }
291
292 /* in icalvalue_new_from_string_with_error, we should not call
293    icaldurationtype_is_null_duration() to see if there is an error
294    condition. Null duration is perfectly valid for an alarm.
295    We cannot depend on the caller to check icalerrno either,
296    following the philosophy of unix errno. we set the is_neg
297    to -1 to indicate that this is a bad duration.
298 */
299 struct icaldurationtype icaldurationtype_bad_duration()
300 {
301     struct icaldurationtype d;
302     memset(&d,0,sizeof(struct icaldurationtype));
303     d.is_neg = -1;
304     return d;
305 }
306
307 int icaldurationtype_is_bad_duration(struct icaldurationtype d)
308 {
309     return (d.is_neg == -1);
310 }
311
312
313 struct icaltimetype  icaltime_add(struct icaltimetype t,
314                                   struct icaldurationtype  d)
315 {
316     if (!d.is_neg) {
317         t.second += d.seconds;
318         t.minute += d.minutes;
319         t.hour += d.hours;
320         t.day += d.days;
321         t.day += d.weeks * 7;
322     } else {
323         t.second -= d.seconds;
324         t.minute -= d.minutes;
325         t.hour -= d.hours;
326         t.day -= d.days;
327         t.day -= d.weeks * 7;
328     }
329     
330     t = icaltime_normalize(t);
331     
332     return t;
333 }
334
335 struct icaldurationtype  icaltime_subtract(struct icaltimetype t1,
336                                            struct icaltimetype t2)
337 {
338
339     time_t t1t = icaltime_as_timet(t1);
340     time_t t2t = icaltime_as_timet(t2);
341
342     return icaldurationtype_from_int((int)(t1t-t2t));
343
344
345 }
346