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