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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9a337c16718282fa8bbce1da4a51cb81d2ad6651
4
- data.tar.gz: fbfa6de417b5b4f8fe626244b234876cd00f430c
3
+ metadata.gz: 1b7eaef5e426ea529d3b33d237e2d41adc37c305
4
+ data.tar.gz: ac576e8a20ca8bc58f9839c1018f45210cc9d0a6
5
5
  SHA512:
6
- metadata.gz: cf150004e0ad6ad4cf8d17d4abc740c4b5e33e3224c39091a2d9b9edc65d4e66de2ba047446c9cbc04fe7c33f680ed156300dc10ca568f38e7c6e97a70896a7e
7
- data.tar.gz: 28bbe1191e5da2bbcbc63d4bda866f6f1720c619212659d6aeaece6c9e21baa7597b95ec7e6d77718895ff9bed54f9cc07c4cd5674a8918fb73874ebfbd12044
6
+ metadata.gz: adb264736922ee868d1890cc9c390e8d34e29e4f31aa6be954a3980f49f5d9a02510d609ab1e72436be78ec6ad79359b0d5868d0e202e8732ffa837f535557be
7
+ data.tar.gz: 4ce4a712b27076f76ae665dd158e0b7153ebdfea42643a8f8568bf4c8eeb58f0c7c7e6d84c4a33a13580f1a0781072f1bdff03a0406386998f304f6218f2c994
data/bin/excel_to_c CHANGED
@@ -74,6 +74,10 @@ END
74
74
  command.create_rakefile = false
75
75
  end
76
76
 
77
+ opts.on('--write-tests-in-c', "Write tests in pure C (normally written in ruby") do
78
+ command.write_tests_in_c = true
79
+ end
80
+
77
81
  opts.on("-h", "--help", "Show this message") do
78
82
  puts opts
79
83
  exit
@@ -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
- write_tests
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 write_tests
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
- CompileToCUnitTest.rewrite(Hash[@references_to_test_array], sloppy_tests, @worksheet_c_names, @constants, o)
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
- puts "Running the resulting tests"
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
- CompileToCUnitTest.rewrite(Hash[@references_to_test_array], sloppy_tests, @worksheet_c_names, @constants, o)
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)
@@ -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>
@@ -1,7 +1,21 @@
1
- require_relative "../ruby/compile_to_ruby_unit_test"
1
+ require_relative "map_values_to_c"
2
2
 
3
- class CompileToCUnitTest < CompileToRubyUnitTest
3
+ class CompileToCUnitTest
4
4
 
5
- # Now produces tests just like the Ruby version
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 new_excel_number(numberdouble) ((ExcelValue) {.type = ExcelNumber, .number = numberdouble})
153
- #define new_excel_string(stringchar) ((ExcelValue) {.type = ExcelString, .string = stringchar})
154
- #define new_excel_range(arrayofvalues, rangerows, rangecolumns) ((ExcelValue) {.type = ExcelRange, .array = arrayofvalues, .rows = rangerows, .columns = rangecolumns})
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 new_excel_number(a + b);
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 new_excel_number(maybe_number);
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 new_excel_number(log(n)/log(b));
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 new_excel_number(log(n));
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 new_excel_number(exp(n));
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 new_excel_number(r.sum/r.count);
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 new_excel_number(a + (b*required_x));
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 new_excel_number(n);
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 new_excel_number(n);
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 new_excel_number(a / b);
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
- case ExcelNumber:
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
- return TRUE;
591
- case ExcelError:
592
- return a_v;
593
- case ExcelRange:
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 new_excel_range(result,rows,1);
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 new_excel_range(result,1,columns);
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 = new_excel_number(sorted[sorted_size - k]);
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 new_excel_number(i+1);
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 new_excel_number(i);
849
+ return EXCEL_NUMBER(i);
850
850
  }
851
851
  }
852
- return new_excel_number(size);
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 new_excel_number(i);
860
+ return EXCEL_NUMBER(i);
861
861
  }
862
862
  }
863
- return new_excel_number(size-1);
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 new_excel_number(result - within_text + 1);
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
- case ExcelString:
932
+ case ExcelString:
933
933
  string = string_v.string;
