summaryrefslogtreecommitdiffabout
path: root/libical/src/libical/icalparser.c
Unidiff
Diffstat (limited to 'libical/src/libical/icalparser.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libical/src/libical/icalparser.c1111
1 files changed, 1111 insertions, 0 deletions
diff --git a/libical/src/libical/icalparser.c b/libical/src/libical/icalparser.c
new file mode 100644
index 0000000..b5824d5
--- a/dev/null
+++ b/libical/src/libical/icalparser.c
@@ -0,0 +1,1111 @@
1/* -*- Mode: C -*-
2 ======================================================================
3 FILE: icalparser.c
4 CREATOR: eric 04 August 1999
5
6 $Id$
7 $Locker$
8
9 The contents of this file are subject to the Mozilla Public License
10 Version 1.0 (the "License"); you may not use this file except in
11 compliance with the License. You may obtain a copy of the License at
12 http://www.mozilla.org/MPL/
13
14 Software distributed under the License is distributed on an "AS IS"
15 basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
16 the License for the specific language governing rights and
17 limitations under the License.
18
19
20 This program is free software; you can redistribute it and/or modify
21 it under the terms of either:
22
23 The LGPL as published by the Free Software Foundation, version
24 2.1, available at: http://www.fsf.org/copyleft/lesser.html
25
26 Or:
27
28 The Mozilla Public License Version 1.0. You may obtain a copy of
29 the License at http://www.mozilla.org/MPL/
30
31 The Initial Developer of the Original Code is Eric Busboom
32
33 (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
34 ======================================================================*/
35
36#ifdef HAVE_CONFIG_H
37#include "config.h"
38#endif
39
40
41#include "icalparser.h"
42#include "pvl.h"
43#include "icalmemory.h"
44#include "icalerror.h"
45#include "icalvalue.h"
46#include "icalderivedparameter.h"
47#include "icalparameter.h"
48#include "icalproperty.h"
49#include "icalcomponent.h"
50
51#include <string.h> /* For strncpy & size_t */
52#include <stdio.h> /* For FILE and fgets and sprintf */
53#include <stdlib.h> /* for free */
54
55int snprintf(char *str, size_t n, char const *fmt, ...);
56
57extern icalvalue* icalparser_yy_value;
58void set_parser_value_state(icalvalue_kind kind);
59int ical_yyparse(void);
60
61char* icalparser_get_next_char(char c, char *str);
62char* icalparser_get_next_parameter(char* line,char** end);
63char* icalparser_get_next_value(char* line, char **end, icalvalue_kind kind);
64char* icalparser_get_prop_name(char* line, char** end);
65char* icalparser_get_param_name(char* line, char **end);
66
67#define TMP_BUF_SIZE 80
68
69struct icalparser_impl
70{
71 int buffer_full; /* flag indicates that temp is smaller that
72 data being read into it*/
73 int continuation_line; /* last line read was a continuation line */
74 size_t tmp_buf_size;
75 char temp[TMP_BUF_SIZE];
76 icalcomponent *root_component;
77 int version;
78 int level;
79 int lineno;
80 icalparser_state state;
81 pvl_list components;
82
83 void *line_gen_data;
84
85};
86
87
88icalparser* icalparser_new(void)
89{
90 struct icalparser_impl* impl = 0;
91 if ( ( impl = (struct icalparser_impl*)
92 malloc(sizeof(struct icalparser_impl))) == 0) {
93 icalerror_set_errno(ICAL_NEWFAILED_ERROR);
94 return 0;
95 }
96
97 impl->root_component = 0;
98 impl->components = pvl_newlist();
99 impl->level = 0;
100 impl->state = ICALPARSER_SUCCESS;
101 impl->tmp_buf_size = TMP_BUF_SIZE;
102 impl->buffer_full = 0;
103 impl->lineno = 0;
104 impl->continuation_line = 0;
105 memset(impl->temp,0, TMP_BUF_SIZE);
106
107 return (icalparser*)impl;
108}
109
110
111void icalparser_free(icalparser* parser)
112{
113 struct icalparser_impl* impl = (struct icalparser_impl*)parser;
114 icalcomponent *c;
115
116 if (impl->root_component != 0){
117 icalcomponent_free(impl->root_component);
118 }
119
120 while( (c=pvl_pop(impl->components)) != 0){
121 icalcomponent_free(c);
122 }
123
124 pvl_free(impl->components);
125
126 free(impl);
127}
128
129void icalparser_set_gen_data(icalparser* parser, void* data)
130{
131 struct icalparser_impl* impl = (struct icalparser_impl*)parser;
132
133 impl->line_gen_data = data;
134}
135
136
137icalvalue* icalvalue_new_From_string_with_error(icalvalue_kind kind,
138 char* str,
139 icalproperty **error);
140
141
142
143char* icalparser_get_next_char(char c, char *str)
144{
145 int quote_mode = 0;
146 char* p;
147
148
149 for(p=str; *p!=0; p++){
150
151 if ( quote_mode == 0 && *p=='"' && *(p-1) != '\\' ){
152 quote_mode =1;
153 continue;
154 }
155
156 if ( quote_mode == 1 && *p=='"' && *(p-1) != '\\' ){
157 quote_mode =0;
158 continue;
159 }
160
161 if (quote_mode == 0 && *p== c && *(p-1) != '\\' ){
162 return p;
163 }
164
165 }
166
167 return 0;
168}
169
170/* make a new tmp buffer out of a substring */
171char* make_segment(char* start, char* end)
172{
173 char *buf;
174 size_t size = (size_t)end - (size_t)start;
175
176 buf = icalmemory_tmp_buffer(size+1);
177
178
179 strncpy(buf,start,size);
180 *(buf+size) = 0;
181
182 return buf;
183
184}
185
186const char* input_buffer;
187const char* input_buffer_p;
188//#define min(a,b) ((a) < (b) ? (a) : (b))
189
190int icalparser_flex_input(char* buf, int max_size)
191{
192 int n = max_size; // = min(max_size,strlen(input_buffer_p));
193 if ( n < ((int )strlen(input_buffer_p)) )
194 n = strlen(input_buffer_p);
195 if (n > 0){
196 memcpy(buf, input_buffer_p, n);
197 input_buffer_p += n;
198 return n;
199 } else {
200 return 0;
201 }
202}
203
204void icalparser_clear_flex_input(void)
205{
206 input_buffer_p = input_buffer+strlen(input_buffer);
207}
208
209/* Call the flex/bison parser to parse a complex value */
210
211icalvalue* icalparser_parse_value(icalvalue_kind kind,
212 const char* str, icalproperty** error)
213{
214 int r;
215 input_buffer_p = input_buffer = str;
216
217 set_parser_value_state(kind);
218 icalparser_yy_value = 0;
219
220 r = ical_yyparse();
221
222 /* Error. Parse failed */
223 if( icalparser_yy_value == 0 || r != 0){
224
225 if(icalparser_yy_value !=0){
226 icalvalue_free(icalparser_yy_value);
227 icalparser_yy_value = 0;
228 }
229
230 return 0;
231 }
232
233 if (error != 0){
234 *error = 0;
235 }
236
237 return icalparser_yy_value;
238}
239
240char* icalparser_get_prop_name(char* line, char** end)
241{
242 char* p;
243 char* v;
244 char *str;
245
246 p = icalparser_get_next_char(';',line);
247 v = icalparser_get_next_char(':',line);
248 if (p== 0 && v == 0) {
249 return 0;
250 }
251
252 /* There is no ';' or, it is after the ';' that marks the beginning of
253 the value */
254 if (v!=0 && ( p == 0 || p > v)){
255 str = make_segment(line,v);
256 *end = v+1;
257 } else {
258 str = make_segment(line,p);
259 *end = p+1;
260 }
261
262 return str;
263}
264
265char* icalparser_get_param_name(char* line, char **end)
266{
267
268 char* next;
269 char *str;
270
271 next = icalparser_get_next_char('=',line);
272
273 if (next == 0) {
274 return 0;
275 }
276
277 str = make_segment(line,next);
278 *end = next+1;
279 return str;
280
281}
282
283char* icalparser_get_next_paramvalue(char* line, char **end)
284{
285
286 char* next;
287 char *str;
288
289 next = icalparser_get_next_char(',',line);
290
291 if (next == 0){
292 next = (char*)(size_t)line+(size_t)strlen(line);\
293 }
294
295 if (next == line){
296 return 0;
297 } else {
298 str = make_segment(line,next);
299 *end = next+1;
300 return str;
301 }
302
303}
304
305/* A property may have multiple values, if the values are seperated by
306 commas in the content line. This routine will look for the next
307 comma after line and will set the next place to start searching in
308 end. */
309
310char* icalparser_get_next_value(char* line, char **end, icalvalue_kind kind)
311{
312
313 char* next;
314 char *p;
315 char *str;
316 size_t length = strlen(line);
317
318 p = line;
319 while(1){
320
321 next = icalparser_get_next_char(',',p);
322
323 /* Unforunately, RFC2445 says that for the RECUR value, COMMA
324 can both seperate digits in a list, and it can seperate
325 multiple recurrence specifications. This is not a friendly
326 part of the spec. This weirdness tries to
327 distinguish the two uses. it is probably a HACK*/
328
329 if( kind == ICAL_RECUR_VALUE ) {
330 if ( next != 0 &&
331 (*end+length) > next+5 &&
332 strncmp(next,"FREQ",4) == 0
333 ) {
334 /* The COMMA was followed by 'FREQ', is it a real seperator*/
335 /* Fall through */
336 } else if (next != 0){
337 /* Not real, get the next COMMA */
338 p = next+1;
339 next = 0;
340 continue;
341 }
342 }
343
344 /* If the comma is preceeded by a '\', then it is a literal and
345 not a value seperator*/
346
347 if ( (next!=0 && *(next-1) == '\\') ||
348 (next!=0 && *(next-3) == '\\')
349 )
350 /*second clause for '/' is on prev line. HACK may be out of bounds */
351 {
352 p = next+1;
353 } else {
354 break;
355 }
356
357 }
358
359 if (next == 0){
360 next = (char*)(size_t)line+length;
361 *end = next;
362 } else {
363 *end = next+1;
364 }
365
366 if (next == line){
367 return 0;
368 }
369
370
371 str = make_segment(line,next);
372 return str;
373
374}
375
376char* icalparser_get_next_parameter(char* line,char** end)
377{
378 char *next;
379 char *v;
380 char *str;
381
382 v = icalparser_get_next_char(':',line);
383 next = icalparser_get_next_char(';', line);
384
385 /* There is no ';' or, it is after the ':' that marks the beginning of
386 the value */
387
388 if (next == 0 || next > v) {
389 next = icalparser_get_next_char(':', line);
390 }
391
392 if (next != 0) {
393 str = make_segment(line,next);
394 *end = next+1;
395 return str;
396 } else {
397 *end = line;
398 return 0;
399 }
400}
401
402/* Get a single property line, from the property name through the
403 final new line, and include any continuation lines */
404
405char* icalparser_get_line(icalparser *parser,
406 char* (*line_gen_func)(char *s, size_t size, void *d))
407{
408 char *line;
409 char *line_p;
410 struct icalparser_impl* impl = (struct icalparser_impl*)parser;
411 size_t buf_size = impl->tmp_buf_size;
412
413
414 line_p = line = icalmemory_new_buffer(buf_size);
415 line[0] = '\0';
416
417 /* Read lines by calling line_gen_func and putting the data into
418 impl->temp. If the line is a continuation line ( begins with a
419 space after a newline ) then append the data onto line and read
420 again. Otherwise, exit the loop. */
421
422 while(1) {
423
424 /* The first part of the loop deals with the temp buffer,
425 which was read on he last pass through the loop. The
426 routine is split like this because it has to read lone line
427 ahead to determine if a line is a continuation line. */
428
429
430 /* The tmp buffer is not clear, so transfer the data in it to the
431 output. This may be left over from a previous call */
432 if (impl->temp[0] != '\0' ) {
433
434 /* If the last position in the temp buffer is occupied,
435 mark the buffer as full. The means we will do another
436 read later, because the line is not finished */
437 if (impl->temp[impl->tmp_buf_size-1] == 0 &&
438 impl->temp[impl->tmp_buf_size-2] != '\n'&&
439 impl->temp[impl->tmp_buf_size-2] != 0 ){
440 impl->buffer_full = 1;
441 } else {
442 impl->buffer_full = 0;
443 }
444
445 /* Copy the temp to the output and clear the temp buffer. */
446 if(impl->continuation_line==1){
447 /* back up the pointer to erase the continuation characters */
448 impl->continuation_line = 0;
449 line_p--;
450
451 if ( *(line_p-1) == '\r'){
452 line_p--;
453 }
454
455 /* copy one space up to eliminate the leading space*/
456 icalmemory_append_string(&line,&line_p,&buf_size,
457 impl->temp+1);
458
459 } else {
460 icalmemory_append_string(&line,&line_p,&buf_size,impl->temp);
461 }
462
463 impl->temp[0] = '\0' ;
464 }
465
466 impl->temp[impl->tmp_buf_size-1] = 1; /* Mark end of buffer */
467
468 /****** Here is where the routine gets string data ******************/
469 if ((*line_gen_func)(impl->temp,impl->tmp_buf_size,impl->line_gen_data)
470 ==0){/* Get more data */
471
472 /* If the first position is clear, it means we didn't get
473 any more data from the last call to line_ge_func*/
474 if (impl->temp[0] == '\0'){
475
476 if(line[0] != '\0'){
477 /* There is data in the output, so fall trhough and process it*/
478 break;
479 } else {
480 /* No data in output; return and signal that there
481 is no more input*/
482 free(line);
483 return 0;
484 }
485 }
486 }
487
488
489 /* If the output line ends in a '\n' and the temp buffer
490 begins with a ' ', then the buffer holds a continuation
491 line, so keep reading. */
492
493 if ( line_p > line+1 && *(line_p-1) == '\n'
494 && (impl->temp[0] == ' ' || impl->temp[0] == '\t') ) {
495
496 impl->continuation_line = 1;
497
498 } else if ( impl->buffer_full == 1 ) {
499
500 /* The buffer was filled on the last read, so read again */
501
502 } else {
503
504 /* Looks like the end of this content line, so break */
505 break;
506 }
507
508
509 }
510
511 /* Erase the final newline and/or carriage return*/
512 if ( line_p > line+1 && *(line_p-1) == '\n') {
513 *(line_p-1) = '\0';
514 if ( *(line_p-2) == '\r'){
515 *(line_p-2) = '\0';
516 }
517
518 } else {
519 *(line_p) = '\0';
520 }
521
522 return line;
523
524}
525
526void insert_error(icalcomponent* comp, char* text,
527 char* message, icalparameter_xlicerrortype type)
528{
529 char temp[1024];
530
531 if (text == 0){
532 snprintf(temp,1024,"%s:",message);
533 } else {
534 snprintf(temp,1024,"%s: %s",message,text);
535 }
536
537 icalcomponent_add_property
538 (comp,
539 icalproperty_vanew_xlicerror(
540 temp,
541 icalparameter_new_xlicerrortype(type),
542 0));
543}
544
545int line_is_blank(char* line){
546 int i=0;
547
548 for(i=0; *(line+i)!=0; i++){
549 char c = *(line+i);
550
551 if(c != ' ' && c != '\n' && c != '\t'){
552 return 0;
553 }
554 }
555
556 return 1;
557}
558
559icalcomponent* icalparser_parse(icalparser *parser,
560 char* (*line_gen_func)(char *s, size_t size,
561 void* d))
562{
563
564 char* line;
565 icalcomponent *c=0;
566 icalcomponent *root=0;
567 struct icalparser_impl *impl = (struct icalparser_impl*)parser;
568 icalerrorstate es = icalerror_get_error_state(ICAL_MALFORMEDDATA_ERROR);
569
570 icalerror_check_arg_rz((parser !=0),"parser");
571
572 icalerror_set_error_state(ICAL_MALFORMEDDATA_ERROR,ICAL_ERROR_NONFATAL);
573
574 do{
575 line = icalparser_get_line(parser, line_gen_func);
576
577 if ((c = icalparser_add_line(parser,line)) != 0){
578
579 if(icalcomponent_get_parent(c) !=0){
580 /* This is bad news... assert? */
581 }
582
583 assert(impl->root_component == 0);
584 assert(pvl_count(impl->components) ==0);
585
586 if (root == 0){
587 /* Just one component */
588 root = c;
589 } else if(icalcomponent_isa(root) != ICAL_XROOT_COMPONENT) {
590 /*Got a second component, so move the two components under
591 an XROOT container */
592 icalcomponent *tempc = icalcomponent_new(ICAL_XROOT_COMPONENT);
593 icalcomponent_add_component(tempc, root);
594 icalcomponent_add_component(tempc, c);
595 root = tempc;
596 } else if(icalcomponent_isa(root) == ICAL_XROOT_COMPONENT) {
597 /* Already have an XROOT container, so add the component
598 to it*/
599 icalcomponent_add_component(root, c);
600
601 } else {
602 /* Badness */
603 assert(0);
604 }
605
606 c = 0;
607
608 }
609 if(line != 0){
610 free(line);
611 }
612 } while ( line != 0);
613
614 icalerror_set_error_state(ICAL_MALFORMEDDATA_ERROR,es);
615
616 return root;
617
618}
619
620
621icalcomponent* icalparser_add_line(icalparser* parser,
622 char* line)
623{
624 char *p;
625 char *str;
626 char *end;
627 int vcount = 0;
628 icalproperty *prop;
629 icalproperty_kind prop_kind;
630 icalvalue *value;
631 icalvalue_kind value_kind = ICAL_NO_VALUE;
632
633
634 struct icalparser_impl *impl = (struct icalparser_impl*)parser;
635 icalerror_check_arg_rz((parser != 0),"parser");
636
637
638 if (line == 0)
639 {
640 impl->state = ICALPARSER_ERROR;
641 return 0;
642 }
643
644 if(line_is_blank(line) == 1){
645 return 0;
646 }
647
648 /* Begin by getting the property name at the start of the line. The
649 property name may end up being "BEGIN" or "END" in which case it
650 is not really a property, but the marker for the start or end of
651 a component */
652
653 end = 0;
654 str = icalparser_get_prop_name(line, &end);
655
656 if (str == 0 || strlen(str) == 0 ){
657 /* Could not get a property name */
658 icalcomponent *tail = pvl_data(pvl_tail(impl->components));
659
660 if (tail){
661 insert_error(tail,line,
662 "Got a data line, but could not find a property name or component begin tag",
663 ICAL_XLICERRORTYPE_COMPONENTPARSEERROR);
664 }
665 tail = 0;
666 impl->state = ICALPARSER_ERROR;
667 return 0;
668 }
669
670 /**********************************************************************
671 * Handle begin and end of components
672 **********************************************************************/
673 /* If the property name is BEGIN or END, we are actually
674 starting or ending a new component */
675
676 if(strcmp(str,"BEGIN") == 0){
677 icalcomponent *c;
678 icalcomponent_kind comp_kind;
679
680 impl->level++;
681 str = icalparser_get_next_value(end,&end, value_kind);
682
683
684 comp_kind = icalenum_string_to_component_kind(str);
685
686 if (comp_kind == ICAL_NO_COMPONENT){
687 c = icalcomponent_new(ICAL_XLICINVALID_COMPONENT);
688 insert_error(c,str,"Parse error in component name",
689 ICAL_XLICERRORTYPE_COMPONENTPARSEERROR);
690 }
691
692 c = icalcomponent_new(comp_kind);
693
694 if (c == 0){
695 c = icalcomponent_new(ICAL_XLICINVALID_COMPONENT);
696 insert_error(c,str,"Parse error in component name",
697 ICAL_XLICERRORTYPE_COMPONENTPARSEERROR);
698 }
699
700 pvl_push(impl->components,c);
701
702 impl->state = ICALPARSER_BEGIN_COMP;
703 return 0;
704
705 } else if (strcmp(str,"END") == 0 ) {
706 icalcomponent* tail;
707
708 impl->level--;
709 str = icalparser_get_next_value(end,&end, value_kind);
710
711 /* Pop last component off of list and add it to the second-to-last*/
712 impl->root_component = pvl_pop(impl->components);
713
714 tail = pvl_data(pvl_tail(impl->components));
715
716 if(tail != 0){
717 icalcomponent_add_component(tail,impl->root_component);
718 }
719
720 tail = 0;
721
722 /* Return the component if we are back to the 0th level */
723 if (impl->level == 0){
724 icalcomponent *rtrn;
725
726 if(pvl_count(impl->components) != 0){
727 /* There are still components on the stack -- this means
728 that one of them did not have a proper "END" */
729 pvl_push(impl->components,impl->root_component);
730 icalparser_clean(parser); /* may reset impl->root_component*/
731 }
732
733 assert(pvl_count(impl->components) == 0);
734
735 impl->state = ICALPARSER_SUCCESS;
736 rtrn = impl->root_component;
737 impl->root_component = 0;
738 return rtrn;
739
740 } else {
741 impl->state = ICALPARSER_END_COMP;
742 return 0;
743 }
744 }
745
746
747 /* There is no point in continuing if we have not seen a
748 component yet */
749
750 if(pvl_data(pvl_tail(impl->components)) == 0){
751 impl->state = ICALPARSER_ERROR;
752 return 0;
753 }
754
755
756 /**********************************************************************
757 * Handle property names
758 **********************************************************************/
759
760 /* At this point, the property name really is a property name,
761 (Not a component name) so make a new property and add it to
762 the component */
763
764
765 prop_kind = icalproperty_string_to_kind(str);
766
767 prop = icalproperty_new(prop_kind);
768
769 if (prop != 0){
770 icalcomponent *tail = pvl_data(pvl_tail(impl->components));
771
772 if(prop_kind==ICAL_X_PROPERTY){
773 icalproperty_set_x_name(prop,str);
774 }
775
776 icalcomponent_add_property(tail, prop);
777
778 /* Set the value kind for the default for this type of
779 property. This may be re-set by a VALUE parameter */
780 value_kind = icalproperty_kind_to_value_kind(icalproperty_isa(prop));
781
782 } else {
783 icalcomponent* tail = pvl_data(pvl_tail(impl->components));
784
785 insert_error(tail,str,"Parse error in property name",
786 ICAL_XLICERRORTYPE_PROPERTYPARSEERROR);
787
788 tail = 0;
789 impl->state = ICALPARSER_ERROR;
790 return 0;
791 }
792
793 /**********************************************************************
794 * Handle parameter values
795 **********************************************************************/
796
797 /* Now, add any parameters to the last property */
798
799 p = 0;
800 while(1) {
801
802 if (*(end-1) == ':'){
803 /* if the last seperator was a ":" and the value is a
804 URL, icalparser_get_next_parameter will find the
805 ':' in the URL, so better break now. */
806 break;
807 }
808
809 str = icalparser_get_next_parameter(end,&end);
810
811 if (str != 0){
812 char* name;
813 char* pvalue;
814
815 icalparameter *param = 0;
816 icalparameter_kind kind;
817 icalcomponent *tail = pvl_data(pvl_tail(impl->components));
818
819 name = icalparser_get_param_name(str,&pvalue);
820
821 if (name == 0){
822 /* 'tail' defined above */
823 insert_error(tail, str, "Cant parse parameter name",
824 ICAL_XLICERRORTYPE_PARAMETERNAMEPARSEERROR);
825 tail = 0;
826 break;
827 }
828
829 kind = icalparameter_string_to_kind(name);
830
831 if(kind == ICAL_X_PARAMETER){
832 param = icalparameter_new(ICAL_X_PARAMETER);
833
834 if(param != 0){
835 icalparameter_set_xname(param,name);
836 icalparameter_set_xvalue(param,pvalue);
837 }
838
839
840 } else if (kind != ICAL_NO_PARAMETER){
841 param = icalparameter_new_from_value_string(kind,pvalue);
842 } else {
843 /* Error. Failed to parse the parameter*/
844 /* 'tail' defined above */
845 insert_error(tail, str, "Cant parse parameter name",
846 ICAL_XLICERRORTYPE_PARAMETERNAMEPARSEERROR);
847 tail = 0;
848 impl->state = ICALPARSER_ERROR;
849 return 0;
850 }
851
852 if (param == 0){
853 /* 'tail' defined above */
854 insert_error(tail,str,"Cant parse parameter value",
855 ICAL_XLICERRORTYPE_PARAMETERVALUEPARSEERROR);
856
857 tail = 0;
858 impl->state = ICALPARSER_ERROR;
859 continue;
860 }
861
862 /* If it is a VALUE parameter, set the kind of value*/
863 if (icalparameter_isa(param)==ICAL_VALUE_PARAMETER){
864
865 value_kind = (icalvalue_kind)
866 icalparameter_value_to_value_kind(
867 icalparameter_get_value(param)
868 );
869
870 if (value_kind == ICAL_NO_VALUE){
871
872 /* Ooops, could not parse the value of the
873 parameter ( it was not one of the defined
874 values ), so reset the value_kind */
875
876 insert_error(
877 tail, str,
878 "Got a VALUE parameter with an unknown type",
879 ICAL_XLICERRORTYPE_PARAMETERVALUEPARSEERROR);
880 icalparameter_free(param);
881
882 value_kind =
883 icalproperty_kind_to_value_kind(
884 icalproperty_isa(prop));
885
886 icalparameter_free(param);
887 tail = 0;
888 impl->state = ICALPARSER_ERROR;
889 return 0;
890 }
891 }
892
893 /* Everything is OK, so add the parameter */
894 icalproperty_add_parameter(prop,param);
895 tail = 0;
896
897 } else { /* if ( str != 0) */
898 /* If we did not get a param string, go on to looking
899 for a value */
900 break;
901 } /* if ( str != 0) */
902
903 } /* while(1) */
904
905 /**********************************************************************
906 * Handle values
907 **********************************************************************/
908
909 /* Look for values. If there are ',' characters in the values,
910 then there are multiple values, so clone the current
911 parameter and add one part of the value to each clone */
912
913 vcount=0;
914 while(1) {
915 str = icalparser_get_next_value(end,&end, value_kind);
916
917 if (str != 0){
918
919 if (vcount > 0){
920 /* Actually, only clone after the second value */
921 icalproperty* clone = icalproperty_new_clone(prop);
922 icalcomponent* tail = pvl_data(pvl_tail(impl->components));
923
924 icalcomponent_add_property(tail, clone);
925 prop = clone;
926 tail = 0;
927 }
928
929 value = icalvalue_new_from_string(value_kind, str);
930
931 /* Don't add properties without value */
932 if (value == 0){
933 char temp[200]; /* HACK */
934
935 icalproperty_kind prop_kind = icalproperty_isa(prop);
936 icalcomponent* tail = pvl_data(pvl_tail(impl->components));
937
938 sprintf(temp,"Cant parse as %s value in %s property. Removing entire property",
939 icalvalue_kind_to_string(value_kind),
940 icalproperty_kind_to_string(prop_kind));
941
942 insert_error(tail, str, temp,
943 ICAL_XLICERRORTYPE_VALUEPARSEERROR);
944
945 /* Remove the troublesome property */
946 icalcomponent_remove_property(tail,prop);
947 icalproperty_free(prop);
948 prop = 0;
949 tail = 0;
950 impl->state = ICALPARSER_ERROR;
951 return 0;
952
953 } else {
954 vcount++;
955 icalproperty_set_value(prop, value);
956 }
957
958
959 } else {
960 if (vcount == 0){
961 char temp[200]; /* HACK */
962
963 icalproperty_kind prop_kind = icalproperty_isa(prop);
964 icalcomponent *tail = pvl_data(pvl_tail(impl->components));
965
966 sprintf(temp,"No value for %s property. Removing entire property",
967 icalproperty_kind_to_string(prop_kind));
968
969 insert_error(tail, str, temp,
970 ICAL_XLICERRORTYPE_VALUEPARSEERROR);
971
972 /* Remove the troublesome property */
973 icalcomponent_remove_property(tail,prop);
974 icalproperty_free(prop);
975 prop = 0;
976 tail = 0;
977 impl->state = ICALPARSER_ERROR;
978 return 0;
979 } else {
980
981 break;
982 }
983 }
984 }
985
986 /****************************************************************
987 * End of component parsing.
988 *****************************************************************/
989
990 if (pvl_data(pvl_tail(impl->components)) == 0 &&
991 impl->level == 0){
992 /* HACK. Does this clause ever get executed? */
993 impl->state = ICALPARSER_SUCCESS;
994 assert(0);
995 return impl->root_component;
996 } else {
997 impl->state = ICALPARSER_IN_PROGRESS;
998 return 0;
999 }
1000
1001}
1002
1003icalparser_state icalparser_get_state(icalparser* parser)
1004{
1005 struct icalparser_impl* impl = (struct icalparser_impl*) parser;
1006 return impl->state;
1007
1008}
1009
1010icalcomponent* icalparser_clean(icalparser* parser)
1011{
1012 struct icalparser_impl* impl = (struct icalparser_impl*) parser;
1013 icalcomponent *tail;
1014
1015 icalerror_check_arg_rz((parser != 0 ),"parser");
1016
1017 /* We won't get a clean exit if some components did not have an
1018 "END" tag. Clear off any component that may be left in the list */
1019
1020 while((tail=pvl_data(pvl_tail(impl->components))) != 0){
1021
1022 insert_error(tail," ",
1023 "Missing END tag for this component. Closing component at end of input.",
1024 ICAL_XLICERRORTYPE_COMPONENTPARSEERROR);
1025
1026
1027 impl->root_component = pvl_pop(impl->components);
1028 tail=pvl_data(pvl_tail(impl->components));
1029
1030 if(tail != 0){
1031 if(icalcomponent_get_parent(impl->root_component)!=0){
1032 icalerror_warn("icalparser_clean is trying to attach a component for the second time");
1033 } else {
1034 icalcomponent_add_component(tail,impl->root_component);
1035 }
1036 }
1037
1038 }
1039
1040 return impl->root_component;
1041
1042}
1043
1044struct slg_data {
1045 const char* pos;
1046 const char* str;
1047};
1048
1049char* string_line_generator(char *out, size_t buf_size, void *d)
1050{
1051 char *n;
1052 size_t size;
1053 struct slg_data* data = (struct slg_data*)d;
1054
1055 if(data->pos==0){
1056 data->pos=data->str;
1057 }
1058
1059 /* If the pointer is at the end of the string, we are done */
1060 if (*(data->pos)==0){
1061 return 0;
1062 }
1063
1064 n = strchr(data->pos,'\n');
1065
1066 if (n == 0){
1067 size = strlen(data->pos);
1068 } else {
1069 n++; /* include newline in output */
1070 size = (n-data->pos);
1071 }
1072
1073 if (size > buf_size-1){
1074 size = buf_size-1;
1075 }
1076
1077
1078 strncpy(out,data->pos,size);
1079
1080 *(out+size) = '\0';
1081
1082 data->pos += size;
1083
1084 return out;
1085}
1086
1087icalcomponent* icalparser_parse_string(const char* str)
1088{
1089 icalcomponent *c;
1090 struct slg_data d;
1091 icalparser *p;
1092
1093 icalerrorstate es = icalerror_get_error_state(ICAL_MALFORMEDDATA_ERROR);
1094
1095 d.pos = 0;
1096 d.str = str;
1097
1098 p = icalparser_new();
1099 icalparser_set_gen_data(p,&d);
1100
1101 icalerror_set_error_state(ICAL_MALFORMEDDATA_ERROR,ICAL_ERROR_NONFATAL);
1102
1103 c = icalparser_parse(p,string_line_generator);
1104
1105 icalerror_set_error_state(ICAL_MALFORMEDDATA_ERROR,es);
1106
1107 icalparser_free(p);
1108
1109 return c;
1110
1111}