fast_excel 0.4.1 → 0.5.0

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.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +1 -7
  3. data/CHANGELOG.md +9 -0
  4. data/Gemfile +1 -1
  5. data/examples/example.rb +2 -0
  6. data/examples/example_date_time.rb +38 -0
  7. data/fast_excel.gemspec +2 -2
  8. data/lib/fast_excel/binding/format.rb +17 -0
  9. data/lib/fast_excel/binding/workbook.rb +39 -17
  10. data/lib/fast_excel/binding/worksheet.rb +57 -13
  11. data/lib/fast_excel/binding.rb +7 -7
  12. data/lib/fast_excel.rb +27 -20
  13. data/libxlsxwriter/.github/FUNDING.yml +1 -0
  14. data/libxlsxwriter/.github/ISSUE_TEMPLATE.md +85 -0
  15. data/libxlsxwriter/.github/PULL_REQUEST_TEMPLATE.md +130 -0
  16. data/libxlsxwriter/.github/workflows/cmake_actions.yml +48 -0
  17. data/libxlsxwriter/.github/workflows/code_style.yml +23 -0
  18. data/libxlsxwriter/.github/workflows/coverity.yml +22 -0
  19. data/libxlsxwriter/.github/workflows/make_actions.yml +52 -0
  20. data/libxlsxwriter/.github/workflows/valgrind.yml +23 -0
  21. data/libxlsxwriter/.github/workflows/windows_build.yml +54 -0
  22. data/libxlsxwriter/.github/workflows/zig_build.yml +22 -0
  23. data/libxlsxwriter/.gitignore +16 -1
  24. data/libxlsxwriter/.indent.pro +24 -0
  25. data/libxlsxwriter/CMakeLists.txt +156 -56
  26. data/libxlsxwriter/CONTRIBUTING.md +2 -2
  27. data/libxlsxwriter/Changes.txt +344 -2
  28. data/libxlsxwriter/LICENSE.txt +66 -8
  29. data/libxlsxwriter/Makefile +151 -54
  30. data/libxlsxwriter/Package.swift +42 -0
  31. data/libxlsxwriter/Readme.md +4 -2
  32. data/libxlsxwriter/build.zig +324 -0
  33. data/libxlsxwriter/build.zig.zon +11 -0
  34. data/libxlsxwriter/cmake/FindMINIZIP.cmake +3 -3
  35. data/libxlsxwriter/cocoapods/libxlsxwriter-umbrella.h +6 -0
  36. data/libxlsxwriter/include/xlsxwriter/app.h +2 -1
  37. data/libxlsxwriter/include/xlsxwriter/chart.h +236 -32
  38. data/libxlsxwriter/include/xlsxwriter/chartsheet.h +7 -7
  39. data/libxlsxwriter/include/xlsxwriter/comment.h +76 -0
  40. data/libxlsxwriter/include/xlsxwriter/common.h +111 -50
  41. data/libxlsxwriter/include/xlsxwriter/content_types.h +8 -1
  42. data/libxlsxwriter/include/xlsxwriter/core.h +1 -1
  43. data/libxlsxwriter/include/xlsxwriter/custom.h +1 -1
  44. data/libxlsxwriter/include/xlsxwriter/drawing.h +11 -20
  45. data/libxlsxwriter/include/xlsxwriter/format.h +121 -8
  46. data/libxlsxwriter/include/xlsxwriter/hash_table.h +1 -1
  47. data/libxlsxwriter/include/xlsxwriter/metadata.h +49 -0
  48. data/libxlsxwriter/include/xlsxwriter/packager.h +27 -16
  49. data/libxlsxwriter/include/xlsxwriter/relationships.h +1 -1
  50. data/libxlsxwriter/include/xlsxwriter/shared_strings.h +1 -1
  51. data/libxlsxwriter/include/xlsxwriter/styles.h +13 -7
  52. data/libxlsxwriter/include/xlsxwriter/table.h +51 -0
  53. data/libxlsxwriter/include/xlsxwriter/theme.h +1 -1
  54. data/libxlsxwriter/include/xlsxwriter/third_party/emyg_dtoa.h +26 -0
  55. data/libxlsxwriter/include/xlsxwriter/third_party/ioapi.h +27 -25
  56. data/libxlsxwriter/include/xlsxwriter/third_party/md5.h +45 -0
  57. data/libxlsxwriter/include/xlsxwriter/third_party/zip.h +155 -153
  58. data/libxlsxwriter/include/xlsxwriter/utility.h +70 -8
  59. data/libxlsxwriter/include/xlsxwriter/vml.h +55 -0
  60. data/libxlsxwriter/include/xlsxwriter/workbook.h +218 -47
  61. data/libxlsxwriter/include/xlsxwriter/worksheet.h +2770 -241
  62. data/libxlsxwriter/include/xlsxwriter/xmlwriter.h +12 -8
  63. data/libxlsxwriter/include/xlsxwriter.h +4 -2
  64. data/libxlsxwriter/libxlsxwriter.podspec +8 -5
  65. data/libxlsxwriter/src/Makefile +58 -21
  66. data/libxlsxwriter/src/app.c +5 -2
  67. data/libxlsxwriter/src/chart.c +396 -81
  68. data/libxlsxwriter/src/chartsheet.c +22 -22
  69. data/libxlsxwriter/src/comment.c +443 -0
  70. data/libxlsxwriter/src/content_types.c +40 -1
  71. data/libxlsxwriter/src/core.c +2 -2
  72. data/libxlsxwriter/src/custom.c +1 -1
  73. data/libxlsxwriter/src/drawing.c +160 -40
  74. data/libxlsxwriter/src/format.c +109 -25
  75. data/libxlsxwriter/src/hash_table.c +1 -1
  76. data/libxlsxwriter/src/metadata.c +283 -0
  77. data/libxlsxwriter/src/packager.c +794 -94
  78. data/libxlsxwriter/src/relationships.c +1 -1
  79. data/libxlsxwriter/src/shared_strings.c +2 -4
  80. data/libxlsxwriter/src/styles.c +353 -58
  81. data/libxlsxwriter/src/table.c +304 -0
  82. data/libxlsxwriter/src/theme.c +1 -1
  83. data/libxlsxwriter/src/utility.c +143 -43
  84. data/libxlsxwriter/src/vml.c +1062 -0
  85. data/libxlsxwriter/src/workbook.c +567 -77
  86. data/libxlsxwriter/src/worksheet.c +6668 -1462
  87. data/libxlsxwriter/src/xmlwriter.c +95 -5
  88. data/libxlsxwriter/third_party/dtoa/Makefile +42 -0
  89. data/libxlsxwriter/third_party/dtoa/emyg_dtoa.c +461 -0
  90. data/libxlsxwriter/third_party/dtoa/emyg_dtoa.h +26 -0
  91. data/libxlsxwriter/third_party/md5/Makefile +42 -0
  92. data/libxlsxwriter/third_party/md5/md5.c +291 -0
  93. data/libxlsxwriter/third_party/md5/md5.h +45 -0
  94. data/libxlsxwriter/third_party/minizip/Makefile +3 -8
  95. data/libxlsxwriter/third_party/minizip/Makefile.orig +8 -4
  96. data/libxlsxwriter/third_party/minizip/MiniZip64_Changes.txt +1 -1
  97. data/libxlsxwriter/third_party/minizip/configure.ac +1 -1
  98. data/libxlsxwriter/third_party/minizip/crypt.h +13 -16
  99. data/libxlsxwriter/third_party/minizip/ioapi.c +31 -57
  100. data/libxlsxwriter/third_party/minizip/ioapi.h +31 -23
  101. data/libxlsxwriter/third_party/minizip/iowin32.c +29 -45
  102. data/libxlsxwriter/third_party/minizip/iowin32.h +4 -4
  103. data/libxlsxwriter/third_party/minizip/miniunz.c +29 -56
  104. data/libxlsxwriter/third_party/minizip/minizip.c +38 -49
  105. data/libxlsxwriter/third_party/minizip/mztools.c +1 -7
  106. data/libxlsxwriter/third_party/minizip/unzip.c +202 -342
  107. data/libxlsxwriter/third_party/minizip/unzip.h +74 -74
  108. data/libxlsxwriter/third_party/minizip/zip.c +165 -218
  109. data/libxlsxwriter/third_party/minizip/zip.h +164 -154
  110. data/libxlsxwriter/third_party/tmpfileplus/Makefile +3 -3
  111. data/libxlsxwriter/version.txt +1 -1
  112. data/test/auto_width_test.rb +20 -0
  113. data/test/default_format_test.rb +1 -1
  114. data/test/validations_test.rb +3 -3
  115. data/test/worksheet_test.rb +6 -1
  116. metadata +33 -7
  117. data/libxlsxwriter/.travis.yml +0 -37
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Used in conjunction with the libxlsxwriter library.
5
5
  *
