1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vi:set ts=4 sts=4 sw=4 expandtab : */
3 /*======================================================================
5 CREATOR: eric 02 May 1999
7 $Id: icalvalue.c,v 1.44 2008-01-15 23:17:43 dothebart Exp $
10 (C) COPYRIGHT 2000, Eric Busboom <eric@softwarestudio.org>
11 http://www.softwarestudio.org
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of either:
16 The LGPL as published by the Free Software Foundation, version
17 2.1, available at: http://www.fsf.org/copyleft/lesser.html
21 The Mozilla Public License Version 1.0. You may obtain a copy of
22 the License at http://www.mozilla.org/MPL/
24 The original code is icalvalue.c
27 Graham Davison <g.m.davison@computer.org>
30 ======================================================================*/
36 #include "icalerror.h"
37 #include "icalmemory.h"
38 #include "icalparser.h"
39 #include "icalenums.h"
40 #include "icalvalueimpl.h"
42 #include <stdlib.h> /* for malloc */
43 #include <stdio.h> /* for snprintf */
44 #include <string.h> /* For memset, others */
45 #include <stddef.h> /* For offsetof() macro */
47 #include <time.h> /* for mktime */
48 #include <stdlib.h> /* for atoi and atof */
49 #include <limits.h> /* for SHRT_MAX */
51 #include <ctype.h> /* for isspace and isdigit */
54 #define snprintf _snprintf
55 #define strcasecmp stricmp
59 #include "icalmemory_strdup.h"
62 #define TMP_BUF_SIZE 1024
64 void print_datetime_to_string(char* str, const struct icaltimetype *data);
65 void print_date_to_string(char* str, const struct icaltimetype *data);
66 void print_time_to_string(char* str, const struct icaltimetype *data);
69 struct icalvalue_impl* icalvalue_new_impl(icalvalue_kind kind){
71 struct icalvalue_impl* v;
73 if (!icalvalue_kind_is_valid(kind))
76 if ( ( v = (struct icalvalue_impl*)
77 malloc(sizeof(struct icalvalue_impl))) == 0) {
78 icalerror_set_errno(ICAL_NEWFAILED_ERROR);
88 memset(&(v->data),0,sizeof(v->data));
97 icalvalue_new (icalvalue_kind kind)
99 return (icalvalue*)icalvalue_new_impl(kind);
102 icalvalue* icalvalue_new_clone(const icalvalue* old) {
103 struct icalvalue_impl* new;
105 new = icalvalue_new_impl(old->kind);
111 strcpy(new->id, old->id);
112 new->kind = old->kind;
113 new->size = old->size;
116 case ICAL_ATTACH_VALUE:
117 case ICAL_BINARY_VALUE:
119 /* Hmm. We just ref the attach value, which may not be the right
120 * thing to do. We cannot quite copy the data, anyways, since we
121 * don't know how long it is.
123 new->data.v_attach = old->data.v_attach;
124 if (new->data.v_attach)
125 icalattach_ref (new->data.v_attach);
129 case ICAL_QUERY_VALUE:
130 case ICAL_STRING_VALUE:
131 case ICAL_TEXT_VALUE:
132 case ICAL_CALADDRESS_VALUE:
135 if (old->data.v_string != 0) {
136 new->data.v_string=icalmemory_strdup(old->data.v_string);
138 if ( new->data.v_string == 0 ) {
146 case ICAL_ACTION_VALUE:
148 new->data = old->data;
150 if (old->data.v_enum == ICAL_ACTION_X) {
151 //preserve the custom action string
152 if (old->x_value != 0) {
153 new->x_value = icalmemory_strdup(old->x_value);
155 if (new->x_value == 0) {
163 case ICAL_RECUR_VALUE:
165 if(old->data.v_recur != 0){
166 new->data.v_recur = malloc(sizeof(struct icalrecurrencetype));
168 if(new->data.v_recur == 0){
173 memcpy( new->data.v_recur, old->data.v_recur,
174 sizeof(struct icalrecurrencetype));
181 if (old->x_value != 0) {
182 new->x_value=icalmemory_strdup(old->x_value);
184 if (new->x_value == 0) {
195 /* all of the other types are stored as values, not
196 pointers, so we can just copy the whole structure. */
198 new->data = old->data;
205 static char* icalmemory_strdup_and_dequote(const char* str)
208 char* out = (char*)malloc(sizeof(char) * strlen(str) +1);
218 /* Stop the loop when encountering a terminator in the source string
219 or if a null has been written to the destination. This prevents
220 reading past the end of the source string if the last character
222 for (p = str; !wroteNull && *p!=0; p++){
230 wroteNull = 1; //stops iteration so p isn't incremented past the end of str
292 * Returns a quoted copy of a string
293 * @todo This is not RFC2445 compliant.
294 * The RFC only allows:
295 * TSAFE-CHAR = %x20-21 / %x23-2B / %x2D-39 / %x3C-5B / %x5D-7E / NON-US-ASCII
296 * As such, \t\r\b\f are not allowed, not even escaped
298 static char* icalmemory_strdup_and_quote(const icalvalue* value,
299 const char* unquoted_str)
306 buf_sz = strlen(unquoted_str)+1;
308 str_p = str = (char*)icalmemory_new_buffer(buf_sz);
314 for(p=unquoted_str; *p!=0; p++){
318 icalmemory_append_string(&str,&str_p,&buf_sz,"\\n");
323 icalmemory_append_string(&str,&str_p,&buf_sz,"\\t");
327 icalmemory_append_string(&str,&str_p,&buf_sz,"\\r");
331 icalmemory_append_string(&str,&str_p,&buf_sz,"\\b");
335 icalmemory_append_string(&str,&str_p,&buf_sz,"\\f");
341 /* unescaped COMMA is allowed in CATEGORIES property as its
342 considered a list delimiter here, see:
343 http://tools.ietf.org/html/rfc2445#section-4.3.11 */
344 if (icalproperty_isa(value->parent) == ICAL_CATEGORIES_PROPERTY) {
345 icalmemory_append_char(&str,&str_p,&buf_sz,*p);
350 icalmemory_append_char(&str,&str_p,&buf_sz,'\\');
351 icalmemory_append_char(&str,&str_p,&buf_sz,*p);
356 icalmemory_append_char(&str,&str_p,&buf_sz,*p);
361 /* Assume the last character is not a '\0' and add one. We could
362 check *str_p != 0, but that would be an uninitialized memory
365 icalmemory_append_char(&str,&str_p,&buf_sz,'\0');
372 * This is a bad API, as it forces callers to specify their own X type.
373 * This function should take care of this by itself.
376 icalvalue* icalvalue_new_enum(icalvalue_kind kind, int x_type, const char* str)
378 int e = icalproperty_kind_and_string_to_enum(kind, str);
379 struct icalvalue_impl *value;
381 if(e != 0 && icalproperty_enum_belongs_to_property(
382 icalproperty_value_kind_to_kind(kind),e)) {
384 value = icalvalue_new_impl(kind);
385 value->data.v_enum = e;
387 /* Make it an X value */
388 value = icalvalue_new_impl(kind);
389 value->data.v_enum = x_type;
390 icalvalue_set_x(value,str);
397 * Transforms a simple float number string into a double.
398 * The decimal separator (if any) of the double has to be '.'
399 * The code is locale *independant* and does *not* change the locale.
400 * It should be thread safe.
401 * If you want a code that that does the same job with a decimal separator
402 * dependant on the current locale, then use strtof() from libc.
404 int simple_str_to_double(const char* from,
408 #define TMP_NUM_SIZE 100
409 char *start=NULL, *end=NULL, *cur=(char*)from ;
410 char tmp_buf[TMP_NUM_SIZE+1] ; /*hack*/
412 struct lconv *loc_data = localeconv () ;
417 if (!from || !result) {
421 /*skip the white spaces at the beginning*/
422 while (cur && isspace (*cur))
427 * copy the part that looks like a double into tmp_buf
428 * so that we can call strtof() on it.
429 * during the copy, we give ourselves a chance to convert the '.'
430 * into the decimal separator of the current locale.
432 while (cur && (isdigit (*cur) ||
439 if (end - start + 1> 100) {
440 /*huh hoh, number is too big. getting out*/
443 memset(tmp_buf, 0, TMP_NUM_SIZE+1) ;
446 * copy the float number string into tmp_buf, and take
447 * care to have the (optional) decimal separator be the one
448 * of the current locale.
451 for (i=0 ; i < end - from ;++i) {
454 && loc_data->decimal_point
455 && loc_data->decimal_point[0]
456 && loc_data->decimal_point[0] != '.') {
457 /*replace '.' by the digit separator of the current locale*/
458 tmp_buf[i] = loc_data->decimal_point[0] ;
460 tmp_buf[i] = start[i] ;
464 GetNumberFormat(LOCALE_SYSTEM_DEFAULT,0,start, NULL, tmp_buf,TMP_NUM_SIZE);
468 *result = atof(tmp_buf) ;
472 icalvalue* icalvalue_new_from_string_with_error(icalvalue_kind kind,const char* str,icalproperty** error)
475 struct icalvalue_impl *value = 0;
477 icalerror_check_arg_rz(str!=0,"str");
485 case ICAL_ATTACH_VALUE:
489 attach = icalattach_new_from_url (str);
493 value = icalvalue_new_attach (attach);
494 icalattach_unref (attach);
498 case ICAL_BINARY_VALUE:
501 attach = icalattach_new_from_data (str, 0, 0);
504 value = icalvalue_new_attach (attach);
505 icalattach_unref (attach);
508 case ICAL_BOOLEAN_VALUE:
514 char temp[TMP_BUF_SIZE];
515 snprintf(temp,sizeof(temp),"%s Values are not implemented",
516 icalvalue_kind_to_string(kind));
517 *error = icalproperty_vanew_xlicerror(
519 icalparameter_new_xlicerrortype(
520 ICAL_XLICERRORTYPE_VALUEPARSEERROR),
527 case ICAL_TRANSP_VALUE:
528 value = icalvalue_new_enum(kind, (int)ICAL_TRANSP_X,str);
530 case ICAL_METHOD_VALUE:
531 value = icalvalue_new_enum(kind, (int)ICAL_METHOD_X,str);
533 case ICAL_STATUS_VALUE:
534 value = icalvalue_new_enum(kind, (int)ICAL_STATUS_X,str);
536 case ICAL_ACTION_VALUE:
537 value = icalvalue_new_enum(kind, (int)ICAL_ACTION_X,str);
540 case ICAL_QUERY_VALUE:
541 value = icalvalue_new_query(str);
544 case ICAL_CLASS_VALUE:
545 value = icalvalue_new_enum(kind, (int)ICAL_CLASS_X,str);
548 value = icalvalue_new_enum(kind, ICAL_CMD_X,str);
550 case ICAL_QUERYLEVEL_VALUE:
551 value = icalvalue_new_enum(kind, ICAL_QUERYLEVEL_X,str);
553 case ICAL_CARLEVEL_VALUE:
554 value = icalvalue_new_enum(kind, ICAL_CARLEVEL_X,str);
557 case ICAL_INTEGER_VALUE:
558 value = icalvalue_new_integer(atoi(str));
561 case ICAL_FLOAT_VALUE:
562 value = icalvalue_new_float((float)atof(str));
565 case ICAL_UTCOFFSET_VALUE:
567 int t,utcoffset, hours, minutes, seconds;
568 /* treat the UTCOFSET string a a decimal number, disassemble its digits
569 and reconstruct it as sections */
570 t = strtol(str,0,10);
571 /* add phantom seconds field */
572 if(abs(t)<9999){t *= 100; }
574 minutes = (t-hours*10000)/100;
575 seconds = (t-hours*10000-minutes*100);
576 utcoffset = hours*3600+minutes*60+seconds;
578 value = icalvalue_new_utcoffset(utcoffset);
583 case ICAL_TEXT_VALUE:
585 char* dequoted_str = icalmemory_strdup_and_dequote(str);
586 value = icalvalue_new_text(dequoted_str);
591 case ICAL_STRING_VALUE:
592 value = icalvalue_new_string(str);
595 case ICAL_CALADDRESS_VALUE:
596 value = icalvalue_new_caladdress(str);
600 value = icalvalue_new_uri(str);
606 struct icalgeotype geo = {0.0, 0.0};
608 if (simple_str_to_double (str, &geo.lat, &cur)) {
609 goto geo_parsing_error ;
612 /*skip white spaces*/
613 while (cur && isspace (*cur)) {
617 /*there is a ';' between the latitude and longitude parts*/
618 if (!cur || *cur != ';') {
619 goto geo_parsing_error ;
624 goto geo_parsing_error ;
626 /*skip white spaces*/
627 while (cur && isspace (*cur)) {
631 if (simple_str_to_double (cur, &geo.lon, &cur)) {
632 goto geo_parsing_error ;
634 value = icalvalue_new_geo (geo) ;
639 char temp[TMP_BUF_SIZE];
640 sprintf(temp, "Could not parse %s as a %s property",
641 str, icalvalue_kind_to_string(kind));
642 *error = icalproperty_vanew_xlicerror(
644 icalparameter_new_xlicerrortype(
645 ICAL_XLICERRORTYPE_VALUEPARSEERROR),
651 case ICAL_RECUR_VALUE:
653 struct icalrecurrencetype rt;
654 rt = icalrecurrencetype_from_string(str);
655 if(rt.freq != ICAL_NO_RECURRENCE){
656 value = icalvalue_new_recur(rt);
661 case ICAL_DATE_VALUE:
662 case ICAL_DATETIME_VALUE:
664 struct icaltimetype tt;
666 tt = icaltime_from_string(str);
667 if(!icaltime_is_null_time(tt)){
668 value = icalvalue_new_impl(kind);
669 value->data.v_time = tt;
671 icalvalue_reset_kind(value);
676 case ICAL_DATETIMEPERIOD_VALUE:
678 struct icaltimetype tt;
679 struct icalperiodtype p;
680 tt = icaltime_from_string(str);
682 if(!icaltime_is_null_time(tt)){
683 value = icalvalue_new_datetime(tt);
687 p = icalperiodtype_from_string(str);
688 if (!icalperiodtype_is_null_period(p)){
689 value = icalvalue_new_period(p);
695 case ICAL_DURATION_VALUE:
697 struct icaldurationtype dur = icaldurationtype_from_string(str);
699 if (!icaldurationtype_is_bad_duration(dur)) { /* failed to parse */
700 value = icalvalue_new_duration(dur);
706 case ICAL_PERIOD_VALUE:
708 struct icalperiodtype p;
709 p = icalperiodtype_from_string(str);
711 if(!icalperiodtype_is_null_period(p)){
712 value = icalvalue_new_period(p);
717 case ICAL_TRIGGER_VALUE:
719 struct icaltriggertype tr = icaltriggertype_from_string(str);
720 if (!icaltriggertype_is_bad_trigger(tr)) {
721 value = icalvalue_new_trigger(tr);
726 case ICAL_REQUESTSTATUS_VALUE:
728 struct icalreqstattype rst = icalreqstattype_from_string(str);
729 if(rst.code != ICAL_UNKNOWN_STATUS){
730 value = icalvalue_new_requeststatus(rst);
738 char* dequoted_str = icalmemory_strdup_and_dequote(str);
739 value = icalvalue_new_x(dequoted_str);
747 char temp[TMP_BUF_SIZE];
749 snprintf(temp,TMP_BUF_SIZE,"Unknown type for \'%s\'",str);
751 *error = icalproperty_vanew_xlicerror(
753 icalparameter_new_xlicerrortype(
754 ICAL_XLICERRORTYPE_VALUEPARSEERROR),
758 icalerror_warn("icalvalue_new_from_string got an unknown value type");
764 if (error != 0 && *error == 0 && value == 0){
765 char temp[TMP_BUF_SIZE];
767 snprintf(temp,TMP_BUF_SIZE,"Failed to parse value: \'%s\'",str);
769 *error = icalproperty_vanew_xlicerror(
771 icalparameter_new_xlicerrortype(
772 ICAL_XLICERRORTYPE_VALUEPARSEERROR),
781 icalvalue* icalvalue_new_from_string(icalvalue_kind kind,const char* str)
783 return icalvalue_new_from_string_with_error(kind,str,(icalproperty**)0);
789 icalvalue_free (icalvalue* v)
791 icalerror_check_arg_rv((v != 0),"value");
793 #ifdef ICAL_FREE_ON_LIST_IS_ERROR
794 icalerror_assert( (v->parent ==0),"This value is still attached to a property");
807 case ICAL_BINARY_VALUE:
808 case ICAL_ATTACH_VALUE: {
809 if (v->data.v_attach) {
810 icalattach_unref (v->data.v_attach);
811 v->data.v_attach = NULL;
816 case ICAL_TEXT_VALUE:
817 case ICAL_CALADDRESS_VALUE:
819 case ICAL_STRING_VALUE:
820 case ICAL_QUERY_VALUE:
822 if (v->data.v_string != 0) {
823 free((void*)v->data.v_string);
824 v->data.v_string = 0;
828 case ICAL_RECUR_VALUE:
830 if(v->data.v_recur != 0){
831 free((void*)v->data.v_recur);
843 v->kind = ICAL_NO_VALUE;
846 memset(&(v->data),0,sizeof(v->data));
852 icalvalue_is_valid (const icalvalue* value)
861 static char* icalvalue_binary_as_ical_string_r(const icalvalue* value) {
865 icalerror_check_arg_rz( (value!=0),"value");
867 data = icalvalue_get_binary(value);
869 str = (char*)icalmemory_new_buffer(60);
870 snprintf(str, 60,"icalvalue_binary_as_ical_string is not implemented yet");
876 #define MAX_INT_DIGITS 12 /* Enough for 2^32 + sign*/
878 static char* icalvalue_int_as_ical_string_r(const icalvalue* value) {
882 icalerror_check_arg_rz( (value!=0),"value");
883 str = (char*)icalmemory_new_buffer(MAX_INT_DIGITS);
885 data = icalvalue_get_integer(value);
887 snprintf(str,MAX_INT_DIGITS,"%d",data);
893 static char* icalvalue_utcoffset_as_ical_string_r(const icalvalue* value)
899 icalerror_check_arg_rz( (value!=0),"value");
901 str = (char*)icalmemory_new_buffer(9);
902 data = icalvalue_get_utcoffset(value);
904 if (abs(data) == data){
911 m = (data - (h*3600))/ 60;
912 s = (data - (h*3600) - (m*60));
915 snprintf(str,9,"%c%02d%02d%02d",sign,abs(h),abs(m),abs(s));
917 snprintf(str,9,"%c%02d%02d",sign,abs(h),abs(m));
922 static char* icalvalue_string_as_ical_string_r(const icalvalue* value) {
926 icalerror_check_arg_rz( (value!=0),"value");
927 data = value->data.v_string;
929 str = (char*)icalmemory_new_buffer(strlen(data)+1);
937 static char* icalvalue_recur_as_ical_string_r(const icalvalue* value)
939 struct icalrecurrencetype *recur = value->data.v_recur;
940 return icalrecurrencetype_as_string_r(recur);
943 static char* icalvalue_text_as_ical_string_r(const icalvalue* value) {
944 return icalmemory_strdup_and_quote(value, value->data.v_string);
950 icalvalue_attach_as_ical_string_r(const icalvalue* value)
955 icalerror_check_arg_rz( (value!=0),"value");
957 a = icalvalue_get_attach(value);
959 if (icalattach_get_is_url (a)) {
962 url = icalattach_get_url (a);
963 str = icalmemory_new_buffer (strlen (url) + 1);
967 const char *data = 0;
968 data = (const char*)icalattach_get_data(a);
969 str = icalmemory_new_buffer (strlen (data) + 1);
976 static char* icalvalue_duration_as_ical_string_r(const icalvalue* value) {
978 struct icaldurationtype data;
980 icalerror_check_arg_rz( (value!=0),"value");
981 data = icalvalue_get_duration(value);
983 return icaldurationtype_as_ical_string_r(data);
988 void print_time_to_string(char* str, const struct icaltimetype *data)
994 if (icaltime_is_utc(*data)){
995 snprintf(temp,sizeof(temp),"%02d%02d%02dZ",data->hour,data->minute,data->second);
998 snprintf(temp,sizeof(temp),"%02d%02d%02d",data->hour,data->minute,data->second);
1005 void print_date_to_string(char* str, const struct icaltimetype *data)
1011 snprintf(temp,sizeof(temp),"%04d%02d%02d",data->year,data->month,data->day);
1012 strncat(str,temp,8);
1016 static char* icalvalue_date_as_ical_string_r(const icalvalue* value) {
1018 struct icaltimetype data;
1020 icalerror_check_arg_rz( (value!=0),"value");
1021 data = icalvalue_get_date(value);
1023 str = (char*)icalmemory_new_buffer(9);
1026 print_date_to_string(str,&data);
1031 void print_datetime_to_string(char* str, const struct icaltimetype *data)
1037 print_date_to_string(str,data);
1038 if ( !data->is_date ) {
1039 strncat(str,"T",19);
1041 print_time_to_string(temp,data);
1042 strncat(str,temp,19);
1048 static char* icalvalue_datetime_as_ical_string_r(const icalvalue* value) {
1050 struct icaltimetype data;
1052 icalvalue_kind kind = icalvalue_isa(value);
1054 icalerror_check_arg_rz( (value!=0),"value");
1057 if( !(kind == ICAL_DATE_VALUE || kind == ICAL_DATETIME_VALUE ))
1059 icalerror_set_errno(ICAL_BADARG_ERROR);
1063 data = icalvalue_get_datetime(value);
1065 str = (char*)icalmemory_new_buffer(20);
1068 print_datetime_to_string(str,&data);
1074 static char* icalvalue_float_as_ical_string_r(const icalvalue* value) {
1079 icalerror_check_arg_rz( (value!=0),"value");
1080 data = icalvalue_get_float(value);
1082 /* bypass current locale in order to make
1083 sure snprintf uses a '.' as a separator
1084 set locate to 'C' and keep old locale */
1085 old_locale = strdup (setlocale (LC_NUMERIC,NULL));
1086 setlocale (LC_NUMERIC,"C");
1088 str = (char*)icalmemory_new_buffer(40);
1090 snprintf(str,40,"%f",data);
1092 /* restore saved locale */
1093 setlocale (LC_NUMERIC,old_locale);
1100 static char* icalvalue_geo_as_ical_string_r(const icalvalue* value) {
1102 struct icalgeotype data;
1105 icalerror_check_arg_rz( (value!=0),"value");
1107 data = icalvalue_get_geo(value);
1109 /* bypass current locale in order to make
1110 * sure snprintf uses a '.' as a separator
1111 * set locate to 'C' and keep old locale */
1112 old_locale = strdup (setlocale (LC_NUMERIC,NULL));
1113 setlocale (LC_NUMERIC,"C");
1115 str = (char*)icalmemory_new_buffer(80);
1117 snprintf(str,80,"%f;%f",data.lat,data.lon);
1119 /* restore saved locale */
1120 setlocale (LC_NUMERIC,old_locale);
1127 static char* icalvalue_datetimeperiod_as_ical_string_r(const icalvalue* value) {
1128 struct icaldatetimeperiodtype dtp = icalvalue_get_datetimeperiod(value);
1130 icalerror_check_arg_rz( (value!=0),"value");
1132 if(!icaltime_is_null_time(dtp.time)){
1133 return icaltime_as_ical_string_r(dtp.time);
1135 return icalperiodtype_as_ical_string_r(dtp.period);
1140 static char* icalvalue_period_as_ical_string_r(const icalvalue* value) {
1141 struct icalperiodtype data;
1142 icalerror_check_arg_rz( (value!=0),"value");
1143 data = icalvalue_get_period(value);
1145 return icalperiodtype_as_ical_string_r(data);
1150 static char* icalvalue_trigger_as_ical_string_r(const icalvalue* value) {
1152 struct icaltriggertype data;
1154 icalerror_check_arg_rz( (value!=0),"value");
1155 data = icalvalue_get_trigger(value);
1157 if(!icaltime_is_null_time(data.time)){
1158 return icaltime_as_ical_string_r(data.time);
1160 return icaldurationtype_as_ical_string_r(data.duration);
1166 icalvalue_as_ical_string(const icalvalue* value)
1169 buf = icalvalue_as_ical_string_r(value);
1170 icalmemory_add_tmp_buffer(buf);
1176 icalvalue_as_ical_string_r(const icalvalue* value)
1182 switch (value->kind){
1184 case ICAL_ATTACH_VALUE:
1185 return icalvalue_attach_as_ical_string_r(value);
1187 case ICAL_BINARY_VALUE:
1188 return icalvalue_binary_as_ical_string_r(value);
1190 case ICAL_BOOLEAN_VALUE:
1191 case ICAL_INTEGER_VALUE:
1192 return icalvalue_int_as_ical_string_r(value);
1194 case ICAL_UTCOFFSET_VALUE:
1195 return icalvalue_utcoffset_as_ical_string_r(value);
1197 case ICAL_TEXT_VALUE:
1198 return icalvalue_text_as_ical_string_r(value);
1200 case ICAL_QUERY_VALUE:
1201 return icalvalue_string_as_ical_string_r(value);
1203 case ICAL_STRING_VALUE:
1204 case ICAL_URI_VALUE:
1205 case ICAL_CALADDRESS_VALUE:
1206 return icalvalue_string_as_ical_string_r(value);
1208 case ICAL_DATE_VALUE:
1209 return icalvalue_date_as_ical_string_r(value);
1210 case ICAL_DATETIME_VALUE:
1211 return icalvalue_datetime_as_ical_string_r(value);
1212 case ICAL_DURATION_VALUE:
1213 return icalvalue_duration_as_ical_string_r(value);
1215 case ICAL_PERIOD_VALUE:
1216 return icalvalue_period_as_ical_string_r(value);
1217 case ICAL_DATETIMEPERIOD_VALUE:
1218 return icalvalue_datetimeperiod_as_ical_string_r(value);
1220 case ICAL_FLOAT_VALUE:
1221 return icalvalue_float_as_ical_string_r(value);
1223 case ICAL_GEO_VALUE:
1224 return icalvalue_geo_as_ical_string_r(value);
1226 case ICAL_RECUR_VALUE:
1227 return icalvalue_recur_as_ical_string_r(value);
1229 case ICAL_TRIGGER_VALUE:
1230 return icalvalue_trigger_as_ical_string_r(value);
1232 case ICAL_REQUESTSTATUS_VALUE:
1233 return icalreqstattype_as_string_r(value->data.v_requeststatus);
1235 case ICAL_ACTION_VALUE:
1236 case ICAL_CMD_VALUE:
1237 case ICAL_QUERYLEVEL_VALUE:
1238 case ICAL_CARLEVEL_VALUE:
1239 case ICAL_METHOD_VALUE:
1240 case ICAL_STATUS_VALUE:
1241 case ICAL_TRANSP_VALUE:
1242 case ICAL_CLASS_VALUE:
1243 if(value->x_value !=0){
1244 return icalmemory_strdup(value->x_value);
1247 return icalproperty_enum_to_string_r(value->data.v_enum);
1250 if (value->x_value != 0)
1251 return icalmemory_strdup_and_quote(value,value->x_value);
1265 icalvalue_isa (const icalvalue* value)
1268 return ICAL_NO_VALUE;
1276 icalvalue_isa_value (void* value)
1278 struct icalvalue_impl *impl = (struct icalvalue_impl *)value;
1280 icalerror_check_arg_rz( (value!=0), "value");
1282 if (strcmp(impl->id,"val") == 0) {
1290 static int icalvalue_is_time(const icalvalue* a) {
1291 icalvalue_kind kind = icalvalue_isa(a);
1293 if(kind == ICAL_DATETIME_VALUE ||
1294 kind == ICAL_DATE_VALUE ){
1303 * In case of error, this function returns 0. This is partly bogus, as 0 is
1304 * not part of the returned enum.
1305 * FIXME We should probably add an error value to the enum.
1307 icalparameter_xliccomparetype
1308 icalvalue_compare(const icalvalue* a, const icalvalue *b)
1311 icalerror_check_arg_rz( (a!=0), "a");
1312 icalerror_check_arg_rz( (b!=0), "b");
1314 /* Not the same type; they can only be unequal */
1315 if( ! (icalvalue_is_time(a) && icalvalue_is_time(b)) &&
1316 icalvalue_isa(a) != icalvalue_isa(b)){
1317 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1320 switch (icalvalue_isa(a)){
1322 case ICAL_ATTACH_VALUE:
1324 if (icalattach_get_is_url(a->data.v_attach) &&
1325 icalattach_get_is_url(b->data.v_attach)) {
1326 if (strcasecmp(icalattach_get_url(a->data.v_attach),
1327 icalattach_get_url(b->data.v_attach)) == 0)
1328 return ICAL_XLICCOMPARETYPE_EQUAL;
1330 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1333 if (a->data.v_attach == b->data.v_attach)
1334 return ICAL_XLICCOMPARETYPE_EQUAL;
1336 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1339 case ICAL_BINARY_VALUE:
1341 if (a->data.v_attach == b->data.v_attach)
1342 return ICAL_XLICCOMPARETYPE_EQUAL;
1344 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1347 case ICAL_BOOLEAN_VALUE:
1349 if (icalvalue_get_boolean(a) == icalvalue_get_boolean(b)){
1350 return ICAL_XLICCOMPARETYPE_EQUAL;
1352 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1356 case ICAL_FLOAT_VALUE:
1358 if (a->data.v_float > b->data.v_float){
1359 return ICAL_XLICCOMPARETYPE_GREATER;
1360 } else if (a->data.v_float < b->data.v_float){
1361 return ICAL_XLICCOMPARETYPE_LESS;
1363 return ICAL_XLICCOMPARETYPE_EQUAL;
1367 case ICAL_INTEGER_VALUE:
1368 case ICAL_UTCOFFSET_VALUE:
1370 if (a->data.v_int > b->data.v_int){
1371 return ICAL_XLICCOMPARETYPE_GREATER;
1372 } else if (a->data.v_int < b->data.v_int){
1373 return ICAL_XLICCOMPARETYPE_LESS;
1375 return ICAL_XLICCOMPARETYPE_EQUAL;
1379 case ICAL_DURATION_VALUE:
1381 int dur_a = icaldurationtype_as_int(a->data.v_duration);
1382 int dur_b = icaldurationtype_as_int(b->data.v_duration);
1385 return ICAL_XLICCOMPARETYPE_GREATER;
1386 } else if (dur_a < dur_b){
1387 return ICAL_XLICCOMPARETYPE_LESS;
1389 return ICAL_XLICCOMPARETYPE_EQUAL;
1394 case ICAL_TEXT_VALUE:
1395 case ICAL_URI_VALUE:
1396 case ICAL_CALADDRESS_VALUE:
1397 case ICAL_TRIGGER_VALUE:
1398 case ICAL_DATE_VALUE:
1399 case ICAL_DATETIME_VALUE:
1400 case ICAL_DATETIMEPERIOD_VALUE:
1401 case ICAL_QUERY_VALUE:
1402 case ICAL_RECUR_VALUE:
1405 char *temp1, *temp2;
1406 temp1 = icalvalue_as_ical_string_r(a);
1407 temp2 = icalvalue_as_ical_string_r(b);
1408 r = strcmp(temp1, temp2);
1413 return ICAL_XLICCOMPARETYPE_GREATER;
1415 return ICAL_XLICCOMPARETYPE_LESS;
1417 return ICAL_XLICCOMPARETYPE_EQUAL;
1423 case ICAL_METHOD_VALUE:
1425 if (icalvalue_get_method(a) == icalvalue_get_method(b)){
1426 return ICAL_XLICCOMPARETYPE_EQUAL;
1428 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1433 case ICAL_STATUS_VALUE:
1435 if (icalvalue_get_status(a) == icalvalue_get_status(b)){
1436 return ICAL_XLICCOMPARETYPE_EQUAL;
1438 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1443 case ICAL_TRANSP_VALUE:
1445 if (icalvalue_get_transp(a) == icalvalue_get_transp(b)){
1446 return ICAL_XLICCOMPARETYPE_EQUAL;
1448 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1452 case ICAL_ACTION_VALUE:
1454 if (icalvalue_get_action(a) == icalvalue_get_action(b)){
1455 return ICAL_XLICCOMPARETYPE_EQUAL;
1457 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1461 case ICAL_PERIOD_VALUE:
1462 case ICAL_GEO_VALUE:
1466 icalerror_warn("Comparison not implemented for value type");
1473 /** Examine the value and possibly change the kind to agree with the
1477 void icalvalue_reset_kind(icalvalue* value)
1479 if( (value->kind==ICAL_DATETIME_VALUE || value->kind==ICAL_DATE_VALUE )&&
1480 !icaltime_is_null_time(value->data.v_time) ) {
1482 if(icaltime_is_date(value->data.v_time)){
1483 value->kind = ICAL_DATE_VALUE;
1485 value->kind = ICAL_DATETIME_VALUE;
1491 void icalvalue_set_parent(icalvalue* value,
1492 icalproperty* property)
1494 value->parent = property;
1497 icalproperty* icalvalue_get_parent(icalvalue* value)
1499 return value->parent;
1503 int icalvalue_encode_ical_string(const char *szText, char *szEncText, int nMaxBufferLen)
1506 icalvalue *value = 0;
1508 if ((szText == 0) || (szEncText == 0))
1511 value = icalvalue_new_from_string(ICAL_STRING_VALUE, szText);
1516 ptr = icalvalue_text_as_ical_string_r(value);
1520 if ((int)strlen(ptr) >= nMaxBufferLen)
1522 icalvalue_free (value);
1527 strcpy(szEncText, ptr);
1530 icalvalue_free ((icalvalue*)value);
1535 int icalvalue_decode_ical_string(const char *szText, char *szDecText, int nMaxBufferLen)
1541 if ((szText == 0) || (szDecText == 0))
1544 buf_sz = strlen(szText);
1545 str_p = str = (char*)icalmemory_new_buffer(buf_sz + 1);
1551 for (p=szText; *p!=0; p++) {
1553 icalmemory_append_char (&str,&str_p,&buf_sz,*(p+1));
1557 icalmemory_append_char (&str,&str_p,&buf_sz,*p);
1560 icalmemory_append_char(&str,&str_p,&buf_sz,'\0');
1562 if ((int)strlen(str) > nMaxBufferLen) {
1563 icalmemory_free_buffer(str);
1567 strcpy(szDecText, str);
1569 icalmemory_free_buffer(str);
1574 /* The remaining interfaces are 'new', 'set' and 'get' for each of the value