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 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
+