excel_to_code 0.0.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 (123) hide show
  1. data/README +41 -0
  2. data/bin/excel_to_c +63 -0
  3. data/bin/excel_to_ruby +9 -0
  4. data/src/commands.rb +2 -0
  5. data/src/commands/excel_to_c.rb +858 -0
  6. data/src/commands/excel_to_ruby.rb +620 -0
  7. data/src/compile.rb +2 -0
  8. data/src/compile/c.rb +5 -0
  9. data/src/compile/c/compile_to_c.rb +62 -0
  10. data/src/compile/c/compile_to_c_header.rb +26 -0
  11. data/src/compile/c/compile_to_c_unit_test.rb +42 -0
  12. data/src/compile/c/excel_to_c_runtime.c +2029 -0
  13. data/src/compile/c/map_formulae_to_c.rb +184 -0
  14. data/src/compile/c/map_sheet_names_to_c_names.rb +19 -0
  15. data/src/compile/c/map_values_to_c.rb +85 -0
  16. data/src/compile/c/map_values_to_c_structs.rb +37 -0
  17. data/src/compile/ruby.rb +3 -0
  18. data/src/compile/ruby/compile_to_ruby.rb +33 -0
  19. data/src/compile/ruby/compile_to_ruby_unit_test.rb +28 -0
  20. data/src/compile/ruby/excel_to_ruby_runtime.rb +1 -0
  21. data/src/compile/ruby/map_formulae_to_ruby.rb +95 -0
  22. data/src/compile/ruby/map_sheet_names_to_ruby_names.rb +19 -0
  23. data/src/compile/ruby/map_values_to_ruby.rb +65 -0
  24. data/src/excel.rb +5 -0
  25. data/src/excel/area.rb +93 -0
  26. data/src/excel/excel_functions.rb +84 -0
  27. data/src/excel/excel_functions/abs.rb +14 -0
  28. data/src/excel/excel_functions/add.rb +18 -0
  29. data/src/excel/excel_functions/and.rb +30 -0
  30. data/src/excel/excel_functions/apply_to_range.rb +17 -0
  31. data/src/excel/excel_functions/average.rb +12 -0
  32. data/src/excel/excel_functions/choose.rb +18 -0
  33. data/src/excel/excel_functions/cosh.rb +9 -0
  34. data/src/excel/excel_functions/count.rb +9 -0
  35. data/src/excel/excel_functions/counta.rb +8 -0
  36. data/src/excel/excel_functions/divide.rb +23 -0
  37. data/src/excel/excel_functions/excel_equal.rb +20 -0
  38. data/src/excel/excel_functions/excel_if.rb +8 -0
  39. data/src/excel/excel_functions/excel_match.rb +51 -0
  40. data/src/excel/excel_functions/find.rb +39 -0
  41. data/src/excel/excel_functions/iferror.rb +10 -0
  42. data/src/excel/excel_functions/index.rb +48 -0
  43. data/src/excel/excel_functions/left.rb +12 -0
  44. data/src/excel/excel_functions/less_than.rb +26 -0
  45. data/src/excel/excel_functions/less_than_or_equal.rb +26 -0
  46. data/src/excel/excel_functions/max.rb +12 -0
  47. data/src/excel/excel_functions/min.rb +12 -0
  48. data/src/excel/excel_functions/mod.rb +15 -0
  49. data/src/excel/excel_functions/more_than.rb +26 -0
  50. data/src/excel/excel_functions/more_than_or_equal.rb +26 -0
  51. data/src/excel/excel_functions/multiply.rb +24 -0
  52. data/src/excel/excel_functions/negative.rb +12 -0
  53. data/src/excel/excel_functions/not_equal.rb +19 -0
  54. data/src/excel/excel_functions/number_argument.rb +30 -0
  55. data/src/excel/excel_functions/pi.rb +7 -0
  56. data/src/excel/excel_functions/pmt.rb +16 -0
  57. data/src/excel/excel_functions/power.rb +18 -0
  58. data/src/excel/excel_functions/round.rb +13 -0
  59. data/src/excel/excel_functions/rounddown.rb +14 -0
  60. data/src/excel/excel_functions/roundup.rb +17 -0
  61. data/src/excel/excel_functions/string_join.rb +19 -0
  62. data/src/excel/excel_functions/subtotal.rb +13 -0
  63. data/src/excel/excel_functions/subtract.rb +18 -0
  64. data/src/excel/excel_functions/sum.rb +8 -0
  65. data/src/excel/excel_functions/sumif.rb +7 -0
  66. data/src/excel/excel_functions/sumifs.rb +74 -0
  67. data/src/excel/excel_functions/sumproduct.rb +32 -0
  68. data/src/excel/excel_functions/vlookup.rb +49 -0
  69. data/src/excel/formula_peg.rb +238 -0
  70. data/src/excel/formula_peg.txt +45 -0
  71. data/src/excel/reference.rb +56 -0
  72. data/src/excel/table.rb +108 -0
  73. data/src/excel_to_code.rb +7 -0
  74. data/src/extract.rb +13 -0
  75. data/src/extract/check_for_unknown_functions.rb +20 -0
  76. data/src/extract/extract_array_formulae.rb +23 -0
  77. data/src/extract/extract_formulae.rb +36 -0
  78. data/src/extract/extract_named_references.rb +38 -0
  79. data/src/extract/extract_relationships.rb +10 -0
  80. data/src/extract/extract_shared_formulae.rb +23 -0
  81. data/src/extract/extract_shared_strings.rb +20 -0
  82. data/src/extract/extract_simple_formulae.rb +18 -0
  83. data/src/extract/extract_table.rb +24 -0
  84. data/src/extract/extract_values.rb +29 -0
  85. data/src/extract/extract_worksheet_dimensions.rb +11 -0
  86. data/src/extract/extract_worksheet_names.rb +10 -0
  87. data/src/extract/extract_worksheet_table_relationships.rb +10 -0
  88. data/src/extract/simple_extract_from_xml.rb +19 -0
  89. data/src/rewrite.rb +10 -0
  90. data/src/rewrite/ast_copy_formula.rb +42 -0
  91. data/src/rewrite/ast_expand_array_formulae.rb +180 -0
  92. data/src/rewrite/rewrite_array_formulae.rb +71 -0
  93. data/src/rewrite/rewrite_array_formulae_to_arrays.rb +18 -0
  94. data/src/rewrite/rewrite_cell_references_to_include_sheet.rb +56 -0
  95. data/src/rewrite/rewrite_formulae_to_ast.rb +24 -0
  96. data/src/rewrite/rewrite_merge_formulae_and_values.rb +18 -0
  97. data/src/rewrite/rewrite_relationship_id_to_filename.rb +22 -0
  98. data/src/rewrite/rewrite_shared_formulae.rb +38 -0
  99. data/src/rewrite/rewrite_values_to_ast.rb +28 -0
  100. data/src/rewrite/rewrite_whole_row_column_references_to_areas.rb +90 -0
  101. data/src/rewrite/rewrite_worksheet_names.rb +20 -0
  102. data/src/simplify.rb +16 -0
  103. data/src/simplify/count_formula_references.rb +58 -0
  104. data/src/simplify/identify_dependencies.rb +56 -0
  105. data/src/simplify/identify_repeated_formula_elements.rb +37 -0
  106. data/src/simplify/inline_formulae.rb +77 -0
  107. data/src/simplify/map_formulae_to_values.rb +157 -0
  108. data/src/simplify/remove_cells.rb +18 -0
  109. data/src/simplify/replace_arrays_with_single_cells.rb +27 -0
  110. data/src/simplify/replace_blanks.rb +58 -0
  111. data/src/simplify/replace_common_elements_in_formulae.rb +19 -0
  112. data/src/simplify/replace_formulae_with_calculated_values.rb +21 -0
  113. data/src/simplify/replace_indirects_with_references.rb +44 -0
  114. data/src/simplify/replace_named_references.rb +82 -0
  115. data/src/simplify/replace_ranges_with_array_literals.rb +54 -0
  116. data/src/simplify/replace_shared_strings.rb +49 -0
  117. data/src/simplify/replace_table_references.rb +71 -0
  118. data/src/simplify/replace_values_with_constants.rb +47 -0
  119. data/src/simplify/simplify_arithmetic.rb +54 -0
  120. data/src/util.rb +2 -0
  121. data/src/util/not_supported_exception.rb +2 -0
  122. data/src/util/try.rb +9 -0
  123. metadata +207 -0
