excel_to_code 0.3.17 → 0.3.18.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +67 -34
  3. data/bin/excel_to_c +8 -78
  4. data/bin/excel_to_go +41 -0
  5. data/bin/excel_to_ruby +2 -69
  6. data/src/commands.rb +2 -0
  7. data/src/commands/common_command_line_options.rb +81 -0
  8. data/src/commands/excel_to_c.rb +3 -0
  9. data/src/commands/excel_to_go.rb +91 -0
  10. data/src/commands/excel_to_x.rb +77 -11
  11. data/src/compile.rb +1 -0
  12. data/src/compile/c/a.out +0 -0
  13. data/src/compile/c/a.out.dSYM/Contents/Resources/DWARF/a.out +0 -0
  14. data/src/compile/c/compile_to_c.rb +2 -0
  15. data/src/compile/c/excel_to_c_runtime.c +691 -145
  16. data/src/compile/c/excel_to_c_runtime_test.c +226 -20
  17. data/src/compile/c/map_formulae_to_c.rb +62 -23
  18. data/src/compile/c/run_c_unit_tests +3 -0
  19. data/src/compile/cd.rb +6 -0
  20. data/src/compile/go.rb +3 -0
  21. data/src/compile/go/compile_to_go.rb +85 -0
  22. data/src/compile/go/compile_to_go_test.rb +73 -0
  23. data/src/compile/go/excel.go +171 -0
  24. data/src/compile/go/excel_test.go +54 -0
  25. data/src/compile/go/map_values_to_go.rb +67 -0
  26. data/src/compile/ruby/map_formulae_to_ruby.rb +30 -12
  27. data/src/excel/excel_functions.rb +26 -1
  28. data/src/excel/excel_functions/ceiling.rb +23 -0
  29. data/src/excel/excel_functions/countif.rb +15 -0
  30. data/src/excel/excel_functions/countifs.rb +10 -0
  31. data/src/excel/excel_functions/floor.rb +14 -0
  32. data/src/excel/excel_functions/hyperlink.rb +9 -0
  33. data/src/excel/excel_functions/na.rb +7 -0
  34. data/src/excel/excel_functions/not.rb +13 -0
  35. data/src/excel/excel_functions/or.rb +30 -0
  36. data/src/excel/excel_functions/product.rb +8 -0
  37. data/src/excel/excel_functions/rate.rb +16 -0
  38. data/src/excel/excel_functions/replace.rb +13 -0
  39. data/src/excel/excel_functions/scurve.rb +73 -0
  40. data/src/excel/excel_functions/sqrt.rb +11 -0
  41. data/src/excel/excel_functions/string_argument.rb +37 -0
  42. data/src/excel/excel_functions/sumifs.rb +19 -8
  43. data/src/excel/excel_functions/text.rb +3 -3
  44. data/src/excel/formula_peg.rb +1 -1
  45. data/src/excel/formula_peg.txt +2 -3
  46. data/src/excel/table.rb +15 -15
  47. data/src/excel_to_code.rb +1 -4
  48. data/src/extract/extract_data_from_worksheet.rb +8 -1
  49. data/src/rewrite/ast_expand_array_formulae.rb +4 -0
  50. data/src/rewrite/caching_formula_parser.rb +16 -11
  51. data/src/simplify.rb +1 -0
  52. data/src/simplify/inline_formulae.rb +16 -0
  53. data/src/simplify/replace_arithmetic_on_ranges.rb +14 -1
  54. data/src/simplify/replace_arrays_with_single_cells.rb +42 -15
  55. data/src/simplify/replace_cell_addresses_with_references.rb +70 -0
  56. data/src/simplify/replace_column_with_column_number.rb +8 -1
  57. data/src/simplify/replace_table_references.rb +40 -19
  58. data/src/simplify/simplify_arithmetic.rb +15 -10
  59. data/src/version.rb +4 -0
  60. metadata +115 -43
  61. data/TODO +0 -25
@@ -10,6 +10,8 @@ class ExcelToC < ExcelToX
10
10
  attr_accessor :create_makefile
11
11
  # If true, writes tests in C rather than in ruby
12
12
  attr_accessor :write_tests_in_c
13
+ # If true, allows unknown Excel functions rather than aborting
14
+ attr_accessor :allow_unknown_functions
13
15
 
14
16
  def set_defaults
15
17
  super
@@ -78,6 +80,7 @@ class ExcelToC < ExcelToX
78
80
  variable_set_counter = 0
79
81
 
80
82
  c = CompileToC.new
83
+ c.allow_unknown_functions = self.allow_unknown_functions
81
84
  c.variable_set_counter = variable_set_counter
82
85
  # Output the elements from each worksheet in turn
83
86
  c.settable = settable
@@ -0,0 +1,91 @@
1
+ # coding: utf-8
2
+
3
+ require_relative 'excel_to_x'
4
+ require 'pathname'
5
+
6
+ class ExcelToGo < ExcelToX
7
+
8
+ def language
9
+ 'go'
10
+ end
11
+
12
+ # Skip this
13
+ def replace_values_with_constants
14
+ end
15
+
16
+ # These actually create the code version of the excel
17
+ def write_code
18
+ write_out_excel_as_code
19
+ write_out_test_as_code
20
+ end
21
+
22
+ def write_out_excel_as_code
23
+ log.info "Starting to write out code"
24
+
25
+ o = output("#{output_name.downcase}.go")
26
+
27
+ o.puts "// Compiled version of #{excel_file}"
28
+ o.puts "package #{output_name.downcase}"
29
+ o.puts
30
+ o.puts excel_lib_imports
31
+ o.puts
32
+
33
+ c = CompileToGo.new
34
+ c.settable = settable
35
+ c.gettable = gettable
36
+ c.rewrite @formulae, @worksheet_c_names, o
37
+ o.puts
38
+
39
+ o.puts excel_lib_functions
40
+ o.puts
41
+
42
+ close(o)
43
+ log.info "Finished writing code"
44
+
45
+ end
46
+
47
+ def excel_lib
48
+ @excel_lib ||= IO.readlines(File.join(File.dirname(__FILE__),'..','compile','go','excel.go')).join
49
+ end
50
+
51
+ def excel_lib_imports
52
+ excel_lib[/import \(.*?\)/m]
53
+ end
54
+
55
+ def excel_lib_functions
56
+ excel_lib[/import \(.*?\)(.*)/m,1]
57
+ end
58
+
59
+ def write_out_test_as_code
60
+ log.info "Starting to write out test"
61
+
62
+ o = output("#{output_name.downcase}_test.go")
63
+
64
+ o.puts "// Test of compiled version of #{excel_file}"
65
+ o.puts "package #{output_name.downcase}"
66
+ o.puts
67
+ o.puts "import ("
68
+ o.puts " \"testing\""
69
+ o.puts ")"
70
+ o.puts
71
+
72
+ c = CompileToGoTest.new
73
+ c.settable = settable
74
+ c.gettable = gettable
75
+ c.rewrite @formulae, @worksheet_c_names, o
76
+ o.puts
77
+
78
+ close(o)
79
+ log.info "Finished writing tests"
80
+ end
81
+
82
+ def compile_code
83
+ # Not needed
84
+ end
85
+
86
+ def run_tests
87
+ return unless actually_run_tests
88
+ log.info "Running the resulting tests"
89
+ log.info `cd #{File.join(output_directory)}; go test`
90
+ end
91
+ end
@@ -6,6 +6,7 @@ class XMLFileNotFoundException < Exception; end
6
6
  require 'fileutils'
7
7
  require 'logger'
8
8
  require 'tmpdir'
9
+ require 'shellwords'
9
10
  require_relative '../excel_to_code'
10
11
 
11
12
  # FIXME: Correct case for all worksheet references
@@ -121,6 +122,22 @@ class ExcelToX
121
122
  # cells on tha sheet and nothing else.
122
123
  attr_accessor :isolate
123
124
 
125
+ # Optional attribute, Boolean. Default false
126
+ # If set to true, will persevere through some errors where it can rather than aborting
127
+ # immediately. This can be helpful in getting to grips with conversion errors on a
128
+ # really messy sheet, since it allows you to see all the errors at once and which are
129
+ # really fatal.
130
+ attr_accessor :persevere
131
+
132
+ # This is a private method, default is a hash, keys are cell references.
133
+ # The code will dump debuging information about the given cells as they
134
+ # progress through the conversion
135
+ attr_accessor :dump_steps
136
+
137
+ # This is a method to use carefull, if true will not abort on external references, but instead
138
+ # treat them as local references.
139
+ attr_accessor :treat_external_references_as_local
140
+
124
141
  # This is the main method. Once all the above attributes have been set, it should be called to actually do the work.
125
142
  def go!
126
143
  # This sorts out the settings
@@ -226,6 +243,9 @@ class ExcelToX
226
243
  # Make sure the relevant directories exist
227
244
  self.excel_file = File.expand_path(excel_file)
228
245
  self.output_directory = File.expand_path(output_directory)
246
+
247
+ # For debugging
248
+ self.dump_steps ||= {}
229
249
 
230
250
  # Set up our log file
231
251
  unless self.log
@@ -268,8 +288,20 @@ class ExcelToX
268
288
 
269
289
  # FIXME: Replace these with pure ruby versions?
270
290
  def unzip_excel
271
- log.info "Removing any old xml #{`rm -fr '#{xml_directory}'`}" # Force delete
272
- log.info "Unziping excel into xml #{`unzip -q '#{excel_file}' -d '#{xml_directory}'`}" # If don't force delete, make sure that force the zip to overwrite old files
291
+ log.info "Removing old folders"
292
+ execute_system_command 'rm', '-fr', xml_directory
293
+ log.info "Unzipping the spreadsheet"
294
+ execute_system_command 'unzip', '-q', excel_file, '-d', xml_directory
295
+ end
296
+
297
+ def execute_system_command(*args)
298
+ c = args.shelljoin
299
+ output = `#{c}`
300
+ unless $?.exitstatus == 0
301
+ log.error "Command failed: #{c}"
302
+ log.error output
303
+ exit 1
304
+ end
273
305
  end
274
306
 
275
307
  # The excel workbook.xml and allied relationship files knows about
@@ -308,16 +340,24 @@ class ExcelToX
308
340
  # Then we parse them
309
341
  @named_references.each do |name, reference|
310
342
  begin
311
- parsed = CachingFormulaParser.parse(reference)
343
+ parsed = CachingFormulaParser.parse(reference, treat_external_references_as_local)
312
344
  if parsed
313
345
  @named_references[name] = parsed
314
346
  else
315
347
  $stderr.puts "Named reference #{name} #{reference} not parsed"
316
348
  exit
317
349
  end
318
- rescue Exception
319
- $stderr.puts "Named reference #{name} #{reference} not parsed"
320
- raise
350
+ rescue Exception => e
351
+ if e.respond_to?(:'ref=')
352
+ e.ref = ['Named reference', name]
353
+ end
354
+ if persevere
355
+ $stderr.puts e.message
356
+ $stderr.puts "--persevere true, so setting #{name} = #REF!"
357
+ @named_references[name] = [:error, "#REF!"]
358
+ else
359
+ raise
360
+ end
321
361
  end
322
362
  end
323
363
 
@@ -441,6 +481,10 @@ class ExcelToX
441
481
  # Named references_to_keep can be passed a block, in which case this loops
442
482
  # through offering up the named references. If the block returns true then
443
483
  # the named reference is kept
484
+ if named_references_to_keep == :all
485
+ @named_references_to_keep = @named_references.keys.concat(@table_areas.keys)
486
+ end
487
+
444
488
  if named_references_to_keep.is_a?(Proc)
445
489
  new_named_references_to_keep = @named_references.keys.select do |named_reference|
446
490
  named_references_to_keep.call(named_reference)
@@ -495,6 +539,7 @@ class ExcelToX
495
539
  # All are hashes of the format ["SheetName", "A1"] => [:number, "1"]
496
540
  # This one has a series of table references
497
541
  extractor = ExtractDataFromWorksheet.new
542
+ extractor.persevere = persevere
498
543
 
499
544
  # Loop through the worksheets
