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