diff --git a/dev/release/fix_example_docs.pl b/dev/release/fix_example_docs.pl index eeb19183..d0e4f0a0 100644 --- a/dev/release/fix_example_docs.pl +++ b/dev/release/fix_example_docs.pl @@ -24,6 +24,7 @@ my @examples = ( [ 'dates_and_times03.c', 'Dates and times with different formats' ], [ 'utf8.c', 'A example of some UTF-8 text' ], [ 'constant_memory.c', 'Write a large file with constant memory usage' ], + [ 'defined_name.c', 'Example of how to create defined names' ], ); # Convert the array refs to a hash for lookups. diff --git a/docs/images/defined_name.png b/docs/images/defined_name.png new file mode 100644 index 00000000..793507e2 Binary files /dev/null and b/docs/images/defined_name.png differ diff --git a/docs/src/examples.dox b/docs/src/examples.dox index 4d64cc7e..0db5d6b1 100644 --- a/docs/src/examples.dox +++ b/docs/src/examples.dox @@ -92,11 +92,22 @@ A simple Unicode UTF-8 example. Note, the source file is UTF-8 encoded. Next example: @ref constant_memory.c @image html utf8.png + @example constant_memory.c Example of using libxlsxwriter for writing large files in constant memory mode. +Next example: @ref defined_name.c @image html constant_memory.png +@example defined_name.c +Example of how to create defined names (named ranges) using libxlsxwriter. + +Defined names are used to define descriptive names to represent a value, a +single cell or a range of cells in a workbook or worksheet. + +@image html defined_name.png + + */ diff --git a/examples/anatomy.c b/examples/anatomy.c index e798ec84..d364be7e 100644 --- a/examples/anatomy.c +++ b/examples/anatomy.c @@ -1,7 +1,7 @@ /* * Anatomy of a simple libxlsxwriter program. * - * Copyright 2014, John McNamara, jmcnamara@cpan.org + * Copyright 2014-2015, John McNamara, jmcnamara@cpan.org * */ diff --git a/examples/constant_memory.c b/examples/constant_memory.c index 33ea2ec9..69a39040 100644 --- a/examples/constant_memory.c +++ b/examples/constant_memory.c @@ -2,7 +2,7 @@ * Example of using libxlsxwriter for writing large files in constant memory * mode. * - * Copyright 2014, John McNamara, jmcnamara@cpan.org + * Copyright 2014-2015, John McNamara, jmcnamara@cpan.org * */ diff --git a/examples/dates_and_times01.c b/examples/dates_and_times01.c index 70b124e1..5caf8370 100644 --- a/examples/dates_and_times01.c +++ b/examples/dates_and_times01.c @@ -6,7 +6,7 @@ * An easier approach using a lxw_datetime struct is shown in example * dates_and_times02.c. * - * Copyright 2014, John McNamara, jmcnamara@cpan.org + * Copyright 2014-2015, John McNamara, jmcnamara@cpan.org * */ diff --git a/examples/dates_and_times02.c b/examples/dates_and_times02.c index 2a63c260..c6708547 100644 --- a/examples/dates_and_times02.c +++ b/examples/dates_and_times02.c @@ -2,7 +2,7 @@ * Example of writing dates and times in Excel using an lxw_datetime struct * and date formatting. * - * Copyright 2014, John McNamara, jmcnamara@cpan.org + * Copyright 2014-2015, John McNamara, jmcnamara@cpan.org * */ diff --git a/examples/dates_and_times03.c b/examples/dates_and_times03.c index 1ef36384..8c9e0f10 100644 --- a/examples/dates_and_times03.c +++ b/examples/dates_and_times03.c @@ -1,7 +1,7 @@ /* * Example of writing dates and times in Excel using different date formats. * - * Copyright 2014, John McNamara, jmcnamara@cpan.org + * Copyright 2014-2015, John McNamara, jmcnamara@cpan.org * */ diff --git a/examples/defined_name.c b/examples/defined_name.c new file mode 100644 index 00000000..dbd62403 --- /dev/null +++ b/examples/defined_name.c @@ -0,0 +1,57 @@ +/* + * Example of how to create defined names using libxlsxwriter. This method is + * used to define a user friendly name to represent a value, a single cell or + * a range of cells in a workbook. + * + * Copyright 2014-2015, John McNamara, jmcnamara@cpan.org + * + */ + +#include "xlsxwriter.h" + +int main() { + + lxw_workbook *workbook = new_workbook("defined_name.xlsx"); + lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, NULL); + lxw_worksheet *worksheet2 = workbook_add_worksheet(workbook, NULL); + + /* Define some global/workbook names. */ + workbook_define_name(workbook, "Sales", "=!G1:H10"); + + workbook_define_name(workbook, "Exchange_rate", "=0.96"); + workbook_define_name(workbook, "Sales", "=Sheet1!$G$1:$H$10"); + + /* Define a local/worksheet name. */ + workbook_define_name(workbook, "Sheet2!Sales", "=Sheet2!$G$1:$G$10"); + + /* Write some text to the first worksheet and a defined names in a formula. */ + worksheet_set_column(worksheet1, 0, 0, 45, NULL, NULL); + + worksheet_write_string(worksheet1, 0, 0, + "This worksheet contains some defined names.", NULL); + + worksheet_write_string(worksheet1, 1, 0, + "See Formulas -> Name Manager above.", NULL); + + worksheet_write_string(worksheet1, 2, 0, + "Example formula in cell B3 ->", NULL); + + worksheet_write_formula(worksheet1, 2, 1, "=Exchange_rate", NULL); + + /* Write some text to the second worksheet and a defined names in a formula. */ + worksheet_set_column(worksheet2, 0, 0, 45, NULL, NULL); + + worksheet_write_string(worksheet2, 0, 0, + "This worksheet contains some defined names.", NULL); + + worksheet_write_string(worksheet2, 1, 0, + "See Formulas -> Name Manager above.", NULL); + + worksheet_write_string(worksheet2, 2, 0, + "Example formula in cell B3 ->", NULL); + + worksheet_write_formula(worksheet2, 2, 1, "=Exchange_rate", NULL); + + + return workbook_close(workbook); +} diff --git a/examples/demo.c b/examples/demo.c index 8dc985fa..2c65bc31 100644 --- a/examples/demo.c +++ b/examples/demo.c @@ -1,7 +1,7 @@ /* * A simple example of some of the features of the libxlsxwriter library. * - * Copyright 2014, John McNamara, jmcnamara@cpan.org + * Copyright 2014-2015, John McNamara, jmcnamara@cpan.org * */ diff --git a/examples/format_font.c b/examples/format_font.c index 146fd177..f91ba059 100644 --- a/examples/format_font.c +++ b/examples/format_font.c @@ -2,7 +2,7 @@ * Example of writing some data with font formatting to a simple Excel * file using libxlsxwriter. * - * Copyright 2014, John McNamara, jmcnamara@cpan.org + * Copyright 2014-2015, John McNamara, jmcnamara@cpan.org * */ diff --git a/examples/format_num_format.c b/examples/format_num_format.c index 1dc9e089..9cd958a3 100644 --- a/examples/format_num_format.c +++ b/examples/format_num_format.c @@ -2,7 +2,7 @@ * Example of writing some data with numeric formatting to a simple Excel file * using libxlsxwriter. * - * Copyright 2014, John McNamara, jmcnamara@cpan.org + * Copyright 2014-2015, John McNamara, jmcnamara@cpan.org * */ diff --git a/examples/hello.c b/examples/hello.c index fce79e01..32c176ba 100644 --- a/examples/hello.c +++ b/examples/hello.c @@ -1,7 +1,7 @@ /* * Example of writing some data to a simple Excel file using libxlsxwriter. * - * Copyright 2014, John McNamara, jmcnamara@cpan.org + * Copyright 2014-2015, John McNamara, jmcnamara@cpan.org * */ diff --git a/examples/tutorial1.c b/examples/tutorial1.c index ae2df029..1ad194a1 100644 --- a/examples/tutorial1.c +++ b/examples/tutorial1.c @@ -5,7 +5,7 @@ * This program is shown, with explanations, in Tutorial 1 of the * libxlsxwriter documentation. * - * Copyright 2014, John McNamara, jmcnamara@cpan.org + * Copyright 2014-2015, John McNamara, jmcnamara@cpan.org * */ diff --git a/examples/tutorial2.c b/examples/tutorial2.c index ec65ee75..dc79621a 100644 --- a/examples/tutorial2.c +++ b/examples/tutorial2.c @@ -5,7 +5,7 @@ * This program is shown, with explanations, in Tutorial 2 of the * libxlsxwriter documentation. * - * Copyright 2014, John McNamara, jmcnamara@cpan.org + * Copyright 2014-2015, John McNamara, jmcnamara@cpan.org * */ diff --git a/examples/tutorial3.c b/examples/tutorial3.c index 311a9493..1e01d39f 100644 --- a/examples/tutorial3.c +++ b/examples/tutorial3.c @@ -5,7 +5,7 @@ * This program is shown, with explanations, in Tutorial 3 of the * libxlsxwriter documentation. * - * Copyright 2014, John McNamara, jmcnamara@cpan.org + * Copyright 2014-2015, John McNamara, jmcnamara@cpan.org * */ diff --git a/examples/utf8.c b/examples/utf8.c index 3f9f1330..38750c73 100644 --- a/examples/utf8.c +++ b/examples/utf8.c @@ -3,7 +3,7 @@ * * Note: The source file must be UTF-8 encoded. * - * Copyright 2014, John McNamara, jmcnamara@cpan.org + * Copyright 2014-2015, John McNamara, jmcnamara@cpan.org * */ diff --git a/include/xlsxwriter/utility.h b/include/xlsxwriter/utility.h index 4ab4a2b5..329b5bb1 100644 --- a/include/xlsxwriter/utility.h +++ b/include/xlsxwriter/utility.h @@ -128,6 +128,8 @@ double _datetime_to_excel_date(lxw_datetime *datetime, uint8_t date_1904); char *lxw_strdup(const char *str); +void lxw_str_tolower(char *str); + FILE *lxw_tmpfile(void); /* Declarations required for unit testing. */ diff --git a/include/xlsxwriter/workbook.h b/include/xlsxwriter/workbook.h index 00c78ed7..ea320164 100644 --- a/include/xlsxwriter/workbook.h +++ b/include/xlsxwriter/workbook.h @@ -51,7 +51,7 @@ /* Define the queue.h structs for the workbook lists. */ STAILQ_HEAD(lxw_worksheets, lxw_worksheet); -LIST_HEAD(lxw_defined_names, lxw_defined_name); +TAILQ_HEAD(lxw_defined_names, lxw_defined_name); #define LXW_DEFINED_NAME_LENGTH 128 @@ -61,9 +61,11 @@ typedef struct lxw_defined_name { uint8_t hidden; char name[LXW_DEFINED_NAME_LENGTH]; char range[LXW_DEFINED_NAME_LENGTH]; + char normalised_name[LXW_DEFINED_NAME_LENGTH]; + char normalised_sheetname[LXW_DEFINED_NAME_LENGTH]; /* List pointers for queue.h. */ - LIST_ENTRY (lxw_defined_name) list_pointers; + TAILQ_ENTRY (lxw_defined_name) list_pointers; } lxw_defined_name; /** @@ -275,6 +277,58 @@ lxw_format *workbook_add_format(lxw_workbook *workbook); */ uint8_t workbook_close(lxw_workbook *workbook); +/** + * @brief Create a defined name in the workbook to use as a variable. + * + * @param workbook Pointer to a lxw_workbook instance. + * @param name The defined name. + * @param formula The cell or range that the defined name refers to. + * + * @return 0 for success, non-zero on errror. + * + * This method is used to defined a name that can be used to represent a + * value, a single cell or a range of cells in a workbook: These defined names + * can then be used in formulas: + * + * @code + * workbook_define_name(workbook, "Exchange_rate", "=0.96"); + * worksheet_write_formula(worksheet, 2, 1, "=Exchange_rate", NULL); + * + * @endcode + * + * @image html defined_name.png + * + * As in Excel a name defined like this is "global" to the workbook and can be + * referred to from any worksheet: + * + * @code + * // Global workbook name. + * workbook_define_name(workbook, "Sales", "=Sheet1!$G$1:$H$10"); + * @endcode + * + * It is also possible to define a local/worksheet name by prefixing it with + * the sheet name using the syntax `'sheetname!definedname'`: + * + * @code + * // Local worksheet name. + * workbook_define_name(workbook, "Sheet2!Sales", "=Sheet2!$G$1:$G$10"); + * @endcode + * + * If the sheet name contains spaces or special characters you must follow the + * Excel convention and enclose it in single quotes: + * + * @code + * workbook_define_name(workbook, "'New Data'!Sales", "=Sheet2!$G$1:$G$10"); + * @endcode + * + * The rules for names in Excel are explained in the + * [Miscrosoft Office +documentation](http://office.microsoft.com/en-001/excel-help/define-and-use-names-in-formulas-HA010147120.aspx). + * + */ +uint8_t workbook_define_name(lxw_workbook *workbook, const char *name, + const char *formula); + void _free_workbook(lxw_workbook *workbook); void _workbook_assemble_xml_file(lxw_workbook *workbook); void _set_default_xf_indices(lxw_workbook *workbook); @@ -298,6 +352,10 @@ STATIC void _write_defined_name(lxw_workbook *self, lxw_defined_name *define_name); STATIC void _write_defined_names(lxw_workbook *self); +STATIC uint8_t _store_defined_name(lxw_workbook *self, const char *name, + const char *formula, int16_t index, + uint8_t hidden); + #endif /* TESTING */ /* *INDENT-OFF* */ diff --git a/src/packager.c b/src/packager.c index d8cd1651..3b02cd60 100644 --- a/src/packager.c +++ b/src/packager.c @@ -169,19 +169,38 @@ _write_app_file(lxw_packager *self) { lxw_workbook *workbook = self->workbook; lxw_worksheet *worksheet; + lxw_defined_name *defined_name; lxw_app *app = _new_app(); - char num_sheets[ATTR_32] = { 0 }; + uint16_t named_range_count = 0; + char *tmp_name; + char number[ATTR_32] = { 0 }; app->file = lxw_tmpfile(); - __builtin_snprintf(num_sheets, ATTR_32, "%d", self->workbook->num_sheets); + __builtin_snprintf(number, ATTR_32, "%d", self->workbook->num_sheets); - _add_heading_pair(app, "Worksheets", num_sheets); + _add_heading_pair(app, "Worksheets", number); STAILQ_FOREACH(worksheet, workbook->worksheets, list_pointers) { _add_part_name(app, worksheet->name); } + /* Add the Named Ranges parts. */ + TAILQ_FOREACH(defined_name, workbook->defined_names, list_pointers) { + tmp_name = strstr(defined_name->name, "_xlnm."); + + if (!tmp_name) { + _add_part_name(app, defined_name->name); + named_range_count++; + } + } + + /* Add the Named Range heading pairs. */ + if (named_range_count) { + __builtin_snprintf(number, ATTR_32, "%d", named_range_count); + _add_heading_pair(app, "Named Ranges", number); + } + _app_assemble_xml_file(app); _add_file_to_zip(self, app->file, "docProps/app.xml"); diff --git a/src/utility.c b/src/utility.c index ee1670ed..3759b0e0 100644 --- a/src/utility.c +++ b/src/utility.c @@ -342,6 +342,16 @@ lxw_strdup(const char *str) return copy; } +/* Simple tolower() for strings. */ +void +lxw_str_tolower(char *str) +{ + int i; + + for (i = 0; str[i]; i++) + str[i] = tolower(str[i]); +} + /* * Thin wrapper for tmpfile() so it can be over-ridden with a safer version if * required. diff --git a/src/workbook.c b/src/workbook.c index c90a025b..393e9b8f 100644 --- a/src/workbook.c +++ b/src/workbook.c @@ -65,9 +65,9 @@ _free_workbook(lxw_workbook *workbook) } /* Free the defined_names in the workbook. */ - while (!LIST_EMPTY(workbook->defined_names)) { - defined_name = LIST_FIRST(workbook->defined_names); - LIST_REMOVE(defined_name, list_pointers); + while (!TAILQ_EMPTY(workbook->defined_names)) { + defined_name = TAILQ_FIRST(workbook->defined_names); + TAILQ_REMOVE(workbook->defined_names, defined_name, list_pointers); free(defined_name); } @@ -370,6 +370,141 @@ _prepare_workbook(lxw_workbook *self) } +/* + * Compare two defined_name structures. + */ +static int +_compare_defined_names(lxw_defined_name *a, lxw_defined_name *b) +{ + int res = strcmp(a->normalised_name, b->normalised_name); + + /* Primary comparison based on defined name. */ + if (res) + return res; + + /* Secondary comparison based on worksheet name. */ + res = strcmp(a->normalised_sheetname, b->normalised_sheetname); + return res; +} + +STATIC uint8_t +_store_defined_name(lxw_workbook *self, const char *name, + const char *formula, int16_t index, uint8_t hidden) +{ + lxw_worksheet *worksheet; + lxw_defined_name *defined_name; + lxw_defined_name *list_defined_name; + char name_copy[LXW_DEFINED_NAME_LENGTH]; + char *tmp_name; + char *worksheet_name; + + /* Do some checks on the input data */ + if (!name || !formula) + return 1; + + if (strlen(name) > LXW_DEFINED_NAME_LENGTH || + strlen(formula) > LXW_DEFINED_NAME_LENGTH) { + return 1; + } + + defined_name = calloc(1, sizeof(struct lxw_defined_name)); + RETURN_ON_MEM_ERROR(defined_name, 1); + + /* Copy the user input string. */ + strcpy(name_copy, name); + + /* Set the worksheet index or -1 for a global defined name. */ + defined_name->index = index; + defined_name->hidden = hidden; + + /* Check for local defined names like like "Sheet1!name". */ + tmp_name = strchr(name_copy, '!'); + + if (tmp_name != NULL) { + /* Split the string into the worksheet name and define name. */ + *tmp_name = '\0'; + tmp_name++; + worksheet_name = name_copy; + + /* Remove any worksheet quoting. */ + if (worksheet_name[0] == '\'') + worksheet_name++; + if (worksheet_name[strlen(worksheet_name) - 1] == '\'') + worksheet_name[strlen(worksheet_name) - 1] = '\0'; + + /* Search for worksheet name to get the equivalent worksheet index. */ + STAILQ_FOREACH(worksheet, self->worksheets, list_pointers) { + if (strcmp(worksheet_name, worksheet->name) == 0) { + defined_name->index = worksheet->index; + strcpy(defined_name->normalised_sheetname, worksheet_name); + } + } + + /* If we didn't find the worksheet name we exit. */ + if (defined_name->index == -1) + goto mem_error; + + strcpy(defined_name->name, tmp_name); + } + else { + /* For non-local names we just store the defined name string. */ + strcpy(defined_name->name, name_copy); + } + + /* We need to normalise the defined names for sorting. This involves + * removing any _xlnm namespace from the string and converting it to + * lowercase. */ + tmp_name = strstr(defined_name->name, "_xlnm."); + + if (tmp_name != NULL) + strcpy(defined_name->normalised_name, tmp_name + 6); + else + strcpy(defined_name->normalised_name, defined_name->name); + + lxw_str_tolower(defined_name->normalised_name); + lxw_str_tolower(defined_name->normalised_sheetname); + + /* Strip leading "=" from the formula. */ + if (formula[0] == '=') + strcpy(defined_name->range, formula + 1); + else + strcpy(defined_name->range, formula); + + /* We add the defined name to the list in sorted order. */ + list_defined_name = TAILQ_FIRST(self->defined_names); + + if (list_defined_name == NULL || + _compare_defined_names(defined_name, list_defined_name) < 1) { + /* List is empty or defined name goes to the head. */ + TAILQ_INSERT_HEAD(self->defined_names, defined_name, list_pointers); + return 0; + } + + TAILQ_FOREACH(list_defined_name, self->defined_names, list_pointers) { + int res = _compare_defined_names(defined_name, list_defined_name); + + /* The entry already exists. We exit and don't overwrite. */ + if (res == 0) + goto mem_error; + + /* New defined name is inserted in sorted order before other entries. */ + if (res < 0) { + TAILQ_INSERT_BEFORE(list_defined_name, defined_name, + list_pointers); + return 0; + } + } + + /* If the entry wasn't less than any of the entries in the list we add it + * to the end. */ + TAILQ_INSERT_TAIL(self->defined_names, defined_name, list_pointers); + return 0; + +mem_error: + free(defined_name); + return 1; +} + /***************************************************************************** * * XML functions. @@ -578,12 +713,12 @@ _write_defined_names(lxw_workbook *self) { lxw_defined_name *defined_name; - if (LIST_EMPTY(self->defined_names)) + if (TAILQ_EMPTY(self->defined_names)) return; _xml_start_tag(self->file, "definedNames", NULL); - LIST_FOREACH(defined_name, self->defined_names, list_pointers) { + TAILQ_FOREACH(defined_name, self->defined_names, list_pointers) { _write_defined_name(self, defined_name); } @@ -675,7 +810,7 @@ new_workbook_opt(const char *filename, lxw_workbook_options *options) /* Add the defined_names list. */ workbook->defined_names = calloc(1, sizeof(struct lxw_defined_names)); GOTO_LABEL_ON_MEM_ERROR(workbook->defined_names, mem_error); - LIST_INIT(workbook->defined_names); + TAILQ_INIT(workbook->defined_names); /* Add the shared strings table. */ workbook->sst = _new_sst(); @@ -813,3 +948,14 @@ workbook_close(lxw_workbook *self) mem_error: return 1; } + +/* + * Create a defined name in Excel. We handle global/workbook level names and + * local/worksheet names. + */ +uint8_t +workbook_define_name(lxw_workbook *self, const char *name, + const char *formula) +{ + return _store_defined_name(self, name, formula, -1, 0); +} diff --git a/test/functional/src/test_defined_name02.c b/test/functional/src/test_defined_name02.c new file mode 100644 index 00000000..0e2c4061 --- /dev/null +++ b/test/functional/src/test_defined_name02.c @@ -0,0 +1,22 @@ +/***************************************************************************** + * Test cases for libxlsxwriter. + * + * Simple test case for defined names. + * + * Copyright 2014-2015, John McNamara, jmcnamara@cpan.org + * + */ + +#include "xlsxwriter.h" + +int main() { + + lxw_workbook *workbook = new_workbook("test_defined_name02.xlsx"); + lxw_worksheet *worksheet = workbook_add_worksheet(workbook, "sheet One"); + + workbook_define_name(workbook, "Sales", "='sheet One'!$G$1:$H$10"); + + (void)worksheet; + + return workbook_close(workbook); +} diff --git a/test/functional/src/test_defined_name03.c b/test/functional/src/test_defined_name03.c new file mode 100644 index 00000000..eb762e38 --- /dev/null +++ b/test/functional/src/test_defined_name03.c @@ -0,0 +1,22 @@ +/***************************************************************************** + * Test cases for libxlsxwriter. + * + * Simple test case for defined names. + * + * Copyright 2014-2015, John McNamara, jmcnamara@cpan.org + * + */ + +#include "xlsxwriter.h" + +int main() { + + lxw_workbook *workbook = new_workbook("test_defined_name03.xlsx"); + lxw_worksheet *worksheet = workbook_add_worksheet(workbook, "sheet One"); + + workbook_define_name(workbook, "Sales", "='sheet One'!G1:H10"); + + (void)worksheet; + + return workbook_close(workbook); +} diff --git a/test/functional/src/test_defined_name04.c b/test/functional/src/test_defined_name04.c new file mode 100644 index 00000000..429b37ff --- /dev/null +++ b/test/functional/src/test_defined_name04.c @@ -0,0 +1,27 @@ +/***************************************************************************** + * Test cases for libxlsxwriter. + * + * Simple test case for defined names. + * + * Copyright 2014-2015, John McNamara, jmcnamara@cpan.org + * + */ + +#include "xlsxwriter.h" + +int main() { + + lxw_workbook *workbook = new_workbook("test_defined_name04.xlsx"); + lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL); + + workbook_define_name(workbook, "\\__", "=Sheet1!$A$1"); + workbook_define_name(workbook, "a3f6", "=Sheet1!$A$2"); + workbook_define_name(workbook, "afoo.bar", "=Sheet1!$A$3"); + workbook_define_name(workbook, "étude", "=Sheet1!$A$4"); + workbook_define_name(workbook, "eésumé", "=Sheet1!$A$5"); + workbook_define_name(workbook, "a", "=Sheet1!$A$6"); + + (void)worksheet; + + return workbook_close(workbook); +} diff --git a/test/functional/test_defined_name.py b/test/functional/test_defined_name.py new file mode 100644 index 00000000..d84bbc87 --- /dev/null +++ b/test/functional/test_defined_name.py @@ -0,0 +1,27 @@ +############################################################################### +# +# Tests for libxlsxwriter. +# +# Copyright 2014-2015, John McNamara, jmcnamara@cpan.org +# + +import base_test_class + +class TestCompareXLSXFiles(base_test_class.XLSXBaseTest): + """ + Test file created with libxlsxwriter against a file created by Excel. + + """ + + # def test_defined_name01(self): + # self.run_exe_test('test_defined_name01') + + def test_defined_name02(self): + self.run_exe_test('test_defined_name02') + + def test_defined_name03(self): + self.run_exe_test('test_defined_name03') + + def test_defined_name04(self): + self.run_exe_test('test_defined_name04') + diff --git a/test/functional/xlsx_files/defined_name01.xlsx b/test/functional/xlsx_files/defined_name01.xlsx new file mode 100644 index 00000000..031b10e7 Binary files /dev/null and b/test/functional/xlsx_files/defined_name01.xlsx differ diff --git a/test/functional/xlsx_files/defined_name02.xlsx b/test/functional/xlsx_files/defined_name02.xlsx new file mode 100644 index 00000000..770b610a Binary files /dev/null and b/test/functional/xlsx_files/defined_name02.xlsx differ diff --git a/test/functional/xlsx_files/defined_name03.xlsx b/test/functional/xlsx_files/defined_name03.xlsx new file mode 100644 index 00000000..37e9f44a Binary files /dev/null and b/test/functional/xlsx_files/defined_name03.xlsx differ diff --git a/test/functional/xlsx_files/defined_name04.xlsx b/test/functional/xlsx_files/defined_name04.xlsx new file mode 100644 index 00000000..1e6d56e4 Binary files /dev/null and b/test/functional/xlsx_files/defined_name04.xlsx differ diff --git a/test/unit/workbook/test_workbook_write_defined_name.c b/test/unit/workbook/test_workbook_write_defined_name.c index b0cfdefb..ebf6e9d6 100644 --- a/test/unit/workbook/test_workbook_write_defined_name.c +++ b/test/unit/workbook/test_workbook_write_defined_name.c @@ -12,12 +12,10 @@ /* Test the _write_defined_name() method. */ CTEST(workbook, write_defined_name) { - - char* got; char exp[] = "Sheet1!$1:$1"; FILE* testfile = tmpfile(); - lxw_defined_name defined_name = {0, 0, "_xlnm.Print_Titles", "Sheet1!$1:$1", {NULL, NULL}}; + lxw_defined_name defined_name = {0, 0, "_xlnm.Print_Titles", "Sheet1!$1:$1", "", "", {NULL, NULL}}; lxw_workbook *workbook = new_workbook(NULL); diff --git a/test/unit/workbook/test_workbook_write_defined_names.c b/test/unit/workbook/test_workbook_write_defined_names.c index dd327414..56d068eb 100644 --- a/test/unit/workbook/test_workbook_write_defined_names.c +++ b/test/unit/workbook/test_workbook_write_defined_names.c @@ -17,15 +17,12 @@ CTEST(workbook, write_defined_names) { char* got; char exp[] = "Sheet1!$1:$1"; FILE* testfile = tmpfile(); - lxw_defined_name *defined_name = calloc(1, sizeof(struct lxw_defined_name)); - - strcpy(defined_name->name, "_xlnm.Print_Titles"); - strcpy(defined_name->range, "Sheet1!$1:$1"); - lxw_workbook *workbook = new_workbook(NULL); workbook->file = testfile; - LIST_INSERT_HEAD(workbook->defined_names, defined_name, list_pointers); + workbook_add_worksheet(workbook, NULL); + + _store_defined_name(workbook, "_xlnm.Print_Titles", "Sheet1!$1:$1", 0, 0); _write_defined_names(workbook); @@ -34,3 +31,36 @@ CTEST(workbook, write_defined_names) { _free_workbook(workbook); } + + +/* Test the _write_defined_name() method. */ +CTEST(workbook, write_defined_names_sorted) { + char* got; + char exp[] = "Sheet1!$A$1Sheet1!$A$1Sheet2!$A$1Sheet1!$A$1'Sheet 3'!$A$1Sheet1!$A$1Sheet2!$A$10.98\"Saab 900\""; + FILE* testfile = tmpfile(); + + + lxw_workbook *workbook = new_workbook(NULL); + workbook->file = testfile; + + workbook_add_worksheet(workbook, NULL); + workbook_add_worksheet(workbook, NULL); + workbook_add_worksheet(workbook, "Sheet 3"); + + + workbook_define_name(workbook, "'Sheet 3'!Bar", "='Sheet 3'!$A$1"); + workbook_define_name(workbook, "Abc", "=Sheet1!$A$1" ); + workbook_define_name(workbook, "Baz", "=0.98" ); + workbook_define_name(workbook, "Sheet1!Bar", "=Sheet1!$A$1" ); + workbook_define_name(workbook, "Sheet2!Bar", "=Sheet2!$A$1" ); + workbook_define_name(workbook, "Sheet2!aaa", "=Sheet2!$A$1" ); + workbook_define_name(workbook, "'Sheet 3'!car", "=\"Saab 900\"" ); + workbook_define_name(workbook, "_Egg", "=Sheet1!$A$1" ); + workbook_define_name(workbook, "_Fog", "=Sheet1!$A$1" ); + + _write_defined_names(workbook); + + RUN_XLSX_STREQ(exp, got); + + _free_workbook(workbook); +}