500
545
  # FIXME: make xml_filename be the IO object?
@@ -857,7 +902,7 @@ class ExcelToX
857
902
  sheet = ref[1]
858
903
  cell = Reference.for(ref[2][1]).unfix.to_sym
859
904
  s = cells_that_can_be_set[sheet]
860
- if s && s.include?(cell)
905
+ if s && ( s == :all || s.include?(cell) )
861
906
  @named_references_that_can_be_set_at_runtime << name
862
907
  cells_that_can_be_set_due_to_named_reference[sheet] << cell.to_sym
863
908
  cells_that_can_be_set_due_to_named_reference[sheet].uniq!
@@ -902,6 +947,11 @@ class ExcelToX
902
947
  end
903
948
 
904
949
  end
950
+
951
+ def debug_dump(ref, ast, location = "")
952
+ return unless dump_steps[ref]
953
+ puts "#{location}: #{ref} = #{ast}"
954
+ end
905
955
 
906
956
  def simplify(cells = @formulae)
907
957
  log.info "Simplifying cells"
@@ -923,6 +973,7 @@ class ExcelToX
923
973
  #require 'pry'; binding.pry
924
974
 
925
975
  cells.each do |ref, ast|
976
+ debug_dump(ref, ast, "simplify 1 - start")
926
977
  begin
927
978
  @sheetless_cell_reference_replacer.worksheet = ref.first
928
979
  @sheetless_cell_reference_replacer.map(ast)
@@ -932,6 +983,17 @@ class ExcelToX
932
983
  @table_reference_replacer.worksheet = ref.first
933
984
  @table_reference_replacer.referring_cell = ref.last
934
985
  @table_reference_replacer.map(ast)
986
+ column_and_row_function_replacement.current_reference = ref.last
987
+ column_and_row_function_replacement.replace(ast)
988
+ rescue Exception => e
989
+ log.fatal "Exception when simplifying #{ref}: #{ast}"
990
+ raise
991
+ end
992
+ debug_dump(ref, ast, "simplify 1 - finish")
993
+ end
994
+ cells.each do |ref, ast|
995
+ debug_dump(ref, ast, "simplify 2 - start")
996
+ begin
935
997
  @replace_ranges_with_array_literals_replacer.map(ast)
936
998
  @replace_arrays_with_single_cells_replacer.ref = ref
937
999
  a = @replace_arrays_with_single_cells_replacer.map(ast)
@@ -941,8 +1003,6 @@ class ExcelToX
941
1003
  @replace_arithmetic_on_ranges_replacer.map(ast)
942
1004
  @replace_string_joins_on_ranges_replacer.map(ast)
943
1005
  @wrap_formulae_that_return_arrays_replacer.map(ast)
944
- column_and_row_function_replacement.current_reference = ref.last
945
- column_and_row_function_replacement.replace(ast)
946
1006
  @replace_references_to_blanks_with_zeros.current_sheet_name = ref.first
947
1007
  @replace_references_to_blanks_with_zeros.map(ast)
948
1008
  @fix_subtotal_of_subtotals.map(ast)
@@ -950,6 +1010,7 @@ class ExcelToX
950
1010
  log.fatal "Exception when simplifying #{ref}: #{ast}"
951
1011
  raise
952
1012
  end
1013
+ debug_dump(ref, ast, "simplify 2 - finish")
953
1014
  end
954
1015
  end
955
1016
 
@@ -1014,6 +1075,7 @@ class ExcelToX
1014
1075
  indirect_replacement = ReplaceIndirectsWithReferencesAst.new
1015
1076
  column_and_row_function_replacement = ReplaceColumnAndRowFunctionsAST.new
1016
1077
  offset_replacement = ReplaceOffsetsWithReferencesAst.new
1078
+ cell_address_replacement = ReplaceCellAddressesWithReferencesAst.new
1017
1079
 
1018
1080
  begin
1019
1081
  number_of_passes += 1
@@ -1024,6 +1086,7 @@ class ExcelToX
1024
1086
  value_replacer.replacements_made_in_the_last_pass = 0
1025
1087
  column_and_row_function_replacement.count_replaced = 0
1026
1088
  offset_replacement.count_replaced = 0
1089
+ cell_address_replacement.count_replaced = 0
1027
1090
  indirect_replacement.count_replaced = 0
1028
1091
  references_that_need_updating = {}
1029
1092
 
@@ -1036,6 +1099,9 @@ class ExcelToX
1036
1099
  if offset_replacement.replace(ast)
1037
1100
  references_that_need_updating[ref] = ast
1038
1101
  end
1102
+ if cell_address_replacement.replace(ast)
1103
+ references_that_need_updating[ref] = ast
1104
+ end
1039
1105
  # FIXME: Shouldn't need to wrap ref.fist in an array
1040
1106
  inline_replacer.current_sheet_name = [ref.first]
1041
1107
  inline_replacer.map(ast)
@@ -1051,7 +1117,6 @@ class ExcelToX
1051
1117
  raise
1052
1118
  end
1053
1119
  end
1054
-
1055
1120
 
1056
1121
  @named_references.each do |ref, ast|
1057
1122
  inline_replacer.current_sheet_name = ref.is_a?(Array) ? [ref.first] : []
@@ -1064,6 +1129,7 @@ class ExcelToX
1064
1129
  replacements_made_in_the_last_pass += value_replacer.replacements_made_in_the_last_pass
1065
1130
  replacements_made_in_the_last_pass += column_and_row_function_replacement.count_replaced
1066
1131
  replacements_made_in_the_last_pass += offset_replacement.count_replaced
1132
+ replacements_made_in_the_last_pass += cell_address_replacement.count_replaced
1067
1133
  replacements_made_in_the_last_pass += indirect_replacement.count_replaced
1068
1134
 
1069
1135
  log.info "Pass #{number_of_passes}: Made #{replacements_made_in_the_last_pass} replacements"
@@ -1352,7 +1418,7 @@ class ExcelToX
1352
1418
  args.flatten!
1353
1419
  File.open(File.join(output_directory,*args),'w')
1354
1420
  end
1355
-
1421
+
1356
1422
  def close(*args)
1357
1423
  args.map do |f|
1358
1424
  next if f.is_a?(StringIO)
data/src/compile.rb CHANGED
@@ -1,2 +1,3 @@
1
1
  require_relative 'compile/ruby'
2
2
  require_relative 'compile/c'
3
+ require_relative 'compile/go'
data/src/compile/c/a.out CHANGED
Binary file
@@ -5,6 +5,7 @@ class CompileToC
5
5
  attr_accessor :settable
6
6
  attr_accessor :gettable
7
7
  attr_accessor :variable_set_counter
8
+ attr_accessor :allow_unknown_functions
8
9
 
9
10
  def self.rewrite(*args)
10
11
  self.new.rewrite(*args)
@@ -16,6 +17,7 @@ class CompileToC
16
17
  @variable_set_counter ||= 0
17
18
 
18
19
  mapper = MapFormulaeToC.new
20
+ mapper.allow_unknown_functions = self.allow_unknown_functions
19
21
  mapper.sheet_names = sheet_names
20
22
  formulae.each do |ref, ast|
21
23
  begin
@@ -11,7 +11,7 @@
11
11
  #endif
12
12
 
13
13
  #ifndef EXCEL_FILENAME
14
- #define EXCEL_FILENAME "NoExcelFilename"
14
+ #define EXCEL_FILENAME "NoExcelFilename"
15
15
  #endif
16
16
 
17
17
  // Need to retain malloc'd values for a while, so can return to functions that use this library
