1#!/usr/bin/env perl
2################################################################################
3# (C) COPYRIGHT 2000, Eric Busboom <eric@civicknowledge.com>
4#
5# This library is free software; you can redistribute it and/or modify
6# it under the terms of either:
7#
8#   The LGPL as published by the Free Software Foundation, version
9#   2.1, available at: https://www.gnu.org/licenses/lgpl-2.1.txt
10#
11# Or:
12#
13#   The Mozilla Public License Version 2.0. You may obtain a copy of
14#   the License at https://www.mozilla.org/MPL/
15################################################################################
16require "readvaluesfile.pl";
17
18use Getopt::Std;
19getopts('chspmi:');
20
21# ARG 0 is properties.csv
22%propmap = read_properties_file($ARGV[0]);
23
24# ARG 1 is value-types.txt
25%valuemap = read_values_file($ARGV[1]);
26
27$include_vanew = 1;
28
29# Write the file inline by copying everything before a demarcation
30# line, and putting the generated data after the demarcation
31
32if ($opt_i) {
33
34  open(IN, $opt_i) || die "Can't open input file $opt_i";
35
36  while (<IN>) {
37
38    if (/<insert_code_here>/) {
39      insert_code();
40    } else {
41      print;
42    }
43
44  }
45
46}
47
48sub fudge_data
49{
50  my $prop = shift;
51
52  my $value = $propmap{$prop}->{'lic_value'};
53
54  if (!$value) {
55    die "Can't find value for property \"$prop\"\n";
56  }
57  my $ucf = join("", map {ucfirst(lc($_));} split(/-/, $prop));
58  my $lc  = lc($ucf);
59  my $uc  = uc($lc);
60
61  my $ucfvalue = join("", map {ucfirst(lc($_));} split(/-/, $value));
62  my $lcvalue  = lc($ucfvalue);
63  my $ucvalue  = uc($lcvalue);
64
65  my $type = $valuemap{$value}->{C}->[1];
66  $type =~ s/char\*/char \*/;
67
68  my @comp_types = @{$valuemap{$value}->{'components'}};
69  return ($uc, $lc, $lcvalue, $ucvalue, $type, @comp_types);
70
71}
72
73sub insert_code
74{
75
76  # Create the property map data
77  if ($opt_c) {
78
79    my @props = sort {$propmap{$a}->{"kindEnum"} <=> $propmap{$b}->{"kindEnum"}} keys %propmap;
80    my $count = scalar(@props);
81
82    print "static const struct icalproperty_map property_map[$count] = {\n";
83
84    foreach $prop (@props) {
85
86      next if !$prop;
87
88      next if $prop eq 'NO' or $prop eq 'ANY';
89
90      my ($uc, $lc, $lcvalue, $ucvalue, $type, @comp_types) = fudge_data($prop);
91      my $defvalue = $propmap{$prop}->{'default_value'};
92      $defvalue =~ s/-//g;
93
94      my @flags = @{$propmap{$prop}->{'flags'}};
95
96      print "    { ICAL_${uc}_PROPERTY, \"$prop\",\n";
97      print "      ICAL_${ucvalue}_VALUE, ICAL_${defvalue}_VALUE,\n";
98      print "      { ";
99
100      if (@comp_types) {
101          foreach $comp (@comp_types) {
102              $comp =~ s/-//g;
103              print "ICAL_${comp}_VALUE, ";
104          }
105      } elsif ($defvalue ne "NO") {
106          print "ICAL_${defvalue}_VALUE, ";
107      } else {
108          print "ICAL_${ucvalue}_VALUE, ";
109      }
110
111      print "ICAL_NO_VALUE }, ";
112
113      if (@flags) {
114          my $sep = "\n      ";
115          foreach $flag (@flags) {
116              $flag =~ s/-//g;
117              $flag  = uc($flag);
118              print "${sep}ICAL_PROPERTY_${flag}";
119              $sep = " | ";
120          }
121      } else {
122          print "0";
123      }
124
125      print " },\n";
126    }
127
128    $prop = "NO";
129
130    my ($uc, $lc, $lcvalue, $ucvalue, $type) = fudge_data($prop);
131
132    print "    { ICAL_${uc}_PROPERTY, \"\",";
133    print "      ICAL_NO_VALUE, ICAL_NO_VALUE,\n";
134    print "      { ICAL_NO_VALUE }, 0 }\n}";
135    print ";\n\n";
136
137    $count    = 1;
138    $bigcount = 0;
139    my %lines;
140
141    foreach $value (sort keys %valuemap) {
142
143      next if !$value;
144      next if $value eq 'NO' or $prop eq 'ANY';
145
146      my $ucv = join("", map {uc(lc($_));} split(/-/, $value));
147      my @enums = @{$valuemap{$value}->{'enums'}};
148
149      if (@enums) {
150
151        my ($c_autogen, $c_type) = @{$valuemap{$value}->{'C'}};
152
153        foreach $e (@enums) {
154
155          $e =~ /([a-zA-Z0-9\-]+)=?([0-9]+)?/;
156          $e = $1;
157          if ($2) {
158            $idx = $2;
159          } else {
160            $idx++;
161          }
162
163          my $uce = join("", map {uc(lc($_));} split(/-/, $e));
164
165          if ($e ne "X" and $e ne "NONE") {
166            $str = $e;
167          } else {
168            $str = "";
169          }
170          if ($e eq "NONE") {
171            $bigcount += 100;
172          }
173
174          # Create empty "future" properties so the hash math works.
175          if ($e eq "NONE") {
176            my ($tbd) = 1;
177            $saveidx++;
178            for (; $saveidx < $idx ; $saveidx++, $tbd++) {
179              $lines{$saveidx} =
180                "    {ICAL_${ucv}_PROPERTY,ICAL_${ucv}_NONE, \"\" }, /*$saveidx*/\n";
181            }
182          }
183
184          # Place each property into a hash based on the index specified in value-types.csv
185          # The lines are printed so they're in the same order as the indices
186          $lines{$idx} = "    {ICAL_${ucv}_PROPERTY,ICAL_${ucv}_${uce}, \"$str\" }, /*$idx*/\n";
187          $saveidx = $idx;
188          $count++;
189        }
190      }
191    }
192
193    $bigcount++;
194
195    print "static const struct icalproperty_enum_map enum_map[$bigcount] = {\n";
196    foreach $line (sort keys %lines) {
197      print $lines{$line};
198    }
199    print "    {ICAL_NO_PROPERTY, 0, \"\"}\n};\n\n";
200
201  }
202
203  if ($opt_h) {
204
205    # Create the property enumerations list
206    my $enumConst = $propmap{'ANY'}->{"kindEnum"};
207    print "typedef enum icalproperty_kind {\n    ICAL_ANY_PROPERTY = " . $enumConst . ",\n";
208    foreach $prop (sort keys %propmap) {
209
210      next if !$prop;
211
212      next if $prop eq 'NO' or $prop eq 'ANY';
213
214      my ($uc, $lc, $lcvalue, $ucvalue, $type) = fudge_data($prop);
215
216      $enumConst = $propmap{$prop}->{"kindEnum"};
217
218      print "    ICAL_${uc}_PROPERTY = " . $enumConst . ",\n";
219
220    }
221    $enumConst = $propmap{'NO'}->{"kindEnum"};
222    print "    ICAL_NO_PROPERTY = " . $enumConst . "\n} icalproperty_kind;\n";
223
224  }
225
226  foreach $prop (sort keys %propmap) {
227
228    next if !$prop;
229
230    next if $prop eq 'NO' or $prop eq 'ANY';
231
232    my ($uc, $lc, $lcvalue, $ucvalue, $type) = fudge_data($prop);
233
234    my $pointer_check;
235    if ($type =~ /\*/) {
236      $pointer_check = "    icalerror_check_arg_rz((v != 0), \"v\");\n" if $type =~ /\*/;
237    } elsif ($type eq "void") {
238      $pointer_check = "    icalerror_check_arg_rv((v != 0), \"v\");\n" if $type =~ /\*/;
239
240    }
241
242    my $set_pointer_check = "\n    icalerror_check_arg_rv((v != 0), \"v\");" if $type =~ /\*/;
243
244    if ($opt_c) {    # Generate C source
245
246      if ($include_vanew) {
247        print <<EOM;
248icalproperty *icalproperty_vanew_${lc}($type v, ...)
249{
250    va_list args;
251    struct icalproperty_impl *impl;
252$pointer_check
253    impl = icalproperty_new_impl(ICAL_${uc}_PROPERTY);
254    icalproperty_set_${lc}((icalproperty*)impl, v);
255    va_start(args, v);
256    icalproperty_add_parameters(impl, args);
257    va_end(args);
258    return (icalproperty*)impl;
259}
260EOM
261      }
262      print <<EOM;
263
264/* $prop */
265icalproperty *icalproperty_new_${lc}($type v)
266{
267    struct icalproperty_impl *impl;
268$pointer_check
269    impl = icalproperty_new_impl(ICAL_${uc}_PROPERTY);
270    icalproperty_set_${lc}((icalproperty*)impl, v);
271    return (icalproperty*)impl;
272}
273
274void icalproperty_set_${lc}(icalproperty *prop, $type v)
275{$set_pointer_check
276    icalerror_check_arg_rv((prop != 0), "prop");
277    icalproperty_set_value(prop, icalvalue_new_${lcvalue}(v));
278}
279
280EOM
281
282      # Dirk Theisen pointed out, exdate needs to match TZID parameters in EXDATE
283      if ($lc eq "exdate") {
284        print <<EOM;
285$type icalproperty_get_${lc}(const icalproperty *prop)
286{
287    icalerror_check_arg((prop != 0), "prop");
288    return icalproperty_get_datetime_with_component((icalproperty *)prop, NULL);
289}
290
291EOM
292      } else {
293        print <<EOM;
294$type icalproperty_get_${lc}(const icalproperty *prop)
295{
296    icalerror_check_arg((prop != 0), "prop");
297    return icalvalue_get_${lcvalue}(icalproperty_get_value(prop));
298}
299
300EOM
301      }
302    } elsif ($opt_h) {    # Generate C Header file
303
304      print "\
305/* $prop */\
306LIBICAL_ICAL_EXPORT icalproperty *icalproperty_new_${lc}($type v);\
307LIBICAL_ICAL_EXPORT void icalproperty_set_${lc}(icalproperty *prop, $type v);\
308LIBICAL_ICAL_EXPORT $type icalproperty_get_${lc}(const icalproperty *prop);";
309
310      if ($include_vanew) {
311        print "\nLIBICAL_ICAL_EXPORT icalproperty *icalproperty_vanew_${lc}($type v, ...);\n";
312      }
313
314    }
315
316  }    # This brace terminates the main loop
317
318  if ($opt_h) {
319
320    print "\n#endif /*ICALPROPERTY_H*/\n";
321  }
322
323}
324