data/src/compile.rb ADDED
@@ -0,0 +1,2 @@
1
+ require_relative 'compile/ruby'
2
+ require_relative 'compile/c'
data/src/compile/c.rb ADDED
@@ -0,0 +1,5 @@
1
+ require_relative 'c/compile_to_c'
2
+ require_relative 'c/compile_to_c_header'
3
+ require_relative 'c/map_sheet_names_to_c_names'
4
+ require_relative "c/compile_to_c_unit_test"
5
+ require_relative "c/map_values_to_c_structs"
@@ -0,0 +1,62 @@
1
+ require_relative 'map_formulae_to_c'
2
+
3
+ class CompileToC
4
+
5
+ attr_accessor :settable
6
+ attr_accessor :gettable
7
+ attr_accessor :worksheet
8
+ attr_accessor :variable_set_counter
9
+
10
+ def self.rewrite(*args)
11
+ self.new.rewrite(*args)
12
+ end
13
+
14
+ def rewrite(input,sheet_names_file,output)
15
+ self.settable ||= lambda { |ref| false }
16
+ self.gettable ||= lambda { |ref| true }
17
+ @variable_set_counter ||= 0
18
+ mapper = MapFormulaeToC.new
19
+ mapper.worksheet = worksheet
20
+ mapper.sheet_names = Hash[sheet_names_file.readlines.map { |line| line.strip.split("\t")}]
21
+ c_name = mapper.sheet_names[worksheet]
22
+ input.lines do |line|
23
+ begin
24
+ ref, formula = line.split("\t")
25
+ ast = eval(formula)
26
+ calculation = mapper.map(ast)
27
+ name = "#{c_name}_#{ref.downcase}"
28
+ static_or_not = gettable.call(ref) ? "" : "static "
29
+ if settable.call(ref)
30
+ output.puts "ExcelValue #{name}_default() {"
31
+ mapper.initializers.each do |i|
32
+ output.puts " #{i}"
33
+ end
34
+ output.puts " return #{calculation};"
35
+ output.puts "}"
36
+ output.puts "static ExcelValue #{name}_variable;"
37
+ output.puts "ExcelValue #{name}() { if(variable_set[#{@variable_set_counter}] == 1) { return #{name}_variable; } else { return #{c_name}_#{ref.downcase}_default(); } }"
38
+ output.puts "void set_#{name}(ExcelValue newValue) { variable_set[#{@variable_set_counter}] = 1; #{name}_variable = newValue; }"
39
+ else
40
+ output.puts "#{static_or_not}ExcelValue #{name}() {"
41
+ output.puts " static ExcelValue result;"
42
+ output.puts " if(variable_set[#{@variable_set_counter}] == 1) { return result;}"
43
+ mapper.initializers.each do |i|
44
+ output.puts " #{i}"
45
+ end
46
+ #output.puts " return #{calculation};"
47
+ output.puts " result = #{calculation};"
48
+ output.puts " variable_set[#{@variable_set_counter}] = 1;"
49
+ output.puts " return result;"
50
+ output.puts "}"
51
+ end
52
+ output.puts
53
+ @variable_set_counter += 1
54
+ mapper.reset
55
+ rescue Exception => e
56
+ puts "Exception at line #{line}"
57
+ raise
58
+ end
59
+ end
60
+ end
61
+
62
+ end
@@ -0,0 +1,26 @@
1
+ class CompileToCHeader
2
+
3
+ attr_accessor :worksheet
4
+ attr_accessor :gettable
5
+ attr_accessor :settable
6
+
7
+ def self.rewrite(*args)
8
+ self.new.rewrite(*args)
9
+ end
10
+
11
+ def rewrite(input,sheet_names_file,output,defaults = nil)
12
+ c_name = Hash[sheet_names_file.readlines.map { |line| line.strip.split("\t")}][worksheet]
13
+ self.gettable ||= lambda { |ref| true }
14
+ self.settable ||= lambda { |ref| false }
15
+ input.lines do |line|
16
+ begin
17
+ ref, formula = line.split("\t")
18
+ static_or_not = (gettable.call(ref) || settable.call(ref)) ? "" : "static "
19
+ output.puts "#{static_or_not}ExcelValue #{c_name}_#{ref.downcase}();"
20
+ rescue Exception => e
21
+ puts "Exception at line #{line}"
22
+ raise
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,42 @@
1
+ class CompileToCUnitTest
2
+
3
+ def self.rewrite(*args)
4
+ self.new.rewrite(*args)
5
+ end
6
+
7
+ def rewrite(input,c_name, refs_to_test, output)
8
+ input.lines do |line|
9
+ begin
10
+ ref, formula = line.split("\t")
11
+ next unless refs_to_test.include?(ref)
12
+ output.puts "def test_#{c_name}_#{ref.downcase}"
13
+ output.puts " r = spreadsheet.#{c_name}_#{ref.downcase}"
14
+ ast = eval(formula)
15
+ case ast.first
16
+ when :number, :percentage
17
+ output.puts " assert_equal(:ExcelNumber,r[:type])"
18
+ output.puts " assert_in_epsilon(#{ast.last.to_f.to_s},r[:number])"
19
+ when :error
20
+ output.puts " assert_equal(:ExcelError,r[:type])"
21
+ when :string
22
+ output.puts " assert_equal(:ExcelString,r[:type])"
23
+ output.puts " assert_equal(#{ast.last.inspect},r[:string].force_encoding('utf-8'))"
24
+ when :boolean_true
25
+ output.puts " assert_equal(:ExcelBoolean,r[:type])"
26
+ output.puts " assert_equal(1,r[:number])"
27
+ when :boolean_false
28
+ output.puts " assert_equal(:ExcelBoolean,r[:type])"
29
+ output.puts " assert_equal(0,r[:number])"
30
+ else
31
+ raise NotSupportedException.new("#{ast} type can't be settable")
32
+ end
33
+ output.puts "end"
34
+ output.puts
35
+ rescue Exception => e
36
+ puts "Exception at line #{line}"
37
+ raise
38
+ end
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,2029 @@
1
+ #include <stdio.h>
2
+ #include <assert.h>
3
+ #include <string.h>
4
+ #include <stdlib.h>
5
+ #include <ctype.h>
6
+ #include <math.h>
7
+
8
+ // FIXME: Extract a header file
9
+
10
+ // I predefine an array of ExcelValues to store calculations
11
+ // Probably bad practice. At the very least, I should make it
12
+ // link to the cell reference in some way.
13
+ #define MAX_EXCEL_VALUE_HEAP_SIZE 1000000
14
+
15
+ #define true 1
16
+ #define false 0
17
+
18
+ // These are the various types of excel cell, plus ExcelRange which allows the passing of arrays of cells
19
+ typedef enum {ExcelEmpty, ExcelNumber, ExcelString, ExcelBoolean, ExcelError, ExcelRange} ExcelType;
20
+
21
+ struct excel_value {
22
+ ExcelType type;
23
+
24
+ double number; // Used for numbers and for error types
25
+ char *string; // Used for strings
26
+
27
+ // The following three are used for ranges
28
+ void *array;
29
+ int rows;
30
+ int columns;
31
+ };
32
+
33
+ typedef struct excel_value ExcelValue;
34
+
35
+
36
+ // These are used in the SUMIF and SUMIFS criteria (e.g., when passed a string like "<20")
37
+ typedef enum {LessThan, LessThanOrEqual, Equal, NotEqual, MoreThanOrEqual, MoreThan} ExcelComparisonType;
38
+
39
+ struct excel_comparison {
40
+ ExcelComparisonType type;
41
+ ExcelValue comparator;
42
+ };
43
+
44
+ typedef struct excel_comparison ExcelComparison;
45
+
46
+ // Headers
47
+ static ExcelValue more_than(ExcelValue a_v, ExcelValue b_v);
48
+ static ExcelValue more_than_or_equal(ExcelValue a_v, ExcelValue b_v);
49
+ static ExcelValue not_equal(ExcelValue a_v, ExcelValue b_v);
50
+ static ExcelValue less_than(ExcelValue a_v, ExcelValue b_v);
51
+ static ExcelValue less_than_or_equal(ExcelValue a_v, ExcelValue b_v);
52
+ static ExcelValue find_2(ExcelValue string_to_look_for_v, ExcelValue string_to_look_in_v);
53
+ static ExcelValue find(ExcelValue string_to_look_for_v, ExcelValue string_to_look_in_v, ExcelValue position_to_start_at_v);
54
+ static ExcelValue iferror(ExcelValue value, ExcelValue value_if_error);
55
+ static ExcelValue excel_index(ExcelValue array_v, ExcelValue row_number_v, ExcelValue column_number_v);
56
+ static ExcelValue excel_index_2(ExcelValue array_v, ExcelValue row_number_v);
57
+ static ExcelValue left(ExcelValue string_v, ExcelValue number_of_characters_v);
58
+ static ExcelValue left_1(ExcelValue string_v);
59
+ static ExcelValue max(int number_of_arguments, ExcelValue *arguments);
60
+ static ExcelValue min(int number_of_arguments, ExcelValue *arguments);
61
+ static ExcelValue mod(ExcelValue a_v, ExcelValue b_v);
62
+ static ExcelValue negative(ExcelValue a_v);
63
+ static ExcelValue pmt(ExcelValue rate_v, ExcelValue number_of_periods_v, ExcelValue present_value_v);
64
+ static ExcelValue power(ExcelValue a_v, ExcelValue b_v);
65
+ static ExcelValue excel_round(ExcelValue number_v, ExcelValue decimal_places_v);
66
+ static ExcelValue rounddown(ExcelValue number_v, ExcelValue decimal_places_v);
67
+ static ExcelValue roundup(ExcelValue number_v, ExcelValue decimal_places_v);
68
+ static ExcelValue string_join(int number_of_arguments, ExcelValue *arguments);
69
+ static ExcelValue subtotal(ExcelValue type, int number_of_arguments, ExcelValue *arguments);
70
+ static ExcelValue sumifs(ExcelValue sum_range_v, int number_of_arguments, ExcelValue *arguments);
71
+ static ExcelValue sumif(ExcelValue check_range_v, ExcelValue criteria_v, ExcelValue sum_range_v );
72
+ static ExcelValue sumif_2(ExcelValue check_range_v, ExcelValue criteria_v);
73
+ static ExcelValue sumproduct(int number_of_arguments, ExcelValue *arguments);
74
+ static ExcelValue vlookup_3(ExcelValue lookup_value_v,ExcelValue lookup_table_v, ExcelValue column_number_v);
75
+ static ExcelValue vlookup(ExcelValue lookup_value_v,ExcelValue lookup_table_v, ExcelValue column_number_v, ExcelValue match_type_v);
76
+
77
+ // My little heap
78
+ ExcelValue cells[MAX_EXCEL_VALUE_HEAP_SIZE];
79
+ int cell_counter = 0;
80
+
81
+ #define HEAPCHECK if(cell_counter >= MAX_EXCEL_VALUE_HEAP_SIZE) { printf("Heap exceeded"); exit(-1); }
82
+
83
+ // The object initializers
84
+ static ExcelValue new_excel_number(double number) {
85
+ cell_counter++;
86
+ HEAPCHECK
87
+ ExcelValue new_cell = cells[cell_counter];
88
+ new_cell.type = ExcelNumber;
89
+ new_cell.number = number;
90
+ return new_cell;
91
+ };
92
+
93
+ static ExcelValue new_excel_string(char *string) {
94
+ cell_counter++;
95
+ HEAPCHECK
96
+ ExcelValue new_cell = cells[cell_counter];
97
+ new_cell.type = ExcelString;
98
+ new_cell.string = string;
99
+ return new_cell;
100
+ };
101
+
102
+ static ExcelValue new_excel_range(void *array, int rows, int columns) {
103
+ cell_counter++;
104
+ HEAPCHECK
105
+ ExcelValue new_cell = cells[cell_counter];
106
+ new_cell.type = ExcelRange;
107
+ new_cell.array =array;
108
+ new_cell.rows = rows;
109
+ new_cell.columns = columns;
110
+ return new_cell;
111
+ };
112
+
113
+ static void * new_excel_value_array(int size) {
114
+ ExcelValue *pointer = malloc(sizeof(ExcelValue)*size);
115
+ if(pointer == 0) {
116
+ printf("Out of memory\n");
117
+ exit(-1);
118
+ }
119
+ return pointer;
120
+ };
121
+
122
+ // Constants
123
+ const ExcelValue BLANK = {.type = ExcelEmpty, .number = 0};
124
+
125
+ const ExcelValue ZERO = {.type = ExcelNumber, .number = 0};
126
+ const ExcelValue ONE = {.type = ExcelNumber, .number = 1};
127
+ const ExcelValue TWO = {.type = ExcelNumber, .number = 2};
128
+ const ExcelValue THREE = {.type = ExcelNumber, .number = 3};
129
+ const ExcelValue FOUR = {.type = ExcelNumber, .number = 4};
130
+ const ExcelValue FIVE = {.type = ExcelNumber, .number = 5};
131
+ const ExcelValue SIX = {.type = ExcelNumber, .number = 6};
132
+ const ExcelValue SEVEN = {.type = ExcelNumber, .number = 7};
133
+ const ExcelValue EIGHT = {.type = ExcelNumber, .number = 8};
134
+ const ExcelValue NINE = {.type = ExcelNumber, .number = 9};
135
+ const ExcelValue TEN = {.type = ExcelNumber, .number = 10};
136
+
137
+
138
+ // Booleans
139
+ const ExcelValue TRUE = {.type = ExcelBoolean, .number = true };
140
+ const ExcelValue FALSE = {.type = ExcelBoolean, .number = false };
141
+
142
+ // Errors
143
+ const ExcelValue VALUE = {.type = ExcelError, .number = 0};
144
+ const ExcelValue NAME = {.type = ExcelError, .number = 1};
145
+ const ExcelValue DIV0 = {.type = ExcelError, .number = 2};
146
+ const ExcelValue REF = {.type = ExcelError, .number = 3};
147
+ const ExcelValue NA = {.type = ExcelError, .number = 4};
148
+
149
+ // This is the error flag
150
+ static int conversion_error = 0;
151
+
152
+ // Helpful for debugging
153
+ static void inspect_excel_value(ExcelValue v) {
154
+ ExcelValue *array;
155
+ int i, j, k;
156
+ switch (v.type) {
157
+ case ExcelNumber:
158
+ printf("Number: %f\n",v.number);
159
+ break;
160
+ case ExcelBoolean:
161
+ if(v.number == true) {
162
+ printf("True\n");
163
+ } else if(v.number == false) {
164
+ printf("False\n");
165
+ } else {
166
+ printf("Boolean with undefined state %f\n",v.number);
167
+ }
168
+ break;
169
+ case ExcelEmpty:
170
+ if(v.number == 0) {
171
+ printf("Empty\n");
172
+ } else {
173
+ printf("Empty with unexpected state %f\n",v.number);
174
+ }
175
+ break;
176
+ case ExcelRange:
177
+ printf("Range rows: %d, columns: %d\n",v.rows,v.columns);
178
+ array = v.array;
179
+ for(i = 0; i < v.rows; i++) {
180
+ printf("Row %d:\n",i+1);
181
+ for(j = 0; j < v.columns; j++ ) {
182
+ printf("%d ",j+1);
183
+ k = (i * v.columns) + j;
184
+ inspect_excel_value(array[k]);
185
+ }
186
+ }
187
+ break;
188
+ case ExcelString:
189
+ printf("String: '%s'\n",v.string);
190
+ break;
191
+ case ExcelError:
192
+ printf("Error number %f ",v.number);
193
+ switch( (int)v.number) {
194
+ case 0: printf("VALUE\n"); break;
195
+ case 1: printf("NAME\n"); break;
196
+ case 2: printf("DIV0\n"); break;
197
+ case 3: printf("REF\n"); break;
198
+ case 4: printf("NA\n"); break;
199
+ }
200
+ break;
201
+ default:
202
+ printf("Type %d not recognised",v.type);
203
+ };
204
+ }
205
+
206
+ // Extracts numbers from ExcelValues
207
+ // Excel treats empty cells as zero
208
+ static double number_from(ExcelValue v) {
209
+ char *s;
210
+ char *p;
211
+ double n;
212
+ ExcelValue *array;
213
+ switch (v.type) {
214
+ case ExcelNumber:
215
+ case ExcelBoolean:
216
+ return v.number;
217
+ case ExcelEmpty:
218
+ return 0;
219
+ case ExcelRange:
220
+ array = v.array;
221
+ return number_from(array[0]);
222
+ case ExcelString:
223
+ s = v.string;
224
+ if (s == NULL || *s == '\0' || isspace(*s)) {
225
+ return 0;
226
+ }
227
+ n = strtod (s, &p);
228
+ if(*p == '\0') {
229
+ return n;
230
+ }
231
+ conversion_error = 1;
232
+ return 0;
233
+ case ExcelError:
234
+ return 0;
235
+ }
236
+ return 0;
237
+ }
238
+
239
+ #define NUMBER(value_name, name) double name; if(value_name.type == ExcelError) { return value_name; }; name = number_from(value_name);
240
+ #define CHECK_FOR_CONVERSION_ERROR if(conversion_error) { conversion_error = 0; return VALUE; };
241
+ #define CHECK_FOR_PASSED_ERROR(name) if(name.type == ExcelError) return name;
242
+
243
+ static ExcelValue excel_abs(ExcelValue a_v) {
244
+ CHECK_FOR_PASSED_ERROR(a_v)
245
+ NUMBER(a_v, a)
246
+ CHECK_FOR_CONVERSION_ERROR
247
+
248
+ if(a >= 0.0 ) {
249
+ return a_v;
250
+ } else {
251
+ return new_excel_number(-a);
252
+ }
253
+ }
254
+
255
+ static ExcelValue add(ExcelValue a_v, ExcelValue b_v) {
256
+ CHECK_FOR_PASSED_ERROR(a_v)
257
+ CHECK_FOR_PASSED_ERROR(b_v)
258
+ NUMBER(a_v, a)
259
+ NUMBER(b_v, b)
260
+ CHECK_FOR_CONVERSION_ERROR
261
+ return new_excel_number(a + b);
262
+ }
263
+
264
+ static ExcelValue excel_and(int array_size, ExcelValue *array) {
265
+ int i;
266
+ ExcelValue current_excel_value, array_result;
267
+
268
+ for(i=0;i<array_size;i++) {
269
+ current_excel_value = array[i];
270
+ switch (current_excel_value.type) {
271
+ case ExcelNumber:
272
+ case ExcelBoolean:
273
+ if(current_excel_value.number == false) return FALSE;
274
+ break;
275
+ case ExcelRange:
276
+ array_result = excel_and( current_excel_value.rows * current_excel_value.columns, current_excel_value.array );
277
+ if(array_result.type == ExcelError) return array_result;
278
+ if(array_result.type == ExcelBoolean && array_result.number == false) return FALSE;
279
+ break;
280
+ case ExcelString:
281
+ case ExcelEmpty:
282
+ break;
283
+ case ExcelError:
284
+ return current_excel_value;
285
+ break;
286
+ }
287
+ }
288
+ return TRUE;
289
+ }
290
+
291
+ struct average_result {
292
+ double sum;
293
+ double count;
294
+ int has_error;
295
+ ExcelValue error;
296
+ };
297
+
298
+ static struct average_result calculate_average(int array_size, ExcelValue *array) {
299
+ double sum = 0;
300
+ double count = 0;
301
+ int i;
302
+ ExcelValue current_excel_value;
303
+ struct average_result array_result, r;
304
+
305
+ for(i=0;i<array_size;i++) {
306
+ current_excel_value = array[i];
307
+ switch (current_excel_value.type) {
308
+ case ExcelNumber:
309
+ sum += current_excel_value.number;
310
+ count++;
311
+ break;
312
+ case ExcelRange:
313
+ array_result = calculate_average( current_excel_value.rows * current_excel_value.columns, current_excel_value.array );
314
+ if(array_result.has_error == true) return array_result;
315
+ sum += array_result.sum;
316
+ count += array_result.count;
317
+ break;
318
+ case ExcelBoolean:
319
+ case ExcelString:
320
+ case ExcelEmpty:
321
+ break;
322
+ case ExcelError:
323
+ r.has_error = true;
324
+ r.error = current_excel_value;
325
+ return r;
326
+ break;
327
+ }
328
+ }
329
+ r.count = count;
330
+ r.sum = sum;
331
+ return r;
332
+ }
333
+
334
+ static ExcelValue average(int array_size, ExcelValue *array) {
335
+ struct average_result r = calculate_average(array_size, array);
336
+ if(r.has_error == true) return r.error;
337
+ if(r.count == 0) return DIV0;
338
+ return new_excel_number(r.sum/r.count);
339
+ }
340
+
341
+ static ExcelValue choose(ExcelValue index_v, int array_size, ExcelValue *array) {
342
+ CHECK_FOR_PASSED_ERROR(index_v)
343
+
344
+ int index = (int) number_from(index_v);
345
+ CHECK_FOR_CONVERSION_ERROR
346
+ int i;
347
+ for(i=0;i<array_size;i++) {
348
+ if(array[i].type == ExcelError) return array[i];
349
+ }
350
+ if(index < 1) return VALUE;
351
+ if(index > array_size) return VALUE;
352
+ return array[index-1];
353
+ }
354
+
355
+ static ExcelValue count(int array_size, ExcelValue *array) {
356
+ int i;
357
+ int n = 0;
358
+ ExcelValue current_excel_value;
359
+
360
+ for(i=0;i<array_size;i++) {
361
+ current_excel_value = array[i];
362
+ switch (current_excel_value.type) {
363
+ case ExcelNumber:
364
+ n++;
365
+ break;
366
+ case ExcelRange:
367
+ n += count( current_excel_value.rows * current_excel_value.columns, current_excel_value.array ).number;
368
+ break;
369
+ case ExcelBoolean:
370
+ case ExcelString:
371
+ case ExcelEmpty:
372
+ case ExcelError:
373
+ break;
374
+ }
375
+ }
376
+ return new_excel_number(n);
377
+ }
378
+
379
+ static ExcelValue counta(int array_size, ExcelValue *array) {
380
+ int i;
381
+ int n = 0;
382
+ ExcelValue current_excel_value;
383
+
384
+ for(i=0;i<array_size;i++) {
385
+ current_excel_value = array[i];
386
+ switch(current_excel_value.type) {
387
+ case ExcelNumber:
388
+ case ExcelBoolean:
389
+ case ExcelString:
390
+ case ExcelError:
391
+ n++;
392
+ break;
393
+ case ExcelRange:
394
+ n += counta( current_excel_value.rows * current_excel_value.columns, current_excel_value.array ).number;
395
+ break;
396
+ case ExcelEmpty:
397
+ break;
398
+ }
399
+ }
400
+ return new_excel_number(n);
401
+ }
402
+
403
+ static ExcelValue divide(ExcelValue a_v, ExcelValue b_v) {
404
+ CHECK_FOR_PASSED_ERROR(a_v)
405
+ CHECK_FOR_PASSED_ERROR(b_v)
406
+ NUMBER(a_v, a)
407
+ NUMBER(b_v, b)
408
+ CHECK_FOR_CONVERSION_ERROR
409
+ if(b == 0) return DIV0;
410
+ return new_excel_number(a / b);
411
+ }
412
+
413
+ static ExcelValue excel_equal(ExcelValue a_v, ExcelValue b_v) {
414
+ CHECK_FOR_PASSED_ERROR(a_v)
415
+ CHECK_FOR_PASSED_ERROR(b_v)
416
+
417
+ if(a_v.type != b_v.type) return FALSE;
418
+
419
+ switch (a_v.type) {
420
+ case ExcelNumber:
421
+ case ExcelBoolean:
422
+ case ExcelEmpty:
423
+ if(a_v.number != b_v.number) return FALSE;
424
+ return TRUE;
425
+ case ExcelString:
426
+ if(strcasecmp(a_v.string,b_v.string) != 0 ) return FALSE;
427
+ return TRUE;
428
+ case ExcelError:
429
+ return a_v;
430
+ case ExcelRange:
431
+ return NA;
432
+ }
433
+ return FALSE;
434
+ }
435
+
436
+ static ExcelValue not_equal(ExcelValue a_v, ExcelValue b_v) {
437
+ ExcelValue result = excel_equal(a_v, b_v);
438
+ if(result.type == ExcelBoolean) {
439
+ if(result.number == 0) return TRUE;
440
+ return FALSE;
441
+ }
442
+ return result;
443
+ }
444
+
445
+ static ExcelValue excel_if(ExcelValue condition, ExcelValue true_case, ExcelValue false_case ) {
446
+ CHECK_FOR_PASSED_ERROR(condition)
447
+ CHECK_FOR_PASSED_ERROR(true_case)
448
+ CHECK_FOR_PASSED_ERROR(false_case)
449
+
450
+ switch (condition.type) {
451
+ case ExcelBoolean:
452
+ if(condition.number == true) return true_case;
453
+ return false_case;
454
+ case ExcelNumber:
455
+ if(condition.number == false) return false_case;
456
+ return true_case;
457
+ case ExcelEmpty:
458
+ return false_case;
459
+ case ExcelString:
460
+ return VALUE;
461
+ case ExcelError:
462
+ return condition;
463
+ case ExcelRange:
464
+ return VALUE;
465
+ }
466
+ return condition;
467
+ }
468
+
469
+ static ExcelValue excel_if_2(ExcelValue condition, ExcelValue true_case ) {
470
+ return excel_if( condition, true_case, FALSE );
471
+ }
472
+
473
+ static ExcelValue excel_index(ExcelValue array_v, ExcelValue row_number_v, ExcelValue column_number_v) {
474
+ CHECK_FOR_PASSED_ERROR(array_v)
475
+ CHECK_FOR_PASSED_ERROR(row_number_v)
476
+ CHECK_FOR_PASSED_ERROR(column_number_v)
477
+
478
+ ExcelValue *array;
479
+ int rows;
480
+ int columns;
481
+
482
+ NUMBER(row_number_v, row_number)
483
+ NUMBER(column_number_v, column_number)
484
+ CHECK_FOR_CONVERSION_ERROR
485
+
486
+ if(array_v.type == ExcelRange) {
487
+ array = array_v.array;
488
+ rows = array_v.rows;
489
+ columns = array_v.columns;
490
+ } else {
491
+ ExcelValue tmp_array[] = {array_v};
492
+ array = tmp_array;
493
+ rows = 1;
494
+ columns = 1;
495
+ }
496
+
497
+ if(row_number > rows) return REF;
498
+ if(column_number > columns) return REF;
499
+
500
+ if(row_number == 0) { // We need the whole column
501
+ if(column_number < 1) return REF;
502
+ ExcelValue *result = (ExcelValue *) new_excel_value_array(rows);
503
+ int result_index = 0;
504
+ ExcelValue r;
505
+ int array_index;
506
+ int i;
507
+ for(i = 0; i < rows; i++) {
508
+ array_index = (i*columns) + column_number - 1;
509
+ r = array[array_index];
510
+ if(r.type == ExcelEmpty) {
511
+ result[result_index] = ZERO;
512
+ } else {
513
+ result[result_index] = r;
514
+ }
515
+ result_index++;
516
+ }
517
+ return new_excel_range(result,rows,1);
518
+ } else if(column_number == 0 ) { // We need the whole row
519
+ if(row_number < 1) return REF;
520
+ ExcelValue *result = (ExcelValue*) new_excel_value_array(columns);
521
+ ExcelValue r;
522
+ int row_start = ((row_number-1)*columns);
523
+ int row_finish = row_start + columns;
524
+ int result_index = 0;
525
+ int i;
526
+ for(i = row_start; i < row_finish; i++) {
527
+ r = array[i];
528
+ if(r.type == ExcelEmpty) {
529
+ result[result_index] = ZERO;
530
+ } else {
531
+ result[result_index] = r;
532
+ }
533
+ result_index++;
534
+ }
535
+ return new_excel_range(result,1,columns);
536
+ } else { // We need a precise point
537
+ if(row_number < 1) return REF;
538
+ if(column_number < 1) return REF;
539
+ int position = ((row_number - 1) * columns) + column_number - 1;
540
+ ExcelValue result = array[position];
541
+ if(result.type == ExcelEmpty) return ZERO;
542
+ return result;
543
+ }
544
+
545
+ return FALSE;
546
+ };
547
+
548
+ static ExcelValue excel_index_2(ExcelValue array_v, ExcelValue offset) {
549
+ if(array_v.type == ExcelRange) {
550
+ if(array_v.rows == 1) {
551
+ return excel_index(array_v,ONE,offset);
552
+ } else if (array_v.columns == 1) {
553
+ return excel_index(array_v,offset,ONE);
554
+ } else {
555
+ return REF;
556
+ }
557
+ } else if (offset.type == ExcelNumber && offset.number == 1) {
558
+ return array_v;
559
+ } else {
560
+ return REF;
561
+ }
562
+ return REF;
563
+ };
564
+
565
+
566
+ static ExcelValue excel_match(ExcelValue lookup_value, ExcelValue lookup_array, ExcelValue match_type ) {
567
+ CHECK_FOR_PASSED_ERROR(lookup_value)
568
+ CHECK_FOR_PASSED_ERROR(lookup_array)
569
+ CHECK_FOR_PASSED_ERROR(match_type)
570
+
571
+ // Blanks are treaked as zeros
572
+ if(lookup_value.type == ExcelEmpty) lookup_value = ZERO;
573
+
574
+ // Setup the array
575
+ ExcelValue *array;
576
+ int size;
577
+ if(lookup_array.type == ExcelRange) {
578
+ // Check that the range is a row or column rather than an area
579
+ if((lookup_array.rows == 1) || (lookup_array.columns == 1)) {
580
+ array = lookup_array.array;
581
+ size = lookup_array.rows * lookup_array.columns;
582
+ } else {
583
+ // return NA error if covers an area.
584
+ return NA;
585
+ };
586
+ } else {
587
+ // Need to wrap the argument up as an array
588
+ size = 1;
589
+ ExcelValue tmp_array[1] = {lookup_array};
590
+ array = tmp_array;
591
+ }
592
+
593
+ int type = (int) number_from(match_type);
594
+ CHECK_FOR_CONVERSION_ERROR;
595
+
596
+ int i;
597
+ ExcelValue x;
598
+
599
+ switch(type) {
600
+ case 0:
601
+ for(i = 0; i < size; i++ ) {
602
+ x = array[i];
603
+ if(x.type == ExcelEmpty) x = ZERO;
604
+ if(excel_equal(lookup_value,x).number == true) return new_excel_number(i+1);
605
+ }
606
+ return NA;
607
+ break;
608
+ case 1:
609
+ for(i = 0; i < size; i++ ) {
610
+ x = array[i];
611
+ if(x.type == ExcelEmpty) x = ZERO;
612
+ if(more_than(x,lookup_value).number == true) {
613
+ if(i==0) return NA;
614
+ return new_excel_number(i);
615
+ }
616
+ }
617
+ return new_excel_number(size);
618
+ break;
619
+ case -1:
620
+ for(i = 0; i < size; i++ ) {
621
+ x = array[i];
622
+ if(x.type == ExcelEmpty) x = ZERO;
623
+ if(less_than(x,lookup_value).number == true) {
624
+ if(i==0) return NA;
625
+ return new_excel_number(i);
626
+ }
627
+ }
628
+ return new_excel_number(size-1);
629
+ break;
630
+ }
631
+ return NA;
632
+ }
633
+
634
+ static ExcelValue excel_match_2(ExcelValue lookup_value, ExcelValue lookup_array ) {
635
+ return excel_match(lookup_value,lookup_array,new_excel_number(0));
636
+ }
637
+
638
+ static ExcelValue find(ExcelValue find_text_v, ExcelValue within_text_v, ExcelValue start_number_v) {
639
+ CHECK_FOR_PASSED_ERROR(find_text_v)
640
+ CHECK_FOR_PASSED_ERROR(within_text_v)
641
+ CHECK_FOR_PASSED_ERROR(start_number_v)
642
+
643
+ char *find_text;
644
+ char *within_text;
645
+ char *within_text_offset;
646
+ char *result;
647
+ int start_number = number_from(start_number_v);
648
+ CHECK_FOR_CONVERSION_ERROR
649
+
650
+ // Deal with blanks
651
+ if(within_text_v.type == ExcelString) {
652
+ within_text = within_text_v.string;
653
+ } else if( within_text_v.type == ExcelEmpty) {
654
+ within_text = "";
655
+ }
656
+
657
+ if(find_text_v.type == ExcelString) {
658
+ find_text = find_text_v.string;
659
+ } else if( find_text_v.type == ExcelEmpty) {
660
+ return start_number_v;
661
+ }
662
+
663
+ // Check length
664
+ if(start_number < 1) return VALUE;
665
+ if(start_number > strlen(within_text)) return VALUE;
666
+
667
+ // Offset our within_text pointer
668
+ // FIXME: No way this is utf-8 compatible
669
+ within_text_offset = within_text + (start_number - 1);
670
+ result = strstr(within_text_offset,find_text);
671
+ if(result) {
672
+ return new_excel_number(result - within_text + 1);
673
+ }
674
+ return VALUE;
675
+ }
676
+
677
+ static ExcelValue find_2(ExcelValue string_to_look_for_v, ExcelValue string_to_look_in_v) {
678
+ return find(string_to_look_for_v, string_to_look_in_v, ONE);
679
+ };
680
+
681
+ static ExcelValue left(ExcelValue string_v, ExcelValue number_of_characters_v) {
682
+ CHECK_FOR_PASSED_ERROR(string_v)
683
+ CHECK_FOR_PASSED_ERROR(number_of_characters_v)
684
+ if(string_v.type == ExcelEmpty) return BLANK;
685
+ if(number_of_characters_v.type == ExcelEmpty) return BLANK;
686
+
687
+ int number_of_characters = (int) number_from(number_of_characters_v);
688
+ CHECK_FOR_CONVERSION_ERROR
689
+
690
+ char *string;
691
+ switch (string_v.type) {
692
+ case ExcelString:
693
+ string = string_v.string;
694
+ break;
695
+ case ExcelNumber:
696
+ string = malloc(20);
697
+ if(string == 0) {
698
+ printf("Out of memory");
699
+ exit(-1);
700
+ }
701
+ snprintf(string,20,"%f",string_v.number);
702
+ break;
703
+ case ExcelBoolean:
704
+ if(string_v.number == true) {
705
+ string = "TRUE";
706
+ } else {
707
+ string = "FALSE";
708
+ }
709
+ break;
710
+ case ExcelEmpty:
711
+ case ExcelError:
712
+ case ExcelRange:
713
+ return string_v;
714
+ }
715
+
716
+ char *left_string = malloc(number_of_characters+1);
717
+ if(left_string == 0) {
718
+ printf("Out of memory");
719
+ exit(-1);
720
+ }
721
+ memcpy(left_string,string,number_of_characters);
722
+ left_string[number_of_characters] = '\0';
723
+ return new_excel_string(left_string);
724
+ }
725
+
726
+ static ExcelValue left_1(ExcelValue string_v) {
727
+ return left(string_v, ONE);
728
+ }
729
+
730
+ static ExcelValue iferror(ExcelValue value, ExcelValue value_if_error) {
731
+ if(value.type == ExcelError) return value_if_error;
732
+ return value;
733
+ }
734
+
735
+ static ExcelValue more_than(ExcelValue a_v, ExcelValue b_v) {
736
+ CHECK_FOR_PASSED_ERROR(a_v)
737
+ CHECK_FOR_PASSED_ERROR(b_v)
738
+
739
+ switch (a_v.type) {
740
+ case ExcelNumber:
741
+ case ExcelBoolean:
742
+ case ExcelEmpty:
743
+ if((b_v.type == ExcelNumber) || (b_v.type == ExcelBoolean) || (b_v.type == ExcelEmpty)) {
744
+ if(a_v.number <= b_v.number) return FALSE;
745
+ return TRUE;
746
+ }
747
+ return FALSE;
748
+ case ExcelString:
749
+ if(b_v.type == ExcelString) {
750
+ if(strcasecmp(a_v.string,b_v.string) <= 0 ) return FALSE;
751
+ return TRUE;
752
+ }
753
+ return FALSE;
754
+ case ExcelError:
755
+ return a_v;
756
+ case ExcelRange:
757
+ return NA;
758
+ }
759
+ return FALSE;
760
+ }
761
+
762
+ static ExcelValue more_than_or_equal(ExcelValue a_v, ExcelValue b_v) {
763
+ CHECK_FOR_PASSED_ERROR(a_v)
764
+ CHECK_FOR_PASSED_ERROR(b_v)
765
+
766
+ switch (a_v.type) {
767
+ case ExcelNumber:
768
+ case ExcelBoolean:
769
+ case ExcelEmpty:
770
+ if((b_v.type == ExcelNumber) || (b_v.type == ExcelBoolean) || (b_v.type == ExcelEmpty)) {
771
+ if(a_v.number < b_v.number) return FALSE;
772
+ return TRUE;
773
+ }
774
+ return FALSE;
775
+ case ExcelString:
776
+ if(b_v.type == ExcelString) {
777
+ if(strcasecmp(a_v.string,b_v.string) < 0 ) return FALSE;
778
+ return TRUE;
779
+ }
780
+ return FALSE;
781
+ case ExcelError:
782
+ return a_v;
783
+ case ExcelRange:
784
+ return NA;
785
+ }
786
+ return FALSE;
787
+ }
788
+
789
+
790
+ static ExcelValue less_than(ExcelValue a_v, ExcelValue b_v) {
791
+ CHECK_FOR_PASSED_ERROR(a_v)
792
+ CHECK_FOR_PASSED_ERROR(b_v)
793
+
794
+ switch (a_v.type) {
795
+ case ExcelNumber:
796
+ case ExcelBoolean:
797
+ case ExcelEmpty:
798
+ if((b_v.type == ExcelNumber) || (b_v.type == ExcelBoolean) || (b_v.type == ExcelEmpty)) {
799
+ if(a_v.number >= b_v.number) return FALSE;
800
+ return TRUE;
801
+ }
802
+ return FALSE;
803
+ case ExcelString:
804
+ if(b_v.type == ExcelString) {
805
+ if(strcasecmp(a_v.string,b_v.string) >= 0 ) return FALSE;
806
+ return TRUE;
807
+ }
808
+ return FALSE;
809
+ case ExcelError:
810
+ return a_v;
811
+ case ExcelRange:
812
+ return NA;
813
+ }
814
+ return FALSE;
815
+ }
816
+
817
+ static ExcelValue less_than_or_equal(ExcelValue a_v, ExcelValue b_v) {
818
+ CHECK_FOR_PASSED_ERROR(a_v)
819
+ CHECK_FOR_PASSED_ERROR(b_v)
820
+
821
+ switch (a_v.type) {
822
+ case ExcelNumber:
823
+ case ExcelBoolean:
824
+ case ExcelEmpty:
825
+ if((b_v.type == ExcelNumber) || (b_v.type == ExcelBoolean) || (b_v.type == ExcelEmpty)) {
826
+ if(a_v.number > b_v.number) return FALSE;
827
+ return TRUE;
828
+ }
829
+ return FALSE;
830
+ case ExcelString:
831
+ if(b_v.type == ExcelString) {
832
+ if(strcasecmp(a_v.string,b_v.string) > 0 ) return FALSE;
833
+ return TRUE;
834
+ }
835
+ return FALSE;
836
+ case ExcelError:
837
+ return a_v;
838
+ case ExcelRange:
839
+ return NA;
840
+ }
841
+ return FALSE;
842
+ }
843
+
844
+ static ExcelValue subtract(ExcelValue a_v, ExcelValue b_v) {
845
+ CHECK_FOR_PASSED_ERROR(a_v)
846
+ CHECK_FOR_PASSED_ERROR(b_v)
847
+ NUMBER(a_v, a)
848
+ NUMBER(b_v, b)
849
+ CHECK_FOR_CONVERSION_ERROR
850
+ return new_excel_number(a - b);
851
+ }
852
+
853
+ static ExcelValue multiply(ExcelValue a_v, ExcelValue b_v) {
854
+ CHECK_FOR_PASSED_ERROR(a_v)
855
+ CHECK_FOR_PASSED_ERROR(b_v)
856
+ NUMBER(a_v, a)
857
+ NUMBER(b_v, b)
858
+ CHECK_FOR_CONVERSION_ERROR
859
+ return new_excel_number(a * b);
860
+ }
861
+
862
+ static ExcelValue sum(int array_size, ExcelValue *array) {
863
+ double total = 0;
864
+ int i;
865
+ for(i=0;i<array_size;i++) {
866
+ switch(array[i].type) {
867
+ case ExcelNumber:
868
+ total += array[i].number;
869
+ break;
870
+ case ExcelRange:
871
+ total += number_from(sum( array[i].rows * array[i].columns, array[i].array ));
872
+ break;
873
+ case ExcelError:
874
+ return array[i];
875
+ break;
876
+ default:
877
+ break;
878
+ }
879
+ }
880
+ return new_excel_number(total);
881
+ }
882
+
883
+ static ExcelValue max(int number_of_arguments, ExcelValue *arguments) {
884
+ double biggest_number_found;
885
+ int any_number_found = 0;
886
+ int i;
887
+ ExcelValue current_excel_value;
888
+
889
+ for(i=0;i<number_of_arguments;i++) {
890
+ current_excel_value = arguments[i];
891
+ if(current_excel_value.type == ExcelNumber) {
892
+ if(!any_number_found) {
893
+ any_number_found = 1;
894
+ biggest_number_found = current_excel_value.number;
895
+ }
896
+ if(current_excel_value.number > biggest_number_found) biggest_number_found = current_excel_value.number;
897
+ } else if(current_excel_value.type == ExcelRange) {
898
+ current_excel_value = max( current_excel_value.rows * current_excel_value.columns, current_excel_value.array );
899
+ if(current_excel_value.type == ExcelError) return current_excel_value;
900
+ if(current_excel_value.type == ExcelNumber)
901
+ if(!any_number_found) {
902
+ any_number_found = 1;
903
+ biggest_number_found = current_excel_value.number;
904
+ }
905
+ if(current_excel_value.number > biggest_number_found) biggest_number_found = current_excel_value.number;
906
+ } else if(current_excel_value.type == ExcelError) {
907
+ return current_excel_value;
908
+ }
909
+ }
910
+ if(!any_number_found) {
911
+ any_number_found = 1;
912
+ biggest_number_found = 0;
913
+ }
914
+ return new_excel_number(biggest_number_found);
915
+ }
916
+
917
+ static ExcelValue min(int number_of_arguments, ExcelValue *arguments) {
918
+ double smallest_number_found = 0;
919
+ int any_number_found = 0;
920
+ int i;
921
+ ExcelValue current_excel_value;
922
+
923
+ for(i=0;i<number_of_arguments;i++) {
924
+ current_excel_value = arguments[i];
925
+ if(current_excel_value.type == ExcelNumber) {
926
+ if(!any_number_found) {
927
+ any_number_found = 1;
928
+ smallest_number_found = current_excel_value.number;
929
+ }
930
+ if(current_excel_value.number < smallest_number_found) smallest_number_found = current_excel_value.number;
931
+ } else if(current_excel_value.type == ExcelRange) {
932
+ current_excel_value = min( current_excel_value.rows * current_excel_value.columns, current_excel_value.array );
933
+ if(current_excel_value.type == ExcelError) return current_excel_value;
934
+ if(current_excel_value.type == ExcelNumber)
935
+ if(!any_number_found) {
936
+ any_number_found = 1;
937
+ smallest_number_found = current_excel_value.number;
938
+ }
939
+ if(current_excel_value.number < smallest_number_found) smallest_number_found = current_excel_value.number;
940
+ } else if(current_excel_value.type == ExcelError) {
941
+ return current_excel_value;
942
+ }
943
+ }
944
+ if(!any_number_found) {
945
+ any_number_found = 1;
946
+ smallest_number_found = 0;
947
+ }
948
+ return new_excel_number(smallest_number_found);
949
+ }
950
+
951
+ static ExcelValue mod(ExcelValue a_v, ExcelValue b_v) {
952
+ CHECK_FOR_PASSED_ERROR(a_v)
953
+ CHECK_FOR_PASSED_ERROR(b_v)
954
+
955
+ NUMBER(a_v, a)
956
+ NUMBER(b_v, b)
957
+ CHECK_FOR_CONVERSION_ERROR
958
+ if(b == 0) return DIV0;
959
+ return new_excel_number(fmod(a,b));
960
+ }
961
+
962
+ static ExcelValue negative(ExcelValue a_v) {
963
+ CHECK_FOR_PASSED_ERROR(a_v)
964
+ NUMBER(a_v, a)
965
+ CHECK_FOR_CONVERSION_ERROR
966
+ return new_excel_number(-a);
967
+ }
968
+
969
+ static ExcelValue pmt(ExcelValue rate_v, ExcelValue number_of_periods_v, ExcelValue present_value_v) {
970
+ CHECK_FOR_PASSED_ERROR(rate_v)
971
+ CHECK_FOR_PASSED_ERROR(number_of_periods_v)
972
+ CHECK_FOR_PASSED_ERROR(present_value_v)
973
+
974
+ NUMBER(rate_v,rate)
975
+ NUMBER(number_of_periods_v,number_of_periods)
976
+ NUMBER(present_value_v,present_value)
977
+ CHECK_FOR_CONVERSION_ERROR
978
+
979
+ if(rate == 0) return new_excel_number(-(present_value / number_of_periods));
980
+ return new_excel_number(-present_value*(rate*(pow((1+rate),number_of_periods)))/((pow((1+rate),number_of_periods))-1));
981
+ }
982
+
983
+ static ExcelValue power(ExcelValue a_v, ExcelValue b_v) {
984
+ CHECK_FOR_PASSED_ERROR(a_v)
985
+ CHECK_FOR_PASSED_ERROR(b_v)
986
+
987
+ NUMBER(a_v, a)
988
+ NUMBER(b_v, b)
989
+ CHECK_FOR_CONVERSION_ERROR
990
+ return new_excel_number(pow(a,b));
991
+ }
992
+
993
+ static ExcelValue excel_round(ExcelValue number_v, ExcelValue decimal_places_v) {
994
+ CHECK_FOR_PASSED_ERROR(number_v)
995
+ CHECK_FOR_PASSED_ERROR(decimal_places_v)
996
+
997
+ NUMBER(number_v, number)
998
+ NUMBER(decimal_places_v, decimal_places)
999
+ CHECK_FOR_CONVERSION_ERROR
1000
+
1001
+ double multiple = pow(10,decimal_places);
1002
+
1003
+ return new_excel_number( round(number * multiple) / multiple );
1004
+ }
1005
+
1006
+ static ExcelValue rounddown(ExcelValue number_v, ExcelValue decimal_places_v) {
1007
+ CHECK_FOR_PASSED_ERROR(number_v)
1008
+ CHECK_FOR_PASSED_ERROR(decimal_places_v)
1009
+
1010
+ NUMBER(number_v, number)
1011
+ NUMBER(decimal_places_v, decimal_places)
1012
+ CHECK_FOR_CONVERSION_ERROR
1013
+
1014
+ double multiple = pow(10,decimal_places);
1015
+
1016
+ return new_excel_number( trunc(number * multiple) / multiple );
1017
+ }
1018
+
1019
+ static ExcelValue roundup(ExcelValue number_v, ExcelValue decimal_places_v) {
1020
+ CHECK_FOR_PASSED_ERROR(number_v)
1021
+ CHECK_FOR_PASSED_ERROR(decimal_places_v)
1022
+
1023
+ NUMBER(number_v, number)
1024
+ NUMBER(decimal_places_v, decimal_places)
1025
+ CHECK_FOR_CONVERSION_ERROR
1026
+
1027
+ double multiple = pow(10,decimal_places);
1028
+ if(number < 0) return new_excel_number( floor(number * multiple) / multiple );
1029
+ return new_excel_number( ceil(number * multiple) / multiple );
1030
+ }
1031
+
1032
+ static ExcelValue string_join(int number_of_arguments, ExcelValue *arguments) {
1033
+ int allocated_length = 100;
1034
+ int used_length = 0;
1035
+ char *string = malloc(allocated_length);
1036
+ if(string == 0) {
1037
+ printf("Out of memory");
1038
+ exit(-1);
1039
+ }
1040
+ char *current_string;
1041
+ int current_string_length;
1042
+ ExcelValue current_v;
1043
+ int i;
1044
+ for(i=0;i<number_of_arguments;i++) {
1045
+ current_v = (ExcelValue) arguments[i];
1046
+ switch (current_v.type) {
1047
+ case ExcelString:
1048
+ current_string = current_v.string;
1049
+ break;
1050
+ case ExcelNumber:
1051
+ current_string = malloc(20);
1052
+ if(current_string == 0) {
1053
+ printf("Out of memory");
1054
+ exit(-1);
1055
+ }
1056
+ snprintf(current_string,20,"%g",current_v.number);
1057
+ break;
1058
+ case ExcelBoolean:
1059
+ if(current_v.number == true) {
1060
+ current_string = "TRUE";
1061
+ } else {
1062
+ current_string = "FALSE";
1063
+ }
1064
+ break;
1065
+ case ExcelEmpty:
1066
+ current_string = "";
1067
+ break;
1068
+ case ExcelError:
1069
+ return current_v;
1070
+ case ExcelRange:
1071
+ return VALUE;
1072
+ }
1073
+ current_string_length = strlen(current_string);
1074
+ if( (used_length + current_string_length + 1) > allocated_length) {
1075
+ allocated_length += 100;
1076
+ string = realloc(string,allocated_length);
1077
+ }
1078
+ memcpy(string + used_length, current_string, current_string_length);
1079
+ used_length = used_length + current_string_length;
1080
+ }
1081
+ string = realloc(string,used_length+1);
1082
+ return new_excel_string(string);
1083
+ }
1084
+
1085
+ static ExcelValue subtotal(ExcelValue subtotal_type_v, int number_of_arguments, ExcelValue *arguments) {
1086
+ CHECK_FOR_PASSED_ERROR(subtotal_type_v)
1087
+ NUMBER(subtotal_type_v,subtotal_type)
1088
+ CHECK_FOR_CONVERSION_ERROR
1089
+
1090
+ switch((int) subtotal_type) {
1091
+ case 1:
1092
+ case 101:
1093
+ return average(number_of_arguments,arguments);
1094
+ break;
1095
+ case 2:
1096
+ case 102:
1097
+ return count(number_of_arguments,arguments);
1098
+ break;
1099
+ case 3:
1100
+ case 103:
1101
+ return counta(number_of_arguments,arguments);
1102
+ break;
1103
+ case 9:
1104
+ case 109:
1105
+ return sum(number_of_arguments,arguments);
1106
+ break;
1107
+ default:
1108
+ return VALUE;
1109
+ break;
1110
+ }
1111
+ }
1112
+
1113
+ static ExcelValue sumifs(ExcelValue sum_range_v, int number_of_arguments, ExcelValue *arguments) {
1114
+ // First, set up the sum_range
1115
+ CHECK_FOR_PASSED_ERROR(sum_range_v);
1116
+
1117
+ // Set up the sum range
1118
+ ExcelValue *sum_range;
1119
+ int sum_range_rows, sum_range_columns;
1120
+
1121
+ if(sum_range_v.type == ExcelRange) {
1122
+ sum_range = sum_range_v.array;
1123
+ sum_range_rows = sum_range_v.rows;
1124
+ sum_range_columns = sum_range_v.columns;
1125
+ } else {
1126
+ sum_range = (ExcelValue*) new_excel_value_array(1);
1127
+ sum_range[0] = sum_range_v;
1128
+ sum_range_rows = 1;
1129
+ sum_range_columns = 1;
1130
+ }
1131
+
1132
+ // Then go through and set up the check ranges
1133
+ if(number_of_arguments % 2 != 0) return VALUE;
1134
+ int number_of_criteria = number_of_arguments / 2;
1135
+ ExcelValue *criteria_range = (ExcelValue*) new_excel_value_array(number_of_criteria);
1136
+ ExcelValue current_value;
1137
+ int i;
1138
+ for(i = 0; i < number_of_criteria; i++) {
1139
+ current_value = arguments[i*2];
1140
+ if(current_value.type == ExcelRange) {
1141
+ criteria_range[i] = current_value;
1142
+ if(current_value.rows != sum_range_rows) return VALUE;
1143
+ if(current_value.columns != sum_range_columns) return VALUE;
1144
+ } else {
1145
+ if(sum_range_rows != 1) return VALUE;
1146
+ if(sum_range_columns != 1) return VALUE;
1147
+ ExcelValue *tmp_array2 = (ExcelValue*) new_excel_value_array(1);
1148
+ tmp_array2[0] = current_value;
1149
+ criteria_range[i] = new_excel_range(tmp_array2,1,1);
1150
+ }
1151
+ }
1152
+
1153
+ // Now go through and set up the criteria
1154
+ ExcelComparison *criteria = malloc(sizeof(ExcelComparison)*number_of_criteria);
1155
+ if(criteria == 0) {
1156
+ printf("Out of memory\n");
1157
+ exit(-1);
1158
+ }
1159
+ char *s;
1160
+ for(i = 0; i < number_of_criteria; i++) {
1161
+ current_value = arguments[(i*2)+1];
1162
+
1163
+ if(current_value.type == ExcelString) {
1164
+ s = current_value.string;
1165
+ if(s[0] == '<') {
1166
+ if( s[1] == '>') {
1167
+ criteria[i].type = NotEqual;
1168
+ criteria[i].comparator = new_excel_string(strndup(s+2,strlen(s)-2));
1169
+ } else if(s[1] == '=') {
1170
+ criteria[i].type = LessThanOrEqual;
1171
+ criteria[i].comparator = new_excel_string(strndup(s+2,strlen(s)-2));
1172
+ } else {
1173
+ criteria[i].type = LessThan;
1174
+ criteria[i].comparator = new_excel_string(strndup(s+1,strlen(s)-1));
1175
+ }
1176
+ } else if(s[0] == '>') {
1177
+ if(s[1] == '=') {
1178
+ criteria[i].type = MoreThanOrEqual;
1179
+ criteria[i].comparator = new_excel_string(strndup(s+2,strlen(s)-2));
1180
+ } else {
1181
+ criteria[i].type = MoreThan;
1182
+ criteria[i].comparator = new_excel_string(strndup(s+1,strlen(s)-1));
1183
+ }
1184
+ } else if(s[0] == '=') {
1185
+ criteria[i].type = Equal;
1186
+ criteria[i].comparator = new_excel_string(strndup(s+1,strlen(s)-1));
1187
+ } else {
1188
+ criteria[i].type = Equal;
1189
+ criteria[i].comparator = current_value;
1190
+ }
1191
+ } else {
1192
+ criteria[i].type = Equal;
1193
+ criteria[i].comparator = current_value;
1194
+ }
1195
+ }
1196
+
1197
+ double total = 0;
1198
+ int size = sum_range_columns * sum_range_rows;
1199
+ int j;
1200
+ int passed = 0;
1201
+ ExcelValue value_to_be_checked;
1202
+ ExcelComparison comparison;
1203
+ ExcelValue comparator;
1204
+ double number;
1205
+ // For each cell in the sum range
1206
+ for(j=0; j < size; j++ ) {
1207
+ passed = 1;
1208
+ for(i=0; i < number_of_criteria; i++) {
1209
+ value_to_be_checked = ((ExcelValue *) ((ExcelValue) criteria_range[i]).array)[j];
1210
+ comparison = criteria[i];
1211
+ comparator = comparison.comparator;
1212
+
1213
+ switch(value_to_be_checked.type) {
1214
+ case ExcelError: // Errors match only errors
1215
+ if(comparison.type != Equal) passed = 0;
1216
+ if(comparator.type != ExcelError) passed = 0;
1217
+ if(value_to_be_checked.number != comparator.number) passed = 0;
1218
+ break;
1219
+ case ExcelBoolean: // Booleans match only booleans (FIXME: I think?)
1220
+ if(comparison.type != Equal) passed = 0;
1221
+ if(comparator.type != ExcelBoolean ) passed = 0;
1222
+ if(value_to_be_checked.number != comparator.number) passed = 0;
1223
+ break;
1224
+ case ExcelEmpty:
1225
+ // if(comparator.type == ExcelEmpty) break; // FIXME: Huh? In excel blank doesn't match blank?!
1226
+ if(comparator.type != ExcelString) {
1227
+ passed = 0;
1228
+ break;
1229
+ } else {
1230
+ if(strlen(comparator.string) != 0) passed = 0; // Empty strings match blanks.
1231
+ break;
1232
+ }
1233
+ break;
1234
+ case ExcelNumber:
1235
+ if(comparator.type == ExcelNumber) {
1236
+ number = comparator.number;
1237
+ } else if(comparator.type == ExcelString) {
1238
+ number = number_from(comparator);
1239
+ if(conversion_error == 1) {
1240
+ conversion_error = 0;
1241
+ passed = 0;
1242
+ break;
1243
+ }
1244
+ } else {
1245
+ passed = 0;
1246
+ break;
1247
+ }
1248
+ switch(comparison.type) {
1249
+ case Equal:
1250
+ if(value_to_be_checked.number != number) passed = 0;
1251
+ break;
1252
+ case LessThan:
1253
+ if(value_to_be_checked.number >= number) passed = 0;
1254
+ break;
1255
+ case LessThanOrEqual:
1256
+ if(value_to_be_checked.number > number) passed = 0;
1257
+ break;
1258
+ case NotEqual:
1259
+ if(value_to_be_checked.number == number) passed = 0;
1260
+ break;
1261
+ case MoreThanOrEqual:
1262
+ if(value_to_be_checked.number < number) passed = 0;
1263
+ break;
1264
+ case MoreThan:
1265
+ if(value_to_be_checked.number <= number) passed = 0;
1266
+ break;
1267
+ }
1268
+ break;
1269
+ case ExcelString:
1270
+ // First case, the comparator is a number, simplification is that it can only be equal
1271
+ if(comparator.type == ExcelNumber) {
1272
+ if(comparison.type != Equal) {
1273
+ printf("This shouldn't be possible?");
1274
+ passed = 0;
1275
+ break;
1276
+ }
1277
+ number = number_from(value_to_be_checked);
1278
+ if(conversion_error == 1) {
1279
+ conversion_error = 0;
1280
+ passed = 0;
1281
+ break;
1282
+ }
1283
+ if(number != comparator.number) {
1284
+ passed = 0;
1285
+ break;
1286
+ } else {
1287
+ break;
1288
+ }
1289
+ // Second case, the comparator is also a string, so need to be able to do full range of tests
1290
+ } else if(comparator.type == ExcelString) {
1291
+ switch(comparison.type) {
1292
+ case Equal:
1293
+ if(excel_equal(value_to_be_checked,comparator).number == 0) passed = 0;
1294
+ break;
1295
+ case LessThan:
1296
+ if(less_than(value_to_be_checked,comparator).number == 0) passed = 0;
1297
+ break;
1298
+ case LessThanOrEqual:
1299
+ if(less_than_or_equal(value_to_be_checked,comparator).number == 0) passed = 0;
1300
+ break;
1301
+ case NotEqual:
1302
+ if(not_equal(value_to_be_checked,comparator).number == 0) passed = 0;
1303
+ break;
1304
+ case MoreThanOrEqual:
1305
+ if(more_than_or_equal(value_to_be_checked,comparator).number == 0) passed = 0;
1306
+ break;
1307
+ case MoreThan:
1308
+ if(more_than(value_to_be_checked,comparator).number == 0) passed = 0;
1309
+ break;
1310
+ }
1311
+ } else {
1312
+ passed = 0;
1313
+ break;
1314
+ }
1315
+ break;
1316
+ case ExcelRange:
1317
+ return VALUE;
1318
+ }
1319
+ if(passed == 0) break;
1320
+ }
1321
+ if(passed == 1) {
1322
+ current_value = sum_range[j];
1323
+ if(current_value.type == ExcelError) {
1324
+ return current_value;
1325
+ } else if(current_value.type == ExcelNumber) {
1326
+ total += current_value.number;
1327
+ }
1328
+ }
1329
+ }
1330
+ return new_excel_number(total);
1331
+ }
1332
+
1333
+ static ExcelValue sumif(ExcelValue check_range_v, ExcelValue criteria_v, ExcelValue sum_range_v ) {
1334
+ ExcelValue tmp_array_sumif[] = {check_range_v, criteria_v};
1335
+ return sumifs(sum_range_v,2,tmp_array_sumif);
1336
+ }
1337
+
1338
+ static ExcelValue sumif_2(ExcelValue check_range_v, ExcelValue criteria_v) {
1339
+ ExcelValue tmp_array_sumif2[] = {check_range_v, criteria_v};
1340
+ return sumifs(check_range_v,2,tmp_array_sumif2);
1341
+ }
1342
+
1343
+ static ExcelValue sumproduct(int number_of_arguments, ExcelValue *arguments) {
1344
+ if(number_of_arguments <1) return VALUE;
1345
+
1346
+ int a;
1347
+ int i;
1348
+ int j;
1349
+ int rows;
1350
+ int columns;
1351
+ ExcelValue current_value;
1352
+ ExcelValue **ranges = malloc(sizeof(ExcelValue *)*number_of_arguments);
1353
+ if(ranges == 0) {
1354
+ printf("Out of memory\n");
1355
+ exit(-1);
1356
+ }
1357
+ double product = 1;
1358
+ double sum = 0;
1359
+
1360
+ // Find out dimensions of first argument
1361
+ if(arguments[0].type == ExcelRange) {
1362
+ rows = arguments[0].rows;
1363
+ columns = arguments[0].columns;
1364
+ } else {
1365
+ rows = 1;
1366
+ columns = 1;
1367
+ }
1368
+ // Extract arrays from each of the given ranges, checking for errors and bounds as we go
1369
+ for(a=0;a<number_of_arguments;a++) {
1370
+ current_value = arguments[a];
1371
+ switch(current_value.type) {
1372
+ case ExcelRange:
1373
+ if(current_value.rows != rows || current_value.columns != columns) return VALUE;
1374
+ ranges[a] = current_value.array;
1375
+ break;
1376
+ case ExcelError:
1377
+ return current_value;
1378
+ break;
1379
+ case ExcelEmpty:
1380
+ return VALUE;
1381
+ break;
1382
+ default:
1383
+ if(rows != 1 && columns !=1) return VALUE;
1384
+ ranges[a] = (ExcelValue*) new_excel_value_array(1);
1385
+ ranges[a][0] = arguments[a];
1386
+ break;
1387
+ }
1388
+ }
1389
+
1390
+ for(i=0;i<rows;i++) {
1391
+ for(j=0;j<columns;j++) {
1392
+ product = 1;
1393
+ for(a=0;a<number_of_arguments;a++) {
1394
+ current_value = ranges[a][(i*columns)+j];
1395
+ if(current_value.type == ExcelNumber) {
1396
+ product *= current_value.number;
1397
+ } else {
1398
+ product *= 0;
1399
+ }
1400
+ }
1401
+ sum += product;
1402
+ }
1403
+ }
1404
+ return new_excel_number(sum);
1405
+ }
1406
+
1407
+ static ExcelValue vlookup_3(ExcelValue lookup_value_v,ExcelValue lookup_table_v, ExcelValue column_number_v) {
1408
+ return vlookup(lookup_value_v,lookup_table_v,column_number_v,TRUE);
1409
+ }
1410
+
1411
+ static ExcelValue vlookup(ExcelValue lookup_value_v,ExcelValue lookup_table_v, ExcelValue column_number_v, ExcelValue match_type_v) {
1412
+ CHECK_FOR_PASSED_ERROR(lookup_value_v)
1413
+ CHECK_FOR_PASSED_ERROR(lookup_table_v)
1414
+ CHECK_FOR_PASSED_ERROR(column_number_v)
1415
+ CHECK_FOR_PASSED_ERROR(match_type_v)
1416
+
1417
+ if(lookup_value_v.type == ExcelEmpty) return NA;
1418
+ if(lookup_table_v.type != ExcelRange) return NA;
1419
+ if(column_number_v.type != ExcelNumber) return NA;
1420
+ if(match_type_v.type != ExcelBoolean) return NA;
1421
+
1422
+ int i;
1423
+ int last_good_match = 0;
1424
+ int rows = lookup_table_v.rows;
1425
+ int columns = lookup_table_v.columns;
1426
+ ExcelValue *array = lookup_table_v.array;
1427
+ ExcelValue possible_match_v;
1428
+
1429
+ if(column_number_v.number > columns) return REF;
1430
+ if(column_number_v.number < 1) return VALUE;
1431
+
1432
+ if(match_type_v.number == false) { // Exact match required
1433
+ for(i=0; i< rows; i++) {
1434
+ possible_match_v = array[i*columns];
1435
+ if(excel_equal(lookup_value_v,possible_match_v).number == true) {
1436
+ return array[(i*columns)+(((int) column_number_v.number) - 1)];
1437
+ }
1438
+ }
1439
+ return NA;
1440
+ } else { // Highest value that is less than or equal
1441
+ for(i=0; i< rows; i++) {
1442
+ possible_match_v = array[i*columns];
1443
+ if(lookup_value_v.type != possible_match_v.type) continue;
1444
+ if(more_than(possible_match_v,lookup_value_v).number == true) {
1445
+ if(i == 0) return NA;
1446
+ return array[((i-1)*columns)+(((int) column_number_v.number) - 1)];
1447
+ } else {
1448
+ last_good_match = i;
1449
+ }
1450
+ }
1451
+ return array[(last_good_match*columns)+(((int) column_number_v.number) - 1)];
1452
+ }
1453
+ return NA;
1454
+ }
1455
+
1456
+
1457
+
1458
+ int test_functions() {
1459
+ // Test ABS
1460
+ assert(excel_abs(ONE).number == 1);
1461
+ assert(excel_abs(new_excel_number(-1)).number == 1);
1462
+ assert(excel_abs(VALUE).type == ExcelError);
1463
+
1464
+ // Test ADD
1465
+ assert(add(ONE,new_excel_number(-2.5)).number == -1.5);
1466
+ assert(add(ONE,VALUE).type == ExcelError);
1467
+
1468
+ // Test AND
1469
+ ExcelValue true_array1[] = { TRUE, new_excel_number(10)};
1470
+ ExcelValue true_array2[] = { ONE };
1471
+ ExcelValue false_array1[] = { FALSE, new_excel_number(10)};
1472
+ ExcelValue false_array2[] = { TRUE, new_excel_number(0)};
1473
+ // ExcelValue error_array1[] = { new_excel_number(10)}; // Not implemented
1474
+ ExcelValue error_array2[] = { TRUE, NA};
1475
+ assert(excel_and(2,true_array1).number == 1);
1476
+ assert(excel_and(1,true_array2).number == 1);
1477
+ assert(excel_and(2,false_array1).number == 0);
1478
+ assert(excel_and(2,false_array2).number == 0);
1479
+ // assert(excel_and(1,error_array1).type == ExcelError); // Not implemented
1480
+ assert(excel_and(2,error_array2).type == ExcelError);
1481
+
1482
+ // Test AVERAGE
1483
+ ExcelValue array1[] = { new_excel_number(10), new_excel_number(5), TRUE, FALSE};
1484
+ ExcelValue array1_v = new_excel_range(array1,2,2);
1485
+ ExcelValue array2[] = { array1_v, new_excel_number(9), new_excel_string("Hello")};
1486
+ ExcelValue array3[] = { array1_v, new_excel_number(9), new_excel_string("Hello"), VALUE};
1487
+ assert(average(4, array1).number == 7.5);
1488
+ assert(average(3, array2).number == 8);
1489
+ assert(average(4, array3).type == ExcelError);
1490
+
1491
+ // Test CHOOSE
1492
+ assert(choose(ONE,4,array1).number == 10);
1493
+ assert(choose(new_excel_number(4),4,array1).type == ExcelBoolean);
1494
+ assert(choose(new_excel_number(0),4,array1).type == ExcelError);
1495
+ assert(choose(new_excel_number(5),4,array1).type == ExcelError);
1496
+ assert(choose(ONE,4,array3).type == ExcelError);
1497
+
1498
+ // Test COUNT
1499
+ assert(count(4,array1).number == 2);
1500
+ assert(count(3,array2).number == 3);
1501
+ assert(count(4,array3).number == 3);
1502
+
1503
+ // Test COUNTA
1504
+ ExcelValue count_a_test_array_1[] = { new_excel_number(10), new_excel_number(5), TRUE, FALSE, new_excel_string("Hello"), VALUE, BLANK};
1505
+ ExcelValue count_a_test_array_1_v = new_excel_range(count_a_test_array_1,7,1);
1506
+ ExcelValue count_a_test_array_2[] = {new_excel_string("Bye"),count_a_test_array_1_v};
1507
+ assert(counta(7, count_a_test_array_1).number == 6);
1508
+ assert(counta(2, count_a_test_array_2).number == 7);
1509
+
1510
+ // Test divide
1511
+ assert(divide(new_excel_number(12.4),new_excel_number(3.2)).number == 3.875);
1512
+ assert(divide(new_excel_number(12.4),new_excel_number(0)).type == ExcelError);
1513
+
1514
+ // Test excel_equal
1515
+ assert(excel_equal(new_excel_number(1.2),new_excel_number(3.4)).type == ExcelBoolean);
1516
+ assert(excel_equal(new_excel_number(1.2),new_excel_number(3.4)).number == false);
1517
+ assert(excel_equal(new_excel_number(1.2),new_excel_number(1.2)).number == true);
1518
+ assert(excel_equal(new_excel_string("hello"), new_excel_string("HELLO")).number == true);
1519
+ assert(excel_equal(new_excel_string("hello world"), new_excel_string("HELLO")).number == false);
1520
+ assert(excel_equal(new_excel_string("1"), ONE).number == false);
1521
+ assert(excel_equal(DIV0, ONE).type == ExcelError);
1522
+
1523
+ // Test not_equal
1524
+ assert(not_equal(new_excel_number(1.2),new_excel_number(3.4)).type == ExcelBoolean);
1525
+ assert(not_equal(new_excel_number(1.2),new_excel_number(3.4)).number == true);
1526
+ assert(not_equal(new_excel_number(1.2),new_excel_number(1.2)).number == false);
1527
+ assert(not_equal(new_excel_string("hello"), new_excel_string("HELLO")).number == false);
1528
+ assert(not_equal(new_excel_string("hello world"), new_excel_string("HELLO")).number == true);
1529
+ assert(not_equal(new_excel_string("1"), ONE).number == true);
1530
+ assert(not_equal(DIV0, ONE).type == ExcelError);
1531
+
1532
+ // Test excel_if
1533
+ // Two argument version
1534
+ assert(excel_if_2(TRUE,new_excel_number(10)).type == ExcelNumber);
1535
+ assert(excel_if_2(TRUE,new_excel_number(10)).number == 10);
1536
+ assert(excel_if_2(FALSE,new_excel_number(10)).type == ExcelBoolean);
1537
+ assert(excel_if_2(FALSE,new_excel_number(10)).number == false);
1538
+ assert(excel_if_2(NA,new_excel_number(10)).type == ExcelError);
1539
+ // Three argument version
1540
+ assert(excel_if(TRUE,new_excel_number(10),new_excel_number(20)).type == ExcelNumber);
1541
+ assert(excel_if(TRUE,new_excel_number(10),new_excel_number(20)).number == 10);
1542
+ assert(excel_if(FALSE,new_excel_number(10),new_excel_number(20)).type == ExcelNumber);
1543
+ assert(excel_if(FALSE,new_excel_number(10),new_excel_number(20)).number == 20);
1544
+ assert(excel_if(NA,new_excel_number(10),new_excel_number(20)).type == ExcelError);
1545
+
1546
+ // Test excel_match
1547
+ ExcelValue excel_match_array_1[] = { new_excel_number(10), new_excel_number(100) };
1548
+ ExcelValue excel_match_array_1_v = new_excel_range(excel_match_array_1,1,2);
1549
+ ExcelValue excel_match_array_2[] = { new_excel_string("Pear"), new_excel_string("Bear"), new_excel_string("Apple") };
1550
+ ExcelValue excel_match_array_2_v = new_excel_range(excel_match_array_2,3,1);
1551
+ ExcelValue excel_match_array_4[] = { ONE, BLANK, new_excel_number(0) };
1552
+ ExcelValue excel_match_array_4_v = new_excel_range(excel_match_array_4,1,3);
1553
+ ExcelValue excel_match_array_5[] = { ONE, new_excel_number(0), BLANK };
1554
+ ExcelValue excel_match_array_5_v = new_excel_range(excel_match_array_5,1,3);
1555
+
1556
+ // Two argument version
1557
+ assert(excel_match_2(new_excel_number(10),excel_match_array_1_v).number == 1);
1558
+ assert(excel_match_2(new_excel_number(100),excel_match_array_1_v).number == 2);
1559
+ assert(excel_match_2(new_excel_number(1000),excel_match_array_1_v).type == ExcelError);
1560
+ assert(excel_match_2(new_excel_number(0), excel_match_array_4_v).number == 2);
1561
+ assert(excel_match_2(BLANK, excel_match_array_5_v).number == 2);
1562
+
1563
+ // Three argument version
1564
+ assert(excel_match(new_excel_number(10.0), excel_match_array_1_v, new_excel_number(0) ).number == 1);
1565
+ assert(excel_match(new_excel_number(100.0), excel_match_array_1_v, new_excel_number(0) ).number == 2);
1566
+ assert(excel_match(new_excel_number(1000.0), excel_match_array_1_v, new_excel_number(0) ).type == ExcelError);
1567
+ assert(excel_match(new_excel_string("bEAr"), excel_match_array_2_v, new_excel_number(0) ).number == 2);
1568
+ assert(excel_match(new_excel_number(1000.0), excel_match_array_1_v, ONE ).number == 2);
1569
+ assert(excel_match(new_excel_number(1.0), excel_match_array_1_v, ONE ).type == ExcelError);
1570
+ assert(excel_match(new_excel_string("Care"), excel_match_array_2_v, new_excel_number(-1) ).number == 1 );
1571
+ assert(excel_match(new_excel_string("Zebra"), excel_match_array_2_v, new_excel_number(-1) ).type == ExcelError);
1572
+ assert(excel_match(new_excel_string("a"), excel_match_array_2_v, new_excel_number(-1) ).number == 2);
1573
+
1574
+ // When not given a range
1575
+ assert(excel_match(new_excel_number(10.0), new_excel_number(10), new_excel_number(0.0)).number == 1);
1576
+ assert(excel_match(new_excel_number(20.0), new_excel_number(10), new_excel_number(0.0)).type == ExcelError);
1577
+ assert(excel_match(new_excel_number(10.0), excel_match_array_1_v, BLANK).number == 1);
1578
+
1579
+ // Test more than on
1580
+ // .. numbers
1581
+ assert(more_than(ONE,new_excel_number(2)).number == false);
1582
+ assert(more_than(ONE,ONE).number == false);
1583
+ assert(more_than(ONE,new_excel_number(0)).number == true);
1584
+ // .. booleans
1585
+ assert(more_than(FALSE,FALSE).number == false);
1586
+ assert(more_than(FALSE,TRUE).number == false);
1587
+ assert(more_than(TRUE,FALSE).number == true);
1588
+ assert(more_than(TRUE,TRUE).number == false);
1589
+ // ..strings
1590
+ assert(more_than(new_excel_string("HELLO"),new_excel_string("Ardvark")).number == true);
1591
+ assert(more_than(new_excel_string("HELLO"),new_excel_string("world")).number == false);
1592
+ assert(more_than(new_excel_string("HELLO"),new_excel_string("hello")).number == false);
1593
+ // ..blanks
1594
+ assert(more_than(BLANK,ONE).number == false);
1595
+ assert(more_than(BLANK,new_excel_number(-1)).number == true);
1596
+ assert(more_than(ONE,BLANK).number == true);
1597
+ assert(more_than(new_excel_number(-1),BLANK).number == false);
1598
+
1599
+ // Test less than on
1600
+ // .. numbers
1601
+ assert(less_than(ONE,new_excel_number(2)).number == true);
1602
+ assert(less_than(ONE,ONE).number == false);
1603
+ assert(less_than(ONE,new_excel_number(0)).number == false);
1604
+ // .. booleans
1605
+ assert(less_than(FALSE,FALSE).number == false);
1606
+ assert(less_than(FALSE,TRUE).number == true);
1607
+ assert(less_than(TRUE,FALSE).number == false);
1608
+ assert(less_than(TRUE,TRUE).number == false);
1609
+ // ..strings
1610
+ assert(less_than(new_excel_string("HELLO"),new_excel_string("Ardvark")).number == false);
1611
+ assert(less_than(new_excel_string("HELLO"),new_excel_string("world")).number == true);
1612
+ assert(less_than(new_excel_string("HELLO"),new_excel_string("hello")).number == false);
1613
+ // ..blanks
1614
+ assert(less_than(BLANK,ONE).number == true);
1615
+ assert(less_than(BLANK,new_excel_number(-1)).number == false);
1616
+ assert(less_than(ONE,BLANK).number == false);
1617
+ assert(less_than(new_excel_number(-1),BLANK).number == true);
1618
+
1619
+ // Test FIND function
1620
+ // ... should find the first occurrence of one string in another, returning :value if the string doesn't match
1621
+ assert(find_2(new_excel_string("one"),new_excel_string("onetwothree")).number == 1);
1622
+ assert(find_2(new_excel_string("one"),new_excel_string("twoonethree")).number == 4);
1623
+ assert(find_2(new_excel_string("one"),new_excel_string("twoonthree")).type == ExcelError);
1624
+ // ... should find the first occurrence of one string in another after a given index, returning :value if the string doesn't match
1625
+ assert(find(new_excel_string("one"),new_excel_string("onetwothree"),ONE).number == 1);
1626
+ assert(find(new_excel_string("one"),new_excel_string("twoonethree"),new_excel_number(5)).type == ExcelError);
1627
+ assert(find(new_excel_string("one"),new_excel_string("oneone"),new_excel_number(2)).number == 4);
1628
+ // ... should be possible for the start_num to be a string, if that string converts to a number
1629
+ assert(find(new_excel_string("one"),new_excel_string("oneone"),new_excel_string("2")).number == 4);
1630
+ // ... should return a :value error when given anything but a number as the third argument
1631
+ assert(find(new_excel_string("one"),new_excel_string("oneone"),new_excel_string("a")).type == ExcelError);
1632
+ // ... should return a :value error when given a third argument that is less than 1 or greater than the length of the string
1633
+ assert(find(new_excel_string("one"),new_excel_string("oneone"),new_excel_number(0)).type == ExcelError);
1634
+ assert(find(new_excel_string("one"),new_excel_string("oneone"),new_excel_number(-1)).type == ExcelError);
1635
+ assert(find(new_excel_string("one"),new_excel_string("oneone"),new_excel_number(7)).type == ExcelError);
1636
+ // ... BLANK in the first argument matches any character
1637
+ assert(find_2(BLANK,new_excel_string("abcdefg")).number == 1);
1638
+ assert(find(BLANK,new_excel_string("abcdefg"),new_excel_number(4)).number == 4);
1639
+ // ... should treat BLANK in the second argument as an empty string
1640
+ assert(find_2(BLANK,BLANK).number == 1);
1641
+ assert(find_2(new_excel_string("a"),BLANK).type == ExcelError);
1642
+ // ... should return an error if any argument is an error
1643
+ assert(find(new_excel_string("one"),new_excel_string("onetwothree"),NA).type == ExcelError);
1644
+ assert(find(new_excel_string("one"),NA,ONE).type == ExcelError);
1645
+ assert(find(NA,new_excel_string("onetwothree"),ONE).type == ExcelError);
1646
+
1647
+ // Test the IFERROR function
1648
+ assert(iferror(new_excel_string("ok"),ONE).type == ExcelString);
1649
+ assert(iferror(VALUE,ONE).type == ExcelNumber);
1650
+
1651
+ // Test the INDEX function
1652
+ ExcelValue index_array_1[] = { new_excel_number(10), new_excel_number(20), BLANK };
1653
+ ExcelValue index_array_1_v_column = new_excel_range(index_array_1,3,1);
1654
+ ExcelValue index_array_1_v_row = new_excel_range(index_array_1,1,3);
1655
+ ExcelValue index_array_2[] = { BLANK, ONE, new_excel_number(10), new_excel_number(11), new_excel_number(100), new_excel_number(101) };
1656
+ ExcelValue index_array_2_v = new_excel_range(index_array_2,3,2);
1657
+ // ... if given one argument should return the value at that offset in the range
1658
+ assert(excel_index_2(index_array_1_v_column,new_excel_number(2.0)).number == 20);
1659
+ assert(excel_index_2(index_array_1_v_row,new_excel_number(2.0)).number == 20);
1660
+ // ... but not if the range is not a single row or single column
1661
+ assert(excel_index_2(index_array_2_v,new_excel_number(2.0)).type == ExcelError);
1662
+ // ... it should return the value in the array at position row_number, column_number
1663
+ assert(excel_index(new_excel_number(10),ONE,ONE).number == 10);
1664
+ assert(excel_index(index_array_2_v,new_excel_number(1.0),new_excel_number(2.0)).number == 1);
1665
+ assert(excel_index(index_array_2_v,new_excel_number(2.0),new_excel_number(1.0)).number == 10);
1666
+ assert(excel_index(index_array_2_v,new_excel_number(3.0),new_excel_number(1.0)).number == 100);
1667
+ assert(excel_index(index_array_2_v,new_excel_number(3.0),new_excel_number(3.0)).type == ExcelError);
1668
+ // ... it should return ZERO not blank, if a blank cell is picked
1669
+ assert(excel_index(index_array_2_v,new_excel_number(1.0),new_excel_number(1.0)).type == ExcelNumber);
1670
+ assert(excel_index(index_array_2_v,new_excel_number(1.0),new_excel_number(1.0)).number == 0);
1671
+ assert(excel_index_2(index_array_1_v_row,new_excel_number(3.0)).type == ExcelNumber);
1672
+ assert(excel_index_2(index_array_1_v_row,new_excel_number(3.0)).number == 0);
1673
+ // ... it should return the whole row if given a zero column number
1674
+ ExcelValue index_result_1_v = excel_index(index_array_2_v,new_excel_number(1.0),new_excel_number(0.0));
1675
+ assert(index_result_1_v.type == ExcelRange);
1676
+ assert(index_result_1_v.rows == 1);
1677
+ assert(index_result_1_v.columns == 2);
1678
+ ExcelValue *index_result_1_a = index_result_1_v.array;
1679
+ assert(index_result_1_a[0].number == 0);
1680
+ assert(index_result_1_a[1].number == 1);
1681
+ // ... it should return the whole column if given a zero row number
1682
+ ExcelValue index_result_2_v = excel_index(index_array_2_v,new_excel_number(0),new_excel_number(1.0));
1683
+ assert(index_result_2_v.type == ExcelRange);
1684
+ assert(index_result_2_v.rows == 3);
1685
+ assert(index_result_2_v.columns == 1);
1686
+ ExcelValue *index_result_2_a = index_result_2_v.array;
1687
+ assert(index_result_2_a[0].number == 0);
1688
+ assert(index_result_2_a[1].number == 10);
1689
+ assert(index_result_2_a[2].number == 100);
1690
+ // ... it should return a :ref error when given arguments outside array range
1691
+ assert(excel_index_2(index_array_1_v_row,new_excel_number(-1)).type == ExcelError);
1692
+ assert(excel_index_2(index_array_1_v_row,new_excel_number(4)).type == ExcelError);
1693
+ // ... it should treat BLANK as zero if given as a required row or column number
1694
+ assert(excel_index(index_array_2_v,new_excel_number(1.0),BLANK).type == ExcelRange);
1695
+ assert(excel_index(index_array_2_v,BLANK,new_excel_number(2.0)).type == ExcelRange);
1696
+ // ... it should return an error if an argument is an error
1697
+ assert(excel_index(NA,NA,NA).type == ExcelError);
1698
+
1699
+ // LEFT(string,[characters])
1700
+ // ... should return the left n characters from a string
1701
+ assert(strcmp(left_1(new_excel_string("ONE")).string,"O") == 0);
1702
+ assert(strcmp(left(new_excel_string("ONE"),ONE).string,"O") == 0);
1703
+ assert(strcmp(left(new_excel_string("ONE"),new_excel_number(3)).string,"ONE") == 0);
1704
+ // ... should turn numbers into strings before processing
1705
+ assert(strcmp(left(new_excel_number(1.31e12),new_excel_number(3)).string, "131") == 0);
1706
+ // ... should turn booleans into the words TRUE and FALSE before processing
1707
+ assert(strcmp(left(TRUE,new_excel_number(3)).string,"TRU") == 0);
1708
+ assert(strcmp(left(FALSE,new_excel_number(3)).string,"FAL") == 0);
1709
+ // ... should return BLANK if given BLANK for either argument
1710
+ assert(left(BLANK,new_excel_number(3)).type == ExcelEmpty);
1711
+ assert(left(new_excel_string("ONE"),BLANK).type == ExcelEmpty);
1712
+ // ... should return an error if an argument is an error
1713
+ assert(left_1(NA).type == ExcelError);
1714
+ assert(left(new_excel_string("ONE"),NA).type == ExcelError);
1715
+
1716
+ // Test less than or equal to
1717
+ // .. numbers
1718
+ assert(less_than_or_equal(ONE,new_excel_number(2)).number == true);
1719
+ assert(less_than_or_equal(ONE,ONE).number == true);
1720
+ assert(less_than_or_equal(ONE,new_excel_number(0)).number == false);
1721
+ // .. booleans
1722
+ assert(less_than_or_equal(FALSE,FALSE).number == true);
1723
+ assert(less_than_or_equal(FALSE,TRUE).number == true);
1724
+ assert(less_than_or_equal(TRUE,FALSE).number == false);
1725
+ assert(less_than_or_equal(TRUE,TRUE).number == true);
1726
+ // ..strings
1727
+ assert(less_than_or_equal(new_excel_string("HELLO"),new_excel_string("Ardvark")).number == false);
1728
+ assert(less_than_or_equal(new_excel_string("HELLO"),new_excel_string("world")).number == true);
1729
+ assert(less_than_or_equal(new_excel_string("HELLO"),new_excel_string("hello")).number == true);
1730
+ // ..blanks
1731
+ assert(less_than_or_equal(BLANK,ONE).number == true);
1732
+ assert(less_than_or_equal(BLANK,new_excel_number(-1)).number == false);
1733
+ assert(less_than_or_equal(ONE,BLANK).number == false);
1734
+ assert(less_than_or_equal(new_excel_number(-1),BLANK).number == true);
1735
+
1736
+ // Test MAX
1737
+ assert(max(4, array1).number == 10);
1738
+ assert(max(3, array2).number == 10);
1739
+ assert(max(4, array3).type == ExcelError);
1740
+
1741
+ // Test MIN
1742
+ assert(min(4, array1).number == 5);
1743
+ assert(min(3, array2).number == 5);
1744
+ assert(min(4, array3).type == ExcelError);
1745
+
1746
+ // Test MOD
1747
+ // ... should return the remainder of a number
1748
+ assert(mod(new_excel_number(10), new_excel_number(3)).number == 1.0);
1749
+ assert(mod(new_excel_number(10), new_excel_number(5)).number == 0.0);
1750
+ // ... should be possible for the the arguments to be strings, if they convert to a number
1751
+ assert(mod(new_excel_string("3.5"),new_excel_string("2")).number == 1.5);
1752
+ // ... should treat BLANK as zero
1753
+ assert(mod(BLANK,new_excel_number(10)).number == 0);
1754
+ assert(mod(new_excel_number(10),BLANK).type == ExcelError);
1755
+ assert(mod(BLANK,BLANK).type == ExcelError);
1756
+ // ... should treat true as 1 and FALSE as 0
1757
+ assert((mod(new_excel_number(1.1),TRUE).number - 0.1) < 0.001);
1758
+ assert(mod(new_excel_number(1.1),FALSE).type == ExcelError);
1759
+ assert(mod(FALSE,new_excel_number(10)).number == 0);
1760
+ // ... should return an error when given inappropriate arguments
1761
+ assert(mod(new_excel_string("Asdasddf"),new_excel_string("adsfads")).type == ExcelError);
1762
+ // ... should return an error if an argument is an error
1763
+ assert(mod(new_excel_number(1),VALUE).type == ExcelError);
1764
+ assert(mod(VALUE,new_excel_number(1)).type == ExcelError);
1765
+ assert(mod(VALUE,VALUE).type == ExcelError);
1766
+
1767
+ // Test more than or equal to on
1768
+ // .. numbers
1769
+ assert(more_than_or_equal(ONE,new_excel_number(2)).number == false);
1770
+ assert(more_than_or_equal(ONE,ONE).number == true);
1771
+ assert(more_than_or_equal(ONE,new_excel_number(0)).number == true);
1772
+ // .. booleans
1773
+ assert(more_than_or_equal(FALSE,FALSE).number == true);
1774
+ assert(more_than_or_equal(FALSE,TRUE).number == false);
1775
+ assert(more_than_or_equal(TRUE,FALSE).number == true);
1776
+ assert(more_than_or_equal(TRUE,TRUE).number == true);
1777
+ // ..strings
1778
+ assert(more_than_or_equal(new_excel_string("HELLO"),new_excel_string("Ardvark")).number == true);
1779
+ assert(more_than_or_equal(new_excel_string("HELLO"),new_excel_string("world")).number == false);
1780
+ assert(more_than_or_equal(new_excel_string("HELLO"),new_excel_string("hello")).number == true);
1781
+ // ..blanks
1782
+ assert(more_than_or_equal(BLANK,BLANK).number == true);
1783
+ assert(more_than_or_equal(BLANK,ONE).number == false);
1784
+ assert(more_than_or_equal(BLANK,new_excel_number(-1)).number == true);
1785
+ assert(more_than_or_equal(ONE,BLANK).number == true);
1786
+ assert(more_than_or_equal(new_excel_number(-1),BLANK).number == false);
1787
+
1788
+ // Test negative
1789
+ // ... should return the negative of its arguments
1790
+ assert(negative(new_excel_number(1)).number == -1);
1791
+ assert(negative(new_excel_number(-1)).number == 1);
1792
+ // ... should treat strings that only contain numbers as numbers
1793
+ assert(negative(new_excel_string("10")).number == -10);
1794
+ assert(negative(new_excel_string("-1.3")).number == 1.3);
1795
+ // ... should return an error when given inappropriate arguments
1796
+ assert(negative(new_excel_string("Asdasddf")).type == ExcelError);
1797
+ // ... should treat BLANK as zero
1798
+ assert(negative(BLANK).number == 0);
1799
+
1800
+ // Test PMT(rate,number_of_periods,present_value) - optional arguments not yet implemented
1801
+ // ... should calculate the monthly payment required for a given principal, interest rate and loan period
1802
+ assert((pmt(new_excel_number(0.1),new_excel_number(10),new_excel_number(100)).number - -16.27) < 0.01);
1803
+ assert((pmt(new_excel_number(0.0123),new_excel_number(99.1),new_excel_number(123.32)).number - -2.159) < 0.01);
1804
+ assert((pmt(new_excel_number(0),new_excel_number(2),new_excel_number(10)).number - -5) < 0.01);
1805
+
1806
+ // Test power
1807
+ // ... should return sum of its arguments
1808
+ assert(power(new_excel_number(2),new_excel_number(3)).number == 8);
1809
+ assert(power(new_excel_number(4.0),new_excel_number(0.5)).number == 2.0);
1810
+
1811
+ // Test round
1812
+ assert(excel_round(new_excel_number(1.1), new_excel_number(0)).number == 1.0);
1813
+ assert(excel_round(new_excel_number(1.5), new_excel_number(0)).number == 2.0);
1814
+ assert(excel_round(new_excel_number(1.56),new_excel_number(1)).number == 1.6);
1815
+ assert(excel_round(new_excel_number(-1.56),new_excel_number(1)).number == -1.6);
1816
+
1817
+ // Test rounddown
1818
+ assert(rounddown(new_excel_number(1.1), new_excel_number(0)).number == 1.0);
1819
+ assert(rounddown(new_excel_number(1.5), new_excel_number(0)).number == 1.0);
1820
+ assert(rounddown(new_excel_number(1.56),new_excel_number(1)).number == 1.5);
1821
+ assert(rounddown(new_excel_number(-1.56),new_excel_number(1)).number == -1.5);
1822
+
1823
+ // Test roundup
1824
+ assert(roundup(new_excel_number(1.1), new_excel_number(0)).number == 2.0);
1825
+ assert(roundup(new_excel_number(1.5), new_excel_number(0)).number == 2.0);
1826
+ assert(roundup(new_excel_number(1.56),new_excel_number(1)).number == 1.6);
1827
+ assert(roundup(new_excel_number(-1.56),new_excel_number(1)).number == -1.6);
1828
+
1829
+ // Test string joining
1830
+ ExcelValue string_join_array_1[] = {new_excel_string("Hello "), new_excel_string("world")};
1831
+ ExcelValue string_join_array_2[] = {new_excel_string("Hello "), new_excel_string("world"), new_excel_string("!")};
1832
+ ExcelValue string_join_array_3[] = {new_excel_string("Top "), new_excel_number(10.0)};
1833
+ ExcelValue string_join_array_4[] = {new_excel_string("Top "), new_excel_number(10.5)};
1834
+ ExcelValue string_join_array_5[] = {new_excel_string("Top "), TRUE, FALSE};
1835
+ // ... should return a string by combining its arguments
1836
+ // inspect_excel_value(string_join(2, string_join_array_1));
1837
+ assert(string_join(2, string_join_array_1).string[6] == 'w');
1838
+ // ... should cope with an arbitrary number of arguments
1839
+ assert(string_join(3, string_join_array_2).string[11] == '!');
1840
+ // ... should convert values to strings as it goes
1841
+ assert(string_join(2, string_join_array_3).string[4] == '1');
1842
+ // ... should convert integer values into strings without decimal points
1843
+ assert(string_join(2, string_join_array_3).string[7] == '\0');
1844
+ assert(string_join(2, string_join_array_4).string[7] == '5');
1845
+ // ... should convert TRUE and FALSE into strings
1846
+ assert(string_join(3,string_join_array_5).string[4] == 'T');
1847
+
1848
+ // Test SUBTOTAL function
1849
+ ExcelValue subtotal_array_1[] = {new_excel_number(10),new_excel_number(100),BLANK};
1850
+ ExcelValue subtotal_array_1_v = new_excel_range(subtotal_array_1,3,1);
1851
+ ExcelValue subtotal_array_2[] = {new_excel_number(1),new_excel_string("two"),subtotal_array_1_v};
1852
+
1853
+ assert(subtotal(new_excel_number(1.0),3,subtotal_array_2).number == 111.0/3.0);
1854
+ assert(subtotal(new_excel_number(2.0),3,subtotal_array_2).number == 3);
1855
+ assert(subtotal(new_excel_number(3.0),7, count_a_test_array_1).number == 6);
1856
+ assert(subtotal(new_excel_number(3.0),3,subtotal_array_2).number == 4);
1857
+ assert(subtotal(new_excel_number(9.0),3,subtotal_array_2).number == 111);
1858
+ assert(subtotal(new_excel_number(101.0),3,subtotal_array_2).number == 111.0/3.0);
1859
+ assert(subtotal(new_excel_number(102.0),3,subtotal_array_2).number == 3);
1860
+ assert(subtotal(new_excel_number(103.0),3,subtotal_array_2).number == 4);
1861
+ assert(subtotal(new_excel_number(109.0),3,subtotal_array_2).number == 111);
1862
+
1863
+ // Test SUMIFS function
1864
+ ExcelValue sumifs_array_1[] = {new_excel_number(10),new_excel_number(100),BLANK};
1865
+ ExcelValue sumifs_array_1_v = new_excel_range(sumifs_array_1,3,1);
1866
+ ExcelValue sumifs_array_2[] = {new_excel_string("pear"),new_excel_string("bear"),new_excel_string("apple")};
1867
+ ExcelValue sumifs_array_2_v = new_excel_range(sumifs_array_2,3,1);
1868
+ ExcelValue sumifs_array_3[] = {new_excel_number(1),new_excel_number(2),new_excel_number(3),new_excel_number(4),new_excel_number(5),new_excel_number(5)};
1869
+ ExcelValue sumifs_array_3_v = new_excel_range(sumifs_array_3,6,1);
1870
+ ExcelValue sumifs_array_4[] = {new_excel_string("CO2"),new_excel_string("CH4"),new_excel_string("N2O"),new_excel_string("CH4"),new_excel_string("N2O"),new_excel_string("CO2")};
1871
+ ExcelValue sumifs_array_4_v = new_excel_range(sumifs_array_4,6,1);
1872
+ ExcelValue sumifs_array_5[] = {new_excel_string("1A"),new_excel_string("1A"),new_excel_string("1A"),new_excel_number(4),new_excel_number(4),new_excel_number(5)};
1873
+ ExcelValue sumifs_array_5_v = new_excel_range(sumifs_array_5,6,1);
1874
+
1875
+ // ... should only sum values that meet all of the criteria
1876
+ ExcelValue sumifs_array_6[] = { sumifs_array_1_v, new_excel_number(10), sumifs_array_2_v, new_excel_string("Bear") };
1877
+ assert(sumifs(sumifs_array_1_v,4,sumifs_array_6).number == 0.0);
1878
+
1879
+ ExcelValue sumifs_array_7[] = { sumifs_array_1_v, new_excel_number(10), sumifs_array_2_v, new_excel_string("Pear") };
1880
+ assert(sumifs(sumifs_array_1_v,4,sumifs_array_7).number == 10.0);
1881
+
1882
+ // ... should work when single cells are given where ranges expected
1883
+ ExcelValue sumifs_array_8[] = { new_excel_string("CAR"), new_excel_string("CAR"), new_excel_string("FCV"), new_excel_string("FCV")};
1884
+ assert(sumifs(new_excel_number(0.143897265452564), 4, sumifs_array_8).number == 0.143897265452564);
1885
+
1886
+ // ... should match numbers with strings that contain numbers
1887
+ ExcelValue sumifs_array_9[] = { new_excel_number(10), new_excel_string("10.0")};
1888
+ assert(sumifs(new_excel_number(100),2,sumifs_array_9).number == 100);
1889
+
1890
+ ExcelValue sumifs_array_10[] = { sumifs_array_4_v, new_excel_string("CO2"), sumifs_array_5_v, new_excel_number(2)};
1891
+ assert(sumifs(sumifs_array_3_v,4, sumifs_array_10).number == 0);
1892
+
1893
+ // ... should match with strings that contain criteria
1894
+ ExcelValue sumifs_array_10a[] = { sumifs_array_3_v, new_excel_string("=5")};
1895
+ assert(sumifs(sumifs_array_3_v,2, sumifs_array_10a).number == 10);
1896
+
1897
+ ExcelValue sumifs_array_10b[] = { sumifs_array_3_v, new_excel_string("<>3")};
1898
+ assert(sumifs(sumifs_array_3_v,2, sumifs_array_10b).number == 17);
1899
+
1900
+ ExcelValue sumifs_array_10c[] = { sumifs_array_3_v, new_excel_string("<3")};
1901
+ assert(sumifs(sumifs_array_3_v,2, sumifs_array_10c).number == 3);
1902
+
1903
+ ExcelValue sumifs_array_10d[] = { sumifs_array_3_v, new_excel_string("<=3")};
1904
+ assert(sumifs(sumifs_array_3_v,2, sumifs_array_10d).number == 6);
1905
+
1906
+ ExcelValue sumifs_array_10e[] = { sumifs_array_3_v, new_excel_string(">3")};
1907
+ assert(sumifs(sumifs_array_3_v,2, sumifs_array_10e).number == 14);
1908
+
1909
+ ExcelValue sumifs_array_10f[] = { sumifs_array_3_v, new_excel_string(">=3")};
1910
+ assert(sumifs(sumifs_array_3_v,2, sumifs_array_10f).number == 17);
1911
+
1912
+ // ... should treat BLANK as an empty string when in the check_range, but not in the criteria
1913
+ ExcelValue sumifs_array_11[] = { BLANK, new_excel_number(20)};
1914
+ assert(sumifs(new_excel_number(100),2,sumifs_array_11).number == 0);
1915
+
1916
+ ExcelValue sumifs_array_12[] = {BLANK, new_excel_string("")};
1917
+ assert(sumifs(new_excel_number(100),2,sumifs_array_12).number == 100);
1918
+
1919
+ ExcelValue sumifs_array_13[] = {BLANK, BLANK};
1920
+ assert(sumifs(new_excel_number(100),2,sumifs_array_13).number == 0);
1921
+
1922
+ // ... should return an error if range argument is an error
1923
+ assert(sumifs(REF,2,sumifs_array_13).type == ExcelError);
1924
+
1925
+
1926
+ // Test SUMIF
1927
+ // ... where there is only a check range
1928
+ assert(sumif_2(sumifs_array_1_v,new_excel_string(">0")).number == 110.0);
1929
+ assert(sumif_2(sumifs_array_1_v,new_excel_string(">10")).number == 100.0);
1930
+ assert(sumif_2(sumifs_array_1_v,new_excel_string("<100")).number == 10.0);
1931
+
1932
+ // ... where there is a seprate sum range
1933
+ ExcelValue sumif_array_1[] = {new_excel_number(15),new_excel_number(20), new_excel_number(30)};
1934
+ ExcelValue sumif_array_1_v = new_excel_range(sumif_array_1,3,1);
1935
+ assert(sumif(sumifs_array_1_v,new_excel_string("10"),sumif_array_1_v).number == 15);
1936
+
1937
+
1938
+ // Test SUMPRODUCT
1939
+ ExcelValue sumproduct_1[] = { new_excel_number(10), new_excel_number(100), BLANK};
1940
+ ExcelValue sumproduct_2[] = { BLANK, new_excel_number(100), new_excel_number(10), BLANK};
1941
+ ExcelValue sumproduct_3[] = { BLANK };
1942
+ ExcelValue sumproduct_4[] = { new_excel_number(10), new_excel_number(100), new_excel_number(1000)};
1943
+ ExcelValue sumproduct_5[] = { new_excel_number(1), new_excel_number(2), new_excel_number(3)};
1944
+ ExcelValue sumproduct_6[] = { new_excel_number(1), new_excel_number(2), new_excel_number(4), new_excel_number(5)};
1945
+ ExcelValue sumproduct_7[] = { new_excel_number(10), new_excel_number(20), new_excel_number(40), new_excel_number(50)};
1946
+ ExcelValue sumproduct_8[] = { new_excel_number(11), new_excel_number(21), new_excel_number(41), new_excel_number(51)};
1947
+ ExcelValue sumproduct_9[] = { BLANK, BLANK };
1948
+
1949
+ ExcelValue sumproduct_1_v = new_excel_range( sumproduct_1, 3, 1);
1950
+ ExcelValue sumproduct_2_v = new_excel_range( sumproduct_2, 3, 1);
1951
+ ExcelValue sumproduct_3_v = new_excel_range( sumproduct_3, 1, 1);
1952
+ // ExcelValue sumproduct_4_v = new_excel_range( sumproduct_4, 1, 3); // Unused
1953
+ ExcelValue sumproduct_5_v = new_excel_range( sumproduct_5, 3, 1);
1954
+ ExcelValue sumproduct_6_v = new_excel_range( sumproduct_6, 2, 2);
1955
+ ExcelValue sumproduct_7_v = new_excel_range( sumproduct_7, 2, 2);
1956
+ ExcelValue sumproduct_8_v = new_excel_range( sumproduct_8, 2, 2);
1957
+ ExcelValue sumproduct_9_v = new_excel_range( sumproduct_9, 2, 1);
1958
+
1959
+ // ... should multiply together and then sum the elements in row or column areas given as arguments
1960
+ ExcelValue sumproducta_1[] = {sumproduct_1_v, sumproduct_2_v};
1961
+ assert(sumproduct(2,sumproducta_1).number == 100*100);
1962
+
1963
+ // ... should return :value when miss-matched array sizes
1964
+ ExcelValue sumproducta_2[] = {sumproduct_1_v, sumproduct_3_v};
1965
+ assert(sumproduct(2,sumproducta_2).type == ExcelError);
1966
+
1967
+ // ... if all its arguments are single values, should multiply them together
1968
+ // ExcelValue *sumproducta_3 = sumproduct_4;
1969
+ assert(sumproduct(3,sumproduct_4).number == 10*100*1000);
1970
+
1971
+ // ... if it only has one range as an argument, should add its elements together
1972
+ ExcelValue sumproducta_4[] = {sumproduct_5_v};
1973
+ assert(sumproduct(1,sumproducta_4).number == 1 + 2 + 3);
1974
+
1975
+ // ... if given multi row and column areas as arguments, should multipy the corresponding cell in each area and then add them all
1976
+ ExcelValue sumproducta_5[] = {sumproduct_6_v, sumproduct_7_v, sumproduct_8_v};
1977
+ assert(sumproduct(3,sumproducta_5).number == 1*10*11 + 2*20*21 + 4*40*41 + 5*50*51);
1978
+
1979
+ // ... should raise an error if BLANK values outside of an array
1980
+ ExcelValue sumproducta_6[] = {BLANK,new_excel_number(1)};
1981
+ assert(sumproduct(2,sumproducta_6).type == ExcelError);
1982
+
1983
+ // ... should ignore non-numeric values within an array
1984
+ ExcelValue sumproducta_7[] = {sumproduct_9_v, sumproduct_9_v};
1985
+ assert(sumproduct(2,sumproducta_7).number == 0);
1986
+
1987
+ // ... should return an error if an argument is an error
1988
+ ExcelValue sumproducta_8[] = {VALUE};
1989
+ assert(sumproduct(1,sumproducta_8).type == ExcelError);
1990
+
1991
+ // Test VLOOKUP
1992
+ ExcelValue vlookup_a1[] = {new_excel_number(1),new_excel_number(10),new_excel_number(2),new_excel_number(20),new_excel_number(3),new_excel_number(30)};
1993
+ ExcelValue vlookup_a2[] = {new_excel_string("hello"),new_excel_number(10),new_excel_number(2),new_excel_number(20),new_excel_number(3),new_excel_number(30)};
1994
+ ExcelValue vlookup_a3[] = {BLANK,new_excel_number(10),new_excel_number(2),new_excel_number(20),new_excel_number(3),new_excel_number(30)};
1995
+ ExcelValue vlookup_a1_v = new_excel_range(vlookup_a1,3,2);
1996
+ ExcelValue vlookup_a2_v = new_excel_range(vlookup_a2,3,2);
1997
+ ExcelValue vlookup_a3_v = new_excel_range(vlookup_a3,3,2);
1998
+ // ... should match the first argument against the first column of the table in the second argument, returning the value in the column specified by the third argument
1999
+ assert(vlookup_3(new_excel_number(2.0),vlookup_a1_v,new_excel_number(2)).number == 20);
2000
+ assert(vlookup_3(new_excel_number(1.5),vlookup_a1_v,new_excel_number(2)).number == 10);
2001
+ assert(vlookup_3(new_excel_number(0.5),vlookup_a1_v,new_excel_number(2)).type == ExcelError);
2002
+ assert(vlookup_3(new_excel_number(10),vlookup_a1_v,new_excel_number(2)).number == 30);
2003
+ assert(vlookup_3(new_excel_number(2.6),vlookup_a1_v,new_excel_number(2)).number == 20);
2004
+ // ... has a four argument variant that matches the lookup type
2005
+ assert(vlookup(new_excel_number(2.6),vlookup_a1_v,new_excel_number(2),TRUE).number == 20);
2006
+ assert(vlookup(new_excel_number(2.6),vlookup_a1_v,new_excel_number(2),FALSE).type == ExcelError);
2007
+ assert(vlookup(new_excel_string("HELLO"),vlookup_a2_v,new_excel_number(2),FALSE).number == 10);
2008
+ assert(vlookup(new_excel_string("HELMP"),vlookup_a2_v,new_excel_number(2),TRUE).number == 10);
2009
+ // ... BLANK should not match with anything" do
2010
+ assert(vlookup_3(BLANK,vlookup_a3_v,new_excel_number(2)).type == ExcelError);
2011
+ // ... should return an error if an argument is an error" do
2012
+ assert(vlookup(VALUE,vlookup_a1_v,new_excel_number(2),FALSE).type == ExcelError);
2013
+ assert(vlookup(new_excel_number(2.0),VALUE,new_excel_number(2),FALSE).type == ExcelError);
2014
+ assert(vlookup(new_excel_number(2.0),vlookup_a1_v,VALUE,FALSE).type == ExcelError);
2015
+ assert(vlookup(new_excel_number(2.0),vlookup_a1_v,new_excel_number(2),VALUE).type == ExcelError);
2016
+ assert(vlookup(VALUE,VALUE,VALUE,VALUE).type == ExcelError);
2017
+
2018
+ // Test SUM
2019
+ ExcelValue sum_array_0[] = {new_excel_number(1084.4557258064517),new_excel_number(32.0516914516129),new_excel_number(137.36439193548387)};
2020
+ ExcelValue sum_array_0_v = new_excel_range(sum_array_0,3,1);
2021
+ ExcelValue sum_array_1[] = {sum_array_0_v};
2022
+ assert(sum(1,sum_array_1).number == 1253.8718091935484);
2023
+
2024
+ return 0;
2025
+ }
2026
+
2027
+ int main() {
2028
+ return test_functions();
2029
+ }