@@ -27,10 +27,10 @@ typedef enum {ExcelEmpty, ExcelNumber, ExcelString, ExcelBoolean, ExcelError, Ex
27
27
 
28
28
  struct excel_value {
29
29
  ExcelType type;
30
-
30
+
31
31
  double number; // Used for numbers and for error types
32
32
  char *string; // Used for strings
33
-
33
+
34
34
  // The following three are used for ranges
35
35
  void *array;
36
36
  int rows;
@@ -59,6 +59,8 @@ static ExcelValue less_than_or_equal(ExcelValue a_v, ExcelValue b_v);
59
59
  static ExcelValue average(int array_size, ExcelValue *array);
60
60
  static ExcelValue averageifs(ExcelValue average_range_v, int number_of_arguments, ExcelValue *arguments);
61
61
  static ExcelValue excel_char(ExcelValue number_v);
62
+ static ExcelValue excel_ceiling_math_2(ExcelValue number_v, ExcelValue multiple_v);
63
+ static ExcelValue excel_ceiling_math(ExcelValue number_v, ExcelValue multiple_v, ExcelValue mode_v);
62
64
  static ExcelValue ensure_is_number(ExcelValue maybe_number_v);
63
65
  static ExcelValue find_2(ExcelValue string_to_look_for_v, ExcelValue string_to_look_in_v);
64
66
  static ExcelValue find(ExcelValue string_to_look_for_v, ExcelValue string_to_look_in_v, ExcelValue position_to_start_at_v);
@@ -84,7 +86,9 @@ static ExcelValue max(int number_of_arguments, ExcelValue *arguments);
84
86
  static ExcelValue min(int number_of_arguments, ExcelValue *arguments);
85
87
  static ExcelValue mmult(ExcelValue a_v, ExcelValue b_v);
86
88
  static ExcelValue mod(ExcelValue a_v, ExcelValue b_v);
89
+ static ExcelValue na();
87
90
  static ExcelValue negative(ExcelValue a_v);
91
+ static ExcelValue excel_not(ExcelValue a_v);
88
92
  static ExcelValue number_or_zero(ExcelValue maybe_number_v);
89
93
  static ExcelValue npv(ExcelValue rate, int number_of_arguments, ExcelValue *arguments);
90
94
  static ExcelValue pmt(ExcelValue rate_v, ExcelValue number_of_periods_v, ExcelValue present_value_v);
@@ -112,6 +116,19 @@ static ExcelValue text(ExcelValue number_v, ExcelValue format_v);
112
116
  static ExcelValue value(ExcelValue string_v);
113
117
  static ExcelValue vlookup_3(ExcelValue lookup_value_v,ExcelValue lookup_table_v, ExcelValue column_number_v);
114
118
  static ExcelValue vlookup(ExcelValue lookup_value_v,ExcelValue lookup_table_v, ExcelValue column_number_v, ExcelValue match_type_v);
119
+ static ExcelValue scurve_4(ExcelValue currentYear, ExcelValue startValue, ExcelValue endValue, ExcelValue duration);
120
+ static ExcelValue scurve(ExcelValue currentYear, ExcelValue startValue, ExcelValue endValue, ExcelValue duration, ExcelValue startYear);
121
+ static ExcelValue halfscurve_4(ExcelValue currentYear, ExcelValue startValue, ExcelValue endValue, ExcelValue duration);
122
+ static ExcelValue halfscurve(ExcelValue currentYear, ExcelValue startValue, ExcelValue endValue, ExcelValue duration, ExcelValue startYear);
123
+ static ExcelValue lcurve_4(ExcelValue currentYear, ExcelValue startValue, ExcelValue endValue, ExcelValue duration);
124
+ static ExcelValue lcurve(ExcelValue currentYear, ExcelValue startValue, ExcelValue endValue, ExcelValue duration, ExcelValue startYear);
125
+ static ExcelValue curve_5(ExcelValue curveType, ExcelValue currentYear, ExcelValue startValue, ExcelValue endValue, ExcelValue duration);
126
+ static ExcelValue curve(ExcelValue curveType, ExcelValue currentYear, ExcelValue startValue, ExcelValue endValue, ExcelValue duration, ExcelValue startYear);
127
+
128
+ static ExcelValue product(int number_of_arguments, ExcelValue *arguments);
129
+ static ExcelValue excel_floor(ExcelValue number_v, ExcelValue multiple_v);
130
+ static ExcelValue rate(ExcelValue a1, ExcelValue a2, ExcelValue a3, ExcelValue a4);
131
+ static ExcelValue excel_sqrt(ExcelValue number_v);
115
132
 
116
133
  // My little heap for keeping pointers to memory that I need to reclaim
117
134
  void **memory_that_needs_to_be_freed;
@@ -119,7 +136,7 @@ int memory_that_needs_to_be_freed_counter = 0;
119
136
  int memory_that_needs_to_be_freed_size = -1;
120
137
 
121
138
  static void free_later(void *pointer) {
122
- if(memory_that_needs_to_be_freed_counter >= memory_that_needs_to_be_freed_size) {
139
+ if(memory_that_needs_to_be_freed_counter >= memory_that_needs_to_be_freed_size) {
123
140
  if(memory_that_needs_to_be_freed_size <= 0) {
124
141
  memory_that_needs_to_be_freed = malloc(MEMORY_TO_BE_FREED_LATER_HEAP_INCREMENT*sizeof(void*));
125
142
  memory_that_needs_to_be_freed_size = MEMORY_TO_BE_FREED_LATER_HEAP_INCREMENT;
@@ -221,7 +238,7 @@ static void inspect_excel_value(ExcelValue v) {
221
238
  if(v.number == 0) {
222
239
  printf("Empty\n");
223
240
  } else {
224
- printf("Empty with unexpected state %f\n",v.number);
241
+ printf("Empty with unexpected state %f\n",v.number);
225
242
  }
226
243
  break;
227
244
  case ExcelRange:
@@ -264,18 +281,18 @@ static double number_from(ExcelValue v) {
264
281
  ExcelValue *array;
265
282
  switch (v.type) {
266
283
  case ExcelNumber:
267
- case ExcelBoolean:
284
+ case ExcelBoolean:
268
285
  return v.number;
269
- case ExcelEmpty:
286
+ case ExcelEmpty:
270
287
  return 0;
271
- case ExcelRange:
288
+ case ExcelRange:
272
289
  array = v.array;
273
290
  return number_from(array[0]);
274
291
  case ExcelString:
275
292
  s = v.string;
276
293
  if (s == NULL || *s == '\0' || isspace(*s)) {
277
294
  return 0;
278
- }
295
+ }
279
296
  n = strtod (s, &p);
280
297
  if(*p == '\0') {
281
298
  return n;
@@ -291,12 +308,12 @@ static double number_from(ExcelValue v) {
291
308
  #define NUMBER(value_name, name) double name; if(value_name.type == ExcelError) { return value_name; }; name = number_from(value_name);
292
309
  #define CHECK_FOR_CONVERSION_ERROR if(conversion_error) { conversion_error = 0; return VALUE; };
293
310
  #define CHECK_FOR_PASSED_ERROR(name) if(name.type == ExcelError) return name;
294
-
311
+
295
312
  static ExcelValue excel_abs(ExcelValue a_v) {
296
- CHECK_FOR_PASSED_ERROR(a_v)
313
+ CHECK_FOR_PASSED_ERROR(a_v)
297
314
  NUMBER(a_v, a)
298
315
  CHECK_FOR_CONVERSION_ERROR
299
-
316
+
300
317
  if(a >= 0.0 ) {
301
318
  return a_v;
302
319
  } else {
@@ -305,7 +322,7 @@ static ExcelValue excel_abs(ExcelValue a_v) {
305
322
  }
306
323
 
307
324
  static ExcelValue excel_char(ExcelValue a_v) {
308
- CHECK_FOR_PASSED_ERROR(a_v)
325
+ CHECK_FOR_PASSED_ERROR(a_v)
309
326
  NUMBER(a_v, a)
310
327
  CHECK_FOR_CONVERSION_ERROR
311
328
  if(a <= 0) { return VALUE; }
@@ -387,18 +404,88 @@ static ExcelValue excel_exp(ExcelValue number_v) {
387
404
  return EXCEL_NUMBER(exp(n));
388
405
  }
389
406
 
407
+ static ExcelValue excel_sqrt(ExcelValue number_v) {
408
+ CHECK_FOR_PASSED_ERROR(number_v)
409
+ NUMBER(number_v, n)
410
+ CHECK_FOR_CONVERSION_ERROR
411
+
412
+ if(n<0) { return NUM; }
413
+
414
+ return EXCEL_NUMBER(sqrt(n));
415
+ }
416
+
417
+ static ExcelValue excel_floor(ExcelValue number_v, ExcelValue multiple_v) {
418
+ CHECK_FOR_PASSED_ERROR(number_v)
419
+ CHECK_FOR_PASSED_ERROR(multiple_v)
420
+ NUMBER(number_v, n)
421
+ NUMBER(multiple_v, m)
422
+ CHECK_FOR_CONVERSION_ERROR
423
+ if(m == 0) { return DIV0; }
424
+ if(m < 0) { return NUM; }
425
+ return EXCEL_NUMBER((n - fmod(n, m)));
426
+ }
427
+
428
+ static ExcelValue excel_ceiling_math_2(ExcelValue number_v, ExcelValue multiple_v) {
429
+ return excel_ceiling_math(number_v, multiple_v, ZERO);
430
+ }
431
+
432
+ static ExcelValue excel_ceiling_math(ExcelValue number_v, ExcelValue multiple_v, ExcelValue mode_v) {
433
+ CHECK_FOR_PASSED_ERROR(number_v)
434
+ CHECK_FOR_PASSED_ERROR(multiple_v)
435
+ CHECK_FOR_PASSED_ERROR(mode_v)
436
+ NUMBER(number_v, n)
437
+ NUMBER(multiple_v, m)
438
+ NUMBER(mode_v, d)
439
+ CHECK_FOR_CONVERSION_ERROR
440
+ if(m == 0) { return ZERO; }
441
+
442
+ if(d == 0 || n > 0 ) {
443
+ double remainder = fmod(n, m);
444
+ if(remainder == 0) {
445
+ return number_v;
446
+ } else {
447
+ return EXCEL_NUMBER(((double) ceil(n/m))*m);
448
+ }
449
+
450
+
451
+ } else { // Need to round negative away from zero
452
+ return negative(excel_ceiling_math(excel_abs(number_v), multiple_v, mode_v));
453
+ }
454
+
455
+ return EXCEL_NUMBER((n - fmod(n, m)));
456
+ }
457
+
458
+ static ExcelValue rate(ExcelValue periods_v, ExcelValue payment_v, ExcelValue presentValue_v, ExcelValue finalValue_v) {
459
+ CHECK_FOR_PASSED_ERROR(periods_v)
460
+ CHECK_FOR_PASSED_ERROR(payment_v)
461
+ CHECK_FOR_PASSED_ERROR(presentValue_v)
462
+ CHECK_FOR_PASSED_ERROR(finalValue_v)
463
+
464
+ NUMBER(periods_v, periods)
465
+ NUMBER(payment_v, payment)
466
+ NUMBER(presentValue_v, presentValue)
467
+ NUMBER(finalValue_v, finalValue)
468
+
469
+ // FIXME: Only implemented the case where payment is zero
470
+ if(payment != 0) {
471
+ return NA;
472
+ }
473
+
474
+ return EXCEL_NUMBER(pow((finalValue/(-presentValue)),(1.0/periods))-1.0);
475
+ }
476
+
390
477
  static ExcelValue excel_and(int array_size, ExcelValue *array) {
391
478
  int i;
392
479
  ExcelValue current_excel_value, array_result;
393
-
480
+
394
481
  for(i=0;i<array_size;i++) {
395
482
  current_excel_value = array[i];
396
483
  switch (current_excel_value.type) {
397
- case ExcelNumber:
398
- case ExcelBoolean:
484
+ case ExcelNumber:
485
+ case ExcelBoolean:
399
486
  if(current_excel_value.number == false) return FALSE;
400
487
  break;
401
- case ExcelRange:
488
+ case ExcelRange:
402
489
  array_result = excel_and( current_excel_value.rows * current_excel_value.columns, current_excel_value.array );
403
490
  if(array_result.type == ExcelError) return array_result;
404
491
  if(array_result.type == ExcelBoolean && array_result.number == false) return FALSE;
@@ -414,20 +501,71 @@ static ExcelValue excel_and(int array_size, ExcelValue *array) {
414
501
  return TRUE;
415
502
  }
416
503
 
504
+ static ExcelValue excel_or(int array_size, ExcelValue *array) {
505
+ int i;
506
+ ExcelValue current_excel_value, array_result;
507
+
508
+ for(i=0;i<array_size;i++) {
509
+ current_excel_value = array[i];
510
+ switch (current_excel_value.type) {
511
+ case ExcelNumber:
512
+ case ExcelBoolean:
513
+ if(current_excel_value.number == true) return TRUE;
514
+ break;
515
+ case ExcelRange:
516
+ array_result = excel_or( current_excel_value.rows * current_excel_value.columns, current_excel_value.array );
517
+ if(array_result.type == ExcelError) return array_result;
518
+ if(array_result.type == ExcelBoolean && array_result.number == true) return TRUE;
519
+ break;
520
+ case ExcelString:
521
+ case ExcelEmpty:
522
+ break;
523
+ case ExcelError:
524
+ return current_excel_value;
525
+ break;
526
+ }
527
+ }
528
+ return FALSE;
529
+ }
530
+
531
+ static ExcelValue excel_not(ExcelValue boolean_v) {
532
+ switch (boolean_v.type) {
533
+ case ExcelNumber:
534
+ if(boolean_v.number == 0) return TRUE;
535
+ return FALSE;
536
+
537
+ case ExcelBoolean:
538
+ if(boolean_v.number == false) return TRUE;
539
+ return FALSE;
540
+
541
+ case ExcelRange:
542
+ return VALUE;
543
+
544
+ case ExcelString:
545
+ return VALUE;
546
+
547
+ case ExcelEmpty:
548
+ return TRUE;
549
+
550
+ case ExcelError:
551
+ return boolean_v;
552
+ }
553
+ }
554
+
417
555
  struct average_result {
418
556
  double sum;
419
557
  double count;
420
558
  int has_error;
421
559
  ExcelValue error;
422
560
  };
423
-
561
+
424
562
  static struct average_result calculate_average(int array_size, ExcelValue *array) {
425
563
  double sum = 0;
426
564
  double count = 0;
427
565
  int i;
428
566
  ExcelValue current_excel_value;
429
567
  struct average_result array_result, r;
430
-
568
+
431
569
  for(i=0;i<array_size;i++) {
432
570
  current_excel_value = array[i];
433
571
  switch (current_excel_value.type) {
@@ -435,13 +573,13 @@ static struct average_result calculate_average(int array_size, ExcelValue *array
435
573
  sum += current_excel_value.number;
436
574
  count++;
437
575
  break;
438
- case ExcelRange:
576
+ case ExcelRange:
439
577
  array_result = calculate_average( current_excel_value.rows * current_excel_value.columns, current_excel_value.array );
440
578
  if(array_result.has_error == true) return array_result;
441
579
  sum += array_result.sum;
442
580
  count += array_result.count;
443
581
  break;
444
- case ExcelBoolean:
582
+ case ExcelBoolean:
445
583
  case ExcelString:
446
584
  case ExcelEmpty:
447
585
  break;
@@ -511,7 +649,7 @@ static ExcelValue forecast(ExcelValue required_x_v, ExcelValue known_y, ExcelVal
511
649
  float my = mean_y.number;
512
650
 
513
651
  float b_numerator, b_denominator, b, a;
514
-
652
+
515
653
  b_denominator = 0;
516
654
  b_numerator = 0;
517
655
 
@@ -537,7 +675,7 @@ static ExcelValue choose(ExcelValue index_v, int array_size, ExcelValue *array)
537
675
  CHECK_FOR_PASSED_ERROR(index_v)
538
676
 
539
677
  int index = (int) number_from(index_v);
540
- CHECK_FOR_CONVERSION_ERROR
678
+ CHECK_FOR_CONVERSION_ERROR
541
679
  int i;
542
680
  for(i=0;i<array_size;i++) {
543
681
  if(array[i].type == ExcelError) return array[i];
@@ -545,23 +683,23 @@ static ExcelValue choose(ExcelValue index_v, int array_size, ExcelValue *array)
545
683
  if(index < 1) return VALUE;
546
684
  if(index > array_size) return VALUE;
547
685
  return array[index-1];
548
- }
686
+ }
549
687
 
550
688
  static ExcelValue count(int array_size, ExcelValue *array) {
551
689
  int i;
552
690
  int n = 0;
553
691
  ExcelValue current_excel_value;
554
-
692
+
555
693
  for(i=0;i<array_size;i++) {
556
694
  current_excel_value = array[i];
557
695
  switch (current_excel_value.type) {
558
696
  case ExcelNumber:
559
697
  n++;
560
698
  break;
561
- case ExcelRange:
699
+ case ExcelRange:
562
700
  n += count( current_excel_value.rows * current_excel_value.columns, current_excel_value.array ).number;
563
701
  break;
564
- case ExcelBoolean:
702
+ case ExcelBoolean:
565
703
  case ExcelString:
566
704
  case ExcelEmpty:
567
705
  case ExcelError:
@@ -575,7 +713,7 @@ static ExcelValue counta(int array_size, ExcelValue *array) {
575
713
  int i;
576
714
  int n = 0;
577
715
  ExcelValue current_excel_value;
578
-
716
+
579
717
  for(i=0;i<array_size;i++) {
580
718
  current_excel_value = array[i];
581
719
  switch(current_excel_value.type) {
@@ -585,7 +723,7 @@ static ExcelValue counta(int array_size, ExcelValue *array) {
585
723
  case ExcelError:
586
724
  n++;
587
725
  break;
588
- case ExcelRange:
726
+ case ExcelRange:
589
727
  n += counta( current_excel_value.rows * current_excel_value.columns, current_excel_value.array ).number;
590
728
  break;
591
729
  case ExcelEmpty:
@@ -610,11 +748,11 @@ static ExcelValue excel_equal(ExcelValue a_v, ExcelValue b_v) {
610
748
  CHECK_FOR_PASSED_ERROR(b_v)
611
749
 
612
750
  if(a_v.type != b_v.type) return FALSE;
613
-
751
+
614
752
  switch (a_v.type) {
615
753
  case ExcelNumber:
616
- case ExcelBoolean:
617
- case ExcelEmpty:
754
+ case ExcelBoolean:
755
+ case ExcelEmpty:
618
756
  if(a_v.number != b_v.number) return FALSE;
619
757
  return TRUE;
620
758
  case ExcelString:
@@ -655,7 +793,7 @@ static ExcelValue excel_isblank(ExcelValue value) {
655
793
 
656
794
  static ExcelValue excel_if(ExcelValue condition, ExcelValue true_case, ExcelValue false_case ) {
657
795
  CHECK_FOR_PASSED_ERROR(condition)
658
-
796
+
659
797
  switch (condition.type) {
660
798
  case ExcelBoolean:
661
799
  if(condition.number == true) return true_case;
@@ -663,7 +801,7 @@ static ExcelValue excel_if(ExcelValue condition, ExcelValue true_case, ExcelValu
663
801
  case ExcelNumber:
664
802
  if(condition.number == false) return false_case;
665
803
  return true_case;
666
- case ExcelEmpty:
804
+ case ExcelEmpty:
667
805
  return false_case;
668
806
  case ExcelString:
669
807
  return VALUE;
@@ -683,15 +821,15 @@ static ExcelValue excel_index(ExcelValue array_v, ExcelValue row_number_v, Excel
683
821
  CHECK_FOR_PASSED_ERROR(array_v)
684
822
  CHECK_FOR_PASSED_ERROR(row_number_v)
685
823
  CHECK_FOR_PASSED_ERROR(column_number_v)
686
-
824
+
687
825
  ExcelValue *array;
688
826
  int rows;
689
827
  int columns;
690
-
828
+
691
829
  NUMBER(row_number_v, row_number)
692
830
  NUMBER(column_number_v, column_number)
693
831
  CHECK_FOR_CONVERSION_ERROR
694
-
832
+
695
833
  if(array_v.type == ExcelRange) {
696
834
  array = array_v.array;
697
835
  rows = array_v.rows;
@@ -702,13 +840,13 @@ static ExcelValue excel_index(ExcelValue array_v, ExcelValue row_number_v, Excel
702
840
  rows = 1;
703
841
  columns = 1;
704
842
  }
705
-
843
+
706
844
  if(row_number > rows) return REF;
707
845
  if(column_number > columns) return REF;
708
846
 
709
847
  if(row_number == 0 && rows == 1) row_number = 1;
710
848
  if(column_number == 0 && columns == 1) column_number = 1;
711
-
849
+
712
850
  if(row_number == 0) { // We need the whole column
713
851
  if(column_number < 1) return REF;
714
852
  ExcelValue *result = (ExcelValue *) new_excel_value_array(rows);
@@ -723,7 +861,7 @@ static ExcelValue excel_index(ExcelValue array_v, ExcelValue row_number_v, Excel
723
861
  result[result_index] = ZERO;
724
862
  } else {
725
863
  result[result_index] = r;
726
- }
864
+ }
727
865
  result_index++;
728
866
  }
729
867
  return EXCEL_RANGE(result,rows,1);
@@ -753,7 +891,7 @@ static ExcelValue excel_index(ExcelValue array_v, ExcelValue row_number_v, Excel
753
891
  if(result.type == ExcelEmpty) return ZERO;
754
892
  return result;
755
893
  }
756
-
894
+
757
895
  return FALSE;
758
896
  };
759
897
 
@@ -798,7 +936,7 @@ static ExcelValue large(ExcelValue range_v, ExcelValue k_v) {
798
936
  }
799
937
 
800
938
  // Otherwise grumble if not a range
801
- if(!range_v.type == ExcelRange) { return VALUE; }
939
+ if(range_v.type != ExcelRange) { return VALUE; }
802
940
 
803
941
  // Check that our k is within bounds
804
942
  if(k < 1) { return NUM; }
@@ -810,7 +948,7 @@ static ExcelValue large(ExcelValue range_v, ExcelValue k_v) {
810
948
  int sorted_size = 0;
811
949
  ExcelValue *array_v = range_v.array;
812
950
  ExcelValue x_v;
813
- int i;
951
+ int i;
814
952
  for(i = 0; i < range_size; i++ ) {
815
953
  x_v = array_v[i];
816
954
  if(x_v.type == ExcelError) { free(sorted); return x_v; };
@@ -834,7 +972,7 @@ static ExcelValue excel_match(ExcelValue lookup_value, ExcelValue lookup_array,
834
972
  CHECK_FOR_PASSED_ERROR(lookup_value)
835
973
  CHECK_FOR_PASSED_ERROR(lookup_array)
836
974
  CHECK_FOR_PASSED_ERROR(match_type)
837
-
975
+
838
976
  // Blanks are treaked as zeros
839
977
  if(lookup_value.type == ExcelEmpty) lookup_value = ZERO;
840
978
 
@@ -856,13 +994,13 @@ static ExcelValue excel_match(ExcelValue lookup_value, ExcelValue lookup_array,
856
994
  ExcelValue tmp_array[1] = {lookup_array};
857
995
  array = tmp_array;
858
996
  }
859
-
997
+
860
998
  int type = (int) number_from(match_type);
861
999
  CHECK_FOR_CONVERSION_ERROR;
862
-
1000
+
863
1001
  int i;
864
1002
  ExcelValue x;
865
-
1003
+
866
1004
  switch(type) {
867
1005
  case 0:
868
1006
  for(i = 0; i < size; i++ ) {
@@ -875,7 +1013,7 @@ static ExcelValue excel_match(ExcelValue lookup_value, ExcelValue lookup_array,
875
1013
  case 1:
876
1014
  for(i = 0; i < size; i++ ) {
877
1015
  x = array[i];
878
- if(x.type == ExcelEmpty) x = ZERO;
1016
+ if(lookup_value.type != x.type ) { continue; }
879
1017
  if(more_than(x,lookup_value).number == true) {
880
1018
  if(i==0) return NA;
881
1019
  return EXCEL_NUMBER(i);
@@ -886,7 +1024,7 @@ static ExcelValue excel_match(ExcelValue lookup_value, ExcelValue lookup_array,
886
1024
  case -1:
887
1025
  for(i = 0; i < size; i++ ) {
888
1026
  x = array[i];
889
- if(x.type == ExcelEmpty) x = ZERO;
1027
+ if(lookup_value.type != x.type ) { continue; }
890
1028
  if(less_than(x,lookup_value).number == true) {
891
1029
  if(i==0) return NA;
892
1030
  return EXCEL_NUMBER(i);
@@ -907,14 +1045,14 @@ static ExcelValue find(ExcelValue find_text_v, ExcelValue within_text_v, ExcelVa
907
1045
  CHECK_FOR_PASSED_ERROR(within_text_v)
908
1046
  CHECK_FOR_PASSED_ERROR(start_number_v)
909
1047
 
910
- char *find_text;
1048
+ char *find_text;
911
1049
  char *within_text;
912
1050
  char *within_text_offset;
913
1051
  char *result;
914
1052
  int start_number = number_from(start_number_v);
915
1053
  CHECK_FOR_CONVERSION_ERROR
916
1054
 
917
- // Deal with blanks
1055
+ // Deal with blanks
918
1056
  if(within_text_v.type == ExcelString) {
919
1057
  within_text = within_text_v.string;
920
1058
  } else if( within_text_v.type == ExcelEmpty) {
@@ -926,11 +1064,11 @@ static ExcelValue find(ExcelValue find_text_v, ExcelValue within_text_v, ExcelVa
926
1064
  } else if( find_text_v.type == ExcelEmpty) {
927
1065
  return start_number_v;
928
1066
  }
929
-
1067
+
930
1068
  // Check length
931
1069
  if(start_number < 1) return VALUE;
932
1070
  if(start_number > strlen(within_text)) return VALUE;
933
-
1071
+
934
1072
  // Offset our within_text pointer
935
1073
  // FIXME: No way this is utf-8 compatible
936
1074
  within_text_offset = within_text + (start_number - 1);
@@ -950,7 +1088,7 @@ static ExcelValue left(ExcelValue string_v, ExcelValue number_of_characters_v) {
950
1088
  CHECK_FOR_PASSED_ERROR(number_of_characters_v)
951
1089
  if(string_v.type == ExcelEmpty) return BLANK;
952
1090
  if(number_of_characters_v.type == ExcelEmpty) return BLANK;
953
-
1091
+
954
1092
  int number_of_characters = (int) number_from(number_of_characters_v);
955
1093
  CHECK_FOR_CONVERSION_ERROR
956
1094
 
@@ -980,7 +1118,7 @@ static ExcelValue left(ExcelValue string_v, ExcelValue number_of_characters_v) {
980
1118
  string = "FALSE";
981
1119
  }
982
1120
  break;
983
- case ExcelEmpty:
1121
+ case ExcelEmpty:
984
1122
  case ExcelError:
985
1123
  case ExcelRange:
986
1124
  return string_v;
@@ -989,7 +1127,7 @@ static ExcelValue left(ExcelValue string_v, ExcelValue number_of_characters_v) {
989
1127
  if(number_of_characters > strlen(string)) {
990
1128
  number_of_characters = strlen(string);
991
1129
  }
992
-
1130
+
993
1131
  char *left_string = malloc(number_of_characters+1); // Freed
994
1132
  if(left_string == 0) {
995
1133
  printf("Out of memoryn in left");
@@ -1034,7 +1172,7 @@ static ExcelValue len(ExcelValue string_v) {
1034
1172
  string = "FALSE";
1035
1173
  }
1036
1174
  break;
1037
- case ExcelEmpty:
1175
+ case ExcelEmpty:
1038
1176
  case ExcelError:
1039
1177
  case ExcelRange:
1040
1178
  return string_v;
@@ -1052,7 +1190,7 @@ static ExcelValue right(ExcelValue string_v, ExcelValue number_of_characters_v)
1052
1190
  CHECK_FOR_PASSED_ERROR(number_of_characters_v)
1053
1191
  if(string_v.type == ExcelEmpty) return BLANK;
1054
1192
  if(number_of_characters_v.type == ExcelEmpty) return BLANK;
1055
-
1193
+
1056
1194
  int number_of_characters = (int) number_from(number_of_characters_v);
1057
1195
  CHECK_FOR_CONVERSION_ERROR
1058
1196
 
@@ -1082,12 +1220,12 @@ static ExcelValue right(ExcelValue string_v, ExcelValue number_of_characters_v)
1082
1220
  string = "FALSE";
1083
1221
  }
1084
1222
  break;
1085
- case ExcelEmpty:
1223
+ case ExcelEmpty:
1086
1224
  case ExcelError:
1087
1225
  case ExcelRange:
1088
1226
  return string_v;
1089
1227
  }
1090
-
1228
+
1091
1229
  char *right_string = malloc(number_of_characters+1); // Freed
1092
1230
  if(right_string == 0) {
1093
1231
  printf("Out of memory in right");
@@ -1149,18 +1287,18 @@ static ExcelValue more_than(ExcelValue a_v, ExcelValue b_v) {
1149
1287
  case ExcelString:
1150
1288
  switch (b_v.type) {
1151
1289
  case ExcelString:
1152
- if(strcasecmp(a_v.string,b_v.string) <= 0 ) {return FALSE;} else {return TRUE;}
1153
- case ExcelNumber:
1290
+ if(strcasecmp(a_v.string,b_v.string) <= 0 ) {return FALSE;} else {return TRUE;}
1291
+ case ExcelNumber:
1154
1292
  return TRUE;
1155
1293
  case ExcelBoolean:
1156
1294
  return FALSE;
1157
1295
  // Following shouldn't happen
1158
- case ExcelEmpty:
1159
- case ExcelError:
1296
+ case ExcelEmpty:
1297
+ case ExcelError:
1160
1298
  case ExcelRange:
1161
1299
  return NA;
1162
1300
  }
1163
- case ExcelBoolean:
1301
+ case ExcelBoolean:
1164
1302
  switch (b_v.type) {
1165
1303
  case ExcelBoolean:
1166
1304
  if(a_v.number == true) {
@@ -1169,11 +1307,11 @@ static ExcelValue more_than(ExcelValue a_v, ExcelValue b_v) {
1169
1307
  return FALSE;
1170
1308
  }
1171
1309
  case ExcelString:
1172
- case ExcelNumber:
1310
+ case ExcelNumber:
1173
1311
  return TRUE;
1174
1312
  // Following shouldn't happen
1175
- case ExcelEmpty:
1176
- case ExcelError:
1313
+ case ExcelEmpty:
1314
+ case ExcelError:
1177
1315
  case ExcelRange:
1178
1316
  return NA;
1179
1317
  }
@@ -1185,17 +1323,17 @@ static ExcelValue more_than(ExcelValue a_v, ExcelValue b_v) {
1185
1323
  case ExcelBoolean:
1186
1324
  return FALSE;
1187
1325
  // Following shouldn't happen
1188
- case ExcelEmpty:
1189
- case ExcelError:
1326
+ case ExcelEmpty:
1327
+ case ExcelError:
1190
1328
  case ExcelRange:
1191
1329
  return NA;
1192
1330
  }
1193
1331
  // Following shouldn't happen
1194
- case ExcelEmpty:
1195
- case ExcelError:
1332
+ case ExcelEmpty:
1333
+ case ExcelError:
1196
1334
  case ExcelRange:
1197
1335
  return NA;
1198
- }
1336
+ }
1199
1337
  // Shouldn't reach here
1200
1338
  return NA;
1201
1339
  }
@@ -1264,7 +1402,7 @@ static ExcelValue less_than(ExcelValue a_v, ExcelValue b_v) {
1264
1402
  }
1265
1403
  case ExcelBoolean:
1266
1404
  switch(b_v.type) {
1267
- case ExcelBoolean:
1405
+ case ExcelBoolean:
1268
1406
  if(a_v.number == true) {
1269
1407
  return FALSE;
1270
1408
  } else { // a_v.number == false
@@ -1395,7 +1533,7 @@ static ExcelValue max(int number_of_arguments, ExcelValue *arguments) {
1395
1533
  int any_number_found = 0;
1396
1534
  int i;
1397
1535
  ExcelValue current_excel_value;
1398
-
1536
+
1399
1537
  for(i=0;i<number_of_arguments;i++) {
1400
1538
  current_excel_value = arguments[i];
1401
1539
  if(current_excel_value.type == ExcelNumber) {
@@ -1403,7 +1541,7 @@ static ExcelValue max(int number_of_arguments, ExcelValue *arguments) {
1403
1541
  any_number_found = 1;
1404
1542
  biggest_number_found = current_excel_value.number;
1405
1543
  }
1406
- if(current_excel_value.number > biggest_number_found) biggest_number_found = current_excel_value.number;
1544
+ if(current_excel_value.number > biggest_number_found) biggest_number_found = current_excel_value.number;
1407
1545
  } else if(current_excel_value.type == ExcelRange) {
1408
1546
  current_excel_value = max( current_excel_value.rows * current_excel_value.columns, current_excel_value.array );
1409
1547
  if(current_excel_value.type == ExcelError) return current_excel_value;
@@ -1412,7 +1550,7 @@ static ExcelValue max(int number_of_arguments, ExcelValue *arguments) {
1412
1550
  any_number_found = 1;
1413
1551
  biggest_number_found = current_excel_value.number;
1414
1552
  }
1415
- if(current_excel_value.number > biggest_number_found) biggest_number_found = current_excel_value.number;
1553
+ if(current_excel_value.number > biggest_number_found) biggest_number_found = current_excel_value.number;
1416
1554
  } else if(current_excel_value.type == ExcelError) {
1417
1555
  return current_excel_value;
1418
1556
  }
@@ -1421,7 +1559,7 @@ static ExcelValue max(int number_of_arguments, ExcelValue *arguments) {
1421
1559
  any_number_found = 1;
1422
1560
  biggest_number_found = 0;
1423
1561
  }
1424
- return EXCEL_NUMBER(biggest_number_found);
1562
+ return EXCEL_NUMBER(biggest_number_found);
1425
1563
  }
1426
1564
 
1427
1565
  static ExcelValue min(int number_of_arguments, ExcelValue *arguments) {
@@ -1429,7 +1567,7 @@ static ExcelValue min(int number_of_arguments, ExcelValue *arguments) {
1429
1567
  int any_number_found = 0;
1430
1568
  int i;
1431
1569
  ExcelValue current_excel_value;
1432
-
1570
+
1433
1571
  for(i=0;i<number_of_arguments;i++) {
1434
1572
  current_excel_value = arguments[i];
1435
1573
  if(current_excel_value.type == ExcelNumber) {
@@ -1437,7 +1575,7 @@ static ExcelValue min(int number_of_arguments, ExcelValue *arguments) {
1437
1575
  any_number_found = 1;
1438
1576
  smallest_number_found = current_excel_value.number;
1439
1577
  }
1440
- if(current_excel_value.number < smallest_number_found) smallest_number_found = current_excel_value.number;
1578
+ if(current_excel_value.number < smallest_number_found) smallest_number_found = current_excel_value.number;
1441
1579
  } else if(current_excel_value.type == ExcelRange) {
1442
1580
  current_excel_value = min( current_excel_value.rows * current_excel_value.columns, current_excel_value.array );
1443
1581
  if(current_excel_value.type == ExcelError) return current_excel_value;
@@ -1446,7 +1584,7 @@ static ExcelValue min(int number_of_arguments, ExcelValue *arguments) {
1446
1584
  any_number_found = 1;
1447
1585
  smallest_number_found = current_excel_value.number;
1448
1586
  }
1449
- if(current_excel_value.number < smallest_number_found) smallest_number_found = current_excel_value.number;
1587
+ if(current_excel_value.number < smallest_number_found) smallest_number_found = current_excel_value.number;
1450
1588
  } else if(current_excel_value.type == ExcelError) {
1451
1589
  return current_excel_value;
1452
1590
  }
@@ -1455,7 +1593,7 @@ static ExcelValue min(int number_of_arguments, ExcelValue *arguments) {
1455
1593
  any_number_found = 1;
1456
1594
  smallest_number_found = 0;
1457
1595
  }
1458
- return EXCEL_NUMBER(smallest_number_found);
1596
+ return EXCEL_NUMBER(smallest_number_found);
1459
1597
  }
1460
1598
 
1461
1599
  static ExcelValue mmult_error(ExcelValue a_v, ExcelValue b_v) {
@@ -1485,13 +1623,13 @@ static ExcelValue mmult(ExcelValue a_v, ExcelValue b_v) {
1485
1623
  int b_columns = b_v.columns;
1486
1624
  ExcelValue *result = (ExcelValue*) new_excel_value_array(a_rows*b_columns);
1487
1625
  int i, j, k;
1488
- double sum;
1626
+ double sum;
1489
1627
  ExcelValue *array_a = a_v.array;
1490
1628
  ExcelValue *array_b = b_v.array;
1491
1629
 
1492
1630
  ExcelValue a;
1493
1631
  ExcelValue b;
1494
-
1632
+
1495
1633
  for(i=0; i<a_rows; i++) {
1496
1634
  for(j=0; j<b_columns; j++) {
1497
1635
  sum = 0;
@@ -1511,7 +1649,7 @@ static ExcelValue mmult(ExcelValue a_v, ExcelValue b_v) {
1511
1649
  static ExcelValue mod(ExcelValue a_v, ExcelValue b_v) {
1512
1650
  CHECK_FOR_PASSED_ERROR(a_v)
1513
1651
  CHECK_FOR_PASSED_ERROR(b_v)
1514
-
1652
+
1515
1653
  NUMBER(a_v, a)
1516
1654
  NUMBER(b_v, b)
1517
1655
  CHECK_FOR_CONVERSION_ERROR
@@ -1519,6 +1657,10 @@ static ExcelValue mod(ExcelValue a_v, ExcelValue b_v) {
1519
1657
  return EXCEL_NUMBER(fmod(a,b));
1520
1658
  }
1521
1659
 
1660
+ static ExcelValue na() {
1661
+ return NA;
1662
+ }
1663
+
1522
1664
  static ExcelValue negative(ExcelValue a_v) {
1523
1665
  CHECK_FOR_PASSED_ERROR(a_v)
1524
1666
  NUMBER(a_v, a)
@@ -1530,22 +1672,22 @@ static ExcelValue pmt(ExcelValue rate_v, ExcelValue number_of_periods_v, ExcelVa
1530
1672
  CHECK_FOR_PASSED_ERROR(rate_v)
1531
1673
  CHECK_FOR_PASSED_ERROR(number_of_periods_v)
1532
1674
  CHECK_FOR_PASSED_ERROR(present_value_v)
1533
-
1675
+
1534
1676
  NUMBER(rate_v,rate)
1535
1677
  NUMBER(number_of_periods_v,number_of_periods)
1536
1678
  NUMBER(present_value_v,present_value)
1537
1679
  CHECK_FOR_CONVERSION_ERROR
1538
-
1680
+
1539
1681
  if(rate == 0) return EXCEL_NUMBER(-(present_value / number_of_periods));
1540
1682
  return EXCEL_NUMBER(-present_value*(rate*(pow((1+rate),number_of_periods)))/((pow((1+rate),number_of_periods))-1));
1541
1683
  }
1542
1684
 
1543
1685
  static ExcelValue pmt_4(ExcelValue rate_v, ExcelValue number_of_periods_v, ExcelValue present_value_v, ExcelValue final_value_v) {
1544
1686
  CHECK_FOR_PASSED_ERROR(final_value_v)
1545
-
1687
+
1546
1688
  NUMBER(final_value_v, final_value)
1547
1689
  CHECK_FOR_CONVERSION_ERROR
1548
-
1690
+
1549
1691
  if(final_value == 0) return pmt(rate_v, number_of_periods_v, present_value_v);
1550
1692
  printf("PMT with non-zero final_value not implemented. halting.");
1551
1693
  exit(-1);
@@ -1553,10 +1695,10 @@ static ExcelValue pmt_4(ExcelValue rate_v, ExcelValue number_of_periods_v, Excel
1553
1695
 
1554
1696
  static ExcelValue pmt_5(ExcelValue rate_v, ExcelValue number_of_periods_v, ExcelValue present_value_v, ExcelValue final_value_v, ExcelValue type_v) {
1555
1697
  CHECK_FOR_PASSED_ERROR(type_v)
1556
-
1698
+
1557
1699
  NUMBER(type_v, type)
1558
1700
  CHECK_FOR_CONVERSION_ERROR
1559
-
1701
+
1560
1702
  if(type == 0) return pmt(rate_v, number_of_periods_v, present_value_v);
1561
1703
  printf("PMT with non-zero type not implemented. halting.");
1562
1704
  exit(-1);
@@ -1605,11 +1747,11 @@ static ExcelValue pv_5(ExcelValue rate_v, ExcelValue nper_v, ExcelValue pmt_v, E
1605
1747
  present_value = present_value * (1+rate);
1606
1748
  } else {
1607
1749
  return VALUE;
1608
- }
1750
+ }
1609
1751
 
1610
1752
  // Add on the final value
1611
1753
  present_value = present_value - (fv/pow(1+rate,nper));
1612
-
1754
+
1613
1755
  return EXCEL_NUMBER(present_value);
1614
1756
  }
1615
1757
 
@@ -1617,7 +1759,7 @@ static ExcelValue pv_5(ExcelValue rate_v, ExcelValue nper_v, ExcelValue pmt_v, E
1617
1759
  static ExcelValue power(ExcelValue a_v, ExcelValue b_v) {
1618
1760
  CHECK_FOR_PASSED_ERROR(a_v)
1619
1761
  CHECK_FOR_PASSED_ERROR(b_v)
1620
-
1762
+
1621
1763
  NUMBER(a_v, a)
1622
1764
  NUMBER(b_v, b)
1623
1765
  CHECK_FOR_CONVERSION_ERROR
@@ -1676,48 +1818,48 @@ static ExcelValue rank_2(ExcelValue number_v, ExcelValue range_v) {
1676
1818
  static ExcelValue excel_round(ExcelValue number_v, ExcelValue decimal_places_v) {
1677
1819
  CHECK_FOR_PASSED_ERROR(number_v)
1678
1820
  CHECK_FOR_PASSED_ERROR(decimal_places_v)
1679
-
1821
+
1680
1822
  NUMBER(number_v, number)
1681
1823
  NUMBER(decimal_places_v, decimal_places)
1682
1824
  CHECK_FOR_CONVERSION_ERROR
1683
-
1825
+
1684
1826
  double multiple = pow(10,decimal_places);
1685
-
1827
+
1686
1828
  return EXCEL_NUMBER( round(number * multiple) / multiple );
1687
1829
  }
1688
1830
 
1689
1831
  static ExcelValue rounddown(ExcelValue number_v, ExcelValue decimal_places_v) {
1690
1832
  CHECK_FOR_PASSED_ERROR(number_v)
1691
1833
  CHECK_FOR_PASSED_ERROR(decimal_places_v)
1692
-
1834
+
1693
1835
  NUMBER(number_v, number)
1694
1836
  NUMBER(decimal_places_v, decimal_places)
1695
1837
  CHECK_FOR_CONVERSION_ERROR
1696
-
1838
+
1697
1839
  double multiple = pow(10,decimal_places);
1698
-
1699
- return EXCEL_NUMBER( trunc(number * multiple) / multiple );
1840
+
1841
+ return EXCEL_NUMBER( trunc(number * multiple) / multiple );
1700
1842
  }
1701
1843
 
1702
1844
  static ExcelValue roundup(ExcelValue number_v, ExcelValue decimal_places_v) {
1703
1845
  CHECK_FOR_PASSED_ERROR(number_v)
1704
1846
  CHECK_FOR_PASSED_ERROR(decimal_places_v)
1705
-
1847
+
1706
1848
  NUMBER(number_v, number)
1707
1849
  NUMBER(decimal_places_v, decimal_places)
1708
1850
  CHECK_FOR_CONVERSION_ERROR
1709
-
1851
+
1710
1852
  double multiple = pow(10,decimal_places);
1711
1853
  if(number < 0) return EXCEL_NUMBER( floor(number * multiple) / multiple );
1712
- return EXCEL_NUMBER( ceil(number * multiple) / multiple );
1854
+ return EXCEL_NUMBER( ceil(number * multiple) / multiple );
1713
1855
  }
1714
1856
 
1715
1857
  static ExcelValue excel_int(ExcelValue number_v) {
1716
1858
  CHECK_FOR_PASSED_ERROR(number_v)
1717
-
1859
+
1718
1860
  NUMBER(number_v, number)
1719
1861
  CHECK_FOR_CONVERSION_ERROR
1720
-
1862
+
1721
1863
  return EXCEL_NUMBER(floor(number));
1722
1864
  }
1723
1865
 
@@ -1747,7 +1889,7 @@ static ExcelValue string_join(int number_of_arguments, ExcelValue *arguments) {
1747
1889
  printf("Out of memory in string join");
1748
1890
  exit(-1);
1749
1891
  }
1750
- must_free_current_string = 1;
1892
+ must_free_current_string = 1;
1751
1893
  snprintf(current_string,20,"%g",current_v.number);
1752
1894
  break;
1753
1895
  case ExcelBoolean:
@@ -1796,7 +1938,7 @@ static ExcelValue subtotal(ExcelValue subtotal_type_v, int number_of_arguments,
1796
1938
  CHECK_FOR_PASSED_ERROR(subtotal_type_v)
1797
1939
  NUMBER(subtotal_type_v,subtotal_type)
1798
1940
  CHECK_FOR_CONVERSION_ERROR
1799
-
1941
+
1800
1942
  switch((int) subtotal_type) {
1801
1943
  case 1:
1802
1944
  case 101:
@@ -1829,22 +1971,22 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
1829
1971
  // Set up the sum range
1830
1972
  ExcelValue *original_range;
1831
1973
  int original_range_rows, original_range_columns;
1832
-
1974
+
1833
1975
  if(original_range_v.type == ExcelRange) {
1834
1976
  original_range = original_range_v.array;
1835
1977
  original_range_rows = original_range_v.rows;
1836
1978
  original_range_columns = original_range_v.columns;
1837
1979
  } else {
1838
1980
  original_range = (ExcelValue*) new_excel_value_array(1);
1839
- original_range[0] = original_range_v;
1981
+ original_range[0] = original_range_v;
1840
1982
  original_range_rows = 1;
1841
1983
  original_range_columns = 1;
1842
1984
  }
1843
1985
 
1844
1986
  // This is the filtered range
1845
1987
  ExcelValue *filtered_range = new_excel_value_array(original_range_rows*original_range_columns);
1846
- int number_of_filtered_values = 0;
1847
-
1988
+ int number_of_filtered_values = 0;
1989
+
1848
1990
  // Then go through and set up the check ranges
1849
1991
  if(number_of_arguments % 2 != 0) return VALUE;
1850
1992
  int number_of_criteria = number_of_arguments / 2;
@@ -1865,7 +2007,7 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
1865
2007
  criteria_range[i] = EXCEL_RANGE(tmp_array2,1,1);
1866
2008
  }
1867
2009
  }
1868
-
2010
+
1869
2011
  // Now go through and set up the criteria
1870
2012
  ExcelComparison *criteria = malloc(sizeof(ExcelComparison)*number_of_criteria); // freed at end of function
1871
2013
  if(criteria == 0) {
@@ -1877,7 +2019,7 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
1877
2019
 
1878
2020
  for(i = 0; i < number_of_criteria; i++) {
1879
2021
  current_value = arguments[(i*2)+1];
1880
-
2022
+
1881
2023
  if(current_value.type == ExcelString) {
1882
2024
  s = current_value.string;
1883
2025
  if(s[0] == '<') {
@@ -1916,14 +2058,14 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
1916
2058
  criteria[i].comparator = EXCEL_STRING(new_comparator);
1917
2059
  } else {
1918
2060
  criteria[i].type = Equal;
1919
- criteria[i].comparator = current_value;
2061
+ criteria[i].comparator = current_value;
1920
2062
  }
1921
2063
  } else {
1922
2064
  criteria[i].type = Equal;
1923
2065
  criteria[i].comparator = current_value;
1924
2066
  }
1925
2067
  }
1926
-
2068
+
1927
2069
  int size = original_range_columns * original_range_rows;
1928
2070
  int j;
1929
2071
  int passed = 0;
@@ -1943,7 +2085,7 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
1943
2085
  if(comparator.type == ExcelEmpty) {
1944
2086
  comparator = ZERO;
1945
2087
  }
1946
-
2088
+
1947
2089
  switch(value_to_be_checked.type) {
1948
2090
  case ExcelError: // Errors match only errors
1949
2091
  if(comparison.type != Equal) passed = 0;
@@ -1984,16 +2126,16 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
1984
2126
  break;
1985
2127
  case LessThan:
1986
2128
  if(value_to_be_checked.number >= number) passed = 0;
1987
- break;
2129
+ break;
1988
2130
  case LessThanOrEqual:
1989
2131
  if(value_to_be_checked.number > number) passed = 0;
1990
- break;
2132
+ break;
1991
2133
  case NotEqual:
1992
2134
  if(value_to_be_checked.number == number) passed = 0;
1993
- break;
2135
+ break;
1994
2136
  case MoreThanOrEqual:
1995
2137
  if(value_to_be_checked.number < number) passed = 0;
1996
- break;
2138
+ break;
1997
2139
  case MoreThan:
1998
2140
  if(value_to_be_checked.number <= number) passed = 0;
1999
2141
  break;
@@ -2034,16 +2176,16 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
2034
2176
  break;
2035
2177
  case LessThan:
2036
2178
  if(less_than(value_to_be_checked,comparator).number == 0) passed = 0;
2037
- break;
2179
+ break;
2038
2180
  case LessThanOrEqual:
2039
2181
  if(less_than_or_equal(value_to_be_checked,comparator).number == 0) passed = 0;
2040
- break;
2182
+ break;
2041
2183
  case NotEqual:
2042
2184
  if(not_equal(value_to_be_checked,comparator).number == 0) passed = 0;
2043
- break;
2185
+ break;
2044
2186
  case MoreThanOrEqual:
2045
2187
  if(more_than_or_equal(value_to_be_checked,comparator).number == 0) passed = 0;
2046
- break;
2188
+ break;
2047
2189
  case MoreThan:
2048
2190
  if(more_than(value_to_be_checked,comparator).number == 0) passed = 0;
2049
2191
  break;
@@ -2055,7 +2197,7 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
2055
2197
  break;
2056
2198
  case ExcelRange:
2057
2199
  free(criteria);
2058
- return VALUE;
2200
+ return VALUE;
2059
2201
  }
2060
2202
  if(passed == 0) break;
2061
2203
  }
@@ -2080,6 +2222,245 @@ static ExcelValue sumifs(ExcelValue sum_range_v, int number_of_arguments, ExcelV
2080
2222
  return sum(1,&filtered_range);
2081
2223
  }
2082
2224
 
2225
+ static ExcelValue countifs(int number_of_arguments, ExcelValue *arguments) {
2226
+ if(number_of_arguments < 2) { return NA;}
2227
+ // Set up the sum range
2228
+ ExcelValue range = arguments[0];
2229
+ int rows, columns;
2230
+
2231
+ if(range.type == ExcelRange) {
2232
+ rows = range.rows;
2233
+ columns = range.columns;
2234
+ } else {
2235
+ rows = 1;
2236
+ columns = 1;
2237
+ }
2238
+
2239
+ int count = 0;
2240
+
2241
+ // Then go through and set up the check ranges
2242
+ if(number_of_arguments % 2 != 0) return VALUE;
2243
+ int number_of_criteria = number_of_arguments / 2;
2244
+ ExcelValue *criteria_range = (ExcelValue*) new_excel_value_array(number_of_criteria);
2245
+ ExcelValue current_value;
2246
+ int i;
2247
+ for(i = 0; i < number_of_criteria; i++) {
2248
+ current_value = arguments[i*2];
2249
+ if(current_value.type == ExcelRange) {
2250
+ criteria_range[i] = current_value;
2251
+ if(current_value.rows != rows) return VALUE;
2252
+ if(current_value.columns != columns) return VALUE;
2253
+ } else {
2254
+ if(rows != 1) return VALUE;
2255
+ if(columns != 1) return VALUE;
2256
+ ExcelValue *tmp_array2 = (ExcelValue*) new_excel_value_array(1);
2257
+ tmp_array2[0] = current_value;
2258
+ criteria_range[i] = EXCEL_RANGE(tmp_array2,1,1);
2259
+ }
2260
+ }
2261
+
2262
+ // Now go through and set up the criteria
2263
+ ExcelComparison *criteria = malloc(sizeof(ExcelComparison)*number_of_criteria); // freed at end of function
2264
+ if(criteria == 0) {
2265
+ printf("Out of memory in filter_range\n");
2266
+ exit(-1);
2267
+ }
2268
+ char *s;
2269
+ char *new_comparator;
2270
+
2271
+ for(i = 0; i < number_of_criteria; i++) {
2272
+ current_value = arguments[(i*2)+1];
2273
+
2274
+ if(current_value.type == ExcelString) {
2275
+ s = current_value.string;
2276
+ if(s[0] == '<') {
2277
+ if( s[1] == '>') {
2278
+ new_comparator = strndup(s+2,strlen(s)-2);
2279
+ free_later(new_comparator);
2280
+ criteria[i].type = NotEqual;
2281
+ criteria[i].comparator = EXCEL_STRING(new_comparator);
2282
+ } else if(s[1] == '=') {
2283
+ new_comparator = strndup(s+2,strlen(s)-2);
2284
+ free_later(new_comparator);
2285
+ criteria[i].type = LessThanOrEqual;
2286
+ criteria[i].comparator = EXCEL_STRING(new_comparator);
2287
+ } else {
2288
+ new_comparator = strndup(s+1,strlen(s)-1);
2289
+ free_later(new_comparator);
2290
+ criteria[i].type = LessThan;
2291
+ criteria[i].comparator = EXCEL_STRING(new_comparator);
2292
+ }
2293
+ } else if(s[0] == '>') {
2294
+ if(s[1] == '=') {
2295
+ new_comparator = strndup(s+2,strlen(s)-2);
2296
+ free_later(new_comparator);
2297
+ criteria[i].type = MoreThanOrEqual;
2298
+ criteria[i].comparator = EXCEL_STRING(new_comparator);
2299
+ } else {
2300
+ new_comparator = strndup(s+1,strlen(s)-1);
2301
+ free_later(new_comparator);
2302
+ criteria[i].type = MoreThan;
2303
+ criteria[i].comparator = EXCEL_STRING(new_comparator);
2304
+ }
2305
+ } else if(s[0] == '=') {
2306
+ new_comparator = strndup(s+1,strlen(s)-1);
2307
+ free_later(new_comparator);
2308
+ criteria[i].type = Equal;
2309
+ criteria[i].comparator = EXCEL_STRING(new_comparator);
2310
+ } else {
2311
+ criteria[i].type = Equal;
2312
+ criteria[i].comparator = current_value;
2313
+ }
2314
+ } else {
2315
+ criteria[i].type = Equal;
2316
+ criteria[i].comparator = current_value;
2317
+ }
2318
+ }
2319
+
2320
+ int size = columns * rows;
2321
+ int j;
2322
+ int passed = 0;
2323
+ ExcelValue value_to_be_checked;
2324
+ ExcelComparison comparison;
2325
+ ExcelValue comparator;
2326
+ double number;
2327
+ // For each cell in the sum range
2328
+ for(j=0; j < size; j++ ) {
2329
+ passed = 1;
2330
+ for(i=0; i < number_of_criteria; i++) {
2331
+ value_to_be_checked = ((ExcelValue *) ((ExcelValue) criteria_range[i]).array)[j];
2332
+ comparison = criteria[i];
2333
+ comparator = comparison.comparator;
2334
+
2335
+ // For the purposes of comparison, treates a blank criteria as matching zeros.
2336
+ if(comparator.type == ExcelEmpty) {
2337
+ comparator = ZERO;
2338
+ }
2339
+
2340
+ switch(value_to_be_checked.type) {
2341
+ case ExcelError: // Errors match only errors
2342
+ if(comparison.type != Equal) passed = 0;
2343
+ if(comparator.type != ExcelError) passed = 0;
2344
+ if(value_to_be_checked.number != comparator.number) passed = 0;
2345
+ break;
2346
+ case ExcelBoolean: // Booleans match only booleans (FIXME: I think?)
2347
+ if(comparison.type != Equal) passed = 0;
2348
+ if(comparator.type != ExcelBoolean ) passed = 0;
2349
+ if(value_to_be_checked.number != comparator.number) passed = 0;
2350
+ break;
2351
+ case ExcelEmpty:
2352
+ // if(comparator.type == ExcelEmpty) break; // FIXME: Huh? In excel blank doesn't match blank?!
2353
+ if(comparator.type != ExcelString) {
2354
+ passed = 0;
2355
+ break;
2356
+ } else {
2357
+ if(strlen(comparator.string) != 0) passed = 0; // Empty strings match blanks.
2358
+ break;
2359
+ }
2360
+ case ExcelNumber:
2361
+ if(comparator.type == ExcelNumber) {
2362
+ number = comparator.number;
2363
+ } else if(comparator.type == ExcelString) {
2364
+ number = number_from(comparator);
2365
+ if(conversion_error == 1) {
2366
+ conversion_error = 0;
2367
+ passed = 0;
2368
+ break;
2369
+ }
2370
+ } else {
2371
+ passed = 0;
2372
+ break;
2373
+ }
2374
+ switch(comparison.type) {
2375
+ case Equal:
2376
+ if(value_to_be_checked.number != number) passed = 0;
2377
+ break;
2378
+ case LessThan:
2379
+ if(value_to_be_checked.number >= number) passed = 0;
2380
+ break;
2381
+ case LessThanOrEqual:
2382
+ if(value_to_be_checked.number > number) passed = 0;
2383
+ break;
2384
+ case NotEqual:
2385
+ if(value_to_be_checked.number == number) passed = 0;
2386
+ break;
2387
+ case MoreThanOrEqual:
2388
+ if(value_to_be_checked.number < number) passed = 0;
2389
+ break;
2390
+ case MoreThan:
2391
+ if(value_to_be_checked.number <= number) passed = 0;
2392
+ break;
2393
+ }
2394
+ break;
2395
+ case ExcelString:
2396
+ // First case, the comparator is a number, simplification is that it can only be equal
2397
+ if(comparator.type == ExcelNumber) {
2398
+ if(comparison.type != Equal) {
2399
+ printf("This shouldn't be possible?");
2400
+ passed = 0;
2401
+ break;
2402
+ }
2403
+
2404
+ // Special case, empty strings don't match zeros here
2405
+ if(strlen(value_to_be_checked.string) == 0) {
2406
+ passed = 0;
2407
+ break;
2408
+ }
2409
+
2410
+ number = number_from(value_to_be_checked);
2411
+ if(conversion_error == 1) {
2412
+ conversion_error = 0;
2413
+ passed = 0;
2414
+ break;
2415
+ }
2416
+ if(number != comparator.number) {
2417
+ passed = 0;
2418
+ break;
2419
+ } else {
2420
+ break;
2421
+ }
2422
+ // Second case, the comparator is also a string, so need to be able to do full range of tests
2423
+ } else if(comparator.type == ExcelString) {
2424
+ switch(comparison.type) {
2425
+ case Equal:
2426
+ if(excel_equal(value_to_be_checked,comparator).number == 0) passed = 0;
2427
+ break;
2428
+ case LessThan:
2429
+ if(less_than(value_to_be_checked,comparator).number == 0) passed = 0;
2430
+ break;
2431
+ case LessThanOrEqual:
2432
+ if(less_than_or_equal(value_to_be_checked,comparator).number == 0) passed = 0;
2433
+ break;
2434
+ case NotEqual:
2435
+ if(not_equal(value_to_be_checked,comparator).number == 0) passed = 0;
2436
+ break;
2437
+ case MoreThanOrEqual:
2438
+ if(more_than_or_equal(value_to_be_checked,comparator).number == 0) passed = 0;
2439
+ break;
2440
+ case MoreThan:
2441
+ if(more_than(value_to_be_checked,comparator).number == 0) passed = 0;
2442
+ break;
2443
+ }
2444
+ } else {
2445
+ passed = 0;
2446
+ break;
2447
+ }
2448
+ break;
2449
+ case ExcelRange:
2450
+ free(criteria);
2451
+ return VALUE;
2452
+ }
2453
+ if(passed == 0) break;
2454
+ }
2455
+ if(passed == 1) {
2456
+ count += 1;
2457
+ }
2458
+ }
2459
+ // Tidy up
2460
+ free(criteria);
2461
+ return EXCEL_NUMBER(count);
2462
+ }
2463
+
2083
2464
  static ExcelValue averageifs(ExcelValue average_range_v, int number_of_arguments, ExcelValue *arguments) {
2084
2465
  ExcelValue filtered_range = filter_range(average_range_v, number_of_arguments, arguments);
2085
2466
  return average(1,&filtered_range);
@@ -2097,7 +2478,7 @@ static ExcelValue sumif_2(ExcelValue check_range_v, ExcelValue criteria_v) {
2097
2478
 
2098
2479
  static ExcelValue sumproduct(int number_of_arguments, ExcelValue *arguments) {
2099
2480
  if(number_of_arguments <1) return VALUE;
2100
-
2481
+
2101
2482
  int a;
2102
2483
  int i;
2103
2484
  int j;
@@ -2111,7 +2492,7 @@ static ExcelValue sumproduct(int number_of_arguments, ExcelValue *arguments) {
2111
2492
  }
2112
2493
  double product = 1;
2113
2494
  double sum = 0;
2114
-
2495
+
2115
2496
  // Find out dimensions of first argument
2116
2497
  if(arguments[0].type == ExcelRange) {
2117
2498
  rows = arguments[0].rows;
@@ -2143,7 +2524,7 @@ static ExcelValue sumproduct(int number_of_arguments, ExcelValue *arguments) {
2143
2524
  break;
2144
2525
  }
2145
2526
  }
2146
-
2527
+
2147
2528
  for(i=0;i<rows;i++) {
2148
2529
  for(j=0;j<columns;j++) {
2149
2530
  product = 1;
@@ -2162,6 +2543,71 @@ static ExcelValue sumproduct(int number_of_arguments, ExcelValue *arguments) {
2162
2543
  return EXCEL_NUMBER(sum);
2163
2544
  }
2164
2545
 
2546
+ static ExcelValue product(int number_of_arguments, ExcelValue *arguments) {
2547
+ if(number_of_arguments <1) return VALUE;
2548
+
2549
+ int a,b;
2550
+ ExcelValue sub_total;
2551
+ ExcelValue current_value;
2552
+ int sub_total_array_size;
2553
+ ExcelValue *sub_total_array;
2554
+ ExcelValue sub_total_value;
2555
+ double total = 0;
2556
+
2557
+ // Extract arrays from each of the given ranges, checking for errors and bounds as we go
2558
+ for(a=0;a<number_of_arguments;a++) {
2559
+ current_value = arguments[a];
2560
+ switch(current_value.type) {
2561
+ case ExcelRange:
2562
+ sub_total_array_size = current_value.rows * current_value.columns;
2563
+ sub_total_array = current_value.array;
2564
+ // We don't use recursion, because we need to check if
2565
+ // the result is 0 becaues a zero, or zero because all blank.
2566
+ for(b=0;b<sub_total_array_size;b++) {
2567
+ sub_total_value = sub_total_array[b];
2568
+ switch(sub_total_value.type) {
2569
+ case ExcelError:
2570
+ return sub_total_value;
2571
+ break;
2572
+
2573
+ case ExcelNumber:
2574
+ // We do this rather than starting with total = 1
2575
+ // so that the product of all blanks is zero
2576
+ if(total == 0) {
2577
+ total = sub_total_value.number;
2578
+ } else {
2579
+ total *= sub_total_value.number;
2580
+ }
2581
+ break;
2582
+
2583
+ default:
2584
+ // Skip
2585
+ break;
2586
+ }
2587
+ }
2588
+ break;
2589
+
2590
+ case ExcelError:
2591
+ return current_value;
2592
+ break;
2593
+
2594
+ case ExcelNumber:
2595
+ if(total == 0) {
2596
+ total = current_value.number;
2597
+ } else {
2598
+ total *= current_value.number;
2599
+ }
2600
+ break;
2601
+
2602
+ default:
2603
+ // Skip
2604
+ break;
2605
+ }
2606
+ }
2607
+
2608
+ return EXCEL_NUMBER(total);
2609
+ }
2610
+
2165
2611
  // FIXME: This could do with being done properly, rather than
2166
2612
  // on a case by case basis.
2167
2613
  static ExcelValue text(ExcelValue number_v, ExcelValue format_v) {
@@ -2189,7 +2635,7 @@ static ExcelValue text(ExcelValue number_v, ExcelValue format_v) {
2189
2635
  s = number_v.string;
2190
2636
  if (s == NULL || *s == '\0' || isspace(*s)) {
2191
2637
  number_v = ZERO;
2192
- }
2638
+ }
2193
2639
  n = strtod (s, &p);
2194
2640
  if(*p == '\0') {
2195
2641
  number_v = EXCEL_NUMBER(n);
@@ -2204,7 +2650,7 @@ static ExcelValue text(ExcelValue number_v, ExcelValue format_v) {
2204
2650
  return format_v;
2205
2651
  }
2206
2652
 
2207
- // FIXME: Too little?
2653
+ // FIXME: Too little?
2208
2654
  s = malloc(100);
2209
2655
  setlocale(LC_ALL,"");
2210
2656
 
@@ -2259,17 +2705,17 @@ static ExcelValue vlookup(ExcelValue lookup_value_v,ExcelValue lookup_table_v, E
2259
2705
  match_type_v.type = ExcelBoolean;
2260
2706
  }
2261
2707
  if(match_type_v.type != ExcelBoolean) return NA;
2262
-
2708
+
2263
2709
  int i;
2264
2710
  int last_good_match = 0;
2265
2711
  int rows = lookup_table_v.rows;
2266
2712
  int columns = lookup_table_v.columns;
2267
2713
  ExcelValue *array = lookup_table_v.array;
2268
2714
  ExcelValue possible_match_v;
2269
-
2715
+
2270
2716
  if(column_number_v.number > columns) return REF;
2271
2717
  if(column_number_v.number < 1) return VALUE;
2272
-
2718
+
2273
2719
  if(match_type_v.number == false) { // Exact match required
2274
2720
  for(i=0; i< rows; i++) {
2275
2721
  possible_match_v = array[i*columns];
@@ -2289,7 +2735,7 @@ static ExcelValue vlookup(ExcelValue lookup_value_v,ExcelValue lookup_table_v, E
2289
2735
  last_good_match = i;
2290
2736
  }
2291
2737
  }
2292
- return array[(last_good_match*columns)+(((int) column_number_v.number) - 1)];
2738
+ return array[(last_good_match*columns)+(((int) column_number_v.number) - 1)];
2293
2739
  }
2294
2740
  return NA;
2295
2741
  }
@@ -2311,17 +2757,17 @@ static ExcelValue hlookup(ExcelValue lookup_value_v,ExcelValue lookup_table_v, E
2311
2757
  match_type_v.type = ExcelBoolean;
2312
2758
  }
2313
2759
  if(match_type_v.type != ExcelBoolean) return NA;
2314
-
2760
+
2315
2761
  int i;
2316
2762
  int last_good_match = 0;
2317
2763
  int rows = lookup_table_v.rows;
2318
2764
  int columns = lookup_table_v.columns;
2319
2765
  ExcelValue *array = lookup_table_v.array;
2320
2766
  ExcelValue possible_match_v;
2321
-
2767
+
2322
2768
  if(row_number_v.number > rows) return REF;
2323
2769
  if(row_number_v.number < 1) return VALUE;
2324
-
2770
+
2325
2771
  if(match_type_v.number == false) { // Exact match required
2326
2772
  for(i=0; i< columns; i++) {
2327
2773
  possible_match_v = array[i];
@@ -2354,14 +2800,116 @@ static ExcelValue value(ExcelValue string_v) {
2354
2800
  return EXCEL_NUMBER(a);
2355
2801
  }
2356
2802
 
2803
+ static ExcelValue scurve_4(ExcelValue currentYear, ExcelValue startValue, ExcelValue endValue, ExcelValue duration) {
2804
+ ExcelValue startYear = EXCEL_NUMBER(2018);
2805
+ return scurve(currentYear, startValue, endValue, duration, startYear);
2806
+ }
2807
+
2808
+ static ExcelValue halfscurve_4(ExcelValue currentYear, ExcelValue startValue, ExcelValue endValue, ExcelValue duration) {
2809
+ ExcelValue startYear = EXCEL_NUMBER(2018);
2810
+ return halfscurve(currentYear, startValue, endValue, duration, startYear);
2811
+ }
2812
+
2813
+ static ExcelValue lcurve_4(ExcelValue currentYear, ExcelValue startValue, ExcelValue endValue, ExcelValue duration) {
2814
+ ExcelValue startYear = EXCEL_NUMBER(2018);
2815
+ return lcurve(currentYear, startValue, endValue, duration, startYear);
2816
+ }
2817
+
2818
+ static ExcelValue curve_5(ExcelValue curveType, ExcelValue currentYear, ExcelValue startValue, ExcelValue endValue, ExcelValue duration) {
2819
+ ExcelValue startYear = EXCEL_NUMBER(2018);
2820
+ return curve(curveType, currentYear, startValue, endValue, duration, startYear);
2821
+ }
2822
+
2823
+ static ExcelValue scurve(ExcelValue currentYear_v, ExcelValue startValue_v, ExcelValue endValue_v, ExcelValue duration_v, ExcelValue startYear_v) {
2824
+
2825
+ NUMBER(currentYear_v, currentYear)
2826
+ NUMBER(startValue_v, startValue)
2827
+ NUMBER(endValue_v, endValue)
2828
+ NUMBER(duration_v, duration)
2829
+ NUMBER(startYear_v, startYear)
2830
+ CHECK_FOR_CONVERSION_ERROR
2831
+
2832
+ if(currentYear < startYear) {
2833
+ return startValue_v;
2834
+ }
2835
+ double x = (currentYear - startYear) / duration;
2836
+ double x0 = 0.0;
2837
+ double a = endValue - startValue;
2838
+ double sc = 0.999;
2839
+ double eps = 1.0 - sc;
2840
+ double mu = 0.5;
2841
+ double beta = (mu - 1.0) / log(1.0 / sc - 1);
2842
+ double scurve = a * (pow((exp(-(x - mu) / beta) + 1),-1) - pow((exp(-(x0 - mu) / beta) + 1),-1)) + startValue;
2843
+ return EXCEL_NUMBER(scurve);
2844
+ }
2845
+
2846
+ static ExcelValue halfscurve(ExcelValue currentYear_v, ExcelValue startValue_v, ExcelValue endValue_v, ExcelValue duration_v, ExcelValue startYear_v) {
2847
+
2848
+ NUMBER(currentYear_v, currentYear)
2849
+ NUMBER(startValue_v, startValue)
2850
+ NUMBER(endValue_v, endValue)
2851
+ NUMBER(duration_v, duration)
2852
+ NUMBER(startYear_v, startYear)
2853
+ CHECK_FOR_CONVERSION_ERROR
2854
+
2855
+ if(currentYear < startYear) {
2856
+ return startValue_v;
2857
+ }
2858
+
2859
+ ExcelValue newCurrentYear = EXCEL_NUMBER(currentYear + duration);
2860
+ ExcelValue newDuration = EXCEL_NUMBER(duration *2);
2861
+ ExcelValue result_v = scurve(newCurrentYear, startValue_v, endValue_v, newDuration, startYear_v);
2862
+
2863
+ NUMBER(result_v, result)
2864
+ CHECK_FOR_CONVERSION_ERROR
2865
+
2866
+ return EXCEL_NUMBER(result -((endValue - startValue)/2.0));
2867
+ }
2868
+
2869
+ static ExcelValue lcurve(ExcelValue currentYear_v, ExcelValue startValue_v, ExcelValue endValue_v, ExcelValue duration_v, ExcelValue startYear_v) {
2870
+
2871
+ NUMBER(currentYear_v, currentYear)
2872
+ NUMBER(startValue_v, startValue)
2873
+ NUMBER(endValue_v, endValue)
2874
+ NUMBER(duration_v, duration)
2875
+ NUMBER(startYear_v, startYear)
2876
+ CHECK_FOR_CONVERSION_ERROR
2877
+
2878
+ if(currentYear > (startYear + duration)) {
2879
+ return endValue_v;
2880
+ }
2881
+
2882
+ if(currentYear < startYear) {
2883
+ return startValue_v;
2884
+ }
2885
+
2886
+ double result = startValue + (((endValue - startValue) / duration) * (currentYear - startYear));
2887
+ return EXCEL_NUMBER(result);
2888
+ }
2889
+
2890
+ static ExcelValue curve(ExcelValue type_v, ExcelValue currentYear_v, ExcelValue startValue_v, ExcelValue endValue_v, ExcelValue duration_v, ExcelValue startYear_v) {
2891
+
2892
+ if(type_v.type == ExcelString && strcasecmp(type_v.string, "s") == 0 ) {
2893
+ return scurve(currentYear_v, startValue_v, endValue_v, duration_v, startYear_v);
2894
+ }
2895
+
2896
+ if(type_v.type == ExcelString && strcasecmp(type_v.string, "hs") == 0 ) {
2897
+ return halfscurve(currentYear_v, startValue_v, endValue_v, duration_v, startYear_v);
2898
+ }
2899
+
2900
+ return lcurve(currentYear_v, startValue_v, endValue_v, duration_v, startYear_v);
2901
+ }
2902
+
2903
+
2904
+
2357
2905
  // Allows numbers to be 0.1% different
2358
2906
  static ExcelValue roughly_equal(ExcelValue a_v, ExcelValue b_v) {
2359
2907
 
2360
2908
  if(a_v.type == ExcelEmpty && b_v.type == ExcelNumber && b_v.number == 0) return TRUE;
2361
2909
  if(b_v.type == ExcelEmpty && a_v.type == ExcelNumber && a_v.number == 0) return TRUE;
2362
-
2910
+
2363
2911
  if(a_v.type != b_v.type) return FALSE;
2364
-
2912
+
2365
2913
  float epsilon, difference;
2366
2914
 
2367
2915
  switch (a_v.type) {
@@ -2378,8 +2926,8 @@ static ExcelValue roughly_equal(ExcelValue a_v, ExcelValue b_v) {
2378
2926
  if(difference <= epsilon) return TRUE;
2379
2927
  // For debuging: printf("a: %e b:%e d: %e e: %e", a_v.number, b_v.number, difference, epsilon);
2380
2928
  return FALSE;
2381
- case ExcelBoolean:
2382
- case ExcelEmpty:
2929
+ case ExcelBoolean:
2930
+ case ExcelEmpty:
2383
2931
  if(a_v.number != b_v.number) return FALSE;
2384
2932
  return TRUE;
2385
2933
  case ExcelString:
@@ -2393,7 +2941,7 @@ static ExcelValue roughly_equal(ExcelValue a_v, ExcelValue b_v) {
2393
2941
  }
2394
2942
  return FALSE;
2395
2943
  }
2396
-
2944
+
2397
2945
 
2398
2946
  static void assert_equal(ExcelValue expected, ExcelValue actual, char location[]) {
2399
2947
  ExcelValue comparison = roughly_equal(actual, expected);
@@ -2408,5 +2956,3 @@ static void assert_equal(ExcelValue expected, ExcelValue actual, char location[]
2408
2956
  putchar('\n');
2409
2957
  }
2410
2958
  }
2411
-
2412
-