6
- * Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
6
+ * Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
7
7
  *
8
8
  */
9
9
 
@@ -14,7 +14,7 @@
14
14
  /*
15
15
  * Forward declarations.
16
16
  */
17
- STATIC void _write_font(lxw_styles *self, lxw_format *format,
17
+ STATIC void _write_font(lxw_styles *self, lxw_format *format, uint8_t is_dxf,
18
18
  uint8_t is_rich_string);
19
19
 
20
20
  /*****************************************************************************
@@ -34,9 +34,12 @@ lxw_styles_new(void)
34
34
 
35
35
  styles->xf_formats = calloc(1, sizeof(struct lxw_formats));
36
36
  GOTO_LABEL_ON_MEM_ERROR(styles->xf_formats, mem_error);
37
-
38
37
  STAILQ_INIT(styles->xf_formats);
39
38
 
39
+ styles->dxf_formats = calloc(1, sizeof(struct lxw_formats));
40
+ GOTO_LABEL_ON_MEM_ERROR(styles->dxf_formats, mem_error);
41
+ STAILQ_INIT(styles->dxf_formats);
42
+
40
43
  return styles;
41
44
 
42
45
  mem_error:
@@ -55,7 +58,7 @@ lxw_styles_free(lxw_styles *styles)
55
58
  if (!styles)
56
59
  return;
57
60
 
58
- /* Free the formats in the styles. */
61
+ /* Free the xf formats in the styles. */
59
62
  if (styles->xf_formats) {
60
63
  while (!STAILQ_EMPTY(styles->xf_formats)) {
61
64
  format = STAILQ_FIRST(styles->xf_formats);
@@ -65,6 +68,16 @@ lxw_styles_free(lxw_styles *styles)
65
68
  free(styles->xf_formats);
66
69
  }
67
70
 
71
+ /* Free the dxf formats in the styles. */
72
+ if (styles->dxf_formats) {
73
+ while (!STAILQ_EMPTY(styles->dxf_formats)) {
74
+ format = STAILQ_FIRST(styles->dxf_formats);
75
+ STAILQ_REMOVE_HEAD(styles->dxf_formats, list_pointers);
76
+ free(format);
77
+ }
78
+ free(styles->dxf_formats);
79
+ }
80
+
68
81
  free(styles);
69
82
  }
70
83
 
@@ -72,7 +85,7 @@ lxw_styles_free(lxw_styles *styles)
72
85
  * Write the <t> element for rich strings.
73
86
  */
74
87
  void
75
- lxw_styles_write_string_fragment(lxw_styles *self, char *string)
88
+ lxw_styles_write_string_fragment(lxw_styles *self, const char *string)
76
89
  {
77
90
  struct xml_attribute_list attributes;
78
91
  struct xml_attribute *attribute;
@@ -93,7 +106,7 @@ void
93
106
  lxw_styles_write_rich_font(lxw_styles *self, lxw_format *format)
94
107
  {
95
108
 
96
- _write_font(self, format, LXW_TRUE);
109
+ _write_font(self, format, LXW_FALSE, LXW_TRUE);
97
110
  }
98
111
 
99
112
  /*****************************************************************************
@@ -136,10 +149,68 @@ _write_num_fmt(lxw_styles *self, uint16_t num_fmt_id, char *format_code)
136
149
  {
137
150
  struct xml_attribute_list attributes;
138
151
  struct xml_attribute *attribute;
152
+ char *format_codes[] = {
153
+ "General",
154
+ "0",
155
+ "0.00",
156
+ "#,##0",
157
+ "#,##0.00",
158
+ "($#,##0_);($#,##0)",
159
+ "($#,##0_);[Red]($#,##0)",
160
+ "($#,##0.00_);($#,##0.00)",
161
+ "($#,##0.00_);[Red]($#,##0.00)",
162
+ "0%",
163
+ "0.00%",
164
+ "0.00E+00",
165
+ "# ?/?",
166
+ "# ?" "?/?" "?", /* Split string to avoid unintentional trigraph. */
167
+ "m/d/yy",
168
+ "d-mmm-yy",
169
+ "d-mmm",
170
+ "mmm-yy",
171
+ "h:mm AM/PM",
172
+ "h:mm:ss AM/PM",
173
+ "h:mm",
174
+ "h:mm:ss",
175
+ "m/d/yy h:mm",
176
+ "General",
177
+ "General",
178
+ "General",
179
+ "General",
180
+ "General",
181
+ "General",
182
+ "General",
183
+ "General",
184
+ "General",
185
+ "General",
186
+ "General",
187
+ "General",
188
+ "General",
189
+ "General",
190
+ "(#,##0_);(#,##0)",
191
+ "(#,##0_);[Red](#,##0)",
192
+ "(#,##0.00_);(#,##0.00)",
193
+ "(#,##0.00_);[Red](#,##0.00)",
194
+ "_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)",
195
+ "_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(@_)",
196
+ "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)",
197
+ "_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(@_)",
198
+ "mm:ss",
199
+ "[h]:mm:ss",
200
+ "mm:ss.0",
201
+ "##0.0E+0",
202
+ "@"
203
+ };
139
204
 
140
205
  LXW_INIT_ATTRIBUTES();
141
206
  LXW_PUSH_ATTRIBUTES_INT("numFmtId", num_fmt_id);
142
- LXW_PUSH_ATTRIBUTES_STR("formatCode", format_code);
207
+
208
+ if (num_fmt_id < 50)
209
+ LXW_PUSH_ATTRIBUTES_STR("formatCode", format_codes[num_fmt_id]);
210
+ else if (num_fmt_id < 164)
211
+ LXW_PUSH_ATTRIBUTES_STR("formatCode", "General");
212
+ else
213
+ LXW_PUSH_ATTRIBUTES_STR("formatCode", format_code);
143
214
 
144
215
  lxw_xml_empty_tag(self->file, "numFmt", &attributes);
145
216
 
@@ -240,6 +311,23 @@ _write_font_color_rgb(lxw_styles *self, int32_t rgb)
240
311
  LXW_FREE_ATTRIBUTES();
241
312
  }
