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 #ifdef WIN32
44 #if defined(_MSC_VER) && (_MSC_VER < 1900)
45 #define snprintf _snprintf
46 #endif
47 #endif
48
49
50
51 /* From Seth Alves, <alves@hungry.com> */
icaldurationtype_from_int(int t)52 struct icaldurationtype icaldurationtype_from_int(int t)
53 {
54 struct icaldurationtype dur;
55 int used = 0;
56
57 dur = icaldurationtype_null_duration();
58
59 if(t < 0){
60 dur.is_neg = 1;
61 t = -t;
62 }
63
64 if (t % (60 * 60 * 24 * 7) == 0) {
65 dur.weeks = t / (60 * 60 * 24 * 7);
66 } else {
67 used += dur.weeks * (60 * 60 * 24 * 7);
68 dur.days = (t - used) / (60 * 60 * 24);
69 used += dur.days * (60 * 60 * 24);
70 dur.hours = (t - used) / (60 * 60);
71 used += dur.hours * (60 * 60);
72 dur.minutes = (t - used) / (60);
73 used += dur.minutes * (60);
74 dur.seconds = (t - used);
75 }
76
77 return dur;
78 }
79
icaldurationtype_from_string(const char * str)80 struct icaldurationtype icaldurationtype_from_string(const char* str)
81 {
82
83 int i;
84 int begin_flag = 0;
85 int time_flag = 0;
86 int date_flag = 0;
87 int week_flag = 0;
88 int digits=-1;
89 int scan_size = -1;
90 int size = strlen(str);
91 char p;
92 struct icaldurationtype d;
93
94 memset(&d, 0, sizeof(struct icaldurationtype));
95
96 for(i=0;i != size;i++){
97 p = str[i];
98
99 switch(p)
100 {
101 case '-': {
102 if(i != 0 || begin_flag == 1) goto error;
103
104 d.is_neg = 1;
105 break;
106 }
107
108 case 'P': {
109 if (i != 0 && i !=1 ) goto error;
110 begin_flag = 1;
111 break;
112 }
113
114 case 'T': {
115 time_flag = 1;
116 break;
117 }
118
119 case '0':
120 case '1':
121 case '2':
122 case '3':
123 case '4':
124 case '5':
125 case '6':
126 case '7':
127 case '8':
128 case '9':
129 {
130
131 /* HACK. Skip any more digits if the l;ast one
132 read has not been assigned */
133 if(digits != -1){
134 break;
135 }
136
137 if (begin_flag == 0) goto error;
138 /* Get all of the digits, not one at a time */
139 scan_size = sscanf(&str[i],"%d",&digits);
140 if(scan_size == 0) goto error;
141 break;
142 }
143
144 case 'H': {
145 if (time_flag == 0||week_flag == 1||d.hours !=0||digits ==-1)
146 goto error;
147 d.hours = digits; digits = -1;
148 break;
149 }
150 case 'M': {
151 if (time_flag == 0||week_flag==1||d.minutes != 0||digits ==-1)
152 goto error;
153 d.minutes = digits; digits = -1;
154 break;
155 }
156 case 'S': {
157 if (time_flag == 0||week_flag==1||d.seconds!=0||digits ==-1)
158 goto error;
159 d.seconds = digits; digits = -1;
160 break;
161 }
162 case 'W': {
163 if (time_flag==1||date_flag==1||d.weeks!=0||digits ==-1)
164 goto error;
165 week_flag = 1;
166 d.weeks = digits; digits = -1;
167 break;
168 }
169 case 'D': {
170 if (time_flag==1||week_flag==1||d.days!=0||digits ==-1)
171 goto error;
172 date_flag = 1;
173 d.days = digits; digits = -1;
174 break;
175 }
176 default: {
177 goto error;
178 }
179
180 }
181 }
182
183 return d;
184
185
186 error:
187 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
188 return icaldurationtype_bad_duration();
189 }
190
191 #define TMP_BUF_SIZE 1024
192 static
append_duration_segment(char ** buf,char ** buf_ptr,size_t * buf_size,const char * sep,unsigned int value)193 void append_duration_segment(char** buf, char** buf_ptr, size_t* buf_size,
194 const char* sep, unsigned int value) {
195
196 char temp[TMP_BUF_SIZE];
197
198 snprintf(temp,sizeof(temp),"%d",value);
199
200 icalmemory_append_string(buf, buf_ptr, buf_size, temp);
201 icalmemory_append_string(buf, buf_ptr, buf_size, sep);
202
203 }
204
icaldurationtype_as_ical_string(struct icaldurationtype d)205 char* icaldurationtype_as_ical_string(struct icaldurationtype d)
206 {
207 char *buf;
208 buf = icaldurationtype_as_ical_string_r(d);
209 icalmemory_add_tmp_buffer(buf);
210 return buf;
211 }
212
213
icaldurationtype_as_ical_string_r(struct icaldurationtype d)214 char* icaldurationtype_as_ical_string_r(struct icaldurationtype d)
215 {
216
217 char *buf;
218 size_t buf_size = 256;
219 char* buf_ptr = 0;
220 int seconds;
221
222 buf = (char*)icalmemory_new_buffer(buf_size);
223 buf_ptr = buf;
224
225
226 seconds = icaldurationtype_as_int(d);
227
228 if(seconds !=0){
229
230 if(d.is_neg == 1){
231 icalmemory_append_char(&buf, &buf_ptr, &buf_size, '-');
232 }
233
234 icalmemory_append_char(&buf, &buf_ptr, &buf_size, 'P');
235
236 if (d.weeks != 0 ) {
237 append_duration_segment(&buf, &buf_ptr, &buf_size, "W", d.weeks);
238 }
239
240 if (d.days != 0 ) {
241 append_duration_segment(&buf, &buf_ptr, &buf_size, "D", d.days);
242 }
243
244 if (d.hours != 0 || d.minutes != 0 || d.seconds != 0) {
245
246 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "T");
247
248 if (d.hours != 0 ) {
249 append_duration_segment(&buf, &buf_ptr, &buf_size, "H", d.hours);
250 }
251 if (d.minutes != 0 ) {
252 append_duration_segment(&buf, &buf_ptr, &buf_size, "M",
253 d.minutes);
254 }
255 if (d.seconds != 0 ) {
256 append_duration_segment(&buf, &buf_ptr, &buf_size, "S",
257 d.seconds);
258 }
259
260 }
261 } else {
262 icalmemory_append_string(&buf, &buf_ptr, &buf_size, "PT0S");
263 }
264
265 return buf;
266 }
267
268
269 /* From Russel Steinthal */
icaldurationtype_as_int(struct icaldurationtype dur)270 int icaldurationtype_as_int(struct icaldurationtype dur)
271 {
272 return (int)( (dur.seconds +
273 (60 * dur.minutes) +
274 (60 * 60 * dur.hours) +
275 (60 * 60 * 24 * dur.days) +
276 (60 * 60 * 24 * 7 * dur.weeks))
277 * (dur.is_neg==1? -1 : 1) ) ;
278 }
279
icaldurationtype_null_duration(void)280 struct icaldurationtype icaldurationtype_null_duration(void)
281 {
282 struct icaldurationtype d;
283
284 memset(&d,0,sizeof(struct icaldurationtype));
285
286 return d;
287 }
288
icaldurationtype_is_null_duration(struct icaldurationtype d)289 int icaldurationtype_is_null_duration(struct icaldurationtype d)
290 {
291 if(icaldurationtype_as_int(d) == 0){
292 return 1;
293 } else {
294 return 0;
295 }
296 }
297
298 /* in icalvalue_new_from_string_with_error, we should not call
299 icaldurationtype_is_null_duration() to see if there is an error
300 condition. Null duration is perfectly valid for an alarm.
301 We cannot depend on the caller to check icalerrno either,
302 following the philosophy of unix errno. we set the is_neg
303 to -1 to indicate that this is a bad duration.
304 */
icaldurationtype_bad_duration()305 struct icaldurationtype icaldurationtype_bad_duration()
306 {
307 struct icaldurationtype d;
308 memset(&d,0,sizeof(struct icaldurationtype));
309 d.is_neg = -1;
310 return d;
311 }
312
icaldurationtype_is_bad_duration(struct icaldurationtype d)313 int icaldurationtype_is_bad_duration(struct icaldurationtype d)
314 {
315 return (d.is_neg == -1);
316 }
317
318
icaltime_add(struct icaltimetype t,struct icaldurationtype d)319 struct icaltimetype icaltime_add(struct icaltimetype t,
320 struct icaldurationtype d)
321 {
322 if (!d.is_neg) {
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 } else {
329 t.second -= d.seconds;
330 t.minute -= d.minutes;
331 t.hour -= d.hours;
332 t.day -= d.days;
333 t.day -= d.weeks * 7;
334 }
335
336 t = icaltime_normalize(t);
337
338 return t;
339 }
340
icaltime_subtract(struct icaltimetype t1,struct icaltimetype t2)341 struct icaldurationtype icaltime_subtract(struct icaltimetype t1,
342 struct icaltimetype t2)
343 {
344
345 time_t t1t = icaltime_as_timet(t1);
346 time_t t2t = icaltime_as_timet(t2);
347
348 return icaldurationtype_from_int((int)(t1t-t2t));
349
350
351 }
352
353