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_RECUR_VALUE:
148 if(old->data.v_recur != 0){
149 new->data.v_recur = malloc(sizeof(struct icalrecurrencetype));
151 if(new->data.v_recur == 0){
156 memcpy( new->data.v_recur, old->data.v_recur,
157 sizeof(struct icalrecurrencetype));
164 if (old->x_value != 0) {
165 new->x_value=icalmemory_strdup(old->x_value);
167 if (new->x_value == 0) {
178 /* all of the other types are stored as values, not
179 pointers, so we can just copy the whole structure. */
181 new->data = old->data;
188 static char* icalmemory_strdup_and_dequote(const char* str)
191 char* out = (char*)malloc(sizeof(char) * strlen(str) +1);
200 for (p = str; *p!=0; p++){
269 * Returns a quoted copy of a string
270 * @todo This is not RFC2445 compliant.
271 * The RFC only allows:
272 * TSAFE-CHAR = %x20-21 / %x23-2B / %x2D-39 / %x3C-5B / %x5D-7E / NON-US-ASCII
273 * As such, \t\r\b\f are not allowed, not even escaped
275 static char* icalmemory_strdup_and_quote(const icalvalue* value,
276 const char* unquoted_str)
283 buf_sz = strlen(unquoted_str)+1;
285 str_p = str = (char*)icalmemory_new_buffer(buf_sz);
291 for(p=unquoted_str; *p!=0; p++){
295 icalmemory_append_string(&str,&str_p,&buf_sz,"\\n");
300 icalmemory_append_string(&str,&str_p,&buf_sz,"\\t");
304 icalmemory_append_string(&str,&str_p,&buf_sz,"\\r");
308 icalmemory_append_string(&str,&str_p,&buf_sz,"\\b");
312 icalmemory_append_string(&str,&str_p,&buf_sz,"\\f");
318 /* unescaped COMMA is allowed in CATEGORIES property as its
319 considered a list delimiter here, see:
320 http://tools.ietf.org/html/rfc2445#section-4.3.11 */
321 if (icalproperty_isa(value->parent) == ICAL_CATEGORIES_PROPERTY) {
322 icalmemory_append_char(&str,&str_p,&buf_sz,*p);
327 icalmemory_append_char(&str,&str_p,&buf_sz,'\\');
328 icalmemory_append_char(&str,&str_p,&buf_sz,*p);
333 icalmemory_append_char(&str,&str_p,&buf_sz,*p);
338 /* Assume the last character is not a '\0' and add one. We could
339 check *str_p != 0, but that would be an uninitialized memory
342 icalmemory_append_char(&str,&str_p,&buf_sz,'\0');
349 * This is a bad API, as it forces callers to specify their own X type.
350 * This function should take care of this by itself.
353 icalvalue* icalvalue_new_enum(icalvalue_kind kind, int x_type, const char* str)
355 int e = icalproperty_kind_and_string_to_enum(kind, str);
356 struct icalvalue_impl *value;
358 if(e != 0 && icalproperty_enum_belongs_to_property(
359 icalproperty_value_kind_to_kind(kind),e)) {
361 value = icalvalue_new_impl(kind);
362 value->data.v_enum = e;
364 /* Make it an X value */
365 value = icalvalue_new_impl(kind);
366 value->data.v_enum = x_type;
367 icalvalue_set_x(value,str);
374 * Transforms a simple float number string into a double.
375 * The decimal separator (if any) of the double has to be '.'
376 * The code is locale *independant* and does *not* change the locale.
377 * It should be thread safe.
378 * If you want a code that that does the same job with a decimal separator
379 * dependant on the current locale, then use strtof() from libc.
381 int simple_str_to_double(const char* from,
385 #define TMP_NUM_SIZE 100
386 char *start=NULL, *end=NULL, *cur=(char*)from ;
387 char tmp_buf[TMP_NUM_SIZE+1] ; /*hack*/
389 struct lconv *loc_data = localeconv () ;
394 if (!from || !result) {
398 /*skip the white spaces at the beginning*/
399 while (cur && isspace (*cur))
404 * copy the part that looks like a double into tmp_buf
405 * so that we can call strtof() on it.
406 * during the copy, we give ourselves a chance to convert the '.'
407 * into the decimal separator of the current locale.
409 while (cur && (isdigit (*cur) ||
416 if (end - start + 1> 100) {
417 /*huh hoh, number is too big. getting out*/
420 memset(tmp_buf, 0, TMP_NUM_SIZE+1) ;
423 * copy the float number string into tmp_buf, and take
424 * care to have the (optional) decimal separator be the one
425 * of the current locale.
428 for (i=0 ; i < end - from ;++i) {
431 && loc_data->decimal_point
432 && loc_data->decimal_point[0]
433 && loc_data->decimal_point[0] != '.') {
434 /*replace '.' by the digit separator of the current locale*/
435 tmp_buf[i] = loc_data->decimal_point[0] ;
437 tmp_buf[i] = start[i] ;
441 GetNumberFormat(LOCALE_SYSTEM_DEFAULT,0,start, NULL, tmp_buf,TMP_NUM_SIZE);
445 *result = atof(tmp_buf) ;
449 icalvalue* icalvalue_new_from_string_with_error(icalvalue_kind kind,const char* str,icalproperty** error)
452 struct icalvalue_impl *value = 0;
454 icalerror_check_arg_rz(str!=0,"str");
462 case ICAL_ATTACH_VALUE:
466 attach = icalattach_new_from_url (str);
470 value = icalvalue_new_attach (attach);
471 icalattach_unref (attach);
475 case ICAL_BINARY_VALUE:
478 attach = icalattach_new_from_data (str, 0, 0);
481 value = icalvalue_new_attach (attach);
482 icalattach_unref (attach);
485 case ICAL_BOOLEAN_VALUE:
491 char temp[TMP_BUF_SIZE];
492 snprintf(temp,sizeof(temp),"%s Values are not implemented",
493 icalvalue_kind_to_string(kind));
494 *error = icalproperty_vanew_xlicerror(
496 icalparameter_new_xlicerrortype(
497 ICAL_XLICERRORTYPE_VALUEPARSEERROR),
504 case ICAL_TRANSP_VALUE:
505 value = icalvalue_new_enum(kind, (int)ICAL_TRANSP_X,str);
507 case ICAL_METHOD_VALUE:
508 value = icalvalue_new_enum(kind, (int)ICAL_METHOD_X,str);
510 case ICAL_STATUS_VALUE:
511 value = icalvalue_new_enum(kind, (int)ICAL_STATUS_X,str);
513 case ICAL_ACTION_VALUE:
514 value = icalvalue_new_enum(kind, (int)ICAL_ACTION_X,str);
517 case ICAL_QUERY_VALUE:
518 value = icalvalue_new_query(str);
521 case ICAL_CLASS_VALUE:
522 value = icalvalue_new_enum(kind, (int)ICAL_CLASS_X,str);
525 value = icalvalue_new_enum(kind, ICAL_CMD_X,str);
527 case ICAL_QUERYLEVEL_VALUE:
528 value = icalvalue_new_enum(kind, ICAL_QUERYLEVEL_X,str);
530 case ICAL_CARLEVEL_VALUE:
531 value = icalvalue_new_enum(kind, ICAL_CARLEVEL_X,str);
534 case ICAL_INTEGER_VALUE:
535 value = icalvalue_new_integer(atoi(str));
538 case ICAL_FLOAT_VALUE:
539 value = icalvalue_new_float((float)atof(str));
542 case ICAL_UTCOFFSET_VALUE:
544 int t,utcoffset, hours, minutes, seconds;
545 /* treat the UTCOFSET string a a decimal number, disassemble its digits
546 and reconstruct it as sections */
547 t = strtol(str,0,10);
548 /* add phantom seconds field */
549 if(abs(t)<9999){t *= 100; }
551 minutes = (t-hours*10000)/100;
552 seconds = (t-hours*10000-minutes*100);
553 utcoffset = hours*3600+minutes*60+seconds;
555 value = icalvalue_new_utcoffset(utcoffset);
560 case ICAL_TEXT_VALUE:
562 char* dequoted_str = icalmemory_strdup_and_dequote(str);
563 value = icalvalue_new_text(dequoted_str);
568 case ICAL_STRING_VALUE:
569 value = icalvalue_new_string(str);
572 case ICAL_CALADDRESS_VALUE:
573 value = icalvalue_new_caladdress(str);
577 value = icalvalue_new_uri(str);
583 struct icalgeotype geo = {0.0, 0.0};
585 if (simple_str_to_double (str, &geo.lat, &cur)) {
586 goto geo_parsing_error ;
589 /*skip white spaces*/
590 while (cur && isspace (*cur)) {
594 /*there is a ';' between the latitude and longitude parts*/
595 if (!cur || *cur != ';') {
596 goto geo_parsing_error ;
601 goto geo_parsing_error ;
603 /*skip white spaces*/
604 while (cur && isspace (*cur)) {
608 if (simple_str_to_double (cur, &geo.lon, &cur)) {
609 goto geo_parsing_error ;
611 value = icalvalue_new_geo (geo) ;
616 char temp[TMP_BUF_SIZE];
617 sprintf(temp, "Could not parse %s as a %s property",
618 str, icalvalue_kind_to_string(kind));
619 *error = icalproperty_vanew_xlicerror(
621 icalparameter_new_xlicerrortype(
622 ICAL_XLICERRORTYPE_VALUEPARSEERROR),
628 case ICAL_RECUR_VALUE:
630 struct icalrecurrencetype rt;
631 rt = icalrecurrencetype_from_string(str);
632 if(rt.freq != ICAL_NO_RECURRENCE){
633 value = icalvalue_new_recur(rt);
638 case ICAL_DATE_VALUE:
639 case ICAL_DATETIME_VALUE:
641 struct icaltimetype tt;
643 tt = icaltime_from_string(str);
644 if(!icaltime_is_null_time(tt)){
645 value = icalvalue_new_impl(kind);
646 value->data.v_time = tt;
648 icalvalue_reset_kind(value);
653 case ICAL_DATETIMEPERIOD_VALUE:
655 struct icaltimetype tt;
656 struct icalperiodtype p;
657 tt = icaltime_from_string(str);
659 if(!icaltime_is_null_time(tt)){
660 value = icalvalue_new_datetime(tt);
664 p = icalperiodtype_from_string(str);
665 if (!icalperiodtype_is_null_period(p)){
666 value = icalvalue_new_period(p);
672 case ICAL_DURATION_VALUE:
674 struct icaldurationtype dur = icaldurationtype_from_string(str);
676 if (!icaldurationtype_is_bad_duration(dur)) { /* failed to parse */
677 value = icalvalue_new_duration(dur);
683 case ICAL_PERIOD_VALUE:
685 struct icalperiodtype p;
686 p = icalperiodtype_from_string(str);
688 if(!icalperiodtype_is_null_period(p)){
689 value = icalvalue_new_period(p);
694 case ICAL_TRIGGER_VALUE:
696 struct icaltriggertype tr = icaltriggertype_from_string(str);
697 if (!icaltriggertype_is_bad_trigger(tr)) {
698 value = icalvalue_new_trigger(tr);
703 case ICAL_REQUESTSTATUS_VALUE:
705 struct icalreqstattype rst = icalreqstattype_from_string(str);
706 if(rst.code != ICAL_UNKNOWN_STATUS){
707 value = icalvalue_new_requeststatus(rst);
715 char* dequoted_str = icalmemory_strdup_and_dequote(str);
716 value = icalvalue_new_x(dequoted_str);
724 char temp[TMP_BUF_SIZE];
726 snprintf(temp,TMP_BUF_SIZE,"Unknown type for \'%s\'",str);
728 *error = icalproperty_vanew_xlicerror(
730 icalparameter_new_xlicerrortype(
731 ICAL_XLICERRORTYPE_VALUEPARSEERROR),
735 icalerror_warn("icalvalue_new_from_string got an unknown value type");
741 if (error != 0 && *error == 0 && value == 0){
742 char temp[TMP_BUF_SIZE];
744 snprintf(temp,TMP_BUF_SIZE,"Failed to parse value: \'%s\'",str);
746 *error = icalproperty_vanew_xlicerror(
748 icalparameter_new_xlicerrortype(
749 ICAL_XLICERRORTYPE_VALUEPARSEERROR),
758 icalvalue* icalvalue_new_from_string(icalvalue_kind kind,const char* str)
760 return icalvalue_new_from_string_with_error(kind,str,(icalproperty**)0);
766 icalvalue_free (icalvalue* v)
768 icalerror_check_arg_rv((v != 0),"value");
770 #ifdef ICAL_FREE_ON_LIST_IS_ERROR
771 icalerror_assert( (v->parent ==0),"This value is still attached to a property");
784 case ICAL_BINARY_VALUE:
785 case ICAL_ATTACH_VALUE: {
786 if (v->data.v_attach) {
787 icalattach_unref (v->data.v_attach);
788 v->data.v_attach = NULL;
793 case ICAL_TEXT_VALUE:
794 case ICAL_CALADDRESS_VALUE:
796 case ICAL_STRING_VALUE:
797 case ICAL_QUERY_VALUE:
799 if (v->data.v_string != 0) {
800 free((void*)v->data.v_string);
801 v->data.v_string = 0;
805 case ICAL_RECUR_VALUE:
807 if(v->data.v_recur != 0){
808 free((void*)v->data.v_recur);
820 v->kind = ICAL_NO_VALUE;
823 memset(&(v->data),0,sizeof(v->data));
829 icalvalue_is_valid (const icalvalue* value)
838 static char* icalvalue_binary_as_ical_string_r(const icalvalue* value) {
842 icalerror_check_arg_rz( (value!=0),"value");
844 data = icalvalue_get_binary(value);
846 str = (char*)icalmemory_new_buffer(60);
847 snprintf(str, 60,"icalvalue_binary_as_ical_string is not implemented yet");
853 #define MAX_INT_DIGITS 12 /* Enough for 2^32 + sign*/
855 static char* icalvalue_int_as_ical_string_r(const icalvalue* value) {
859 icalerror_check_arg_rz( (value!=0),"value");
860 str = (char*)icalmemory_new_buffer(MAX_INT_DIGITS);
862 data = icalvalue_get_integer(value);
864 snprintf(str,MAX_INT_DIGITS,"%d",data);
870 static char* icalvalue_utcoffset_as_ical_string_r(const icalvalue* value)
876 icalerror_check_arg_rz( (value!=0),"value");
878 str = (char*)icalmemory_new_buffer(9);
879 data = icalvalue_get_utcoffset(value);
881 if (abs(data) == data){
888 m = (data - (h*3600))/ 60;
889 s = (data - (h*3600) - (m*60));
892 snprintf(str,9,"%c%02d%02d%02d",sign,abs(h),abs(m),abs(s));
894 snprintf(str,9,"%c%02d%02d",sign,abs(h),abs(m));
899 static char* icalvalue_string_as_ical_string_r(const icalvalue* value) {
903 icalerror_check_arg_rz( (value!=0),"value");
904 data = value->data.v_string;
906 str = (char*)icalmemory_new_buffer(strlen(data)+1);
914 static char* icalvalue_recur_as_ical_string_r(const icalvalue* value)
916 struct icalrecurrencetype *recur = value->data.v_recur;
917 return icalrecurrencetype_as_string_r(recur);
920 static char* icalvalue_text_as_ical_string_r(const icalvalue* value) {
921 return icalmemory_strdup_and_quote(value, value->data.v_string);
927 icalvalue_attach_as_ical_string_r(const icalvalue* value)
932 icalerror_check_arg_rz( (value!=0),"value");
934 a = icalvalue_get_attach(value);
936 if (icalattach_get_is_url (a)) {
939 url = icalattach_get_url (a);
940 str = icalmemory_new_buffer (strlen (url) + 1);
944 const char *data = 0;
945 data = (const char*)icalattach_get_data(a);
946 str = icalmemory_new_buffer (strlen (data) + 1);
953 static char* icalvalue_duration_as_ical_string_r(const icalvalue* value) {
955 struct icaldurationtype data;
957 icalerror_check_arg_rz( (value!=0),"value");
958 data = icalvalue_get_duration(value);
960 return icaldurationtype_as_ical_string_r(data);
965 void print_time_to_string(char* str, const struct icaltimetype *data)
971 if (icaltime_is_utc(*data)){
972 snprintf(temp,sizeof(temp),"%02d%02d%02dZ",data->hour,data->minute,data->second);
975 snprintf(temp,sizeof(temp),"%02d%02d%02d",data->hour,data->minute,data->second);
982 void print_date_to_string(char* str, const struct icaltimetype *data)
988 snprintf(temp,sizeof(temp),"%04d%02d%02d",data->year,data->month,data->day);
993 static char* icalvalue_date_as_ical_string_r(const icalvalue* value) {
995 struct icaltimetype data;
997 icalerror_check_arg_rz( (value!=0),"value");
998 data = icalvalue_get_date(value);
1000 str = (char*)icalmemory_new_buffer(9);
1003 print_date_to_string(str,&data);
1008 void print_datetime_to_string(char* str, const struct icaltimetype *data)
1014 print_date_to_string(str,data);
1015 if ( !data->is_date ) {
1016 strncat(str,"T",19);
1018 print_time_to_string(temp,data);
1019 strncat(str,temp,19);
1025 static char* icalvalue_datetime_as_ical_string_r(const icalvalue* value) {
1027 struct icaltimetype data;
1029 icalvalue_kind kind = icalvalue_isa(value);
1031 icalerror_check_arg_rz( (value!=0),"value");
1034 if( !(kind == ICAL_DATE_VALUE || kind == ICAL_DATETIME_VALUE ))
1036 icalerror_set_errno(ICAL_BADARG_ERROR);
1040 data = icalvalue_get_datetime(value);
1042 str = (char*)icalmemory_new_buffer(20);
1045 print_datetime_to_string(str,&data);
1051 static char* icalvalue_float_as_ical_string_r(const icalvalue* value) {
1055 icalerror_check_arg_rz( (value!=0),"value");
1056 data = icalvalue_get_float(value);
1058 str = (char*)icalmemory_new_buffer(40);
1060 snprintf(str,40,"%f",data);
1066 static char* icalvalue_geo_as_ical_string_r(const icalvalue* value) {
1068 struct icalgeotype data;
1070 icalerror_check_arg_rz( (value!=0),"value");
1072 data = icalvalue_get_geo(value);
1074 str = (char*)icalmemory_new_buffer(80);
1076 snprintf(str,80,"%f;%f",data.lat,data.lon);
1082 static char* icalvalue_datetimeperiod_as_ical_string_r(const icalvalue* value) {
1083 struct icaldatetimeperiodtype dtp = icalvalue_get_datetimeperiod(value);
1085 icalerror_check_arg_rz( (value!=0),"value");
1087 if(!icaltime_is_null_time(dtp.time)){
1088 return icaltime_as_ical_string_r(dtp.time);
1090 return icalperiodtype_as_ical_string_r(dtp.period);
1095 static char* icalvalue_period_as_ical_string_r(const icalvalue* value) {
1096 struct icalperiodtype data;
1097 icalerror_check_arg_rz( (value!=0),"value");
1098 data = icalvalue_get_period(value);
1100 return icalperiodtype_as_ical_string_r(data);
1105 static char* icalvalue_trigger_as_ical_string_r(const icalvalue* value) {
1107 struct icaltriggertype data;
1109 icalerror_check_arg_rz( (value!=0),"value");
1110 data = icalvalue_get_trigger(value);
1112 if(!icaltime_is_null_time(data.time)){
1113 return icaltime_as_ical_string_r(data.time);
1115 return icaldurationtype_as_ical_string_r(data.duration);
1121 icalvalue_as_ical_string(const icalvalue* value)
1124 buf = icalvalue_as_ical_string_r(value);
1125 icalmemory_add_tmp_buffer(buf);
1131 icalvalue_as_ical_string_r(const icalvalue* value)
1137 switch (value->kind){
1139 case ICAL_ATTACH_VALUE:
1140 return icalvalue_attach_as_ical_string_r(value);
1142 case ICAL_BINARY_VALUE:
1143 return icalvalue_binary_as_ical_string_r(value);
1145 case ICAL_BOOLEAN_VALUE:
1146 case ICAL_INTEGER_VALUE:
1147 return icalvalue_int_as_ical_string_r(value);
1149 case ICAL_UTCOFFSET_VALUE:
1150 return icalvalue_utcoffset_as_ical_string_r(value);
1152 case ICAL_TEXT_VALUE:
1153 return icalvalue_text_as_ical_string_r(value);
1155 case ICAL_QUERY_VALUE:
1156 return icalvalue_string_as_ical_string_r(value);
1158 case ICAL_STRING_VALUE:
1159 case ICAL_URI_VALUE:
1160 case ICAL_CALADDRESS_VALUE:
1161 return icalvalue_string_as_ical_string_r(value);
1163 case ICAL_DATE_VALUE:
1164 return icalvalue_date_as_ical_string_r(value);
1165 case ICAL_DATETIME_VALUE:
1166 return icalvalue_datetime_as_ical_string_r(value);
1167 case ICAL_DURATION_VALUE:
1168 return icalvalue_duration_as_ical_string_r(value);
1170 case ICAL_PERIOD_VALUE:
1171 return icalvalue_period_as_ical_string_r(value);
1172 case ICAL_DATETIMEPERIOD_VALUE:
1173 return icalvalue_datetimeperiod_as_ical_string_r(value);
1175 case ICAL_FLOAT_VALUE:
1176 return icalvalue_float_as_ical_string_r(value);
1178 case ICAL_GEO_VALUE:
1179 return icalvalue_geo_as_ical_string_r(value);
1181 case ICAL_RECUR_VALUE:
1182 return icalvalue_recur_as_ical_string_r(value);
1184 case ICAL_TRIGGER_VALUE:
1185 return icalvalue_trigger_as_ical_string_r(value);
1187 case ICAL_REQUESTSTATUS_VALUE:
1188 return icalreqstattype_as_string_r(value->data.v_requeststatus);
1190 case ICAL_ACTION_VALUE:
1191 case ICAL_CMD_VALUE:
1192 case ICAL_QUERYLEVEL_VALUE:
1193 case ICAL_CARLEVEL_VALUE:
1194 case ICAL_METHOD_VALUE:
1195 case ICAL_STATUS_VALUE:
1196 case ICAL_TRANSP_VALUE:
1197 case ICAL_CLASS_VALUE:
1198 if(value->x_value !=0){
1199 return icalmemory_strdup(value->x_value);
1202 return icalproperty_enum_to_string_r(value->data.v_enum);
1205 if (value->x_value != 0)
1206 return icalmemory_strdup_and_quote(value,value->x_value);
1220 icalvalue_isa (const icalvalue* value)
1223 return ICAL_NO_VALUE;
1231 icalvalue_isa_value (void* value)
1233 struct icalvalue_impl *impl = (struct icalvalue_impl *)value;
1235 icalerror_check_arg_rz( (value!=0), "value");
1237 if (strcmp(impl->id,"val") == 0) {
1245 static int icalvalue_is_time(const icalvalue* a) {
1246 icalvalue_kind kind = icalvalue_isa(a);
1248 if(kind == ICAL_DATETIME_VALUE ||
1249 kind == ICAL_DATE_VALUE ){
1258 * In case of error, this function returns 0. This is partly bogus, as 0 is
1259 * not part of the returned enum.
1260 * FIXME We should probably add an error value to the enum.
1262 icalparameter_xliccomparetype
1263 icalvalue_compare(const icalvalue* a, const icalvalue *b)
1266 icalerror_check_arg_rz( (a!=0), "a");
1267 icalerror_check_arg_rz( (b!=0), "b");
1269 /* Not the same type; they can only be unequal */
1270 if( ! (icalvalue_is_time(a) && icalvalue_is_time(b)) &&
1271 icalvalue_isa(a) != icalvalue_isa(b)){
1272 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1275 switch (icalvalue_isa(a)){
1277 case ICAL_ATTACH_VALUE:
1279 if (icalattach_get_is_url(a->data.v_attach) &&
1280 icalattach_get_is_url(b->data.v_attach)) {
1281 if (strcasecmp(icalattach_get_url(a->data.v_attach),
1282 icalattach_get_url(b->data.v_attach)) == 0)
1283 return ICAL_XLICCOMPARETYPE_EQUAL;
1285 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1288 if (a->data.v_attach == b->data.v_attach)
1289 return ICAL_XLICCOMPARETYPE_EQUAL;
1291 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1294 case ICAL_BINARY_VALUE:
1296 if (a->data.v_attach == b->data.v_attach)
1297 return ICAL_XLICCOMPARETYPE_EQUAL;
1299 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1302 case ICAL_BOOLEAN_VALUE:
1304 if (icalvalue_get_boolean(a) == icalvalue_get_boolean(b)){
1305 return ICAL_XLICCOMPARETYPE_EQUAL;
1307 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1311 case ICAL_FLOAT_VALUE:
1313 if (a->data.v_float > b->data.v_float){
1314 return ICAL_XLICCOMPARETYPE_GREATER;
1315 } else if (a->data.v_float < b->data.v_float){
1316 return ICAL_XLICCOMPARETYPE_LESS;
1318 return ICAL_XLICCOMPARETYPE_EQUAL;
1322 case ICAL_INTEGER_VALUE:
1323 case ICAL_UTCOFFSET_VALUE:
1325 if (a->data.v_int > b->data.v_int){
1326 return ICAL_XLICCOMPARETYPE_GREATER;
1327 } else if (a->data.v_int < b->data.v_int){
1328 return ICAL_XLICCOMPARETYPE_LESS;
1330 return ICAL_XLICCOMPARETYPE_EQUAL;
1334 case ICAL_DURATION_VALUE:
1336 int dur_a = icaldurationtype_as_int(a->data.v_duration);
1337 int dur_b = icaldurationtype_as_int(b->data.v_duration);
1340 return ICAL_XLICCOMPARETYPE_GREATER;
1341 } else if (dur_a < dur_b){
1342 return ICAL_XLICCOMPARETYPE_LESS;
1344 return ICAL_XLICCOMPARETYPE_EQUAL;
1349 case ICAL_TEXT_VALUE:
1350 case ICAL_URI_VALUE:
1351 case ICAL_CALADDRESS_VALUE:
1352 case ICAL_TRIGGER_VALUE:
1353 case ICAL_DATE_VALUE:
1354 case ICAL_DATETIME_VALUE:
1355 case ICAL_DATETIMEPERIOD_VALUE:
1356 case ICAL_QUERY_VALUE:
1357 case ICAL_RECUR_VALUE:
1360 char *temp1, *temp2;
1361 temp1 = icalvalue_as_ical_string_r(a);
1362 temp2 = icalvalue_as_ical_string_r(b);
1363 r = strcmp(temp1, temp2);
1368 return ICAL_XLICCOMPARETYPE_GREATER;
1370 return ICAL_XLICCOMPARETYPE_LESS;
1372 return ICAL_XLICCOMPARETYPE_EQUAL;
1378 case ICAL_METHOD_VALUE:
1380 if (icalvalue_get_method(a) == icalvalue_get_method(b)){
1381 return ICAL_XLICCOMPARETYPE_EQUAL;
1383 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1388 case ICAL_STATUS_VALUE:
1390 if (icalvalue_get_status(a) == icalvalue_get_status(b)){
1391 return ICAL_XLICCOMPARETYPE_EQUAL;
1393 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1398 case ICAL_TRANSP_VALUE:
1400 if (icalvalue_get_transp(a) == icalvalue_get_transp(b)){
1401 return ICAL_XLICCOMPARETYPE_EQUAL;
1403 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1407 case ICAL_ACTION_VALUE:
1409 if (icalvalue_get_action(a) == icalvalue_get_action(b)){
1410 return ICAL_XLICCOMPARETYPE_EQUAL;
1412 return ICAL_XLICCOMPARETYPE_NOTEQUAL;
1416 case ICAL_PERIOD_VALUE:
1417 case ICAL_GEO_VALUE:
1421 icalerror_warn("Comparison not implemented for value type");
1428 /** Examine the value and possibly change the kind to agree with the
1432 void icalvalue_reset_kind(icalvalue* value)
1434 if( (value->kind==ICAL_DATETIME_VALUE || value->kind==ICAL_DATE_VALUE )&&
1435 !icaltime_is_null_time(value->data.v_time) ) {
1437 if(icaltime_is_date(value->data.v_time)){
1438 value->kind = ICAL_DATE_VALUE;
1440 value->kind = ICAL_DATETIME_VALUE;
1446 void icalvalue_set_parent(icalvalue* value,
1447 icalproperty* property)
1449 value->parent = property;
1452 icalproperty* icalvalue_get_parent(icalvalue* value)
1454 return value->parent;
1458 int icalvalue_encode_ical_string(const char *szText, char *szEncText, int nMaxBufferLen)
1461 icalvalue *value = 0;
1463 if ((szText == 0) || (szEncText == 0))
1466 value = icalvalue_new_from_string(ICAL_STRING_VALUE, szText);
1471 ptr = icalvalue_text_as_ical_string_r(value);
1475 if ((int)strlen(ptr) >= nMaxBufferLen)
1477 icalvalue_free (value);
1482 strcpy(szEncText, ptr);
1485 icalvalue_free ((icalvalue*)value);
1490 int icalvalue_decode_ical_string(const char *szText, char *szDecText, int nMaxBufferLen)
1496 if ((szText == 0) || (szDecText == 0))
1499 buf_sz = strlen(szText);
1500 str_p = str = (char*)icalmemory_new_buffer(buf_sz + 1);
1506 for (p=szText; *p!=0; p++) {
1508 icalmemory_append_char (&str,&str_p,&buf_sz,*(p+1));
1512 icalmemory_append_char (&str,&str_p,&buf_sz,*p);
1515 icalmemory_append_char(&str,&str_p,&buf_sz,'\0');
1517 if ((int)strlen(str) > nMaxBufferLen) {
1518 icalmemory_free_buffer(str);
1522 strcpy(szDecText, str);
1524 icalmemory_free_buffer(str);
1529 /* The remaining interfaces are 'new', 'set' and 'get' for each of the value