242
313
 
314
+ /*
315
+ * Write the <color> element for indexed colors.
316
+ */
317
+ STATIC void
318
+ _write_font_color_indexed(lxw_styles *self, uint8_t index)
319
+ {
320
+ struct xml_attribute_list attributes;
321
+ struct xml_attribute *attribute;
322
+
323
+ LXW_INIT_ATTRIBUTES();
324
+ LXW_PUSH_ATTRIBUTES_INT("indexed", index);
325
+
326
+ lxw_xml_empty_tag(self->file, "color", &attributes);
327
+
328
+ LXW_FREE_ATTRIBUTES();
329
+ }
330
+
243
331
  /*
244
332
  * Write the <name> element.
245
333
  */
@@ -329,11 +417,45 @@ _write_font_underline(lxw_styles *self, uint8_t underline)
329
417
 
330
418
  }
331
419
 
420
+ /*
421
+ * Write the font <condense> element.
422
+ */
423
+ STATIC void
424
+ _write_font_condense(lxw_styles *self)
425
+ {
426
+ struct xml_attribute_list attributes;
427
+ struct xml_attribute *attribute;
428
+
429
+ LXW_INIT_ATTRIBUTES();
430
+ LXW_PUSH_ATTRIBUTES_STR("val", "0");
431
+
432
+ lxw_xml_empty_tag(self->file, "condense", &attributes);
433
+
434
+ LXW_FREE_ATTRIBUTES();
435
+ }
436
+
437
+ /*
438
+ * Write the font <extend> element.
439
+ */
440
+ STATIC void
441
+ _write_font_extend(lxw_styles *self)
442
+ {
443
+ struct xml_attribute_list attributes;
444
+ struct xml_attribute *attribute;
445
+
446
+ LXW_INIT_ATTRIBUTES();
447
+ LXW_PUSH_ATTRIBUTES_STR("val", "0");
448
+
449
+ lxw_xml_empty_tag(self->file, "extend", &attributes);
450
+
451
+ LXW_FREE_ATTRIBUTES();
452
+ }
453
+
332
454
  /*
333
455
  * Write the <vertAlign> font sub-element.
334
456
  */
