mirror of
https://github.com/jmcnamara/libxlsxwriter.git
synced 2026-05-18 06:06:12 -06:00
404 lines
12 KiB
C
404 lines
12 KiB
C
/*
|
|
* libxlsxwriter
|
|
*
|
|
* Copyright 2014-2015, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
|
*/
|
|
|
|
/**
|
|
* @page workbook_page The Workbook object
|
|
*
|
|
* The Workbook is the main object exposed by the libxlsxwriter library. It
|
|
* represents the entire spreadsheet as you see it in Excel and internally it
|
|
* represents the Excel file as it is written on disk.
|
|
*
|
|
* See @ref workbook.h for full details of the functionality.
|
|
*
|
|
* @file workbook.h
|
|
*
|
|
* @brief Functions related to creating an Excel xlsx workbook.
|
|
*
|
|
* The Workbook is the main object exposed by the libxlsxwriter library. It
|
|
* represents the entire spreadsheet as you see it in Excel and internally it
|
|
* represents the Excel file as it is written on disk.
|
|
*
|
|
* @code
|
|
* #include "xlsxwriter.h"
|
|
*
|
|
* int main() {
|
|
*
|
|
* lxw_workbook *workbook = new_workbook("filename.xlsx");
|
|
* lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
|
*
|
|
* worksheet_write_string(worksheet, 0, 0, "Hello Excel", NULL);
|
|
*
|
|
* return workbook_close(workbook);
|
|
* }
|
|
* @endcode
|
|
*
|
|
* @image html workbook01.png
|
|
*
|
|
*/
|
|
#ifndef __LXW_WORKBOOK_H__
|
|
#define __LXW_WORKBOOK_H__
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include "xlsxwriter/third_party/queue.h"
|
|
|
|
#include "worksheet.h"
|
|
#include "shared_strings.h"
|
|
#include "hash_table.h"
|
|
#include "common.h"
|
|
|
|
/* Define the queue.h structs for the workbook lists. */
|
|
STAILQ_HEAD(lxw_worksheets, lxw_worksheet);
|
|
TAILQ_HEAD(lxw_defined_names, lxw_defined_name);
|
|
|
|
#define LXW_DEFINED_NAME_LENGTH 128
|
|
|
|
/**
|
|
* @brief Macro to loop over all the worksheets in a workbook.
|
|
*
|
|
* This macro allows you to loop over all the worksheets that have been
|
|
* added to a workbook. You must provide a lxw_worksheet pointer and
|
|
* a pointer to the lxw_workbook:
|
|
*
|
|
* @code
|
|
* lxw_workbook *workbook = new_workbook("test.xlsx");
|
|
*
|
|
* lxw_worksheet *worksheet; // Generic worksheet pointer.
|
|
*
|
|
* // Worksheet objects used in the program.
|
|
* lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, NULL);
|
|
* lxw_worksheet *worksheet2 = workbook_add_worksheet(workbook, NULL);
|
|
* lxw_worksheet *worksheet3 = workbook_add_worksheet(workbook, NULL);
|
|
*
|
|
* // Iterate over the 3 worksheets and perform the same operation on each.
|
|
* LXW_FOREACH_WORKSHEET(worksheet, workbook) {
|
|
* worksheet_write_string(worksheet, 0, 0, "Hello", NULL);
|
|
* }
|
|
* @endcode
|
|
*/
|
|
#define LXW_FOREACH_WORKSHEET(worksheet, workbook) \
|
|
STAILQ_FOREACH((worksheet), (workbook)->worksheets, list_pointers)
|
|
|
|
/* Struct to represent a defined name. */
|
|
typedef struct lxw_defined_name {
|
|
int16_t index;
|
|
uint8_t hidden;
|
|
char name[LXW_DEFINED_NAME_LENGTH];
|
|
char app_name[LXW_DEFINED_NAME_LENGTH];
|
|
char formula[LXW_DEFINED_NAME_LENGTH];
|
|
char normalised_name[LXW_DEFINED_NAME_LENGTH];
|
|
char normalised_sheetname[LXW_DEFINED_NAME_LENGTH];
|
|
|
|
/* List pointers for queue.h. */
|
|
TAILQ_ENTRY (lxw_defined_name) list_pointers;
|
|
} lxw_defined_name;
|
|
|
|
/**
|
|
* @brief Error codes from workbook functions.
|
|
*/
|
|
enum lxw_workbook_error {
|
|
/** No error */
|
|
LXW_ERROR_WORKBOOK_NONE = 0,
|
|
|
|
/** Error encountered when creating file */
|
|
LXW_ERROR_WORKBOOK_FILE_CREATE,
|
|
|
|
/** Error encountered when creating a packager object */
|
|
LXW_ERROR_WORKBOOK_PACKAGER,
|
|
|
|
/** Error encountered when creating file zip container */
|
|
LXW_ERROR_WORKBOOK_ZIP,
|
|
|
|
/** Memory error. */
|
|
LXW_ERROR_WORKBOOK_MEMORY_ERROR
|
|
};
|
|
|
|
/**
|
|
* @brief Workbook options.
|
|
*
|
|
* Optional parameters when creating a new Workbook object via
|
|
* new_workbook_opt().
|
|
*
|
|
* Currently only the `constant_memory` property is supported:
|
|
*
|
|
* * `constant_memory`
|
|
*/
|
|
typedef struct lxw_workbook_options {
|
|
/** Optimize the workbook to use constant memory for worksheets */
|
|
uint8_t constant_memory;
|
|
} lxw_workbook_options;
|
|
|
|
/**
|
|
* @brief Struct to represent an Excel workbook.
|
|
*
|
|
* The members of the lxw_workbook struct aren't modified directly. Instead
|
|
* the workbook properties are set by calling the functions shown in
|
|
* workbook.h.
|
|
*/
|
|
typedef struct lxw_workbook {
|
|
|
|
FILE *file;
|
|
struct lxw_worksheets *worksheets;
|
|
struct lxw_formats *formats;
|
|
struct lxw_defined_names *defined_names;
|
|
lxw_sst *sst;
|
|
lxw_doc_properties *properties;
|
|
char *filename;
|
|
lxw_workbook_options options;
|
|
|
|
uint16_t num_sheets;
|
|
uint16_t first_sheet;
|
|
uint32_t active_sheet;
|
|
uint16_t num_xf_formats;
|
|
uint16_t num_format_count;
|
|
|
|
uint16_t font_count;
|
|
uint16_t border_count;
|
|
uint16_t fill_count;
|
|
uint8_t optimize;
|
|
|
|
lxw_hash_table *used_xf_formats;
|
|
|
|
} lxw_workbook;
|
|
|
|
|
|
/* *INDENT-OFF* */
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
/* *INDENT-ON* */
|
|
|
|
/**
|
|
* @brief Create a new workbook object.
|
|
*
|
|
* @param filename The name of the new Excel file to create.
|
|
*
|
|
* @return A lxw_workbook instance.
|
|
*
|
|
* The `%new_workbook()` constructor is used to create a new Excel workbook
|
|
* with a given filename:
|
|
*
|
|
* @code
|
|
* lxw_workbook *workbook = new_workbook("filename.xlsx");
|
|
* @endcode
|
|
*
|
|
* When specifying a filename it is recommended that you use an `.xlsx`
|
|
* extension or Excel will generate a warning when opening the file.
|
|
*
|
|
*/
|
|
lxw_workbook *new_workbook(const char *filename);
|
|
|
|
/**
|
|
* @brief Create a new workbook object, and set the workbook options.
|
|
*
|
|
* @param filename The name of the new Excel file to create.
|
|
* @param options Workbook options.
|
|
*
|
|
* @return A lxw_workbook instance.
|
|
*
|
|
* This method is the same as the `new_workbook()` constructor but allows
|
|
* additional options to be set.
|
|
*
|
|
* @code
|
|
* lxw_workbook_options options = {.constant_memory = 1};
|
|
*
|
|
* lxw_workbook *workbook = new_workbook_opt("filename.xlsx", &options);
|
|
* @endcode
|
|
*
|
|
* Note, in this mode a row of data is written and then discarded when a cell
|
|
* in a new row is added via one of the worksheet `worksheet_write_*()`
|
|
* methods. Therefore, once this mode is active, data should be written in
|
|
* sequential row order.
|
|
*
|
|
* See @ref working_with_memory for more details.
|
|
*
|
|
*/
|
|
lxw_workbook *new_workbook_opt(const char *filename,
|
|
lxw_workbook_options *options);
|
|
|
|
/**
|
|
* @brief Add a new worksheet to a workbook:
|
|
*
|
|
* @param workbook Pointer to a lxw_workbook instance.
|
|
* @param sheetname Optional worksheet name, defaults to Sheet1, etc.
|
|
*
|
|
* @return A lxw_worksheet instance.
|
|
*
|
|
* The `%workbook_add_worksheet()` method adds a new worksheet to a workbook:
|
|
*
|
|
* At least one worksheet should be added to a new workbook: The @ref
|
|
* worksheet.h "Worksheet" object is used to write data and configure a
|
|
* worksheet in the workbook.
|
|
*
|
|
* The `sheetname` parameter is optional. If it is `NULL` the default
|
|
* Excel convention will be followed, i.e. Sheet1, Sheet2, etc.:
|
|
*
|
|
* @code
|
|
* worksheet = workbook_add_worksheet(workbook, NULL ); // Sheet1
|
|
* worksheet = workbook_add_worksheet(workbook, "Foglio2"); // Foglio2
|
|
* worksheet = workbook_add_worksheet(workbook, "Data"); // Data
|
|
* worksheet = workbook_add_worksheet(workbook, NULL ); // Sheet4
|
|
*
|
|
* @endcode
|
|
*
|
|
* @image html workbook02.png
|
|
*
|
|
* The worksheet name must be a valid Excel worksheet name, i.e. it must be
|
|
* less than 32 character and it cannot contain any of the characters:
|
|
*
|
|
* / \ [ ] : * ?
|
|
*
|
|
* In addition, you cannot use the same, case insensitive, `sheetname` for more
|
|
* than one worksheet.
|
|
*
|
|
*/
|
|
lxw_worksheet *workbook_add_worksheet(lxw_workbook *workbook,
|
|
const char *sheetname);
|
|
|
|
/**
|
|
* @brief Create a new @ref format.h "Format" object to formats cells in
|
|
* worksheets.
|
|
*
|
|
* @param workbook Pointer to a lxw_workbook instance.
|
|
*
|
|
* @return A lxw_format instance.
|
|
*
|
|
* The `workbook_add_format()` function can be used to create new @ref
|
|
* format.h "Format" objects which are used to apply formatting to a cell.
|
|
*
|
|
* @code
|
|
* // Create the Format.
|
|
* lxw_format *format = workbook_add_format(workbook);
|
|
*
|
|
* // Set some of the format properties.
|
|
* format_set_bold(format);
|
|
* format_set_font_color(format, LXW_COLOR_RED);
|
|
*
|
|
* // Use the format to change the text format in a cell.
|
|
* worksheet_write_string(worksheet, 0, 0, "Hello", format);
|
|
* @endcode
|
|
*
|
|
* See @ref format.h "the Format object" and @ref working_with_formats
|
|
* sections for more details about Format properties and how to set them.
|
|
*
|
|
*/
|
|
lxw_format *workbook_add_format(lxw_workbook *workbook);
|
|
|
|
/**
|
|
* @brief Close the Workbook object and write the XLSX file.
|
|
*
|
|
* @param workbook Pointer to a lxw_workbook instance.
|
|
*
|
|
* @return A #lxw_workbook_error.
|
|
*
|
|
* The `%workbook_close()` function closes a Workbook object, writes the Excel
|
|
* file to disk, frees any memory allocated internally to the Workbook and
|
|
* frees the object itself.
|
|
*
|
|
* @code
|
|
* workbook_close(workbook);
|
|
* @endcode
|
|
*
|
|
* The `%workbook_close()` function returns any #lxw_workbook_error error codes
|
|
* encountered when creating the Excel file. The error code can be returned
|
|
* from the program main or the calling function:
|
|
*
|
|
* @code
|
|
* return workbook_close(workbook);
|
|
* @endcode
|
|
*
|
|
*/
|
|
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 error.
|
|
*
|
|
* 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
|
|
* [Microsoft 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);
|
|
|
|
/* Declarations required for unit testing. */
|
|
#ifdef TESTING
|
|
|
|
STATIC void _workbook_xml_declaration(lxw_workbook *self);
|
|
STATIC void _workbook_xml_declaration(lxw_workbook *self);
|
|
STATIC void _write_workbook(lxw_workbook *self);
|
|
STATIC void _write_file_version(lxw_workbook *self);
|
|
STATIC void _write_workbook_pr(lxw_workbook *self);
|
|
STATIC void _write_book_views(lxw_workbook *self);
|
|
STATIC void _write_workbook_view(lxw_workbook *self);
|
|
STATIC void _write_sheet(lxw_workbook *self,
|
|
const char *name, uint32_t sheet_id, uint8_t hidden);
|
|
STATIC void _write_sheets(lxw_workbook *self);
|
|
STATIC void _write_calc_pr(lxw_workbook *self);
|
|
|
|
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 *app_name, const char *formula,
|
|
int16_t index, uint8_t hidden);
|
|
|
|
#endif /* TESTING */
|
|
|
|
/* *INDENT-OFF* */
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
/* *INDENT-ON* */
|
|
|
|
#endif /* __LXW_WORKBOOK_H__ */
|