summaryrefslogtreecommitdiff
path: root/lib/chaos_calendar/ical_occurrences.c
blob: 30a8d85628a88f3c98067dde6c8ec3d6f0f3e9f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <ruby.h>
#include <libical/ical.h>
#include <time.h>

//#define RRULE   "FREQ=MONTHLY;BYMONTH=1,2,3,4,5,6,7,8,9,10,11;BYDAY=-1WE;UNTIL=20091105T220000"
//#define RRULE   "FREQ=DAILY;UNTIL=20991111T220000;VFOO"

VALUE occurrences( VALUE dtstart, VALUE dtend, char *rrule ) {
  struct icaltimetype start, end;
  time_t tt;
  VALUE  tv_sec, occurr = rb_ary_new(); 

  /* Get method ID for Time.tv_sec */
  ID time_tv_sec  = rb_intern( "tv_sec" );
  ID time_to_time = rb_intern( "to_time" );

  if( !rb_respond_to( dtstart, time_tv_sec ) ) {
    if( rb_respond_to( dtstart, time_to_time ) )
      dtstart = rb_funcall( dtstart, time_to_time, 0 );
    else
     rb_raise( rb_eTypeError, "Can't convert dtstart into a Time-like object." );
  }

  if( !rb_respond_to( dtend, time_tv_sec ) ) {
    if( rb_respond_to( dtend, time_to_time ) ) 
      dtend = rb_funcall( dtend, time_to_time, 0 );
    else
     rb_raise( rb_eTypeError, "Can't convert dtend into a Time-like object." );
  }

  /* Apply .tv_sec to our Time objects (if they are Times ...) */
  tv_sec = rb_funcall( dtstart, time_tv_sec, 0 ); 
  tt     = NUM2INT( tv_sec );
  start  = icaltime_from_timet( tt, 0 );

  tv_sec = rb_funcall( dtend, time_tv_sec, 0 );
  tt     = NUM2INT( tv_sec );
  end    = icaltime_from_timet( tt, 0 );

  icalerror_clear_errno();
  icalerror_set_error_state( ICAL_MALFORMEDDATA_ERROR, ICAL_ERROR_NONFATAL);

  struct icalrecurrencetype recur = icalrecurrencetype_from_string( rrule );
  if( icalerrno != ICAL_NO_ERROR ) {
    rb_raise(rb_eArgError, "Malformed RRule");
    return Qnil;
  }

  icalrecur_iterator* ritr = icalrecur_iterator_new( recur, start );

  while(1) {
    struct icaltimetype next = icalrecur_iterator_next(ritr);

    if( icaltime_is_null_time(next) || ( icaltime_compare( next, end ) > 0 ) ) {
      icalrecur_iterator_free(ritr);
      return occurr; 
    }

    rb_ary_push( occurr, rb_time_new( icaltime_as_timet( next ), 0 ) );
  };

  icalrecur_iterator_free(ritr);
  return occurr;
}

VALUE duration_to_fixnum( char * duration ) {
  icalerror_clear_errno();
  icalerror_set_error_state( ICAL_MALFORMEDDATA_ERROR, ICAL_ERROR_NONFATAL);

  struct icaldurationtype dur_struct = icaldurationtype_from_string( duration );

  if( icaldurationtype_is_bad_duration( dur_struct ) )
    rb_raise(rb_eArgError, "Malformed Duration");

  return LONG2FIX(icaldurationtype_as_int( dur_struct ));
}