335
457
  STATIC void
336
- _write_vert_align(lxw_styles *self, const char *align)
458
+ _write_font_vert_align(lxw_styles *self, const char *align)
337
459
  {
338
460
  struct xml_attribute_list attributes;
339
461
  struct xml_attribute *attribute;
@@ -350,13 +472,20 @@ _write_vert_align(lxw_styles *self, const char *align)
350
472
  * Write the <font> element.
351
473
  */
352
474
  STATIC void
353
- _write_font(lxw_styles *self, lxw_format *format, uint8_t is_rich_string)
475
+ _write_font(lxw_styles *self, lxw_format *format, uint8_t is_dxf,
476
+ uint8_t is_rich_string)
354
477
  {
355
478
  if (is_rich_string)
356
479
  lxw_xml_start_tag(self->file, "rPr", NULL);
357
480
  else
358
481
  lxw_xml_start_tag(self->file, "font", NULL);
359
482
 
483
+ if (format->font_condense)
484
+ _write_font_condense(self);
485
+
486
+ if (format->font_extend)
487
+ _write_font_extend(self);
488
+
360
489
  if (format->bold)
361
490
  lxw_xml_empty_tag(self->file, "b", NULL);
362
491
 
@@ -376,30 +505,41 @@ _write_font(lxw_styles *self, lxw_format *format, uint8_t is_rich_string)
376
505
  _write_font_underline(self, format->underline);
377
506
 
378
507
  if (format->font_script == LXW_FONT_SUPERSCRIPT)
379
- _write_vert_align(self, "superscript");
508
+ _write_font_vert_align(self, "superscript");
380
509
 
381
510
  if (format->font_script == LXW_FONT_SUBSCRIPT)
382
- _write_vert_align(self, "subscript");
511
+ _write_font_vert_align(self, "subscript");
383
512
 
384
- if (format->font_size > 0.0)
513
+ if (!is_dxf && format->font_size > 0.0)
385
514
  _write_font_size(self, format->font_size);
386
515
 
387
516
  if (format->theme)
388
517
  _write_font_color_theme(self, format->theme);
518
+ else if (format->color_indexed)
519
+ _write_font_color_indexed(self, format->color_indexed);
389
520
  else if (format->font_color != LXW_COLOR_UNSET)
390
521
  _write_font_color_rgb(self, format->font_color);
391
- else
522
+ else if (!is_dxf)
392
523
  _write_font_color_theme(self, LXW_DEFAULT_FONT_THEME);
393
524
 
394
- _write_font_name(self, format->font_name, is_rich_string);
395
- _write_font_family(self, format->font_family);
525
+ if (!is_dxf) {
526
+ _write_font_name(self, format->font_name, is_rich_string);
527
+ _write_font_family(self, format->font_family);
396
528
 
397
- /* Only write the scheme element for the default font type if it
398
- * is a hyperlink. */
399
- if ((!*format->font_name
400
- || strcmp(LXW_DEFAULT_FONT_NAME, format->font_name) == 0)
401
- && !format->hyperlink) {
402
- _write_font_scheme(self, format->font_scheme);
529
+ /* Only write the scheme element for the default font type if it
530
+ * is a hyperlink. */
531
+ if ((!*format->font_name
532
+ || strcmp(LXW_DEFAULT_FONT_NAME, format->font_name) == 0)
533
+ && !format->hyperlink) {
534
+ _write_font_scheme(self, format->font_scheme);
535
+ }
536
+ }
537
+
538
+ if (format->hyperlink) {
539
+ self->has_hyperlink = LXW_TRUE;
540
+
541
+ if (self->hyperlink_font_id == 0)
542
+ self->hyperlink_font_id = format->font_index;
403
543
  }
404
544
 
405
545
  if (is_rich_string)
@@ -408,6 +548,22 @@ _write_font(lxw_styles *self, lxw_format *format, uint8_t is_rich_string)
408
548
  lxw_xml_end_tag(self->file, "font");
409
549
  }
410
550
 
551
+ /*
552
+ * Write the <font> element for comments.
553
+ */
554
+ STATIC void
555
+ _write_comment_font(lxw_styles *self)
556
+ {
557
+ lxw_xml_start_tag(self->file, "font", NULL);
558
+
559
+ _write_font_size(self, 8);
560
+ _write_font_color_indexed(self, 81);
561
+ _write_font_name(self, "Tahoma", LXW_FALSE);
562
+ _write_font_family(self, 2);
563
+
564
+ lxw_xml_end_tag(self->file, "font");
565
+ }
566
+
411
567
  /*
412
568
  * Write the <fonts> element.
413
569
  */
@@ -417,17 +573,26 @@ _write_fonts(lxw_styles *self)
417
573
  struct xml_attribute_list attributes;
418
574
  struct xml_attribute *attribute;
419
575
  lxw_format *format;
576
+ uint32_t count;
420
577
 
421
578
  LXW_INIT_ATTRIBUTES();
422
- LXW_PUSH_ATTRIBUTES_INT("count", self->font_count);
579
+
580
+ count = self->font_count;
581
+ if (self->has_comments)
582
+ count++;
583
+
584
+ LXW_PUSH_ATTRIBUTES_INT("count", count);
423
585
 
424
586
  lxw_xml_start_tag(self->file, "fonts", &attributes);
425
587
 
426
588
  STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
427
589
  if (format->has_font)
428
- _write_font(self, format, LXW_FALSE);
590
+ _write_font(self, format, LXW_FALSE, LXW_FALSE);
429
591
  }
430
592
 
593
+ if (self->has_comments)
594
+ _write_comment_font(self);
595
+
431
596
  lxw_xml_end_tag(self->file, "fonts");
432
597
 
433
598
  LXW_FREE_ATTRIBUTES();
@@ -476,7 +641,7 @@ _write_fg_color(lxw_styles *self, lxw_color_t color)
476
641
  * Write the <bgColor> element.
477
642
  */
478
643
  STATIC void
479
- _write_bg_color(lxw_styles *self, lxw_color_t color)
644
+ _write_bg_color(lxw_styles *self, lxw_color_t color, uint8_t pattern)
480
645
  {
481
646
  struct xml_attribute_list attributes;
482
647
  struct xml_attribute *attribute;
@@ -485,15 +650,17 @@ _write_bg_color(lxw_styles *self, lxw_color_t color)
485
650
  LXW_INIT_ATTRIBUTES();
486
651
 
487
652
  if (color == LXW_COLOR_UNSET) {
488
- LXW_PUSH_ATTRIBUTES_STR("indexed", "64");
653
+ if (pattern <= LXW_PATTERN_SOLID) {
654
+ LXW_PUSH_ATTRIBUTES_STR("indexed", "64");
655
+ lxw_xml_empty_tag(self->file, "bgColor", &attributes);
656
+ }
489
657
  }
490
658
  else {
491
659
  lxw_snprintf(rgb_str, LXW_ATTR_32, "FF%06X", color & LXW_COLOR_MASK);
492
660
  LXW_PUSH_ATTRIBUTES_STR("rgb", rgb_str);
661
+ lxw_xml_empty_tag(self->file, "bgColor", &attributes);
493
662
  }
494
663
 
495
- lxw_xml_empty_tag(self->file, "bgColor", &attributes);
496
-
497
664
  LXW_FREE_ATTRIBUTES();
498
665
  }
499
666
 
@@ -501,7 +668,7 @@ _write_bg_color(lxw_styles *self, lxw_color_t color)
501
668
  * Write the <fill> element.
502
669
  */
503
670
  STATIC void
504
- _write_fill(lxw_styles *self, lxw_format *format)
671
+ _write_fill(lxw_styles *self, lxw_format *format, uint8_t is_dxf)
505
672
  {
506
673
  struct xml_attribute_list attributes;
507
674
  struct xml_attribute *attribute;
@@ -532,11 +699,24 @@ _write_fill(lxw_styles *self, lxw_format *format)
532
699
  "gray0625",
533
700
  };
534
701
 
702
+ if (is_dxf) {
703
+ bg_color = format->dxf_bg_color;
704
+ fg_color = format->dxf_fg_color;
705
+ }
706
+
535
707
  LXW_INIT_ATTRIBUTES();
536
708
 
709
+ /* Special handling for pattern only case. */
710
+ if (!bg_color && !fg_color && pattern) {
711
+ _write_default_fill(self, patterns[pattern]);
712
+ LXW_FREE_ATTRIBUTES();
713
+ return;
714
+ }
715
+
537
716
  lxw_xml_start_tag(self->file, "fill", NULL);
538
717
 
539
- if (pattern)
718
+ /* None/Solid patterns are handled differently for dxf formats. */
719
+ if (pattern && !(is_dxf && pattern <= LXW_PATTERN_SOLID))
540
720
  LXW_PUSH_ATTRIBUTES_STR("patternType", patterns[pattern]);
541
721
 
542
722
  lxw_xml_start_tag(self->file, "patternFill", &attributes);
@@ -544,7 +724,7 @@ _write_fill(lxw_styles *self, lxw_format *format)
544
724
  if (fg_color != LXW_COLOR_UNSET)
545
725
  _write_fg_color(self, fg_color);
546
726
 
547
- _write_bg_color(self, bg_color);
727
+ _write_bg_color(self, bg_color, pattern);
548
728
 
549
729
  lxw_xml_end_tag(self->file, "patternFill");
550
730
  lxw_xml_end_tag(self->file, "fill");
@@ -573,7 +753,7 @@ _write_fills(lxw_styles *self)
573
753
 
574
754
  STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
575
755
  if (format->has_fill)
576
- _write_fill(self, format);
756
+ _write_fill(self, format, LXW_FALSE);
577
757
  }
