excel_to_code 0.3.17 → 0.3.18.beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
-