934
934
  break;
935
- case ExcelNumber:
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
- } else {
948
- string = "FALSE";
949
- }
950
- break;
947
+ } else {
948
+ string = "FALSE";
949
+ }
950
+ break;
951
951
  case ExcelEmpty:
952
- case ExcelError:
953
- case ExcelRange:
954
- return string_v;
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 new_excel_string(left_string);
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
- case ExcelString:
986
+ case ExcelString:
983
987
  string = string_v.string;
984
988
  break;
985
- case ExcelNumber:
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
- } else {
998
- string = "FALSE";
999
- }
1000
- break;
1001
+ } else {
1002
+ string = "FALSE";
1003
+ }
1004
+ break;
1001
1005
  case ExcelEmpty:
1002
- case ExcelError:
1003
- case ExcelRange:
1004
- return string_v;
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 new_excel_number(length);
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
- case ExcelString:
1034
+ case ExcelString:
1031
1035
  string = string_v.string;
1032
1036
  break;
1033
- case ExcelNumber:
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
- } else {
1046
- string = "FALSE";
1047
- }
1048
- break;
1049
+ } else {
1050
+ string = "FALSE";
1051
+ }
1052
+ break;
1049
1053
  case ExcelEmpty:
1050
- case ExcelError:
1051
- case ExcelRange:
1052
- return string_v;
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(length < number_of_characters) {
1062
- if(string_must_be_freed == 1) {
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 new_excel_number(a - b);
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 new_excel_number(a * b);
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 new_excel_number(total);
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 new_excel_number(npv);
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 new_excel_number(biggest_number_found);
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 new_excel_number(smallest_number_found);
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 new_excel_range(result, rows, columns);
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] = new_excel_number(sum);
1464
+ result[(i*b_columns)+j] = EXCEL_NUMBER(sum);
1465
1465
  }
1466
1466
  }
1467
- return new_excel_range(result, a_rows, b_columns);
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 new_excel_number(fmod(a,b));
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 new_excel_number(-a);
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 new_excel_number(-(present_value / number_of_periods));
1499
- return new_excel_number(-present_value*(rate*(pow((1+rate),number_of_periods)))/((pow((1+rate),number_of_periods))-1));
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 new_excel_number(present_value);
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 new_excel_number(result);
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 new_excel_number(ranked);
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 new_excel_number( round(number * multiple) / multiple );
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 new_excel_number( trunc(number * multiple) / multiple );
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 new_excel_number( floor(number * multiple) / multiple );
1648
- return new_excel_number( ceil(number * multiple) / multiple );
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 new_excel_number(floor(number));
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
- must_free_current_string = 1;
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 += 100;
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 new_excel_string(string);
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] = new_excel_range(tmp_array2,1,1);
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 = new_excel_string(strndup(s+2,strlen(s)-2));
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 = new_excel_string(strndup(s+2,strlen(s)-2));
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 = new_excel_string(strndup(s+1,strlen(s)-1));
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 = new_excel_string(strndup(s+2,strlen(s)-2));
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 = new_excel_string(strndup(s+1,strlen(s)-1));
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 = new_excel_string(strndup(s+1,strlen(s)-1));
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 new_excel_range(filtered_range, number_of_filtered_values, 1);
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); // Added free statements
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
- free(ranges);
2068
+ free(ranges);
2043
2069
  return current_value;
2044
2070
  break;
2045
2071
  case ExcelEmpty:
2046
- free(ranges);
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
- return new_excel_number(sum);
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 new_excel_string("");
2117
+ return EXCEL_STRING("");
2092
2118
  }
2093
2119
 
2094
2120
  if(format_v.type == ExcelNumber && format_v.number == 0) {
2095
- format_v = new_excel_string("0");
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 = new_excel_number(n);
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
- // FIXME: Too little?
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
- // FIXME: Too little?
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 = malloc(100);
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 = malloc(100);
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 = malloc(100);
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 = malloc(100);
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 = malloc(100);
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 = malloc(100);
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 = malloc(100);
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 = malloc(100);
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 = malloc(100);
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 = malloc(100);
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
- return new_excel_string("Text format not recognised");
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 new_excel_number(a);
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
+