578
758
 
579
759
  lxw_xml_end_tag(self->file, "fills");
@@ -654,7 +834,7 @@ _write_sub_border(lxw_styles *self, const char *type, uint8_t style,
654
834
  * Write the <border> element.
655
835
  */
656
836
  STATIC void
657
- _write_border(lxw_styles *self, lxw_format *format)
837
+ _write_border(lxw_styles *self, lxw_format *format, uint8_t is_dxf)
658
838
  {
659
839
  struct xml_attribute_list attributes;
660
840
  struct xml_attribute *attribute;
@@ -675,7 +855,7 @@ _write_border(lxw_styles *self, lxw_format *format)
675
855
 
676
856
  /* Ensure that a default diag border is set if the diag type is set. */
677
857
  if (format->diag_type && !format->diag_border) {
678
- format->diag_border = 1;
858
+ format->diag_border = LXW_BORDER_THIN;
679
859
  }
680
860
 
681
861
  /* Write the start border tag. */
@@ -686,8 +866,16 @@ _write_border(lxw_styles *self, lxw_format *format)
686
866
  _write_sub_border(self, "right", format->right, format->right_color);
687
867
  _write_sub_border(self, "top", format->top, format->top_color);
688
868
  _write_sub_border(self, "bottom", format->bottom, format->bottom_color);
689
- _write_sub_border(self,
690
- "diagonal", format->diag_border, format->diag_color);
869
+
870
+ if (is_dxf) {
871
+ _write_sub_border(self, "vertical", 0, LXW_COLOR_UNSET);
872
+ _write_sub_border(self, "horizontal", 0, LXW_COLOR_UNSET);
873
+ }
874
+
875
+ /* Conditional DXF formats don't allow diagonal borders. */
876
+ if (!is_dxf)
877
+ _write_sub_border(self, "diagonal",
878
+ format->diag_border, format->diag_color);
691
879
 
692
880
  lxw_xml_end_tag(self->file, "border");
693
881
 
@@ -711,7 +899,7 @@ _write_borders(lxw_styles *self)
711
899
 
712
900
  STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
713
901
  if (format->has_border)
714
- _write_border(self, format);
902
+ _write_border(self, format, LXW_FALSE);
715
903
  }
716
904
 
717
905
  lxw_xml_end_tag(self->file, "borders");
@@ -719,22 +907,70 @@ _write_borders(lxw_styles *self)
719
907
  LXW_FREE_ATTRIBUTES();
720
908
  }
