excel_to_code 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }