excel_to_code 0.3.4 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/excel_to_c +4 -0
- data/src/commands/excel_to_c.rb +30 -5
- data/src/commands/excel_to_ruby.rb +1 -1
- data/src/commands/excel_to_x.rb +9 -0
- data/src/compile/c/a.out +0 -0
- data/src/compile/c/a.out.dSYM/Contents/Info.plist +20 -0
- data/src/compile/c/a.out.dSYM/Contents/Resources/DWARF/a.out +0 -0
- data/src/compile/c/compile_to_c_unit_test.rb +17 -3
- data/src/compile/c/excel_to_c_runtime.c +216 -170
- data/src/compile/c/excel_to_c_runtime_test.c +471 -451
- data/src/compile/c/map_formulae_to_c.rb +1 -1
- data/src/compile/c/map_values_to_c.rb +3 -3
- data/src/excel/excel_functions/right.rb +1 -0
- data/src/excel_to_code.rb +1 -1
- data/src/simplify/replace_values_with_constants.rb +0 -24
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b7eaef5e426ea529d3b33d237e2d41adc37c305
|
4
|
+
data.tar.gz: ac576e8a20ca8bc58f9839c1018f45210cc9d0a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: adb264736922ee868d1890cc9c390e8d34e29e4f31aa6be954a3980f49f5d9a02510d609ab1e72436be78ec6ad79359b0d5868d0e202e8732ffa837f535557be
|
7
|
+
data.tar.gz: 4ce4a712b27076f76ae665dd158e0b7153ebdfea42643a8f8568bf4c8eeb58f0c7c7e6d84c4a33a13580f1a0781072f1bdff03a0406386998f304f6218f2c994
|
data/bin/excel_to_c
CHANGED
data/src/commands/excel_to_c.rb
CHANGED
@@ -8,11 +8,14 @@ class ExcelToC < ExcelToX
|
|
8
8
|
attr_accessor :create_rakefile
|
9
9
|
# If true, creates a Makefile, if false, doesn't (default false)
|
10
10
|
attr_accessor :create_makefile
|
11
|
+
# If true, writes tests in C rather than in ruby
|
12
|
+
attr_accessor :write_tests_in_c
|
11
13
|
|
12
14
|
def set_defaults
|
13
15
|
super
|
14
16
|
@create_rakefile = true if @create_rakefile == nil
|
15
17
|
@create_makefile = false if @create_makefile == nil
|
18
|
+
@write_tests_in_c = false if @write_tests_in_c == nil
|
16
19
|
end
|
17
20
|
|
18
21
|
def language
|
@@ -24,7 +27,10 @@ class ExcelToC < ExcelToX
|
|
24
27
|
write_out_excel_as_code
|
25
28
|
write_build_script
|
26
29
|
write_fuby_ffi_interface
|
27
|
-
|
30
|
+
if write_tests_in_c
|
31
|
+
write_tests_as_c
|
32
|
+
end
|
33
|
+
write_tests_as_ruby
|
28
34
|
end
|
29
35
|
|
30
36
|
def write_out_excel_as_code
|
@@ -352,8 +358,8 @@ END
|
|
352
358
|
close(o)
|
353
359
|
end
|
354
360
|
|
355
|
-
def
|
356
|
-
log.info "Writing tests"
|
361
|
+
def write_tests_as_ruby
|
362
|
+
log.info "Writing tests in ruby"
|
357
363
|
|
358
364
|
name = output_name.downcase
|
359
365
|
o = output("test_#{name}.rb")
|
@@ -370,11 +376,27 @@ END
|
|
370
376
|
o.puts " def worksheet; @worksheet ||= init_spreadsheet; end"
|
371
377
|
o.puts " def init_spreadsheet; #{ruby_module_name}.new end"
|
372
378
|
|
373
|
-
|
379
|
+
CompileToRubyUnitTest.rewrite(Hash[@references_to_test_array], sloppy_tests, @worksheet_c_names, @constants, o)
|
374
380
|
o.puts "end"
|
375
381
|
close(o)
|
376
382
|
end
|
377
383
|
|
384
|
+
def write_tests_as_c
|
385
|
+
log.info "Writing tests in C"
|
386
|
+
|
387
|
+
name = output_name.downcase
|
388
|
+
o = output("test_#{name}.c")
|
389
|
+
o.puts "#include \"#{name}.c\""
|
390
|
+
o.puts "int main() {"
|
391
|
+
o.puts " printf(\"\\n\\nRunning tests on #{name}\\n\\n\");"
|
392
|
+
CompileToCUnitTest.rewrite(Hash[@references_to_test_array], sloppy_tests, @worksheet_c_names, @constants, o)
|
393
|
+
o.puts " free_all_allocated_memory();"
|
394
|
+
o.puts " printf(\"\\n\\nFinished tests on #{name}\\n\\n\");"
|
395
|
+
o.puts " return 0;"
|
396
|
+
o.puts "}"
|
397
|
+
close(o)
|
398
|
+
end
|
399
|
+
|
378
400
|
|
379
401
|
def compile_code
|
380
402
|
return unless actually_compile_code || actually_run_tests
|
@@ -386,7 +408,10 @@ END
|
|
386
408
|
|
387
409
|
def run_tests
|
388
410
|
return unless actually_run_tests
|
389
|
-
|
411
|
+
log.info "Running the resulting tests"
|
412
|
+
if write_tests_as_c
|
413
|
+
puts `cd #{File.join(output_directory)}; gcc "test_#{output_name.downcase}.c"; ./a.out`
|
414
|
+
end
|
390
415
|
puts `cd #{File.join(output_directory)}; ruby "test_#{output_name.downcase}.rb"`
|
391
416
|
end
|
392
417
|
|
@@ -94,7 +94,7 @@ class ExcelToRuby < ExcelToX
|
|
94
94
|
o.puts "class Test#{ruby_module_name} < Minitest::Unit::TestCase"
|
95
95
|
o.puts " def worksheet; @worksheet ||= #{ruby_module_name}.new; end"
|
96
96
|
|
97
|
-
|
97
|
+
CompileToRubyUnitTest.rewrite(Hash[@references_to_test_array], sloppy_tests, @worksheet_c_names, @constants, o)
|
98
98
|
|
99
99
|
o.puts "end"
|
100
100
|
close(o)
|
data/src/commands/excel_to_x.rb
CHANGED
@@ -1032,6 +1032,11 @@ class ExcelToX
|
|
1032
1032
|
end
|
1033
1033
|
end
|
1034
1034
|
|
1035
|
+
@named_references.each do |ref, ast|
|
1036
|
+
inline_replacer.current_sheet_name = ref.is_a?(Array) ? [ref.first] : []
|
1037
|
+
inline_replacer.map(ast)
|
1038
|
+
end
|
1039
|
+
|
1035
1040
|
simplify(references_that_need_updating)
|
1036
1041
|
|
1037
1042
|
replacements_made_in_the_last_pass += inline_replacer.count_replaced
|
@@ -1209,6 +1214,10 @@ class ExcelToX
|
|
1209
1214
|
r.map(ast)
|
1210
1215
|
end
|
1211
1216
|
|
1217
|
+
@named_references.each do |ref, ast|
|
1218
|
+
r.map(ast)
|
1219
|
+
end
|
1220
|
+
|
1212
1221
|
@constants = r.constants.invert
|
1213
1222
|
end
|
1214
1223
|
|
data/src/compile/c/a.out
CHANGED
Binary file
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>CFBundleDevelopmentRegion</key>
|
6
|
+
<string>English</string>
|
7
|
+
<key>CFBundleIdentifier</key>
|
8
|
+
<string>com.apple.xcode.dsym.a.out</string>
|
9
|
+
<key>CFBundleInfoDictionaryVersion</key>
|
10
|
+
<string>6.0</string>
|
11
|
+
<key>CFBundlePackageType</key>
|
12
|
+
<string>dSYM</string>
|
13
|
+
<key>CFBundleSignature</key>
|
14
|
+
<string>????</string>
|
15
|
+
<key>CFBundleShortVersionString</key>
|
16
|
+
<string>1.0</string>
|
17
|
+
<key>CFBundleVersion</key>
|
18
|
+
<string>1</string>
|
19
|
+
</dict>
|
20
|
+
</plist>
|
Binary file
|
@@ -1,7 +1,21 @@
|
|
1
|
-
require_relative "
|
1
|
+
require_relative "map_values_to_c"
|
2
2
|
|
3
|
-
class CompileToCUnitTest
|
3
|
+
class CompileToCUnitTest
|
4
4
|
|
5
|
-
|
5
|
+
def self.rewrite(*args)
|
6
|
+
self.new.rewrite(*args)
|
7
|
+
end
|
8
|
+
|
9
|
+
def rewrite(input, sloppy, sheet_names, constants, o)
|
10
|
+
mapper = MapValuesToC.new
|
11
|
+
input.each do |ref, ast|
|
12
|
+
worksheet_c_name = sheet_names[ref.first.to_s] || ref.first.to_s #FIXME: Need to make it the actual c_name
|
13
|
+
cell = ref.last
|
14
|
+
value = mapper.map(ast)
|
15
|
+
full_reference = worksheet_c_name.length > 0 ? "#{worksheet_c_name}_#{cell.downcase}()" : "#{cell.downcase}()"
|
16
|
+
test_name = "'#{ref.first.to_s}'!#{cell.upcase}"
|
17
|
+
o.puts " assert_equal(#{value}, #{full_reference}, #{test_name.inspect});"
|
18
|
+
end
|
19
|
+
end
|
6
20
|
|
7
21
|
end
|
@@ -149,9 +149,9 @@ void reset() {
|
|
149
149
|
|
150
150
|
// Handy macros
|
151
151
|
|
152
|
-
#define
|
153
|
-
#define
|
154
|
-
#define
|
152
|
+
#define EXCEL_NUMBER(numberdouble) ((ExcelValue) {.type = ExcelNumber, .number = numberdouble})
|
153
|
+
#define EXCEL_STRING(stringchar) ((ExcelValue) {.type = ExcelString, .string = stringchar})
|
154
|
+
#define EXCEL_RANGE(arrayofvalues, rangerows, rangecolumns) ((ExcelValue) {.type = ExcelRange, .array = arrayofvalues, .rows = rangerows, .columns = rangecolumns})
|
155
155
|
|
156
156
|
static void * new_excel_value_array(int size) {
|
157
157
|
ExcelValue *pointer = malloc(sizeof(ExcelValue)*size); // Freed later
|
@@ -305,7 +305,7 @@ static ExcelValue add(ExcelValue a_v, ExcelValue b_v) {
|
|
305
305
|
NUMBER(a_v, a)
|
306
306
|
NUMBER(b_v, b)
|
307
307
|
CHECK_FOR_CONVERSION_ERROR
|
308
|
-
return
|
308
|
+
return EXCEL_NUMBER(a + b);
|
309
309
|
}
|
310
310
|
|
311
311
|
static ExcelValue ensure_is_number(ExcelValue maybe_number_v) {
|
@@ -317,7 +317,7 @@ static ExcelValue ensure_is_number(ExcelValue maybe_number_v) {
|
|
317
317
|
}
|
318
318
|
NUMBER(maybe_number_v, maybe_number)
|
319
319
|
CHECK_FOR_CONVERSION_ERROR
|
320
|
-
return
|
320
|
+
return EXCEL_NUMBER(maybe_number);
|
321
321
|
}
|
322
322
|
|
323
323
|
static ExcelValue excel_log(ExcelValue number) {
|
@@ -334,7 +334,7 @@ static ExcelValue excel_log_2(ExcelValue number_v, ExcelValue base_v) {
|
|
334
334
|
if(n<=0) { return NUM; }
|
335
335
|
if(b<=0) { return NUM; }
|
336
336
|
|
337
|
-
return
|
337
|
+
return EXCEL_NUMBER(log(n)/log(b));
|
338
338
|
}
|
339
339
|
|
340
340
|
static ExcelValue ln(ExcelValue number_v) {
|
@@ -344,7 +344,7 @@ static ExcelValue ln(ExcelValue number_v) {
|
|
344
344
|
|
345
345
|
if(n<=0) { return NUM; }
|
346
346
|
|
347
|
-
return
|
347
|
+
return EXCEL_NUMBER(log(n));
|
348
348
|
}
|
349
349
|
|
350
350
|
static ExcelValue excel_exp(ExcelValue number_v) {
|
@@ -352,7 +352,7 @@ static ExcelValue excel_exp(ExcelValue number_v) {
|
|
352
352
|
NUMBER(number_v, n)
|
353
353
|
CHECK_FOR_CONVERSION_ERROR
|
354
354
|
|
355
|
-
return
|
355
|
+
return EXCEL_NUMBER(exp(n));
|
356
356
|
}
|
357
357
|
|
358
358
|
static ExcelValue excel_and(int array_size, ExcelValue *array) {
|
@@ -430,7 +430,7 @@ static ExcelValue average(int array_size, ExcelValue *array) {
|
|
430
430
|
struct average_result r = calculate_average(array_size, array);
|
431
431
|
if(r.has_error == true) return r.error;
|
432
432
|
if(r.count == 0) return DIV0;
|
433
|
-
return
|
433
|
+
return EXCEL_NUMBER(r.sum/r.count);
|
434
434
|
}
|
435
435
|
|
436
436
|
static ExcelValue forecast(ExcelValue required_x_v, ExcelValue known_y, ExcelValue known_x) {
|
@@ -498,7 +498,7 @@ static ExcelValue forecast(ExcelValue required_x_v, ExcelValue known_y, ExcelVal
|
|
498
498
|
b = b_numerator / b_denominator;
|
499
499
|
a = mean_y.number - (b*mean_x.number);
|
500
500
|
|
501
|
-
return
|
501
|
+
return EXCEL_NUMBER(a + (b*required_x));
|
502
502
|
}
|
503
503
|
|
504
504
|
static ExcelValue choose(ExcelValue index_v, int array_size, ExcelValue *array) {
|
@@ -536,7 +536,7 @@ static ExcelValue count(int array_size, ExcelValue *array) {
|
|
536
536
|
break;
|
537
537
|
}
|
538
538
|
}
|
539
|
-
return
|
539
|
+
return EXCEL_NUMBER(n);
|
540
540
|
}
|
541
541
|
|
542
542
|
static ExcelValue counta(int array_size, ExcelValue *array) {
|
@@ -560,7 +560,7 @@ static ExcelValue counta(int array_size, ExcelValue *array) {
|
|
560
560
|
break;
|
561
561
|
}
|
562
562
|
}
|
563
|
-
return
|
563
|
+
return EXCEL_NUMBER(n);
|
564
564
|
}
|
565
565
|
|
566
566
|
static ExcelValue divide(ExcelValue a_v, ExcelValue b_v) {
|
@@ -570,7 +570,7 @@ static ExcelValue divide(ExcelValue a_v, ExcelValue b_v) {
|
|
570
570
|
NUMBER(b_v, b)
|
571
571
|
CHECK_FOR_CONVERSION_ERROR
|
572
572
|
if(b == 0) return DIV0;
|
573
|
-
return
|
573
|
+
return EXCEL_NUMBER(a / b);
|
574
574
|
}
|
575
575
|
|
576
576
|
static ExcelValue excel_equal(ExcelValue a_v, ExcelValue b_v) {
|
@@ -580,17 +580,17 @@ static ExcelValue excel_equal(ExcelValue a_v, ExcelValue b_v) {
|
|
580
580
|
if(a_v.type != b_v.type) return FALSE;
|
581
581
|
|
582
582
|
switch (a_v.type) {
|
583
|
-
|
583
|
+
case ExcelNumber:
|
584
584
|
case ExcelBoolean:
|
585
585
|
case ExcelEmpty:
|
586
586
|
if(a_v.number != b_v.number) return FALSE;
|
587
587
|
return TRUE;
|
588
588
|
case ExcelString:
|
589
589
|
if(strcasecmp(a_v.string,b_v.string) != 0 ) return FALSE;
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
590
|
+
return TRUE;
|
591
|
+
case ExcelError:
|
592
|
+
return a_v;
|
593
|
+
case ExcelRange:
|
594
594
|
return NA;
|
595
595
|
}
|
596
596
|
return FALSE;
|
@@ -694,7 +694,7 @@ static ExcelValue excel_index(ExcelValue array_v, ExcelValue row_number_v, Excel
|
|
694
694
|
}
|
695
695
|
result_index++;
|
696
696
|
}
|
697
|
-
return
|
697
|
+
return EXCEL_RANGE(result,rows,1);
|
698
698
|
} else if(column_number == 0 ) { // We need the whole row
|
699
699
|
if(row_number < 1) return REF;
|
700
700
|
ExcelValue *result = (ExcelValue*) new_excel_value_array(columns);
|
@@ -712,7 +712,7 @@ static ExcelValue excel_index(ExcelValue array_v, ExcelValue row_number_v, Excel
|
|
712
712
|
}
|
713
713
|
result_index++;
|
714
714
|
}
|
715
|
-
return
|
715
|
+
return EXCEL_RANGE(result,1,columns);
|
716
716
|
} else { // We need a precise point
|
717
717
|
if(row_number < 1) return REF;
|
718
718
|
if(column_number < 1) return REF;
|
@@ -781,18 +781,18 @@ static ExcelValue large(ExcelValue range_v, ExcelValue k_v) {
|
|
781
781
|
int i;
|
782
782
|
for(i = 0; i < range_size; i++ ) {
|
783
783
|
x_v = array_v[i];
|
784
|
-
if(x_v.type == ExcelError) { return x_v; };
|
784
|
+
if(x_v.type == ExcelError) { free(sorted); return x_v; };
|
785
785
|
if(x_v.type == ExcelNumber) {
|
786
786
|
sorted[sorted_size] = x_v.number;
|
787
787
|
sorted_size++;
|
788
788
|
}
|
789
789
|
}
|
790
790
|
// Check other bound
|
791
|
-
if(k > sorted_size) { return NUM; }
|
791
|
+
if(k > sorted_size) { free(sorted); return NUM; }
|
792
792
|
|
793
793
|
qsort(sorted, sorted_size, sizeof (double), compare_doubles);
|
794
794
|
|
795
|
-
ExcelValue result =
|
795
|
+
ExcelValue result = EXCEL_NUMBER(sorted[sorted_size - k]);
|
796
796
|
free(sorted);
|
797
797
|
return result;
|
798
798
|
}
|
@@ -836,7 +836,7 @@ static ExcelValue excel_match(ExcelValue lookup_value, ExcelValue lookup_array,
|
|
836
836
|
for(i = 0; i < size; i++ ) {
|
837
837
|
x = array[i];
|
838
838
|
if(x.type == ExcelEmpty) x = ZERO;
|
839
|
-
if(excel_equal(lookup_value,x).number == true) return
|
839
|
+
if(excel_equal(lookup_value,x).number == true) return EXCEL_NUMBER(i+1);
|
840
840
|
}
|
841
841
|
return NA;
|
842
842
|
break;
|
@@ -846,10 +846,10 @@ static ExcelValue excel_match(ExcelValue lookup_value, ExcelValue lookup_array,
|
|
846
846
|
if(x.type == ExcelEmpty) x = ZERO;
|
847
847
|
if(more_than(x,lookup_value).number == true) {
|
848
848
|
if(i==0) return NA;
|
849
|
-
return
|
849
|
+
return EXCEL_NUMBER(i);
|
850
850
|
}
|
851
851
|
}
|
852
|
-
return
|
852
|
+
return EXCEL_NUMBER(size);
|
853
853
|
break;
|
854
854
|
case -1:
|
855
855
|
for(i = 0; i < size; i++ ) {
|
@@ -857,10 +857,10 @@ static ExcelValue excel_match(ExcelValue lookup_value, ExcelValue lookup_array,
|
|
857
857
|
if(x.type == ExcelEmpty) x = ZERO;
|
858
858
|
if(less_than(x,lookup_value).number == true) {
|
859
859
|
if(i==0) return NA;
|
860
|
-
return
|
860
|
+
return EXCEL_NUMBER(i);
|
861
861
|
}
|
862
862
|
}
|
863
|
-
return
|
863
|
+
return EXCEL_NUMBER(size-1);
|
864
864
|
break;
|
865
865
|
}
|
866
866
|
return NA;
|
@@ -904,7 +904,7 @@ static ExcelValue find(ExcelValue find_text_v, ExcelValue within_text_v, ExcelVa
|
|
904
904
|
within_text_offset = within_text + (start_number - 1);
|
905
905
|
result = strstr(within_text_offset,find_text);
|
906
906
|
if(result) {
|
907
|
-
return
|
907
|
+
return EXCEL_NUMBER(result - within_text + 1);
|
908
908
|
}
|
909
909
|
return VALUE;
|
910
910
|
}
|
@@ -929,10 +929,10 @@ static ExcelValue left(ExcelValue string_v, ExcelValue number_of_characters_v) {
|
|
929
929
|
char *string;
|
930
930
|
int string_must_be_freed = 0;
|
931
931
|
switch (string_v.type) {
|
932
|
-
|
932
|
+
case ExcelString:
|
933
933
|
string = string_v.string;
|
934
934
|
break;
|
935
|
-
|
935
|
+
case ExcelNumber:
|
936
936
|
string = malloc(20); // Freed
|
937
937
|
if(string == 0) {
|
938
938
|
printf("Out of memory in left");
|
@@ -944,15 +944,19 @@ static ExcelValue left(ExcelValue string_v, ExcelValue number_of_characters_v) {
|
|
944
944
|
case ExcelBoolean:
|
945
945
|
if(string_v.number == true) {
|
946
946
|
string = "TRUE";
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
947
|
+
} else {
|
948
|
+
string = "FALSE";
|
949
|
+
}
|
950
|
+
break;
|
951
951
|
case ExcelEmpty:
|
952
|
-
|
953
|
-
|
954
|
-
|
952
|
+
case ExcelError:
|
953
|
+
case ExcelRange:
|
954
|
+
return string_v;
|
955
955
|
}
|
956
|
+
|
957
|
+
if(number_of_characters > strlen(string)) {
|
958
|
+
number_of_characters = strlen(string);
|
959
|
+
}
|
956
960
|
|
957
961
|
char *left_string = malloc(number_of_characters+1); // Freed
|
958
962
|
if(left_string == 0) {
|
@@ -965,7 +969,7 @@ static ExcelValue left(ExcelValue string_v, ExcelValue number_of_characters_v) {
|
|
965
969
|
free(string);
|
966
970
|
}
|
967
971
|
free_later(left_string);
|
968
|
-
return
|
972
|
+
return EXCEL_STRING(left_string);
|
969
973
|
}
|
970
974
|
|
971
975
|
static ExcelValue left_1(ExcelValue string_v) {
|
@@ -979,10 +983,10 @@ static ExcelValue len(ExcelValue string_v) {
|
|
979
983
|
char *string;
|
980
984
|
int string_must_be_freed = 0;
|
981
985
|
switch (string_v.type) {
|
982
|
-
|
986
|
+
case ExcelString:
|
983
987
|
string = string_v.string;
|
984
988
|
break;
|
985
|
-
|
989
|
+
case ExcelNumber:
|
986
990
|
string = malloc(20); // Freed
|
987
991
|
if(string == 0) {
|
988
992
|
printf("Out of memory in len");
|
@@ -994,21 +998,21 @@ static ExcelValue len(ExcelValue string_v) {
|
|
994
998
|
case ExcelBoolean:
|
995
999
|
if(string_v.number == true) {
|
996
1000
|
string = "TRUE";
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
+
} else {
|
1002
|
+
string = "FALSE";
|
1003
|
+
}
|
1004
|
+
break;
|
1001
1005
|
case ExcelEmpty:
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1006
|
+
case ExcelError:
|
1007
|
+
case ExcelRange:
|
1008
|
+
return string_v;
|
1005
1009
|
}
|
1006
1010
|
|
1007
1011
|
int length = strlen(string);
|
1008
1012
|
if(string_must_be_freed == 1) {
|
1009
1013
|
free(string);
|
1010
1014
|
}
|
1011
|
-
return
|
1015
|
+
return EXCEL_NUMBER(length);
|
1012
1016
|
}
|
1013
1017
|
|
1014
1018
|
static ExcelValue right(ExcelValue string_v, ExcelValue number_of_characters_v) {
|
@@ -1027,10 +1031,10 @@ static ExcelValue right(ExcelValue string_v, ExcelValue number_of_characters_v)
|
|
1027
1031
|
char *string;
|
1028
1032
|
int string_must_be_freed = 0;
|
1029
1033
|
switch (string_v.type) {
|
1030
|
-
|
1034
|
+
case ExcelString:
|
1031
1035
|
string = string_v.string;
|
1032
1036
|
break;
|
1033
|
-
|
1037
|
+
case ExcelNumber:
|
1034
1038
|
string = malloc(20); // Freed
|
1035
1039
|
if(string == 0) {
|
1036
1040
|
printf("Out of memory in right");
|
@@ -1042,14 +1046,14 @@ static ExcelValue right(ExcelValue string_v, ExcelValue number_of_characters_v)
|
|
1042
1046
|
case ExcelBoolean:
|
1043
1047
|
if(string_v.number == true) {
|
1044
1048
|
string = "TRUE";
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
+
} else {
|
1050
|
+
string = "FALSE";
|
1051
|
+
}
|
1052
|
+
break;
|
1049
1053
|
case ExcelEmpty:
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1054
|
+
case ExcelError:
|
1055
|
+
case ExcelRange:
|
1056
|
+
return string_v;
|
1053
1057
|
}
|
1054
1058
|
|
1055
1059
|
char *right_string = malloc(number_of_characters+1); // Freed
|
@@ -1058,20 +1062,16 @@ static ExcelValue right(ExcelValue string_v, ExcelValue number_of_characters_v)
|
|
1058
1062
|
exit(-1);
|
1059
1063
|
}
|
1060
1064
|
int length = strlen(string);
|
1061
|
-
if(
|
1062
|
-
|
1063
|
-
free(string);
|
1064
|
-
}
|
1065
|
-
return new_excel_string("");
|
1066
|
-
} else {
|
1067
|
-
memcpy(right_string,string+length-number_of_characters,number_of_characters);
|
1068
|
-
right_string[number_of_characters] = '\0';
|
1069
|
-
if(string_must_be_freed == 1) {
|
1070
|
-
free(string);
|
1071
|
-
}
|
1072
|
-
free_later(right_string);
|
1073
|
-
return new_excel_string(right_string);
|
1065
|
+
if(number_of_characters > length) {
|
1066
|
+
number_of_characters = length;
|
1074
1067
|
}
|
1068
|
+
memcpy(right_string,string+length-number_of_characters,number_of_characters);
|
1069
|
+
right_string[number_of_characters] = '\0';
|
1070
|
+
if(string_must_be_freed == 1) {
|
1071
|
+
free(string);
|
1072
|
+
}
|
1073
|
+
free_later(right_string);
|
1074
|
+
return EXCEL_STRING(right_string);
|
1075
1075
|
}
|
1076
1076
|
|
1077
1077
|
static ExcelValue right_1(ExcelValue string_v) {
|
@@ -1272,7 +1272,7 @@ static ExcelValue subtract(ExcelValue a_v, ExcelValue b_v) {
|
|
1272
1272
|
NUMBER(a_v, a)
|
1273
1273
|
NUMBER(b_v, b)
|
1274
1274
|
CHECK_FOR_CONVERSION_ERROR
|
1275
|
-
return
|
1275
|
+
return EXCEL_NUMBER(a - b);
|
1276
1276
|
}
|
1277
1277
|
|
1278
1278
|
static ExcelValue multiply(ExcelValue a_v, ExcelValue b_v) {
|
@@ -1281,7 +1281,7 @@ static ExcelValue multiply(ExcelValue a_v, ExcelValue b_v) {
|
|
1281
1281
|
NUMBER(a_v, a)
|
1282
1282
|
NUMBER(b_v, b)
|
1283
1283
|
CHECK_FOR_CONVERSION_ERROR
|
1284
|
-
return
|
1284
|
+
return EXCEL_NUMBER(a * b);
|
1285
1285
|
}
|
1286
1286
|
|
1287
1287
|
static ExcelValue sum(int array_size, ExcelValue *array) {
|
@@ -1308,7 +1308,7 @@ static ExcelValue sum(int array_size, ExcelValue *array) {
|
|
1308
1308
|
break;
|
1309
1309
|
}
|
1310
1310
|
}
|
1311
|
-
return
|
1311
|
+
return EXCEL_NUMBER(total);
|
1312
1312
|
}
|
1313
1313
|
|
1314
1314
|
static ExcelValue npv(ExcelValue rate_v, int number_of_arguments, ExcelValue *arguments) {
|
@@ -1346,7 +1346,7 @@ static ExcelValue npv(ExcelValue rate_v, int number_of_arguments, ExcelValue *ar
|
|
1346
1346
|
n++;
|
1347
1347
|
}
|
1348
1348
|
}
|
1349
|
-
return
|
1349
|
+
return EXCEL_NUMBER(npv);
|
1350
1350
|
}
|
1351
1351
|
|
1352
1352
|
static ExcelValue max(int number_of_arguments, ExcelValue *arguments) {
|
@@ -1380,7 +1380,7 @@ static ExcelValue max(int number_of_arguments, ExcelValue *arguments) {
|
|
1380
1380
|
any_number_found = 1;
|
1381
1381
|
biggest_number_found = 0;
|
1382
1382
|
}
|
1383
|
-
return
|
1383
|
+
return EXCEL_NUMBER(biggest_number_found);
|
1384
1384
|
}
|
1385
1385
|
|
1386
1386
|
static ExcelValue min(int number_of_arguments, ExcelValue *arguments) {
|
@@ -1414,7 +1414,7 @@ static ExcelValue min(int number_of_arguments, ExcelValue *arguments) {
|
|
1414
1414
|
any_number_found = 1;
|
1415
1415
|
smallest_number_found = 0;
|
1416
1416
|
}
|
1417
|
-
return
|
1417
|
+
return EXCEL_NUMBER(smallest_number_found);
|
1418
1418
|
}
|
1419
1419
|
|
1420
1420
|
static ExcelValue mmult_error(ExcelValue a_v, ExcelValue b_v) {
|
@@ -1429,7 +1429,7 @@ static ExcelValue mmult_error(ExcelValue a_v, ExcelValue b_v) {
|
|
1429
1429
|
result[(i*columns) + j] = VALUE;
|
1430
1430
|
}
|
1431
1431
|
}
|
1432
|
-
return
|
1432
|
+
return EXCEL_RANGE(result, rows, columns);
|
1433
1433
|
}
|
1434
1434
|
|
1435
1435
|
static ExcelValue mmult(ExcelValue a_v, ExcelValue b_v) {
|
@@ -1461,10 +1461,10 @@ static ExcelValue mmult(ExcelValue a_v, ExcelValue b_v) {
|
|
1461
1461
|
if(b.type != ExcelNumber) { return mmult_error(a_v, b_v); }
|
1462
1462
|
sum = sum + (a.number * b.number);
|
1463
1463
|
}
|
1464
|
-
result[(i*b_columns)+j] =
|
1464
|
+
result[(i*b_columns)+j] = EXCEL_NUMBER(sum);
|
1465
1465
|
}
|
1466
1466
|
}
|
1467
|
-
return
|
1467
|
+
return EXCEL_RANGE(result, a_rows, b_columns);
|
1468
1468
|
}
|
1469
1469
|
|
1470
1470
|
static ExcelValue mod(ExcelValue a_v, ExcelValue b_v) {
|
@@ -1475,14 +1475,14 @@ static ExcelValue mod(ExcelValue a_v, ExcelValue b_v) {
|
|
1475
1475
|
NUMBER(b_v, b)
|
1476
1476
|
CHECK_FOR_CONVERSION_ERROR
|
1477
1477
|
if(b == 0) return DIV0;
|
1478
|
-
return
|
1478
|
+
return EXCEL_NUMBER(fmod(a,b));
|
1479
1479
|
}
|
1480
1480
|
|
1481
1481
|
static ExcelValue negative(ExcelValue a_v) {
|
1482
1482
|
CHECK_FOR_PASSED_ERROR(a_v)
|
1483
1483
|
NUMBER(a_v, a)
|
1484
1484
|
CHECK_FOR_CONVERSION_ERROR
|
1485
|
-
return
|
1485
|
+
return EXCEL_NUMBER(-a);
|
1486
1486
|
}
|
1487
1487
|
|
1488
1488
|
static ExcelValue pmt(ExcelValue rate_v, ExcelValue number_of_periods_v, ExcelValue present_value_v) {
|
@@ -1495,8 +1495,8 @@ static ExcelValue pmt(ExcelValue rate_v, ExcelValue number_of_periods_v, ExcelVa
|
|
1495
1495
|
NUMBER(present_value_v,present_value)
|
1496
1496
|
CHECK_FOR_CONVERSION_ERROR
|
1497
1497
|
|
1498
|
-
if(rate == 0) return
|
1499
|
-
return
|
1498
|
+
if(rate == 0) return EXCEL_NUMBER(-(present_value / number_of_periods));
|
1499
|
+
return EXCEL_NUMBER(-present_value*(rate*(pow((1+rate),number_of_periods)))/((pow((1+rate),number_of_periods))-1));
|
1500
1500
|
}
|
1501
1501
|
|
1502
1502
|
static ExcelValue pv_3(ExcelValue rate_v, ExcelValue nper_v, ExcelValue pmt_v) {
|
@@ -1546,7 +1546,7 @@ static ExcelValue pv_5(ExcelValue rate_v, ExcelValue nper_v, ExcelValue pmt_v, E
|
|
1546
1546
|
// Add on the final value
|
1547
1547
|
present_value = present_value - (fv/pow(1+rate,nper));
|
1548
1548
|
|
1549
|
-
return
|
1549
|
+
return EXCEL_NUMBER(present_value);
|
1550
1550
|
}
|
1551
1551
|
|
1552
1552
|
|
@@ -1561,7 +1561,7 @@ static ExcelValue power(ExcelValue a_v, ExcelValue b_v) {
|
|
1561
1561
|
if(isnan(result) == 1) {
|
1562
1562
|
return NUM;
|
1563
1563
|
} else {
|
1564
|
-
return
|
1564
|
+
return EXCEL_NUMBER(result);
|
1565
1565
|
}
|
1566
1566
|
}
|
1567
1567
|
static ExcelValue rank(ExcelValue number_v, ExcelValue range_v, ExcelValue order_v) {
|
@@ -1602,7 +1602,7 @@ static ExcelValue rank(ExcelValue number_v, ExcelValue range_v, ExcelValue order
|
|
1602
1602
|
}
|
1603
1603
|
}
|
1604
1604
|
if(found == false) { return NA; }
|
1605
|
-
return
|
1605
|
+
return EXCEL_NUMBER(ranked);
|
1606
1606
|
}
|
1607
1607
|
|
1608
1608
|
static ExcelValue rank_2(ExcelValue number_v, ExcelValue range_v) {
|
@@ -1619,7 +1619,7 @@ static ExcelValue excel_round(ExcelValue number_v, ExcelValue decimal_places_v)
|
|
1619
1619
|
|
1620
1620
|
double multiple = pow(10,decimal_places);
|
1621
1621
|
|
1622
|
-
return
|
1622
|
+
return EXCEL_NUMBER( round(number * multiple) / multiple );
|
1623
1623
|
}
|
1624
1624
|
|
1625
1625
|
static ExcelValue rounddown(ExcelValue number_v, ExcelValue decimal_places_v) {
|
@@ -1632,7 +1632,7 @@ static ExcelValue rounddown(ExcelValue number_v, ExcelValue decimal_places_v) {
|
|
1632
1632
|
|
1633
1633
|
double multiple = pow(10,decimal_places);
|
1634
1634
|
|
1635
|
-
return
|
1635
|
+
return EXCEL_NUMBER( trunc(number * multiple) / multiple );
|
1636
1636
|
}
|
1637
1637
|
|
1638
1638
|
static ExcelValue roundup(ExcelValue number_v, ExcelValue decimal_places_v) {
|
@@ -1644,8 +1644,8 @@ static ExcelValue roundup(ExcelValue number_v, ExcelValue decimal_places_v) {
|
|
1644
1644
|
CHECK_FOR_CONVERSION_ERROR
|
1645
1645
|
|
1646
1646
|
double multiple = pow(10,decimal_places);
|
1647
|
-
if(number < 0) return
|
1648
|
-
return
|
1647
|
+
if(number < 0) return EXCEL_NUMBER( floor(number * multiple) / multiple );
|
1648
|
+
return EXCEL_NUMBER( ceil(number * multiple) / multiple );
|
1649
1649
|
}
|
1650
1650
|
|
1651
1651
|
static ExcelValue excel_int(ExcelValue number_v) {
|
@@ -1654,7 +1654,7 @@ static ExcelValue excel_int(ExcelValue number_v) {
|
|
1654
1654
|
NUMBER(number_v, number)
|
1655
1655
|
CHECK_FOR_CONVERSION_ERROR
|
1656
1656
|
|
1657
|
-
return
|
1657
|
+
return EXCEL_NUMBER(floor(number));
|
1658
1658
|
}
|
1659
1659
|
|
1660
1660
|
static ExcelValue string_join(int number_of_arguments, ExcelValue *arguments) {
|
@@ -1683,7 +1683,7 @@ static ExcelValue string_join(int number_of_arguments, ExcelValue *arguments) {
|
|
1683
1683
|
printf("Out of memory in string join");
|
1684
1684
|
exit(-1);
|
1685
1685
|
}
|
1686
|
-
|
1686
|
+
must_free_current_string = 1;
|
1687
1687
|
snprintf(current_string,20,"%g",current_v.number);
|
1688
1688
|
break;
|
1689
1689
|
case ExcelBoolean:
|
@@ -1697,25 +1697,35 @@ static ExcelValue string_join(int number_of_arguments, ExcelValue *arguments) {
|
|
1697
1697
|
current_string = "";
|
1698
1698
|
break;
|
1699
1699
|
case ExcelError:
|
1700
|
+
free(string);
|
1700
1701
|
return current_v;
|
1701
1702
|
case ExcelRange:
|
1703
|
+
free(string);
|
1702
1704
|
return VALUE;
|
1703
1705
|
}
|
1704
1706
|
current_string_length = strlen(current_string);
|
1705
1707
|
if( (used_length + current_string_length + 1) > allocated_length) {
|
1706
|
-
allocated_length
|
1708
|
+
allocated_length = used_length + current_string_length + 1 + 100;
|
1707
1709
|
string = realloc(string,allocated_length);
|
1710
|
+
if(!string) {
|
1711
|
+
printf("Out of memory in string join realloc trying to increase to %d", allocated_length);
|
1712
|
+
exit(-1);
|
1713
|
+
}
|
1708
1714
|
}
|
1709
1715
|
memcpy(string + used_length, current_string, current_string_length);
|
1710
1716
|
if(must_free_current_string == 1) {
|
1711
1717
|
free(current_string);
|
1712
1718
|
}
|
1713
1719
|
used_length = used_length + current_string_length;
|
1714
|
-
}
|
1720
|
+
} // Finished looping through passed strings
|
1715
1721
|
string = realloc(string,used_length+1);
|
1722
|
+
if(!string) {
|
1723
|
+
printf("Out of memory in string join realloc trying to increase to %d", used_length+1);
|
1724
|
+
exit(-1);
|
1725
|
+
}
|
1716
1726
|
string[used_length] = '\0';
|
1717
1727
|
free_later(string);
|
1718
|
-
return
|
1728
|
+
return EXCEL_STRING(string);
|
1719
1729
|
}
|
1720
1730
|
|
1721
1731
|
static ExcelValue subtotal(ExcelValue subtotal_type_v, int number_of_arguments, ExcelValue *arguments) {
|
@@ -1788,7 +1798,7 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
|
|
1788
1798
|
if(original_range_columns != 1) return VALUE;
|
1789
1799
|
ExcelValue *tmp_array2 = (ExcelValue*) new_excel_value_array(1);
|
1790
1800
|
tmp_array2[0] = current_value;
|
1791
|
-
criteria_range[i] =
|
1801
|
+
criteria_range[i] = EXCEL_RANGE(tmp_array2,1,1);
|
1792
1802
|
}
|
1793
1803
|
}
|
1794
1804
|
|
@@ -1799,6 +1809,8 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
|
|
1799
1809
|
exit(-1);
|
1800
1810
|
}
|
1801
1811
|
char *s;
|
1812
|
+
char *new_comparator;
|
1813
|
+
|
1802
1814
|
for(i = 0; i < number_of_criteria; i++) {
|
1803
1815
|
current_value = arguments[(i*2)+1];
|
1804
1816
|
|
@@ -1806,26 +1818,38 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
|
|
1806
1818
|
s = current_value.string;
|
1807
1819
|
if(s[0] == '<') {
|
1808
1820
|
if( s[1] == '>') {
|
1821
|
+
new_comparator = strndup(s+2,strlen(s)-2);
|
1822
|
+
free_later(new_comparator);
|
1809
1823
|
criteria[i].type = NotEqual;
|
1810
|
-
criteria[i].comparator =
|
1824
|
+
criteria[i].comparator = EXCEL_STRING(new_comparator);
|
1811
1825
|
} else if(s[1] == '=') {
|
1826
|
+
new_comparator = strndup(s+2,strlen(s)-2);
|
1827
|
+
free_later(new_comparator);
|
1812
1828
|
criteria[i].type = LessThanOrEqual;
|
1813
|
-
criteria[i].comparator =
|
1829
|
+
criteria[i].comparator = EXCEL_STRING(new_comparator);
|
1814
1830
|
} else {
|
1831
|
+
new_comparator = strndup(s+1,strlen(s)-1);
|
1832
|
+
free_later(new_comparator);
|
1815
1833
|
criteria[i].type = LessThan;
|
1816
|
-
criteria[i].comparator =
|
1834
|
+
criteria[i].comparator = EXCEL_STRING(new_comparator);
|
1817
1835
|
}
|
1818
1836
|
} else if(s[0] == '>') {
|
1819
1837
|
if(s[1] == '=') {
|
1838
|
+
new_comparator = strndup(s+2,strlen(s)-2);
|
1839
|
+
free_later(new_comparator);
|
1820
1840
|
criteria[i].type = MoreThanOrEqual;
|
1821
|
-
criteria[i].comparator =
|
1841
|
+
criteria[i].comparator = EXCEL_STRING(new_comparator);
|
1822
1842
|
} else {
|
1843
|
+
new_comparator = strndup(s+1,strlen(s)-1);
|
1844
|
+
free_later(new_comparator);
|
1823
1845
|
criteria[i].type = MoreThan;
|
1824
|
-
criteria[i].comparator =
|
1846
|
+
criteria[i].comparator = EXCEL_STRING(new_comparator);
|
1825
1847
|
}
|
1826
1848
|
} else if(s[0] == '=') {
|
1849
|
+
new_comparator = strndup(s+1,strlen(s)-1);
|
1850
|
+
free_later(new_comparator);
|
1827
1851
|
criteria[i].type = Equal;
|
1828
|
-
criteria[i].comparator =
|
1852
|
+
criteria[i].comparator = EXCEL_STRING(new_comparator);
|
1829
1853
|
} else {
|
1830
1854
|
criteria[i].type = Equal;
|
1831
1855
|
criteria[i].comparator = current_value;
|
@@ -1966,6 +1990,7 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
|
|
1966
1990
|
}
|
1967
1991
|
break;
|
1968
1992
|
case ExcelRange:
|
1993
|
+
free(criteria);
|
1969
1994
|
return VALUE;
|
1970
1995
|
}
|
1971
1996
|
if(passed == 0) break;
|
@@ -1973,6 +1998,7 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
|
|
1973
1998
|
if(passed == 1) {
|
1974
1999
|
current_value = original_range[j];
|
1975
2000
|
if(current_value.type == ExcelError) {
|
2001
|
+
free(criteria);
|
1976
2002
|
return current_value;
|
1977
2003
|
} else if(current_value.type == ExcelNumber) {
|
1978
2004
|
filtered_range[number_of_filtered_values] = current_value;
|
@@ -1982,7 +2008,7 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
|
|
1982
2008
|
}
|
1983
2009
|
// Tidy up
|
1984
2010
|
free(criteria);
|
1985
|
-
return
|
2011
|
+
return EXCEL_RANGE(filtered_range, number_of_filtered_values, 1);
|
1986
2012
|
}
|
1987
2013
|
|
1988
2014
|
static ExcelValue sumifs(ExcelValue sum_range_v, int number_of_arguments, ExcelValue *arguments) {
|
@@ -2014,7 +2040,7 @@ static ExcelValue sumproduct(int number_of_arguments, ExcelValue *arguments) {
|
|
2014
2040
|
int rows;
|
2015
2041
|
int columns;
|
2016
2042
|
ExcelValue current_value;
|
2017
|
-
ExcelValue **ranges = malloc(sizeof(ExcelValue *)*number_of_arguments);
|
2043
|
+
ExcelValue **ranges = malloc(sizeof(ExcelValue *)*number_of_arguments);
|
2018
2044
|
if(ranges == 0) {
|
2019
2045
|
printf("Out of memory in sumproduct\n");
|
2020
2046
|
exit(-1);
|
@@ -2035,19 +2061,19 @@ static ExcelValue sumproduct(int number_of_arguments, ExcelValue *arguments) {
|
|
2035
2061
|
current_value = arguments[a];
|
2036
2062
|
switch(current_value.type) {
|
2037
2063
|
case ExcelRange:
|
2038
|
-
if(current_value.rows != rows || current_value.columns != columns) return VALUE;
|
2064
|
+
if(current_value.rows != rows || current_value.columns != columns) { free(ranges); return VALUE; }
|
2039
2065
|
ranges[a] = current_value.array;
|
2040
2066
|
break;
|
2041
2067
|
case ExcelError:
|
2042
|
-
|
2068
|
+
free(ranges);
|
2043
2069
|
return current_value;
|
2044
2070
|
break;
|
2045
2071
|
case ExcelEmpty:
|
2046
|
-
|
2072
|
+
free(ranges);
|
2047
2073
|
return VALUE;
|
2048
2074
|
break;
|
2049
2075
|
default:
|
2050
|
-
if(rows != 1 && columns !=1) return VALUE;
|
2076
|
+
if(rows != 1 && columns !=1) { free(ranges); return VALUE; }
|
2051
2077
|
ranges[a] = (ExcelValue*) new_excel_value_array(1);
|
2052
2078
|
ranges[a][0] = arguments[a];
|
2053
2079
|
break;
|
@@ -2069,7 +2095,7 @@ static ExcelValue sumproduct(int number_of_arguments, ExcelValue *arguments) {
|
|
2069
2095
|
}
|
2070
2096
|
}
|
2071
2097
|
free(ranges);
|
2072
|
-
|
2098
|
+
return EXCEL_NUMBER(sum);
|
2073
2099
|
}
|
2074
2100
|
|
2075
2101
|
// FIXME: This could do with being done properly, rather than
|
@@ -2088,11 +2114,11 @@ static ExcelValue text(ExcelValue number_v, ExcelValue format_v) {
|
|
2088
2114
|
}
|
2089
2115
|
|
2090
2116
|
if(format_v.type == ExcelEmpty) {
|
2091
|
-
return
|
2117
|
+
return EXCEL_STRING("");
|
2092
2118
|
}
|
2093
2119
|
|
2094
2120
|
if(format_v.type == ExcelNumber && format_v.number == 0) {
|
2095
|
-
format_v =
|
2121
|
+
format_v = EXCEL_STRING("0");
|
2096
2122
|
}
|
2097
2123
|
|
2098
2124
|
if(number_v.type == ExcelString) {
|
@@ -2102,7 +2128,7 @@ static ExcelValue text(ExcelValue number_v, ExcelValue format_v) {
|
|
2102
2128
|
}
|
2103
2129
|
n = strtod (s, &p);
|
2104
2130
|
if(*p == '\0') {
|
2105
|
-
number_v =
|
2131
|
+
number_v = EXCEL_NUMBER(n);
|
2106
2132
|
}
|
2107
2133
|
}
|
2108
2134
|
|
@@ -2114,77 +2140,40 @@ static ExcelValue text(ExcelValue number_v, ExcelValue format_v) {
|
|
2114
2140
|
return format_v;
|
2115
2141
|
}
|
2116
2142
|
|
2143
|
+
// FIXME: Too little?
|
2144
|
+
s = malloc(100);
|
2145
|
+
setlocale(LC_ALL,"");
|
2146
|
+
|
2117
2147
|
if(strcmp(format_v.string,"0%") == 0) {
|
2118
|
-
|
2119
|
-
s = malloc(100);
|
2120
|
-
sprintf(s, "%0.0f%%", number_v.number*100);
|
2121
|
-
free_later(s);
|
2122
|
-
result = new_excel_string(s);
|
2148
|
+
snprintf(s, 99, "%0.0f%%", number_v.number*100);
|
2123
2149
|
} else if(strcmp(format_v.string,"0.0%") == 0) {
|
2124
|
-
|
2125
|
-
s = malloc(100);
|
2126
|
-
sprintf(s, "%0.1f%%", number_v.number*100);
|
2127
|
-
free_later(s);
|
2128
|
-
result = new_excel_string(s);
|
2150
|
+
snprintf(s, 99, "%0.1f%%", number_v.number*100);
|
2129
2151
|
} else if(strcmp(format_v.string,"0") == 0) {
|
2130
|
-
s
|
2131
|
-
sprintf(s, "%0.0f",number_v.number);
|
2132
|
-
free_later(s);
|
2133
|
-
result = new_excel_string(s);
|
2152
|
+
snprintf(s, 99, "%0.0f",number_v.number);
|
2134
2153
|
} else if(strcmp(format_v.string,"0.0") == 0) {
|
2135
|
-
s
|
2136
|
-
sprintf(s, "%0.1f",number_v.number);
|
2137
|
-
free_later(s);
|
2138
|
-
result = new_excel_string(s);
|
2154
|
+
snprintf(s, 99, "%0.1f",number_v.number);
|
2139
2155
|
} else if(strcmp(format_v.string,"0.00") == 0) {
|
2140
|
-
s
|
2141
|
-
sprintf(s, "%0.2f",number_v.number);
|
2142
|
-
free_later(s);
|
2143
|
-
result = new_excel_string(s);
|
2156
|
+
snprintf(s, 99, "%0.2f",number_v.number);
|
2144
2157
|
} else if(strcmp(format_v.string,"0.000") == 0) {
|
2145
|
-
s
|
2146
|
-
sprintf(s, "%0.3f",number_v.number);
|
2147
|
-
free_later(s);
|
2148
|
-
result = new_excel_string(s);
|
2158
|
+
snprintf(s, 99, "%0.3f",number_v.number);
|
2149
2159
|
} else if(strcmp(format_v.string,"#,##") == 0) {
|
2150
|
-
s
|
2151
|
-
setlocale(LC_ALL,"");
|
2152
|
-
sprintf(s, "%'0.0f",number_v.number);
|
2153
|
-
free_later(s);
|
2154
|
-
result = new_excel_string(s);
|
2160
|
+
snprintf(s, 99, "%'0.0f",number_v.number);
|
2155
2161
|
} else if(strcmp(format_v.string,"#,##0") == 0) {
|
2156
|
-
s
|
2157
|
-
setlocale(LC_ALL,"");
|
2158
|
-
sprintf(s, "%'0.0f",number_v.number);
|
2159
|
-
free_later(s);
|
2160
|
-
result = new_excel_string(s);
|
2162
|
+
snprintf(s, 99, "%'0.0f",number_v.number);
|
2161
2163
|
} else if(strcmp(format_v.string,"#,##0.0") == 0) {
|
2162
|
-
s
|
2163
|
-
setlocale(LC_ALL,"");
|
2164
|
-
sprintf(s, "%'0.1f",number_v.number);
|
2165
|
-
free_later(s);
|
2166
|
-
result = new_excel_string(s);
|
2164
|
+
snprintf(s, 99, "%'0.1f",number_v.number);
|
2167
2165
|
} else if(strcmp(format_v.string,"#,##0.00") == 0) {
|
2168
|
-
s
|
2169
|
-
setlocale(LC_ALL,"");
|
2170
|
-
sprintf(s, "%'0.2f",number_v.number);
|
2171
|
-
free_later(s);
|
2172
|
-
result = new_excel_string(s);
|
2166
|
+
snprintf(s, 99, "%'0.2f",number_v.number);
|
2173
2167
|
} else if(strcmp(format_v.string,"#,##0.000") == 0) {
|
2174
|
-
s
|
2175
|
-
setlocale(LC_ALL,"");
|
2176
|
-
sprintf(s, "%'0.3f",number_v.number);
|
2177
|
-
free_later(s);
|
2178
|
-
result = new_excel_string(s);
|
2168
|
+
snprintf(s, 99, "%'0.3f",number_v.number);
|
2179
2169
|
} else if(strcmp(format_v.string,"0000") == 0) {
|
2180
|
-
s
|
2181
|
-
sprintf(s, "%04.0f",number_v.number);
|
2182
|
-
free_later(s);
|
2183
|
-
result = new_excel_string(s);
|
2170
|
+
snprintf(s, 99, "%04.0f",number_v.number);
|
2184
2171
|
} else {
|
2185
|
-
|
2172
|
+
snprintf(s, 99, "Text format not recognised");
|
2186
2173
|
}
|
2187
2174
|
|
2175
|
+
free_later(s);
|
2176
|
+
result = EXCEL_STRING(s);
|
2188
2177
|
// inspect_excel_value(result);
|
2189
2178
|
return result;
|
2190
2179
|
}
|
@@ -2298,5 +2287,62 @@ static ExcelValue value(ExcelValue string_v) {
|
|
2298
2287
|
CHECK_FOR_PASSED_ERROR(string_v)
|
2299
2288
|
NUMBER(string_v, a)
|
2300
2289
|
CHECK_FOR_CONVERSION_ERROR
|
2301
|
-
return
|
2290
|
+
return EXCEL_NUMBER(a);
|
2291
|
+
}
|
2292
|
+
|
2293
|
+
// Allows numbers to be 0.1% different
|
2294
|
+
static ExcelValue roughly_equal(ExcelValue a_v, ExcelValue b_v) {
|
2295
|
+
|
2296
|
+
if(a_v.type == ExcelEmpty && b_v.type == ExcelNumber && b_v.number == 0) return TRUE;
|
2297
|
+
if(b_v.type == ExcelEmpty && a_v.type == ExcelNumber && a_v.number == 0) return TRUE;
|
2298
|
+
|
2299
|
+
if(a_v.type != b_v.type) return FALSE;
|
2300
|
+
|
2301
|
+
float epsilon, difference;
|
2302
|
+
|
2303
|
+
switch (a_v.type) {
|
2304
|
+
case ExcelNumber:
|
2305
|
+
// FIXME: Arbitrary choice of epsilons
|
2306
|
+
if(b_v.number > -1e-6 && b_v.number < 1e-6) {
|
2307
|
+
epsilon = 1e-6;
|
2308
|
+
} else {
|
2309
|
+
epsilon = b_v.number * 0.001;
|
2310
|
+
}
|
2311
|
+
if(epsilon < 0) epsilon = -epsilon;
|
2312
|
+
difference = a_v.number - b_v.number;
|
2313
|
+
if(difference < 0) difference = -difference;
|
2314
|
+
if(difference <= epsilon) return TRUE;
|
2315
|
+
// For debuging: printf("a: %e b:%e d: %e e: %e", a_v.number, b_v.number, difference, epsilon);
|
2316
|
+
return FALSE;
|
2317
|
+
case ExcelBoolean:
|
2318
|
+
case ExcelEmpty:
|
2319
|
+
if(a_v.number != b_v.number) return FALSE;
|
2320
|
+
return TRUE;
|
2321
|
+
case ExcelString:
|
2322
|
+
if(strcasecmp(a_v.string,b_v.string) != 0 ) return FALSE;
|
2323
|
+
return TRUE;
|
2324
|
+
case ExcelError:
|
2325
|
+
if(a_v.number != b_v.number) return FALSE;
|
2326
|
+
return TRUE;
|
2327
|
+
case ExcelRange:
|
2328
|
+
return NA;
|
2329
|
+
}
|
2330
|
+
return FALSE;
|
2331
|
+
}
|
2332
|
+
|
2333
|
+
|
2334
|
+
static void assert_equal(ExcelValue expected, ExcelValue actual, char location[]) {
|
2335
|
+
ExcelValue comparison = roughly_equal(actual, expected);
|
2336
|
+
if(comparison.type == ExcelBoolean && comparison.number == 1) {
|
2337
|
+
putchar('.');
|
2338
|
+
} else {
|
2339
|
+
printf("\n\nFailed at %s\n", location);
|
2340
|
+
printf("Expected: ");
|
2341
|
+
inspect_excel_value(expected);
|
2342
|
+
printf("Got: ");
|
2343
|
+
inspect_excel_value(actual);
|
2344
|
+
putchar('\n');
|
2345
|
+
}
|
2302
2346
|
}
|
2347
|
+
|
2348
|
+
|