721
909
 
910
+ /*
911
+ * Write the <alignment> element for hyperlinks.
912
+ */
913
+ STATIC void
914
+ _write_hyperlink_alignment(lxw_styles *self)
915
+ {
916
+ struct xml_attribute_list attributes;
917
+ struct xml_attribute *attribute;
918
+
919
+ LXW_INIT_ATTRIBUTES();
920
+ LXW_PUSH_ATTRIBUTES_STR("vertical", "top");
921
+
922
+ lxw_xml_empty_tag(self->file, "alignment", &attributes);
923
+
924
+ LXW_FREE_ATTRIBUTES();
925
+ }
926
+
927
+ /*
928
+ * Write the <protection> element for hyperlinks.
929
+ */
930
+ STATIC void
931
+ _write_hyperlink_protection(lxw_styles *self)
932
+ {
933
+ struct xml_attribute_list attributes;
934
+ struct xml_attribute *attribute;
935
+
936
+ LXW_INIT_ATTRIBUTES();
937
+ LXW_PUSH_ATTRIBUTES_STR("locked", "0");
938
+
939
+ lxw_xml_empty_tag(self->file, "protection", &attributes);
940
+
941
+ LXW_FREE_ATTRIBUTES();
942
+ }
943
+
722
944
  /*
723
945
  * Write the <xf> element for styles.
724
946
  */
725
947
  STATIC void
726
- _write_style_xf(lxw_styles *self)
948
+ _write_style_xf(lxw_styles *self, uint8_t has_hyperlink, uint16_t font_id)
727
949
  {
728
950
  struct xml_attribute_list attributes;
729
951
  struct xml_attribute *attribute;
730
952
 
731
953
  LXW_INIT_ATTRIBUTES();
732
954
  LXW_PUSH_ATTRIBUTES_STR("numFmtId", "0");
733
- LXW_PUSH_ATTRIBUTES_STR("fontId", "0");
955
+ LXW_PUSH_ATTRIBUTES_INT("fontId", font_id);
734
956
  LXW_PUSH_ATTRIBUTES_STR("fillId", "0");
735
957
  LXW_PUSH_ATTRIBUTES_STR("borderId", "0");
736
958
 
737
- lxw_xml_empty_tag(self->file, "xf", &attributes);
959
+ if (has_hyperlink) {
960
+ LXW_PUSH_ATTRIBUTES_STR("applyNumberFormat", "0");
961
+ LXW_PUSH_ATTRIBUTES_STR("applyFill", "0");
962
+ LXW_PUSH_ATTRIBUTES_STR("applyBorder", "0");
963
+ LXW_PUSH_ATTRIBUTES_STR("applyAlignment", "0");
964
+ LXW_PUSH_ATTRIBUTES_STR("applyProtection", "0");
965
+
966
+ lxw_xml_start_tag(self->file, "xf", &attributes);
967
+ _write_hyperlink_alignment(self);
968
+ _write_hyperlink_protection(self);
969
+ lxw_xml_end_tag(self->file, "xf");
970
+ }
971
+ else {
972
+ lxw_xml_empty_tag(self->file, "xf", &attributes);
973
+ }
738
974
 
739
975
  LXW_FREE_ATTRIBUTES();
740
976
  }
@@ -749,10 +985,18 @@ _write_cell_style_xfs(lxw_styles *self)
749
985
  struct xml_attribute *attribute;
750
986
 
751
987
  LXW_INIT_ATTRIBUTES();
752
- LXW_PUSH_ATTRIBUTES_STR("count", "1");
988
+
989
+ if (self->has_hyperlink)
990
+ LXW_PUSH_ATTRIBUTES_STR("count", "2");
991
+ else
992
+ LXW_PUSH_ATTRIBUTES_STR("count", "1");
753
993
 
754
994
  lxw_xml_start_tag(self->file, "cellStyleXfs", &attributes);
755
- _write_style_xf(self);
995
+ _write_style_xf(self, LXW_FALSE, 0);
996
+
997
+ if (self->has_hyperlink)
998
+ _write_style_xf(self, self->has_hyperlink, self->hyperlink_font_id);
999
+
756
1000
  lxw_xml_end_tag(self->file, "cellStyleXfs");
757
1001
 
758
1002
  LXW_FREE_ATTRIBUTES();
@@ -936,13 +1180,16 @@ _write_xf(lxw_styles *self, lxw_format *format)
936
1180
  LXW_PUSH_ATTRIBUTES_INT("fontId", format->font_index);
937
1181
  LXW_PUSH_ATTRIBUTES_INT("fillId", format->fill_index);
938
1182
  LXW_PUSH_ATTRIBUTES_INT("borderId", format->border_index);
939
- LXW_PUSH_ATTRIBUTES_STR("xfId", "0");
1183
+ LXW_PUSH_ATTRIBUTES_INT("xfId", format->xf_id);
1184
+
1185
+ if (format->quote_prefix)
1186
+ LXW_PUSH_ATTRIBUTES_STR("quotePrefix", "1");
940
1187
 
941
1188
  if (format->num_format_index > 0)
942
1189
  LXW_PUSH_ATTRIBUTES_STR("applyNumberFormat", "1");
943
1190
 
944
1191
  /* Add applyFont attribute if XF format uses a font element. */
945
- if (format->font_index > 0)
1192
+ if (format->font_index > 0 && !format->hyperlink)
946
1193
  LXW_PUSH_ATTRIBUTES_STR("applyFont", "1");
947
1194
 
948
1195
  /* Add applyFill attribute if XF format uses a fill element. */
@@ -954,10 +1201,10 @@ _write_xf(lxw_styles *self, lxw_format *format)
954
1201
  LXW_PUSH_ATTRIBUTES_STR("applyBorder", "1");
955
1202
 
956
1203
  /* We can also have applyAlignment without a sub-element. */
957
- if (apply_alignment)
1204
+ if (apply_alignment || format->hyperlink)
958
1205
  LXW_PUSH_ATTRIBUTES_STR("applyAlignment", "1");
959
1206
 
960
- if (has_protection)
1207
+ if (has_protection || format->hyperlink)
961
1208
  LXW_PUSH_ATTRIBUTES_STR("applyProtection", "1");
962
1209
 
963
1210
  /* Write XF with sub-elements if required. */
@@ -988,14 +1235,27 @@ _write_cell_xfs(lxw_styles *self)
988
1235
  struct xml_attribute_list attributes;
989
1236
  struct xml_attribute *attribute;
990
1237
  lxw_format *format;
1238
+ uint32_t count = self->xf_count;
1239
+ uint32_t i = 0;
1240
+
1241
+ /* If the last format is "font_only" it is for the comment font and
1242
+ * shouldn't be counted. This is a workaround to get the last object
1243
+ * in the list since STAILQ_LAST() requires __containerof and isn't
1244
+ * ANSI compatible. */
1245
+ STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
1246
+ i++;
1247
+ if (i == self->xf_count && format->font_only)
1248
+ count--;
1249
+ }
991
1250
 
992
1251
  LXW_INIT_ATTRIBUTES();
993
- LXW_PUSH_ATTRIBUTES_INT("count", self->xf_count);
1252
+ LXW_PUSH_ATTRIBUTES_INT("count", count);
994
1253
 
995
1254
  lxw_xml_start_tag(self->file, "cellXfs", &attributes);
996
1255
 
997
1256
  STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
998
- _write_xf(self, format);
1257
+ if (!format->font_only)
1258
+ _write_xf(self, format);
999
1259
  }
1000
1260
 
1001
1261
  lxw_xml_end_tag(self->file, "cellXfs");
@@ -1007,15 +1267,16 @@ _write_cell_xfs(lxw_styles *self)
1007
1267
  * Write the <cellStyle> element.
1008
1268
  */
1009
1269
  STATIC void
1010
- _write_cell_style(lxw_styles *self)
1270
+ _write_cell_style(lxw_styles *self, char *name, uint8_t xf_id,
1271
+ uint8_t builtin_id)
1011
1272
  {
1012
1273
  struct xml_attribute_list attributes;
1013
1274
  struct xml_attribute *attribute;
1014
1275
 
1015
1276
  LXW_INIT_ATTRIBUTES();
1016
- LXW_PUSH_ATTRIBUTES_STR("name", "Normal");
1017
- LXW_PUSH_ATTRIBUTES_STR("xfId", "0");
1018
- LXW_PUSH_ATTRIBUTES_STR("builtinId", "0");
1277
+ LXW_PUSH_ATTRIBUTES_STR("name", name);
1278
+ LXW_PUSH_ATTRIBUTES_INT("xfId", xf_id);
1279
+ LXW_PUSH_ATTRIBUTES_INT("builtinId", builtin_id);
1019
1280
 
1020
1281
  lxw_xml_empty_tag(self->file, "cellStyle", &attributes);
1021
1282
 
@@ -1031,10 +1292,19 @@ _write_cell_styles(lxw_styles *self)
1031
1292
  struct xml_attribute_list attributes;
1032
1293
  struct xml_attribute *attribute;
1033
1294
  LXW_INIT_ATTRIBUTES();
1034
- LXW_PUSH_ATTRIBUTES_STR("count", "1");
1295
+
1296
+ if (self->has_hyperlink)
1297
+ LXW_PUSH_ATTRIBUTES_STR("count", "2");
1298
+ else
1299
+ LXW_PUSH_ATTRIBUTES_STR("count", "1");
1035
1300
 
1036
1301
  lxw_xml_start_tag(self->file, "cellStyles", &attributes);
1037
- _write_cell_style(self);
1302
+
1303
+ if (self->has_hyperlink)
1304
+ _write_cell_style(self, "Hyperlink", 1, 8);
1305
+
1306
+ _write_cell_style(self, "Normal", 0, 0);
1307
+
1038
1308
  lxw_xml_end_tag(self->file, "cellStyles");
1039
1309
 
1040
1310
  LXW_FREE_ATTRIBUTES();
@@ -1042,18 +1312,46 @@ _write_cell_styles(lxw_styles *self)
1042
1312
 
1043
1313
  /*
1044
1314
  * Write the <dxfs> element.
1315
+ *
1045
1316
  */
1046
1317
  STATIC void
1047
1318
  _write_dxfs(lxw_styles *self)
1048
1319
  {
1049
1320
  struct xml_attribute_list attributes;
1050
1321
  struct xml_attribute *attribute;
1322
+ lxw_format *format;
1323
+ uint32_t count = self->dxf_count;
1051
1324
 
1052
1325
  LXW_INIT_ATTRIBUTES();
1053
- LXW_PUSH_ATTRIBUTES_STR("count", "0");
1326
+ LXW_PUSH_ATTRIBUTES_INT("count", count);
1327
+
1328
+ if (count) {
1329
+ lxw_xml_start_tag(self->file, "dxfs", &attributes);
1330
+
1331
+ STAILQ_FOREACH(format, self->dxf_formats, list_pointers) {
1332
+ lxw_xml_start_tag(self->file, "dxf", NULL);
1333
+
1334
+ if (format->has_dxf_font)
1335
+ _write_font(self, format, LXW_TRUE, LXW_FALSE);
1054
1336
 
1055
- lxw_xml_empty_tag(self->file, "dxfs", &attributes);
1337
+ if (format->num_format_index)
1338
+ _write_num_fmt(self, format->num_format_index,
1339
+ format->num_format);
1056
1340
 
1341
+ if (format->has_dxf_fill)
1342
+ _write_fill(self, format, LXW_TRUE);
1343
+
1344
+ if (format->has_dxf_border)
1345
+ _write_border(self, format, LXW_TRUE);
1346
+
1347
+ lxw_xml_end_tag(self->file, "dxf");
1348
+ }
1349
+
1350
+ lxw_xml_end_tag(self->file, "dxfs");
1351
+ }
1352
+ else {
1353
+ lxw_xml_empty_tag(self->file, "dxfs", &attributes);
1354
+ }
1057
1355
  LXW_FREE_ATTRIBUTES();
1058
1356
  }
1059
1357
 
@@ -1121,9 +1419,6 @@ lxw_styles_assemble_xml_file(lxw_styles *self)
1121
1419
  /* Write the tableStyles element. */
1122
1420
  _write_table_styles(self);
1123
1421
 
1124
- /* Write the colors element. */
1125
- /* _write_colors(self); */
1126
-
1127
1422
  /* Close the style sheet tag. */
1128
1423
  lxw_xml_end_tag(self->file, "styleSheet");
1129
1424
  }