writexl/ 0000755 0001762 0000144 00000000000 14766116671 011767 5 ustar ligges users writexl/tests/ 0000755 0001762 0000144 00000000000 14766110233 013115 5 ustar ligges users writexl/tests/testthat/ 0000755 0001762 0000144 00000000000 14766116671 014771 5 ustar ligges users writexl/tests/testthat/test-types.R 0000644 0001762 0000144 00000002300 14747162622 017224 0 ustar ligges users context("Types")
roundtrip <- function(df){
readxl::read_xlsx(writexl::write_xlsx(df))
}
test_that("Types roundtrip properly",{
kremlin <- "http://\u043F\u0440\u0435\u0437\u0438\u0434\u0435\u043D\u0442.\u0440\u0444"
num <- c(NA_real_, pi, 1.2345e80)
int <- c(NA_integer_, 0L, -100L)
str <- c(NA_character_, "foo", kremlin) #note empty strings don't work yet
time <- Sys.time() + 1:3
bigint <- bit64::as.integer64(.Machine$integer.max) ^ c(0,1,1.5)
input <- data.frame(num = num, int = int, bigint = bigint, str = str, time = time, stringsAsFactors = FALSE)
expect_warning(output <- roundtrip(input), "int64")
output$bigint <- bit64::as.integer64(output$bigint)
attr(output$time, 'tzone') <- attr(time, 'tzone')
expect_equal(input, as.data.frame(output))
})
test_that("Writing formulas", {
df <- data.frame(
name = c("UCLA", "Berkeley"),
founded = c(1919, 1868),
website = xl_hyperlink(c("http://www.ucla.edu", "http://www.berkeley.edu"), "website")
)
# repeats a formula for entire column
df$age <- xl_formula('=(YEAR(TODAY()) - INDIRECT("B" & ROW()))')
# currently readxl does not support formulas so inspect manually
expect_true(file.exists(write_xlsx(df)))
})
writexl/tests/testthat/test-performance.R 0000644 0001762 0000144 00000000432 14747162622 020365 0 ustar ligges users context("Performance")
test_that("Performance is OK", {
tmp <- writexl::write_xlsx(nycflights13::flights)
out <- readxl::read_xlsx(tmp)
unlink(tmp)
attr(out$time_hour, 'tzone') <- attr(nycflights13::flights$time_hour, 'tzone')
expect_equal(out, nycflights13::flights)
})
writexl/tests/testthat.R 0000644 0001762 0000144 00000000072 14747162622 015107 0 ustar ligges users library(testthat)
library(writexl)
test_check("writexl")
writexl/tests/spelling.R 0000644 0001762 0000144 00000000074 14747162622 015066 0 ustar ligges users spelling::spell_check_test(vignettes = TRUE, error = FALSE)
writexl/MD5 0000644 0001762 0000144 00000011335 14766116671 012302 0 ustar ligges users b01873e09579d9f3c07231c779b65af0 *DESCRIPTION
1ee0683cce6d3479250337954c075d63 *LICENSE
90b3275c0bf168216e46188c580c1830 *NAMESPACE
e3c346df734133dc4fc4f192f1f76bde *NEWS
64565fbf5e6d3a999d0b1a2e3a916b3f *R/excel_types.R
737b6d239bec61b4b19e2e8b3b015a39 *R/version.R
bb2947c21d98f2cce4f1c4acc7dffce8 *R/write_xlsx.R
140af18107fff96197be0916c7435874 *inst/AUTHORS
71b6e204131683c365f4d8cad6dfb2ee *inst/COPYRIGHT
ee7896b1dfafac481ebdf4d546fff4df *inst/WORDLIST
5d6cd0aede82ee5950a2fc383d41f6ef *man/write_xlsx.Rd
12ee667a4a5b48eff478e33b3aed6871 *man/writexl.Rd
ca36be80c0269ac56ba7dcf8bcc92553 *man/xl_formula.Rd
f8dfd99994dfba815561a2dbb6cfad9c *src/Makevars
31a7709e2db76fe96b0882140c0b4c38 *src/include/xlsxwriter.h
10b5c3a7a260f6f743083781efd7700b *src/include/xlsxwriter/app.h
c20fb1f17597f5bf83f64439781e4b37 *src/include/xlsxwriter/chart.h
e4cfcdd589c1bb413736f64db5d2bf6b *src/include/xlsxwriter/chartsheet.h
071537b3ce0cc852a5946821f1ecfe67 *src/include/xlsxwriter/comment.h
8f54f1736db150b65a75aac49a152cc7 *src/include/xlsxwriter/common.h
a73bfc39bc562535088e1d6784fbc89b *src/include/xlsxwriter/content_types.h
f37b9b0112ac91f8231d9216eb9e5fe9 *src/include/xlsxwriter/core.h
0b2b733fee0227e9dbe02d683b78e148 *src/include/xlsxwriter/custom.h
2b6be1831bbe6f474223a82f9fcf4a45 *src/include/xlsxwriter/drawing.h
8ce9ec993f8991feacec63bc3260f571 *src/include/xlsxwriter/format.h
7e607de3bb08942f5026443932a2a597 *src/include/xlsxwriter/hash_table.h
672801489f8cc638672176d0a29110fe *src/include/xlsxwriter/metadata.h
37c9818b4a18bdb983e994aa26c3d07c *src/include/xlsxwriter/packager.h
795b637effc5f4eb933faaf138073e40 *src/include/xlsxwriter/relationships.h
cc681c406908cfaded98606bca983ab4 *src/include/xlsxwriter/shared_strings.h
39a266941448948034bbbcf68b18f6c6 *src/include/xlsxwriter/styles.h
fc39d05afe656cd3e2e3a8b849922eb3 *src/include/xlsxwriter/table.h
7a7a583c11fd42670ecc940520d8a20e *src/include/xlsxwriter/theme.h
418b9368e13d819a0b3111f9712cd175 *src/include/xlsxwriter/third_party/ioapi.h
9a78fb091fa245b64434692197e9b4f2 *src/include/xlsxwriter/third_party/md5.h
e396c26d747f73186edf08d48c83996b *src/include/xlsxwriter/third_party/queue.h
91ecc39f822ba460d99a451fec030cfa *src/include/xlsxwriter/third_party/tmpfileplus.h
de224c89e67700652f117cab66f4acbb *src/include/xlsxwriter/third_party/tree.h
6dc6de0874d78350319224058bf1ab51 *src/include/xlsxwriter/third_party/zip.h
5ad6668d4ab700b1032ec47147ef5345 *src/include/xlsxwriter/utility.h
4b7b607a4874f3c80c5f62e00500cacc *src/include/xlsxwriter/vml.h
ef1ffb06103bbcb28143c035757a5274 *src/include/xlsxwriter/workbook.h
7f1d4a420142941f39ab6c76086af533 *src/include/xlsxwriter/worksheet.h
edc7069a40bc558257b6ed11634978e8 *src/include/xlsxwriter/xmlwriter.h
885074bb45268485041f804e30f3a8a1 *src/libxlsxwriter/app.c
d272111e429a9abca52ea980e9c9f4f7 *src/libxlsxwriter/chart.c
a2e8dc5be6a4f0cbf5945125356ff19a *src/libxlsxwriter/chartsheet.c
d08a25a937a2fa206a81631a51fac32a *src/libxlsxwriter/comment.c
fd837352689d6e3a7e0938582e2b2c3d *src/libxlsxwriter/content_types.c
76f83de9800415ec5310ea6606cf47a7 *src/libxlsxwriter/core.c
c0a1928cfaa035513e6d38f72f57532f *src/libxlsxwriter/custom.c
188c52dc16d40b7b57011fba380a0a7d *src/libxlsxwriter/drawing.c
212f5abdf5b5b2be6963c26ff84ea567 *src/libxlsxwriter/format.c
fb9dcc18596b4b59a67114e30c4dbc7f *src/libxlsxwriter/hash_table.c
8a32f28028bef4d45afa448d8eb5f7f4 *src/libxlsxwriter/metadata.c
f1c1faf7759fda8ccdf0db2f734c0367 *src/libxlsxwriter/packager.c
2363bd3e88318fc34bac899c00641502 *src/libxlsxwriter/relationships.c
5da46bcea6824ab9d9e644fd41365f76 *src/libxlsxwriter/shared_strings.c
e487b52229bb8c482e6f03d59f81ecee *src/libxlsxwriter/styles.c
212b50ae2ae4fe04e5864184bf7116da *src/libxlsxwriter/table.c
f2c007cf68dd40c7b4f17ab870db3ed7 *src/libxlsxwriter/theme.c
ac80feed2f2dc692d791891555e713a3 *src/libxlsxwriter/utility.c
aa5a62f4e5b331571fb1ac9e9de27fdc *src/libxlsxwriter/vml.c
a4cd12f5732089282c851dc83ec7c100 *src/libxlsxwriter/workbook.c
0f1e7f3695b88b06a04aa0bee48f6a45 *src/libxlsxwriter/worksheet.c
42b2387ccb88ee991efc1c70764c9665 *src/libxlsxwriter/xmlwriter.c
4d6bbe6eab64e6a0b90ea116883c1fe7 *src/md5/md5.c
9a78fb091fa245b64434692197e9b4f2 *src/md5/md5.h
0bb4267f9320e96ad7bf9c7dbe4c7912 *src/minizip/ioapi.c
418b9368e13d819a0b3111f9712cd175 *src/minizip/ioapi.h
412000864e4eb2a753353b0ad02f18f0 *src/minizip/zip.c
6dc6de0874d78350319224058bf1ab51 *src/minizip/zip.h
636907d331156d62e8e750411db3a87b *src/tmpfileplus/tmpfileplus.c
91ecc39f822ba460d99a451fec030cfa *src/tmpfileplus/tmpfileplus.h
300f7fc9d58721c94793adf9e97098d6 *src/write_xlsx.c
bc882e5235bfdccc9e49f99290365b40 *tests/spelling.R
71190c953f4f20bb7683748096679dc4 *tests/testthat.R
f593ee0b058391fe787bf07f62604ef2 *tests/testthat/test-performance.R
f7ed43304acb6af25f548ba738349064 *tests/testthat/test-types.R
writexl/R/ 0000755 0001762 0000144 00000000000 14750415353 012160 5 ustar ligges users writexl/R/version.R 0000644 0001762 0000144 00000000503 14747162622 013772 0 ustar ligges users #' Version
#'
#' Shows version of bundled libxlsxwriter.
#'
#' @export
#' @rdname writexl
#' @useDynLib writexl C_lxw_version
lxw_version <- function(){
version <- .Call(C_lxw_version)
as.numeric_version(version)
}
#' @useDynLib writexl C_set_tempdir
.onLoad <- function(lib, pkg){
.Call(C_set_tempdir, tempdir())
}
writexl/R/excel_types.R 0000644 0001762 0000144 00000004103 14747162622 014631 0 ustar ligges users #' Excel Types
#'
#' Create special column types to write to a spreadsheet
#'
#' @family writexl
#' @param x character vector to be interpreted as formula
#' @export
#' @rdname xl_formula
#' @examples
#' df <- data.frame(
#' name = c("UCLA", "Berkeley", "Jeroen"),
#' founded = c(1919, 1868, 2030),
#' website = xl_hyperlink(c("http://www.ucla.edu", "http://www.berkeley.edu", NA), "homepage")
#' )
#' df$age <- xl_formula('=(YEAR(TODAY()) - INDIRECT("B" & ROW()))')
#' write_xlsx(df, 'universities.xlsx')
#'
#' # cleanup
#' unlink('universities.xlsx')
xl_formula <- function(x){
if(is.factor(x))
x <- as.character(x)
stopifnot(is.character(x))
if(!all(grepl("^=",x) | is.na(x)))
stop("Formulas must start with '='")
structure(x, class = c('xl_formula', 'xl_object'))
}
#' @rdname xl_formula
#' @export
#' @param url character vector of URLs
#' @param name character vector of friendly names
xl_hyperlink <- function(url, name = NULL){
if(is.factor(url))
url <- as.character(url)
stopifnot(is.character(url))
hyperlink <- dubquote(url)
if(length(name)){
hyperlink <- paste(hyperlink, dubquote(name), sep = ",")
}
out <- xl_formula(sprintf("=HYPERLINK(%s)", hyperlink))
out[is.na(url)] <- NA
structure(out, class = c('xl_hyperlink', 'xl_formula', 'xl_object'))
}
#' @export
print.xl_formula <- function(x, max = 10, ...){
cat(sprintf(" [:%s:]\n", class(x)[1]))
if(length(x) > max)
x <- c(x[1:max], "...", sprintf("(total: %s)", length(x)))
cat(x, sep = "\n")
}
#' @export
rep.xl_object <- function(x, ...){
structure(rep(unclass(x), ...), class = class(x))
}
#' @export
`[.xl_object` <- function(x, ...){
structure(`[`(unclass(x), ...), class = class(x))
}
#' @export
`[[.xl_object` <- function(x, ...){
structure(`[[`(unclass(x), ...), class = class(x))
}
#' @export
c.xl_object <- function(x, ...){
structure(c(unclass(x), ...), class = class(x))
}
#' @export
as.data.frame.xl_object <- function(x, ..., stringsAsFactors = FALSE){
as.data.frame.character(x, ..., stringsAsFactors = FALSE)
}
dubquote <- function(x){
paste0('"', x, '"')
}
writexl/R/write_xlsx.R 0000644 0001762 0000144 00000005303 14750415353 014514 0 ustar ligges users #' Export to xlsx
#'
#' Writes a data frame to an xlsx file. To create an xlsx with (multiple) named
#' sheets, simply set \code{x} to a named list of data frames.
#'
#' Currently supports strings, numbers, booleans and dates. Formatting options
#' may be added in future versions.
#'
#' \if{html}{
#' \out{
#'
#'
#' }}
#'
#' @export
#' @aliases writexl
#' @useDynLib writexl C_write_data_frame_list
#' @param x data frame or named list of data frames that will be sheets in the xlsx
#' @param path a file name to write to
#' @param col_names write column names at the top of the file?
#' @param format_headers make the \code{col_names} in the xlsx centered and bold
#' @param use_zip64 use \href{https://en.wikipedia.org/wiki/Zip_(file_format)#ZIP64}{zip64}
#' to enable support for 4GB+ xlsx files. Not all platforms can read this.
#' @examples # Roundtrip example with single excel sheet named 'mysheet'
#' tmp <- write_xlsx(list(mysheet = iris))
#' readxl::read_xlsx(tmp)
write_xlsx <- function(x, path = tempfile(fileext = ".xlsx"), col_names = TRUE,
format_headers = TRUE, use_zip64 = FALSE){
if(is.data.frame(x))
x <- list(x)
if(!is.list(x) || !all(vapply(x, is.data.frame, logical(1))))
stop("Argument x must be a data frame or list of data frames")
x <- lapply(x, normalize_df)
if(any(nchar(names(x)) > 31)){
warning("Truncating sheet name(s) to 31 characters")
names(x) <- substring(names(x), 1, 29)
}
nm <- names(x)
if(length(unique(nm)) < length(nm)){
warning("Deduplicating sheet names")
names(x) <- make.unique(substring(names(x), 1, 28), sep = "_")
}
stopifnot(is.character(path) && length(path))
path <- normalizePath(path, mustWork = FALSE)
ret <- .Call(C_write_data_frame_list, x, path, col_names, format_headers, use_zip64)
invisible(ret)
}
normalize_df <- function(df){
if(nrow(df) > 1024^2){
stop("the xlsx format does not support tables with 1M+ rows")
}
# Types to coerce to strings
for(i in which(vapply(df, inherits, logical(1), c("factor", "hms")))){
df[[i]] <- as.character(df[[i]])
}
for(i in which(vapply(df, function(x){is.integer(x) && inherits(x, "POSIXct")}, logical(1)))){
df[[i]] <- as.POSIXct(as.double(df[[i]]))
}
for(i in which(vapply(df, inherits, logical(1), "POSIXlt"))){
df[[i]] <- as.POSIXct(df[[i]])
}
for(i in which(vapply(df, inherits, logical(1), "integer64"))){
warning(sprintf("Coercing column %s from int64 to double", names(df)[i]), call. = FALSE)
getNamespace("bit64")
df[[i]] <- as.double(df[[i]])
}
df
}
writexl/NEWS 0000644 0001762 0000144 00000002147 14766110236 012461 0 ustar ligges users 1.5.2
- Fix parallel make; cleanup after build
1.5.0
- Update libxlsxwriter from b0c76b33
1.4.2
- Bugfix for NA timestamps
1.4.1
- Fix strict-prototypes warnings
1.4.0
- Update libxlsxwriter to 1.0.3
1.3.1
- Fix a unit test in R-devel for timezone attribute comparisons
1.3
- write_xlsx gains option use_zip64 for 4GB+ file support
- libxslxwriter error messages are printed to REprintf instead of fprintf
- Handle overly long or duplicate sheet names
- The help assistant only appears once per session
1.2
- Update bundled libxlswriter 0.8.8
- xl_formula and xl_hyperlink now correctly support NA
- Oil clippy a bit
1.1
- Update bundled libxlswriter 0.8.4
- Do not write blank xlsx strings for NA and "" character values
- Coerce bit64 vectors to double with warning (xlsx does not have int64)
1.0
- Save R 'Date' types as proper datetime strings
- Update vendored libxlswriter to 0.7.6
0.2
- Add support for lists in write_xlsx() to create xlsx with multiple sheets
- Automatically coerce columns of type 'Date' and 'hms' to strings
0.1
- Initial CRAN release with clippy
writexl/src/ 0000755 0001762 0000144 00000000000 14766110236 012545 5 ustar ligges users writexl/src/include/ 0000755 0001762 0000144 00000000000 14747162622 014175 5 ustar ligges users writexl/src/include/xlsxwriter.h 0000644 0001762 0000144 00000000767 14747162622 016613 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*/
/**
* @file xlsxwriter.h
*
* xlsxwriter - A library for creating Excel XLSX files.
*
*/
#ifndef __LXW_XLSXWRITER_H__
#define __LXW_XLSXWRITER_H__
#include "xlsxwriter/workbook.h"
#include "xlsxwriter/worksheet.h"
#include "xlsxwriter/format.h"
#include "xlsxwriter/utility.h"
#define LXW_VERSION "1.1.5"
#define LXW_VERSION_ID 115
#define LXW_SOVERSION "5"
#endif /* __LXW_XLSXWRITER_H__ */
writexl/src/include/xlsxwriter/ 0000755 0001762 0000144 00000000000 14766116671 016434 5 ustar ligges users writexl/src/include/xlsxwriter/metadata.h 0000644 0001762 0000144 00000001536 14747162622 020366 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* metadata - A libxlsxwriter library for creating Excel XLSX metadata files.
*
*/
#ifndef __LXW_METADATA_H__
#define __LXW_METADATA_H__
#include
#include "common.h"
/*
* Struct to represent a metadata object.
*/
typedef struct lxw_metadata {
FILE *file;
} lxw_metadata;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
lxw_metadata *lxw_metadata_new(void);
void lxw_metadata_free(lxw_metadata *metadata);
void lxw_metadata_assemble_xml_file(lxw_metadata *self);
/* Declarations required for unit testing. */
#ifdef TESTING
STATIC void _metadata_xml_declaration(lxw_metadata *self);
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_METADATA_H__ */
writexl/src/include/xlsxwriter/xmlwriter.h 0000644 0001762 0000144 00000014557 14747162622 020652 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* xmlwriter - A libxlsxwriter library for creating Excel XLSX
* XML files.
*
* The xmlwriter library is used to create the XML sub-components files
* in the Excel XLSX file format.
*
* This library is used in preference to a more generic XML library to allow
* for customization and optimization for the XLSX file format.
*
* The xmlwriter functions are only used internally and do not need to be
* called directly by the end user.
*
*/
#ifndef __XMLWRITER_H__
#define __XMLWRITER_H__
#include
#include
#include
#include "utility.h"
#define LXW_MAX_ATTRIBUTE_LENGTH 2080 /* Max URL length. */
#define LXW_ATTR_32 32
#define LXW_ATTRIBUTE_COPY(dst, src) \
do{ \
strncpy(dst, src, LXW_MAX_ATTRIBUTE_LENGTH -1); \
dst[LXW_MAX_ATTRIBUTE_LENGTH - 1] = '\0'; \
} while (0)
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* Attribute used in XML elements. */
struct xml_attribute {
char key[LXW_MAX_ATTRIBUTE_LENGTH];
char value[LXW_MAX_ATTRIBUTE_LENGTH];
/* Make the struct a queue.h list element. */
STAILQ_ENTRY (xml_attribute) list_entries;
};
/* Use queue.h macros to define the xml_attribute_list type. */
STAILQ_HEAD(xml_attribute_list, xml_attribute);
/* Create a new attribute struct to add to a xml_attribute_list. */
struct xml_attribute *lxw_new_attribute_str(const char *key,
const char *value);
struct xml_attribute *lxw_new_attribute_int(const char *key, uint64_t value);
struct xml_attribute *lxw_new_attribute_dbl(const char *key, double value);
/* Macro to initialize the xml_attribute_list pointers. */
#define LXW_INIT_ATTRIBUTES() \
STAILQ_INIT(&attributes)
/* Macro to add attribute string elements to xml_attribute_list. */
#define LXW_PUSH_ATTRIBUTES_STR(key, value) \
do { \
attribute = lxw_new_attribute_str((key), (value)); \
STAILQ_INSERT_TAIL(&attributes, attribute, list_entries); \
} while (0)
/* Macro to add attribute int values to xml_attribute_list. */
#define LXW_PUSH_ATTRIBUTES_INT(key, value) \
do { \
attribute = lxw_new_attribute_int((key), (value)); \
STAILQ_INSERT_TAIL(&attributes, attribute, list_entries); \
} while (0)
/* Macro to add attribute double values to xml_attribute_list. */
#define LXW_PUSH_ATTRIBUTES_DBL(key, value) \
do { \
attribute = lxw_new_attribute_dbl((key), (value)); \
STAILQ_INSERT_TAIL(&attributes, attribute, list_entries); \
} while (0)
/* Macro to free xml_attribute_list and attribute. */
#define LXW_FREE_ATTRIBUTES() \
do { \
while (!STAILQ_EMPTY(&attributes)) { \
attribute = STAILQ_FIRST(&attributes); \
STAILQ_REMOVE_HEAD(&attributes, list_entries); \
free(attribute); \
} \
} while (0)
/**
* Create the XML declaration in an XML file.
*
* @param xmlfile A FILE pointer to the output XML file.
*/
void lxw_xml_declaration(FILE * xmlfile);
/**
* Write an XML start tag with optional attributes.
*
* @param xmlfile A FILE pointer to the output XML file.
* @param tag The XML tag to write.
* @param attributes An optional list of attributes to add to the tag.
*/
void lxw_xml_start_tag(FILE * xmlfile,
const char *tag,
struct xml_attribute_list *attributes);
/**
* Write an XML start tag with optional un-encoded attributes.
* This is a minor optimization for attributes that don't need encoding.
*
* @param xmlfile A FILE pointer to the output XML file.
* @param tag The XML tag to write.
* @param attributes An optional list of attributes to add to the tag.
*/
void lxw_xml_start_tag_unencoded(FILE * xmlfile,
const char *tag,
struct xml_attribute_list *attributes);
/**
* Write an XML end tag.
*
* @param xmlfile A FILE pointer to the output XML file.
* @param tag The XML tag to write.
*/
void lxw_xml_end_tag(FILE * xmlfile, const char *tag);
/**
* Write an XML empty tag with optional attributes.
*
* @param xmlfile A FILE pointer to the output XML file.
* @param tag The XML tag to write.
* @param attributes An optional list of attributes to add to the tag.
*/
void lxw_xml_empty_tag(FILE * xmlfile,
const char *tag,
struct xml_attribute_list *attributes);
/**
* Write an XML empty tag with optional un-encoded attributes.
* This is a minor optimization for attributes that don't need encoding.
*
* @param xmlfile A FILE pointer to the output XML file.
* @param tag The XML tag to write.
* @param attributes An optional list of attributes to add to the tag.
*/
void lxw_xml_empty_tag_unencoded(FILE * xmlfile,
const char *tag,
struct xml_attribute_list *attributes);
/**
* Write an XML element containing data and optional attributes.
*
* @param xmlfile A FILE pointer to the output XML file.
* @param tag The XML tag to write.
* @param data The data section of the XML element.
* @param attributes An optional list of attributes to add to the tag.
*/
void lxw_xml_data_element(FILE * xmlfile,
const char *tag,
const char *data,
struct xml_attribute_list *attributes);
void lxw_xml_rich_si_element(FILE * xmlfile, const char *string);
uint8_t lxw_has_control_characters(const char *string);
char *lxw_escape_control_characters(const char *string);
char *lxw_escape_url_characters(const char *string, uint8_t escape_hash);
char *lxw_escape_data(const char *data);
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __XMLWRITER_H__ */
writexl/src/include/xlsxwriter/worksheet.h 0000644 0001762 0000144 00000627333 14747162622 020632 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*/
/**
* @page worksheet_page The Worksheet object
*
* The Worksheet object represents an Excel worksheet. It handles
* operations such as writing data to cells or formatting worksheet
* layout.
*
* See @ref worksheet.h for full details of the functionality.
*
* @file worksheet.h
*
* @brief Functions related to adding data and formatting to a worksheet.
*
* The Worksheet object represents an Excel worksheet. It handles
* operations such as writing data to cells or formatting worksheet
* layout.
*
* A Worksheet object isn't created directly. Instead a worksheet is
* created by calling the workbook_add_worksheet() function from a
* Workbook object:
*
* @code
* #include "xlsxwriter.h"
*
* int main() {
*
* lxw_workbook *workbook = workbook_new("filename.xlsx");
* lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
*
* worksheet_write_string(worksheet, 0, 0, "Hello Excel", NULL);
*
* return workbook_close(workbook);
* }
* @endcode
*
*/
#ifndef __LXW_WORKSHEET_H__
#define __LXW_WORKSHEET_H__
#include
#include
#include
#include "shared_strings.h"
#include "chart.h"
#include "drawing.h"
#include "common.h"
#include "format.h"
#include "styles.h"
#include "utility.h"
#include "relationships.h"
#define LXW_ROW_MAX 1048576
#define LXW_COL_MAX 16384
#define LXW_COL_META_MAX 128
#define LXW_HEADER_FOOTER_MAX 255
#define LXW_MAX_NUMBER_URLS 65530
#define LXW_PANE_NAME_LENGTH 12 /* bottomRight + 1 */
#define LXW_IMAGE_BUFFER_SIZE 1024
#define LXW_HEADER_FOOTER_OBJS_MAX 6 /* Header/footer image objs. */
/* The Excel 2007 specification says that the maximum number of page
* breaks is 1026. However, in practice it is actually 1023. */
#define LXW_BREAKS_MAX 1023
/** Default Excel column width in character units. */
#define LXW_DEF_COL_WIDTH (double)8.43
/** Default Excel column height in character units. */
#define LXW_DEF_ROW_HEIGHT (double)15.0
/** Default Excel column width in pixels. */
#define LXW_DEF_COL_WIDTH_PIXELS 64
/** Default Excel column height in pixels. */
#define LXW_DEF_ROW_HEIGHT_PIXELS 20
/** Gridline options using in `worksheet_gridlines()`. */
enum lxw_gridlines {
/** Hide screen and print gridlines. */
LXW_HIDE_ALL_GRIDLINES = 0,
/** Show screen gridlines. */
LXW_SHOW_SCREEN_GRIDLINES,
/** Show print gridlines. */
LXW_SHOW_PRINT_GRIDLINES,
/** Show screen and print gridlines. */
LXW_SHOW_ALL_GRIDLINES
};
/** Data validation property values. */
enum lxw_validation_boolean {
LXW_VALIDATION_DEFAULT,
/** Turn a data validation property off. */
LXW_VALIDATION_OFF,
/** Turn a data validation property on. Data validation properties are
* generally on by default. */
LXW_VALIDATION_ON
};
/** Data validation types. */
enum lxw_validation_types {
LXW_VALIDATION_TYPE_NONE,
/** Restrict cell input to whole/integer numbers only. */
LXW_VALIDATION_TYPE_INTEGER,
/** Restrict cell input to whole/integer numbers only, using a cell
* reference. */
LXW_VALIDATION_TYPE_INTEGER_FORMULA,
/** Restrict cell input to decimal numbers only. */
LXW_VALIDATION_TYPE_DECIMAL,
/** Restrict cell input to decimal numbers only, using a cell
* reference. */
LXW_VALIDATION_TYPE_DECIMAL_FORMULA,
/** Restrict cell input to a list of strings in a dropdown. */
LXW_VALIDATION_TYPE_LIST,
/** Restrict cell input to a list of strings in a dropdown, using a
* cell range. */
LXW_VALIDATION_TYPE_LIST_FORMULA,
/** Restrict cell input to date values only, using a lxw_datetime type. */
LXW_VALIDATION_TYPE_DATE,
/** Restrict cell input to date values only, using a cell reference. */
LXW_VALIDATION_TYPE_DATE_FORMULA,
/* Restrict cell input to date values only, as a serial number.
* Undocumented. */
LXW_VALIDATION_TYPE_DATE_NUMBER,
/** Restrict cell input to time values only, using a lxw_datetime type. */
LXW_VALIDATION_TYPE_TIME,
/** Restrict cell input to time values only, using a cell reference. */
LXW_VALIDATION_TYPE_TIME_FORMULA,
/* Restrict cell input to time values only, as a serial number.
* Undocumented. */
LXW_VALIDATION_TYPE_TIME_NUMBER,
/** Restrict cell input to strings of defined length, using a cell
* reference. */
LXW_VALIDATION_TYPE_LENGTH,
/** Restrict cell input to strings of defined length, using a cell
* reference. */
LXW_VALIDATION_TYPE_LENGTH_FORMULA,
/** Restrict cell to input controlled by a custom formula that returns
* `TRUE/FALSE`. */
LXW_VALIDATION_TYPE_CUSTOM_FORMULA,
/** Allow any type of input. Mainly only useful for pop-up messages. */
LXW_VALIDATION_TYPE_ANY
};
/** Data validation criteria uses to control the selection of data. */
enum lxw_validation_criteria {
LXW_VALIDATION_CRITERIA_NONE,
/** Select data between two values. */
LXW_VALIDATION_CRITERIA_BETWEEN,
/** Select data that is not between two values. */
LXW_VALIDATION_CRITERIA_NOT_BETWEEN,
/** Select data equal to a value. */
LXW_VALIDATION_CRITERIA_EQUAL_TO,
/** Select data not equal to a value. */
LXW_VALIDATION_CRITERIA_NOT_EQUAL_TO,
/** Select data greater than a value. */
LXW_VALIDATION_CRITERIA_GREATER_THAN,
/** Select data less than a value. */
LXW_VALIDATION_CRITERIA_LESS_THAN,
/** Select data greater than or equal to a value. */
LXW_VALIDATION_CRITERIA_GREATER_THAN_OR_EQUAL_TO,
/** Select data less than or equal to a value. */
LXW_VALIDATION_CRITERIA_LESS_THAN_OR_EQUAL_TO
};
/** Data validation error types for pop-up messages. */
enum lxw_validation_error_types {
/** Show a "Stop" data validation pop-up message. This is the default. */
LXW_VALIDATION_ERROR_TYPE_STOP,
/** Show an "Error" data validation pop-up message. */
LXW_VALIDATION_ERROR_TYPE_WARNING,
/** Show an "Information" data validation pop-up message. */
LXW_VALIDATION_ERROR_TYPE_INFORMATION
};
/** Set the display type for a cell comment. This is hidden by default but
* can be set to visible with the `worksheet_show_comments()` function. */
enum lxw_comment_display_types {
/** Default to the worksheet default which can be hidden or visible.*/
LXW_COMMENT_DISPLAY_DEFAULT,
/** Hide the cell comment. Usually the default. */
LXW_COMMENT_DISPLAY_HIDDEN,
/** Show the cell comment. Can also be set for the worksheet with the
* `worksheet_show_comments()` function.*/
LXW_COMMENT_DISPLAY_VISIBLE
};
/** @brief Type definitions for conditional formats.
*
* Values used to set the "type" field of conditional format.
*/
enum lxw_conditional_format_types {
LXW_CONDITIONAL_TYPE_NONE,
/** The Cell type is the most common conditional formatting type. It is
* used when a format is applied to a cell based on a simple
* criterion. */
LXW_CONDITIONAL_TYPE_CELL,
/** The Text type is used to specify Excel's "Specific Text" style
* conditional format. */
LXW_CONDITIONAL_TYPE_TEXT,
/** The Time Period type is used to specify Excel's "Dates Occurring"
* style conditional format. */
LXW_CONDITIONAL_TYPE_TIME_PERIOD,
/** The Average type is used to specify Excel's "Average" style
* conditional format. */
LXW_CONDITIONAL_TYPE_AVERAGE,
/** The Duplicate type is used to highlight duplicate cells in a range. */
LXW_CONDITIONAL_TYPE_DUPLICATE,
/** The Unique type is used to highlight unique cells in a range. */
LXW_CONDITIONAL_TYPE_UNIQUE,
/** The Top type is used to specify the top n values by number or
* percentage in a range. */
LXW_CONDITIONAL_TYPE_TOP,
/** The Bottom type is used to specify the bottom n values by number or
* percentage in a range. */
LXW_CONDITIONAL_TYPE_BOTTOM,
/** The Blanks type is used to highlight blank cells in a range. */
LXW_CONDITIONAL_TYPE_BLANKS,
/** The No Blanks type is used to highlight non blank cells in a range. */
LXW_CONDITIONAL_TYPE_NO_BLANKS,
/** The Errors type is used to highlight error cells in a range. */
LXW_CONDITIONAL_TYPE_ERRORS,
/** The No Errors type is used to highlight non error cells in a range. */
LXW_CONDITIONAL_TYPE_NO_ERRORS,
/** The Formula type is used to specify a conditional format based on a
* user defined formula. */
LXW_CONDITIONAL_TYPE_FORMULA,
/** The 2 Color Scale type is used to specify Excel's "2 Color Scale"
* style conditional format. */
LXW_CONDITIONAL_2_COLOR_SCALE,
/** The 3 Color Scale type is used to specify Excel's "3 Color Scale"
* style conditional format. */
LXW_CONDITIONAL_3_COLOR_SCALE,
/** The Data Bar type is used to specify Excel's "Data Bar" style
* conditional format. */
LXW_CONDITIONAL_DATA_BAR,
/** The Icon Set type is used to specify a conditional format with a set
* of icons such as traffic lights or arrows. */
LXW_CONDITIONAL_TYPE_ICON_SETS,
LXW_CONDITIONAL_TYPE_LAST
};
/** @brief The criteria used in a conditional format.
*
* Criteria used to define how a conditional format works.
*/
enum lxw_conditional_criteria {
LXW_CONDITIONAL_CRITERIA_NONE,
/** Format cells equal to a value. */
LXW_CONDITIONAL_CRITERIA_EQUAL_TO,
/** Format cells not equal to a value. */
LXW_CONDITIONAL_CRITERIA_NOT_EQUAL_TO,
/** Format cells greater than a value. */
LXW_CONDITIONAL_CRITERIA_GREATER_THAN,
/** Format cells less than a value. */
LXW_CONDITIONAL_CRITERIA_LESS_THAN,
/** Format cells greater than or equal to a value. */
LXW_CONDITIONAL_CRITERIA_GREATER_THAN_OR_EQUAL_TO,
/** Format cells less than or equal to a value. */
LXW_CONDITIONAL_CRITERIA_LESS_THAN_OR_EQUAL_TO,
/** Format cells between two values. */
LXW_CONDITIONAL_CRITERIA_BETWEEN,
/** Format cells that is not between two values. */
LXW_CONDITIONAL_CRITERIA_NOT_BETWEEN,
/** Format cells that contain the specified text. */
LXW_CONDITIONAL_CRITERIA_TEXT_CONTAINING,
/** Format cells that don't contain the specified text. */
LXW_CONDITIONAL_CRITERIA_TEXT_NOT_CONTAINING,
/** Format cells that begin with the specified text. */
LXW_CONDITIONAL_CRITERIA_TEXT_BEGINS_WITH,
/** Format cells that end with the specified text. */
LXW_CONDITIONAL_CRITERIA_TEXT_ENDS_WITH,
/** Format cells with a date of yesterday. */
LXW_CONDITIONAL_CRITERIA_TIME_PERIOD_YESTERDAY,
/** Format cells with a date of today. */
LXW_CONDITIONAL_CRITERIA_TIME_PERIOD_TODAY,
/** Format cells with a date of tomorrow. */
LXW_CONDITIONAL_CRITERIA_TIME_PERIOD_TOMORROW,
/** Format cells with a date in the last 7 days. */
LXW_CONDITIONAL_CRITERIA_TIME_PERIOD_LAST_7_DAYS,
/** Format cells with a date in the last week. */
LXW_CONDITIONAL_CRITERIA_TIME_PERIOD_LAST_WEEK,
/** Format cells with a date in the current week. */
LXW_CONDITIONAL_CRITERIA_TIME_PERIOD_THIS_WEEK,
/** Format cells with a date in the next week. */
LXW_CONDITIONAL_CRITERIA_TIME_PERIOD_NEXT_WEEK,
/** Format cells with a date in the last month. */
LXW_CONDITIONAL_CRITERIA_TIME_PERIOD_LAST_MONTH,
/** Format cells with a date in the current month. */
LXW_CONDITIONAL_CRITERIA_TIME_PERIOD_THIS_MONTH,
/** Format cells with a date in the next month. */
LXW_CONDITIONAL_CRITERIA_TIME_PERIOD_NEXT_MONTH,
/** Format cells above the average for the range. */
LXW_CONDITIONAL_CRITERIA_AVERAGE_ABOVE,
/** Format cells below the average for the range. */
LXW_CONDITIONAL_CRITERIA_AVERAGE_BELOW,
/** Format cells above or equal to the average for the range. */
LXW_CONDITIONAL_CRITERIA_AVERAGE_ABOVE_OR_EQUAL,
/** Format cells below or equal to the average for the range. */
LXW_CONDITIONAL_CRITERIA_AVERAGE_BELOW_OR_EQUAL,
/** Format cells 1 standard deviation above the average for the range. */
LXW_CONDITIONAL_CRITERIA_AVERAGE_1_STD_DEV_ABOVE,
/** Format cells 1 standard deviation below the average for the range. */
LXW_CONDITIONAL_CRITERIA_AVERAGE_1_STD_DEV_BELOW,
/** Format cells 2 standard deviation above the average for the range. */
LXW_CONDITIONAL_CRITERIA_AVERAGE_2_STD_DEV_ABOVE,
/** Format cells 2 standard deviation below the average for the range. */
LXW_CONDITIONAL_CRITERIA_AVERAGE_2_STD_DEV_BELOW,
/** Format cells 3 standard deviation above the average for the range. */
LXW_CONDITIONAL_CRITERIA_AVERAGE_3_STD_DEV_ABOVE,
/** Format cells 3 standard deviation below the average for the range. */
LXW_CONDITIONAL_CRITERIA_AVERAGE_3_STD_DEV_BELOW,
/** Format cells in the top of bottom percentage. */
LXW_CONDITIONAL_CRITERIA_TOP_OR_BOTTOM_PERCENT
};
/** @brief Conditional format rule types.
*
* Conditional format rule types that apply to Color Scale and Data Bars.
*/
enum lxw_conditional_format_rule_types {
LXW_CONDITIONAL_RULE_TYPE_NONE,
/** Conditional format rule type: matches the minimum values in the
* range. Can only be applied to min_rule_type.*/
LXW_CONDITIONAL_RULE_TYPE_MINIMUM,
/** Conditional format rule type: use a number to set the bound.*/
LXW_CONDITIONAL_RULE_TYPE_NUMBER,
/** Conditional format rule type: use a percentage to set the bound.*/
LXW_CONDITIONAL_RULE_TYPE_PERCENT,
/** Conditional format rule type: use a percentile to set the bound.*/
LXW_CONDITIONAL_RULE_TYPE_PERCENTILE,
/** Conditional format rule type: use a formula to set the bound.*/
LXW_CONDITIONAL_RULE_TYPE_FORMULA,
/** Conditional format rule type: matches the maximum values in the
* range. Can only be applied to max_rule_type.*/
LXW_CONDITIONAL_RULE_TYPE_MAXIMUM,
/* Used internally for Excel2010 bars. Not documented. */
LXW_CONDITIONAL_RULE_TYPE_AUTO_MIN,
/* Used internally for Excel2010 bars. Not documented. */
LXW_CONDITIONAL_RULE_TYPE_AUTO_MAX
};
/** @brief Conditional format data bar directions.
*
* Values used to set the bar direction of a conditional format data bar.
*/
enum lxw_conditional_format_bar_direction {
/** Data bar direction is set by Excel based on the context of the data
* displayed. */
LXW_CONDITIONAL_BAR_DIRECTION_CONTEXT,
/** Data bar direction is from right to left. */
LXW_CONDITIONAL_BAR_DIRECTION_RIGHT_TO_LEFT,
/** Data bar direction is from left to right. */
LXW_CONDITIONAL_BAR_DIRECTION_LEFT_TO_RIGHT
};
/** @brief Conditional format data bar axis options.
*
* Values used to set the position of the axis in a conditional format data
* bar.
*/
enum lxw_conditional_bar_axis_position {
/** Data bar axis position is set by Excel based on the context of the
* data displayed. */
LXW_CONDITIONAL_BAR_AXIS_AUTOMATIC,
/** Data bar axis position is set at the midpoint. */
LXW_CONDITIONAL_BAR_AXIS_MIDPOINT,
/** Data bar axis is turned off. */
LXW_CONDITIONAL_BAR_AXIS_NONE
};
/** @brief Icon types used in the #lxw_conditional_format icon_style field.
*
* Definitions of icon styles used with Icon Set conditional formats.
*/
enum lxw_conditional_icon_types {
/** Icon style: 3 colored arrows showing up, sideways and down. */
LXW_CONDITIONAL_ICONS_3_ARROWS_COLORED,
/** Icon style: 3 gray arrows showing up, sideways and down. */
LXW_CONDITIONAL_ICONS_3_ARROWS_GRAY,
/** Icon style: 3 colored flags in red, yellow and green. */
LXW_CONDITIONAL_ICONS_3_FLAGS,
/** Icon style: 3 traffic lights - rounded. */
LXW_CONDITIONAL_ICONS_3_TRAFFIC_LIGHTS_UNRIMMED,
/** Icon style: 3 traffic lights with a rim - squarish. */
LXW_CONDITIONAL_ICONS_3_TRAFFIC_LIGHTS_RIMMED,
/** Icon style: 3 colored shapes - a circle, triangle and diamond. */
LXW_CONDITIONAL_ICONS_3_SIGNS,
/** Icon style: 3 circled symbols with tick mark, exclamation and
* cross. */
LXW_CONDITIONAL_ICONS_3_SYMBOLS_CIRCLED,
/** Icon style: 3 symbols with tick mark, exclamation and cross. */
LXW_CONDITIONAL_ICONS_3_SYMBOLS_UNCIRCLED,
/** Icon style: 4 colored arrows showing up, diagonal up, diagonal down
* and down. */
LXW_CONDITIONAL_ICONS_4_ARROWS_COLORED,
/** Icon style: 4 gray arrows showing up, diagonal up, diagonal down and
* down. */
LXW_CONDITIONAL_ICONS_4_ARROWS_GRAY,
/** Icon style: 4 circles in 4 colors going from red to black. */
LXW_CONDITIONAL_ICONS_4_RED_TO_BLACK,
/** Icon style: 4 histogram ratings. */
LXW_CONDITIONAL_ICONS_4_RATINGS,
/** Icon style: 4 traffic lights. */
LXW_CONDITIONAL_ICONS_4_TRAFFIC_LIGHTS,
/** Icon style: 5 colored arrows showing up, diagonal up, sideways,
* diagonal down and down. */
LXW_CONDITIONAL_ICONS_5_ARROWS_COLORED,
/** Icon style: 5 gray arrows showing up, diagonal up, sideways, diagonal
* down and down. */
LXW_CONDITIONAL_ICONS_5_ARROWS_GRAY,
/** Icon style: 5 histogram ratings. */
LXW_CONDITIONAL_ICONS_5_RATINGS,
/** Icon style: 5 quarters, from 0 to 4 quadrants filled. */
LXW_CONDITIONAL_ICONS_5_QUARTERS
};
/** @brief The type of table style.
*
* The type of table style (Light, Medium or Dark).
*/
enum lxw_table_style_type {
LXW_TABLE_STYLE_TYPE_DEFAULT,
/** Light table style. */
LXW_TABLE_STYLE_TYPE_LIGHT,
/** Light table style. */
LXW_TABLE_STYLE_TYPE_MEDIUM,
/** Light table style. */
LXW_TABLE_STYLE_TYPE_DARK
};
/**
* @brief Standard Excel functions for totals in tables.
*
* Definitions for the standard Excel functions that are available via the
* dropdown in the total row of an Excel table.
*
*/
enum lxw_table_total_functions {
LXW_TABLE_FUNCTION_NONE = 0,
/** Use the average function as the table total. */
LXW_TABLE_FUNCTION_AVERAGE = 101,
/** Use the count numbers function as the table total. */
LXW_TABLE_FUNCTION_COUNT_NUMS = 102,
/** Use the count function as the table total. */
LXW_TABLE_FUNCTION_COUNT = 103,
/** Use the max function as the table total. */
LXW_TABLE_FUNCTION_MAX = 104,
/** Use the min function as the table total. */
LXW_TABLE_FUNCTION_MIN = 105,
/** Use the standard deviation function as the table total. */
LXW_TABLE_FUNCTION_STD_DEV = 107,
/** Use the sum function as the table total. */
LXW_TABLE_FUNCTION_SUM = 109,
/** Use the var function as the table total. */
LXW_TABLE_FUNCTION_VAR = 110
};
/** @brief The criteria used in autofilter rules.
*
* Criteria used to define an autofilter rule condition.
*/
enum lxw_filter_criteria {
LXW_FILTER_CRITERIA_NONE,
/** Filter cells equal to a value. */
LXW_FILTER_CRITERIA_EQUAL_TO,
/** Filter cells not equal to a value. */
LXW_FILTER_CRITERIA_NOT_EQUAL_TO,
/** Filter cells greater than a value. */
LXW_FILTER_CRITERIA_GREATER_THAN,
/** Filter cells less than a value. */
LXW_FILTER_CRITERIA_LESS_THAN,
/** Filter cells greater than or equal to a value. */
LXW_FILTER_CRITERIA_GREATER_THAN_OR_EQUAL_TO,
/** Filter cells less than or equal to a value. */
LXW_FILTER_CRITERIA_LESS_THAN_OR_EQUAL_TO,
/** Filter cells that are blank. */
LXW_FILTER_CRITERIA_BLANKS,
/** Filter cells that are not blank. */
LXW_FILTER_CRITERIA_NON_BLANKS
};
/**
* @brief And/or operator when using 2 filter rules.
*
* And/or operator conditions when using 2 filter rules with
* worksheet_filter_column2(). In general LXW_FILTER_OR is used with
* LXW_FILTER_CRITERIA_EQUAL_TO and LXW_FILTER_AND is used with the other
* filter criteria.
*/
enum lxw_filter_operator {
/** Logical "and" of 2 filter rules. */
LXW_FILTER_AND,
/** Logical "or" of 2 filter rules. */
LXW_FILTER_OR
};
/* Internal filter types. */
enum lxw_filter_type {
LXW_FILTER_TYPE_NONE,
LXW_FILTER_TYPE_SINGLE,
LXW_FILTER_TYPE_AND,
LXW_FILTER_TYPE_OR,
LXW_FILTER_TYPE_STRING_LIST
};
/** Options to control the positioning of worksheet objects such as images
* or charts. See @ref working_with_object_positioning. */
enum lxw_object_position {
/** Default positioning for the object. */
LXW_OBJECT_POSITION_DEFAULT,
/** Move and size the worksheet object with the cells. */
LXW_OBJECT_MOVE_AND_SIZE,
/** Move but don't size the worksheet object with the cells. */
LXW_OBJECT_MOVE_DONT_SIZE,
/** Don't move or size the worksheet object with the cells. */
LXW_OBJECT_DONT_MOVE_DONT_SIZE,
/** Same as #LXW_OBJECT_MOVE_AND_SIZE except libxlsxwriter applies hidden
* cells after the object is inserted. */
LXW_OBJECT_MOVE_AND_SIZE_AFTER
};
/** Options for ignoring worksheet errors/warnings. See worksheet_ignore_errors(). */
enum lxw_ignore_errors {
/** Turn off errors/warnings for numbers stores as text. */
LXW_IGNORE_NUMBER_STORED_AS_TEXT = 1,
/** Turn off errors/warnings for formula errors (such as divide by
* zero). */
LXW_IGNORE_EVAL_ERROR,
/** Turn off errors/warnings for formulas that differ from surrounding
* formulas. */
LXW_IGNORE_FORMULA_DIFFERS,
/** Turn off errors/warnings for formulas that omit cells in a range. */
LXW_IGNORE_FORMULA_RANGE,
/** Turn off errors/warnings for unlocked cells that contain formulas. */
LXW_IGNORE_FORMULA_UNLOCKED,
/** Turn off errors/warnings for formulas that refer to empty cells. */
LXW_IGNORE_EMPTY_CELL_REFERENCE,
/** Turn off errors/warnings for cells in a table that do not comply with
* applicable data validation rules. */
LXW_IGNORE_LIST_DATA_VALIDATION,
/** Turn off errors/warnings for cell formulas that differ from the column
* formula. */
LXW_IGNORE_CALCULATED_COLUMN,
/** Turn off errors/warnings for formulas that contain a two digit text
* representation of a year. */
LXW_IGNORE_TWO_DIGIT_TEXT_YEAR,
LXW_IGNORE_LAST_OPTION
};
enum cell_types {
NUMBER_CELL = 1,
STRING_CELL,
INLINE_STRING_CELL,
INLINE_RICH_STRING_CELL,
FORMULA_CELL,
ARRAY_FORMULA_CELL,
DYNAMIC_ARRAY_FORMULA_CELL,
BLANK_CELL,
BOOLEAN_CELL,
COMMENT,
HYPERLINK_URL,
HYPERLINK_INTERNAL,
HYPERLINK_EXTERNAL
};
enum pane_types {
NO_PANES = 0,
FREEZE_PANES,
SPLIT_PANES,
FREEZE_SPLIT_PANES
};
enum lxw_image_position {
HEADER_LEFT = 0,
HEADER_CENTER,
HEADER_RIGHT,
FOOTER_LEFT,
FOOTER_CENTER,
FOOTER_RIGHT
};
/* Define the tree.h RB structs for the red-black head types. */
RB_HEAD(lxw_table_cells, lxw_cell);
RB_HEAD(lxw_drawing_rel_ids, lxw_drawing_rel_id);
RB_HEAD(lxw_vml_drawing_rel_ids, lxw_drawing_rel_id);
RB_HEAD(lxw_cond_format_hash, lxw_cond_format_hash_element);
/* Define a RB_TREE struct manually to add extra members. */
struct lxw_table_rows {
struct lxw_row *rbh_root;
struct lxw_row *cached_row;
lxw_row_t cached_row_num;
};
/* Wrapper around RB_GENERATE_STATIC from tree.h to avoid unused function
* warnings and to avoid portability issues with the _unused attribute. */
#define LXW_RB_GENERATE_ROW(name, type, field, cmp) \
RB_GENERATE_INSERT_COLOR(name, type, field, static) \
RB_GENERATE_REMOVE_COLOR(name, type, field, static) \
RB_GENERATE_INSERT(name, type, field, cmp, static) \
RB_GENERATE_REMOVE(name, type, field, static) \
RB_GENERATE_FIND(name, type, field, cmp, static) \
RB_GENERATE_NEXT(name, type, field, static) \
RB_GENERATE_MINMAX(name, type, field, static) \
/* Add unused struct to allow adding a semicolon */ \
struct lxw_rb_generate_row{int unused;}
#define LXW_RB_GENERATE_CELL(name, type, field, cmp) \
RB_GENERATE_INSERT_COLOR(name, type, field, static) \
RB_GENERATE_REMOVE_COLOR(name, type, field, static) \
RB_GENERATE_INSERT(name, type, field, cmp, static) \
RB_GENERATE_REMOVE(name, type, field, static) \
RB_GENERATE_FIND(name, type, field, cmp, static) \
RB_GENERATE_NEXT(name, type, field, static) \
RB_GENERATE_MINMAX(name, type, field, static) \
/* Add unused struct to allow adding a semicolon */ \
struct lxw_rb_generate_cell{int unused;}
#define LXW_RB_GENERATE_DRAWING_REL_IDS(name, type, field, cmp) \
RB_GENERATE_INSERT_COLOR(name, type, field, static) \
RB_GENERATE_REMOVE_COLOR(name, type, field, static) \
RB_GENERATE_INSERT(name, type, field, cmp, static) \
RB_GENERATE_REMOVE(name, type, field, static) \
RB_GENERATE_FIND(name, type, field, cmp, static) \
RB_GENERATE_NEXT(name, type, field, static) \
RB_GENERATE_MINMAX(name, type, field, static) \
/* Add unused struct to allow adding a semicolon */ \
struct lxw_rb_generate_drawing_rel_ids{int unused;}
#define LXW_RB_GENERATE_VML_DRAWING_REL_IDS(name, type, field, cmp) \
RB_GENERATE_INSERT_COLOR(name, type, field, static) \
RB_GENERATE_REMOVE_COLOR(name, type, field, static) \
RB_GENERATE_INSERT(name, type, field, cmp, static) \
RB_GENERATE_REMOVE(name, type, field, static) \
RB_GENERATE_FIND(name, type, field, cmp, static) \
RB_GENERATE_NEXT(name, type, field, static) \
RB_GENERATE_MINMAX(name, type, field, static) \
/* Add unused struct to allow adding a semicolon */ \
struct lxw_rb_generate_vml_drawing_rel_ids{int unused;}
#define LXW_RB_GENERATE_COND_FORMAT_HASH(name, type, field, cmp) \
RB_GENERATE_INSERT_COLOR(name, type, field, static) \
RB_GENERATE_REMOVE_COLOR(name, type, field, static) \
RB_GENERATE_INSERT(name, type, field, cmp, static) \
RB_GENERATE_REMOVE(name, type, field, static) \
RB_GENERATE_FIND(name, type, field, cmp, static) \
RB_GENERATE_NEXT(name, type, field, static) \
RB_GENERATE_MINMAX(name, type, field, static) \
/* Add unused struct to allow adding a semicolon */ \
struct lxw_rb_generate_cond_format_hash{int unused;}
STAILQ_HEAD(lxw_merged_ranges, lxw_merged_range);
STAILQ_HEAD(lxw_selections, lxw_selection);
STAILQ_HEAD(lxw_data_validations, lxw_data_val_obj);
STAILQ_HEAD(lxw_cond_format_list, lxw_cond_format_obj);
STAILQ_HEAD(lxw_image_props, lxw_object_properties);
STAILQ_HEAD(lxw_chart_props, lxw_object_properties);
STAILQ_HEAD(lxw_comment_objs, lxw_vml_obj);
STAILQ_HEAD(lxw_table_objs, lxw_table_obj);
/**
* @brief Options for rows and columns.
*
* Options struct for the worksheet_set_column() and worksheet_set_row()
* functions.
*
* It has the following members:
*
* * `hidden`
* * `level`
* * `collapsed`
*
* The members of this struct are explained in @ref ww_outlines_grouping.
*
*/
typedef struct lxw_row_col_options {
/** Hide the row/column. @ref ww_outlines_grouping.*/
uint8_t hidden;
/** Outline level. See @ref ww_outlines_grouping.*/
uint8_t level;
/** Set the outline row as collapsed. See @ref ww_outlines_grouping.*/
uint8_t collapsed;
} lxw_row_col_options;
typedef struct lxw_col_options {
lxw_col_t firstcol;
lxw_col_t lastcol;
double width;
lxw_format *format;
uint8_t hidden;
uint8_t level;
uint8_t collapsed;
} lxw_col_options;
typedef struct lxw_merged_range {
lxw_row_t first_row;
lxw_row_t last_row;
lxw_col_t first_col;
lxw_col_t last_col;
STAILQ_ENTRY (lxw_merged_range) list_pointers;
} lxw_merged_range;
typedef struct lxw_repeat_rows {
uint8_t in_use;
lxw_row_t first_row;
lxw_row_t last_row;
} lxw_repeat_rows;
typedef struct lxw_repeat_cols {
uint8_t in_use;
lxw_col_t first_col;
lxw_col_t last_col;
} lxw_repeat_cols;
typedef struct lxw_print_area {
uint8_t in_use;
lxw_row_t first_row;
lxw_row_t last_row;
lxw_col_t first_col;
lxw_col_t last_col;
} lxw_print_area;
typedef struct lxw_autofilter {
uint8_t in_use;
uint8_t has_rules;
lxw_row_t first_row;
lxw_row_t last_row;
lxw_col_t first_col;
lxw_col_t last_col;
} lxw_autofilter;
typedef struct lxw_panes {
uint8_t type;
lxw_row_t first_row;
lxw_col_t first_col;
lxw_row_t top_row;
lxw_col_t left_col;
double x_split;
double y_split;
} lxw_panes;
typedef struct lxw_selection {
char pane[LXW_PANE_NAME_LENGTH];
char active_cell[LXW_MAX_CELL_RANGE_LENGTH];
char sqref[LXW_MAX_CELL_RANGE_LENGTH];
STAILQ_ENTRY (lxw_selection) list_pointers;
} lxw_selection;
/**
* @brief Worksheet data validation options.
*/
typedef struct lxw_data_validation {
/**
* Set the validation type. Should be a #lxw_validation_types value.
*/
uint8_t validate;
/**
* Set the validation criteria type to select the data. Should be a
* #lxw_validation_criteria value.
*/
uint8_t criteria;
/** Controls whether a data validation is not applied to blank data in the
* cell. Should be a #lxw_validation_boolean value. It is on by
* default.
*/
uint8_t ignore_blank;
/**
* This parameter is used to toggle on and off the 'Show input message
* when cell is selected' option in the Excel data validation dialog. When
* the option is off an input message is not displayed even if it has been
* set using input_message. Should be a #lxw_validation_boolean value. It
* is on by default.
*/
uint8_t show_input;
/**
* This parameter is used to toggle on and off the 'Show error alert
* after invalid data is entered' option in the Excel data validation
* dialog. When the option is off an error message is not displayed even
* if it has been set using error_message. Should be a
* #lxw_validation_boolean value. It is on by default.
*/
uint8_t show_error;
/**
* This parameter is used to specify the type of error dialog that is
* displayed. Should be a #lxw_validation_error_types value.
*/
uint8_t error_type;
/**
* This parameter is used to toggle on and off the 'In-cell dropdown'
* option in the Excel data validation dialog. When the option is on a
* dropdown list will be shown for list validations. Should be a
* #lxw_validation_boolean value. It is on by default.
*/
uint8_t dropdown;
/**
* This parameter is used to set the limiting value to which the criteria
* is applied using a whole or decimal number.
*/
double value_number;
/**
* This parameter is used to set the limiting value to which the criteria
* is applied using a cell reference. It is valid for any of the
* `_FORMULA` validation types.
*/
const char *value_formula;
/**
* This parameter is used to set a list of strings for a drop down list.
* The list should be a `NULL` terminated array of char* strings:
*
* @code
* char *list[] = {"open", "high", "close", NULL};
*
* data_validation->validate = LXW_VALIDATION_TYPE_LIST;
* data_validation->value_list = list;
* @endcode
*
* The `value_formula` parameter can also be used to specify a list from
* an Excel cell range.
*
* Note, the string list is restricted by Excel to 255 characters,
* including comma separators.
*/
const char **value_list;
/**
* This parameter is used to set the limiting value to which the date or
* time criteria is applied using a #lxw_datetime struct.
*/
lxw_datetime value_datetime;
/**
* This parameter is the same as `value_number` but for the minimum value
* when a `BETWEEN` criteria is used.
*/
double minimum_number;
/**
* This parameter is the same as `value_formula` but for the minimum value
* when a `BETWEEN` criteria is used.
*/
const char *minimum_formula;
/**
* This parameter is the same as `value_datetime` but for the minimum value
* when a `BETWEEN` criteria is used.
*/
lxw_datetime minimum_datetime;
/**
* This parameter is the same as `value_number` but for the maximum value
* when a `BETWEEN` criteria is used.
*/
double maximum_number;
/**
* This parameter is the same as `value_formula` but for the maximum value
* when a `BETWEEN` criteria is used.
*/
const char *maximum_formula;
/**
* This parameter is the same as `value_datetime` but for the maximum value
* when a `BETWEEN` criteria is used.
*/
lxw_datetime maximum_datetime;
/**
* The input_title parameter is used to set the title of the input message
* that is displayed when a cell is entered. It has no default value and
* is only displayed if the input message is displayed. See the
* `input_message` parameter below.
*
* The maximum title length is 32 characters.
*/
const char *input_title;
/**
* The input_message parameter is used to set the input message that is
* displayed when a cell is entered. It has no default value.
*
* The message can be split over several lines using newlines. The maximum
* message length is 255 characters.
*/
const char *input_message;
/**
* The error_title parameter is used to set the title of the error message
* that is displayed when the data validation criteria is not met. The
* default error title is 'Microsoft Excel'. The maximum title length is
* 32 characters.
*/
const char *error_title;
/**
* The error_message parameter is used to set the error message that is
* displayed when a cell is entered. The default error message is "The
* value you entered is not valid. A user has restricted values that can
* be entered into the cell".
*
* The message can be split over several lines using newlines. The maximum
* message length is 255 characters.
*/
const char *error_message;
} lxw_data_validation;
/* A copy of lxw_data_validation which is used internally and which contains
* some additional fields.
*/
typedef struct lxw_data_val_obj {
uint8_t validate;
uint8_t criteria;
uint8_t ignore_blank;
uint8_t show_input;
uint8_t show_error;
uint8_t error_type;
uint8_t dropdown;
double value_number;
char *value_formula;
char **value_list;
double minimum_number;
char *minimum_formula;
lxw_datetime minimum_datetime;
double maximum_number;
char *maximum_formula;
lxw_datetime maximum_datetime;
char *input_title;
char *input_message;
char *error_title;
char *error_message;
char sqref[LXW_MAX_CELL_RANGE_LENGTH];
STAILQ_ENTRY (lxw_data_val_obj) list_pointers;
} lxw_data_val_obj;
/**
* @brief Worksheet conditional formatting options.
*
* The fields/options in the the lxw_conditional_format are used to define a
* worksheet conditional format. It is used in conjunction with
* `worksheet_conditional_format()`.
*
*/
typedef struct lxw_conditional_format {
/** The type of conditional format such as #LXW_CONDITIONAL_TYPE_CELL or
* #LXW_CONDITIONAL_DATA_BAR. Should be a #lxw_conditional_format_types
* value.*/
uint8_t type;
/** The criteria parameter is used to set the criteria by which the cell
* data will be evaluated. For example in the expression `a > 5 the
* criteria is `>` or, in libxlsxwriter terms,
* #LXW_CONDITIONAL_CRITERIA_GREATER_THAN. The criteria that are
* applicable depend on the conditional format type. The criteria
* options are defined in #lxw_conditional_criteria. */
uint8_t criteria;
/** The number value to which the condition refers. For example in the
* expression `a > 5`, the value is 5.*/
double value;
/** The string value to which the condition refers, such as `"=A1"`. If a
* value_string exists in the struct then the number value is
* ignored. Note, if the condition refers to a text string then it must
* be double quoted like this `"foo"`. */
const char *value_string;
/** The format field is used to specify the #lxw_format format that will
* be applied to the cell when the conditional formatting criterion is
* met. The #lxw_format is created using the `workbook_add_format()`
* method in the same way as cell formats.
*
* @note In Excel, a conditional format is superimposed over the existing
* cell format and not all cell format properties can be
* modified. Properties that @b cannot be modified, in Excel, by a
* conditional format are: font name, font size, superscript and
* subscript, diagonal borders, all alignment properties and all
* protection properties. */
lxw_format *format;
/** The minimum value used for Cell, Color Scale and Data Bar conditional
* formats. For Cell types this is usually used with a "Between" style criteria. */
double min_value;
/** The minimum string value used for Cell, Color Scale and Data Bar conditional
* formats. Usually used to set ranges like `=A1`. */
const char *min_value_string;
/** The rule used for the minimum condition in Color Scale and Data Bar
* conditional formats. The rule types are defined in
* #lxw_conditional_format_rule_types. */
uint8_t min_rule_type;
/** The color used for the minimum Color Scale conditional format.
* See @ref working_with_colors. */
lxw_color_t min_color;
/** The middle value used for Color Scale and Data Bar conditional
* formats. */
double mid_value;
/** The middle string value used for Color Scale and Data Bar conditional
* formats. Usually used to set ranges like `=A1`. */
const char *mid_value_string;
/** The rule used for the middle condition in Color Scale and Data Bar
* conditional formats. The rule types are defined in
* #lxw_conditional_format_rule_types. */
uint8_t mid_rule_type;
/** The color used for the middle Color Scale conditional format.
* See @ref working_with_colors. */
lxw_color_t mid_color;
/** The maximum value used for Cell, Color Scale and Data Bar conditional
* formats. For Cell types this is usually used with a "Between" style
* criteria. */
double max_value;
/** The maximum string value used for Cell, Color Scale and Data Bar conditional
* formats. Usually used to set ranges like `=A1`. */
const char *max_value_string;
/** The rule used for the maximum condition in Color Scale and Data Bar
* conditional formats. The rule types are defined in
* #lxw_conditional_format_rule_types. */
uint8_t max_rule_type;
/** The color used for the maximum Color Scale conditional format.
* See @ref working_with_colors. */
lxw_color_t max_color;
/** The bar_color field sets the fill color for data bars. See @ref
* working_with_colors. */
lxw_color_t bar_color;
/** The bar_only field sets The bar_only field displays a bar data but
* not the data in the cells. */
uint8_t bar_only;
/** In Excel 2010 additional data bar properties were added such as solid
* (non-gradient) bars and control over how negative values are
* displayed. These properties can shown below.
*
* The data_bar_2010 field sets Excel 2010 style data bars even when
* Excel 2010 specific properties aren't used. */
uint8_t data_bar_2010;
/** The bar_solid field turns on a solid (non-gradient) fill for data
* bars. Set to LXW_TRUE to turn on. Excel 2010 only. */
uint8_t bar_solid;
/** The bar_negative_color field sets the color fill for the negative
* portion of a data bar. See @ref working_with_colors. Excel 2010 only. */
lxw_color_t bar_negative_color;
/** The bar_border_color field sets the color for the border line of a
* data bar. See @ref working_with_colors. Excel 2010 only. */
lxw_color_t bar_border_color;
/** The bar_negative_border_color field sets the color for the border of
* the negative portion of a data bar. See @ref
* working_with_colors. Excel 2010 only. */
lxw_color_t bar_negative_border_color;
/** The bar_negative_color_same field sets the fill color for the negative
* portion of a data bar to be the same as the fill color for the
* positive portion of the data bar. Set to LXW_TRUE to turn on. Excel
* 2010 only. */
uint8_t bar_negative_color_same;
/** The bar_negative_border_color_same field sets the border color for the
* negative portion of a data bar to be the same as the border color for
* the positive portion of the data bar. Set to LXW_TRUE to turn
* on. Excel 2010 only. */
uint8_t bar_negative_border_color_same;
/** The bar_no_border field turns off the border for data bars. Set to
* LXW_TRUE to enable. Excel 2010 only. */
uint8_t bar_no_border;
/** The bar_direction field sets the direction for data bars. This
* property can be either left for left-to-right or right for
* right-to-left. If the property isn't set then Excel will adjust the
* position automatically based on the context. Should be a
* #lxw_conditional_format_bar_direction value. Excel 2010 only. */
uint8_t bar_direction;
/** The bar_axis_position field sets the position within the cells for the
* axis that is shown in data bars when there are negative values to
* display. The property can be either middle or none. If the property
* isn't set then Excel will position the axis based on the range of
* positive and negative values. Should be a
* lxw_conditional_bar_axis_position value. Excel 2010 only. */
uint8_t bar_axis_position;
/** The bar_axis_color field sets the color for the axis that is shown
* in data bars when there are negative values to display. See @ref
* working_with_colors. Excel 2010 only. */
lxw_color_t bar_axis_color;
/** The Icons Sets style is specified by the icon_style parameter. Should
* be a #lxw_conditional_icon_types. */
uint8_t icon_style;
/** The order of Icon Sets icons can be reversed by setting reverse_icons
* to LXW_TRUE. */
uint8_t reverse_icons;
/** The icons can be displayed without the cell value by settings the
* icons_only parameter to LXW_TRUE. */
uint8_t icons_only;
/** The multi_range field is used to extend a conditional format over
* non-contiguous ranges.
*
* It is possible to apply the conditional format to different cell
* ranges in a worksheet using multiple calls to
* `worksheet_conditional_format()`. However, as a minor optimization it
* is also possible in Excel to apply the same conditional format to
* different non-contiguous cell ranges.
*
* This is replicated in `worksheet_conditional_format()` using the
* multi_range option. The range must contain the primary range for the
* conditional format and any others separated by spaces. For example
* `"A1 C1:C5 E2 G1:G100"`.
*/
const char *multi_range;
/** The stop_if_true parameter can be used to set the "stop if true"
* feature of a conditional formatting rule when more than one rule is
* applied to a cell or a range of cells. When this parameter is set then
* subsequent rules are not evaluated if the current rule is true. Set to
* LXW_TRUE to turn on. */
uint8_t stop_if_true;
} lxw_conditional_format;
/* Internal */
typedef struct lxw_cond_format_obj {
uint8_t type;
uint8_t criteria;
double min_value;
char *min_value_string;
uint8_t min_rule_type;
lxw_color_t min_color;
double mid_value;
char *mid_value_string;
uint8_t mid_value_type;
uint8_t mid_rule_type;
lxw_color_t mid_color;
double max_value;
char *max_value_string;
uint8_t max_value_type;
uint8_t max_rule_type;
lxw_color_t max_color;
uint8_t data_bar_2010;
uint8_t auto_min;
uint8_t auto_max;
uint8_t bar_only;
uint8_t bar_solid;
uint8_t bar_negative_color_same;
uint8_t bar_negative_border_color_same;
uint8_t bar_no_border;
uint8_t bar_direction;
uint8_t bar_axis_position;
lxw_color_t bar_color;
lxw_color_t bar_negative_color;
lxw_color_t bar_border_color;
lxw_color_t bar_negative_border_color;
lxw_color_t bar_axis_color;
uint8_t icon_style;
uint8_t reverse_icons;
uint8_t icons_only;
uint8_t stop_if_true;
uint8_t has_max;
char *type_string;
char *guid;
int32_t dxf_index;
uint32_t dxf_priority;
char first_cell[LXW_MAX_CELL_NAME_LENGTH];
char sqref[LXW_MAX_ATTRIBUTE_LENGTH];
STAILQ_ENTRY (lxw_cond_format_obj) list_pointers;
} lxw_cond_format_obj;
typedef struct lxw_cond_format_hash_element {
char sqref[LXW_MAX_ATTRIBUTE_LENGTH];
struct lxw_cond_format_list *cond_formats;
RB_ENTRY (lxw_cond_format_hash_element) tree_pointers;
} lxw_cond_format_hash_element;
/**
* @brief Table columns options.
*
* Structure to set the options of a table column added with
* worksheet_add_table(). See @ref ww_tables_columns.
*/
typedef struct lxw_table_column {
/** Set the header name/caption for the column. If NULL the header defaults
* to Column 1, Column 2, etc. */
const char *header;
/** Set the formula for the column. */
const char *formula;
/** Set the string description for the column total. */
const char *total_string;
/** Set the function for the column total. */
uint8_t total_function;
/** Set the format for the column header. */
lxw_format *header_format;
/** Set the format for the data rows in the column. */
lxw_format *format;
/** Set the formula value for the column total (not generally required). */
double total_value;
} lxw_table_column;
/**
* @brief Worksheet table options.
*
* Options used to define worksheet tables. See @ref working_with_tables for
* more information.
*
*/
typedef struct lxw_table_options {
/**
* The `name` parameter is used to set the name of the table. This
* parameter is optional and by default tables are named `Table1`,
* `Table2`, etc. in the worksheet order that they are added.
*
* @code
* lxw_table_options options = {.name = "Sales"};
*
* worksheet_add_table(worksheet, RANGE("B3:G8"), &options);
* @endcode
*
* If you override the table name you must ensure that it doesn't clash
* with an existing table name and that it follows Excel's requirements
* for table names, see the Microsoft Office documentation on
* [Naming an Excel Table]
* (https://support.microsoft.com/en-us/office/rename-an-excel-table-fbf49a4f-82a3-43eb-8ba2-44d21233b114).
*/
const char *name;
/**
* The `no_header_row` parameter can be used to turn off the header row in
* the table. It is on by default:
*
* @code
* lxw_table_options options = {.no_header_row = LXW_TRUE};
*
* worksheet_add_table(worksheet, RANGE("B4:F7"), &options);
* @endcode
*
* @image html tables4.png
*
* Without this option the header row will contain default captions such
* as `Column 1`, ``Column 2``, etc. These captions can be overridden
* using the `columns` parameter shown below.
*
*/
uint8_t no_header_row;
/**
* The `no_autofilter` parameter can be used to turn off the autofilter in
* the header row. It is on by default:
*
* @code
* lxw_table_options options = {.no_autofilter = LXW_TRUE};
*
* worksheet_add_table(worksheet, RANGE("B3:F7"), &options);
* @endcode
*
* @image html tables3.png
*
* The autofilter is only shown if the `no_header_row` parameter is off
* (the default). Filter conditions within the table are not supported.
*
*/
uint8_t no_autofilter;
/**
* The `no_banded_rows` parameter can be used to turn off the rows of alternating
* color in the table. It is on by default:
*
* @code
* lxw_table_options options = {.no_banded_rows = LXW_TRUE};
*
* worksheet_add_table(worksheet, RANGE("B3:F7"), &options);
* @endcode
*
* @image html tables6.png
*
*/
uint8_t no_banded_rows;
/**
* The `banded_columns` parameter can be used to used to create columns of
* alternating color in the table. It is off by default:
*
* @code
* lxw_table_options options = {.banded_columns = LXW_TRUE};
*
* worksheet_add_table(worksheet, RANGE("B3:F7"), &options);
* @endcode
*
* The banded columns formatting is shown in the image in the previous
* section above.
*/
uint8_t banded_columns;
/**
* The `first_column` parameter can be used to highlight the first column
* of the table. The type of highlighting will depend on the `style_type`
* of the table. It may be bold text or a different color. It is off by
* default:
*
* @code
* lxw_table_options options = {.first_column = LXW_TRUE, .last_column = LXW_TRUE};
*
* worksheet_add_table(worksheet, RANGE("B3:F7"), &options);
* @endcode
*
* @image html tables5.png
*/
uint8_t first_column;
/**
* The `last_column` parameter can be used to highlight the last column of
* the table. The type of highlighting will depend on the `style` of the
* table. It may be bold text or a different color. It is off by default:
*
* @code
* lxw_table_options options = {.first_column = LXW_TRUE, .last_column = LXW_TRUE};
*
* worksheet_add_table(worksheet, RANGE("B3:F7"), &options);
* @endcode
*
* The `last_column` formatting is shown in the image in the previous
* section above.
*/
uint8_t last_column;
/**
* The `style_type` parameter can be used to set the style of the table,
* in conjunction with the `style_type_number` parameter:
*
* @code
* lxw_table_options options = {
* .style_type = LXW_TABLE_STYLE_TYPE_LIGHT,
* .style_type_number = 11,
* };
*
* worksheet_add_table(worksheet, RANGE("B3:G8"), &options);
* @endcode
*
*
* @image html tables11.png
*
* There are three types of table style in Excel: Light, Medium and Dark
* which are represented using the #lxw_table_style_type enum values:
*
* - #LXW_TABLE_STYLE_TYPE_LIGHT
*
* - #LXW_TABLE_STYLE_TYPE_MEDIUM
*
* - #LXW_TABLE_STYLE_TYPE_DARK
*
* Within those ranges there are between 11 and 28 other style types which
* can be set with `style_type_number` (depending on the style type).
* Check Excel to find the style that you want. The dialog with the
* options laid out in numeric order are shown below:
*
* @image html tables14.png
*
* The default table style in Excel is 'Table Style Medium 9' (highlighted
* with a green border in the image above), which is set by default in
* libxlsxwriter as:
*
* @code
* lxw_table_options options = {
* .style_type = LXW_TABLE_STYLE_TYPE_MEDIUM,
* .style_type_number = 9,
* };
* @endcode
*
* You can also turn the table style off by setting it to Light 0:
*
* @code
* lxw_table_options options = {
* .style_type = LXW_TABLE_STYLE_TYPE_LIGHT,
* .style_type_number = 0,
* };
* @endcode
*
* @image html tables13.png
*
*/
uint8_t style_type;
/**
* The `style_type_number` parameter is used with `style_type` to set the
* style of a worksheet table. */
uint8_t style_type_number;
/**
* The `total_row` parameter can be used to turn on the total row in the
* last row of a table. It is distinguished from the other rows by a
* different formatting and also with dropdown `SUBTOTAL` functions:
*
* @code
* lxw_table_options options = {.total_row = LXW_TRUE};
*
* worksheet_add_table(worksheet, RANGE("B3:G8"), &options);
* @endcode
*
* @image html tables9.png
*
* The default total row doesn't have any captions or functions. These
* must by specified via the `columns` parameter below.
*/
uint8_t total_row;
/**
* The `columns` parameter can be used to set properties for columns
* within the table. See @ref ww_tables_columns for a detailed
* explanation.
*/
lxw_table_column **columns;
} lxw_table_options;
typedef struct lxw_table_obj {
char *name;
char *total_string;
lxw_table_column **columns;
uint8_t banded_columns;
uint8_t first_column;
uint8_t last_column;
uint8_t no_autofilter;
uint8_t no_banded_rows;
uint8_t no_header_row;
uint8_t style_type;
uint8_t style_type_number;
uint8_t total_row;
lxw_row_t first_row;
lxw_col_t first_col;
lxw_row_t last_row;
lxw_col_t last_col;
lxw_col_t num_cols;
uint32_t id;
char sqref[LXW_MAX_ATTRIBUTE_LENGTH];
char filter_sqref[LXW_MAX_ATTRIBUTE_LENGTH];
STAILQ_ENTRY (lxw_table_obj) list_pointers;
} lxw_table_obj;
/**
* @brief Options for autofilter rules.
*
* Options to define an autofilter rule.
*
*/
typedef struct lxw_filter_rule {
/** The #lxw_filter_criteria to define the rule. */
uint8_t criteria;
/** String value to which the criteria applies. */
const char *value_string;
/** Numeric value to which the criteria applies (if value_string isn't used). */
double value;
} lxw_filter_rule;
typedef struct lxw_filter_rule_obj {
uint8_t type;
uint8_t is_custom;
uint8_t has_blanks;
lxw_col_t col_num;
uint8_t criteria1;
uint8_t criteria2;
double value1;
double value2;
char *value1_string;
char *value2_string;
uint16_t num_list_filters;
char **list;
} lxw_filter_rule_obj;
/**
* @brief Options for inserted images.
*
* Options for modifying images inserted via `worksheet_insert_image_opt()`.
*
*/
typedef struct lxw_image_options {
/** Offset from the left of the cell in pixels. */
int32_t x_offset;
/** Offset from the top of the cell in pixels. */
int32_t y_offset;
/** X scale of the image as a decimal. */
double x_scale;
/** Y scale of the image as a decimal. */
double y_scale;
/** Object position - use one of the values of #lxw_object_position.
* See @ref working_with_object_positioning.*/
uint8_t object_position;
/** Optional description or "Alt text" for the image. This field can be
* used to provide a text description of the image to help
* accessibility. Defaults to the image filename as in Excel. Set to ""
* to ignore the description field. */
const char *description;
/** Optional parameter to help accessibility. It is used to mark the image
* as decorative, and thus uninformative, for automated screen
* readers. As in Excel, if this parameter is in use the `description`
* field isn't written. */
uint8_t decorative;
/** Add an optional hyperlink to the image. Follows the same URL rules
* and types as `worksheet_write_url()`. */
const char *url;
/** Add an optional mouseover tip for a hyperlink to the image. */
const char *tip;
} lxw_image_options;
/**
* @brief Options for inserted charts.
*
* Options for modifying charts inserted via `worksheet_insert_chart_opt()`.
*
*/
typedef struct lxw_chart_options {
/** Offset from the left of the cell in pixels. */
int32_t x_offset;
/** Offset from the top of the cell in pixels. */
int32_t y_offset;
/** X scale of the chart as a decimal. */
double x_scale;
/** Y scale of the chart as a decimal. */
double y_scale;
/** Object position - use one of the values of #lxw_object_position.
* See @ref working_with_object_positioning.*/
uint8_t object_position;
/** Optional description or "Alt text" for the chart. This field can be
* used to provide a text description of the chart to help
* accessibility. Defaults to the image filename as in Excel. Set to NULL
* to ignore the description field. */
const char *description;
/** Optional parameter to help accessibility. It is used to mark the chart
* as decorative, and thus uninformative, for automated screen
* readers. As in Excel, if this parameter is in use the `description`
* field isn't written. */
uint8_t decorative;
} lxw_chart_options;
/* Internal struct to represent lxw_image_options and lxw_chart_options
* values as well as internal metadata.
*/
typedef struct lxw_object_properties {
int32_t x_offset;
int32_t y_offset;
double x_scale;
double y_scale;
lxw_row_t row;
lxw_col_t col;
char *filename;
char *description;
char *url;
char *tip;
uint8_t object_position;
FILE *stream;
uint8_t image_type;
uint8_t is_image_buffer;
char *image_buffer;
size_t image_buffer_size;
double width;
double height;
char *extension;
double x_dpi;
double y_dpi;
lxw_chart *chart;
uint8_t is_duplicate;
uint8_t is_background;
char *md5;
char *image_position;
uint8_t decorative;
STAILQ_ENTRY (lxw_object_properties) list_pointers;
} lxw_object_properties;
/**
* @brief Options for inserted comments.
*
* Options for modifying comments inserted via `worksheet_write_comment_opt()`.
*
*/
typedef struct lxw_comment_options {
/** This option is used to make a cell comment visible when the worksheet
* is opened. The default behavior in Excel is that comments are
* initially hidden. However, it is also possible in Excel to make
* individual comments or all comments visible. You can make all
* comments in the worksheet visible using the
* `worksheet_show_comments()` function. Defaults to
* LXW_COMMENT_DISPLAY_DEFAULT. See also @ref ww_comments_visible. */
uint8_t visible;
/** This option is used to indicate the author of the cell comment. Excel
* displays the author in the status bar at the bottom of the
* worksheet. The default author for all cell comments in a worksheet can
* be set using the `worksheet_set_comments_author()` function. Set to
* NULL if not required. See also @ref ww_comments_author. */
const char *author;
/** This option is used to set the width of the cell comment box
* explicitly in pixels. The default width is 128 pixels. See also @ref
* ww_comments_width. */
uint16_t width;
/** This option is used to set the height of the cell comment box
* explicitly in pixels. The default height is 74 pixels. See also @ref
* ww_comments_height. */
uint16_t height;
/** X scale of the comment as a decimal. See also
* @ref ww_comments_x_scale. */
double x_scale;
/** Y scale of the comment as a decimal. See also
* @ref ww_comments_y_scale. */
double y_scale;
/** This option is used to set the background color of cell comment
* box. The color should be an RGB integer value, see @ref
* working_with_colors. See also @ref ww_comments_color. */
lxw_color_t color;
/** This option is used to set the font for the comment. The default font
* is 'Tahoma'. See also @ref ww_comments_font_name. */
const char *font_name;
/** This option is used to set the font size for the comment. The default
* is 8. See also @ref ww_comments_font_size. */
double font_size;
/** This option is used to set the font family number for the comment.
* Not required very often. Set to 0. */
uint8_t font_family;
/** This option is used to set the row in which the comment will
* appear. By default Excel displays comments one cell to the right and
* one cell above the cell to which the comment relates. The `start_row`
* and `start_col` options should both be set to 0 if not used. See also
* @ref ww_comments_start_row. */
lxw_row_t start_row;
/** This option is used to set the column in which the comment will
* appear. See the `start_row` option for more information and see also
* @ref ww_comments_start_col. */
lxw_col_t start_col;
/** Offset from the left of the cell in pixels. See also
* @ref ww_comments_x_offset. */
int32_t x_offset;
/** Offset from the top of the cell in pixels. See also
* @ref ww_comments_y_offset. */
int32_t y_offset;
} lxw_comment_options;
/**
* @brief Options for inserted buttons.
*
* Options for modifying buttons inserted via `worksheet_insert_button()`.
*
*/
typedef struct lxw_button_options {
/** Sets the caption on the button. The default is "Button n" where n is
* the current number of buttons in the worksheet, including this
* button. */
const char *caption;
/** Name of the macro to run when the button is pressed. The macro must be
* included with workbook_add_vba_project(). */
const char *macro;
/** Optional description or "Alt text" for the button. This field can be
* used to provide a text description of the button to help
* accessibility. Set to NULL to ignore the description field. */
const char *description;
/** This option is used to set the width of the cell button box
* explicitly in pixels. The default width is 64 pixels. */
uint16_t width;
/** This option is used to set the height of the cell button box
* explicitly in pixels. The default height is 20 pixels. */
uint16_t height;
/** X scale of the button as a decimal. */
double x_scale;
/** Y scale of the button as a decimal. */
double y_scale;
/** Offset from the left of the cell in pixels. */
int32_t x_offset;
/** Offset from the top of the cell in pixels. */
int32_t y_offset;
} lxw_button_options;
/* Internal structure for VML object options. */
typedef struct lxw_vml_obj {
lxw_row_t row;
lxw_col_t col;
lxw_row_t start_row;
lxw_col_t start_col;
int32_t x_offset;
int32_t y_offset;
uint64_t col_absolute;
uint64_t row_absolute;
uint32_t width;
uint32_t height;
double x_dpi;
double y_dpi;
lxw_color_t color;
uint8_t font_family;
uint8_t visible;
uint32_t author_id;
uint32_t rel_index;
double font_size;
struct lxw_drawing_coords from;
struct lxw_drawing_coords to;
char *author;
char *font_name;
char *text;
char *image_position;
char *name;
char *macro;
STAILQ_ENTRY (lxw_vml_obj) list_pointers;
} lxw_vml_obj;
/**
* @brief Header and footer options.
*
* Optional parameters used in the `worksheet_set_header_opt()` and
* worksheet_set_footer_opt() functions.
*
*/
typedef struct lxw_header_footer_options {
/** Header or footer margin in inches. Excel default is 0.3. Must by
* larger than 0.0. See `worksheet_set_header_opt()`. */
double margin;
/** The left header image filename, with path if required. This should
* have a corresponding `&G/&[Picture]` placeholder in the `&L` section of
* the header/footer string. See `worksheet_set_header_opt()`. */
const char *image_left;
/** The center header image filename, with path if required. This should
* have a corresponding `&G/&[Picture]` placeholder in the `&C` section of
* the header/footer string. See `worksheet_set_header_opt()`. */
const char *image_center;
/** The right header image filename, with path if required. This should
* have a corresponding `&G/&[Picture]` placeholder in the `&R` section of
* the header/footer string. See `worksheet_set_header_opt()`. */
const char *image_right;
} lxw_header_footer_options;
/**
* @brief Worksheet protection options.
*/
typedef struct lxw_protection {
/** Turn off selection of locked cells. This in on in Excel by default.*/
uint8_t no_select_locked_cells;
/** Turn off selection of unlocked cells. This in on in Excel by default.*/
uint8_t no_select_unlocked_cells;
/** Prevent formatting of cells. */
uint8_t format_cells;
/** Prevent formatting of columns. */
uint8_t format_columns;
/** Prevent formatting of rows. */
uint8_t format_rows;
/** Prevent insertion of columns. */
uint8_t insert_columns;
/** Prevent insertion of rows. */
uint8_t insert_rows;
/** Prevent insertion of hyperlinks. */
uint8_t insert_hyperlinks;
/** Prevent deletion of columns. */
uint8_t delete_columns;
/** Prevent deletion of rows. */
uint8_t delete_rows;
/** Prevent sorting data. */
uint8_t sort;
/** Prevent filtering data. */
uint8_t autofilter;
/** Prevent insertion of pivot tables. */
uint8_t pivot_tables;
/** Protect scenarios. */
uint8_t scenarios;
/** Protect drawing objects. Worksheets only. */
uint8_t objects;
/** Turn off chartsheet content protection. */
uint8_t no_content;
/** Turn off chartsheet objects. */
uint8_t no_objects;
} lxw_protection;
/* Internal struct to copy lxw_protection options and internal metadata. */
typedef struct lxw_protection_obj {
uint8_t no_select_locked_cells;
uint8_t no_select_unlocked_cells;
uint8_t format_cells;
uint8_t format_columns;
uint8_t format_rows;
uint8_t insert_columns;
uint8_t insert_rows;
uint8_t insert_hyperlinks;
uint8_t delete_columns;
uint8_t delete_rows;
uint8_t sort;
uint8_t autofilter;
uint8_t pivot_tables;
uint8_t scenarios;
uint8_t objects;
uint8_t no_content;
uint8_t no_objects;
uint8_t no_sheet;
uint8_t is_configured;
char hash[5];
} lxw_protection_obj;
/**
* @brief Struct to represent a rich string format/string pair.
*
* Arrays of this struct are used to define "rich" multi-format strings that
* are passed to `worksheet_write_rich_string()`. Each struct represents a
* fragment of the rich multi-format string with a lxw_format to define the
* format for the string part. If the string fragment is unformatted then
* `NULL` can be used for the format.
*/
typedef struct lxw_rich_string_tuple {
/** The format for a string fragment in a rich string. NULL if the string
* isn't formatted. */
lxw_format *format;
/** The string fragment. */
const char *string;
} lxw_rich_string_tuple;
/**
* @brief Struct to represent an Excel worksheet.
*
* The members of the lxw_worksheet struct aren't modified directly. Instead
* the worksheet properties are set by calling the functions shown in
* worksheet.h.
*/
typedef struct lxw_worksheet {
FILE *file;
FILE *optimize_tmpfile;
char *optimize_buffer;
size_t optimize_buffer_size;
struct lxw_table_rows *table;
struct lxw_table_rows *hyperlinks;
struct lxw_table_rows *comments;
struct lxw_cell **array;
struct lxw_merged_ranges *merged_ranges;
struct lxw_selections *selections;
struct lxw_data_validations *data_validations;
struct lxw_cond_format_hash *conditional_formats;
struct lxw_image_props *image_props;
struct lxw_chart_props *chart_data;
struct lxw_drawing_rel_ids *drawing_rel_ids;
struct lxw_vml_drawing_rel_ids *vml_drawing_rel_ids;
struct lxw_comment_objs *comment_objs;
struct lxw_comment_objs *header_image_objs;
struct lxw_comment_objs *button_objs;
struct lxw_table_objs *table_objs;
uint16_t table_count;
lxw_row_t dim_rowmin;
lxw_row_t dim_rowmax;
lxw_col_t dim_colmin;
lxw_col_t dim_colmax;
lxw_sst *sst;
const char *name;
const char *quoted_name;
const char *tmpdir;
uint16_t index;
uint8_t active;
uint8_t selected;
uint8_t hidden;
uint16_t *active_sheet;
uint16_t *first_sheet;
uint8_t is_chartsheet;
lxw_col_options **col_options;
uint16_t col_options_max;
double *col_sizes;
uint16_t col_sizes_max;
lxw_format **col_formats;
uint16_t col_formats_max;
uint8_t col_size_changed;
uint8_t row_size_changed;
uint8_t optimize;
struct lxw_row *optimize_row;
uint16_t fit_height;
uint16_t fit_width;
uint16_t horizontal_dpi;
uint16_t hlink_count;
uint16_t page_start;
uint16_t print_scale;
uint16_t rel_count;
uint16_t vertical_dpi;
uint16_t zoom;
uint8_t filter_on;
uint8_t fit_page;
uint8_t hcenter;
uint8_t orientation;
uint8_t outline_changed;
uint8_t outline_on;
uint8_t outline_style;
uint8_t outline_below;
uint8_t outline_right;
uint8_t page_order;
uint8_t page_setup_changed;
uint8_t page_view;
uint8_t paper_size;
uint8_t print_gridlines;
uint8_t print_headers;
uint8_t print_options_changed;
uint8_t right_to_left;
uint8_t screen_gridlines;
uint8_t show_zeros;
uint8_t vcenter;
uint8_t zoom_scale_normal;
uint8_t black_white;
uint8_t num_validations;
uint8_t has_dynamic_arrays;
char *vba_codename;
uint16_t num_buttons;
lxw_color_t tab_color;
double margin_left;
double margin_right;
double margin_top;
double margin_bottom;
double margin_header;
double margin_footer;
double default_row_height;
uint32_t default_row_pixels;
uint32_t default_col_pixels;
uint8_t default_row_zeroed;
uint8_t default_row_set;
uint8_t outline_row_level;
uint8_t outline_col_level;
uint8_t header_footer_changed;
char *header;
char *footer;
struct lxw_repeat_rows repeat_rows;
struct lxw_repeat_cols repeat_cols;
struct lxw_print_area print_area;
struct lxw_autofilter autofilter;
uint16_t merged_range_count;
uint16_t max_url_length;
lxw_row_t *hbreaks;
lxw_col_t *vbreaks;
uint16_t hbreaks_count;
uint16_t vbreaks_count;
uint32_t drawing_rel_id;
uint32_t vml_drawing_rel_id;
struct lxw_rel_tuples *external_hyperlinks;
struct lxw_rel_tuples *external_drawing_links;
struct lxw_rel_tuples *drawing_links;
struct lxw_rel_tuples *vml_drawing_links;
struct lxw_rel_tuples *external_table_links;
struct lxw_panes panes;
char top_left_cell[LXW_MAX_CELL_NAME_LENGTH];
struct lxw_protection_obj protection;
lxw_drawing *drawing;
lxw_format *default_url_format;
uint8_t has_vml;
uint8_t has_comments;
uint8_t has_header_vml;
uint8_t has_background_image;
uint8_t has_buttons;
lxw_rel_tuple *external_vml_comment_link;
lxw_rel_tuple *external_comment_link;
lxw_rel_tuple *external_vml_header_link;
lxw_rel_tuple *external_background_link;
char *comment_author;
char *vml_data_id_str;
char *vml_header_id_str;
uint32_t vml_shape_id;
uint32_t vml_header_id;
uint32_t dxf_priority;
uint8_t comment_display_default;
uint32_t data_bar_2010_index;
uint8_t has_ignore_errors;
char *ignore_number_stored_as_text;
char *ignore_eval_error;
char *ignore_formula_differs;
char *ignore_formula_range;
char *ignore_formula_unlocked;
char *ignore_empty_cell_reference;
char *ignore_list_data_validation;
char *ignore_calculated_column;
char *ignore_two_digit_text_year;
uint16_t excel_version;
lxw_object_properties **header_footer_objs[LXW_HEADER_FOOTER_OBJS_MAX];
lxw_object_properties *header_left_object_props;
lxw_object_properties *header_center_object_props;
lxw_object_properties *header_right_object_props;
lxw_object_properties *footer_left_object_props;
lxw_object_properties *footer_center_object_props;
lxw_object_properties *footer_right_object_props;
lxw_object_properties *background_image;
lxw_filter_rule_obj **filter_rules;
lxw_col_t num_filter_rules;
STAILQ_ENTRY (lxw_worksheet) list_pointers;
} lxw_worksheet;
/*
* Worksheet initialization data.
*/
typedef struct lxw_worksheet_init_data {
uint16_t index;
uint8_t hidden;
uint8_t optimize;
uint16_t *active_sheet;
uint16_t *first_sheet;
lxw_sst *sst;
const char *name;
const char *quoted_name;
const char *tmpdir;
lxw_format *default_url_format;
uint16_t max_url_length;
} lxw_worksheet_init_data;
/* Struct to represent a worksheet row. */
typedef struct lxw_row {
lxw_row_t row_num;
double height;
lxw_format *format;
uint8_t hidden;
uint8_t level;
uint8_t collapsed;
uint8_t row_changed;
uint8_t data_changed;
uint8_t height_changed;
struct lxw_table_cells *cells;
/* tree management pointers for tree.h. */
RB_ENTRY (lxw_row) tree_pointers;
} lxw_row;
/* Struct to represent a worksheet cell. */
typedef struct lxw_cell {
lxw_row_t row_num;
lxw_col_t col_num;
enum cell_types type;
lxw_format *format;
lxw_vml_obj *comment;
union {
double number;
int32_t string_id;
const char *string;
} u;
double formula_result;
char *user_data1;
char *user_data2;
char *sst_string;
/* List pointers for tree.h. */
RB_ENTRY (lxw_cell) tree_pointers;
} lxw_cell;
/* Struct to represent a drawing Target/ID pair. */
typedef struct lxw_drawing_rel_id {
uint32_t id;
char *target;
RB_ENTRY (lxw_drawing_rel_id) tree_pointers;
} lxw_drawing_rel_id;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/**
* @brief Write a number to a worksheet cell.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param number The number to write to the cell.
* @param format A pointer to a Format instance or NULL.
*
* @return A #lxw_error code.
*
* The `worksheet_write_number()` function writes numeric types to the cell
* specified by `row` and `column`:
*
* @code
* worksheet_write_number(worksheet, 0, 0, 123456, NULL);
* worksheet_write_number(worksheet, 1, 0, 2.3451, NULL);
* @endcode
*
* @image html write_number01.png
*
* The native data type for all numbers in Excel is a IEEE-754 64-bit
* double-precision floating point, which is also the default type used by
* `%worksheet_write_number`.
*
* The `format` parameter is used to apply formatting to the cell. This
* parameter can be `NULL` to indicate no formatting or it can be a
* @ref format.h "Format" object.
*
* @code
* lxw_format *format = workbook_add_format(workbook);
* format_set_num_format(format, "$#,##0.00");
*
* worksheet_write_number(worksheet, 0, 0, 1234.567, format);
* @endcode
*
* @image html write_number02.png
*
* @note Excel doesn't support `NaN`, `Inf` or `-Inf` as a number value. If
* you are writing data that contains these values then your application
* should convert them to a string or handle them in some other way.
*
*/
lxw_error worksheet_write_number(lxw_worksheet *worksheet,
lxw_row_t row,
lxw_col_t col, double number,
lxw_format *format);
/**
* @brief Write a string to a worksheet cell.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param string String to write to cell.
* @param format A pointer to a Format instance or NULL.
*
* @return A #lxw_error code.
*
* The `%worksheet_write_string()` function writes a string to the cell
* specified by `row` and `column`:
*
* @code
* worksheet_write_string(worksheet, 0, 0, "This phrase is English!", NULL);
* @endcode
*
* @image html write_string01.png
*
* The `format` parameter is used to apply formatting to the cell. This
* parameter can be `NULL` to indicate no formatting or it can be a
* @ref format.h "Format" object:
*
* @code
* lxw_format *format = workbook_add_format(workbook);
* format_set_bold(format);
*
* worksheet_write_string(worksheet, 0, 0, "This phrase is Bold!", format);
* @endcode
*
* @image html write_string02.png
*
* Unicode strings are supported in UTF-8 encoding. This generally requires
* that your source file is UTF-8 encoded or that the data has been read from
* a UTF-8 source:
*
* @code
* worksheet_write_string(worksheet, 0, 0, "Это фраза на русском!", NULL);
* @endcode
*
* @image html write_string03.png
*
*/
lxw_error worksheet_write_string(lxw_worksheet *worksheet,
lxw_row_t row,
lxw_col_t col, const char *string,
lxw_format *format);
/**
* @brief Write a formula to a worksheet cell.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param formula Formula string to write to cell.
* @param format A pointer to a Format instance or NULL.
*
* @return A #lxw_error code.
*
* The `%worksheet_write_formula()` function writes a formula or function to
* the cell specified by `row` and `column`:
*
* @code
* worksheet_write_formula(worksheet, 0, 0, "=B3 + 6", NULL);
* worksheet_write_formula(worksheet, 1, 0, "=SIN(PI()/4)", NULL);
* worksheet_write_formula(worksheet, 2, 0, "=SUM(A1:A2)", NULL);
* worksheet_write_formula(worksheet, 3, 0, "=IF(A3>1,\"Yes\", \"No\")", NULL);
* worksheet_write_formula(worksheet, 4, 0, "=AVERAGE(1, 2, 3, 4)", NULL);
* worksheet_write_formula(worksheet, 5, 0, "=DATEVALUE(\"1-Jan-2013\")", NULL);
* @endcode
*
* @image html write_formula01.png
*
* The `format` parameter is used to apply formatting to the cell. This
* parameter can be `NULL` to indicate no formatting or it can be a
* @ref format.h "Format" object.
*
* Libxlsxwriter doesn't calculate the value of a formula and instead stores a
* default value of `0`. The correct formula result is displayed in Excel, as
* shown in the example above, since it recalculates the formulas when it loads
* the file. For cases where this is an issue see the
* `worksheet_write_formula_num()` function and the discussion in that section.
*
* Formulas must be written with the US style separator/range operator which
* is a comma (not semi-colon). Therefore a formula with multiple values
* should be written as follows:
*
* @code
* // OK.
* worksheet_write_formula(worksheet, 0, 0, "=SUM(1, 2, 3)", NULL);
*
* // NO. Error on load.
* worksheet_write_formula(worksheet, 1, 0, "=SUM(1; 2; 3)", NULL);
* @endcode
*
* See also @ref working_with_formulas.
*/
lxw_error worksheet_write_formula(lxw_worksheet *worksheet,
lxw_row_t row,
lxw_col_t col, const char *formula,
lxw_format *format);
/**
* @brief Write an array formula to a worksheet cell.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param first_row The first row of the range. (All zero indexed.)
* @param first_col The first column of the range.
* @param last_row The last row of the range.
* @param last_col The last col of the range.
* @param formula Array formula to write to cell.
* @param format A pointer to a Format instance or NULL.
*
* @return A #lxw_error code.
*
* The `%worksheet_write_array_formula()` function writes an array formula to
* a cell range. In Excel an array formula is a formula that performs a
* calculation on a set of values.
*
* In Excel an array formula is indicated by a pair of braces around the
* formula: `{=SUM(A1:B1*A2:B2)}`.
*
* Array formulas can return a single value or a range or values. For array
* formulas that return a range of values you must specify the range that the
* return values will be written to. This is why this function has `first_`
* and `last_` row/column parameters. The RANGE() macro can also be used to
* specify the range:
*
* @code
* worksheet_write_array_formula(worksheet, 4, 0, 6, 0, "{=TREND(C5:C7,B5:B7)}", NULL);
*
* // Same as above using the RANGE() macro.
* worksheet_write_array_formula(worksheet, RANGE("A5:A7"), "{=TREND(C5:C7,B5:B7)}", NULL);
* @endcode
*
* If the array formula returns a single value then the `first_` and `last_`
* parameters should be the same:
*
* @code
* worksheet_write_array_formula(worksheet, 1, 0, 1, 0, "{=SUM(B1:C1*B2:C2)}", NULL);
* worksheet_write_array_formula(worksheet, RANGE("A2:A2"), "{=SUM(B1:C1*B2:C2)}", NULL);
* @endcode
*
*/
lxw_error worksheet_write_array_formula(lxw_worksheet *worksheet,
lxw_row_t first_row,
lxw_col_t first_col,
lxw_row_t last_row,
lxw_col_t last_col,
const char *formula,
lxw_format *format);
/**
* @brief Write an Excel 365 dynamic array formula to a worksheet range.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param first_row The first row of the range. (All zero indexed.)
* @param first_col The first column of the range.
* @param last_row The last row of the range.
* @param last_col The last col of the range.
* @param formula Dynamic Array formula to write to cell.
* @param format A pointer to a Format instance or NULL.
*
* @return A #lxw_error code.
*
*
* The `%worksheet_write_dynamic_array_formula()` function writes an Excel 365
* dynamic array formula to a cell range. Some examples of functions that
* return dynamic arrays are:
*
* - `FILTER`
* - `RANDARRAY`
* - `SEQUENCE`
* - `SORTBY`
* - `SORT`
* - `UNIQUE`
* - `XLOOKUP`
* - `XMATCH`
*
* Dynamic array formulas and their usage in libxlsxwriter is explained in
* detail @ref ww_formulas_dynamic_arrays. The following is a example usage:
*
* @code
* worksheet_write_dynamic_array_formula(worksheet, 1, 5, 1, 5,
* "=_xlfn._xlws.FILTER(A1:D17,C1:C17=K2)",
* NULL);
* @endcode
*
* This formula gives the results shown in the image below.
*
* @image html dynamic_arrays02.png
*
* The need for the `_xlfn._xlws.` prefix in the formula is explained in @ref
* ww_formulas_future.
*/
lxw_error worksheet_write_dynamic_array_formula(lxw_worksheet *worksheet,
lxw_row_t first_row,
lxw_col_t first_col,
lxw_row_t last_row,
lxw_col_t last_col,
const char *formula,
lxw_format *format);
/**
* @brief Write an Excel 365 dynamic array formula to a worksheet cell.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param formula Formula string to write to cell.
* @param format A pointer to a Format instance or NULL.
*
* @return A #lxw_error code.
*
* The `%worksheet_write_dynamic_formula()` function is similar to the
* `worksheet_write_dynamic_array_formula()` function, shown above, except
* that it writes a dynamic array formula to a single cell, rather than a
* range. This is a syntactic shortcut since the array range isn't generally
* known for a dynamic range and specifying the initial cell is sufficient for
* Excel, as shown in the example below:
*
* @code
* worksheet_write_dynamic_formula(worksheet, 7, 1,
* "=_xlfn._xlws.SORT(_xlfn.UNIQUE(B2:B17))",
* NULL);
* @endcode
*
* This formula gives the following result:
*
* @image html dynamic_arrays01.png
*
* The need for the `_xlfn.` and `_xlfn._xlws.` prefixes in the formula is
* explained in @ref ww_formulas_future.
*/
lxw_error worksheet_write_dynamic_formula(lxw_worksheet *worksheet,
lxw_row_t row,
lxw_col_t col,
const char *formula,
lxw_format *format);
lxw_error worksheet_write_array_formula_num(lxw_worksheet *worksheet,
lxw_row_t first_row,
lxw_col_t first_col,
lxw_row_t last_row,
lxw_col_t last_col,
const char *formula,
lxw_format *format,
double result);
lxw_error worksheet_write_dynamic_array_formula_num(lxw_worksheet *worksheet,
lxw_row_t first_row,
lxw_col_t first_col,
lxw_row_t last_row,
lxw_col_t last_col,
const char *formula,
lxw_format *format,
double result);
lxw_error worksheet_write_dynamic_formula_num(lxw_worksheet *worksheet,
lxw_row_t row,
lxw_col_t col,
const char *formula,
lxw_format *format,
double result);
/**
* @brief Write a date or time to a worksheet cell.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param datetime The datetime to write to the cell.
* @param format A pointer to a Format instance or NULL.
*
* @return A #lxw_error code.
*
* The `%worksheet_write_datetime()` function can be used to write a date or
* time to the cell specified by `row` and `column`:
*
* @dontinclude dates_and_times02.c
* @skip include
* @until num_format
* @skip Feb
* @until }
*
* The `format` parameter should be used to apply formatting to the cell using
* a @ref format.h "Format" object as shown above. Without a date format the
* datetime will appear as a number only.
*
* See @ref working_with_dates for more information about handling dates and
* times in libxlsxwriter.
*/
lxw_error worksheet_write_datetime(lxw_worksheet *worksheet,
lxw_row_t row,
lxw_col_t col, lxw_datetime *datetime,
lxw_format *format);
/**
* @brief Write a Unix datetime to a worksheet cell.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param unixtime The Unix datetime to write to the cell.
* @param format A pointer to a Format instance or NULL.
*
* @return A #lxw_error code.
*
* The `%worksheet_write_unixtime()` function can be used to write dates and
* times in Unix date format to the cell specified by `row` and
* `column`. [Unix Time](https://en.wikipedia.org/wiki/Unix_time) which is a
* common integer time format. It is defined as the number of seconds since
* the Unix epoch (1970-01-01 00:00 UTC). Negative values can also be used for
* dates prior to 1970:
*
* @dontinclude dates_and_times03.c
* @skip 1970
* @until 2208988800
*
* The `format` parameter should be used to apply formatting to the cell using
* a @ref format.h "Format" object as shown above. Without a date format the
* datetime will appear as a number only.
*
* The output from this code sample is:
*
* @image html date_example03.png
*
* Unixtime is generally represented with a 32 bit `time_t` type which has a
* range of approximately 1900-12-14 to 2038-01-19. To access the full Excel
* date range of 1900-01-01 to 9999-12-31 this function uses a 64 bit
* parameter.
*
* See @ref working_with_dates for more information about handling dates and
* times in libxlsxwriter.
*/
lxw_error worksheet_write_unixtime(lxw_worksheet *worksheet,
lxw_row_t row,
lxw_col_t col, int64_t unixtime,
lxw_format *format);
/**
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param url The url to write to the cell.
* @param format A pointer to a Format instance or NULL.
*
* @return A #lxw_error code.
*
*
* The `%worksheet_write_url()` function is used to write a URL/hyperlink to a
* worksheet cell specified by `row` and `column`.
*
* @code
* worksheet_write_url(worksheet, 0, 0, "http://libxlsxwriter.github.io", NULL);
* @endcode
*
* @image html hyperlinks_short.png
*
* The `format` parameter is used to apply formatting to the cell. This
* parameter can be `NULL`, in which case the default Excel blue underlined
* hyperlink style will be used. If required a user defined @ref format.h
* "Format" object can be used:
* underline:
*
* @code
* lxw_format *url_format = workbook_add_format(workbook);
*
* format_set_underline (url_format, LXW_UNDERLINE_SINGLE);
* format_set_font_color(url_format, LXW_COLOR_RED);
*
* @endcode
*
* The usual web style URI's are supported: `%http://`, `%https://`, `%ftp://`
* and `mailto:` :
*
* @code
* worksheet_write_url(worksheet, 0, 0, "ftp://www.python.org/", NULL);
* worksheet_write_url(worksheet, 1, 0, "http://www.python.org/", NULL);
* worksheet_write_url(worksheet, 2, 0, "https://www.python.org/", NULL);
* worksheet_write_url(worksheet, 3, 0, "mailto:jmcnamara@cpan.org", NULL);
*
* @endcode
*
* An Excel hyperlink is comprised of two elements: the displayed string and
* the non-displayed link. By default the displayed string is the same as the
* link. However, it is possible to overwrite it with any other
* `libxlsxwriter` type using the appropriate `worksheet_write_*()`
* function. The most common case is to overwrite the displayed link text with
* another string. To do this we must also match the default URL format using
* `workbook_get_default_url_format()`:
*
* @code
* // Write a hyperlink with the default blue underline format.
* worksheet_write_url(worksheet, 2, 0, "http://libxlsxwriter.github.io", NULL);
*
* // Get the default url format.
* lxw_format *url_format = workbook_get_default_url_format(workbook);
*
* // Overwrite the hyperlink with a user defined string and default format.
* worksheet_write_string(worksheet, 2, 0, "Read the documentation.", url_format);
* @endcode
*
* @image html hyperlinks_short2.png
*
* Two local URIs are supported: `internal:` and `external:`. These are used
* for hyperlinks to internal worksheet references or external workbook and
* worksheet references:
*
* @code
* worksheet_write_url(worksheet, 0, 0, "internal:Sheet2!A1", NULL);
* worksheet_write_url(worksheet, 1, 0, "internal:Sheet2!B2", NULL);
* worksheet_write_url(worksheet, 2, 0, "internal:Sheet2!A1:B2", NULL);
* worksheet_write_url(worksheet, 3, 0, "internal:'Sales Data'!A1", NULL);
* worksheet_write_url(worksheet, 4, 0, "external:c:\\temp\\foo.xlsx", NULL);
* worksheet_write_url(worksheet, 5, 0, "external:c:\\foo.xlsx#Sheet2!A1", NULL);
* worksheet_write_url(worksheet, 6, 0, "external:..\\foo.xlsx", NULL);
* worksheet_write_url(worksheet, 7, 0, "external:..\\foo.xlsx#Sheet2!A1", NULL);
* worksheet_write_url(worksheet, 8, 0, "external:\\\\NET\\share\\foo.xlsx", NULL);
*
* @endcode
*
* Worksheet references are typically of the form `Sheet1!A1`. You can also
* link to a worksheet range using the standard Excel notation:
* `Sheet1!A1:B2`.
*
* In external links the workbook and worksheet name must be separated by the
* `#` character:
*
* @code
* worksheet_write_url(worksheet, 0, 0, "external:c:\\foo.xlsx#Sheet2!A1", NULL);
* @endcode
*
* You can also link to a named range in the target worksheet: For example say
* you have a named range called `my_name` in the workbook `c:\temp\foo.xlsx`
* you could link to it as follows:
*
* @code
* worksheet_write_url(worksheet, 0, 0, "external:c:\\temp\\foo.xlsx#my_name", NULL);
*
* @endcode
*
* Excel requires that worksheet names containing spaces or non alphanumeric
* characters are single quoted as follows:
*
* @code
* worksheet_write_url(worksheet, 0, 0, "internal:'Sales Data'!A1", NULL);
* @endcode
*
* Links to network files are also supported. Network files normally begin
* with two back slashes as follows `\\NETWORK\etc`. In order to represent
* this in a C string literal the backslashes should be escaped:
* @code
* worksheet_write_url(worksheet, 0, 0, "external:\\\\NET\\share\\foo.xlsx", NULL);
* @endcode
*
*
* Alternatively, you can use Unix style forward slashes. These are
* translated internally to backslashes:
*
* @code
* worksheet_write_url(worksheet, 0, 0, "external:c:/temp/foo.xlsx", NULL);
* worksheet_write_url(worksheet, 1, 0, "external://NET/share/foo.xlsx", NULL);
*
* @endcode
*
*
* **Note:**
*
* libxlsxwriter will escape the following characters in URLs as required
* by Excel: `\s " < > \ [ ] ^ { }`. Existing URL `%%xx` style escapes in
* the string are ignored to allow for user-escaped strings.
*
* **Note:**
*
* The maximum allowable URL length in recent versions of Excel is 2079
* characters. In older versions of Excel (and libxlsxwriter <= 0.8.8) the
* limit was 255 characters.
*/
lxw_error worksheet_write_url(lxw_worksheet *worksheet,
lxw_row_t row,
lxw_col_t col, const char *url,
lxw_format *format);
/* Don't document for now since the string option can be achieved by a
* subsequent cell worksheet_write() as shown in the docs, and the
* tooltip option isn't very useful. */
lxw_error worksheet_write_url_opt(lxw_worksheet *worksheet,
lxw_row_t row_num,
lxw_col_t col_num, const char *url,
lxw_format *format, const char *string,
const char *tooltip);
/**
* @brief Write a formatted boolean worksheet cell.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param value The boolean value to write to the cell.
* @param format A pointer to a Format instance or NULL.
*
* @return A #lxw_error code.
*
* Write an Excel boolean to the cell specified by `row` and `column`:
*
* @code
* worksheet_write_boolean(worksheet, 2, 2, 0, my_format);
* @endcode
*
*/
lxw_error worksheet_write_boolean(lxw_worksheet *worksheet,
lxw_row_t row, lxw_col_t col,
int value, lxw_format *format);
/**
* @brief Write a formatted blank worksheet cell.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param format A pointer to a Format instance or NULL.
*
* @return A #lxw_error code.
*
* Write a blank cell specified by `row` and `column`:
*
* @code
* worksheet_write_blank(worksheet, 1, 1, border_format);
* @endcode
*
* This function is used to add formatting to a cell which doesn't contain a
* string or number value.
*
* Excel differentiates between an "Empty" cell and a "Blank" cell. An Empty
* cell is a cell which doesn't contain data or formatting whilst a Blank cell
* doesn't contain data but does contain formatting. Excel stores Blank cells
* but ignores Empty cells.
*
* As such, if you write an empty cell without formatting it is ignored.
*
*/
lxw_error worksheet_write_blank(lxw_worksheet *worksheet,
lxw_row_t row, lxw_col_t col,
lxw_format *format);
/**
* @brief Write a formula to a worksheet cell with a user defined numeric
* result.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param formula Formula string to write to cell.
* @param format A pointer to a Format instance or NULL.
* @param result A user defined numeric result for the formula.
*
* @return A #lxw_error code.
*
* The `%worksheet_write_formula_num()` function writes a formula or Excel
* function to the cell specified by `row` and `column` with a user defined
* numeric result:
*
* @code
* // Required as a workaround only.
* worksheet_write_formula_num(worksheet, 0, 0, "=1 + 2", NULL, 3);
* @endcode
*
* Libxlsxwriter doesn't calculate the value of a formula and instead stores
* the value `0` as the formula result. It then sets a global flag in the XLSX
* file to say that all formulas and functions should be recalculated when the
* file is opened.
*
* This is the method recommended in the Excel documentation and in general it
* works fine with spreadsheet applications.
*
* However, applications that don't have a facility to calculate formulas,
* such as Excel Viewer, or some mobile applications will only display the `0`
* results.
*
* If required, the `%worksheet_write_formula_num()` function can be used to
* specify a formula and its result.
*
* This function is rarely required and is only provided for compatibility
* with some third party applications. For most applications the
* worksheet_write_formula() function is the recommended way of writing
* formulas.
*
* See also @ref working_with_formulas.
*/
lxw_error worksheet_write_formula_num(lxw_worksheet *worksheet,
lxw_row_t row,
lxw_col_t col,
const char *formula,
lxw_format *format, double result);
/**
* @brief Write a formula to a worksheet cell with a user defined string
* result.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param formula Formula string to write to cell.
* @param format A pointer to a Format instance or NULL.
* @param result A user defined string result for the formula.
*
* @return A #lxw_error code.
*
* The `%worksheet_write_formula_str()` function writes a formula or Excel
* function to the cell specified by `row` and `column` with a user defined
* string result:
*
* @code
* // The example formula is A & B -> AB.
* worksheet_write_formula_str(worksheet, 0, 0, "=\"A\" & \"B\"", NULL, "AB");
* @endcode
*
* The `%worksheet_write_formula_str()` function is similar to the
* `%worksheet_write_formula_num()` function except it writes a string result
* instead or a numeric result. See `worksheet_write_formula_num()` for more
* details on why/when these functions are required.
*
* One place where the `%worksheet_write_formula_str()` function may be required
* is to specify an empty result which will force a recalculation of the formula
* when loaded in LibreOffice.
*
* @code
* worksheet_write_formula_str(worksheet, 0, 0, "=Sheet1!$A$1", NULL, "");
* @endcode
*
* See the FAQ @ref faq_formula_zero.
*
* See also @ref working_with_formulas.
*/
lxw_error worksheet_write_formula_str(lxw_worksheet *worksheet,
lxw_row_t row,
lxw_col_t col,
const char *formula,
lxw_format *format, const char *result);
/**
* @brief Write a "Rich" multi-format string to a worksheet cell.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param rich_string An array of format/string lxw_rich_string_tuple fragments.
* @param format A pointer to a Format instance or NULL.
*
* @return A #lxw_error code.
*
* The `%worksheet_write_rich_string()` function is used to write strings with
* multiple formats. For example to write the string 'This is **bold**
* and this is *italic*' you would use the following:
*
* @code
* lxw_format *bold = workbook_add_format(workbook);
* format_set_bold(bold);
*
* lxw_format *italic = workbook_add_format(workbook);
* format_set_italic(italic);
*
* lxw_rich_string_tuple fragment11 = {.format = NULL, .string = "This is " };
* lxw_rich_string_tuple fragment12 = {.format = bold, .string = "bold" };
* lxw_rich_string_tuple fragment13 = {.format = NULL, .string = " and this is "};
* lxw_rich_string_tuple fragment14 = {.format = italic, .string = "italic" };
*
* lxw_rich_string_tuple *rich_string1[] = {&fragment11, &fragment12,
* &fragment13, &fragment14, NULL};
*
* worksheet_write_rich_string(worksheet, CELL("A1"), rich_string1, NULL);
*
* @endcode
*
* @image html rich_strings_small.png
*
* The basic rule is to break the string into fragments and put a lxw_format
* object before the fragment that you want to format. So if we look at the
* above example again:
*
* This is **bold** and this is *italic*
*
* The would be broken down into 4 fragments:
*
* default: |This is |
* bold: |bold|
* default: | and this is |
* italic: |italic|
*
* This in then converted to the lxw_rich_string_tuple fragments shown in the
* example above. For the default format we use `NULL`.
*
* The fragments are passed to `%worksheet_write_rich_string()` as a `NULL`
* terminated array:
*
* @code
* lxw_rich_string_tuple *rich_string1[] = {&fragment11, &fragment12,
* &fragment13, &fragment14, NULL};
*
* worksheet_write_rich_string(worksheet, CELL("A1"), rich_string1, NULL);
*
* @endcode
*
* **Note**:
* Excel doesn't allow the use of two consecutive formats in a rich string or
* an empty string fragment. For either of these conditions a warning is
* raised and the input to `%worksheet_write_rich_string()` is ignored.
*
*/
lxw_error worksheet_write_rich_string(lxw_worksheet *worksheet,
lxw_row_t row,
lxw_col_t col,
lxw_rich_string_tuple *rich_string[],
lxw_format *format);
/**
* @brief Write a comment to a worksheet cell.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param string The comment string to be written.
*
* @return A #lxw_error code.
*
* The `%worksheet_write_comment()` function is used to add a comment to a
* cell. A comment is indicated in Excel by a small red triangle in the upper
* right-hand corner of the cell. Moving the cursor over the red triangle will
* reveal the comment.
*
* The following example shows how to add a comment to a cell:
*
* @code
* worksheet_write_comment(worksheet, 0, 0, "This is a comment");
* @endcode
*
* @image html comments1.png
*
* See also @ref working_with_comments
*
*/
lxw_error worksheet_write_comment(lxw_worksheet *worksheet,
lxw_row_t row, lxw_col_t col,
const char *string);
/**
* @brief Write a comment to a worksheet cell with options.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param string The comment string to be written.
* @param options #lxw_comment_options to control position and format
* of the comment.
*
* @return A #lxw_error code.
*
* The `%worksheet_write_comment_opt()` function is used to add a comment to a
* cell with option that control the position, format and metadata of the
* comment. A comment is indicated in Excel by a small red triangle in the
* upper right-hand corner of the cell. Moving the cursor over the red
* triangle will reveal the comment.
*
* The following example shows how to add a comment to a cell with options:
*
* @code
* lxw_comment_options options = {.visible = LXW_COMMENT_DISPLAY_VISIBLE};
*
* worksheet_write_comment_opt(worksheet, CELL("C6"), "Hello.", &options);
* @endcode
*
* The following options are available in #lxw_comment_options:
*
* - `author`
* - `visible`
* - `width`
* - `height`
* - `x_scale`
* - `y_scale`
* - `color`
* - `font_name`
* - `font_size`
* - `start_row`
* - `start_col`
* - `x_offset`
* - `y_offset`
*
* @image html comments2.png
*
* Comment options are explained in detail in the @ref ww_comments_properties
* section of the docs.
*/
lxw_error worksheet_write_comment_opt(lxw_worksheet *worksheet,
lxw_row_t row, lxw_col_t col,
const char *string,
lxw_comment_options *options);
/**
* @brief Set the properties for a row of cells.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param height The row height, in character units.
* @param format A pointer to a Format instance or NULL.
*
* @return A #lxw_error code.
*
* The `%worksheet_set_row()` function is used to change the default
* properties of a row. The most common use for this function is to change the
* height of a row:
*
* @code
* // Set the height of Row 1 to 20.
* worksheet_set_row(worksheet, 0, 20, NULL);
* @endcode
*
* The height is specified in character units. To specify the height in pixels
* use the `worksheet_set_row_pixels()` function.
*
* The other common use for `%worksheet_set_row()` is to set the a @ref
* format.h "Format" for all cells in the row:
*
* @code
* lxw_format *bold = workbook_add_format(workbook);
* format_set_bold(bold);
*
* // Set the header row to bold.
* worksheet_set_row(worksheet, 0, 15, bold);
* @endcode
*
* If you wish to set the format of a row without changing the height you can
* pass the default row height of #LXW_DEF_ROW_HEIGHT = 15:
*
* @code
* worksheet_set_row(worksheet, 0, LXW_DEF_ROW_HEIGHT, format);
* worksheet_set_row(worksheet, 0, 15, format); // Same as above.
* @endcode
*
* The `format` parameter will be applied to any cells in the row that don't
* have a format. As with Excel the row format is overridden by an explicit
* cell format. For example:
*
* @code
* // Row 1 has format1.
* worksheet_set_row(worksheet, 0, 15, format1);
*
* // Cell A1 in Row 1 defaults to format1.
* worksheet_write_string(worksheet, 0, 0, "Hello", NULL);
*
* // Cell B1 in Row 1 keeps format2.
* worksheet_write_string(worksheet, 0, 1, "Hello", format2);
* @endcode
*
*/
lxw_error worksheet_set_row(lxw_worksheet *worksheet,
lxw_row_t row, double height, lxw_format *format);
/**
* @brief Set the properties for a row of cells.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param height The row height.
* @param format A pointer to a Format instance or NULL.
* @param options Optional row parameters: hidden, level, collapsed.
*
* @return A #lxw_error code.
*
* The `%worksheet_set_row_opt()` function is the same as
* `worksheet_set_row()` with an additional `options` parameter.
*
* The `options` parameter is a #lxw_row_col_options struct. It has the
* following members:
*
* - `hidden`
* - `level`
* - `collapsed`
*
* The `"hidden"` option is used to hide a row. This can be used, for
* example, to hide intermediary steps in a complicated calculation:
*
* @code
* lxw_row_col_options options1 = {.hidden = 1, .level = 0, .collapsed = 0};
*
* // Hide the fourth and fifth (zero indexed) rows.
* worksheet_set_row_opt(worksheet, 3, LXW_DEF_ROW_HEIGHT, NULL, &options1);
* worksheet_set_row_opt(worksheet, 4, LXW_DEF_ROW_HEIGHT, NULL, &options1);
*
* @endcode
*
* @image html hide_row_col2.png
*
* The `"hidden"`, `"level"`, and `"collapsed"`, options can also be used to
* create Outlines and Grouping. See @ref working_with_outlines.
*
* @code
* // The option structs with the outline level set.
* lxw_row_col_options options1 = {.hidden = 0, .level = 2, .collapsed = 0};
* lxw_row_col_options options2 = {.hidden = 0, .level = 1, .collapsed = 0};
*
*
* // Set the row options with the outline level.
* worksheet_set_row_opt(worksheet, 1, LXW_DEF_ROW_HEIGHT, NULL, &options1);
* worksheet_set_row_opt(worksheet, 2, LXW_DEF_ROW_HEIGHT, NULL, &options1);
* worksheet_set_row_opt(worksheet, 3, LXW_DEF_ROW_HEIGHT, NULL, &options1);
* worksheet_set_row_opt(worksheet, 4, LXW_DEF_ROW_HEIGHT, NULL, &options1);
* worksheet_set_row_opt(worksheet, 5, LXW_DEF_ROW_HEIGHT, NULL, &options2);
*
* worksheet_set_row_opt(worksheet, 6, LXW_DEF_ROW_HEIGHT, NULL, &options1);
* worksheet_set_row_opt(worksheet, 7, LXW_DEF_ROW_HEIGHT, NULL, &options1);
* worksheet_set_row_opt(worksheet, 8, LXW_DEF_ROW_HEIGHT, NULL, &options1);
* worksheet_set_row_opt(worksheet, 9, LXW_DEF_ROW_HEIGHT, NULL, &options1);
* worksheet_set_row_opt(worksheet, 10, LXW_DEF_ROW_HEIGHT, NULL, &options2);
* @endcode
*
* @image html outline1.png
*
*/
lxw_error worksheet_set_row_opt(lxw_worksheet *worksheet,
lxw_row_t row,
double height,
lxw_format *format,
lxw_row_col_options *options);
/**
* @brief Set the properties for a row of cells, with the height in pixels.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param pixels The row height in pixels.
* @param format A pointer to a Format instance or NULL.
*
* @return A #lxw_error code.
*
* The `%worksheet_set_row_pixels()` function is the same as the
* `worksheet_set_row()` function except that the height can be set in pixels
*
* @code
* // Set the height of Row 1 to 20 pixels.
* worksheet_set_row_pixels(worksheet, 0, 20, NULL);
* @endcode
*
* If you wish to set the format of a row without changing the height you can
* pass the default row height in pixels: #LXW_DEF_ROW_HEIGHT_PIXELS.
*/
lxw_error worksheet_set_row_pixels(lxw_worksheet *worksheet,
lxw_row_t row, uint32_t pixels,
lxw_format *format);
/**
* @brief Set the properties for a row of cells, with the height in pixels.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param pixels The row height in pixels.
* @param format A pointer to a Format instance or NULL.
* @param options Optional row parameters: hidden, level, collapsed.
*
* @return A #lxw_error code.
*
* The `%worksheet_set_row_pixels_opt()` function is the same as the
* `worksheet_set_row_opt()` function except that the height can be set in
* pixels.
*
*/
lxw_error worksheet_set_row_pixels_opt(lxw_worksheet *worksheet,
lxw_row_t row,
uint32_t pixels,
lxw_format *format,
lxw_row_col_options *options);
/**
* @brief Set the properties for one or more columns of cells.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param first_col The zero indexed first column.
* @param last_col The zero indexed last column.
* @param width The width of the column(s).
* @param format A pointer to a Format instance or NULL.
*
* @return A #lxw_error code.
*
* The `%worksheet_set_column()` function can be used to change the default
* properties of a single column or a range of columns:
*
* @code
* // Width of columns B:D set to 30.
* worksheet_set_column(worksheet, 1, 3, 30, NULL);
*
* @endcode
*
* If `%worksheet_set_column()` is applied to a single column the value of
* `first_col` and `last_col` should be the same:
*
* @code
* // Width of column B set to 30.
* worksheet_set_column(worksheet, 1, 1, 30, NULL);
*
* @endcode
*
* It is also possible, and generally clearer, to specify a column range using
* the form of `COLS()` macro:
*
* @code
* worksheet_set_column(worksheet, 4, 4, 20, NULL);
* worksheet_set_column(worksheet, 5, 8, 30, NULL);
*
* // Same as the examples above but clearer.
* worksheet_set_column(worksheet, COLS("E:E"), 20, NULL);
* worksheet_set_column(worksheet, COLS("F:H"), 30, NULL);
*
* @endcode
*
* The `width` parameter sets the column width in the same units used by Excel
* which is: the number of characters in the default font. The default width
* is 8.43 in the default font of Calibri 11. The actual relationship between
* a string width and a column width in Excel is complex. See the
* [following explanation of column widths](https://support.microsoft.com/en-us/kb/214123)
* from the Microsoft support documentation for more details. To set the width
* in pixels use the `worksheet_set_column_pixels()` function.
*
* There is no way to specify "AutoFit" for a column in the Excel file
* format. This feature is only available at runtime from within Excel. It is
* possible to simulate "AutoFit" in your application by tracking the maximum
* width of the data in the column as your write it and then adjusting the
* column width at the end.
*
* As usual the @ref format.h `format` parameter is optional. If you wish to
* set the format without changing the width you can pass a default column
* width of #LXW_DEF_COL_WIDTH = 8.43:
*
* @code
* lxw_format *bold = workbook_add_format(workbook);
* format_set_bold(bold);
*
* // Set the first column to bold.
* worksheet_set_column(worksheet, 0, 0, LXW_DEF_COL_WIDTH, bold);
* @endcode
*
* The `format` parameter will be applied to any cells in the column that
* don't have a format. For example:
*
* @code
* // Column 1 has format1.
* worksheet_set_column(worksheet, COLS("A:A"), 8.43, format1);
*
* // Cell A1 in column 1 defaults to format1.
* worksheet_write_string(worksheet, 0, 0, "Hello", NULL);
*
* // Cell A2 in column 1 keeps format2.
* worksheet_write_string(worksheet, 1, 0, "Hello", format2);
* @endcode
*
* As in Excel a row format takes precedence over a default column format:
*
* @code
* // Row 1 has format1.
* worksheet_set_row(worksheet, 0, 15, format1);
*
* // Col 1 has format2.
* worksheet_set_column(worksheet, COLS("A:A"), 8.43, format2);
*
* // Cell A1 defaults to format1, the row format.
* worksheet_write_string(worksheet, 0, 0, "Hello", NULL);
*
* // Cell A2 keeps format2, the column format.
* worksheet_write_string(worksheet, 1, 0, "Hello", NULL);
* @endcode
*/
lxw_error worksheet_set_column(lxw_worksheet *worksheet,
lxw_col_t first_col,
lxw_col_t last_col,
double width, lxw_format *format);
/**
* @brief Set the properties for one or more columns of cells with options.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param first_col The zero indexed first column.
* @param last_col The zero indexed last column.
* @param width The width of the column(s).
* @param format A pointer to a Format instance or NULL.
* @param options Optional row parameters: hidden, level, collapsed.
*
* @return A #lxw_error code.
*
* The `%worksheet_set_column_opt()` function is the same as
* `worksheet_set_column()` with an additional `options` parameter.
*
* The `options` parameter is a #lxw_row_col_options struct. It has the
* following members:
*
* - `hidden`
* - `level`
* - `collapsed`
*
* The `"hidden"` option is used to hide a column. This can be used, for
* example, to hide intermediary steps in a complicated calculation:
*
* @code
* lxw_row_col_options options1 = {.hidden = 1, .level = 0, .collapsed = 0};
*
* worksheet_set_column_opt(worksheet, COLS("D:E"), LXW_DEF_COL_WIDTH, NULL, &options1);
* @endcode
*
* @image html hide_row_col3.png
*
* The `"hidden"`, `"level"`, and `"collapsed"`, options can also be used to
* create Outlines and Grouping. See @ref working_with_outlines.
*
* @code
* lxw_row_col_options options1 = {.hidden = 0, .level = 1, .collapsed = 0};
*
* worksheet_set_column_opt(worksheet, COLS("B:G"), 5, NULL, &options1);
* @endcode
*
* @image html outline8.png
*/
lxw_error worksheet_set_column_opt(lxw_worksheet *worksheet,
lxw_col_t first_col,
lxw_col_t last_col,
double width,
lxw_format *format,
lxw_row_col_options *options);
/**
* @brief Set the properties for one or more columns of cells, with the width
* in pixels.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param first_col The zero indexed first column.
* @param last_col The zero indexed last column.
* @param pixels The width of the column(s) in pixels.
* @param format A pointer to a Format instance or NULL.
*
* @return A #lxw_error code.
*
* The `%worksheet_set_column_pixels()` function is the same as
* `worksheet_set_column()` function except that the width can be set in
* pixels:
*
* @code
* // Column width set to 75 pixels, the same as 10 character units.
* worksheet_set_column(worksheet, 5, 5, 75, NULL);
* @endcode
*
* @image html set_column_pixels.png
*
* If you wish to set the format of a column without changing the width you can
* pass the default column width in pixels: #LXW_DEF_COL_WIDTH_PIXELS.
*/
lxw_error worksheet_set_column_pixels(lxw_worksheet *worksheet,
lxw_col_t first_col,
lxw_col_t last_col,
uint32_t pixels, lxw_format *format);
/**
* @brief Set the properties for one or more columns of cells with options,
* with the width in pixels.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param first_col The zero indexed first column.
* @param last_col The zero indexed last column.
* @param pixels The width of the column(s) in pixels.
* @param format A pointer to a Format instance or NULL.
* @param options Optional row parameters: hidden, level, collapsed.
*
* @return A #lxw_error code.
*
* The `%worksheet_set_column_pixels_opt()` function is the same as the
* `worksheet_set_column_opt()` function except that the width can be set in
* pixels.
*
*/
lxw_error worksheet_set_column_pixels_opt(lxw_worksheet *worksheet,
lxw_col_t first_col,
lxw_col_t last_col,
uint32_t pixels,
lxw_format *format,
lxw_row_col_options *options);
/**
* @brief Insert an image in a worksheet cell.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param filename The image filename, with path if required.
*
* @return A #lxw_error code.
*
* This function can be used to insert a image into a worksheet. The image can
* be in PNG, JPEG, GIF or BMP format:
*
* @code
* worksheet_insert_image(worksheet, 2, 1, "logo.png");
* @endcode
*
* @image html insert_image.png
*
* The `worksheet_insert_image_opt()` function takes additional optional
* parameters to position and scale the image, see below.
*
* **Note**:
* The scaling of a image may be affected if is crosses a row that has its
* default height changed due to a font that is larger than the default font
* size or that has text wrapping turned on. To avoid this you should
* explicitly set the height of the row using `worksheet_set_row()` if it
* crosses an inserted image. See @ref working_with_object_positioning.
*
* BMP images are only supported for backward compatibility. In general it is
* best to avoid BMP images since they aren't compressed. If used, BMP images
* must be 24 bit, true color, bitmaps.
*/
lxw_error worksheet_insert_image(lxw_worksheet *worksheet,
lxw_row_t row, lxw_col_t col,
const char *filename);
/**
* @brief Insert an image in a worksheet cell, with options.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param filename The image filename, with path if required.
* @param options Optional image parameters.
*
* @return A #lxw_error code.
*
* The `%worksheet_insert_image_opt()` function is like
* `worksheet_insert_image()` function except that it takes an optional
* #lxw_image_options struct with the following members/options:
*
* - `x_offset`: Offset from the left of the cell in pixels.
* - `y_offset`: Offset from the top of the cell in pixels.
* - `x_scale`: X scale of the image as a decimal.
* - `y_scale`: Y scale of the image as a decimal.
* - `object_position`: See @ref working_with_object_positioning.
* - `description`: Optional description or "Alt text" for the image.
* - `decorative`: Optional parameter to mark image as decorative.
* - `url`: Add an optional hyperlink to the image.
* - `tip`: Add an optional mouseover tip for a hyperlink to the image.
*
* For example, to scale and position the image:
*
* @code
* lxw_image_options options = {.x_offset = 30, .y_offset = 10,
* .x_scale = 0.5, .y_scale = 0.5};
*
* worksheet_insert_image_opt(worksheet, 2, 1, "logo.png", &options);
*
* @endcode
*
* @image html insert_image_opt.png
*
* The `url` field of lxw_image_options can be use to used to add a hyperlink
* to an image:
*
* @code
* lxw_image_options options = {.url = "https://github.com/jmcnamara"};
*
* worksheet_insert_image_opt(worksheet, 3, 1, "logo.png", &options);
* @endcode
*
* The supported URL formats are the same as those supported by the
* `worksheet_write_url()` method and the same rules/limits apply.
*
* The `tip` field of lxw_image_options can be use to used to add a mouseover
* tip to the hyperlink:
*
* @code
* lxw_image_options options = {.url = "https://github.com/jmcnamara",
.tip = "GitHub"};
*
* worksheet_insert_image_opt(worksheet, 4, 1, "logo.png", &options);
* @endcode
*
* @note See the notes about row scaling and BMP images in
* `worksheet_insert_image()` above.
*/
lxw_error worksheet_insert_image_opt(lxw_worksheet *worksheet,
lxw_row_t row, lxw_col_t col,
const char *filename,
lxw_image_options *options);
/**
* @brief Insert an image in a worksheet cell, from a memory buffer.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param image_buffer Pointer to an array of bytes that holds the image data.
* @param image_size The size of the array of bytes.
*
* @return A #lxw_error code.
*
* This function can be used to insert a image into a worksheet from a memory
* buffer:
*
* @code
* worksheet_insert_image_buffer(worksheet, CELL("B3"), image_buffer, image_size);
* @endcode
*
* @image html image_buffer.png
*
* The buffer should be a pointer to an array of unsigned char data with a
* specified size.
*
* See `worksheet_insert_image()` for details about the supported image
* formats, and other image features.
*/
lxw_error worksheet_insert_image_buffer(lxw_worksheet *worksheet,
lxw_row_t row,
lxw_col_t col,
const unsigned char *image_buffer,
size_t image_size);
/**
* @brief Insert an image in a worksheet cell, from a memory buffer.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param image_buffer Pointer to an array of bytes that holds the image data.
* @param image_size The size of the array of bytes.
* @param options Optional image parameters.
*
* @return A #lxw_error code.
*
* The `%worksheet_insert_image_buffer_opt()` function is like
* `worksheet_insert_image_buffer()` function except that it takes an optional
* #lxw_image_options struct * #lxw_image_options struct with the following members/options:
*
* - `x_offset`: Offset from the left of the cell in pixels.
* - `y_offset`: Offset from the top of the cell in pixels.
* - `x_scale`: X scale of the image as a decimal.
* - `y_scale`: Y scale of the image as a decimal.
* - `object_position`: See @ref working_with_object_positioning.
* - `description`: Optional description or "Alt text" for the image.
* - `decorative`: Optional parameter to mark image as decorative.
* - `url`: Add an optional hyperlink to the image.
* - `tip`: Add an optional mouseover tip for a hyperlink to the image.
*
* For example, to scale and position the image:
*
* @code
* lxw_image_options options = {.x_offset = 32, .y_offset = 4,
* .x_scale = 2, .y_scale = 1};
*
* worksheet_insert_image_buffer_opt(worksheet, CELL("B3"), image_buffer, image_size, &options);
* @endcode
*
* @image html image_buffer_opt.png
*
* The buffer should be a pointer to an array of unsigned char data with a
* specified size.
*
* See `worksheet_insert_image_buffer_opt()` for details about the supported
* image formats, and other image options.
*/
lxw_error worksheet_insert_image_buffer_opt(lxw_worksheet *worksheet,
lxw_row_t row,
lxw_col_t col,
const unsigned char *image_buffer,
size_t image_size,
lxw_image_options *options);
/**
* @brief Set the background image for a worksheet.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param filename The image filename, with path if required.
*
* @return A #lxw_error code.
*
* The `%worksheet_set_background()` function can be used to set the
* background image for a worksheet:
*
* @code
* worksheet_set_background(worksheet, "logo.png");
* @endcode
*
* @image html background.png
*
* The ``set_background()`` method supports all the image formats supported by
* `worksheet_insert_image()`.
*
* Some people use this method to add a watermark background to their
* document. However, Microsoft recommends using a header image [to set a
* watermark][watermark]. The choice of method depends on whether you want the
* watermark to be visible in normal viewing mode or just when the file is
* printed. In libxlsxwriter you can get the header watermark effect using
* `worksheet_set_header()`:
*
* @code
* lxw_header_footer_options header_options = {.image_center = "watermark.png"};
* worksheet_set_header_opt(worksheet, "&C&G", &header_options);
* @endcode
*
* [watermark]:https://support.microsoft.com/en-us/office/add-a-watermark-in-excel-a372182a-d733-484e-825c-18ddf3edf009
*
*/
lxw_error worksheet_set_background(lxw_worksheet *worksheet,
const char *filename);
/**
* @brief Set the background image for a worksheet, from a buffer.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param image_buffer Pointer to an array of bytes that holds the image data.
* @param image_size The size of the array of bytes.
*
* @return A #lxw_error code.
*
* This function can be used to insert a background image into a worksheet
* from a memory buffer:
*
* @code
* worksheet_set_background_buffer(worksheet, image_buffer, image_size);
* @endcode
*
* The buffer should be a pointer to an array of unsigned char data with a
* specified size.
*
* See `worksheet_set_background()` for more details.
*
*/
lxw_error worksheet_set_background_buffer(lxw_worksheet *worksheet,
const unsigned char *image_buffer,
size_t image_size);
/**
* @brief Insert a chart object into a worksheet.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param chart A #lxw_chart object created via workbook_add_chart().
*
* @return A #lxw_error code.
*
* The `%worksheet_insert_chart()` function can be used to insert a chart into
* a worksheet. The chart object must be created first using the
* `workbook_add_chart()` function and configured using the @ref chart.h
* functions.
*
* @code
* // Create a chart object.
* lxw_chart *chart = workbook_add_chart(workbook, LXW_CHART_LINE);
*
* // Add a data series to the chart.
* chart_add_series(chart, NULL, "=Sheet1!$A$1:$A$6");
*
* // Insert the chart into the worksheet.
* worksheet_insert_chart(worksheet, 0, 2, chart);
* @endcode
*
* @image html chart_working.png
*
* **Note:**
*
* A chart may only be inserted into a worksheet once. If several similar
* charts are required then each one must be created separately with
* `%worksheet_insert_chart()`.
*
*/
lxw_error worksheet_insert_chart(lxw_worksheet *worksheet,
lxw_row_t row, lxw_col_t col,
lxw_chart *chart);
/**
* @brief Insert a chart object into a worksheet, with options.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param chart A #lxw_chart object created via workbook_add_chart().
* @param user_options Optional chart parameters.
*
* @return A #lxw_error code.
*
* The `%worksheet_insert_chart_opt()` function is like
* `worksheet_insert_chart()` function except that it takes an optional
* #lxw_chart_options struct to scale and position the chart:
*
* @code
* lxw_chart_options options = {.x_offset = 30, .y_offset = 10,
* .x_scale = 0.5, .y_scale = 0.75};
*
* worksheet_insert_chart_opt(worksheet, 0, 2, chart, &options);
*
* @endcode
*
* @image html chart_line_opt.png
*
*/
lxw_error worksheet_insert_chart_opt(lxw_worksheet *worksheet,
lxw_row_t row, lxw_col_t col,
lxw_chart *chart,
lxw_chart_options *user_options);
/**
* @brief Merge a range of cells.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param first_row The first row of the range. (All zero indexed.)
* @param first_col The first column of the range.
* @param last_row The last row of the range.
* @param last_col The last col of the range.
* @param string String to write to the merged range.
* @param format A pointer to a Format instance or NULL.
*
* @return A #lxw_error code.
*
* The `%worksheet_merge_range()` function allows cells to be merged together
* so that they act as a single area.
*
* Excel generally merges and centers cells at same time. To get similar
* behavior with libxlsxwriter you need to apply a @ref format.h "Format"
* object with the appropriate alignment:
*
* @code
* lxw_format *merge_format = workbook_add_format(workbook);
* format_set_align(merge_format, LXW_ALIGN_CENTER);
*
* worksheet_merge_range(worksheet, 1, 1, 1, 3, "Merged Range", merge_format);
*
* @endcode
*
* It is possible to apply other formatting to the merged cells as well:
*
* @code
* format_set_align (merge_format, LXW_ALIGN_CENTER);
* format_set_align (merge_format, LXW_ALIGN_VERTICAL_CENTER);
* format_set_border (merge_format, LXW_BORDER_DOUBLE);
* format_set_bold (merge_format);
* format_set_bg_color(merge_format, 0xD7E4BC);
*
* worksheet_merge_range(worksheet, 2, 1, 3, 3, "Merged Range", merge_format);
*
* @endcode
*
* @image html merge.png
*
* The `%worksheet_merge_range()` function writes a `char*` string using
* `worksheet_write_string()`. In order to write other data types, such as a
* number or a formula, you can overwrite the first cell with a call to one of
* the other write functions. The same Format should be used as was used in
* the merged range.
*
* @code
* // First write a range with a blank string.
* worksheet_merge_range (worksheet, 1, 1, 1, 3, "", format);
*
* // Then overwrite the first cell with a number.
* worksheet_write_number(worksheet, 1, 1, 123, format);
* @endcode
*
* @note Merged ranges generally don't work in libxlsxwriter when the Workbook
* #lxw_workbook_options `constant_memory` mode is enabled.
*/
lxw_error worksheet_merge_range(lxw_worksheet *worksheet, lxw_row_t first_row,
lxw_col_t first_col, lxw_row_t last_row,
lxw_col_t last_col, const char *string,
lxw_format *format);
/**
* @brief Set the autofilter area in the worksheet.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param first_row The first row of the range. (All zero indexed.)
* @param first_col The first column of the range.
* @param last_row The last row of the range.
* @param last_col The last col of the range.
*
* @return A #lxw_error code.
*
* The `%worksheet_autofilter()` function allows an autofilter to be added to
* a worksheet.
*
* An autofilter is a way of adding drop down lists to the headers of a 2D
* range of worksheet data. This allows users to filter the data based on
* simple criteria so that some data is shown and some is hidden.
*
* @image html autofilter3.png
*
* To add an autofilter to a worksheet:
*
* @code
* worksheet_autofilter(worksheet, 0, 0, 50, 3);
*
* // Same as above using the RANGE() macro.
* worksheet_autofilter(worksheet, RANGE("A1:D51"));
* @endcode
*
* In order to apply a filter condition it is necessary to add filter rules to
* the columns using either the `%worksheet_filter_column()`,
* `%worksheet_filter_column2()` or `%worksheet_filter_list()` functions:
*
* - `worksheet_filter_column()`: filter on a single criterion such as "Column ==
* East". More complex conditions such as "<=" or ">=" can also be use.
*
* - `worksheet_filter_column2()`: filter on two criteria such as "Column == East
* or Column == West". Complex conditions can also be used.
*
* - `worksheet_filter_list()`: filter on a list of values such as "Column in (East, West,
* North)".
*
* These functions are explained below. It isn't sufficient to just specify
* the filter condition. You must also hide any rows that don't match the
* filter condition. See @ref ww_autofilters_data for more details.
*
*/
lxw_error worksheet_autofilter(lxw_worksheet *worksheet, lxw_row_t first_row,
lxw_col_t first_col, lxw_row_t last_row,
lxw_col_t last_col);
/**
* @brief Write a filter rule to an autofilter column.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param col The column in the autofilter that the rule applies to.
* @param rule The lxw_filter_rule autofilter rule.
*
* @return A #lxw_error code.
*
* The `worksheet_filter_column` function can be used to filter columns in a
* autofilter range based on single rule conditions:
*
* @code
* lxw_filter_rule filter_rule = {.criteria = LXW_FILTER_CRITERIA_EQUAL_TO,
* .value_string = "East"};
*
* worksheet_filter_column(worksheet, 0, &filter_rule);
*@endcode
*
* @image html autofilter4.png
*
* The rules and criteria are explained in more detail in @ref
* ww_autofilters_criteria in @ref working_with_autofilters.
*
* The `col` parameter is a zero indexed column number and must refer to a
* column in an existing autofilter created with `worksheet_autofilter()`.
*
* It isn't sufficient to just specify the filter condition. You must also
* hide any rows that don't match the filter condition. See @ref
* ww_autofilters_data for more details.
*/
lxw_error worksheet_filter_column(lxw_worksheet *worksheet, lxw_col_t col,
lxw_filter_rule *rule);
/**
* @brief Write two filter rules to an autofilter column.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param col The column in the autofilter that the rules applies to.
* @param rule1 First lxw_filter_rule autofilter rule.
* @param rule2 Second lxw_filter_rule autofilter rule.
* @param and_or A #lxw_filter_operator and/or operator.
*
* @return A #lxw_error code.
*
* The `worksheet_filter_column2` function can be used to filter columns in a autofilter
* range based on two rule conditions:
*
* @code
* lxw_filter_rule filter_rule1 = {.criteria = LXW_FILTER_CRITERIA_EQUAL_TO,
* .value_string = "East"};
*
* lxw_filter_rule filter_rule2 = {.criteria = LXW_FILTER_CRITERIA_EQUAL_TO,
* .value_string = "South"};
*
* worksheet_filter_column2(worksheet, 0, &filter_rule1, &filter_rule2, LXW_FILTER_OR);
* @endcode
*
* @image html autofilter5.png
*
* The rules and criteria are explained in more detail in @ref
* ww_autofilters_criteria in @ref working_with_autofilters.
*
* The `col` parameter is a zero indexed column number and must refer to a
* column in an existing autofilter created with `worksheet_autofilter()`.
*
* The `and_or` parameter is either "and (LXW_FILTER_AND)" or "or (LXW_FILTER_OR)".
*
* It isn't sufficient to just specify the filter condition. You must also
* hide any rows that don't match the filter condition. See @ref
* ww_autofilters_data for more details.
*/
lxw_error worksheet_filter_column2(lxw_worksheet *worksheet, lxw_col_t col,
lxw_filter_rule *rule1,
lxw_filter_rule *rule2, uint8_t and_or);
/**
* @brief Write multiple string filters to an autofilter column.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param col The column in the autofilter that the rules applies to.
* @param list A NULL terminated array of strings to filter on.
*
* @return A #lxw_error code.
*
* The `worksheet_filter_column_list()` function can be used specify multiple
* string matching criteria. This is a newer type of filter introduced in
* Excel 2007. Prior to that it was only possible to have either 1 or 2 filter
* conditions, such as the ones used by `worksheet_filter_column()` and
* `worksheet_filter_column2()`.
*
* As an example, consider a column that contains data for the months of the
* year. The `%worksheet_filter_list()` function can be used to filter out
* data rows for different months:
*
* @code
* char* list[] = {"March", "April", "May", NULL};
*
* worksheet_filter_list(worksheet, 0, list);
* @endcode
*
* @image html autofilter2.png
*
*
* Note, the array must be NULL terminated to indicate the end of the array of
* strings. To filter blanks as part of the list use `Blanks` as a list item:
*
* @code
* char* list[] = {"March", "April", "May", "Blanks", NULL};
*
* worksheet_filter_list(worksheet, 0, list);
* @endcode
*
* It isn't sufficient to just specify the filter condition. You must also
* hide any rows that don't match the filter condition. See @ref
* ww_autofilters_data for more details.
*/
lxw_error worksheet_filter_list(lxw_worksheet *worksheet, lxw_col_t col,
const char **list);
/**
* @brief Add a data validation to a cell.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param validation A #lxw_data_validation object to control the validation.
*
* @return A #lxw_error code.
*
* The `%worksheet_data_validation_cell()` function is used to construct an
* Excel data validation or to limit the user input to a dropdown list of
* values:
*
* @code
*
* lxw_data_validation *data_validation = calloc(1, sizeof(lxw_data_validation));
*
* data_validation->validate = LXW_VALIDATION_TYPE_INTEGER;
* data_validation->criteria = LXW_VALIDATION_CRITERIA_BETWEEN;
* data_validation->minimum_number = 1;
* data_validation->maximum_number = 10;
*
* worksheet_data_validation_cell(worksheet, 2, 1, data_validation);
*
* // Same as above with the CELL() macro.
* worksheet_data_validation_cell(worksheet, CELL("B3"), data_validation);
*
* @endcode
*
* @image html data_validate4.png
*
* Data validation and the various options of #lxw_data_validation are
* described in more detail in @ref working_with_data_validation.
*/
lxw_error worksheet_data_validation_cell(lxw_worksheet *worksheet,
lxw_row_t row, lxw_col_t col,
lxw_data_validation *validation);
/**
* @brief Add a data validation to a range.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param first_row The first row of the range. (All zero indexed.)
* @param first_col The first column of the range.
* @param last_row The last row of the range.
* @param last_col The last col of the range.
* @param validation A #lxw_data_validation object to control the validation.
*
* @return A #lxw_error code.
*
* The `%worksheet_data_validation_range()` function is the same as the
* `%worksheet_data_validation_cell()`, see above, except the data validation
* is applied to a range of cells:
*
* @code
*
* lxw_data_validation *data_validation = calloc(1, sizeof(lxw_data_validation));
*
* data_validation->validate = LXW_VALIDATION_TYPE_INTEGER;
* data_validation->criteria = LXW_VALIDATION_CRITERIA_BETWEEN;
* data_validation->minimum_number = 1;
* data_validation->maximum_number = 10;
*
* worksheet_data_validation_range(worksheet, 2, 1, 4, 1, data_validation);
*
* // Same as above with the RANGE() macro.
* worksheet_data_validation_range(worksheet, RANGE("B3:B5"), data_validation);
*
* @endcode
*
* Data validation and the various options of #lxw_data_validation are
* described in more detail in @ref working_with_data_validation.
*/
lxw_error worksheet_data_validation_range(lxw_worksheet *worksheet,
lxw_row_t first_row,
lxw_col_t first_col,
lxw_row_t last_row,
lxw_col_t last_col,
lxw_data_validation *validation);
/**
* @brief Add a conditional format to a worksheet cell.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param conditional_format A #lxw_conditional_format object to control the
* conditional format.
*
* @return A #lxw_error code.
*
* The `%worksheet_conditional_format_cell()` function is used to set a
* conditional format for a cell in a worksheet:
*
* @code
* conditional_format->type = LXW_CONDITIONAL_TYPE_CELL;
* conditional_format->criteria = LXW_CONDITIONAL_CRITERIA_GREATER_THAN_OR_EQUAL_TO;
* conditional_format->value = 50;
* conditional_format->format = format1;
* worksheet_conditional_format_cell(worksheet, CELL("A1"), conditional_format);
* @endcode
*
* The conditional format parameters is specified in #lxw_conditional_format.
*
* See @ref working_with_conditional_formatting for full details.
*/
lxw_error worksheet_conditional_format_cell(lxw_worksheet *worksheet,
lxw_row_t row,
lxw_col_t col,
lxw_conditional_format
*conditional_format);
/**
* @brief Add a conditional format to a worksheet range.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param first_row The first row of the range. (All zero indexed.)
* @param first_col The first column of the range.
* @param last_row The last row of the range.
* @param last_col The last col of the range.
* @param conditional_format A #lxw_conditional_format object to control the
* conditional format.
*
* @return A #lxw_error code.
*
* The `%worksheet_conditional_format_cell()` function is used to set a
* conditional format for a range of cells in a worksheet:
*
* @code
* conditional_format->type = LXW_CONDITIONAL_TYPE_CELL;
* conditional_format->criteria = LXW_CONDITIONAL_CRITERIA_GREATER_THAN_OR_EQUAL_TO;
* conditional_format->value = 50;
* conditional_format->format = format1;
* worksheet_conditional_format_range(worksheet1, RANGE("B3:K12"), conditional_format);
*
* conditional_format->type = LXW_CONDITIONAL_TYPE_CELL;
* conditional_format->criteria = LXW_CONDITIONAL_CRITERIA_LESS_THAN;
* conditional_format->value = 50;
* conditional_format->format = format2;
* worksheet_conditional_format_range(worksheet1, RANGE("B3:K12"), conditional_format);
* @endcode
*
* Output:
*
* @image html conditional_format1.png
*
*
* The conditional format parameters is specified in #lxw_conditional_format.
*
* See @ref working_with_conditional_formatting for full details.
*/
lxw_error worksheet_conditional_format_range(lxw_worksheet *worksheet,
lxw_row_t first_row,
lxw_col_t first_col,
lxw_row_t last_row,
lxw_col_t last_col,
lxw_conditional_format
*conditional_format);
/**
* @brief Insert a button object into a worksheet.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The zero indexed row number.
* @param col The zero indexed column number.
* @param options A #lxw_button_options object to set the button properties.
*
* @return A #lxw_error code.
*
* The `%worksheet_insert_button()` function can be used to insert an Excel
* form button into a worksheet. This function is generally only useful when
* used in conjunction with the `workbook_add_vba_project()` function to tie
* the button to a macro from an embedded VBA project:
*
* @code
* lxw_button_options options = {.caption = "Press Me",
* .macro = "say_hello"};
*
* worksheet_insert_button(worksheet, 2, 1, &options);
* @endcode
*
* @image html macros.png
*
* The button properties are set using the lxw_button_options struct.
*
* See also @ref working_with_macros
*/
lxw_error worksheet_insert_button(lxw_worksheet *worksheet, lxw_row_t row,
lxw_col_t col, lxw_button_options *options);
/**
* @brief Add an Excel table to a worksheet.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param first_row The first row of the range. (All zero indexed.)
* @param first_col The first column of the range.
* @param last_row The last row of the range.
* @param last_col The last col of the range.
* @param options A #lxw_table_options struct to define the table options.
*
* @return A #lxw_error code.
*
* The `%worksheet_add_table()` function is used to add a table to a
* worksheet. Tables in Excel are a way of grouping a range of cells into a
* single entity that has common formatting or that can be referenced from
* formulas. Tables can have column headers, autofilters, total rows, column
* formulas and default formatting.
*
* @code
* worksheet_add_table(worksheet, 2, 1, 6, 5, NULL);
* @endcode
*
* Output:
*
* @image html tables1.png
*
* See @ref working_with_tables for more detailed usage information and also
* @ref tables.c.
*
*/
lxw_error worksheet_add_table(lxw_worksheet *worksheet, lxw_row_t first_row,
lxw_col_t first_col, lxw_row_t last_row,
lxw_col_t last_col, lxw_table_options *options);
/**
* @brief Make a worksheet the active, i.e., visible worksheet.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
*
* The `%worksheet_activate()` function is used to specify which worksheet is
* initially visible in a multi-sheet workbook:
*
* @code
* lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, NULL);
* lxw_worksheet *worksheet2 = workbook_add_worksheet(workbook, NULL);
* lxw_worksheet *worksheet3 = workbook_add_worksheet(workbook, NULL);
*
* worksheet_activate(worksheet3);
* @endcode
*
* @image html worksheet_activate.png
*
* More than one worksheet can be selected via the `worksheet_select()`
* function, see below, however only one worksheet can be active.
*
* The default active worksheet is the first worksheet.
*
*/
void worksheet_activate(lxw_worksheet *worksheet);
/**
* @brief Set a worksheet tab as selected.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
*
* The `%worksheet_select()` function is used to indicate that a worksheet is
* selected in a multi-sheet workbook:
*
* @code
* worksheet_activate(worksheet1);
* worksheet_select(worksheet2);
* worksheet_select(worksheet3);
*
* @endcode
*
* A selected worksheet has its tab highlighted. Selecting worksheets is a
* way of grouping them together so that, for example, several worksheets
* could be printed in one go. A worksheet that has been activated via the
* `worksheet_activate()` function will also appear as selected.
*
*/
void worksheet_select(lxw_worksheet *worksheet);
/**
* @brief Hide the current worksheet.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
*
* The `%worksheet_hide()` function is used to hide a worksheet:
*
* @code
* worksheet_hide(worksheet2);
* @endcode
*
* You may wish to hide a worksheet in order to avoid confusing a user with
* intermediate data or calculations.
*
* @image html hide_sheet.png
*
* A hidden worksheet can not be activated or selected so this function is
* mutually exclusive with the `worksheet_activate()` and `worksheet_select()`
* functions. In addition, since the first worksheet will default to being the
* active worksheet, you cannot hide the first worksheet without activating
* another sheet:
*
* @code
* worksheet_activate(worksheet2);
* worksheet_hide(worksheet1);
* @endcode
*/
void worksheet_hide(lxw_worksheet *worksheet);
/**
* @brief Set current worksheet as the first visible sheet tab.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
*
* The `worksheet_activate()` function determines which worksheet is initially
* selected. However, if there are a large number of worksheets the selected
* worksheet may not appear on the screen. To avoid this you can select the
* leftmost visible worksheet tab using `%worksheet_set_first_sheet()`:
*
* @code
* worksheet_set_first_sheet(worksheet19); // First visible worksheet tab.
* worksheet_activate(worksheet20); // First visible worksheet.
* @endcode
*
* This function is not required very often. The default value is the first
* worksheet.
*/
void worksheet_set_first_sheet(lxw_worksheet *worksheet);
/**
* @brief Split and freeze a worksheet into panes.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The cell row (zero indexed).
* @param col The cell column (zero indexed).
*
* The `%worksheet_freeze_panes()` function can be used to divide a worksheet
* into horizontal or vertical regions known as panes and to "freeze" these
* panes so that the splitter bars are not visible.
*
* The parameters `row` and `col` are used to specify the location of the
* split. It should be noted that the split is specified at the top or left of
* a cell and that the function uses zero based indexing. Therefore to freeze
* the first row of a worksheet it is necessary to specify the split at row 2
* (which is 1 as the zero-based index).
*
* You can set one of the `row` and `col` parameters as zero if you do not
* want either a vertical or horizontal split.
*
* Examples:
*
* @code
* worksheet_freeze_panes(worksheet1, 1, 0); // Freeze the first row.
* worksheet_freeze_panes(worksheet2, 0, 1); // Freeze the first column.
* worksheet_freeze_panes(worksheet3, 1, 1); // Freeze first row/column.
*
* @endcode
*
*/
void worksheet_freeze_panes(lxw_worksheet *worksheet,
lxw_row_t row, lxw_col_t col);
/**
* @brief Split a worksheet into panes.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param vertical The position for the vertical split.
* @param horizontal The position for the horizontal split.
*
* The `%worksheet_split_panes()` function can be used to divide a worksheet
* into horizontal or vertical regions known as panes. This function is
* different from the `worksheet_freeze_panes()` function in that the splits
* between the panes will be visible to the user and each pane will have its
* own scroll bars.
*
* The parameters `vertical` and `horizontal` are used to specify the vertical
* and horizontal position of the split. The units for `vertical` and
* `horizontal` are the same as those used by Excel to specify row height and
* column width. However, the vertical and horizontal units are different from
* each other. Therefore you must specify the `vertical` and `horizontal`
* parameters in terms of the row heights and column widths that you have set
* or the default values which are 15 for a row and 8.43 for a column.
*
* Examples:
*
* @code
* worksheet_split_panes(worksheet1, 15, 0); // First row.
* worksheet_split_panes(worksheet2, 0, 8.43); // First column.
* worksheet_split_panes(worksheet3, 15, 8.43); // First row and column.
*
* @endcode
*
*/
void worksheet_split_panes(lxw_worksheet *worksheet,
double vertical, double horizontal);
/* worksheet_freeze_panes() with infrequent options. Undocumented for now. */
void worksheet_freeze_panes_opt(lxw_worksheet *worksheet,
lxw_row_t first_row, lxw_col_t first_col,
lxw_row_t top_row, lxw_col_t left_col,
uint8_t type);
/* worksheet_split_panes() with infrequent options. Undocumented for now. */
void worksheet_split_panes_opt(lxw_worksheet *worksheet,
double vertical, double horizontal,
lxw_row_t top_row, lxw_col_t left_col);
/**
* @brief Set the selected cell or cells in a worksheet:
*
* @param worksheet A pointer to a lxw_worksheet instance to be updated.
* @param first_row The first row of the range. (All zero indexed.)
* @param first_col The first column of the range.
* @param last_row The last row of the range.
* @param last_col The last col of the range.
*
*
* The `%worksheet_set_selection()` function can be used to specify which cell
* or range of cells is selected in a worksheet: The most common requirement
* is to select a single cell, in which case the `first_` and `last_`
* parameters should be the same.
*
* The active cell within a selected range is determined by the order in which
* `first_` and `last_` are specified.
*
* Examples:
*
* @code
* worksheet_set_selection(worksheet1, 3, 3, 3, 3); // Cell D4.
* worksheet_set_selection(worksheet2, 3, 3, 6, 6); // Cells D4 to G7.
* worksheet_set_selection(worksheet3, 6, 6, 3, 3); // Cells G7 to D4.
* worksheet_set_selection(worksheet5, RANGE("D4:G7")); // Using the RANGE macro.
*
* @endcode
*
*/
void worksheet_set_selection(lxw_worksheet *worksheet,
lxw_row_t first_row, lxw_col_t first_col,
lxw_row_t last_row, lxw_col_t last_col);
/**
* @brief Set the first visible cell at the top left of a worksheet.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param row The cell row (zero indexed).
* @param col The cell column (zero indexed).
*
* The `%worksheet_set_top_left_cell()` function can be used to set the
* top leftmost visible cell in the worksheet:
*
* @code
* worksheet_set_top_left_cell(worksheet, 31, 26);
* worksheet_set_top_left_cell(worksheet, CELL("AA32")); // Same as above.
* @endcode
*
* @image html top_left_cell.png
*
*/
void worksheet_set_top_left_cell(lxw_worksheet *worksheet, lxw_row_t row,
lxw_col_t col);
/**
* @brief Set the page orientation as landscape.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
*
* This function is used to set the orientation of a worksheet's printed page
* to landscape:
*
* @code
* worksheet_set_landscape(worksheet);
* @endcode
*/
void worksheet_set_landscape(lxw_worksheet *worksheet);
/**
* @brief Set the page orientation as portrait.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
*
* This function is used to set the orientation of a worksheet's printed page
* to portrait. The default worksheet orientation is portrait, so this
* function isn't generally required:
*
* @code
* worksheet_set_portrait(worksheet);
* @endcode
*/
void worksheet_set_portrait(lxw_worksheet *worksheet);
/**
* @brief Set the page layout to page view mode.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
*
* This function is used to display the worksheet in "Page View/Layout" mode:
*
* @code
* worksheet_set_page_view(worksheet);
* @endcode
*/
void worksheet_set_page_view(lxw_worksheet *worksheet);
/**
* @brief Set the paper type for printing.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param paper_type The Excel paper format type.
*
* This function is used to set the paper format for the printed output of a
* worksheet. The following paper styles are available:
*
*
* Index | Paper format | Paper size
* :------- | :---------------------- | :-------------------
* 0 | Printer default | Printer default
* 1 | Letter | 8 1/2 x 11 in
* 2 | Letter Small | 8 1/2 x 11 in
* 3 | Tabloid | 11 x 17 in
* 4 | Ledger | 17 x 11 in
* 5 | Legal | 8 1/2 x 14 in
* 6 | Statement | 5 1/2 x 8 1/2 in
* 7 | Executive | 7 1/4 x 10 1/2 in
* 8 | A3 | 297 x 420 mm
* 9 | A4 | 210 x 297 mm
* 10 | A4 Small | 210 x 297 mm
* 11 | A5 | 148 x 210 mm
* 12 | B4 | 250 x 354 mm
* 13 | B5 | 182 x 257 mm
* 14 | Folio | 8 1/2 x 13 in
* 15 | Quarto | 215 x 275 mm
* 16 | --- | 10x14 in
* 17 | --- | 11x17 in
* 18 | Note | 8 1/2 x 11 in
* 19 | Envelope 9 | 3 7/8 x 8 7/8
* 20 | Envelope 10 | 4 1/8 x 9 1/2
* 21 | Envelope 11 | 4 1/2 x 10 3/8
* 22 | Envelope 12 | 4 3/4 x 11
* 23 | Envelope 14 | 5 x 11 1/2
* 24 | C size sheet | ---
* 25 | D size sheet | ---
* 26 | E size sheet | ---
* 27 | Envelope DL | 110 x 220 mm
* 28 | Envelope C3 | 324 x 458 mm
* 29 | Envelope C4 | 229 x 324 mm
* 30 | Envelope C5 | 162 x 229 mm
* 31 | Envelope C6 | 114 x 162 mm
* 32 | Envelope C65 | 114 x 229 mm
* 33 | Envelope B4 | 250 x 353 mm
* 34 | Envelope B5 | 176 x 250 mm
* 35 | Envelope B6 | 176 x 125 mm
* 36 | Envelope | 110 x 230 mm
* 37 | Monarch | 3.875 x 7.5 in
* 38 | Envelope | 3 5/8 x 6 1/2 in
* 39 | Fanfold | 14 7/8 x 11 in
* 40 | German Std Fanfold | 8 1/2 x 12 in
* 41 | German Legal Fanfold | 8 1/2 x 13 in
*
* Note, it is likely that not all of these paper types will be available to
* the end user since it will depend on the paper formats that the user's
* printer supports. Therefore, it is best to stick to standard paper types:
*
* @code
* worksheet_set_paper(worksheet1, 1); // US Letter
* worksheet_set_paper(worksheet2, 9); // A4
* @endcode
*
* If you do not specify a paper type the worksheet will print using the
* printer's default paper style.
*/
void worksheet_set_paper(lxw_worksheet *worksheet, uint8_t paper_type);
/**
* @brief Set the worksheet margins for the printed page.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param left Left margin in inches. Excel default is 0.7.
* @param right Right margin in inches. Excel default is 0.7.
* @param top Top margin in inches. Excel default is 0.75.
* @param bottom Bottom margin in inches. Excel default is 0.75.
*
* The `%worksheet_set_margins()` function is used to set the margins of the
* worksheet when it is printed. The units are in inches. Specifying `-1` for
* any parameter will give the default Excel value as shown above.
*
* @code
* worksheet_set_margins(worksheet, 1.3, 1.2, -1, -1);
* @endcode
*
*/
void worksheet_set_margins(lxw_worksheet *worksheet, double left,
double right, double top, double bottom);
/**
* @brief Set the printed page header caption.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param string The header string.
*
* @return A #lxw_error code.
*
* Headers and footers are generated using a string which is a combination of
* plain text and control characters.
*
* The available control character are:
*
*
* | Control | Category | Description |
* | --------------- | ------------- | --------------------- |
* | `&L` | Justification | Left |
* | `&C` | | Center |
* | `&R` | | Right |
* | `&P` | Information | Page number |
* | `&N` | | Total number of pages |
* | `&D` | | Date |
* | `&T` | | Time |
* | `&F` | | File name |
* | `&A` | | Worksheet name |
* | `&Z` | | Workbook path |
* | `&fontsize` | Font | Font size |
* | `&"font,style"` | | Font name and style |
* | `&U` | | Single underline |
* | `&E` | | Double underline |
* | `&S` | | Strikethrough |
* | `&X` | | Superscript |
* | `&Y` | | Subscript |
* | `&[Picture]` | Images | Image placeholder |
* | `&G` | | Same as `&[Picture]` |
* | `&&` | Miscellaneous | Literal ampersand & |
*
* Note: inserting images requires the `worksheet_set_header_opt()` function.
*
* Text in headers and footers can be justified (aligned) to the left, center
* and right by prefixing the text with the control characters `&L`, `&C` and
* `&R`.
*
* For example (with ASCII art representation of the results):
*
* @code
* worksheet_set_header(worksheet, "&LHello");
*
* // ---------------------------------------------------------------
* // | |
* // | Hello |
* // | |
*
*
* worksheet_set_header(worksheet, "&CHello");
*
* // ---------------------------------------------------------------
* // | |
* // | Hello |
* // | |
*
*
* worksheet_set_header(worksheet, "&RHello");
*
* // ---------------------------------------------------------------
* // | |
* // | Hello |
* // | |
*
*
* @endcode
*
* For simple text, if you do not specify any justification the text will be
* centered. However, you must prefix the text with `&C` if you specify a font
* name or any other formatting:
*
* @code
* worksheet_set_header(worksheet, "Hello");
*
* // ---------------------------------------------------------------
* // | |
* // | Hello |
* // | |
*
* @endcode
*
* You can have text in each of the justification regions:
*
* @code
* worksheet_set_header(worksheet, "&LCiao&CBello&RCielo");
*
* // ---------------------------------------------------------------
* // | |
* // | Ciao Bello Cielo |
* // | |
*
* @endcode
*
* The information control characters act as variables that Excel will update
* as the workbook or worksheet changes. Times and dates are in the users
* default format:
*
* @code
* worksheet_set_header(worksheet, "&CPage &P of &N");
*
* // ---------------------------------------------------------------
* // | |
* // | Page 1 of 6 |
* // | |
*
* worksheet_set_header(worksheet, "&CUpdated at &T");
*
* // ---------------------------------------------------------------
* // | |
* // | Updated at 12:30 PM |
* // | |
*
* @endcode
*
* You can specify the font size of a section of the text by prefixing it with
* the control character `&n` where `n` is the font size:
*
* @code
* worksheet_set_header(worksheet1, "&C&30Hello Big");
* worksheet_set_header(worksheet2, "&C&10Hello Small");
*
* @endcode
*
* You can specify the font of a section of the text by prefixing it with the
* control sequence `&"font,style"` where `fontname` is a font name such as
* Windows font descriptions: "Regular", "Italic", "Bold" or "Bold Italic":
* "Courier New" or "Times New Roman" and `style` is one of the standard
*
* @code
* worksheet_set_header(worksheet1, "&C&\"Courier New,Italic\"Hello");
* worksheet_set_header(worksheet2, "&C&\"Courier New,Bold Italic\"Hello");
* worksheet_set_header(worksheet3, "&C&\"Times New Roman,Regular\"Hello");
*
* @endcode
*
* It is possible to combine all of these features together to create
* sophisticated headers and footers. As an aid to setting up complicated
* headers and footers you can record a page set-up as a macro in Excel and
* look at the format strings that VBA produces. Remember however that VBA
* uses two double quotes `""` to indicate a single double quote. For the last
* example above the equivalent VBA code looks like this:
*
* @code
* .LeftHeader = ""
* .CenterHeader = "&""Times New Roman,Regular""Hello"
* .RightHeader = ""
*
* @endcode
*
* Alternatively you can inspect the header and footer strings in an Excel
* file by unzipping it and grepping the XML sub-files. The following shows
* how to do that using libxml's xmllint to format the XML for clarity:
*
* @code
*
* $ unzip myfile.xlsm -d myfile
* $ xmllint --format `find myfile -name "*.xml" | xargs` | egrep "Header|Footer" | sed 's/&/\&/g'
*
*
* &L&P
*
*
* @endcode
*
* To include a single literal ampersand `&` in a header or footer you should
* use a double ampersand `&&`:
*
* @code
* worksheet_set_header(worksheet, "&CCuriouser && Curiouser - Attorneys at Law");
* @endcode
*
* @note
* Excel requires that the header or footer string cannot be longer than 255
* characters, including the control characters. Strings longer than this will
* not be written.
*
*/
lxw_error worksheet_set_header(lxw_worksheet *worksheet, const char *string);
/**
* @brief Set the printed page footer caption.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param string The footer string.
*
* @return A #lxw_error code.
*
* The syntax of this function is the same as worksheet_set_header().
*
*/
lxw_error worksheet_set_footer(lxw_worksheet *worksheet, const char *string);
/**
* @brief Set the printed page header caption with additional options.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param string The header string.
* @param options Header options.
*
* @return A #lxw_error code.
*
* The syntax of this function is the same as `worksheet_set_header()` with an
* additional parameter to specify options for the header.
*
* The #lxw_header_footer_options options are:
*
* - `margin`: Header or footer margin in inches. The value must by larger
* than 0.0. The Excel default is 0.3.
*
* - `image_left`: The left header image filename, with path if required. This
* should have a corresponding `&G/&[Picture]` placeholder in the `&L`
* section of the header/footer string.
*
* - `image_center`: The center header image filename, with path if
* required. This should have a corresponding `&G/&[Picture]` placeholder in
* the `&C` section of the header/footer string.
*
* - `image_right`: The right header image filename, with path if
* required. This should have a corresponding `&G/&[Picture]` placeholder in
* the `&R` section of the header/footer string.
*
* @code
* lxw_header_footer_options header_options = { .margin = 0.2 };
*
* worksheet_set_header_opt(worksheet, "Some text", &header_options);
* @endcode
*
* Images can be inserted in the header by specifying the `&[Picture]`
* placeholder and a filename/path to the image:
*
* @code
* lxw_header_footer_options header_options = {.image_left = "logo.png"};
*
* worksheet_set_header_opt(worksheet, "&L&[Picture]", &header_options);
* @endcode
*
* @image html headers_footers.png
*
*/
lxw_error worksheet_set_header_opt(lxw_worksheet *worksheet,
const char *string,
lxw_header_footer_options *options);
/**
* @brief Set the printed page footer caption with additional options.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param string The footer string.
* @param options Footer options.
*
* @return A #lxw_error code.
*
* The syntax of this function is the same as `worksheet_set_header_opt()`.
*
*/
lxw_error worksheet_set_footer_opt(lxw_worksheet *worksheet,
const char *string,
lxw_header_footer_options *options);
/**
* @brief Set the horizontal page breaks on a worksheet.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param breaks Array of page breaks.
*
* @return A #lxw_error code.
*
* The `%worksheet_set_h_pagebreaks()` function adds horizontal page breaks to
* a worksheet. A page break causes all the data that follows it to be printed
* on the next page. Horizontal page breaks act between rows.
*
* The function takes an array of one or more page breaks. The type of the
* array data is @ref lxw_row_t and the last element of the array must be 0:
*
* @code
* lxw_row_t breaks1[] = {20, 0}; // 1 page break. Zero indicates the end.
* lxw_row_t breaks2[] = {20, 40, 60, 80, 0};
*
* worksheet_set_h_pagebreaks(worksheet1, breaks1);
* worksheet_set_h_pagebreaks(worksheet2, breaks2);
* @endcode
*
* To create a page break between rows 20 and 21 you must specify the break at
* row 21. However in zero index notation this is actually row 20:
*
* @code
* // Break between row 20 and 21.
* lxw_row_t breaks[] = {20, 0};
*
* worksheet_set_h_pagebreaks(worksheet, breaks);
* @endcode
*
* There is an Excel limitation of 1023 horizontal page breaks per worksheet.
*
* Note: If you specify the "fit to page" option via the
* `worksheet_fit_to_pages()` function it will override all manual page
* breaks.
*
*/
lxw_error worksheet_set_h_pagebreaks(lxw_worksheet *worksheet,
lxw_row_t breaks[]);
/**
* @brief Set the vertical page breaks on a worksheet.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param breaks Array of page breaks.
*
* @return A #lxw_error code.
*
* The `%worksheet_set_v_pagebreaks()` function adds vertical page breaks to a
* worksheet. A page break causes all the data that follows it to be printed
* on the next page. Vertical page breaks act between columns.
*
* The function takes an array of one or more page breaks. The type of the
* array data is @ref lxw_col_t and the last element of the array must be 0:
*
* @code
* lxw_col_t breaks1[] = {20, 0}; // 1 page break. Zero indicates the end.
* lxw_col_t breaks2[] = {20, 40, 60, 80, 0};
*
* worksheet_set_v_pagebreaks(worksheet1, breaks1);
* worksheet_set_v_pagebreaks(worksheet2, breaks2);
* @endcode
*
* To create a page break between columns 20 and 21 you must specify the break
* at column 21. However in zero index notation this is actually column 20:
*
* @code
* // Break between column 20 and 21.
* lxw_col_t breaks[] = {20, 0};
*
* worksheet_set_v_pagebreaks(worksheet, breaks);
* @endcode
*
* There is an Excel limitation of 1023 vertical page breaks per worksheet.
*
* Note: If you specify the "fit to page" option via the
* `worksheet_fit_to_pages()` function it will override all manual page
* breaks.
*
*/
lxw_error worksheet_set_v_pagebreaks(lxw_worksheet *worksheet,
lxw_col_t breaks[]);
/**
* @brief Set the order in which pages are printed.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
*
* The `%worksheet_print_across()` function is used to change the default
* print direction. This is referred to by Excel as the sheet "page order":
*
* @code
* worksheet_print_across(worksheet);
* @endcode
*
* The default page order is shown below for a worksheet that extends over 4
* pages. The order is called "down then across":
*
* [1] [3]
* [2] [4]
*
* However, by using the `print_across` function the print order will be
* changed to "across then down":
*
* [1] [2]
* [3] [4]
*
*/
void worksheet_print_across(lxw_worksheet *worksheet);
/**
* @brief Set the worksheet zoom factor.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param scale Worksheet zoom factor.
*
* Set the worksheet zoom factor in the range `10 <= zoom <= 400`:
*
* @code
* worksheet_set_zoom(worksheet1, 50);
* worksheet_set_zoom(worksheet2, 75);
* worksheet_set_zoom(worksheet3, 300);
* worksheet_set_zoom(worksheet4, 400);
* @endcode
*
* The default zoom factor is 100. It isn't possible to set the zoom to
* "Selection" because it is calculated by Excel at run-time.
*
* Note, `%worksheet_zoom()` does not affect the scale of the printed
* page. For that you should use `worksheet_set_print_scale()`.
*/
void worksheet_set_zoom(lxw_worksheet *worksheet, uint16_t scale);
/**
* @brief Set the option to display or hide gridlines on the screen and
* the printed page.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param option Gridline option.
*
* Display or hide screen and print gridlines using one of the values of
* @ref lxw_gridlines.
*
* @code
* worksheet_gridlines(worksheet1, LXW_HIDE_ALL_GRIDLINES);
*
* worksheet_gridlines(worksheet2, LXW_SHOW_PRINT_GRIDLINES);
* @endcode
*
* The Excel default is that the screen gridlines are on and the printed
* worksheet is off.
*
*/
void worksheet_gridlines(lxw_worksheet *worksheet, uint8_t option);
/**
* @brief Center the printed page horizontally.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
*
* Center the worksheet data horizontally between the margins on the printed
* page:
*
* @code
* worksheet_center_horizontally(worksheet);
* @endcode
*
*/
void worksheet_center_horizontally(lxw_worksheet *worksheet);
/**
* @brief Center the printed page vertically.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
*
* Center the worksheet data vertically between the margins on the printed
* page:
*
* @code
* worksheet_center_vertically(worksheet);
* @endcode
*
*/
void worksheet_center_vertically(lxw_worksheet *worksheet);
/**
* @brief Set the option to print the row and column headers on the printed
* page.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
*
* When printing a worksheet from Excel the row and column headers (the row
* numbers on the left and the column letters at the top) aren't printed by
* default.
*
* This function sets the printer option to print these headers:
*
* @code
* worksheet_print_row_col_headers(worksheet);
* @endcode
*
*/
void worksheet_print_row_col_headers(lxw_worksheet *worksheet);
/**
* @brief Set the number of rows to repeat at the top of each printed page.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param first_row First row of repeat range.
* @param last_row Last row of repeat range.
*
* @return A #lxw_error code.
*
* For large Excel documents it is often desirable to have the first row or
* rows of the worksheet print out at the top of each page.
*
* This can be achieved by using this function. The parameters `first_row`
* and `last_row` are zero based:
*
* @code
* worksheet_repeat_rows(worksheet, 0, 0); // Repeat the first row.
* worksheet_repeat_rows(worksheet, 0, 1); // Repeat the first two rows.
* @endcode
*/
lxw_error worksheet_repeat_rows(lxw_worksheet *worksheet, lxw_row_t first_row,
lxw_row_t last_row);
/**
* @brief Set the number of columns to repeat at the top of each printed page.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param first_col First column of repeat range.
* @param last_col Last column of repeat range.
*
* @return A #lxw_error code.
*
* For large Excel documents it is often desirable to have the first column or
* columns of the worksheet print out at the left of each page.
*
* This can be achieved by using this function. The parameters `first_col`
* and `last_col` are zero based:
*
* @code
* worksheet_repeat_columns(worksheet, 0, 0); // Repeat the first col.
* worksheet_repeat_columns(worksheet, 0, 1); // Repeat the first two cols.
* @endcode
*/
lxw_error worksheet_repeat_columns(lxw_worksheet *worksheet,
lxw_col_t first_col, lxw_col_t last_col);
/**
* @brief Set the print area for a worksheet.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param first_row The first row of the range. (All zero indexed.)
* @param first_col The first column of the range.
* @param last_row The last row of the range.
* @param last_col The last col of the range.
*
* @return A #lxw_error code.
*
* This function is used to specify the area of the worksheet that will be
* printed. The RANGE() macro is often convenient for this.
*
* @code
* worksheet_print_area(worksheet, 0, 0, 41, 10); // A1:K42.
*
* // Same as:
* worksheet_print_area(worksheet, RANGE("A1:K42"));
* @endcode
*
* In order to set a row or column range you must specify the entire range:
*
* @code
* worksheet_print_area(worksheet, RANGE("A1:H1048576")); // Same as A:H.
* @endcode
*/
lxw_error worksheet_print_area(lxw_worksheet *worksheet, lxw_row_t first_row,
lxw_col_t first_col, lxw_row_t last_row,
lxw_col_t last_col);
/**
* @brief Fit the printed area to a specific number of pages both vertically
* and horizontally.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param width Number of pages horizontally.
* @param height Number of pages vertically.
*
* The `%worksheet_fit_to_pages()` function is used to fit the printed area to
* a specific number of pages both vertically and horizontally. If the printed
* area exceeds the specified number of pages it will be scaled down to
* fit. This ensures that the printed area will always appear on the specified
* number of pages even if the page size or margins change:
*
* @code
* worksheet_fit_to_pages(worksheet1, 1, 1); // Fit to 1x1 pages.
* worksheet_fit_to_pages(worksheet2, 2, 1); // Fit to 2x1 pages.
* worksheet_fit_to_pages(worksheet3, 1, 2); // Fit to 1x2 pages.
* @endcode
*
* The print area can be defined using the `worksheet_print_area()` function
* as described above.
*
* A common requirement is to fit the printed output to `n` pages wide but
* have the height be as long as necessary. To achieve this set the `height`
* to zero:
*
* @code
* // 1 page wide and as long as necessary.
* worksheet_fit_to_pages(worksheet, 1, 0);
* @endcode
*
* **Note**:
*
* - Although it is valid to use both `%worksheet_fit_to_pages()` and
* `worksheet_set_print_scale()` on the same worksheet Excel only allows one
* of these options to be active at a time. The last function call made will
* set the active option.
*
* - The `%worksheet_fit_to_pages()` function will override any manual page
* breaks that are defined in the worksheet.
*
* - When using `%worksheet_fit_to_pages()` it may also be required to set the
* printer paper size using `worksheet_set_paper()` or else Excel will
* default to "US Letter".
*
*/
void worksheet_fit_to_pages(lxw_worksheet *worksheet, uint16_t width,
uint16_t height);
/**
* @brief Set the start/first page number when printing.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param start_page Page number of the starting page when printing.
*
* The `%worksheet_set_start_page()` function is used to set the number number
* of the first page when the worksheet is printed out. It is the same as the
* "First Page Number" option in Excel:
*
* @code
* // Start print from page 2.
* worksheet_set_start_page(worksheet, 2);
* @endcode
*/
void worksheet_set_start_page(lxw_worksheet *worksheet, uint16_t start_page);
/**
* @brief Set the scale factor for the printed page.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param scale Print scale of worksheet to be printed.
*
* This function sets the scale factor of the printed page. The Scale factor
* must be in the range `10 <= scale <= 400`:
*
* @code
* worksheet_set_print_scale(worksheet1, 75);
* worksheet_set_print_scale(worksheet2, 400);
* @endcode
*
* The default scale factor is 100. Note, `%worksheet_set_print_scale()` does
* not affect the scale of the visible page in Excel. For that you should use
* `worksheet_set_zoom()`.
*
* Note that although it is valid to use both `worksheet_fit_to_pages()` and
* `%worksheet_set_print_scale()` on the same worksheet Excel only allows one
* of these options to be active at a time. The last function call made will
* set the active option.
*
*/
void worksheet_set_print_scale(lxw_worksheet *worksheet, uint16_t scale);
/**
* @brief Set the worksheet to print in black and white
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
*
* Set the option to print the worksheet in black and white:
* @code
* worksheet_print_black_and_white(worksheet);
* @endcode
*/
void worksheet_print_black_and_white(lxw_worksheet *worksheet);
/**
* @brief Display the worksheet cells from right to left for some versions of
* Excel.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
*
* The `%worksheet_right_to_left()` function is used to change the default
* direction of the worksheet from left-to-right, with the `A1` cell in the
* top left, to right-to-left, with the `A1` cell in the top right.
*
* @code
* worksheet_right_to_left(worksheet1);
* @endcode
*
* This is useful when creating Arabic, Hebrew or other near or far eastern
* worksheets that use right-to-left as the default direction.
*/
void worksheet_right_to_left(lxw_worksheet *worksheet);
/**
* @brief Hide zero values in worksheet cells.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
*
* The `%worksheet_hide_zero()` function is used to hide any zero values that
* appear in cells:
*
* @code
* worksheet_hide_zero(worksheet1);
* @endcode
*/
void worksheet_hide_zero(lxw_worksheet *worksheet);
/**
* @brief Set the color of the worksheet tab.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param color The tab color.
*
* The `%worksheet_set_tab_color()` function is used to change the color of
* the worksheet tab:
*
* @code
* worksheet_set_tab_color(worksheet1, LXW_COLOR_RED);
* worksheet_set_tab_color(worksheet2, LXW_COLOR_GREEN);
* worksheet_set_tab_color(worksheet3, 0xFF9900); // Orange.
* @endcode
*
* The color should be an RGB integer value, see @ref working_with_colors.
*/
void worksheet_set_tab_color(lxw_worksheet *worksheet, lxw_color_t color);
/**
* @brief Protect elements of a worksheet from modification.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param password A worksheet password.
* @param options Worksheet elements to protect.
*
* The `%worksheet_protect()` function protects worksheet elements from modification:
*
* @code
* worksheet_protect(worksheet, "Some Password", options);
* @endcode
*
* The `password` and lxw_protection pointer are both optional:
*
* @code
* worksheet_protect(worksheet1, NULL, NULL);
* worksheet_protect(worksheet2, NULL, my_options);
* worksheet_protect(worksheet3, "password", NULL);
* worksheet_protect(worksheet4, "password", my_options);
* @endcode
*
* Passing a `NULL` password is the same as turning on protection without a
* password. Passing a `NULL` password and `NULL` options, or any other
* combination has the effect of enabling a cell's `locked` and `hidden`
* properties if they have been set.
*
* A *locked* cell cannot be edited and this property is on by default for all
* cells. A *hidden* cell will display the results of a formula but not the
* formula itself. These properties can be set using the format_set_unlocked()
* and format_set_hidden() format functions.
*
* You can specify which worksheet elements you wish to protect by passing a
* lxw_protection pointer in the `options` argument with any or all of the
* following members set:
*
* no_select_locked_cells
* no_select_unlocked_cells
* format_cells
* format_columns
* format_rows
* insert_columns
* insert_rows
* insert_hyperlinks
* delete_columns
* delete_rows
* sort
* autofilter
* pivot_tables
* scenarios
* objects
*
* All parameters are off by default. Individual elements can be protected as
* follows:
*
* @code
* lxw_protection options = {
* .format_cells = 1,
* .insert_hyperlinks = 1,
* .insert_rows = 1,
* .delete_rows = 1,
* .insert_columns = 1,
* .delete_columns = 1,
* };
*
* worksheet_protect(worksheet, NULL, &options);
*
* @endcode
*
* See also the format_set_unlocked() and format_set_hidden() format functions.
*
* **Note:** Sheet level passwords in Excel offer **very** weak
* protection. They don't encrypt your data and are very easy to
* deactivate. Full workbook encryption is not supported by `libxlsxwriter`
* since it requires a completely different file format.
*/
void worksheet_protect(lxw_worksheet *worksheet, const char *password,
lxw_protection *options);
/**
* @brief Set the Outline and Grouping display properties.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param visible Outlines are visible. Optional, defaults to True.
* @param symbols_below Show row outline symbols below the outline bar.
* @param symbols_right Show column outline symbols to the right of outline.
* @param auto_style Use Automatic outline style.
*
* The `%worksheet_outline_settings()` method is used to control the
* appearance of outlines in Excel. Outlines are described the section on
* @ref working_with_outlines.
*
* The `visible` parameter is used to control whether or not outlines are
* visible. Setting this parameter to False will cause all outlines on the
* worksheet to be hidden. They can be un-hidden in Excel by means of the
* "Show Outline Symbols" command button. The default Excel setting is True
* for visible outlines.
*
* The `symbols_below` parameter is used to control whether the row outline
* symbol will appear above or below the outline level bar. The default Excel
* setting is True for symbols to appear below the outline level bar.
*
* The `symbols_right` parameter is used to control whether the column outline
* symbol will appear to the left or the right of the outline level bar. The
* default Excel setting is True for symbols to appear to the right of the
* outline level bar.
*
* The `auto_style` parameter is used to control whether the automatic outline
* generator in Excel uses automatic styles when creating an outline. This has
* no effect on a file generated by XlsxWriter but it does have an effect on
* how the worksheet behaves after it is created. The default Excel setting is
* False for "Automatic Styles" to be turned off.
*
* The default settings for all of these parameters in libxlsxwriter
* correspond to Excel's default parameters and are shown below:
*
* @code
* worksheet_outline_settings(worksheet1, LXW_TRUE, LXW_TRUE, LXW_TRUE, LXW_FALSE);
* @endcode
*
* The worksheet parameters controlled by `worksheet_outline_settings()` are
* rarely used.
*/
void worksheet_outline_settings(lxw_worksheet *worksheet, uint8_t visible,
uint8_t symbols_below, uint8_t symbols_right,
uint8_t auto_style);
/**
* @brief Set the default row properties.
*
* @param worksheet Pointer to a lxw_worksheet instance to be updated.
* @param height Default row height.
* @param hide_unused_rows Hide unused cells.
*
* The `%worksheet_set_default_row()` function is used to set Excel default
* row properties such as the default height and the option to hide unused
* rows. These parameters are an optimization used by Excel to set row
* properties without generating a very large file with an entry for each row.
*
* To set the default row height:
*
* @code
* worksheet_set_default_row(worksheet, 24, LXW_FALSE);
*
* @endcode
*
* To hide unused rows:
*
* @code
* worksheet_set_default_row(worksheet, 15, LXW_TRUE);
* @endcode
*
* Note, in the previous case we use the default height #LXW_DEF_ROW_HEIGHT =
* 15 so the the height remains unchanged.
*/
void worksheet_set_default_row(lxw_worksheet *worksheet, double height,
uint8_t hide_unused_rows);
/**
* @brief Set the VBA name for the worksheet.
*
* @param worksheet Pointer to a lxw_worksheet instance.
* @param name Name of the worksheet used by VBA.
*
* @return A #lxw_error.
*
* The `worksheet_set_vba_name()` function can be used to set the VBA name for
* the worksheet. This is sometimes required when a vbaProject macro included
* via `workbook_add_vba_project()` refers to the worksheet by a name other
* than the worksheet name:
*
* @code
* workbook_set_vba_name (workbook, "MyWorkbook");
* worksheet_set_vba_name(worksheet, "MySheet1");
* @endcode
*
* In general Excel uses the worksheet name such as "Sheet1" as the VBA name.
* However, this can be changed in the VBA environment or if the the macro was
* extracted from a foreign language version of Excel.
*
* See also @ref working_with_macros
*/
lxw_error worksheet_set_vba_name(lxw_worksheet *worksheet, const char *name);
/**
* @brief Make all comments in the worksheet visible.
*
* @param worksheet Pointer to a lxw_worksheet instance.
*
* This `%worksheet_show_comments()` function is used to make all cell
* comments visible when a worksheet is opened:
*
* @code
* worksheet_show_comments(worksheet);
* @endcode
*
* Individual comments can be made visible or hidden using the `visible`
* option of the #lxw_comment_options struct and the `worksheet_write_comment_opt()`
* function (see above and @ref ww_comments_visible).
*/
void worksheet_show_comments(lxw_worksheet *worksheet);
/**
* @brief Set the default author of the cell comments.
*
* @param worksheet Pointer to a lxw_worksheet instance.
* @param author The name of the comment author.
*
* This `%worksheet_set_comments_author()` function is used to set the
* default author of all cell comments:
*
* @code
* worksheet_set_comments_author(worksheet, "Jane Gloriana Villanueva")
* @endcode
*
* Individual authors can be set using the `author` option of the
* #lxw_comment_options struct and the `worksheet_write_comment_opt()`
* function (see above and @ref ww_comments_author).
*/
void worksheet_set_comments_author(lxw_worksheet *worksheet,
const char *author);
/**
* @brief Ignore various Excel errors/warnings in a worksheet for user
* defined ranges.
*
* @param worksheet Pointer to a lxw_worksheet instance.
* @param type The type of error/warning to ignore. See #lxw_ignore_errors.
* @param range The range(s) for which the error/warning should be ignored.
*
* @return A #lxw_error.
*
*
* The `%worksheet_ignore_errors()` function can be used to ignore various
* worksheet cell errors/warnings. For example the following code writes a string
* that looks like a number:
*
* @code
* worksheet_write_string(worksheet, CELL("D2"), "123", NULL);
* @endcode
*
* This causes Excel to display a small green triangle in the top left hand
* corner of the cell to indicate an error/warning:
*
* @image html ignore_errors1.png
*
* Sometimes these warnings are useful indicators that there is an issue in
* the spreadsheet but sometimes it is preferable to turn them off. Warnings
* can be turned off at the Excel level for all workbooks and worksheets by
* using the using "Excel options -> Formulas -> Error checking
* rules". Alternatively you can turn them off for individual cells in a
* worksheet, or ranges of cells, using the `%worksheet_ignore_errors()`
* function with different #lxw_ignore_errors options and ranges like this:
*
* @code
* worksheet_ignore_errors(worksheet, LXW_IGNORE_NUMBER_STORED_AS_TEXT, "C3");
* worksheet_ignore_errors(worksheet, LXW_IGNORE_EVAL_ERROR, "C6");
* @endcode
*
* The range can be a single cell, a range of cells, or multiple cells and ranges
* separated by spaces:
*
* @code
* // Single cell.
* worksheet_ignore_errors(worksheet, LXW_IGNORE_NUMBER_STORED_AS_TEXT, "C6");
*
* // Or a single range:
* worksheet_ignore_errors(worksheet, LXW_IGNORE_NUMBER_STORED_AS_TEXT, "C6:G8");
*
* // Or multiple cells and ranges:
* worksheet_ignore_errors(worksheet, LXW_IGNORE_NUMBER_STORED_AS_TEXT, "C6 E6 G1:G20 J2:J6");
* @endcode
*
* @note Calling `%worksheet_ignore_errors()` more than once for the same
* #lxw_ignore_errors type will overwrite the previous range.
*
* You can turn off warnings for an entire column by specifying the range from
* the first cell in the column to the last cell in the column:
*
* @code
* worksheet_ignore_errors(worksheet, LXW_IGNORE_NUMBER_STORED_AS_TEXT, "A1:A1048576");
* @endcode
*
* Or for the entire worksheet by specifying the range from the first cell in
* the worksheet to the last cell in the worksheet:
*
* @code
* worksheet_ignore_errors(worksheet, LXW_IGNORE_NUMBER_STORED_AS_TEXT, "A1:XFD1048576");
* @endcode
*
* The worksheet errors/warnings that can be ignored are:
*
* - #LXW_IGNORE_NUMBER_STORED_AS_TEXT: Turn off errors/warnings for numbers
* stores as text.
*
* - #LXW_IGNORE_EVAL_ERROR: Turn off errors/warnings for formula errors (such
* as divide by zero).
*
* - #LXW_IGNORE_FORMULA_DIFFERS: Turn off errors/warnings for formulas that
* differ from surrounding formulas.
*
* - #LXW_IGNORE_FORMULA_RANGE: Turn off errors/warnings for formulas that
* omit cells in a range.
*
* - #LXW_IGNORE_FORMULA_UNLOCKED: Turn off errors/warnings for unlocked cells
* that contain formulas.
*
* - #LXW_IGNORE_EMPTY_CELL_REFERENCE: Turn off errors/warnings for formulas
* that refer to empty cells.
*
* - #LXW_IGNORE_LIST_DATA_VALIDATION: Turn off errors/warnings for cells in a
* table that do not comply with applicable data validation rules.
*
* - #LXW_IGNORE_CALCULATED_COLUMN: Turn off errors/warnings for cell formulas
* that differ from the column formula.
*
* - #LXW_IGNORE_TWO_DIGIT_TEXT_YEAR: Turn off errors/warnings for formulas
* that contain a two digit text representation of a year.
*
*/
lxw_error worksheet_ignore_errors(lxw_worksheet *worksheet, uint8_t type,
const char *range);
lxw_worksheet *lxw_worksheet_new(lxw_worksheet_init_data *init_data);
void lxw_worksheet_free(lxw_worksheet *worksheet);
void lxw_worksheet_assemble_xml_file(lxw_worksheet *worksheet);
void lxw_worksheet_write_single_row(lxw_worksheet *worksheet);
void lxw_worksheet_prepare_image(lxw_worksheet *worksheet,
uint32_t image_ref_id, uint32_t drawing_id,
lxw_object_properties *object_props);
void lxw_worksheet_prepare_header_image(lxw_worksheet *worksheet,
uint32_t image_ref_id,
lxw_object_properties *object_props);
void lxw_worksheet_prepare_background(lxw_worksheet *worksheet,
uint32_t image_ref_id,
lxw_object_properties *object_props);
void lxw_worksheet_prepare_chart(lxw_worksheet *worksheet,
uint32_t chart_ref_id, uint32_t drawing_id,
lxw_object_properties *object_props,
uint8_t is_chartsheet);
uint32_t lxw_worksheet_prepare_vml_objects(lxw_worksheet *worksheet,
uint32_t vml_data_id,
uint32_t vml_shape_id,
uint32_t vml_drawing_id,
uint32_t comment_id);
void lxw_worksheet_prepare_header_vml_objects(lxw_worksheet *worksheet,
uint32_t vml_header_id,
uint32_t vml_drawing_id);
void lxw_worksheet_prepare_tables(lxw_worksheet *worksheet,
uint32_t table_id);
lxw_row *lxw_worksheet_find_row(lxw_worksheet *worksheet, lxw_row_t row_num);
lxw_cell *lxw_worksheet_find_cell_in_row(lxw_row *row, lxw_col_t col_num);
/*
* External functions to call intern XML functions shared with chartsheet.
*/
void lxw_worksheet_write_sheet_views(lxw_worksheet *worksheet);
void lxw_worksheet_write_page_margins(lxw_worksheet *worksheet);
void lxw_worksheet_write_drawings(lxw_worksheet *worksheet);
void lxw_worksheet_write_sheet_protection(lxw_worksheet *worksheet,
lxw_protection_obj *protect);
void lxw_worksheet_write_sheet_pr(lxw_worksheet *worksheet);
void lxw_worksheet_write_page_setup(lxw_worksheet *worksheet);
void lxw_worksheet_write_header_footer(lxw_worksheet *worksheet);
/* Declarations required for unit testing. */
#ifdef TESTING
STATIC void _worksheet_xml_declaration(lxw_worksheet *worksheet);
STATIC void _worksheet_write_worksheet(lxw_worksheet *worksheet);
STATIC void _worksheet_write_dimension(lxw_worksheet *worksheet);
STATIC void _worksheet_write_sheet_view(lxw_worksheet *worksheet);
STATIC void _worksheet_write_sheet_views(lxw_worksheet *worksheet);
STATIC void _worksheet_write_sheet_format_pr(lxw_worksheet *worksheet);
STATIC void _worksheet_write_sheet_data(lxw_worksheet *worksheet);
STATIC void _worksheet_write_page_margins(lxw_worksheet *worksheet);
STATIC void _worksheet_write_page_setup(lxw_worksheet *worksheet);
STATIC void _worksheet_write_col_info(lxw_worksheet *worksheet,
lxw_col_options *options);
STATIC void _write_row(lxw_worksheet *worksheet, lxw_row *row, char *spans);
STATIC lxw_row *_get_row_list(struct lxw_table_rows *table,
lxw_row_t row_num);
STATIC void _worksheet_write_merge_cell(lxw_worksheet *worksheet,
lxw_merged_range *merged_range);
STATIC void _worksheet_write_merge_cells(lxw_worksheet *worksheet);
STATIC void _worksheet_write_odd_header(lxw_worksheet *worksheet);
STATIC void _worksheet_write_odd_footer(lxw_worksheet *worksheet);
STATIC void _worksheet_write_header_footer(lxw_worksheet *worksheet);
STATIC void _worksheet_write_print_options(lxw_worksheet *worksheet);
STATIC void _worksheet_write_sheet_pr(lxw_worksheet *worksheet);
STATIC void _worksheet_write_tab_color(lxw_worksheet *worksheet);
STATIC void _worksheet_write_sheet_protection(lxw_worksheet *worksheet,
lxw_protection_obj *protect);
STATIC void _worksheet_write_data_validations(lxw_worksheet *self);
STATIC double _pixels_to_height(double pixels);
STATIC double _pixels_to_width(double pixels);
STATIC void _worksheet_write_auto_filter(lxw_worksheet *worksheet);
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_WORKSHEET_H__ */
writexl/src/include/xlsxwriter/drawing.h 0000644 0001762 0000144 00000004150 14747162622 020234 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* drawing - A libxlsxwriter library for creating Excel XLSX drawing files.
*
*/
#ifndef __LXW_DRAWING_H__
#define __LXW_DRAWING_H__
#include
#include
#include "common.h"
STAILQ_HEAD(lxw_drawing_objects, lxw_drawing_object);
enum lxw_drawing_types {
LXW_DRAWING_NONE = 0,
LXW_DRAWING_IMAGE,
LXW_DRAWING_CHART,
LXW_DRAWING_SHAPE
};
enum image_types {
LXW_IMAGE_UNKNOWN = 0,
LXW_IMAGE_PNG,
LXW_IMAGE_JPEG,
LXW_IMAGE_BMP,
LXW_IMAGE_GIF
};
/* Coordinates used in a drawing object. */
typedef struct lxw_drawing_coords {
uint32_t col;
uint32_t row;
double col_offset;
double row_offset;
} lxw_drawing_coords;
/* Object to represent the properties of a drawing. */
typedef struct lxw_drawing_object {
uint8_t type;
uint8_t anchor;
struct lxw_drawing_coords from;
struct lxw_drawing_coords to;
uint64_t col_absolute;
uint64_t row_absolute;
uint32_t width;
uint32_t height;
uint8_t shape;
uint32_t rel_index;
uint32_t url_rel_index;
char *description;
char *tip;
uint8_t decorative;
STAILQ_ENTRY (lxw_drawing_object) list_pointers;
} lxw_drawing_object;
/*
* Struct to represent a collection of drawings.
*/
typedef struct lxw_drawing {
FILE *file;
uint8_t embedded;
uint8_t orientation;
struct lxw_drawing_objects *drawing_objects;
} lxw_drawing;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
lxw_drawing *lxw_drawing_new(void);
void lxw_drawing_free(lxw_drawing *drawing);
void lxw_drawing_assemble_xml_file(lxw_drawing *self);
void lxw_free_drawing_object(struct lxw_drawing_object *drawing_object);
void lxw_add_drawing_object(lxw_drawing *drawing,
lxw_drawing_object *drawing_object);
/* Declarations required for unit testing. */
#ifdef TESTING
STATIC void _drawing_xml_declaration(lxw_drawing *self);
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_DRAWING_H__ */
writexl/src/include/xlsxwriter/core.h 0000644 0001762 0000144 00000001515 14747162622 017533 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* core - A libxlsxwriter library for creating Excel XLSX core files.
*
*/
#ifndef __LXW_CORE_H__
#define __LXW_CORE_H__
#include
#include "workbook.h"
#include "common.h"
/*
* Struct to represent a core.
*/
typedef struct lxw_core {
FILE *file;
lxw_doc_properties *properties;
} lxw_core;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
lxw_core *lxw_core_new(void);
void lxw_core_free(lxw_core *core);
void lxw_core_assemble_xml_file(lxw_core *self);
/* Declarations required for unit testing. */
#ifdef TESTING
STATIC void _core_xml_declaration(lxw_core *self);
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_CORE_H__ */
writexl/src/include/xlsxwriter/app.h 0000644 0001762 0000144 00000003111 14747162622 017355 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* app - A libxlsxwriter library for creating Excel XLSX app files.
*
*/
#ifndef __LXW_APP_H__
#define __LXW_APP_H__
#include
#include
#include "workbook.h"
#include "common.h"
/* Define the queue.h TAILQ structs for the App structs. */
STAILQ_HEAD(lxw_heading_pairs, lxw_heading_pair);
STAILQ_HEAD(lxw_part_names, lxw_part_name);
typedef struct lxw_heading_pair {
char *key;
char *value;
STAILQ_ENTRY (lxw_heading_pair) list_pointers;
} lxw_heading_pair;
typedef struct lxw_part_name {
char *name;
STAILQ_ENTRY (lxw_part_name) list_pointers;
} lxw_part_name;
/* Struct to represent an App object. */
typedef struct lxw_app {
FILE *file;
struct lxw_heading_pairs *heading_pairs;
struct lxw_part_names *part_names;
lxw_doc_properties *properties;
uint32_t num_heading_pairs;
uint32_t num_part_names;
uint8_t doc_security;
} lxw_app;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
lxw_app *lxw_app_new(void);
void lxw_app_free(lxw_app *app);
void lxw_app_assemble_xml_file(lxw_app *self);
void lxw_app_add_part_name(lxw_app *self, const char *name);
void lxw_app_add_heading_pair(lxw_app *self, const char *key,
const char *value);
/* Declarations required for unit testing. */
#ifdef TESTING
STATIC void _app_xml_declaration(lxw_app *self);
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_APP_H__ */
writexl/src/include/xlsxwriter/workbook.h 0000644 0001762 0000144 00000116730 14747162622 020446 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, 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 = workbook_new("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
#include
#include
#include "worksheet.h"
#include "chartsheet.h"
#include "chart.h"
#include "shared_strings.h"
#include "hash_table.h"
#include "common.h"
#define LXW_DEFINED_NAME_LENGTH 128
/* Define the tree.h RB structs for the red-black head types. */
RB_HEAD(lxw_worksheet_names, lxw_worksheet_name);
RB_HEAD(lxw_chartsheet_names, lxw_chartsheet_name);
RB_HEAD(lxw_image_md5s, lxw_image_md5);
/* Define the queue.h structs for the workbook lists. */
STAILQ_HEAD(lxw_sheets, lxw_sheet);
STAILQ_HEAD(lxw_worksheets, lxw_worksheet);
STAILQ_HEAD(lxw_chartsheets, lxw_chartsheet);
STAILQ_HEAD(lxw_charts, lxw_chart);
TAILQ_HEAD(lxw_defined_names, lxw_defined_name);
/* Struct to hold the 2 sheet types. */
typedef struct lxw_sheet {
uint8_t is_chartsheet;
union {
lxw_worksheet *worksheet;
lxw_chartsheet *chartsheet;
} u;
STAILQ_ENTRY (lxw_sheet) list_pointers;
} lxw_sheet;
/* Struct to represent a worksheet name/pointer pair. */
typedef struct lxw_worksheet_name {
const char *name;
lxw_worksheet *worksheet;
RB_ENTRY (lxw_worksheet_name) tree_pointers;
} lxw_worksheet_name;
/* Struct to represent a chartsheet name/pointer pair. */
typedef struct lxw_chartsheet_name {
const char *name;
lxw_chartsheet *chartsheet;
RB_ENTRY (lxw_chartsheet_name) tree_pointers;
} lxw_chartsheet_name;
/* Struct to represent an image MD5/ID pair. */
typedef struct lxw_image_md5 {
uint32_t id;
char *md5;
RB_ENTRY (lxw_image_md5) tree_pointers;
} lxw_image_md5;
/* Wrapper around RB_GENERATE_STATIC from tree.h to avoid unused function
* warnings and to avoid portability issues with the _unused attribute. */
#define LXW_RB_GENERATE_WORKSHEET_NAMES(name, type, field, cmp) \
RB_GENERATE_INSERT_COLOR(name, type, field, static) \
RB_GENERATE_REMOVE_COLOR(name, type, field, static) \
RB_GENERATE_INSERT(name, type, field, cmp, static) \
RB_GENERATE_REMOVE(name, type, field, static) \
RB_GENERATE_FIND(name, type, field, cmp, static) \
RB_GENERATE_NEXT(name, type, field, static) \
RB_GENERATE_MINMAX(name, type, field, static) \
/* Add unused struct to allow adding a semicolon */ \
struct lxw_rb_generate_worksheet_names{int unused;}
#define LXW_RB_GENERATE_CHARTSHEET_NAMES(name, type, field, cmp) \
RB_GENERATE_INSERT_COLOR(name, type, field, static) \
RB_GENERATE_REMOVE_COLOR(name, type, field, static) \
RB_GENERATE_INSERT(name, type, field, cmp, static) \
RB_GENERATE_REMOVE(name, type, field, static) \
RB_GENERATE_FIND(name, type, field, cmp, static) \
RB_GENERATE_NEXT(name, type, field, static) \
RB_GENERATE_MINMAX(name, type, field, static) \
/* Add unused struct to allow adding a semicolon */ \
struct lxw_rb_generate_charsheet_names{int unused;}
#define LXW_RB_GENERATE_IMAGE_MD5S(name, type, field, cmp) \
RB_GENERATE_INSERT_COLOR(name, type, field, static) \
RB_GENERATE_REMOVE_COLOR(name, type, field, static) \
RB_GENERATE_INSERT(name, type, field, cmp, static) \
RB_GENERATE_REMOVE(name, type, field, static) \
RB_GENERATE_FIND(name, type, field, cmp, static) \
RB_GENERATE_NEXT(name, type, field, static) \
RB_GENERATE_MINMAX(name, type, field, static) \
/* Add unused struct to allow adding a semicolon */ \
struct lxw_rb_generate_image_md5s{int unused;}
/**
* @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 = workbook_new("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;
/**
* Workbook document properties. Set any unused fields to NULL or 0.
*/
typedef struct lxw_doc_properties {
/** The title of the Excel Document. */
const char *title;
/** The subject of the Excel Document. */
const char *subject;
/** The author of the Excel Document. */
const char *author;
/** The manager field of the Excel Document. */
const char *manager;
/** The company field of the Excel Document. */
const char *company;
/** The category of the Excel Document. */
const char *category;
/** The keywords of the Excel Document. */
const char *keywords;
/** The comment field of the Excel Document. */
const char *comments;
/** The status of the Excel Document. */
const char *status;
/** The hyperlink base URL of the Excel Document. */
const char *hyperlink_base;
/** The file creation date/time shown in Excel. This defaults to the
* current time and date if set to 0. If you wish to create files that are
* binary equivalent (for the same input data) then you should set this
* creation date/time to a known value. */
time_t created;
} lxw_doc_properties;
/**
* @brief Workbook options.
*
* Optional parameters when creating a new Workbook object via
* workbook_new_opt().
*
* The following properties are supported:
*
* - `constant_memory`: This option reduces the amount of data stored in
* memory so that large files can be written efficiently. This option is off
* by default. See the notes below for limitations when this mode is on.
*
* - `tmpdir`: libxlsxwriter stores workbook data in temporary files prior to
* assembling the final XLSX file. The temporary files are created in the
* system's temp directory. If the default temporary directory isn't
* accessible to your application, or doesn't contain enough space, you can
* specify an alternative location using the `tmpdir` option.
*
* - `use_zip64`: Make the zip library use ZIP64 extensions when writing very
* large xlsx files to allow the zip container, or individual XML files
* within it, to be greater than 4 GB. See [ZIP64 on Wikipedia][zip64_wiki]
* for more information. This option is off by default.
*
* [zip64_wiki]: https://en.wikipedia.org/wiki/Zip_(file_format)#ZIP64
* - `output_buffer`: Output to a buffer instead of a file. The buffer must be
* freed manually by calling free(). This option can only be used if filename
* is NULL.
*
* - `output_buffer_size`: Used with output_buffer to get the size of the
* created buffer. This option can only be used if filename is NULL.
*
* @note In `constant_memory` mode each row of in-memory data is written to
* disk and then freed when a new row is started via one of the
* `worksheet_write_*()` functions. Therefore, once this option is active data
* should be written in sequential row by row order. For this reason
* `worksheet_merge_range()` and some other row based functionality doesn't
* work in this mode. See @ref ww_mem_constant for more details.
*
* @note Also, in `constant_memory` mode the library uses temp file storage
* for worksheet data. This can lead to an issue on OSes that map the `/tmp`
* directory into memory since it is possible to consume the "system" memory
* even though the "process" memory remains constant. In these cases you
* should use an alternative temp file location by using the `tmpdir` option
* shown above. See @ref ww_mem_temp for more details.
*/
typedef struct lxw_workbook_options {
/** Optimize the workbook to use constant memory for worksheets. */
uint8_t constant_memory;
/** Directory to use for the temporary files created by libxlsxwriter. */
const char *tmpdir;
/** Allow ZIP64 extensions when creating the xlsx file zip container. */
uint8_t use_zip64;
/** Output buffer to use instead of writing to a file */
const char **output_buffer;
/** Used with output_buffer to get the size of the created buffer */
size_t *output_buffer_size;
} 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_sheets *sheets;
struct lxw_worksheets *worksheets;
struct lxw_chartsheets *chartsheets;
struct lxw_worksheet_names *worksheet_names;
struct lxw_chartsheet_names *chartsheet_names;
struct lxw_image_md5s *image_md5s;
struct lxw_image_md5s *header_image_md5s;
struct lxw_image_md5s *background_md5s;
struct lxw_charts *charts;
struct lxw_charts *ordered_charts;
struct lxw_formats *formats;
struct lxw_defined_names *defined_names;
lxw_sst *sst;
lxw_doc_properties *properties;
struct lxw_custom_properties *custom_properties;
char *filename;
lxw_workbook_options options;
uint16_t num_sheets;
uint16_t num_worksheets;
uint16_t num_chartsheets;
uint16_t first_sheet;
uint16_t active_sheet;
uint16_t num_xf_formats;
uint16_t num_dxf_formats;
uint16_t num_format_count;
uint16_t drawing_count;
uint16_t comment_count;
uint16_t font_count;
uint16_t border_count;
uint16_t fill_count;
uint8_t optimize;
uint16_t max_url_length;
uint8_t read_only;
uint8_t has_png;
uint8_t has_jpeg;
uint8_t has_bmp;
uint8_t has_gif;
uint8_t has_vml;
uint8_t has_comments;
uint8_t has_metadata;
lxw_hash_table *used_xf_formats;
lxw_hash_table *used_dxf_formats;
char *vba_project;
char *vba_project_signature;
char *vba_codename;
lxw_format *default_url_format;
} 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 `%workbook_new()` constructor is used to create a new Excel workbook
* with a given filename:
*
* @code
* lxw_workbook *workbook = workbook_new("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 *workbook_new(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 function is the same as the `workbook_new()` constructor but allows
* additional options to be set.
*
* @code
* lxw_workbook_options options = {.constant_memory = LXW_TRUE,
* .tmpdir = "C:\\Temp",
* .use_zip64 = LXW_FALSE,
* .output_buffer = NULL,
* .output_buffer_size = NULL};
*
* lxw_workbook *workbook = workbook_new_opt("filename.xlsx", &options);
* @endcode
*
* The options that can be set via #lxw_workbook_options are:
*
* - `constant_memory`: This option reduces the amount of data stored in
* memory so that large files can be written efficiently. This option is off
* by default. See the note below for limitations when this mode is on.
*
* - `tmpdir`: libxlsxwriter stores workbook data in temporary files prior to
* assembling the final XLSX file. The temporary files are created in the
* system's temp directory. If the default temporary directory isn't
* accessible to your application, or doesn't contain enough space, you can
* specify an alternative location using the `tmpdir` option.
*
* - `use_zip64`: Make the zip library use ZIP64 extensions when writing very
* large xlsx files to allow the zip container, or individual XML files
* within it, to be greater than 4 GB. See [ZIP64 on Wikipedia][zip64_wiki]
* for more information. This option is off by default.
*
* [zip64_wiki]: https://en.wikipedia.org/wiki/Zip_(file_format)#ZIP64
*
* - `output_buffer`: Output to a memory buffer instead of a file. The buffer
* must be freed manually by calling `free()`. This option can only be used if
* filename is NULL.
*
* - `output_buffer_size`: Used with output_buffer to get the size of the
* created buffer. This option can only be used if filename is `NULL`.
*
* @note In `constant_memory` mode each row of in-memory data is written to
* disk and then freed when a new row is started via one of the
* `worksheet_write_*()` functions. Therefore, once this option is active data
* should be written in sequential row by row order. For this reason
* `worksheet_merge_range()` and some other row based functionality doesn't
* work in this mode. See @ref ww_mem_constant for more details.
*
* @note Also, in `constant_memory` mode the library uses temp file storage
* for worksheet data. This can lead to an issue on OSes that map the `/tmp`
* directory into memory since it is possible to consume the "system" memory
* even though the "process" memory remains constant. In these cases you
* should use an alternative temp file location by using the `tmpdir` option
* shown above. See @ref ww_mem_temp for more details.
*/
lxw_workbook *workbook_new_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 object.
*
* The `%workbook_add_worksheet()` function 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:
*
* - The name is less than or equal to 31 UTF-8 characters.
* - The name doesn't contain any of the characters: ` [ ] : * ? / \ `
* - The name doesn't start or end with an apostrophe.
* - The name isn't already in use. (Case insensitive).
*
* If any of these errors are encountered the function will return NULL.
* You can check for valid name using the `workbook_validate_sheet_name()`
* function.
*
* @note You should also avoid using the worksheet name "History" (case
* insensitive) which is reserved in English language versions of
* Excel. Non-English versions may have restrictions on the equivalent word.
*/
lxw_worksheet *workbook_add_worksheet(lxw_workbook *workbook,
const char *sheetname);
/**
* @brief Add a new chartsheet to a workbook.
*
* @param workbook Pointer to a lxw_workbook instance.
* @param sheetname Optional chartsheet name, defaults to Chart1, etc.
*
* @return A lxw_chartsheet object.
*
* The `%workbook_add_chartsheet()` function adds a new chartsheet to a
* workbook. The @ref chartsheet.h "Chartsheet" object is like a worksheet
* except it displays a chart instead of cell data.
*
* @image html chartsheet.png
*
* The `sheetname` parameter is optional. If it is `NULL` the default
* Excel convention will be followed, i.e. Chart1, Chart2, etc.:
*
* @code
* chartsheet = workbook_add_chartsheet(workbook, NULL ); // Chart1
* chartsheet = workbook_add_chartsheet(workbook, "My Chart"); // My Chart
* chartsheet = workbook_add_chartsheet(workbook, NULL ); // Chart3
*
* @endcode
*
* The chartsheet name must be a valid Excel worksheet name, i.e.:
*
* - The name is less than or equal to 31 UTF-8 characters.
* - The name doesn't contain any of the characters: ` [ ] : * ? / \ `
* - The name doesn't start or end with an apostrophe.
* - The name isn't already in use. (Case insensitive).
*
* If any of these errors are encountered the function will return NULL.
* You can check for valid name using the `workbook_validate_sheet_name()`
* function.
*
* @note You should also avoid using the worksheet name "History" (case
* insensitive) which is reserved in English language versions of
* Excel. Non-English versions may have restrictions on the equivalent word.
*
* At least one worksheet should be added to a new workbook when creating a
* chartsheet in order to provide data for the chart. The @ref worksheet.h
* "Worksheet" object is used to write data and configure a worksheet in the
* workbook.
*/
lxw_chartsheet *workbook_add_chartsheet(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 Create a new chart to be added to a worksheet:
*
* @param workbook Pointer to a lxw_workbook instance.
* @param chart_type The type of chart to be created. See #lxw_chart_type.
*
* @return A lxw_chart object.
*
* The `%workbook_add_chart()` function creates a new chart object that can
* be added to a worksheet:
*
* @code
* // Create a chart object.
* lxw_chart *chart = workbook_add_chart(workbook, LXW_CHART_COLUMN);
*
* // Add data series to the chart.
* chart_add_series(chart, NULL, "Sheet1!$A$1:$A$5");
* chart_add_series(chart, NULL, "Sheet1!$B$1:$B$5");
* chart_add_series(chart, NULL, "Sheet1!$C$1:$C$5");
*
* // Insert the chart into the worksheet
* worksheet_insert_chart(worksheet, CELL("B7"), chart);
* @endcode
*
* The available chart types are defined in #lxw_chart_type. The types of
* charts that are supported are:
*
* | Chart type | Description |
* | :--------------------------------------- | :------------------------------------ |
* | #LXW_CHART_AREA | Area chart. |
* | #LXW_CHART_AREA_STACKED | Area chart - stacked. |
* | #LXW_CHART_AREA_STACKED_PERCENT | Area chart - percentage stacked. |
* | #LXW_CHART_BAR | Bar chart. |
* | #LXW_CHART_BAR_STACKED | Bar chart - stacked. |
* | #LXW_CHART_BAR_STACKED_PERCENT | Bar chart - percentage stacked. |
* | #LXW_CHART_COLUMN | Column chart. |
* | #LXW_CHART_COLUMN_STACKED | Column chart - stacked. |
* | #LXW_CHART_COLUMN_STACKED_PERCENT | Column chart - percentage stacked. |
* | #LXW_CHART_DOUGHNUT | Doughnut chart. |
* | #LXW_CHART_LINE | Line chart. |
* | #LXW_CHART_LINE_STACKED | Line chart - stacked. |
* | #LXW_CHART_LINE_STACKED_PERCENT | Line chart - percentage stacked. |
* | #LXW_CHART_PIE | Pie chart. |
* | #LXW_CHART_SCATTER | Scatter chart. |
* | #LXW_CHART_SCATTER_STRAIGHT | Scatter chart - straight. |
* | #LXW_CHART_SCATTER_STRAIGHT_WITH_MARKERS | Scatter chart - straight with markers. |
* | #LXW_CHART_SCATTER_SMOOTH | Scatter chart - smooth. |
* | #LXW_CHART_SCATTER_SMOOTH_WITH_MARKERS | Scatter chart - smooth with markers. |
* | #LXW_CHART_RADAR | Radar chart. |
* | #LXW_CHART_RADAR_WITH_MARKERS | Radar chart - with markers. |
* | #LXW_CHART_RADAR_FILLED | Radar chart - filled. |
*
*
*
* See @ref chart.h for details.
*/
lxw_chart *workbook_add_chart(lxw_workbook *workbook, uint8_t chart_type);
/**
* @brief Close the Workbook object and write the XLSX file.
*
* @param workbook Pointer to a lxw_workbook instance.
*
* @return A #lxw_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_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
*
*/
lxw_error workbook_close(lxw_workbook *workbook);
/**
* @brief Set the document properties such as Title, Author etc.
*
* @param workbook Pointer to a lxw_workbook instance.
* @param properties Document properties to set.
*
* @return A #lxw_error.
*
* The `%workbook_set_properties` function can be used to set the document
* properties of the Excel file created by `libxlsxwriter`. These properties
* are visible when you use the `Office Button -> Prepare -> Properties`
* option in Excel and are also available to external applications that read
* or index windows files.
*
* The properties that can be set are:
*
* - `title`
* - `subject`
* - `author`
* - `manager`
* - `company`
* - `category`
* - `keywords`
* - `comments`
* - `hyperlink_base`
* - `created`
*
* The properties are specified via a `lxw_doc_properties` struct. All the
* fields are all optional. An example of how to create and pass the
* properties is:
*
* @code
* // Create a properties structure and set some of the fields.
* lxw_doc_properties properties = {
* .title = "This is an example spreadsheet",
* .subject = "With document properties",
* .author = "John McNamara",
* .manager = "Dr. Heinz Doofenshmirtz",
* .company = "of Wolves",
* .category = "Example spreadsheets",
* .keywords = "Sample, Example, Properties",
* .comments = "Created with libxlsxwriter",
* .status = "Quo",
* };
*
* // Set the properties in the workbook.
* workbook_set_properties(workbook, &properties);
* @endcode
*
* @image html doc_properties.png
*
* The `created` parameter sets the file creation date/time shown in
* Excel. This defaults to the current time and date if set to 0. If you wish
* to create files that are binary equivalent (for the same input data) then
* you should set this creation date/time to a known value using a `time_t`
* value.
*
*/
lxw_error workbook_set_properties(lxw_workbook *workbook,
lxw_doc_properties *properties);
/**
* @brief Set a custom document text property.
*
* @param workbook Pointer to a lxw_workbook instance.
* @param name The name of the custom property.
* @param value The value of the custom property.
*
* @return A #lxw_error.
*
* The `%workbook_set_custom_property_string()` function can be used to set one
* or more custom document text properties not covered by the standard
* properties in the `workbook_set_properties()` function above.
*
* For example:
*
* @code
* workbook_set_custom_property_string(workbook, "Checked by", "Eve");
* @endcode
*
* @image html custom_properties.png
*
* There are 4 `workbook_set_custom_property_string_*()` functions for each
* of the custom property types supported by Excel:
*
* - text/string: `workbook_set_custom_property_string()`
* - number: `workbook_set_custom_property_number()`
* - datetime: `workbook_set_custom_property_datetime()`
* - boolean: `workbook_set_custom_property_boolean()`
*
* **Note**: the name and value parameters are limited to 255 characters
* by Excel.
*
*/
lxw_error workbook_set_custom_property_string(lxw_workbook *workbook,
const char *name,
const char *value);
/**
* @brief Set a custom document number property.
*
* @param workbook Pointer to a lxw_workbook instance.
* @param name The name of the custom property.
* @param value The value of the custom property.
*
* @return A #lxw_error.
*
* Set a custom document number property.
* See `workbook_set_custom_property_string()` above for details.
*
* @code
* workbook_set_custom_property_number(workbook, "Document number", 12345);
* @endcode
*/
lxw_error workbook_set_custom_property_number(lxw_workbook *workbook,
const char *name, double value);
/* Undocumented since the user can use workbook_set_custom_property_number().
* Only implemented for file format completeness and testing.
*/
lxw_error workbook_set_custom_property_integer(lxw_workbook *workbook,
const char *name,
int32_t value);
/**
* @brief Set a custom document boolean property.
*
* @param workbook Pointer to a lxw_workbook instance.
* @param name The name of the custom property.
* @param value The value of the custom property.
*
* @return A #lxw_error.
*
* Set a custom document boolean property.
* See `workbook_set_custom_property_string()` above for details.
*
* @code
* workbook_set_custom_property_boolean(workbook, "Has Review", 1);
* @endcode
*/
lxw_error workbook_set_custom_property_boolean(lxw_workbook *workbook,
const char *name,
uint8_t value);
/**
* @brief Set a custom document date or time property.
*
* @param workbook Pointer to a lxw_workbook instance.
* @param name The name of the custom property.
* @param datetime The value of the custom property.
*
* @return A #lxw_error.
*
* Set a custom date or time number property.
* See `workbook_set_custom_property_string()` above for details.
*
* @code
* lxw_datetime datetime = {2016, 12, 1, 11, 55, 0.0};
*
* workbook_set_custom_property_datetime(workbook, "Date completed", &datetime);
* @endcode
*/
lxw_error workbook_set_custom_property_datetime(lxw_workbook *workbook,
const char *name,
lxw_datetime *datetime);
/**
* @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 A #lxw_error.
*
* This function 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).
*
*/
lxw_error workbook_define_name(lxw_workbook *workbook, const char *name,
const char *formula);
/**
* @brief Get the default URL format used with `worksheet_write_url()`.
*
* @param workbook Pointer to a lxw_workbook instance.
* @return A lxw_format instance that has hyperlink properties set.
*
* This function returns a lxw_format instance that is used for the default
* blue underline hyperlink in the `worksheet_write_url()` function when a
* format isn't specified:
*
* @code
* lxw_format *url_format = workbook_get_default_url_format(workbook);
* @endcode
*
* The format is the hyperlink style defined by Excel for the default theme.
* This format is only ever required when overwriting a string URL with
* data of a different type. See the example below.
*/
lxw_format *workbook_get_default_url_format(lxw_workbook *workbook);
/**
* @brief Get a worksheet object from its name.
*
* @param workbook Pointer to a lxw_workbook instance.
* @param name Worksheet name.
*
* @return A lxw_worksheet object.
*
* This function returns a lxw_worksheet object reference based on its name:
*
* @code
* worksheet = workbook_get_worksheet_by_name(workbook, "Sheet1");
* @endcode
*
*/
lxw_worksheet *workbook_get_worksheet_by_name(lxw_workbook *workbook,
const char *name);
/**
* @brief Get a chartsheet object from its name.
*
* @param workbook Pointer to a lxw_workbook instance.
* @param name chartsheet name.
*
* @return A lxw_chartsheet object.
*
* This function returns a lxw_chartsheet object reference based on its name:
*
* @code
* chartsheet = workbook_get_chartsheet_by_name(workbook, "Chart1");
* @endcode
*
*/
lxw_chartsheet *workbook_get_chartsheet_by_name(lxw_workbook *workbook,
const char *name);
/**
* @brief Validate a worksheet or chartsheet name.
*
* @param workbook Pointer to a lxw_workbook instance.
* @param sheetname Sheet name to validate.
*
* @return A #lxw_error.
*
* This function is used to validate a worksheet or chartsheet name according
* to the rules used by Excel:
*
* - The name is less than or equal to 31 UTF-8 characters.
* - The name doesn't contain any of the characters: ` [ ] : * ? / \ `
* - The name doesn't start or end with an apostrophe.
* - The name isn't already in use. (Case insensitive, see the note below).
*
* @code
* lxw_error err = workbook_validate_sheet_name(workbook, "Foglio");
* @endcode
*
* This function is called by `workbook_add_worksheet()` and
* `workbook_add_chartsheet()` but it can be explicitly called by the user
* beforehand to ensure that the sheet name is valid.
*
* @note You should also avoid using the worksheet name "History" (case
* insensitive) which is reserved in English language versions of
* Excel. Non-English versions may have restrictions on the equivalent word.
*
* @note This function does an ASCII lowercase string comparison to determine
* if the sheet name is already in use. It doesn't take UTF-8 characters into
* account. Thus it would flag "Café" and "café" as a duplicate (just like
* Excel) but it wouldn't catch "CAFÉ". If you need a full UTF-8 case
* insensitive check you should use a third party library to implement it.
*
*/
lxw_error workbook_validate_sheet_name(lxw_workbook *workbook,
const char *sheetname);
/**
* @brief Add a vbaProject binary to the Excel workbook.
*
* @param workbook Pointer to a lxw_workbook instance.
* @param filename The path/filename of the vbaProject.bin file.
*
* The `%workbook_add_vba_project()` function can be used to add macros or
* functions to a workbook using a binary VBA project file that has been
* extracted from an existing Excel xlsm file:
*
* @code
* workbook_add_vba_project(workbook, "vbaProject.bin");
* @endcode
*
* Only one `vbaProject.bin` file can be added per workbook. The name doesn't
* have to be `vbaProject.bin`. Any suitable path/name for an existing VBA bin
* file will do.
*
* Once you add a VBA project had been add to an libxlsxwriter workbook you
* should ensure that the file extension is `.xlsm` to prevent Excel from
* giving a warning when it opens the file:
*
* @code
* lxw_workbook *workbook = new_workbook("macro.xlsm");
* @endcode
*
* See also @ref working_with_macros
*
* @return A #lxw_error.
*/
lxw_error workbook_add_vba_project(lxw_workbook *workbook,
const char *filename);
/**
* @brief Add a vbaProject binary and a vbaProjectSignature binary to the Excel
* workbook.
*
* @param workbook Pointer to a lxw_workbook instance.
* @param vba_project The path/filename of the vbaProject.bin file.
* @param signature The path/filename of the vbaProjectSignature.bin file.
*
* The `%workbook_add_signed_vba_project()` function can be used to add digitally
* signed macros or functions to a workbook. The function adds a binary VBA project
* file and a binary VBA project signature file that have been extracted from an
* existing Excel xlsm file with digitally signed macros:
*
* @code
* workbook_add_signed_vba_project(workbook, "vbaProject.bin", "vbaProjectSignature.bin");
* @endcode
*
* Only one `vbaProject.bin` file can be added per workbook. The name doesn't
* have to be `vbaProject.bin`. Any suitable path/name for an existing VBA bin
* file will do. The same applies for `vbaProjectSignature.bin`.
*
* See also @ref working_with_macros
*
* @return A #lxw_error.
*/
lxw_error workbook_add_signed_vba_project(lxw_workbook *workbook,
const char *vba_project,
const char *signature);
/**
* @brief Set the VBA name for the workbook.
*
* @param workbook Pointer to a lxw_workbook instance.
* @param name Name of the workbook used by VBA.
*
* The `workbook_set_vba_name()` function can be used to set the VBA name for
* the workbook. This is sometimes required when a vbaProject macro included
* via `workbook_add_vba_project()` refers to the workbook by a name other
* than `ThisWorkbook`.
*
* @code
* workbook_set_vba_name(workbook, "MyWorkbook");
* @endcode
*
* If an Excel VBA name for the workbook isn't specified then libxlsxwriter
* will use `ThisWorkbook`.
*
* See also @ref working_with_macros
*
* @return A #lxw_error.
*/
lxw_error workbook_set_vba_name(lxw_workbook *workbook, const char *name);
/**
* @brief Add a recommendation to open the file in "read-only" mode.
*
* @param workbook Pointer to a lxw_workbook instance.
*
* This function can be used to set the Excel "Read-only Recommended" option
* that is available when saving a file. This presents the user of the file
* with an option to open it in "read-only" mode. This means that any changes
* to the file can't be saved back to the same file and must be saved to a new
* file. It can be set as follows:
*
* @code
* workbook_read_only_recommended(workbook);
* @endcode
*
* Which will raise a dialog like the following when opening the file:
*
* @image html read_only.png
*/
void workbook_read_only_recommended(lxw_workbook *workbook);
void lxw_workbook_free(lxw_workbook *workbook);
void lxw_workbook_assemble_xml_file(lxw_workbook *workbook);
void lxw_workbook_set_default_xf_indices(lxw_workbook *workbook);
void workbook_unset_default_url_format(lxw_workbook *workbook);
/* Declarations required for unit testing. */
#ifdef TESTING
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 lxw_error _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__ */
writexl/src/include/xlsxwriter/chart.h 0000644 0001762 0000144 00000345423 14747162622 017715 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* chart - A libxlsxwriter library for creating Excel XLSX chart files.
*
*/
/**
* @page chart_page The Chart object
*
* The Chart object represents an Excel chart. It provides functions for
* adding data series to the chart and for configuring the chart.
*
* See @ref chart.h for full details of the functionality.
*
* @file chart.h
*
* @brief Functions related to adding data to and configuring a chart.
*
* The Chart object represents an Excel chart. It provides functions for
* adding data series to the chart and for configuring the chart.
*
* A Chart object isn't created directly. Instead a chart is created by
* calling the `workbook_add_chart()` function from a Workbook object. For
* example:
*
* @code
*
* #include "xlsxwriter.h"
*
* int main() {
*
* lxw_workbook *workbook = new_workbook("chart.xlsx");
* lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
*
* // User function to add data to worksheet, not shown here.
* write_worksheet_data(worksheet);
*
* // Create a chart object.
* lxw_chart *chart = workbook_add_chart(workbook, LXW_CHART_COLUMN);
*
* // In the simplest case we just add some value data series.
* // The NULL categories will default to 1 to 5 like in Excel.
* chart_add_series(chart, NULL, "=Sheet1!$A$1:$A$5");
* chart_add_series(chart, NULL, "=Sheet1!$B$1:$B$5");
* chart_add_series(chart, NULL, "=Sheet1!$C$1:$C$5");
*
* // Insert the chart into the worksheet
* worksheet_insert_chart(worksheet, CELL("B7"), chart);
*
* return workbook_close(workbook);
* }
*
* @endcode
*
* The chart in the worksheet will look like this:
* @image html chart_simple.png
*
* The basic procedure for adding a chart to a worksheet is:
*
* 1. Create the chart with `workbook_add_chart()`.
* 2. Add one or more data series to the chart which refers to data in the
* workbook using `chart_add_series()`.
* 3. Configure the chart with the other available functions shown below.
* 4. Insert the chart into a worksheet using `worksheet_insert_chart()`.
*
*/
#ifndef __LXW_CHART_H__
#define __LXW_CHART_H__
#include
#include
#include "common.h"
#include "format.h"
STAILQ_HEAD(lxw_chart_series_list, lxw_chart_series);
STAILQ_HEAD(lxw_series_data_points, lxw_series_data_point);
#define LXW_CHART_NUM_FORMAT_LEN 128
#define LXW_CHART_DEFAULT_GAP 501
/**
* @brief Available chart types.
*/
typedef enum lxw_chart_type {
/** None. */
LXW_CHART_NONE = 0,
/** Area chart. */
LXW_CHART_AREA,
/** Area chart - stacked. */
LXW_CHART_AREA_STACKED,
/** Area chart - percentage stacked. */
LXW_CHART_AREA_STACKED_PERCENT,
/** Bar chart. */
LXW_CHART_BAR,
/** Bar chart - stacked. */
LXW_CHART_BAR_STACKED,
/** Bar chart - percentage stacked. */
LXW_CHART_BAR_STACKED_PERCENT,
/** Column chart. */
LXW_CHART_COLUMN,
/** Column chart - stacked. */
LXW_CHART_COLUMN_STACKED,
/** Column chart - percentage stacked. */
LXW_CHART_COLUMN_STACKED_PERCENT,
/** Doughnut chart. */
LXW_CHART_DOUGHNUT,
/** Line chart. */
LXW_CHART_LINE,
/** Line chart - stacked. */
LXW_CHART_LINE_STACKED,
/** Line chart - percentage stacked. */
LXW_CHART_LINE_STACKED_PERCENT,
/** Pie chart. */
LXW_CHART_PIE,
/** Scatter chart. */
LXW_CHART_SCATTER,
/** Scatter chart - straight. */
LXW_CHART_SCATTER_STRAIGHT,
/** Scatter chart - straight with markers. */
LXW_CHART_SCATTER_STRAIGHT_WITH_MARKERS,
/** Scatter chart - smooth. */
LXW_CHART_SCATTER_SMOOTH,
/** Scatter chart - smooth with markers. */
LXW_CHART_SCATTER_SMOOTH_WITH_MARKERS,
/** Radar chart. */
LXW_CHART_RADAR,
/** Radar chart - with markers. */
LXW_CHART_RADAR_WITH_MARKERS,
/** Radar chart - filled. */
LXW_CHART_RADAR_FILLED
} lxw_chart_type;
/**
* @brief Chart legend positions.
*/
typedef enum lxw_chart_legend_position {
/** No chart legend. */
LXW_CHART_LEGEND_NONE = 0,
/** Chart legend positioned at right side. */
LXW_CHART_LEGEND_RIGHT,
/** Chart legend positioned at left side. */
LXW_CHART_LEGEND_LEFT,
/** Chart legend positioned at top. */
LXW_CHART_LEGEND_TOP,
/** Chart legend positioned at bottom. */
LXW_CHART_LEGEND_BOTTOM,
/** Chart legend positioned at top right. */
LXW_CHART_LEGEND_TOP_RIGHT,
/** Chart legend overlaid at right side. */
LXW_CHART_LEGEND_OVERLAY_RIGHT,
/** Chart legend overlaid at left side. */
LXW_CHART_LEGEND_OVERLAY_LEFT,
/** Chart legend overlaid at top right. */
LXW_CHART_LEGEND_OVERLAY_TOP_RIGHT
} lxw_chart_legend_position;
/**
* @brief Chart line dash types.
*
* The dash types are shown in the order that they appear in the Excel dialog.
* See @ref chart_lines.
*/
typedef enum lxw_chart_line_dash_type {
/** Solid. */
LXW_CHART_LINE_DASH_SOLID = 0,
/** Round Dot. */
LXW_CHART_LINE_DASH_ROUND_DOT,
/** Square Dot. */
LXW_CHART_LINE_DASH_SQUARE_DOT,
/** Dash. */
LXW_CHART_LINE_DASH_DASH,
/** Dash Dot. */
LXW_CHART_LINE_DASH_DASH_DOT,
/** Long Dash. */
LXW_CHART_LINE_DASH_LONG_DASH,
/** Long Dash Dot. */
LXW_CHART_LINE_DASH_LONG_DASH_DOT,
/** Long Dash Dot Dot. */
LXW_CHART_LINE_DASH_LONG_DASH_DOT_DOT,
/* These aren't available in the dialog but are used by Excel. */
LXW_CHART_LINE_DASH_DOT,
LXW_CHART_LINE_DASH_SYSTEM_DASH_DOT,
LXW_CHART_LINE_DASH_SYSTEM_DASH_DOT_DOT
} lxw_chart_line_dash_type;
/**
* @brief Chart marker types.
*/
typedef enum lxw_chart_marker_type {
/** Automatic, series default, marker type. */
LXW_CHART_MARKER_AUTOMATIC,
/** No marker type. */
LXW_CHART_MARKER_NONE,
/** Square marker type. */
LXW_CHART_MARKER_SQUARE,
/** Diamond marker type. */
LXW_CHART_MARKER_DIAMOND,
/** Triangle marker type. */
LXW_CHART_MARKER_TRIANGLE,
/** X shape marker type. */
LXW_CHART_MARKER_X,
/** Star marker type. */
LXW_CHART_MARKER_STAR,
/** Short dash marker type. */
LXW_CHART_MARKER_SHORT_DASH,
/** Long dash marker type. */
LXW_CHART_MARKER_LONG_DASH,
/** Circle marker type. */
LXW_CHART_MARKER_CIRCLE,
/** Plus (+) marker type. */
LXW_CHART_MARKER_PLUS
} lxw_chart_marker_type;
/**
* @brief Chart pattern types.
*/
typedef enum lxw_chart_pattern_type {
/** None pattern. */
LXW_CHART_PATTERN_NONE,
/** 5 Percent pattern. */
LXW_CHART_PATTERN_PERCENT_5,
/** 10 Percent pattern. */
LXW_CHART_PATTERN_PERCENT_10,
/** 20 Percent pattern. */
LXW_CHART_PATTERN_PERCENT_20,
/** 25 Percent pattern. */
LXW_CHART_PATTERN_PERCENT_25,
/** 30 Percent pattern. */
LXW_CHART_PATTERN_PERCENT_30,
/** 40 Percent pattern. */
LXW_CHART_PATTERN_PERCENT_40,
/** 50 Percent pattern. */
LXW_CHART_PATTERN_PERCENT_50,
/** 60 Percent pattern. */
LXW_CHART_PATTERN_PERCENT_60,
/** 70 Percent pattern. */
LXW_CHART_PATTERN_PERCENT_70,
/** 75 Percent pattern. */
LXW_CHART_PATTERN_PERCENT_75,
/** 80 Percent pattern. */
LXW_CHART_PATTERN_PERCENT_80,
/** 90 Percent pattern. */
LXW_CHART_PATTERN_PERCENT_90,
/** Light downward diagonal pattern. */
LXW_CHART_PATTERN_LIGHT_DOWNWARD_DIAGONAL,
/** Light upward diagonal pattern. */
LXW_CHART_PATTERN_LIGHT_UPWARD_DIAGONAL,
/** Dark downward diagonal pattern. */
LXW_CHART_PATTERN_DARK_DOWNWARD_DIAGONAL,
/** Dark upward diagonal pattern. */
LXW_CHART_PATTERN_DARK_UPWARD_DIAGONAL,
/** Wide downward diagonal pattern. */
LXW_CHART_PATTERN_WIDE_DOWNWARD_DIAGONAL,
/** Wide upward diagonal pattern. */
LXW_CHART_PATTERN_WIDE_UPWARD_DIAGONAL,
/** Light vertical pattern. */
LXW_CHART_PATTERN_LIGHT_VERTICAL,
/** Light horizontal pattern. */
LXW_CHART_PATTERN_LIGHT_HORIZONTAL,
/** Narrow vertical pattern. */
LXW_CHART_PATTERN_NARROW_VERTICAL,
/** Narrow horizontal pattern. */
LXW_CHART_PATTERN_NARROW_HORIZONTAL,
/** Dark vertical pattern. */
LXW_CHART_PATTERN_DARK_VERTICAL,
/** Dark horizontal pattern. */
LXW_CHART_PATTERN_DARK_HORIZONTAL,
/** Dashed downward diagonal pattern. */
LXW_CHART_PATTERN_DASHED_DOWNWARD_DIAGONAL,
/** Dashed upward diagonal pattern. */
LXW_CHART_PATTERN_DASHED_UPWARD_DIAGONAL,
/** Dashed horizontal pattern. */
LXW_CHART_PATTERN_DASHED_HORIZONTAL,
/** Dashed vertical pattern. */
LXW_CHART_PATTERN_DASHED_VERTICAL,
/** Small confetti pattern. */
LXW_CHART_PATTERN_SMALL_CONFETTI,
/** Large confetti pattern. */
LXW_CHART_PATTERN_LARGE_CONFETTI,
/** Zigzag pattern. */
LXW_CHART_PATTERN_ZIGZAG,
/** Wave pattern. */
LXW_CHART_PATTERN_WAVE,
/** Diagonal brick pattern. */
LXW_CHART_PATTERN_DIAGONAL_BRICK,
/** Horizontal brick pattern. */
LXW_CHART_PATTERN_HORIZONTAL_BRICK,
/** Weave pattern. */
LXW_CHART_PATTERN_WEAVE,
/** Plaid pattern. */
LXW_CHART_PATTERN_PLAID,
/** Divot pattern. */
LXW_CHART_PATTERN_DIVOT,
/** Dotted grid pattern. */
LXW_CHART_PATTERN_DOTTED_GRID,
/** Dotted diamond pattern. */
LXW_CHART_PATTERN_DOTTED_DIAMOND,
/** Shingle pattern. */
LXW_CHART_PATTERN_SHINGLE,
/** Trellis pattern. */
LXW_CHART_PATTERN_TRELLIS,
/** Sphere pattern. */
LXW_CHART_PATTERN_SPHERE,
/** Small grid pattern. */
LXW_CHART_PATTERN_SMALL_GRID,
/** Large grid pattern. */
LXW_CHART_PATTERN_LARGE_GRID,
/** Small check pattern. */
LXW_CHART_PATTERN_SMALL_CHECK,
/** Large check pattern. */
LXW_CHART_PATTERN_LARGE_CHECK,
/** Outlined diamond pattern. */
LXW_CHART_PATTERN_OUTLINED_DIAMOND,
/** Solid diamond pattern. */
LXW_CHART_PATTERN_SOLID_DIAMOND
} lxw_chart_pattern_type;
/**
* @brief Chart data label positions.
*/
typedef enum lxw_chart_label_position {
/** Series data label position: default position. */
LXW_CHART_LABEL_POSITION_DEFAULT,
/** Series data label position: center. */
LXW_CHART_LABEL_POSITION_CENTER,
/** Series data label position: right. */
LXW_CHART_LABEL_POSITION_RIGHT,
/** Series data label position: left. */
LXW_CHART_LABEL_POSITION_LEFT,
/** Series data label position: above. */
LXW_CHART_LABEL_POSITION_ABOVE,
/** Series data label position: below. */
LXW_CHART_LABEL_POSITION_BELOW,
/** Series data label position: inside base. */
LXW_CHART_LABEL_POSITION_INSIDE_BASE,
/** Series data label position: inside end. */
LXW_CHART_LABEL_POSITION_INSIDE_END,
/** Series data label position: outside end. */
LXW_CHART_LABEL_POSITION_OUTSIDE_END,
/** Series data label position: best fit. */
LXW_CHART_LABEL_POSITION_BEST_FIT
} lxw_chart_label_position;
/**
* @brief Chart data label separator.
*/
typedef enum lxw_chart_label_separator {
/** Series data label separator: comma (the default). */
LXW_CHART_LABEL_SEPARATOR_COMMA,
/** Series data label separator: semicolon. */
LXW_CHART_LABEL_SEPARATOR_SEMICOLON,
/** Series data label separator: period. */
LXW_CHART_LABEL_SEPARATOR_PERIOD,
/** Series data label separator: newline. */
LXW_CHART_LABEL_SEPARATOR_NEWLINE,
/** Series data label separator: space. */
LXW_CHART_LABEL_SEPARATOR_SPACE
} lxw_chart_label_separator;
/**
* @brief Chart axis types.
*/
typedef enum lxw_chart_axis_type {
/** Chart X axis. */
LXW_CHART_AXIS_TYPE_X,
/** Chart Y axis. */
LXW_CHART_AXIS_TYPE_Y
} lxw_chart_axis_type;
enum lxw_chart_subtype {
LXW_CHART_SUBTYPE_NONE = 0,
LXW_CHART_SUBTYPE_STACKED,
LXW_CHART_SUBTYPE_STACKED_PERCENT
};
enum lxw_chart_grouping {
LXW_GROUPING_CLUSTERED,
LXW_GROUPING_STANDARD,
LXW_GROUPING_PERCENTSTACKED,
LXW_GROUPING_STACKED
};
/**
* @brief Axis positions for category axes.
*/
typedef enum lxw_chart_axis_tick_position {
LXW_CHART_AXIS_POSITION_DEFAULT,
/** Position category axis on tick marks. */
LXW_CHART_AXIS_POSITION_ON_TICK,
/** Position category axis between tick marks. */
LXW_CHART_AXIS_POSITION_BETWEEN
} lxw_chart_axis_tick_position;
/**
* @brief Axis label positions.
*/
typedef enum lxw_chart_axis_label_position {
/** Position the axis labels next to the axis. The default. */
LXW_CHART_AXIS_LABEL_POSITION_NEXT_TO,
/** Position the axis labels at the top of the chart, for horizontal
* axes, or to the right for vertical axes.*/
LXW_CHART_AXIS_LABEL_POSITION_HIGH,
/** Position the axis labels at the bottom of the chart, for horizontal
* axes, or to the left for vertical axes.*/
LXW_CHART_AXIS_LABEL_POSITION_LOW,
/** Turn off the the axis labels. */
LXW_CHART_AXIS_LABEL_POSITION_NONE
} lxw_chart_axis_label_position;
/**
* @brief Axis label alignments.
*/
typedef enum lxw_chart_axis_label_alignment {
/** Chart axis label alignment: center. */
LXW_CHART_AXIS_LABEL_ALIGN_CENTER,
/** Chart axis label alignment: left. */
LXW_CHART_AXIS_LABEL_ALIGN_LEFT,
/** Chart axis label alignment: right. */
LXW_CHART_AXIS_LABEL_ALIGN_RIGHT
} lxw_chart_axis_label_alignment;
/**
* @brief Display units for chart value axis.
*/
typedef enum lxw_chart_axis_display_unit {
/** Axis display units: None. The default. */
LXW_CHART_AXIS_UNITS_NONE,
/** Axis display units: Hundreds. */
LXW_CHART_AXIS_UNITS_HUNDREDS,
/** Axis display units: Thousands. */
LXW_CHART_AXIS_UNITS_THOUSANDS,
/** Axis display units: Ten thousands. */
LXW_CHART_AXIS_UNITS_TEN_THOUSANDS,
/** Axis display units: Hundred thousands. */
LXW_CHART_AXIS_UNITS_HUNDRED_THOUSANDS,
/** Axis display units: Millions. */
LXW_CHART_AXIS_UNITS_MILLIONS,
/** Axis display units: Ten millions. */
LXW_CHART_AXIS_UNITS_TEN_MILLIONS,
/** Axis display units: Hundred millions. */
LXW_CHART_AXIS_UNITS_HUNDRED_MILLIONS,
/** Axis display units: Billions. */
LXW_CHART_AXIS_UNITS_BILLIONS,
/** Axis display units: Trillions. */
LXW_CHART_AXIS_UNITS_TRILLIONS
} lxw_chart_axis_display_unit;
/**
* @brief Tick mark types for an axis.
*/
typedef enum lxw_chart_axis_tick_mark {
/** Default tick mark for the chart axis. Usually outside. */
LXW_CHART_AXIS_TICK_MARK_DEFAULT,
/** No tick mark for the axis. */
LXW_CHART_AXIS_TICK_MARK_NONE,
/** Tick mark inside the axis only. */
LXW_CHART_AXIS_TICK_MARK_INSIDE,
/** Tick mark outside the axis only. */
LXW_CHART_AXIS_TICK_MARK_OUTSIDE,
/** Tick mark inside and outside the axis. */
LXW_CHART_AXIS_TICK_MARK_CROSSING
} lxw_chart_tick_mark;
typedef struct lxw_series_range {
char *formula;
char *sheetname;
lxw_row_t first_row;
lxw_row_t last_row;
lxw_col_t first_col;
lxw_col_t last_col;
uint8_t ignore_cache;
uint8_t has_string_cache;
uint16_t num_data_points;
struct lxw_series_data_points *data_cache;
} lxw_series_range;
typedef struct lxw_series_data_point {
uint8_t is_string;
double number;
char *string;
uint8_t no_data;
STAILQ_ENTRY (lxw_series_data_point) list_pointers;
} lxw_series_data_point;
/**
* @brief Struct to represent a chart line.
*
* See @ref chart_lines.
*/
typedef struct lxw_chart_line {
/** The chart font color. See @ref working_with_colors. */
lxw_color_t color;
/** Turn off/hide line. Set to 0 or 1.*/
uint8_t none;
/** Width of the line in increments of 0.25. Default is 2.25. */
float width;
/** The line dash type. See #lxw_chart_line_dash_type. */
uint8_t dash_type;
/** Set the transparency of the line. 0 - 100. Default 0. */
uint8_t transparency;
} lxw_chart_line;
/**
* @brief Struct to represent a chart fill.
*
* See @ref chart_fills.
*/
typedef struct lxw_chart_fill {
/** The chart font color. See @ref working_with_colors. */
lxw_color_t color;
/** Turn off/hide line. Set to 0 or 1.*/
uint8_t none;
/** Set the transparency of the fill. 0 - 100. Default 0. */
uint8_t transparency;
} lxw_chart_fill;
/**
* @brief Struct to represent a chart pattern.
*
* See @ref chart_patterns.
*/
typedef struct lxw_chart_pattern {
/** The pattern foreground color. See @ref working_with_colors. */
lxw_color_t fg_color;
/** The pattern background color. See @ref working_with_colors. */
lxw_color_t bg_color;
/** The pattern type. See #lxw_chart_pattern_type. */
uint8_t type;
} lxw_chart_pattern;
/**
* @brief Struct to represent a chart font.
*
* See @ref chart_fonts.
*/
typedef struct lxw_chart_font {
/** The chart font name, such as "Arial" or "Calibri". */
const char *name;
/** The chart font size. The default is 11. */
double size;
/** The chart font bold property. Set to 0 or 1. */
uint8_t bold;
/** The chart font italic property. Set to 0 or 1. */
uint8_t italic;
/** The chart font underline property. Set to 0 or 1. */
uint8_t underline;
/** The chart font rotation property. Range: -90 to 90, and 270, 271 and 360:
*
* - The angles -90 to 90 are the normal range shown in the Excel user interface.
* - The angle 270 gives a stacked (top to bottom) alignment.
* - The angle 271 gives a stacked alignment for East Asian fonts.
* - The angle 360 gives an explicit angle of 0 to override the y axis default.
* */
int32_t rotation;
/** The chart font color. See @ref working_with_colors. */
lxw_color_t color;
/** The chart font pitch family property. Rarely required, set to 0. */
uint8_t pitch_family;
/** The chart font character set property. Rarely required, set to 0. */
uint8_t charset;
/** The chart font baseline property. Rarely required, set to 0. */
int8_t baseline;
} lxw_chart_font;
typedef struct lxw_chart_marker {
uint8_t type;
uint8_t size;
lxw_chart_line *line;
lxw_chart_fill *fill;
lxw_chart_pattern *pattern;
} lxw_chart_marker;
typedef struct lxw_chart_legend {
lxw_chart_font *font;
uint8_t position;
} lxw_chart_legend;
typedef struct lxw_chart_title {
char *name;
lxw_row_t row;
lxw_col_t col;
lxw_chart_font *font;
uint8_t off;
uint8_t is_horizontal;
uint8_t ignore_cache;
/* We use a range to hold the title formula properties even though it
* will only have 1 point in order to re-use similar functions.*/
lxw_series_range *range;
struct lxw_series_data_point data_point;
} lxw_chart_title;
/**
* @brief Struct to represent an Excel chart data point.
*
* The lxw_chart_point used to set the line, fill and pattern of one or more
* points in a chart data series. See @ref chart_points.
*/
typedef struct lxw_chart_point {
/** The line/border for the chart point. See @ref chart_lines. */
lxw_chart_line *line;
/** The fill for the chart point. See @ref chart_fills. */
lxw_chart_fill *fill;
/** The pattern for the chart point. See @ref chart_patterns.*/
lxw_chart_pattern *pattern;
} lxw_chart_point;
/**
* @brief Struct to represent an Excel chart data label.
*
* The lxw_chart_data_label struct is used to represent a data label in a
* chart series so that custom properties can be set for it.
*/
typedef struct lxw_chart_data_label {
/** The string or formula value for the data label. See
* @ref chart_custom_labels. */
const char *value;
/** Option to hide/delete the data label from the chart series.
* See @ref chart_custom_labels. */
uint8_t hide;
/** The font properties for the chart data label. @ref chart_fonts. */
lxw_chart_font *font;
/** The line/border for the chart data label. See @ref chart_lines. */
lxw_chart_line *line;
/** The fill for the chart data label. See @ref chart_fills. */
lxw_chart_fill *fill;
/** The pattern for the chart data label. See @ref chart_patterns.*/
lxw_chart_pattern *pattern;
} lxw_chart_data_label;
/* Internal version of lxw_chart_data_label with more metadata. */
typedef struct lxw_chart_custom_label {
char *value;
uint8_t hide;
lxw_chart_font *font;
lxw_chart_line *line;
lxw_chart_fill *fill;
lxw_chart_pattern *pattern;
/* We use a range to hold the label formula properties even though it
* will only have 1 point in order to re-use similar functions.*/
lxw_series_range *range;
struct lxw_series_data_point data_point;
} lxw_chart_custom_label;
/**
* @brief Define how blank values are displayed in a chart.
*/
typedef enum lxw_chart_blank {
/** Show empty chart cells as gaps in the data. The default. */
LXW_CHART_BLANKS_AS_GAP,
/** Show empty chart cells as zeros. */
LXW_CHART_BLANKS_AS_ZERO,
/** Show empty chart cells as connected. Only for charts with lines. */
LXW_CHART_BLANKS_AS_CONNECTED
} lxw_chart_blank;
enum lxw_chart_position {
LXW_CHART_AXIS_RIGHT,
LXW_CHART_AXIS_LEFT,
LXW_CHART_AXIS_TOP,
LXW_CHART_AXIS_BOTTOM
};
/**
* @brief Type/amount of data series error bar.
*/
typedef enum lxw_chart_error_bar_type {
/** Error bar type: Standard error. */
LXW_CHART_ERROR_BAR_TYPE_STD_ERROR,
/** Error bar type: Fixed value. */
LXW_CHART_ERROR_BAR_TYPE_FIXED,
/** Error bar type: Percentage. */
LXW_CHART_ERROR_BAR_TYPE_PERCENTAGE,
/** Error bar type: Standard deviation(s). */
LXW_CHART_ERROR_BAR_TYPE_STD_DEV
} lxw_chart_error_bar_type;
/**
* @brief Direction for a data series error bar.
*/
typedef enum lxw_chart_error_bar_direction {
/** Error bar extends in both directions. The default. */
LXW_CHART_ERROR_BAR_DIR_BOTH,
/** Error bar extends in positive direction. */
LXW_CHART_ERROR_BAR_DIR_PLUS,
/** Error bar extends in negative direction. */
LXW_CHART_ERROR_BAR_DIR_MINUS
} lxw_chart_error_bar_direction;
/**
* @brief Direction for a data series error bar.
*/
typedef enum lxw_chart_error_bar_axis {
/** X axis error bar. */
LXW_CHART_ERROR_BAR_AXIS_X,
/** Y axis error bar. */
LXW_CHART_ERROR_BAR_AXIS_Y
} lxw_chart_error_bar_axis;
/**
* @brief End cap styles for a data series error bar.
*/
typedef enum lxw_chart_error_bar_cap {
/** Flat end cap. The default. */
LXW_CHART_ERROR_BAR_END_CAP,
/** No end cap. */
LXW_CHART_ERROR_BAR_NO_CAP
} lxw_chart_error_bar_cap;
typedef struct lxw_series_error_bars {
uint8_t type;
uint8_t direction;
uint8_t endcap;
uint8_t has_value;
uint8_t is_set;
uint8_t is_x;
uint8_t chart_group;
double value;
lxw_chart_line *line;
} lxw_series_error_bars;
/**
* @brief Series trendline/regression types.
*/
typedef enum lxw_chart_trendline_type {
/** Trendline type: Linear. */
LXW_CHART_TRENDLINE_TYPE_LINEAR,
/** Trendline type: Logarithm. */
LXW_CHART_TRENDLINE_TYPE_LOG,
/** Trendline type: Polynomial. */
LXW_CHART_TRENDLINE_TYPE_POLY,
/** Trendline type: Power. */
LXW_CHART_TRENDLINE_TYPE_POWER,
/** Trendline type: Exponential. */
LXW_CHART_TRENDLINE_TYPE_EXP,
/** Trendline type: Moving Average. */
LXW_CHART_TRENDLINE_TYPE_AVERAGE
} lxw_chart_trendline_type;
/**
* @brief Struct to represent an Excel chart data series.
*
* The lxw_chart_series is created using the chart_add_series function. It is
* used in functions that modify a chart series but the members of the struct
* aren't modified directly.
*/
typedef struct lxw_chart_series {
lxw_series_range *categories;
lxw_series_range *values;
lxw_chart_title title;
lxw_chart_line *line;
lxw_chart_fill *fill;
lxw_chart_pattern *pattern;
lxw_chart_marker *marker;
lxw_chart_point *points;
lxw_chart_custom_label *data_labels;
uint16_t point_count;
uint16_t data_label_count;
uint8_t smooth;
uint8_t invert_if_negative;
/* Data label parameters. */
uint8_t has_labels;
uint8_t show_labels_value;
uint8_t show_labels_category;
uint8_t show_labels_name;
uint8_t show_labels_leader;
uint8_t show_labels_legend;
uint8_t show_labels_percent;
uint8_t label_position;
uint8_t label_separator;
uint8_t default_label_position;
char *label_num_format;
lxw_chart_font *label_font;
lxw_chart_line *label_line;
lxw_chart_fill *label_fill;
lxw_chart_pattern *label_pattern;
lxw_series_error_bars *x_error_bars;
lxw_series_error_bars *y_error_bars;
uint8_t has_trendline;
uint8_t has_trendline_forecast;
uint8_t has_trendline_equation;
uint8_t has_trendline_r_squared;
uint8_t has_trendline_intercept;
uint8_t trendline_type;
uint8_t trendline_value;
double trendline_forward;
double trendline_backward;
uint8_t trendline_value_type;
char *trendline_name;
lxw_chart_line *trendline_line;
double trendline_intercept;
STAILQ_ENTRY (lxw_chart_series) list_pointers;
} lxw_chart_series;
/* Struct for major/minor axis gridlines. */
typedef struct lxw_chart_gridline {
uint8_t visible;
lxw_chart_line *line;
} lxw_chart_gridline;
/**
* @brief Struct to represent an Excel chart axis.
*
* The lxw_chart_axis struct is used in functions that modify a chart axis
* but the members of the struct aren't modified directly.
*/
typedef struct lxw_chart_axis {
lxw_chart_title title;
char *num_format;
char *default_num_format;
uint8_t source_linked;
uint8_t major_tick_mark;
uint8_t minor_tick_mark;
uint8_t is_horizontal;
lxw_chart_gridline major_gridlines;
lxw_chart_gridline minor_gridlines;
lxw_chart_font *num_font;
lxw_chart_line *line;
lxw_chart_fill *fill;
lxw_chart_pattern *pattern;
uint8_t is_category;
uint8_t is_date;
uint8_t is_value;
uint8_t axis_position;
uint8_t position_axis;
uint8_t label_position;
uint8_t label_align;
uint8_t hidden;
uint8_t reverse;
uint8_t has_min;
double min;
uint8_t has_max;
double max;
uint8_t has_major_unit;
double major_unit;
uint8_t has_minor_unit;
double minor_unit;
uint16_t interval_unit;
uint16_t interval_tick;
uint16_t log_base;
uint8_t display_units;
uint8_t display_units_visible;
uint8_t has_crossing;
uint8_t crossing_min;
uint8_t crossing_max;
double crossing;
} lxw_chart_axis;
/**
* @brief Struct to represent an Excel chart.
*
* The members of the lxw_chart struct aren't modified directly. Instead
* the chart properties are set by calling the functions shown in chart.h.
*/
typedef struct lxw_chart {
FILE *file;
uint8_t type;
uint8_t subtype;
uint16_t series_index;
void (*write_chart_type)(struct lxw_chart *);
void (*write_plot_area)(struct lxw_chart *);
/**
* A pointer to the chart x_axis object which can be used in functions
* that configures the X axis.
*/
lxw_chart_axis *x_axis;
/**
* A pointer to the chart y_axis object which can be used in functions
* that configures the Y axis.
*/
lxw_chart_axis *y_axis;
lxw_chart_title title;
uint32_t id;
uint32_t axis_id_1;
uint32_t axis_id_2;
uint32_t axis_id_3;
uint32_t axis_id_4;
uint8_t in_use;
uint8_t chart_group;
uint8_t cat_has_num_fmt;
uint8_t is_chartsheet;
uint8_t has_horiz_cat_axis;
uint8_t has_horiz_val_axis;
uint8_t style_id;
uint16_t rotation;
uint16_t hole_size;
uint8_t no_title;
uint8_t has_overlap;
int8_t overlap_y1;
int8_t overlap_y2;
uint16_t gap_y1;
uint16_t gap_y2;
uint8_t grouping;
uint8_t default_cross_between;
lxw_chart_legend legend;
int16_t *delete_series;
uint16_t delete_series_count;
lxw_chart_marker *default_marker;
lxw_chart_line *chartarea_line;
lxw_chart_fill *chartarea_fill;
lxw_chart_pattern *chartarea_pattern;
lxw_chart_line *plotarea_line;
lxw_chart_fill *plotarea_fill;
lxw_chart_pattern *plotarea_pattern;
uint8_t has_drop_lines;
lxw_chart_line *drop_lines_line;
uint8_t has_high_low_lines;
lxw_chart_line *high_low_lines_line;
struct lxw_chart_series_list *series_list;
uint8_t has_table;
uint8_t has_table_vertical;
uint8_t has_table_horizontal;
uint8_t has_table_outline;
uint8_t has_table_legend_keys;
lxw_chart_font *table_font;
uint8_t show_blanks_as;
uint8_t show_hidden_data;
uint8_t has_up_down_bars;
lxw_chart_line *up_bar_line;
lxw_chart_line *down_bar_line;
lxw_chart_fill *up_bar_fill;
lxw_chart_fill *down_bar_fill;
uint8_t default_label_position;
uint8_t is_protected;
STAILQ_ENTRY (lxw_chart) ordered_list_pointers;
STAILQ_ENTRY (lxw_chart) list_pointers;
} lxw_chart;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
lxw_chart *lxw_chart_new(uint8_t type);
void lxw_chart_free(lxw_chart *chart);
void lxw_chart_assemble_xml_file(lxw_chart *chart);
/**
* @brief Add a data series to a chart.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param categories The range of categories in the data series.
* @param values The range of values in the data series.
*
* @return A lxw_chart_series object pointer.
*
* In Excel a chart **series** is a collection of information that defines
* which data is plotted such as the categories and values. It is also used to
* define the formatting for the data.
*
* For an libxlsxwriter chart object the `%chart_add_series()` function is
* used to set the categories and values of the series:
*
* @code
* chart_add_series(chart, "=Sheet1!$A$2:$A$7", "=Sheet1!$C$2:$C$7");
* @endcode
*
*
* The series parameters are:
*
* - `categories`: This sets the chart category labels. The category is more
* or less the same as the X axis. In most Excel chart types the
* `categories` property is optional and the chart will just assume a
* sequential series from `1..n`:
*
* @code
* // The NULL category will default to 1 to 5 like in Excel.
* chart_add_series(chart, NULL, "Sheet1!$A$1:$A$5");
* @endcode
*
* - `values`: This is the most important property of a series and is the
* only mandatory option for every chart object. This parameter links the
* chart with the worksheet data that it displays.
*
* The `categories` and `values` should be a string formula like
* `"=Sheet1!$A$2:$A$7"` in the same way it is represented in Excel. This is
* convenient when recreating a chart from an example in Excel but it is
* trickier to generate programmatically. For these cases you can set the
* `categories` and `values` to `NULL` and use the
* `chart_series_set_categories()` and `chart_series_set_values()` functions:
*
* @code
* lxw_chart_series *series = chart_add_series(chart, NULL, NULL);
*
* // Configure the series using a syntax that is easier to define programmatically.
* chart_series_set_categories(series, "Sheet1", 1, 0, 6, 0); // "=Sheet1!$A$2:$A$7"
* chart_series_set_values( series, "Sheet1", 1, 2, 6, 2); // "=Sheet1!$C$2:$C$7"
* @endcode
*
* As shown in the previous example the return value from
* `%chart_add_series()` is a lxw_chart_series pointer. This can be used in
* other functions that configure a series.
*
*
* More than one series can be added to a chart. The series numbering and
* order in the Excel chart will be the same as the order in which they are
* added in libxlsxwriter:
*
* @code
* chart_add_series(chart, NULL, "Sheet1!$A$1:$A$5");
* chart_add_series(chart, NULL, "Sheet1!$B$1:$B$5");
* chart_add_series(chart, NULL, "Sheet1!$C$1:$C$5");
* @endcode
*
* It is also possible to specify non-contiguous ranges:
*
* @code
* chart_add_series(
* chart,
* "=(Sheet1!$A$1:$A$9,Sheet1!$A$14:$A$25)",
* "=(Sheet1!$B$1:$B$9,Sheet1!$B$14:$B$25)"
* );
* @endcode
*
*/
lxw_chart_series *chart_add_series(lxw_chart *chart,
const char *categories,
const char *values);
/**
* @brief Set a series "categories" range using row and column values.
*
* @param series A series object created via `chart_add_series()`.
* @param sheetname The name of the worksheet that contains the data range.
* @param first_row The first row of the range. (All zero indexed.)
* @param first_col The first column of the range.
* @param last_row The last row of the range.
* @param last_col The last col of the range.
*
* The `categories` and `values` of a chart data series are generally set
* using the `chart_add_series()` function and Excel range formulas like
* `"=Sheet1!$A$2:$A$7"`.
*
* The `%chart_series_set_categories()` function is an alternative method that
* is easier to generate programmatically. It requires that you set the
* `categories` and `values` parameters in `chart_add_series()`to `NULL` and
* then set them using row and column values in
* `chart_series_set_categories()` and `chart_series_set_values()`:
*
* @code
* lxw_chart_series *series = chart_add_series(chart, NULL, NULL);
*
* // Configure the series ranges programmatically.
* chart_series_set_categories(series, "Sheet1", 1, 0, 6, 0); // "=Sheet1!$A$2:$A$7"
* chart_series_set_values( series, "Sheet1", 1, 2, 6, 2); // "=Sheet1!$C$2:$C$7"
* @endcode
*
*/
void chart_series_set_categories(lxw_chart_series *series,
const char *sheetname, lxw_row_t first_row,
lxw_col_t first_col, lxw_row_t last_row,
lxw_col_t last_col);
/**
* @brief Set a series "values" range using row and column values.
*
* @param series A series object created via `chart_add_series()`.
* @param sheetname The name of the worksheet that contains the data range.
* @param first_row The first row of the range. (All zero indexed.)
* @param first_col The first column of the range.
* @param last_row The last row of the range.
* @param last_col The last col of the range.
*
* The `categories` and `values` of a chart data series are generally set
* using the `chart_add_series()` function and Excel range formulas like
* `"=Sheet1!$A$2:$A$7"`.
*
* The `%chart_series_set_values()` function is an alternative method that is
* easier to generate programmatically. See the documentation for
* `chart_series_set_categories()` above.
*/
void chart_series_set_values(lxw_chart_series *series, const char *sheetname,
lxw_row_t first_row, lxw_col_t first_col,
lxw_row_t last_row, lxw_col_t last_col);
/**
* @brief Set the name of a chart series range.
*
* @param series A series object created via `chart_add_series()`.
* @param name The series name.
*
* The `%chart_series_set_name` function is used to set the name for a chart
* data series. The series name in Excel is displayed in the chart legend and
* in the formula bar. The name property is optional and if it isn't supplied
* it will default to `Series 1..n`.
*
* The function applies to a #lxw_chart_series object created using
* `chart_add_series()`:
*
* @code
* lxw_chart_series *series = chart_add_series(chart, NULL, "=Sheet1!$B$2:$B$7");
*
* chart_series_set_name(series, "Quarterly budget data");
* @endcode
*
* The name parameter can also be a formula such as `=Sheet1!$A$1` to point to
* a cell in the workbook that contains the name:
*
* @code
* lxw_chart_series *series = chart_add_series(chart, NULL, "=Sheet1!$B$2:$B$7");
*
* chart_series_set_name(series, "=Sheet1!$B$1");
* @endcode
*
* See also the `chart_series_set_name_range()` function to see how to set the
* name formula programmatically.
*/
void chart_series_set_name(lxw_chart_series *series, const char *name);
/**
* @brief Set a series name formula using row and column values.
*
* @param series A series object created via `chart_add_series()`.
* @param sheetname The name of the worksheet that contains the cell range.
* @param row The zero indexed row number of the range.
* @param col The zero indexed column number of the range.
*
* The `%chart_series_set_name_range()` function can be used to set a series
* name range and is an alternative to using `chart_series_set_name()` and a
* string formula:
*
* @code
* lxw_chart_series *series = chart_add_series(chart, NULL, "=Sheet1!$B$2:$B$7");
*
* chart_series_set_name_range(series, "Sheet1", 0, 2); // "=Sheet1!$C$1"
* @endcode
*/
void chart_series_set_name_range(lxw_chart_series *series,
const char *sheetname, lxw_row_t row,
lxw_col_t col);
/**
* @brief Set the line properties for a chart series.
*
* @param series A series object created via `chart_add_series()`.
* @param line A #lxw_chart_line struct.
*
* Set the line/border properties of a chart series:
*
* @code
* lxw_chart_line line = {.color = LXW_COLOR_RED};
*
* chart_series_set_line(series1, &line);
* chart_series_set_line(series2, &line);
* chart_series_set_line(series3, &line);
* @endcode
*
* @image html chart_series_set_line.png
*
* For more information see @ref chart_lines.
*/
void chart_series_set_line(lxw_chart_series *series, lxw_chart_line *line);
/**
* @brief Set the fill properties for a chart series.
*
* @param series A series object created via `chart_add_series()`.
* @param fill A #lxw_chart_fill struct.
*
* Set the fill properties of a chart series:
*
* @code
* lxw_chart_fill fill1 = {.color = LXW_COLOR_RED};
* lxw_chart_fill fill2 = {.color = LXW_COLOR_YELLOW};
* lxw_chart_fill fill3 = {.color = LXW_COLOR_GREEN};
*
* chart_series_set_fill(series1, &fill1);
* chart_series_set_fill(series2, &fill2);
* chart_series_set_fill(series3, &fill3);
* @endcode
*
* @image html chart_series_set_fill.png
*
* For more information see @ref chart_fills.
*/
void chart_series_set_fill(lxw_chart_series *series, lxw_chart_fill *fill);
/**
* @brief Invert the fill color for negative series values.
*
* @param series A series object created via `chart_add_series()`.
*
* Invert the fill color for negative values. Usually only applicable to
* column and bar charts.
*
* @code
* chart_series_set_invert_if_negative(series);
* @endcode
*
*/
void chart_series_set_invert_if_negative(lxw_chart_series *series);
/**
* @brief Set the pattern properties for a chart series.
*
* @param series A series object created via `chart_add_series()`.
* @param pattern A #lxw_chart_pattern struct.
*
* Set the pattern properties of a chart series:
*
* @code
* lxw_chart_pattern pattern1 = {.type = LXW_CHART_PATTERN_SHINGLE,
* .fg_color = 0x804000,
* .bg_color = 0XC68C53};
*
* lxw_chart_pattern pattern2 = {.type = LXW_CHART_PATTERN_HORIZONTAL_BRICK,
* .fg_color = 0XB30000,
* .bg_color = 0XFF6666};
*
* chart_series_set_pattern(series1, &pattern1);
* chart_series_set_pattern(series2, &pattern2);
*
* @endcode
*
* @image html chart_pattern.png
*
* For more information see #lxw_chart_pattern_type and @ref chart_patterns.
*/
void chart_series_set_pattern(lxw_chart_series *series,
lxw_chart_pattern *pattern);
/**
* @brief Set the data marker type for a series.
*
* @param series A series object created via `chart_add_series()`.
* @param type The marker type, see #lxw_chart_marker_type.
*
* In Excel a chart marker is used to distinguish data points in a plotted
* series. In general only Line and Scatter and Radar chart types use
* markers. The libxlsxwriter chart types that can have markers are:
*
* - #LXW_CHART_LINE
* - #LXW_CHART_SCATTER
* - #LXW_CHART_SCATTER_STRAIGHT
* - #LXW_CHART_SCATTER_STRAIGHT_WITH_MARKERS
* - #LXW_CHART_SCATTER_SMOOTH
* - #LXW_CHART_SCATTER_SMOOTH_WITH_MARKERS
* - #LXW_CHART_RADAR
* - #LXW_CHART_RADAR_WITH_MARKERS
*
* The chart types with `MARKERS` in the name have markers with default colors
* and shapes turned on by default but it is possible using the various
* `chart_series_set_marker_xxx()` functions below to change these defaults. It
* is also possible to turn on an off markers.
*
* The `%chart_series_set_marker_type()` function is used to specify the
* type of the series marker:
*
* @code
* chart_series_set_marker_type(series, LXW_CHART_MARKER_DIAMOND);
* @endcode
*
* @image html chart_marker1.png
*
* The available marker types defined by #lxw_chart_marker_type are:
*
* - #LXW_CHART_MARKER_AUTOMATIC
* - #LXW_CHART_MARKER_NONE
* - #LXW_CHART_MARKER_SQUARE
* - #LXW_CHART_MARKER_DIAMOND
* - #LXW_CHART_MARKER_TRIANGLE
* - #LXW_CHART_MARKER_X
* - #LXW_CHART_MARKER_STAR
* - #LXW_CHART_MARKER_SHORT_DASH
* - #LXW_CHART_MARKER_LONG_DASH
* - #LXW_CHART_MARKER_CIRCLE
* - #LXW_CHART_MARKER_PLUS
*
* The `#LXW_CHART_MARKER_NONE` type can be used to turn off default markers:
*
* @code
* chart_series_set_marker_type(series, LXW_CHART_MARKER_NONE);
* @endcode
*
* @image html chart_series_set_marker_none.png
*
* The `#LXW_CHART_MARKER_AUTOMATIC` type is a special case which turns on a
* marker using the default marker style for the particular series. If
* automatic is on then other marker properties such as size, line or fill
* cannot be set.
*/
void chart_series_set_marker_type(lxw_chart_series *series, uint8_t type);
/**
* @brief Set the size of a data marker for a series.
*
* @param series A series object created via `chart_add_series()`.
* @param size The size of the marker.
*
* The `%chart_series_set_marker_size()` function is used to specify the
* size of the series marker:
*
* @code
* chart_series_set_marker_type(series, LXW_CHART_MARKER_CIRCLE);
* chart_series_set_marker_size(series, 10);
* @endcode
*
* @image html chart_series_set_marker_size.png
*
*/
void chart_series_set_marker_size(lxw_chart_series *series, uint8_t size);
/**
* @brief Set the line properties for a chart series marker.
*
* @param series A series object created via `chart_add_series()`.
* @param line A #lxw_chart_line struct.
*
* Set the line/border properties of a chart marker:
*
* @code
* lxw_chart_line line = {.color = LXW_COLOR_BLACK};
* lxw_chart_fill fill = {.color = LXW_COLOR_RED};
*
* chart_series_set_marker_type(series, LXW_CHART_MARKER_SQUARE);
* chart_series_set_marker_size(series, 8);
*
* chart_series_set_marker_line(series, &line);
* chart_series_set_marker_fill(series, &fill);
* @endcode
*
* @image html chart_marker2.png
*
* For more information see @ref chart_lines.
*/
void chart_series_set_marker_line(lxw_chart_series *series,
lxw_chart_line *line);
/**
* @brief Set the fill properties for a chart series marker.
*
* @param series A series object created via `chart_add_series()`.
* @param fill A #lxw_chart_fill struct.
*
* Set the fill properties of a chart marker:
*
* @code
* chart_series_set_marker_fill(series, &fill);
* @endcode
*
* See the example and image above and also see @ref chart_fills.
*/
void chart_series_set_marker_fill(lxw_chart_series *series,
lxw_chart_fill *fill);
/**
* @brief Set the pattern properties for a chart series marker.
*
* @param series A series object created via `chart_add_series()`.
* @param pattern A #lxw_chart_pattern struct.
*
* Set the pattern properties of a chart marker:
*
* @code
* chart_series_set_marker_pattern(series, &pattern);
* @endcode
*
* For more information see #lxw_chart_pattern_type and @ref chart_patterns.
*/
void chart_series_set_marker_pattern(lxw_chart_series *series,
lxw_chart_pattern *pattern);
/**
* @brief Set the formatting for points in the series.
*
* @param series A series object created via `chart_add_series()`.
* @param points An NULL terminated array of #lxw_chart_point pointers.
*
* @return A #lxw_error.
*
* In general formatting is applied to an entire series in a chart. However,
* it is occasionally required to format individual points in a series. In
* particular this is required for Pie/Doughnut charts where each segment is
* represented by a point.
*
* @dontinclude chart_pie_colors.c
* @skip Add the data series
* @until chart_series_set_points
*
* @image html chart_points1.png
*
* @note The array of #lxw_chart_point pointers should be NULL terminated
* as shown in the example.
*
* For more details see @ref chart_points
*/
lxw_error chart_series_set_points(lxw_chart_series *series,
lxw_chart_point *points[]);
/**
* @brief Smooth a line or scatter chart series.
*
* @param series A series object created via `chart_add_series()`.
* @param smooth Turn off/on the line smoothing. (0/1)
*
* The `chart_series_set_smooth()` function is used to set the smooth property
* of a line series. It is only applicable to the line and scatter chart
* types:
*
* @code
* chart_series_set_smooth(series2, LXW_TRUE);
* @endcode
*
* @image html chart_smooth.png
*
*
*/
void chart_series_set_smooth(lxw_chart_series *series, uint8_t smooth);
/**
* @brief Add data labels to a chart series.
*
* @param series A series object created via `chart_add_series()`.
*
* The `%chart_series_set_labels()` function is used to turn on data labels
* for a chart series. Data labels indicate the values of the plotted data
* points.
*
* @code
* chart_series_set_labels(series);
* @endcode
*
* @image html chart_data_labels1.png
*
* By default data labels are displayed in Excel with only the values shown:
*
* @image html chart_data_labels2.png
*
* However, it is possible to configure other display options, as shown
* in the functions below.
*
* For more information see @ref chart_labels.
*/
void chart_series_set_labels(lxw_chart_series *series);
/**
* @brief Set the display options for the labels of a data series.
*
* @param series A series object created via `chart_add_series()`.
* @param show_name Turn on/off the series name in the label caption.
* @param show_category Turn on/off the category name in the label caption.
* @param show_value Turn on/off the value in the label caption.
*
* The `%chart_series_set_labels_options()` function is used to set the
* parameters that are displayed in the series data label:
*
* @code
* chart_series_set_labels(series);
* chart_series_set_labels_options(series, LXW_TRUE, LXW_TRUE, LXW_TRUE);
* @endcode
*
* @image html chart_data_labels3.png
*
* For more information see @ref chart_labels.
*/
void chart_series_set_labels_options(lxw_chart_series *series,
uint8_t show_name, uint8_t show_category,
uint8_t show_value);
/** @brief Set the properties for data labels in a series.
*
* @param series A series object created via `chart_add_series()`.
* @param data_labels An NULL terminated array of #lxw_chart_data_label pointers.
*
* @return A #lxw_error.
*
* The `%chart_series_set_labels_custom()` function is used to set the properties
* for data labels in a series. It can also be used to delete individual data
* labels in a series.
*
* In general properties are set for all the data labels in a chart
* series. However, it is also possible to set properties for individual data
* labels in a series using `%chart_series_set_labels_custom()`.
*
* The `%chart_series_set_labels_custom()` function takes a pointer to an array
* of #lxw_chart_data_label pointers. The list should be `NULL` terminated:
*
* @code
* // Add the series data labels.
* chart_series_set_labels(series);
*
* // Create some custom labels.
* lxw_chart_data_label data_label1 = {.value = "Jan"};
* lxw_chart_data_label data_label2 = {.value = "Feb"};
* lxw_chart_data_label data_label3 = {.value = "Mar"};
* lxw_chart_data_label data_label4 = {.value = "Apr"};
* lxw_chart_data_label data_label5 = {.value = "May"};
* lxw_chart_data_label data_label6 = {.value = "Jun"};
*
* // Create an array of label pointers. NULL indicates the end of the array.
* lxw_chart_data_label *data_labels[] = {
* &data_label1,
* &data_label2,
* &data_label3,
* &data_label4,
* &data_label5,
* &data_label6,
* NULL
* };
*
* // Set the custom labels.
* chart_series_set_labels_custom(series, data_labels);
* @endcode
*
* @image html chart_data_labels18.png
*
* @note The array of #lxw_chart_point pointers should be NULL terminated as
* shown in the example. Any #lxw_chart_data_label items set to a default
* initialization or omitted from the list will be assigned the default data
* label value.
*
* For more details see @ref chart_custom_labels.
*/
lxw_error chart_series_set_labels_custom(lxw_chart_series *series, lxw_chart_data_label
*data_labels[]);
/**
* @brief Set the separator for the data label captions.
*
* @param series A series object created via `chart_add_series()`.
* @param separator The separator for the data label options:
* #lxw_chart_label_separator.
*
* The `%chart_series_set_labels_separator()` function is used to change the
* separator between multiple data label items. The default options is a comma
* separator as shown in the previous example.
*
* The available options are:
*
* - #LXW_CHART_LABEL_SEPARATOR_SEMICOLON: semicolon separator.
* - #LXW_CHART_LABEL_SEPARATOR_PERIOD: a period (dot) separator.
* - #LXW_CHART_LABEL_SEPARATOR_NEWLINE: a newline separator.
* - #LXW_CHART_LABEL_SEPARATOR_SPACE: a space separator.
*
* For example:
*
* @code
* chart_series_set_labels(series);
* chart_series_set_labels_options(series, LXW_TRUE, LXW_TRUE, LXW_TRUE);
* chart_series_set_labels_separator(series, LXW_CHART_LABEL_SEPARATOR_NEWLINE);
* @endcode
*
* @image html chart_data_labels4.png
*
* For more information see @ref chart_labels.
*/
void chart_series_set_labels_separator(lxw_chart_series *series,
uint8_t separator);
/**
* @brief Set the data label position for a series.
*
* @param series A series object created via `chart_add_series()`.
* @param position The data label position: #lxw_chart_label_position.
*
* The `%chart_series_set_labels_position()` function sets the position of
* the labels in the data series:
*
* @code
* chart_series_set_labels(series);
* chart_series_set_labels_position(series, LXW_CHART_LABEL_POSITION_ABOVE);
* @endcode
*
* @image html chart_data_labels5.png
*
* In Excel the allowable data label positions vary for different chart
* types. The allowable, and default, positions are:
*
* | Position | Line, Scatter | Bar, Column | Pie, Doughnut | Area, Radar |
* | :------------------------------------ | :------------ | :------------ | :------------ | :------------ |
* | #LXW_CHART_LABEL_POSITION_CENTER | Yes | Yes | Yes | Yes (default) |
* | #LXW_CHART_LABEL_POSITION_RIGHT | Yes (default) | | | |
* | #LXW_CHART_LABEL_POSITION_LEFT | Yes | | | |
* | #LXW_CHART_LABEL_POSITION_ABOVE | Yes | | | |
* | #LXW_CHART_LABEL_POSITION_BELOW | Yes | | | |
* | #LXW_CHART_LABEL_POSITION_INSIDE_BASE | | Yes | | |
* | #LXW_CHART_LABEL_POSITION_INSIDE_END | | Yes | Yes | |
* | #LXW_CHART_LABEL_POSITION_OUTSIDE_END | | Yes (default) | Yes | |
* | #LXW_CHART_LABEL_POSITION_BEST_FIT | | | Yes (default) | |
*
*
* For more information see @ref chart_labels.
*/
void chart_series_set_labels_position(lxw_chart_series *series,
uint8_t position);
/**
* @brief Set leader lines for Pie and Doughnut charts.
*
* @param series A series object created via `chart_add_series()`.
*
* The `%chart_series_set_labels_leader_line()` function is used to turn on
* leader lines for the data label of a series. It is mainly used for pie
* or doughnut charts:
*
* @code
* chart_series_set_labels(series);
* chart_series_set_labels_leader_line(series);
* @endcode
*
* @note Even when leader lines are turned on they aren't automatically
* visible in Excel or XlsxWriter. Due to an Excel limitation
* (or design) leader lines only appear if the data label is moved
* manually or if the data labels are very close and need to be
* adjusted automatically.
*
* For more information see @ref chart_labels.
*/
void chart_series_set_labels_leader_line(lxw_chart_series *series);
/**
* @brief Set the legend key for a data label in a chart series.
*
* @param series A series object created via `chart_add_series()`.
*
* The `%chart_series_set_labels_legend()` function is used to set the
* legend key for a data series:
*
* @code
* chart_series_set_labels(series);
* chart_series_set_labels_legend(series);
* @endcode
*
* @image html chart_data_labels6.png
*
* For more information see @ref chart_labels.
*/
void chart_series_set_labels_legend(lxw_chart_series *series);
/**
* @brief Set the percentage for a Pie/Doughnut data point.
*
* @param series A series object created via `chart_add_series()`.
*
* The `%chart_series_set_labels_percentage()` function is used to turn on
* the display of data labels as a percentage for a series. It is mainly
* used for pie charts:
*
* @code
* chart_series_set_labels(series);
* chart_series_set_labels_options(series, LXW_FALSE, LXW_FALSE, LXW_FALSE);
* chart_series_set_labels_percentage(series);
* @endcode
*
* @image html chart_data_labels7.png
*
* For more information see @ref chart_labels.
*/
void chart_series_set_labels_percentage(lxw_chart_series *series);
/**
* @brief Set the number format for chart data labels in a series.
*
* @param series A series object created via `chart_add_series()`.
* @param num_format The number format string.
*
* The `%chart_series_set_labels_num_format()` function is used to set the
* number format for data labels:
*
* @code
* chart_series_set_labels(series);
* chart_series_set_labels_num_format(series, "$0.00");
* @endcode
*
* @image html chart_data_labels8.png
*
* The number format is similar to the Worksheet Cell Format num_format,
* see `format_set_num_format()`.
*
* For more information see @ref chart_labels.
*/
void chart_series_set_labels_num_format(lxw_chart_series *series,
const char *num_format);
/**
* @brief Set the font properties for chart data labels in a series
*
* @param series A series object created via `chart_add_series()`.
* @param font A pointer to a chart #lxw_chart_font font struct.
*
*
* The `%chart_series_set_labels_font()` function is used to set the font
* for data labels:
*
* @code
* lxw_chart_font font = {.name = "Consolas", .color = LXW_COLOR_RED};
*
* chart_series_set_labels(series);
* chart_series_set_labels_font(series, &font);
* @endcode
*
* @image html chart_data_labels9.png
*
* For more information see @ref chart_fonts and @ref chart_labels.
*
*/
void chart_series_set_labels_font(lxw_chart_series *series,
lxw_chart_font *font);
/**
* @brief Set the line properties for the data labels in a chart series.
*
* @param series A series object created via `chart_add_series()`.
* @param line A #lxw_chart_line struct.
*
* Set the line/border properties of the data labels in a chart series:
*
* @code
* lxw_chart_line line = {.color = LXW_COLOR_RED};
* lxw_chart_fill fill = {.color = LXW_COLOR_YELLOW};
*
* chart_series_set_labels_line(series, &line);
* chart_series_set_labels_fill(series, &fill);
*
* @endcode
*
* @image html chart_data_labels24.png
*
* For more information see @ref chart_lines and @ref chart_labels.
*/
void chart_series_set_labels_line(lxw_chart_series *series,
lxw_chart_line *line);
/**
* @brief Set the fill properties for the data labels in a chart series.
*
* @param series A series object created via `chart_add_series()`.
* @param fill A #lxw_chart_fill struct.
*
* Set the fill properties of the data labels in a chart series:
*
* @code
* lxw_chart_fill fill = {.color = LXW_COLOR_YELLOW};
*
* chart_series_set_labels_fill(series, &fill);
* @endcode
*
* See the example and image above and also see @ref chart_fills and
* @ref chart_labels.
*/
void chart_series_set_labels_fill(lxw_chart_series *series,
lxw_chart_fill *fill);
/**
* @brief Set the pattern properties for the data labels in a chart series.
*
* @param series A series object created via `chart_add_series()`.
* @param pattern A #lxw_chart_pattern struct.
*
* Set the pattern properties of the data labels in a chart series:
*
* @code
* chart_series_set_labels_pattern(series, &pattern);
* @endcode
*
* For more information see #lxw_chart_pattern_type and @ref chart_patterns.
*/
void chart_series_set_labels_pattern(lxw_chart_series *series,
lxw_chart_pattern *pattern);
/**
* @brief Turn on a trendline for a chart data series.
*
* @param series A series object created via `chart_add_series()`.
* @param type The type of trendline: #lxw_chart_trendline_type.
* @param value The order/period value for polynomial and moving average
* trendlines.
*
* A trendline can be added to a chart series to indicate trends in the data
* such as a moving average or a polynomial fit. The trendlines types are
* shown in the following Excel dialog:
*
* @image html chart_trendline0.png
*
* The `%chart_series_set_trendline()` function turns on these trendlines for
* a data series:
*
* @code
* chart = workbook_add_chart(workbook, LXW_CHART_LINE);
* series = chart_add_series(chart, NULL, "Sheet1!$A$1:$A$6");
*
* chart_series_set_trendline(series, LXW_CHART_TRENDLINE_TYPE_LINEAR, 0);
* @endcode
*
* @image html chart_trendline2.png
*
* The `value` parameter corresponds to *order* for a polynomial trendline
* and *period* for a Moving Average trendline. It both cases it must be >= 2.
* The `value` parameter is ignored for all other trendlines:
*
* @code
* chart_series_set_trendline(series, LXW_CHART_TRENDLINE_TYPE_AVERAGE, 2);
* @endcode
*
* @image html chart_trendline3.png
*
* The allowable values for the the trendline `type` are:
*
* - #LXW_CHART_TRENDLINE_TYPE_LINEAR: Linear trendline.
* - #LXW_CHART_TRENDLINE_TYPE_LOG: Logarithm trendline.
* - #LXW_CHART_TRENDLINE_TYPE_POLY: Polynomial trendline. The `value`
* parameter corresponds to *order*.
* - #LXW_CHART_TRENDLINE_TYPE_POWER: Power trendline.
* - #LXW_CHART_TRENDLINE_TYPE_EXP: Exponential trendline.
* - #LXW_CHART_TRENDLINE_TYPE_AVERAGE: Moving Average trendline. The `value`
* parameter corresponds to *period*.
*
* Other trendline options, such as those shown in the following Excel
* dialog, can be set using the functions below.
*
* @image html chart_trendline1.png
*
* For more information see @ref chart_trendlines.
*/
void chart_series_set_trendline(lxw_chart_series *series, uint8_t type,
uint8_t value);
/**
* @brief Set the trendline forecast for a chart data series.
*
* @param series A series object created via `chart_add_series()`.
* @param forward The forward period.
* @param backward The backwards period.
*
* The `%chart_series_set_trendline_forecast()` function sets the forward
* and backward forecast periods for the trendline:
*
* @code
* chart_series_set_trendline(series, LXW_CHART_TRENDLINE_TYPE_LINEAR, 0);
* chart_series_set_trendline_forecast(series, 0.5, 0.5);
* @endcode
*
* @image html chart_trendline4.png
*
* @note This feature isn't available for Moving Average in Excel.
*
* For more information see @ref chart_trendlines.
*/
void chart_series_set_trendline_forecast(lxw_chart_series *series,
double forward, double backward);
/**
* @brief Display the equation of a trendline for a chart data series.
*
* @param series A series object created via `chart_add_series()`.
*
* The `%chart_series_set_trendline_equation()` function displays the
* equation of the trendline on the chart:
*
* @code
* chart_series_set_trendline(series, LXW_CHART_TRENDLINE_TYPE_LINEAR, 0);
* chart_series_set_trendline_equation(series);
* @endcode
*
* @image html chart_trendline5.png
*
* @note This feature isn't available for Moving Average in Excel.
*
* For more information see @ref chart_trendlines.
*/
void chart_series_set_trendline_equation(lxw_chart_series *series);
/**
* @brief Display the R squared value of a trendline for a chart data series.
*
* @param series A series object created via `chart_add_series()`.
*
* The `%chart_series_set_trendline_r_squared()` function displays the
* R-squared value for the trendline on the chart:
*
* @code
* chart_series_set_trendline(series, LXW_CHART_TRENDLINE_TYPE_LINEAR, 0);
* chart_series_set_trendline_r_squared(series);
* @endcode
*
* @image html chart_trendline6.png
*
* @note This feature isn't available for Moving Average in Excel.
*
* For more information see @ref chart_trendlines.
*/
void chart_series_set_trendline_r_squared(lxw_chart_series *series);
/**
* @brief Set the trendline Y-axis intercept for a chart data series.
*
* @param series A series object created via `chart_add_series()`.
* @param intercept Y-axis intercept value.
*
* The `%chart_series_set_trendline_intercept()` function sets the Y-axis
* intercept for the trendline:
*
* @code
* chart_series_set_trendline(series, LXW_CHART_TRENDLINE_TYPE_LINEAR, 0);
* chart_series_set_trendline_equation(series);
* chart_series_set_trendline_intercept(series, 0.8);
* @endcode
*
* @image html chart_trendline7.png
*
* As can be seen from the equation on the chart the intercept point
* (when X=0) is the same as the value set in the equation.
*
* @note The intercept feature is only available in Excel for Exponential,
* Linear and Polynomial trendline types.
*
* For more information see @ref chart_trendlines.
*/
void chart_series_set_trendline_intercept(lxw_chart_series *series,
double intercept);
/**
* @brief Set the trendline name for a chart data series.
*
* @param series A series object created via `chart_add_series()`.
* @param name The name of the trendline to display in the legend.
*
* The `%chart_series_set_trendline_name()` function sets the name of the
* trendline that is displayed in the chart legend. In the examples above
* the trendlines are displayed with default names like "Linear (Series 1)"
* and "2 per Mov. Avg. (Series 1)". If these names are too verbose or not
* descriptive enough you can set your own trendline name:
*
* @code
* chart_series_set_trendline(series, LXW_CHART_TRENDLINE_TYPE_LINEAR, 0);
* chart_series_set_trendline_name(series, "My trendline");
* @endcode
*
* @image html chart_trendline8.png
*
* It is often preferable to turn off the trendline caption in the legend.
* This is down in Excel by deleting the trendline name from the legend.
* In libxlsxwriter this is done using the `chart_legend_delete_series()`
* function to delete the zero based series numbers:
*
* @code
* chart_series_set_trendline(series, LXW_CHART_TRENDLINE_TYPE_LINEAR, 0);
*
* // Delete the series name for the second series (=1 in zero base).
* // The -1 value indicates the end of the array of values.
* int16_t names[] = {1, -1};
* chart_legend_delete_series(chart, names);
* @endcode
*
* @image html chart_trendline9.png
*
* For more information see @ref chart_trendlines.
*/
void chart_series_set_trendline_name(lxw_chart_series *series,
const char *name);
/**
* @brief Set the trendline line properties for a chart data series.
*
* @param series A series object created via `chart_add_series()`.
* @param line A #lxw_chart_line struct.
*
* The `%chart_series_set_trendline_line()` function is used to set the line
* properties of a trendline:
*
* @code
* lxw_chart_line line = {.color = LXW_COLOR_RED,
* .dash_type = LXW_CHART_LINE_DASH_LONG_DASH};
*
* chart_series_set_trendline(series, LXW_CHART_TRENDLINE_TYPE_LINEAR, 0);
* chart_series_set_trendline_line(series, &line);
* @endcode
*
* @image html chart_trendline10.png
*
* For more information see @ref chart_trendlines and @ref chart_lines.
*/
void chart_series_set_trendline_line(lxw_chart_series *series,
lxw_chart_line *line);
/**
* @brief Get a pointer to X or Y error bars from a chart series.
*
* @param series A series object created via `chart_add_series()`.
* @param axis_type The axis type (X or Y): #lxw_chart_error_bar_axis.
*
* The `%chart_series_get_error_bars()` function returns a pointer to the
* error bars of a series based on the type of #lxw_chart_error_bar_axis:
*
* @code
* lxw_series_error_bars *x_error_bars;
* lxw_series_error_bars *y_error_bars;
*
* x_error_bars = chart_series_get_error_bars(series, LXW_CHART_ERROR_BAR_AXIS_X);
* y_error_bars = chart_series_get_error_bars(series, LXW_CHART_ERROR_BAR_AXIS_Y);
*
* // Use the error bar pointers.
* chart_series_set_error_bars(x_error_bars,
* LXW_CHART_ERROR_BAR_TYPE_STD_DEV, 1);
*
* chart_series_set_error_bars(y_error_bars,
* LXW_CHART_ERROR_BAR_TYPE_STD_ERROR, 0);
* @endcode
*
* Note, the series error bars can also be accessed directly:
*
* @code
* // Equivalent to the above example, without function calls.
* chart_series_set_error_bars(series->x_error_bars,
* LXW_CHART_ERROR_BAR_TYPE_STD_DEV, 1);
*
* chart_series_set_error_bars(series->y_error_bars,
* LXW_CHART_ERROR_BAR_TYPE_STD_ERROR, 0);
* @endcode
*
* @return Pointer to the series error bars, or NULL if not found.
*/
lxw_series_error_bars *chart_series_get_error_bars(lxw_chart_series *series, lxw_chart_error_bar_axis
axis_type);
/**
* Set the X or Y error bars for a chart series.
*
* @param error_bars A pointer to the series X or Y error bars.
* @param type The type of error bar: #lxw_chart_error_bar_type.
* @param value The error value.
*
* Error bars can be added to a chart series to indicate error bounds in the
* data. The error bars can be vertical `y_error_bars` (the most common type)
* or horizontal `x_error_bars` (for Bar and Scatter charts only).
*
* @image html chart_error_bars0.png
*
* The `%chart_series_set_error_bars()` function sets the error bar type
* and value associated with the type:
*
* @code
* lxw_chart_series *series = chart_add_series(chart,
* "=Sheet1!$A$1:$A$5",
* "=Sheet1!$B$1:$B$5");
*
* chart_series_set_error_bars(series->y_error_bars,
* LXW_CHART_ERROR_BAR_TYPE_STD_ERROR, 0);
* @endcode
*
* @image html chart_error_bars1.png
*
* The error bar types that be used are:
*
* - #LXW_CHART_ERROR_BAR_TYPE_STD_ERROR: Standard error.
* - #LXW_CHART_ERROR_BAR_TYPE_FIXED: Fixed value.
* - #LXW_CHART_ERROR_BAR_TYPE_PERCENTAGE: Percentage.
* - #LXW_CHART_ERROR_BAR_TYPE_STD_DEV: Standard deviation(s).
*
* @note Custom error bars are not currently supported.
*
* All error bar types, apart from Standard error, should have a valid
* value to set the error range:
*
* @code
* chart_series_set_error_bars(series1->y_error_bars,
* LXW_CHART_ERROR_BAR_TYPE_FIXED, 2);
*
* chart_series_set_error_bars(series2->y_error_bars,
* LXW_CHART_ERROR_BAR_TYPE_PERCENTAGE, 5);
*
* chart_series_set_error_bars(series3->y_error_bars,
* LXW_CHART_ERROR_BAR_TYPE_STD_DEV, 1);
* @endcode
*
* For the Standard error type the value is ignored.
*
* For more information see @ref chart_error_bars.
*/
void chart_series_set_error_bars(lxw_series_error_bars *error_bars,
uint8_t type, double value);
/**
* @brief Set the direction (up, down or both) of the error bars for a chart
* series.
*
* @param error_bars A pointer to the series X or Y error bars.
* @param direction The bar direction: #lxw_chart_error_bar_direction.
*
* The `%chart_series_set_error_bars_direction()` function sets the
* direction of the error bars:
*
* @code
* chart_series_set_error_bars(series->y_error_bars,
* LXW_CHART_ERROR_BAR_TYPE_STD_ERROR, 0);
*
* chart_series_set_error_bars_direction(series->y_error_bars,
* LXW_CHART_ERROR_BAR_DIR_PLUS);
* @endcode
*
* @image html chart_error_bars2.png
*
* The valid directions are:
*
* - #LXW_CHART_ERROR_BAR_DIR_BOTH: Error bar extends in both directions.
* The default.
* - #LXW_CHART_ERROR_BAR_DIR_PLUS: Error bar extends in positive direction.
* - #LXW_CHART_ERROR_BAR_DIR_MINUS: Error bar extends in negative direction.
*
* For more information see @ref chart_error_bars.
*/
void chart_series_set_error_bars_direction(lxw_series_error_bars *error_bars,
uint8_t direction);
/**
* @brief Set the end cap type for the error bars of a chart series.
*
* @param error_bars A pointer to the series X or Y error bars.
* @param endcap The error bar end cap type: #lxw_chart_error_bar_cap .
*
* The `%chart_series_set_error_bars_endcap()` function sets the end cap
* type for the error bars:
*
* @code
* chart_series_set_error_bars(series->y_error_bars,
* LXW_CHART_ERROR_BAR_TYPE_STD_ERROR, 0);
*
* chart_series_set_error_bars_endcap(series->y_error_bars,
LXW_CHART_ERROR_BAR_NO_CAP);
* @endcode
*
* @image html chart_error_bars3.png
*
* The valid values are:
*
* - #LXW_CHART_ERROR_BAR_END_CAP: Flat end cap. The default.
* - #LXW_CHART_ERROR_BAR_NO_CAP: No end cap.
*
* For more information see @ref chart_error_bars.
*/
void chart_series_set_error_bars_endcap(lxw_series_error_bars *error_bars,
uint8_t endcap);
/**
* @brief Set the line properties for a chart series error bars.
*
* @param error_bars A pointer to the series X or Y error bars.
* @param line A #lxw_chart_line struct.
*
* The `%chart_series_set_error_bars_line()` function sets the line
* properties for the error bars:
*
* @code
* lxw_chart_line line = {.color = LXW_COLOR_RED,
* .dash_type = LXW_CHART_LINE_DASH_ROUND_DOT};
*
* chart_series_set_error_bars(series->y_error_bars,
* LXW_CHART_ERROR_BAR_TYPE_STD_ERROR, 0);
*
* chart_series_set_error_bars_line(series->y_error_bars, &line);
* @endcode
*
* @image html chart_error_bars4.png
*
* For more information see @ref chart_lines and @ref chart_error_bars.
*/
void chart_series_set_error_bars_line(lxw_series_error_bars *error_bars,
lxw_chart_line *line);
/**
* @brief Get an axis pointer from a chart.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param axis_type The axis type (X or Y): #lxw_chart_axis_type.
*
* The `%chart_axis_get()` function returns a pointer to a chart axis based
* on the #lxw_chart_axis_type:
*
* @code
* lxw_chart_axis *x_axis = chart_axis_get(chart, LXW_CHART_AXIS_TYPE_X);
* lxw_chart_axis *y_axis = chart_axis_get(chart, LXW_CHART_AXIS_TYPE_Y);
*
* // Use the axis pointer in other functions.
* chart_axis_major_gridlines_set_visible(x_axis, LXW_TRUE);
* chart_axis_major_gridlines_set_visible(y_axis, LXW_TRUE);
* @endcode
*
* Note, the axis pointer can also be accessed directly:
*
* @code
* // Equivalent to the above example, without function calls.
* chart_axis_major_gridlines_set_visible(chart->x_axis, LXW_TRUE);
* chart_axis_major_gridlines_set_visible(chart->y_axis, LXW_TRUE);
* @endcode
*
* @return Pointer to the chart axis, or NULL if not found.
*/
lxw_chart_axis *chart_axis_get(lxw_chart *chart,
lxw_chart_axis_type axis_type);
/**
* @brief Set the name caption of the an axis.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param name The name caption of the axis.
*
* The `%chart_axis_set_name()` function sets the name (also known as title or
* caption) for an axis. It can be used for the X or Y axes. The name is
* displayed below an X axis and to the side of a Y axis.
*
* @code
* chart_axis_set_name(chart->x_axis, "Earnings per Quarter");
* chart_axis_set_name(chart->y_axis, "US Dollars (Millions)");
* @endcode
*
* @image html chart_axis_set_name.png
*
* The name parameter can also be a formula such as `=Sheet1!$A$1` to point to
* a cell in the workbook that contains the name:
*
* @code
* chart_axis_set_name(chart->x_axis, "=Sheet1!$B$1");
* @endcode
*
* See also the `chart_axis_set_name_range()` function to see how to set the
* name formula programmatically.
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_set_name(lxw_chart_axis *axis, const char *name);
/**
* @brief Set a chart axis name formula using row and column values.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param sheetname The name of the worksheet that contains the cell range.
* @param row The zero indexed row number of the range.
* @param col The zero indexed column number of the range.
*
* The `%chart_axis_set_name_range()` function can be used to set an axis name
* range and is an alternative to using `chart_axis_set_name()` and a string
* formula:
*
* @code
* chart_axis_set_name_range(chart->x_axis, "Sheet1", 1, 0);
* chart_axis_set_name_range(chart->y_axis, "Sheet1", 2, 0);
* @endcode
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_set_name_range(lxw_chart_axis *axis, const char *sheetname,
lxw_row_t row, lxw_col_t col);
/**
* @brief Set the font properties for a chart axis name.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param font A pointer to a chart #lxw_chart_font font struct.
*
* The `%chart_axis_set_name_font()` function is used to set the font of an
* axis name:
*
* @code
* lxw_chart_font font = {.bold = LXW_TRUE, .color = LXW_COLOR_BLUE};
*
* chart_axis_set_name(chart->x_axis, "Yearly data");
* chart_axis_set_name_font(chart->x_axis, &font);
* @endcode
*
* @image html chart_axis_set_name_font.png
*
* For more information see @ref chart_fonts.
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_set_name_font(lxw_chart_axis *axis, lxw_chart_font *font);
/**
* @brief Set the font properties for the numbers of a chart axis.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param font A pointer to a chart #lxw_chart_font font struct.
*
* The `%chart_axis_set_num_font()` function is used to set the font of the
* numbers on an axis:
*
* @code
* lxw_chart_font font = {.bold = LXW_TRUE, .color = LXW_COLOR_BLUE};
*
* chart_axis_set_num_font(chart->x_axis, &font1);
* @endcode
*
* @image html chart_axis_set_num_font.png
*
* For more information see @ref chart_fonts.
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_set_num_font(lxw_chart_axis *axis, lxw_chart_font *font);
/**
* @brief Set the number format for a chart axis.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param num_format The number format string.
*
* The `%chart_axis_set_num_format()` function is used to set the format of
* the numbers on an axis:
*
* @code
* chart_axis_set_num_format(chart->x_axis, "0.00%");
* chart_axis_set_num_format(chart->y_axis, "$#,##0.00");
* @endcode
*
* The number format is similar to the Worksheet Cell Format num_format,
* see `format_set_num_format()`.
*
* @image html chart_axis_num_format.png
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_set_num_format(lxw_chart_axis *axis, const char *num_format);
/**
* @brief Set the line properties for a chart axis.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param line A #lxw_chart_line struct.
*
* Set the line properties of a chart axis:
*
* @code
* // Hide the Y axis.
* lxw_chart_line line = {.none = LXW_TRUE};
*
* chart_axis_set_line(chart->y_axis, &line);
* @endcode
*
* @image html chart_axis_set_line.png
*
* For more information see @ref chart_lines.
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_set_line(lxw_chart_axis *axis, lxw_chart_line *line);
/**
* @brief Set the fill properties for a chart axis.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param fill A #lxw_chart_fill struct.
*
* Set the fill properties of a chart axis:
*
* @code
* lxw_chart_fill fill = {.color = LXW_COLOR_YELLOW};
*
* chart_axis_set_fill(chart->y_axis, &fill);
* @endcode
*
* @image html chart_axis_set_fill.png
*
* For more information see @ref chart_fills.
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_set_fill(lxw_chart_axis *axis, lxw_chart_fill *fill);
/**
* @brief Set the pattern properties for a chart axis.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param pattern A #lxw_chart_pattern struct.
*
* Set the pattern properties of a chart axis:
*
* @code
* chart_axis_set_pattern(chart->y_axis, &pattern);
* @endcode
*
* For more information see #lxw_chart_pattern_type and @ref chart_patterns.
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_set_pattern(lxw_chart_axis *axis, lxw_chart_pattern *pattern);
/**
* @brief Reverse the order of the axis categories or values.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
*
* Reverse the order of the axis categories or values:
*
* @code
* chart_axis_set_reverse(chart->x_axis);
* @endcode
*
* @image html chart_reverse.png
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_set_reverse(lxw_chart_axis *axis);
/**
* @brief Set the position that the axis will cross the opposite axis.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param value The category or value that the axis crosses at.
*
* Set the position that the axis will cross the opposite axis:
*
* @code
* chart_axis_set_crossing(chart->x_axis, 3);
* chart_axis_set_crossing(chart->y_axis, 8);
* @endcode
*
* @image html chart_crossing1.png
*
* If crossing is omitted (the default) the crossing will be set automatically
* by Excel based on the chart data.
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_set_crossing(lxw_chart_axis *axis, double value);
/**
* @brief Set the opposite axis crossing position as the axis maximum.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
*
* Set the position that the opposite axis will cross as the axis maximum.
* The default axis crossing position is generally the axis minimum so this
* function can be used to reverse the location of the axes without reversing
* the number sequence:
*
* @code
* chart_axis_set_crossing_max(chart->x_axis);
* chart_axis_set_crossing_max(chart->y_axis);
* @endcode
*
* @image html chart_crossing2.png
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_set_crossing_max(lxw_chart_axis *axis);
/**
* @brief Set the opposite axis crossing position as the axis minimum.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
*
* Set the position that the opposite axis will cross as the axis minimum.
* The default axis crossing position is generally the axis minimum so this
* function can be used to reverse the location of the axes without reversing
* the number sequence:
*
* @code
* chart_axis_set_crossing_min(chart->x_axis);
* chart_axis_set_crossing_min(chart->y_axis);
* @endcode
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_set_crossing_min(lxw_chart_axis *axis);
/**
* @brief Turn off/hide an axis.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
*
* Turn off, hide, a chart axis:
*
* @code
* chart_axis_off(chart->x_axis);
* @endcode
*
* @image html chart_axis_off.png
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_off(lxw_chart_axis *axis);
/**
* @brief Position a category axis on or between the axis tick marks.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param position A #lxw_chart_axis_tick_position value.
*
* Position a category axis horizontally on, or between, the axis tick marks.
*
* There are two allowable values:
*
* - #LXW_CHART_AXIS_POSITION_ON_TICK
* - #LXW_CHART_AXIS_POSITION_BETWEEN
*
* @code
* chart_axis_set_position(chart->x_axis, LXW_CHART_AXIS_POSITION_BETWEEN);
* @endcode
*
* @image html chart_axis_set_position.png
*
* **Axis types**: This function is applicable to category axes only.
* See @ref ww_charts_axes.
*/
void chart_axis_set_position(lxw_chart_axis *axis, uint8_t position);
/**
* @brief Position the axis labels.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param position A #lxw_chart_axis_label_position value.
*
* Position the axis labels for the chart. The labels are the numbers, or
* strings or dates, on the axis that indicate the categories or values of
* the axis.
*
* For example:
*
* @code
* chart_axis_set_label_position(chart->x_axis, LXW_CHART_AXIS_LABEL_POSITION_HIGH);
* chart_axis_set_label_position(chart->y_axis, LXW_CHART_AXIS_LABEL_POSITION_HIGH);
* @endcode
*
* @image html chart_label_position2.png
*
* The allowable values:
*
* - #LXW_CHART_AXIS_LABEL_POSITION_NEXT_TO - The default.
* - #LXW_CHART_AXIS_LABEL_POSITION_HIGH - Also right for vertical axes.
* - #LXW_CHART_AXIS_LABEL_POSITION_LOW - Also left for vertical axes.
* - #LXW_CHART_AXIS_LABEL_POSITION_NONE
*
* @image html chart_label_position1.png
*
* The #LXW_CHART_AXIS_LABEL_POSITION_NONE turns off the axis labels. This
* is slightly different from `chart_axis_off()` which also turns off the
* labels but also turns off tick marks.
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_set_label_position(lxw_chart_axis *axis, uint8_t position);
/**
* @brief Set the alignment of the axis labels.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param align A #lxw_chart_axis_label_alignment value.
*
* Position the category axis labels for the chart. The labels are the
* numbers, or strings or dates, on the axis that indicate the categories
* of the axis.
*
* The allowable values:
*
* - #LXW_CHART_AXIS_LABEL_ALIGN_CENTER - Align label center (default).
* - #LXW_CHART_AXIS_LABEL_ALIGN_LEFT - Align label left.
* - #LXW_CHART_AXIS_LABEL_ALIGN_RIGHT - Align label right.
*
* @code
* chart_axis_set_label_align(chart->x_axis, LXW_CHART_AXIS_LABEL_ALIGN_RIGHT);
* @endcode
*
* **Axis types**: This function is applicable to category axes only.
* See @ref ww_charts_axes.
*/
void chart_axis_set_label_align(lxw_chart_axis *axis, uint8_t align);
/**
* @brief Set the minimum value for a chart axis.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param min Minimum value for chart axis. Value axes only.
*
* Set the minimum value for the axis range.
*
* @code
* chart_axis_set_min(chart->y_axis, -4);
* chart_axis_set_max(chart->y_axis, 21);
* @endcode
*
* @image html chart_max_min.png
*
* **Axis types**: This function is applicable to value and date axes only.
* See @ref ww_charts_axes.
*/
void chart_axis_set_min(lxw_chart_axis *axis, double min);
/**
* @brief Set the maximum value for a chart axis.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param max Maximum value for chart axis. Value axes only.
*
* Set the maximum value for the axis range.
*
* @code
* chart_axis_set_min(chart->y_axis, -4);
* chart_axis_set_max(chart->y_axis, 21);
* @endcode
*
* See the above image.
*
* **Axis types**: This function is applicable to value and date axes only.
* See @ref ww_charts_axes.
*/
void chart_axis_set_max(lxw_chart_axis *axis, double max);
/**
* @brief Set the log base of the axis range.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param log_base The log base for value axis. Value axes only.
*
* Set the log base for the axis:
*
* @code
* chart_axis_set_log_base(chart->y_axis, 10);
* @endcode
*
* @image html chart_log_base.png
*
* The allowable range of values for the log base in Excel is between 2 and
* 1000.
*
* **Axis types**: This function is applicable to value axes only.
* See @ref ww_charts_axes.
*/
void chart_axis_set_log_base(lxw_chart_axis *axis, uint16_t log_base);
/**
* @brief Set the major axis tick mark type.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param type The tick mark type, defined by #lxw_chart_tick_mark.
*
* Set the type of the major axis tick mark:
*
* @code
* chart_axis_set_major_tick_mark(chart->x_axis, LXW_CHART_AXIS_TICK_MARK_CROSSING);
* chart_axis_set_minor_tick_mark(chart->x_axis, LXW_CHART_AXIS_TICK_MARK_INSIDE);
*
* chart_axis_set_major_tick_mark(chart->x_axis, LXW_CHART_AXIS_TICK_MARK_OUTSIDE);
* chart_axis_set_minor_tick_mark(chart->y_axis, LXW_CHART_AXIS_TICK_MARK_INSIDE);
*
* // Hide the default gridlines so the tick marks are visible.
* chart_axis_major_gridlines_set_visible(chart->y_axis, LXW_FALSE);
* @endcode
*
* @image html chart_tick_marks.png
*
* The tick mark types are:
*
* - #LXW_CHART_AXIS_TICK_MARK_NONE
* - #LXW_CHART_AXIS_TICK_MARK_INSIDE
* - #LXW_CHART_AXIS_TICK_MARK_OUTSIDE
* - #LXW_CHART_AXIS_TICK_MARK_CROSSING
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_set_major_tick_mark(lxw_chart_axis *axis, uint8_t type);
/**
* @brief Set the minor axis tick mark type.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param type The tick mark type, defined by #lxw_chart_tick_mark.
*
* Set the type of the minor axis tick mark:
*
* @code
* chart_axis_set_minor_tick_mark(chart->x_axis, LXW_CHART_AXIS_TICK_MARK_INSIDE);
* @endcode
*
* See the image and example above.
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_set_minor_tick_mark(lxw_chart_axis *axis, uint8_t type);
/**
* @brief Set the interval between category values.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param unit The interval between the categories.
*
* Set the interval between the category values. The default interval is 1
* which gives the intervals shown in the charts above:
*
* 1, 2, 3, 4, 5, etc.
*
* Setting it to 2 gives:
*
* 1, 3, 5, 7, etc.
*
* For example:
*
* @code
* chart_axis_set_interval_unit(chart->x_axis, 2);
* @endcode
*
* @image html chart_set_interval1.png
*
* **Axis types**: This function is applicable to category and date axes only.
* See @ref ww_charts_axes.
*/
void chart_axis_set_interval_unit(lxw_chart_axis *axis, uint16_t unit);
/**
* @brief Set the interval between category tick marks.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param unit The interval between the category ticks.
*
* Set the interval between the category tick marks. The default interval is 1
* between each category but it can be set to other integer values:
*
* @code
* chart_axis_set_interval_tick(chart->x_axis, 2);
* @endcode
*
* @image html chart_set_interval2.png
*
* **Axis types**: This function is applicable to category and date axes only.
* See @ref ww_charts_axes.
*/
void chart_axis_set_interval_tick(lxw_chart_axis *axis, uint16_t unit);
/**
* @brief Set the increment of the major units in the axis.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param unit The increment of the major units.
*
* Set the increment of the major units in the axis range.
*
* @code
* // Turn on the minor gridline (it is off by default).
* chart_axis_minor_gridlines_set_visible(chart->y_axis, LXW_TRUE);
*
* chart_axis_set_major_unit(chart->y_axis, 4);
* chart_axis_set_minor_unit(chart->y_axis, 2);
* @endcode
*
* @image html chart_set_major_units.png
*
* **Axis types**: This function is applicable to value and date axes only.
* See @ref ww_charts_axes.
*/
void chart_axis_set_major_unit(lxw_chart_axis *axis, double unit);
/**
* @brief Set the increment of the minor units in the axis.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param unit The increment of the minor units.
*
* Set the increment of the minor units in the axis range.
*
* @code
* chart_axis_set_minor_unit(chart->y_axis, 2);
* @endcode
*
* See the image above
*
* **Axis types**: This function is applicable to value and date axes only.
* See @ref ww_charts_axes.
*/
void chart_axis_set_minor_unit(lxw_chart_axis *axis, double unit);
/**
* @brief Set the display units for a value axis.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param units The display units: #lxw_chart_axis_display_unit.
*
* Set the display units for the axis. This can be useful if the axis numbers
* are very large but you don't want to represent them in scientific notation:
*
* @code
* chart_axis_set_display_units(chart->x_axis, LXW_CHART_AXIS_UNITS_THOUSANDS);
* chart_axis_set_display_units(chart->y_axis, LXW_CHART_AXIS_UNITS_MILLIONS);
* @endcode
*
* @image html chart_display_units.png
*
* **Axis types**: This function is applicable to value axes only.
* See @ref ww_charts_axes.
*/
void chart_axis_set_display_units(lxw_chart_axis *axis, uint8_t units);
/**
* @brief Turn on/off the display units for a value axis.
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param visible Turn off/on the display units. (0/1)
*
* Turn on or off the display units for the axis. This option is set on
* automatically by `chart_axis_set_display_units()`.
*
* @code
* chart_axis_set_display_units_visible(chart->y_axis, LXW_TRUE);
* @endcode
*
* **Axis types**: This function is applicable to value axes only.
* See @ref ww_charts_axes.
*/
void chart_axis_set_display_units_visible(lxw_chart_axis *axis,
uint8_t visible);
/**
* @brief Turn on/off the major gridlines for an axis.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param visible Turn off/on the major gridline. (0/1)
*
* Turn on or off the major gridlines for an X or Y axis. In most Excel charts
* the Y axis major gridlines are on by default and the X axis major
* gridlines are off by default.
*
* Example:
*
* @code
* // Reverse the normal visible/hidden gridlines for a column chart.
* chart_axis_major_gridlines_set_visible(chart->x_axis, LXW_TRUE);
* chart_axis_major_gridlines_set_visible(chart->y_axis, LXW_FALSE);
* @endcode
*
* @image html chart_gridline1.png
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_major_gridlines_set_visible(lxw_chart_axis *axis,
uint8_t visible);
/**
* @brief Turn on/off the minor gridlines for an axis.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param visible Turn off/on the minor gridline. (0/1)
*
* Turn on or off the minor gridlines for an X or Y axis. In most Excel charts
* the X and Y axis minor gridlines are off by default.
*
* Example, turn on all major and minor gridlines:
*
* @code
* chart_axis_major_gridlines_set_visible(chart->x_axis, LXW_TRUE);
* chart_axis_minor_gridlines_set_visible(chart->x_axis, LXW_TRUE);
* chart_axis_major_gridlines_set_visible(chart->y_axis, LXW_TRUE);
* chart_axis_minor_gridlines_set_visible(chart->y_axis, LXW_TRUE);
* @endcode
*
* @image html chart_gridline2.png
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_minor_gridlines_set_visible(lxw_chart_axis *axis,
uint8_t visible);
/**
* @brief Set the line properties for the chart axis major gridlines.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param line A #lxw_chart_line struct.
*
* Format the line properties of the major gridlines of a chart:
*
* @code
* lxw_chart_line line1 = {.color = LXW_COLOR_RED,
* .width = 0.5,
* .dash_type = LXW_CHART_LINE_DASH_SQUARE_DOT};
*
* lxw_chart_line line2 = {.color = LXW_COLOR_YELLOW};
*
* lxw_chart_line line3 = {.width = 1.25,
* .dash_type = LXW_CHART_LINE_DASH_DASH};
*
* lxw_chart_line line4 = {.color = 0x00B050};
*
* chart_axis_major_gridlines_set_line(chart->x_axis, &line1);
* chart_axis_minor_gridlines_set_line(chart->x_axis, &line2);
* chart_axis_major_gridlines_set_line(chart->y_axis, &line3);
* chart_axis_minor_gridlines_set_line(chart->y_axis, &line4);
* @endcode
*
* @image html chart_gridline3.png
*
* For more information see @ref chart_lines.
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_major_gridlines_set_line(lxw_chart_axis *axis,
lxw_chart_line *line);
/**
* @brief Set the line properties for the chart axis minor gridlines.
*
* @param axis A pointer to a chart #lxw_chart_axis object.
* @param line A #lxw_chart_line struct.
*
* Format the line properties of the minor gridlines of a chart, see the
* example above.
*
* For more information see @ref chart_lines.
*
* **Axis types**: This function is applicable to to all axes types.
* See @ref ww_charts_axes.
*/
void chart_axis_minor_gridlines_set_line(lxw_chart_axis *axis,
lxw_chart_line *line);
/**
* @brief Set the title of the chart.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param name The chart title name.
*
* The `%chart_title_set_name()` function sets the name (title) for the
* chart. The name is displayed above the chart.
*
* @code
* chart_title_set_name(chart, "Year End Results");
* @endcode
*
* @image html chart_title_set_name.png
*
* The name parameter can also be a formula such as `=Sheet1!$A$1` to point to
* a cell in the workbook that contains the name:
*
* @code
* chart_title_set_name(chart, "=Sheet1!$B$1");
* @endcode
*
* See also the `chart_title_set_name_range()` function to see how to set the
* name formula programmatically.
*
* The Excel default is to have no chart title.
*/
void chart_title_set_name(lxw_chart *chart, const char *name);
/**
* @brief Set a chart title formula using row and column values.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param sheetname The name of the worksheet that contains the cell range.
* @param row The zero indexed row number of the range.
* @param col The zero indexed column number of the range.
*
* The `%chart_title_set_name_range()` function can be used to set a chart
* title range and is an alternative to using `chart_title_set_name()` and a
* string formula:
*
* @code
* chart_title_set_name_range(chart, "Sheet1", 1, 0);
* @endcode
*/
void chart_title_set_name_range(lxw_chart *chart, const char *sheetname,
lxw_row_t row, lxw_col_t col);
/**
* @brief Set the font properties for a chart title.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param font A pointer to a chart #lxw_chart_font font struct.
*
* The `%chart_title_set_name_font()` function is used to set the font of a
* chart title:
*
* @code
* lxw_chart_font font = {.color = LXW_COLOR_BLUE};
*
* chart_title_set_name(chart, "Year End Results");
* chart_title_set_name_font(chart, &font);
* @endcode
*
* @image html chart_title_set_name_font.png
*
* In Excel a chart title font is bold by default (as shown in the image
* above). To turn off bold in the font you cannot use #LXW_FALSE (0) since
* that is indistinguishable from an uninitialized value. Instead you should
* use #LXW_EXPLICIT_FALSE:
*
* @code
* lxw_chart_font font = {.bold = LXW_EXPLICIT_FALSE, .color = LXW_COLOR_BLUE};
*
* chart_title_set_name(chart, "Year End Results");
* chart_title_set_name_font(chart, &font);
* @endcode
*
* @image html chart_title_set_name_font2.png
*
* For more information see @ref chart_fonts.
*/
void chart_title_set_name_font(lxw_chart *chart, lxw_chart_font *font);
/**
* @brief Turn off an automatic chart title.
*
* @param chart Pointer to a lxw_chart instance to be configured.
*
* In general in Excel a chart title isn't displayed unless the user
* explicitly adds one. However, Excel adds an automatic chart title to charts
* with a single series and a user defined series name. The
* `chart_title_off()` function allows you to turn off this automatic chart
* title:
*
* @code
* chart_title_off(chart);
* @endcode
*/
void chart_title_off(lxw_chart *chart);
/**
* @brief Set the position of the chart legend.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param position The #lxw_chart_legend_position value for the legend.
*
* The `%chart_legend_set_position()` function is used to set the chart
* legend to one of the #lxw_chart_legend_position values:
*
* LXW_CHART_LEGEND_NONE
* LXW_CHART_LEGEND_RIGHT
* LXW_CHART_LEGEND_LEFT
* LXW_CHART_LEGEND_TOP
* LXW_CHART_LEGEND_BOTTOM
* LXW_CHART_LEGEND_TOP_RIGHT
* LXW_CHART_LEGEND_OVERLAY_RIGHT
* LXW_CHART_LEGEND_OVERLAY_LEFT
* LXW_CHART_LEGEND_OVERLAY_TOP_RIGHT
*
* For example:
*
* @code
* chart_legend_set_position(chart, LXW_CHART_LEGEND_BOTTOM);
* @endcode
*
* @image html chart_legend_bottom.png
*
* This function can also be used to turn off a chart legend:
*
* @code
* chart_legend_set_position(chart, LXW_CHART_LEGEND_NONE);
* @endcode
*
* @image html chart_legend_none.png
*
*/
void chart_legend_set_position(lxw_chart *chart, uint8_t position);
/**
* @brief Set the font properties for a chart legend.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param font A pointer to a chart #lxw_chart_font font struct.
*
* The `%chart_legend_set_font()` function is used to set the font of a
* chart legend:
*
* @code
* lxw_chart_font font = {.bold = LXW_TRUE, .color = LXW_COLOR_BLUE};
*
* chart_legend_set_font(chart, &font);
* @endcode
*
* @image html chart_legend_set_font.png
*
* For more information see @ref chart_fonts.
*/
void chart_legend_set_font(lxw_chart *chart, lxw_chart_font *font);
/**
* @brief Remove one or more series from the the legend.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param delete_series An array of zero-indexed values to delete from series.
*
* @return A #lxw_error.
*
* The `%chart_legend_delete_series()` function allows you to remove/hide one
* or more series in a chart legend (the series will still display on the chart).
*
* This function takes an array of one or more zero indexed series
* numbers. The array should be terminated with -1.
*
* For example to remove the first and third zero-indexed series from the
* legend of a chart with 3 series:
*
* @code
* int16_t series[] = {0, 2, -1};
*
* chart_legend_delete_series(chart, series);
* @endcode
*
* @image html chart_legend_delete.png
*/
lxw_error chart_legend_delete_series(lxw_chart *chart,
int16_t delete_series[]);
/**
* @brief Set the line properties for a chartarea.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param line A #lxw_chart_line struct.
*
* Set the line/border properties of a chartarea. In Excel the chartarea
* is the background area behind the chart:
*
* @code
* lxw_chart_line line = {.none = LXW_TRUE};
* lxw_chart_fill fill = {.color = LXW_COLOR_RED};
*
* chart_chartarea_set_line(chart, &line);
* chart_chartarea_set_fill(chart, &fill);
* @endcode
*
* @image html chart_chartarea.png
*
* For more information see @ref chart_lines.
*/
void chart_chartarea_set_line(lxw_chart *chart, lxw_chart_line *line);
/**
* @brief Set the fill properties for a chartarea.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param fill A #lxw_chart_fill struct.
*
* Set the fill properties of a chartarea:
*
* @code
* chart_chartarea_set_fill(chart, &fill);
* @endcode
*
* See the example and image above.
*
* For more information see @ref chart_fills.
*/
void chart_chartarea_set_fill(lxw_chart *chart, lxw_chart_fill *fill);
/**
* @brief Set the pattern properties for a chartarea.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param pattern A #lxw_chart_pattern struct.
*
* Set the pattern properties of a chartarea:
*
* @code
* chart_chartarea_set_pattern(series1, &pattern);
* @endcode
*
* For more information see #lxw_chart_pattern_type and @ref chart_patterns.
*/
void chart_chartarea_set_pattern(lxw_chart *chart,
lxw_chart_pattern *pattern);
/**
* @brief Set the line properties for a plotarea.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param line A #lxw_chart_line struct.
*
* Set the line/border properties of a plotarea. In Excel the plotarea is
* the area between the axes on which the chart series are plotted:
*
* @code
* lxw_chart_line line = {.color = LXW_COLOR_RED,
* .width = 2,
* .dash_type = LXW_CHART_LINE_DASH_DASH};
* lxw_chart_fill fill = {.color = 0xFFFFC2};
*
* chart_plotarea_set_line(chart, &line);
* chart_plotarea_set_fill(chart, &fill);
*
* @endcode
*
* @image html chart_plotarea.png
*
* For more information see @ref chart_lines.
*/
void chart_plotarea_set_line(lxw_chart *chart, lxw_chart_line *line);
/**
* @brief Set the fill properties for a plotarea.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param fill A #lxw_chart_fill struct.
*
* Set the fill properties of a plotarea:
*
* @code
* chart_plotarea_set_fill(chart, &fill);
* @endcode
*
* See the example and image above.
*
* For more information see @ref chart_fills.
*/
void chart_plotarea_set_fill(lxw_chart *chart, lxw_chart_fill *fill);
/**
* @brief Set the pattern properties for a plotarea.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param pattern A #lxw_chart_pattern struct.
*
* Set the pattern properties of a plotarea:
*
* @code
* chart_plotarea_set_pattern(series1, &pattern);
* @endcode
*
* For more information see #lxw_chart_pattern_type and @ref chart_patterns.
*/
void chart_plotarea_set_pattern(lxw_chart *chart, lxw_chart_pattern *pattern);
/**
* @brief Set the chart style type.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param style_id An index representing the chart style, 1 - 48.
*
* The `%chart_set_style()` function is used to set the style of the chart to
* one of the 48 built-in styles available on the "Design" tab in Excel 2007:
*
* @code
* chart_set_style(chart, 37)
* @endcode
*
* @image html chart_style.png
*
* The style index number is counted from 1 on the top left in the Excel
* dialog. The default style is 2.
*
* **Note:**
*
* In Excel 2013 the Styles section of the "Design" tab in Excel shows what
* were referred to as "Layouts" in previous versions of Excel. These layouts
* are not defined in the file format. They are a collection of modifications
* to the base chart type. They can not be defined by the `chart_set_style()``
* function.
*
*/
void chart_set_style(lxw_chart *chart, uint8_t style_id);
/**
* @brief Turn on a data table below the horizontal axis.
*
* @param chart Pointer to a lxw_chart instance to be configured.
*
* The `%chart_set_table()` function adds a data table below the horizontal
* axis with the data used to plot the chart:
*
* @code
* // Turn on the data table with default options.
* chart_set_table(chart);
* @endcode
*
* @image html chart_data_table1.png
*
* The data table can only be shown with Bar, Column, Line and Area charts.
*
*/
void chart_set_table(lxw_chart *chart);
/**
* @brief Turn on/off grid options for a chart data table.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param horizontal Turn on/off the horizontal grid lines in the table.
* @param vertical Turn on/off the vertical grid lines in the table.
* @param outline Turn on/off the outline lines in the table.
* @param legend_keys Turn on/off the legend keys in the table.
*
* The `%chart_set_table_grid()` function turns on/off grid options for a
* chart data table. The data table grid options in Excel are shown in the
* dialog below:
*
* @image html chart_data_table3.png
*
* These options can be passed to the `%chart_set_table_grid()` function.
* The values for a default chart are:
*
* - `horizontal`: On.
* - `vertical`: On.
* - `outline`: On.
* - `legend_keys`: Off.
*
* Example:
*
* @code
* // Turn on the data table with default options.
* chart_set_table(chart);
*
* // Turn on all grid lines and the grid legend.
* chart_set_table_grid(chart, LXW_TRUE, LXW_TRUE, LXW_TRUE, LXW_TRUE);
*
* // Turn off the legend since it is show in the table.
* chart_legend_set_position(chart, LXW_CHART_LEGEND_NONE);
*
* @endcode
*
* @image html chart_data_table2.png
*
* The data table can only be shown with Bar, Column, Line and Area charts.
*
*/
void chart_set_table_grid(lxw_chart *chart, uint8_t horizontal,
uint8_t vertical, uint8_t outline,
uint8_t legend_keys);
void chart_set_table_font(lxw_chart *chart, lxw_chart_font *font);
/**
* @brief Turn on up-down bars for the chart.
*
* @param chart Pointer to a lxw_chart instance to be configured.
*
* The `%chart_set_up_down_bars()` function adds Up-Down bars to Line charts
* to indicate the difference between the first and last data series:
*
* @code
* chart_set_up_down_bars(chart);
* @endcode
*
* @image html chart_data_tools4.png
*
* Up-Down bars are only available in Line charts. By default Up-Down bars are
* black and white like in the above example. To format the border or fill
* of the bars see the `chart_set_up_down_bars_format()` function below.
*/
void chart_set_up_down_bars(lxw_chart *chart);
/**
* @brief Turn on up-down bars for the chart, with formatting.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param up_bar_line A #lxw_chart_line struct for the up-bar border.
* @param up_bar_fill A #lxw_chart_fill struct for the up-bar fill.
* @param down_bar_line A #lxw_chart_line struct for the down-bar border.
* @param down_bar_fill A #lxw_chart_fill struct for the down-bar fill.
*
* The `%chart_set_up_down_bars_format()` function adds Up-Down bars to Line
* charts to indicate the difference between the first and last data series.
* It also allows the up and down bars to be formatted:
*
* @code
* lxw_chart_line line = {.color = LXW_COLOR_BLACK};
* lxw_chart_fill up_fill = {.color = 0x00B050};
* lxw_chart_fill down_fill = {.color = LXW_COLOR_RED};
*
* chart_set_up_down_bars_format(chart, &line, &up_fill, &line, &down_fill);
* @endcode
*
* @image html chart_up_down_bars.png
*
* Up-Down bars are only available in Line charts.
* For more format information see @ref chart_lines and @ref chart_fills.
*/
void chart_set_up_down_bars_format(lxw_chart *chart,
lxw_chart_line *up_bar_line,
lxw_chart_fill *up_bar_fill,
lxw_chart_line *down_bar_line,
lxw_chart_fill *down_bar_fill);
/**
* @brief Turn on and format Drop Lines for a chart.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param line A #lxw_chart_line struct.
*
* The `%chart_set_drop_lines()` function adds Drop Lines to charts to
* show the Category value of points in the data:
*
* @code
* chart_set_drop_lines(chart, NULL);
* @endcode
*
* @image html chart_data_tools6.png
*
* It is possible to format the Drop Line line properties if required:
*
* @code
* lxw_chart_line line = {.color = LXW_COLOR_RED,
* .dash_type = LXW_CHART_LINE_DASH_SQUARE_DOT};
*
* chart_set_drop_lines(chart, &line);
* @endcode
*
* Drop Lines are only available in Line and Area charts.
* For more format information see @ref chart_lines.
*/
void chart_set_drop_lines(lxw_chart *chart, lxw_chart_line *line);
/**
* @brief Turn on and format high-low Lines for a chart.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param line A #lxw_chart_line struct.
*
* The `%chart_set_high_low_lines()` function adds High-Low Lines to charts
* to show the Category value of points in the data:
*
* @code
* chart_set_high_low_lines(chart, NULL);
* @endcode
*
* @image html chart_data_tools5.png
*
* It is possible to format the High-Low Line line properties if required:
*
* @code
* lxw_chart_line line = {.color = LXW_COLOR_RED,
* .dash_type = LXW_CHART_LINE_DASH_SQUARE_DOT};
*
* chart_set_high_low_lines(chart, &line);
* @endcode
*
* High-Low Lines are only available in Line charts.
* For more format information see @ref chart_lines.
*/
void chart_set_high_low_lines(lxw_chart *chart, lxw_chart_line *line);
/**
* @brief Set the overlap between series in a Bar/Column chart.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param overlap The overlap between the series. -100 to 100.
*
* The `%chart_set_series_overlap()` function sets the overlap between series
* in Bar and Column charts.
*
* @code
* chart_set_series_overlap(chart, -50);
* @endcode
*
* @image html chart_overlap.png
*
* The overlap value must be in the range `0 <= overlap <= 500`.
* The default value is 0.
*
* This option is only available for Bar/Column charts.
*/
void chart_set_series_overlap(lxw_chart *chart, int8_t overlap);
/**
* @brief Set the gap between series in a Bar/Column chart.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param gap The gap between the series. 0 to 500.
*
* The `%chart_set_series_gap()` function sets the gap between series in
* Bar and Column charts.
*
* @code
* chart_set_series_gap(chart, 400);
* @endcode
*
* @image html chart_gap.png
*
* The gap value must be in the range `0 <= gap <= 500`. The default value
* is 150.
*
* This option is only available for Bar/Column charts.
*/
void chart_set_series_gap(lxw_chart *chart, uint16_t gap);
/**
* @brief Set the option for displaying blank data in a chart.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param option The display option. A #lxw_chart_blank option.
*
* The `%chart_show_blanks_as()` function controls how blank data is displayed
* in a chart:
*
* @code
* chart_show_blanks_as(chart, LXW_CHART_BLANKS_AS_CONNECTED);
* @endcode
*
* The `option` parameter can have one of the following values:
*
* - #LXW_CHART_BLANKS_AS_GAP: Show empty chart cells as gaps in the data.
* This is the default option for Excel charts.
* - #LXW_CHART_BLANKS_AS_ZERO: Show empty chart cells as zeros.
* - #LXW_CHART_BLANKS_AS_CONNECTED: Show empty chart cells as connected.
* Only for charts with lines.
*/
void chart_show_blanks_as(lxw_chart *chart, uint8_t option);
/**
* @brief Display data on charts from hidden rows or columns.
*
* @param chart Pointer to a lxw_chart instance to be configured.
*
* Display data that is in hidden rows or columns on the chart:
*
* @code
* chart_show_hidden_data(chart);
* @endcode
*/
void chart_show_hidden_data(lxw_chart *chart);
/**
* @brief Set the Pie/Doughnut chart rotation.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param rotation The angle of rotation.
*
* The `chart_set_rotation()` function is used to set the rotation of the
* first segment of a Pie/Doughnut chart. This has the effect of rotating
* the entire chart:
*
* @code
* chart_set_rotation(chart, 28);
* @endcode
*
* The angle of rotation must be in the range `0 <= rotation <= 360`.
*
* This option is only available for Pie/Doughnut charts.
*
*/
void chart_set_rotation(lxw_chart *chart, uint16_t rotation);
/**
* @brief Set the Doughnut chart hole size.
*
* @param chart Pointer to a lxw_chart instance to be configured.
* @param size The hole size as a percentage.
*
* The `chart_set_hole_size()` function is used to set the hole size of a
* Doughnut chart:
*
* @code
* chart_set_hole_size(chart, 33);
* @endcode
*
* The hole size must be in the range `10 <= size <= 90`.
*
* This option is only available for Doughnut charts.
*
*/
void chart_set_hole_size(lxw_chart *chart, uint8_t size);
lxw_error lxw_chart_add_data_cache(lxw_series_range *range, uint8_t *data,
uint16_t rows, uint8_t cols, uint8_t col);
/* Declarations required for unit testing. */
#ifdef TESTING
STATIC void _chart_xml_declaration(lxw_chart *chart);
STATIC void _chart_write_legend(lxw_chart *chart);
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_CHART_H__ */
writexl/src/include/xlsxwriter/table.h 0000644 0001762 0000144 00000001521 14747162622 017667 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* table - A libxlsxwriter library for creating Excel XLSX table files.
*
*/
#ifndef __LXW_TABLE_H__
#define __LXW_TABLE_H__
#include
#include "common.h"
/*
* Struct to represent a table object.
*/
typedef struct lxw_table {
FILE *file;
struct lxw_table_obj *table_obj;
} lxw_table;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
lxw_table *lxw_table_new(void);
void lxw_table_free(lxw_table *table);
void lxw_table_assemble_xml_file(lxw_table *self);
/* Declarations required for unit testing. */
#ifdef TESTING
STATIC void _table_xml_declaration(lxw_table *self);
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_TABLE_H__ */
writexl/src/include/xlsxwriter/styles.h 0000644 0001762 0000144 00000005272 14747162622 020132 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* styles - A libxlsxwriter library for creating Excel XLSX styles files.
*
*/
#ifndef __LXW_STYLES_H__
#define __LXW_STYLES_H__
#include
#include
#include "format.h"
/*
* Struct to represent a styles.
*/
typedef struct lxw_styles {
FILE *file;
uint32_t font_count;
uint32_t xf_count;
uint32_t dxf_count;
uint32_t num_format_count;
uint32_t border_count;
uint32_t fill_count;
struct lxw_formats *xf_formats;
struct lxw_formats *dxf_formats;
uint8_t has_hyperlink;
uint16_t hyperlink_font_id;
uint8_t has_comments;
} lxw_styles;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
lxw_styles *lxw_styles_new(void);
void lxw_styles_free(lxw_styles *styles);
void lxw_styles_assemble_xml_file(lxw_styles *self);
void lxw_styles_write_string_fragment(lxw_styles *self, const char *string);
void lxw_styles_write_rich_font(lxw_styles *styles, lxw_format *format);
/* Declarations required for unit testing. */
#ifdef TESTING
STATIC void _styles_xml_declaration(lxw_styles *self);
STATIC void _write_style_sheet(lxw_styles *self);
STATIC void _write_font_size(lxw_styles *self, double font_size);
STATIC void _write_font_color_theme(lxw_styles *self, uint8_t theme);
STATIC void _write_font_name(lxw_styles *self, const char *font_name,
uint8_t is_rich_string);
STATIC void _write_font_family(lxw_styles *self, uint8_t font_family);
STATIC void _write_font_scheme(lxw_styles *self, const char *font_scheme);
STATIC void _write_font(lxw_styles *self, lxw_format *format, uint8_t is_dxf,
uint8_t is_rich_string);
STATIC void _write_fonts(lxw_styles *self);
STATIC void _write_default_fill(lxw_styles *self, const char *pattern);
STATIC void _write_fills(lxw_styles *self);
STATIC void _write_border(lxw_styles *self, lxw_format *format,
uint8_t is_dxf);
STATIC void _write_borders(lxw_styles *self);
STATIC void _write_style_xf(lxw_styles *self, uint8_t has_hyperlink,
uint16_t font_id);
STATIC void _write_cell_style_xfs(lxw_styles *self);
STATIC void _write_xf(lxw_styles *self, lxw_format *format);
STATIC void _write_cell_xfs(lxw_styles *self);
STATIC void _write_cell_style(lxw_styles *self, char *name, uint8_t xf_id,
uint8_t builtin_id);
STATIC void _write_cell_styles(lxw_styles *self);
STATIC void _write_dxfs(lxw_styles *self);
STATIC void _write_table_styles(lxw_styles *self);
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_STYLES_H__ */
writexl/src/include/xlsxwriter/custom.h 0000644 0001762 0000144 00000001626 14747162622 020120 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* custom - A libxlsxwriter library for creating Excel custom property files.
*
*/
#ifndef __LXW_CUSTOM_H__
#define __LXW_CUSTOM_H__
#include
#include "common.h"
/*
* Struct to represent a custom property file object.
*/
typedef struct lxw_custom {
FILE *file;
struct lxw_custom_properties *custom_properties;
uint32_t pid;
} lxw_custom;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
lxw_custom *lxw_custom_new(void);
void lxw_custom_free(lxw_custom *custom);
void lxw_custom_assemble_xml_file(lxw_custom *self);
/* Declarations required for unit testing. */
#ifdef TESTING
STATIC void _custom_xml_declaration(lxw_custom *self);
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_CUSTOM_H__ */
writexl/src/include/xlsxwriter/relationships.h 0000644 0001762 0000144 00000003552 14747162622 021472 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* relationships - A libxlsxwriter library for creating Excel XLSX
* relationships files.
*
*/
#ifndef __LXW_RELATIONSHIPS_H__
#define __LXW_RELATIONSHIPS_H__
#include
#include "common.h"
/* Define the queue.h STAILQ structs for the generic data structs. */
STAILQ_HEAD(lxw_rel_tuples, lxw_rel_tuple);
typedef struct lxw_rel_tuple {
char *type;
char *target;
char *target_mode;
STAILQ_ENTRY (lxw_rel_tuple) list_pointers;
} lxw_rel_tuple;
/*
* Struct to represent a relationships.
*/
typedef struct lxw_relationships {
FILE *file;
uint32_t rel_id;
struct lxw_rel_tuples *relationships;
} lxw_relationships;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
lxw_relationships *lxw_relationships_new(void);
void lxw_free_relationships(lxw_relationships *relationships);
void lxw_relationships_assemble_xml_file(lxw_relationships *self);
void lxw_add_document_relationship(lxw_relationships *self, const char *type,
const char *target);
void lxw_add_package_relationship(lxw_relationships *self, const char *type,
const char *target);
void lxw_add_ms_package_relationship(lxw_relationships *self,
const char *type, const char *target);
void lxw_add_worksheet_relationship(lxw_relationships *self, const char *type,
const char *target,
const char *target_mode);
/* Declarations required for unit testing. */
#ifdef TESTING
STATIC void _relationships_xml_declaration(lxw_relationships *self);
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_RELATIONSHIPS_H__ */
writexl/src/include/xlsxwriter/third_party/ 0000755 0001762 0000144 00000000000 14747162622 020761 5 ustar ligges users writexl/src/include/xlsxwriter/third_party/ioapi.h 0000644 0001762 0000144 00000016072 14747162622 022241 0 ustar ligges users /* ioapi.h -- IO base function header for compress/uncompress .zip
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
Modifications for Zip64 support
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
For more info read MiniZip_info.txt
Changes
Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this)
Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux.
More if/def section may be needed to support other platforms
Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows.
(but you should use iowin32.c for windows instead)
*/
/* Pragma added by libxlsxwriter to avoid warnings with -pedantic -ansi. */
#ifndef _WIN32
#pragma GCC system_header
#endif
#ifndef _ZLIBIOAPI64_H
#define _ZLIBIOAPI64_H
#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
// Linux needs this to support file operation on files larger then 4+GB
// But might need better if/def to select just the platforms that needs them.
#ifndef __USE_FILE_OFFSET64
#define __USE_FILE_OFFSET64
#endif
#ifndef __USE_LARGEFILE64
#define __USE_LARGEFILE64
#endif
#ifndef _LARGEFILE64_SOURCE
#define _LARGEFILE64_SOURCE
#endif
#ifndef _FILE_OFFSET_BIT
#define _FILE_OFFSET_BIT 64
#endif
#endif
#include
#include
#include "zlib.h"
#if defined(USE_FILE32API)
#define fopen64 fopen
#define ftello64 ftell
#define fseeko64 fseek
#else
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64)
#define fopen64 fopen
#define ftello64 ftello
#define fseeko64 fseeko
#endif
#ifdef _MSC_VER
#define fopen64 fopen
#if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
#define ftello64 _ftelli64
#define fseeko64 _fseeki64
#else // old MSC
#define ftello64 ftell
#define fseeko64 fseek
#endif
#endif
#endif
/*
#ifndef ZPOS64_T
#ifdef _WIN32
#define ZPOS64_T fpos_t
#else
#include
#define ZPOS64_T uint64_t
#endif
#endif
*/
#ifdef HAVE_MINIZIP64_CONF_H
#include "mz64conf.h"
#endif
/* a type chosen by DEFINE */
#ifdef HAVE_64BIT_INT_CUSTOM
typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T;
#else
#ifdef HAS_STDINT_H
#include "stdint.h"
typedef uint64_t ZPOS64_T;
#else
#if defined(_MSC_VER) || defined(__BORLANDC__)
typedef unsigned __int64 ZPOS64_T;
#else
typedef unsigned long long int ZPOS64_T;
#endif
#endif
#endif
/* Maximum unsigned 32-bit value used as placeholder for zip64 */
#ifndef MAXU32
#define MAXU32 (0xffffffff)
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define ZLIB_FILEFUNC_SEEK_CUR (1)
#define ZLIB_FILEFUNC_SEEK_END (2)
#define ZLIB_FILEFUNC_SEEK_SET (0)
#define ZLIB_FILEFUNC_MODE_READ (1)
#define ZLIB_FILEFUNC_MODE_WRITE (2)
#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
#define ZLIB_FILEFUNC_MODE_EXISTING (4)
#define ZLIB_FILEFUNC_MODE_CREATE (8)
#ifndef ZCALLBACK
#if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
#define ZCALLBACK CALLBACK
#else
#define ZCALLBACK
#endif
#endif
typedef voidpf (ZCALLBACK *open_file_func) (voidpf opaque, const char* filename, int mode);
typedef uLong (ZCALLBACK *read_file_func) (voidpf opaque, voidpf stream, void* buf, uLong size);
typedef uLong (ZCALLBACK *write_file_func) (voidpf opaque, voidpf stream, const void* buf, uLong size);
typedef int (ZCALLBACK *close_file_func) (voidpf opaque, voidpf stream);
typedef int (ZCALLBACK *testerror_file_func) (voidpf opaque, voidpf stream);
typedef long (ZCALLBACK *tell_file_func) (voidpf opaque, voidpf stream);
typedef long (ZCALLBACK *seek_file_func) (voidpf opaque, voidpf stream, uLong offset, int origin);
/* here is the "old" 32 bits structure */
typedef struct zlib_filefunc_def_s
{
open_file_func zopen_file;
read_file_func zread_file;
write_file_func zwrite_file;
tell_file_func ztell_file;
seek_file_func zseek_file;
close_file_func zclose_file;
testerror_file_func zerror_file;
voidpf opaque;
} zlib_filefunc_def;
typedef ZPOS64_T (ZCALLBACK *tell64_file_func) (voidpf opaque, voidpf stream);
typedef long (ZCALLBACK *seek64_file_func) (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin);
typedef voidpf (ZCALLBACK *open64_file_func) (voidpf opaque, const void* filename, int mode);
typedef struct zlib_filefunc64_def_s
{
open64_file_func zopen64_file;
read_file_func zread_file;
write_file_func zwrite_file;
tell64_file_func ztell64_file;
seek64_file_func zseek64_file;
close_file_func zclose_file;
testerror_file_func zerror_file;
voidpf opaque;
} zlib_filefunc64_def;
void fill_fopen64_filefunc(zlib_filefunc64_def* pzlib_filefunc_def);
void fill_fopen_filefunc(zlib_filefunc_def* pzlib_filefunc_def);
/* now internal definition, only for zip.c and unzip.h */
typedef struct zlib_filefunc64_32_def_s
{
zlib_filefunc64_def zfile_func64;
open_file_func zopen32_file;
tell_file_func ztell32_file;
seek_file_func zseek32_file;
} zlib_filefunc64_32_def;
#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))
//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))
#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream))
#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream))
voidpf call_zopen64(const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode);
long call_zseek64(const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin);
ZPOS64_T call_ztell64(const zlib_filefunc64_32_def* pfilefunc,voidpf filestream);
void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32);
#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode)))
#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream)))
#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
#ifdef __cplusplus
}
#endif
#endif
writexl/src/include/xlsxwriter/third_party/zip.h 0000644 0001762 0000144 00000036635 14747162622 021751 0 ustar ligges users /* zip.h -- IO on .zip files using zlib
Version 1.1, February 14h, 2010
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
Modifications for Zip64 support
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
For more info read MiniZip_info.txt
---------------------------------------------------------------------------
Condition of use and distribution are the same than zlib :
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
---------------------------------------------------------------------------
Changes
See header of zip.h
*/
/* Pragma added by libxlsxwriter to avoid warnings with -pedantic -ansi. */
#ifndef _WIN32
#pragma GCC system_header
#endif
#ifndef _zip12_H
#define _zip12_H
#ifdef __cplusplus
extern "C" {
#endif
//#define HAVE_BZIP2
#ifndef _ZLIB_H
#include "zlib.h"
#endif
#ifndef _ZLIBIOAPI_H
#include "ioapi.h"
#endif
/* Encryption not required by libxlsxwriter. */
#ifndef NOCRYPT
#define NOCRYPT
#endif
#ifndef NOUNCRYPT
#define NOUNCRYPT
#endif
#ifdef HAVE_BZIP2
#include "bzlib.h"
#endif
#define Z_BZIP2ED 12
#if defined(STRICTZIP) || defined(STRICTZIPUNZIP)
/* like the STRICT of WIN32, we define a pointer that cannot be converted
from (void*) without cast */
typedef struct TagzipFile__ { int unused; } zipFile__;
typedef zipFile__ *zipFile;
#else
typedef voidp zipFile;
#endif
#define ZIP_OK (0)
#define ZIP_EOF (0)
#define ZIP_ERRNO (Z_ERRNO)
#define ZIP_PARAMERROR (-102)
#define ZIP_BADZIPFILE (-103)
#define ZIP_INTERNALERROR (-104)
#ifndef DEF_MEM_LEVEL
# if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
# else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
# endif
#endif
/* default memLevel */
/* tm_zip contain date/time info */
typedef struct tm_zip_s
{
int tm_sec; /* seconds after the minute - [0,59] */
int tm_min; /* minutes after the hour - [0,59] */
int tm_hour; /* hours since midnight - [0,23] */
int tm_mday; /* day of the month - [1,31] */
int tm_mon; /* months since January - [0,11] */
int tm_year; /* years - [1980..2044] */
} tm_zip;
typedef struct
{
tm_zip tmz_date; /* date in understandable format */
uLong dosDate; /* if dos_date == 0, tmu_date is used */
/* uLong flag; */ /* general purpose bit flag 2 bytes */
uLong internal_fa; /* internal file attributes 2 bytes */
uLong external_fa; /* external file attributes 4 bytes */
} zip_fileinfo;
typedef const char* zipcharpc;
#define APPEND_STATUS_CREATE (0)
#define APPEND_STATUS_CREATEAFTER (1)
#define APPEND_STATUS_ADDINZIP (2)
extern zipFile ZEXPORT zipOpen(const char *pathname, int append);
extern zipFile ZEXPORT zipOpen64(const void *pathname, int append);
/*
Create a zipfile.
pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on
an Unix computer "zlib/zlib113.zip".
if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip
will be created at the end of the file.
(useful if the file contain a self extractor code)
if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will
add files in existing zip (be sure you don't add file that doesn't exist)
If the zipfile cannot be opened, the return value is NULL.
Else, the return value is a zipFile Handle, usable with other function
of this zip package.
*/
/* Note : there is no delete function into a zipfile.
If you want delete file into a zipfile, you must open a zipfile, and create another
Of course, you can use RAW reading and writing to copy the file you did not want delete
*/
extern zipFile ZEXPORT zipOpen2(const char *pathname,
int append,
zipcharpc* globalcomment,
zlib_filefunc_def* pzlib_filefunc_def);
extern zipFile ZEXPORT zipOpen2_64(const void *pathname,
int append,
zipcharpc* globalcomment,
zlib_filefunc64_def* pzlib_filefunc_def);
extern zipFile ZEXPORT zipOpen3(const void *pathname,
int append,
zipcharpc* globalcomment,
zlib_filefunc64_32_def* pzlib_filefunc64_32_def);
extern int ZEXPORT zipOpenNewFileInZip(zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level);
extern int ZEXPORT zipOpenNewFileInZip64(zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int zip64);
/*
Open a file in the ZIP for writing.
filename : the filename in zip (if NULL, '-' without quote will be used
*zipfi contain supplemental information
if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local
contains the extrafield data for the local header
if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global
contains the extrafield data for the global header
if comment != NULL, comment contain the comment string
method contain the compression method (0 for store, Z_DEFLATED for deflate)
level contain the level of compression (can be Z_DEFAULT_COMPRESSION)
zip64 is set to 1 if a zip64 extended information block should be added to the local file header.
this MUST be '1' if the uncompressed size is >= 0xffffffff.
*/
extern int ZEXPORT zipOpenNewFileInZip2(zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw);
extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw,
int zip64);
/*
Same than zipOpenNewFileInZip, except if raw=1, we write raw file
*/
extern int ZEXPORT zipOpenNewFileInZip3(zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw,
int windowBits,
int memLevel,
int strategy,
const char* password,
uLong crcForCrypting);
extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw,
int windowBits,
int memLevel,
int strategy,
const char* password,
uLong crcForCrypting,
int zip64);
/*
Same than zipOpenNewFileInZip2, except
windowBits,memLevel,,strategy : see parameter strategy in deflateInit2
password : crypting password (NULL for no crypting)
crcForCrypting : crc of file to compress (needed for crypting)
*/
extern int ZEXPORT zipOpenNewFileInZip4(zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw,
int windowBits,
int memLevel,
int strategy,
const char* password,
uLong crcForCrypting,
uLong versionMadeBy,
uLong flagBase);
extern int ZEXPORT zipOpenNewFileInZip4_64(zipFile file,
const char* filename,
const zip_fileinfo* zipfi,
const void* extrafield_local,
uInt size_extrafield_local,
const void* extrafield_global,
uInt size_extrafield_global,
const char* comment,
int method,
int level,
int raw,
int windowBits,
int memLevel,
int strategy,
const char* password,
uLong crcForCrypting,
uLong versionMadeBy,
uLong flagBase,
int zip64);
/*
Same than zipOpenNewFileInZip4, except
versionMadeBy : value for Version made by field
flag : value for flag field (compression level info will be added)
*/
extern int ZEXPORT zipWriteInFileInZip(zipFile file,
const void* buf,
unsigned len);
/*
Write data in the zipfile
*/
extern int ZEXPORT zipCloseFileInZip(zipFile file);
/*
Close the current file in the zipfile
*/
extern int ZEXPORT zipCloseFileInZipRaw(zipFile file,
uLong uncompressed_size,
uLong crc32);
extern int ZEXPORT zipCloseFileInZipRaw64(zipFile file,
ZPOS64_T uncompressed_size,
uLong crc32);
/*
Close the current file in the zipfile, for file opened with
parameter raw=1 in zipOpenNewFileInZip2
uncompressed_size and crc32 are value for the uncompressed size
*/
extern int ZEXPORT zipClose(zipFile file,
const char* global_comment);
/*
Close the zipfile
*/
extern int ZEXPORT zipRemoveExtraInfoBlock(char* pData, int* dataLen, short sHeader);
/*
zipRemoveExtraInfoBlock - Added by Mathias Svensson
Remove extra information block from a extra information data for the local file header or central directory header
It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode.
0x0001 is the signature header for the ZIP64 extra information blocks
usage.
Remove ZIP64 Extra information from a central director extra field data
zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001);
Remove ZIP64 Extra information from a Local File Header extra field data
zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001);
*/
#ifdef __cplusplus
}
#endif
#endif /* _zip64_H */
writexl/src/include/xlsxwriter/third_party/tree.h 0000644 0001762 0000144 00000065454 14747162622 022107 0 ustar ligges users /* $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ */
/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */
/* $FreeBSD$ */
/*-
* Copyright 2002 Niels Provos
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SYS_TREE_H_
#define _SYS_TREE_H_
/* #include */
/*
* This file defines data structures for different types of trees:
* splay trees and red-black trees.
*
* A splay tree is a self-organizing data structure. Every operation
* on the tree causes a splay to happen. The splay moves the requested
* node to the root of the tree and partly rebalances it.
*
* This has the benefit that request locality causes faster lookups as
* the requested nodes move to the top of the tree. On the other hand,
* every lookup causes memory writes.
*
* The Balance Theorem bounds the total access time for m operations
* and n inserts on an initially empty tree as O((m + n)lg n). The
* amortized cost for a sequence of m accesses to a splay tree is O(lg n);
*
* A red-black tree is a binary search tree with the node color as an
* extra attribute. It fulfills a set of conditions:
* - every search path from the root to a leaf consists of the
* same number of black nodes,
* - each red node (except for the root) has a black parent,
* - each leaf node is black.
*
* Every operation on a red-black tree is bounded as O(lg n).
* The maximum height of a red-black tree is 2lg (n+1).
*/
#define SPLAY_HEAD(name, type) \
struct name { \
struct type *sph_root; /* root of the tree */ \
}
#define SPLAY_INITIALIZER(root) \
{ NULL }
#define SPLAY_INIT(root) do { \
(root)->sph_root = NULL; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ENTRY(type) \
struct { \
struct type *spe_left; /* left element */ \
struct type *spe_right; /* right element */ \
}
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
#define SPLAY_ROOT(head) (head)->sph_root
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_LINKLEFT(head, tmp, field) do { \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
} while (/*CONSTCOND*/ 0)
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
} while (/*CONSTCOND*/ 0)
/* Generates prototypes and inline functions */
#define SPLAY_PROTOTYPE(name, type, field, cmp) \
void name##_SPLAY(struct name *, struct type *); \
void name##_SPLAY_MINMAX(struct name *, int); \
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
\
/* Finds the node with the same key as elm */ \
static __inline struct type * \
name##_SPLAY_FIND(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) \
return(NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) \
return (head->sph_root); \
return (NULL); \
} \
\
static __inline struct type * \
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
{ \
name##_SPLAY(head, elm); \
if (SPLAY_RIGHT(elm, field) != NULL) { \
elm = SPLAY_RIGHT(elm, field); \
while (SPLAY_LEFT(elm, field) != NULL) { \
elm = SPLAY_LEFT(elm, field); \
} \
} else \
elm = NULL; \
return (elm); \
} \
\
static __inline struct type * \
name##_SPLAY_MIN_MAX(struct name *head, int val) \
{ \
name##_SPLAY_MINMAX(head, val); \
return (SPLAY_ROOT(head)); \
}
/* Main splay operation.
* Moves node close to the key of elm to top
*/
#define SPLAY_GENERATE(name, type, field, cmp) \
struct type * \
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) { \
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
} else { \
int __comp; \
name##_SPLAY(head, elm); \
__comp = (cmp)(elm, (head)->sph_root); \
if(__comp < 0) { \
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
SPLAY_LEFT((head)->sph_root, field) = NULL; \
} else if (__comp > 0) { \
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT(elm, field) = (head)->sph_root; \
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
} else \
return ((head)->sph_root); \
} \
(head)->sph_root = (elm); \
return (NULL); \
} \
\
struct type * \
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *__tmp; \
if (SPLAY_EMPTY(head)) \
return (NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) { \
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
} else { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
name##_SPLAY(head, elm); \
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
} \
return (elm); \
} \
return (NULL); \
} \
\
void \
name##_SPLAY(struct name *head, struct type *elm) \
{ \
struct type __node, *__left, *__right, *__tmp; \
int __comp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) > 0){ \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
} \
\
/* Splay with either the minimum or the maximum element \
* Used to find minimum or maximum element in tree. \
*/ \
void name##_SPLAY_MINMAX(struct name *head, int __comp) \
{ \
struct type __node, *__left, *__right, *__tmp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while (1) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp > 0) { \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
}
#define SPLAY_NEGINF -1
#define SPLAY_INF 1
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
#define SPLAY_FOREACH(x, name, head) \
for ((x) = SPLAY_MIN(name, head); \
(x) != NULL; \
(x) = SPLAY_NEXT(name, head, x))
/* Macros that define a red-black tree */
#define RB_HEAD(name, type) \
struct name { \
struct type *rbh_root; /* root of the tree */ \
}
#define RB_INITIALIZER(root) \
{ NULL }
#define RB_INIT(root) do { \
(root)->rbh_root = NULL; \
} while (/*CONSTCOND*/ 0)
#define RB_BLACK 0
#define RB_RED 1
#define RB_ENTRY(type) \
struct { \
struct type *rbe_left; /* left element */ \
struct type *rbe_right; /* right element */ \
struct type *rbe_parent; /* parent element */ \
int rbe_color; /* node color */ \
}
#define RB_LEFT(elm, field) (elm)->field.rbe_left
#define RB_RIGHT(elm, field) (elm)->field.rbe_right
#define RB_PARENT(elm, field) (elm)->field.rbe_parent
#define RB_COLOR(elm, field) (elm)->field.rbe_color
#define RB_ROOT(head) (head)->rbh_root
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
#define RB_SET(elm, parent, field) do { \
RB_PARENT(elm, field) = parent; \
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
RB_COLOR(elm, field) = RB_RED; \
} while (/*CONSTCOND*/ 0)
#define RB_SET_BLACKRED(black, red, field) do { \
RB_COLOR(black, field) = RB_BLACK; \
RB_COLOR(red, field) = RB_RED; \
} while (/*CONSTCOND*/ 0)
#ifndef RB_AUGMENT
#define RB_AUGMENT(x) do {} while (0)
#endif
#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
(tmp) = RB_RIGHT(elm, field); \
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_LEFT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (/*CONSTCOND*/ 0)
#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
(tmp) = RB_LEFT(elm, field); \
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_RIGHT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (/*CONSTCOND*/ 0)
/* Generates prototypes and inline functions */
#define RB_PROTOTYPE(name, type, field, cmp) \
RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static)
#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
RB_PROTOTYPE_INSERT_COLOR(name, type, attr); \
RB_PROTOTYPE_REMOVE_COLOR(name, type, attr); \
RB_PROTOTYPE_INSERT(name, type, attr); \
RB_PROTOTYPE_REMOVE(name, type, attr); \
RB_PROTOTYPE_FIND(name, type, attr); \
RB_PROTOTYPE_NFIND(name, type, attr); \
RB_PROTOTYPE_NEXT(name, type, attr); \
RB_PROTOTYPE_PREV(name, type, attr); \
RB_PROTOTYPE_MINMAX(name, type, attr);
#define RB_PROTOTYPE_INSERT_COLOR(name, type, attr) \
attr void name##_RB_INSERT_COLOR(struct name *, struct type *)
#define RB_PROTOTYPE_REMOVE_COLOR(name, type, attr) \
attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *)
#define RB_PROTOTYPE_REMOVE(name, type, attr) \
attr struct type *name##_RB_REMOVE(struct name *, struct type *)
#define RB_PROTOTYPE_INSERT(name, type, attr) \
attr struct type *name##_RB_INSERT(struct name *, struct type *)
#define RB_PROTOTYPE_FIND(name, type, attr) \
attr struct type *name##_RB_FIND(struct name *, struct type *)
#define RB_PROTOTYPE_NFIND(name, type, attr) \
attr struct type *name##_RB_NFIND(struct name *, struct type *)
#define RB_PROTOTYPE_NEXT(name, type, attr) \
attr struct type *name##_RB_NEXT(struct type *)
#define RB_PROTOTYPE_PREV(name, type, attr) \
attr struct type *name##_RB_PREV(struct type *)
#define RB_PROTOTYPE_MINMAX(name, type, attr) \
attr struct type *name##_RB_MINMAX(struct name *, int)
/* Main rb operation.
* Moves node close to the key of elm to top
*/
#define RB_GENERATE(name, type, field, cmp) \
RB_GENERATE_INTERNAL(name, type, field, cmp,)
#define RB_GENERATE_STATIC(name, type, field, cmp) \
RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static)
#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
RB_GENERATE_INSERT_COLOR(name, type, field, attr) \
RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \
RB_GENERATE_INSERT(name, type, field, cmp, attr) \
RB_GENERATE_REMOVE(name, type, field, attr) \
RB_GENERATE_FIND(name, type, field, cmp, attr) \
RB_GENERATE_NFIND(name, type, field, cmp, attr) \
RB_GENERATE_NEXT(name, type, field, attr) \
RB_GENERATE_PREV(name, type, field, attr) \
RB_GENERATE_MINMAX(name, type, field, attr)
#define RB_GENERATE_INSERT_COLOR(name, type, field, attr) \
attr void \
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
{ \
struct type *parent, *gparent, *tmp; \
while ((parent = RB_PARENT(elm, field)) != NULL && \
RB_COLOR(parent, field) == RB_RED) { \
gparent = RB_PARENT(parent, field); \
if (parent == RB_LEFT(gparent, field)) { \
tmp = RB_RIGHT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_RIGHT(parent, field) == elm) { \
RB_ROTATE_LEFT(head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_RIGHT(head, gparent, tmp, field); \
} else { \
tmp = RB_LEFT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_LEFT(parent, field) == elm) { \
RB_ROTATE_RIGHT(head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_LEFT(head, gparent, tmp, field); \
} \
} \
RB_COLOR(head->rbh_root, field) = RB_BLACK; \
}
#define RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \
attr void \
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
{ \
struct type *tmp; \
while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
elm != RB_ROOT(head)) { \
if (RB_LEFT(parent, field) == elm) { \
tmp = RB_RIGHT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_LEFT(head, parent, tmp, field);\
tmp = RB_RIGHT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
} else { \
if (RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
struct type *oleft; \
if ((oleft = RB_LEFT(tmp, field)) \
!= NULL) \
RB_COLOR(oleft, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_RIGHT(head, tmp, oleft, field);\
tmp = RB_RIGHT(parent, field); \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
RB_COLOR(parent, field) = RB_BLACK; \
if (RB_RIGHT(tmp, field)) \
RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
RB_ROTATE_LEFT(head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} else { \
tmp = RB_LEFT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_RIGHT(head, parent, tmp, field);\
tmp = RB_LEFT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
} else { \
if (RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
struct type *oright; \
if ((oright = RB_RIGHT(tmp, field)) \
!= NULL) \
RB_COLOR(oright, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_LEFT(head, tmp, oright, field);\
tmp = RB_LEFT(parent, field); \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
RB_COLOR(parent, field) = RB_BLACK; \
if (RB_LEFT(tmp, field)) \
RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
RB_ROTATE_RIGHT(head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} \
} \
if (elm) \
RB_COLOR(elm, field) = RB_BLACK; \
}
#define RB_GENERATE_REMOVE(name, type, field, attr) \
attr struct type * \
name##_RB_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *child, *parent, *old = elm; \
int color; \
if (RB_LEFT(elm, field) == NULL) \
child = RB_RIGHT(elm, field); \
else if (RB_RIGHT(elm, field) == NULL) \
child = RB_LEFT(elm, field); \
else { \
struct type *left; \
elm = RB_RIGHT(elm, field); \
while ((left = RB_LEFT(elm, field)) != NULL) \
elm = left; \
child = RB_RIGHT(elm, field); \
parent = RB_PARENT(elm, field); \
color = RB_COLOR(elm, field); \
if (child) \
RB_PARENT(child, field) = parent; \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
if (RB_PARENT(elm, field) == old) \
parent = elm; \
(elm)->field = (old)->field; \
if (RB_PARENT(old, field)) { \
if (RB_LEFT(RB_PARENT(old, field), field) == old)\
RB_LEFT(RB_PARENT(old, field), field) = elm;\
else \
RB_RIGHT(RB_PARENT(old, field), field) = elm;\
RB_AUGMENT(RB_PARENT(old, field)); \
} else \
RB_ROOT(head) = elm; \
RB_PARENT(RB_LEFT(old, field), field) = elm; \
if (RB_RIGHT(old, field)) \
RB_PARENT(RB_RIGHT(old, field), field) = elm; \
if (parent) { \
left = parent; \
do { \
RB_AUGMENT(left); \
} while ((left = RB_PARENT(left, field)) != NULL); \
} \
goto color; \
} \
parent = RB_PARENT(elm, field); \
color = RB_COLOR(elm, field); \
if (child) \
RB_PARENT(child, field) = parent; \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
color: \
if (color == RB_BLACK) \
name##_RB_REMOVE_COLOR(head, parent, child); \
return (old); \
} \
#define RB_GENERATE_INSERT(name, type, field, cmp, attr) \
/* Inserts a node into the RB tree */ \
attr struct type * \
name##_RB_INSERT(struct name *head, struct type *elm) \
{ \
struct type *tmp; \
struct type *parent = NULL; \
int comp = 0; \
tmp = RB_ROOT(head); \
while (tmp) { \
parent = tmp; \
comp = (cmp)(elm, parent); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
RB_SET(elm, parent, field); \
if (parent != NULL) { \
if (comp < 0) \
RB_LEFT(parent, field) = elm; \
else \
RB_RIGHT(parent, field) = elm; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = elm; \
name##_RB_INSERT_COLOR(head, elm); \
return (NULL); \
}
#define RB_GENERATE_FIND(name, type, field, cmp, attr) \
/* Finds the node with the same key as elm */ \
attr struct type * \
name##_RB_FIND(struct name *head, struct type *elm) \
{ \
struct type *tmp = RB_ROOT(head); \
int comp; \
while (tmp) { \
comp = cmp(elm, tmp); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (NULL); \
}
#define RB_GENERATE_NFIND(name, type, field, cmp, attr) \
/* Finds the first node greater than or equal to the search key */ \
attr struct type * \
name##_RB_NFIND(struct name *head, struct type *elm) \
{ \
struct type *tmp = RB_ROOT(head); \
struct type *res = NULL; \
int comp; \
while (tmp) { \
comp = cmp(elm, tmp); \
if (comp < 0) { \
res = tmp; \
tmp = RB_LEFT(tmp, field); \
} \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (res); \
}
#define RB_GENERATE_NEXT(name, type, field, attr) \
/* ARGSUSED */ \
attr struct type * \
name##_RB_NEXT(struct type *elm) \
{ \
if (RB_RIGHT(elm, field)) { \
elm = RB_RIGHT(elm, field); \
while (RB_LEFT(elm, field)) \
elm = RB_LEFT(elm, field); \
} else { \
if (RB_PARENT(elm, field) && \
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \
else { \
while (RB_PARENT(elm, field) && \
(elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
elm = RB_PARENT(elm, field); \
elm = RB_PARENT(elm, field); \
} \
} \
return (elm); \
}
#define RB_GENERATE_PREV(name, type, field, attr) \
/* ARGSUSED */ \
attr struct type * \
name##_RB_PREV(struct type *elm) \
{ \
if (RB_LEFT(elm, field)) { \
elm = RB_LEFT(elm, field); \
while (RB_RIGHT(elm, field)) \
elm = RB_RIGHT(elm, field); \
} else { \
if (RB_PARENT(elm, field) && \
(elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \
else { \
while (RB_PARENT(elm, field) && \
(elm == RB_LEFT(RB_PARENT(elm, field), field)))\
elm = RB_PARENT(elm, field); \
elm = RB_PARENT(elm, field); \
} \
} \
return (elm); \
}
#define RB_GENERATE_MINMAX(name, type, field, attr) \
attr struct type * \
name##_RB_MINMAX(struct name *head, int val) \
{ \
struct type *tmp = RB_ROOT(head); \
struct type *parent = NULL; \
while (tmp) { \
parent = tmp; \
if (val < 0) \
tmp = RB_LEFT(tmp, field); \
else \
tmp = RB_RIGHT(tmp, field); \
} \
return (parent); \
}
#define RB_NEGINF -1
#define RB_INF 1
#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
#define RB_PREV(name, x, y) name##_RB_PREV(y)
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
#define RB_FOREACH(x, name, head) \
for ((x) = RB_MIN(name, head); \
(x) != NULL; \
(x) = name##_RB_NEXT(x))
#define RB_FOREACH_FROM(x, name, y) \
for ((x) = (y); \
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
(x) = (y))
#define RB_FOREACH_SAFE(x, name, head, y) \
for ((x) = RB_MIN(name, head); \
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
(x) = (y))
#define RB_FOREACH_REVERSE(x, name, head) \
for ((x) = RB_MAX(name, head); \
(x) != NULL; \
(x) = name##_RB_PREV(x))
#define RB_FOREACH_REVERSE_FROM(x, name, y) \
for ((x) = (y); \
((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
(x) = (y))
#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
for ((x) = RB_MAX(name, head); \
((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
(x) = (y))
#endif /* _SYS_TREE_H_ */
writexl/src/include/xlsxwriter/third_party/queue.h 0000644 0001762 0000144 00000056353 14747162622 022272 0 ustar ligges users /*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
* $FreeBSD$
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
/* #include */
/*
* This file defines four types of data structures: singly-linked lists,
* singly-linked tail queues, lists and tail queues.
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A singly-linked tail queue is headed by a pair of pointers, one to the
* head of the list and the other to the tail of the list. The elements are
* singly linked for minimum space and pointer manipulation overhead at the
* expense of O(n) removal for arbitrary elements. New elements can be added
* to the list after an existing element, at the head of the list, or at the
* end of the list. Elements being removed from the head of the tail queue
* should use the explicit macro for this purpose for optimum efficiency.
* A singly-linked tail queue may only be traversed in the forward direction.
* Singly-linked tail queues are ideal for applications with large datasets
* and few or no removals or for implementing a FIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may be traversed in either direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* For details on the use of these macros, see the queue(3) manual page.
*
*
* SLIST LIST STAILQ TAILQ
* _HEAD + + + +
* _HEAD_INITIALIZER + + + +
* _ENTRY + + + +
* _INIT + + + +
* _EMPTY + + + +
* _FIRST + + + +
* _NEXT + + + +
* _PREV - + - +
* _LAST - - + +
* _FOREACH + + + +
* _FOREACH_FROM + + + +
* _FOREACH_SAFE + + + +
* _FOREACH_FROM_SAFE + + + +
* _FOREACH_REVERSE - - - +
* _FOREACH_REVERSE_FROM - - - +
* _FOREACH_REVERSE_SAFE - - - +
* _FOREACH_REVERSE_FROM_SAFE - - - +
* _INSERT_HEAD + + + +
* _INSERT_BEFORE - + - +
* _INSERT_AFTER + + + +
* _INSERT_TAIL - - + +
* _CONCAT - - + +
* _REMOVE_AFTER + - + -
* _REMOVE_HEAD + - + -
* _REMOVE + + + +
* _SWAP + + + +
*
*/
#ifdef QUEUE_MACRO_DEBUG
/* Store the last 2 places the queue element or head was altered */
struct qm_trace {
unsigned long lastline;
unsigned long prevline;
const char *lastfile;
const char *prevfile;
};
#define TRACEBUF struct qm_trace trace;
#define TRACEBUF_INITIALIZER { __FILE__, __LINE__, NULL, 0 } ,
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
#define QMD_TRACE_HEAD(head) do { \
(head)->trace.prevline = (head)->trace.lastline; \
(head)->trace.prevfile = (head)->trace.lastfile; \
(head)->trace.lastline = __LINE__; \
(head)->trace.lastfile = __FILE__; \
} while (0)
#define QMD_TRACE_ELEM(elem) do { \
(elem)->trace.prevline = (elem)->trace.lastline; \
(elem)->trace.prevfile = (elem)->trace.lastfile; \
(elem)->trace.lastline = __LINE__; \
(elem)->trace.lastfile = __FILE__; \
} while (0)
#else
#define QMD_TRACE_ELEM(elem)
#define QMD_TRACE_HEAD(head)
#define QMD_SAVELINK(name, link)
#define TRACEBUF
#define TRACEBUF_INITIALIZER
#define TRASHIT(x)
#endif /* QUEUE_MACRO_DEBUG */
/*
* Singly-linked List declarations.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List functions.
*/
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_FOREACH(var, head, field) \
for ((var) = SLIST_FIRST((head)); \
(var); \
(var) = SLIST_NEXT((var), field))
#define SLIST_FOREACH_FROM(var, head, field) \
for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \
(var); \
(var) = SLIST_NEXT((var), field))
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST((head)); \
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
(var) = (tvar))
#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
(var) = (tvar))
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
for ((varp) = &SLIST_FIRST((head)); \
((var) = *(varp)) != NULL; \
(varp) = &SLIST_NEXT((var), field))
#define SLIST_INIT(head) do { \
SLIST_FIRST((head)) = NULL; \
} while (0)
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
SLIST_NEXT((slistelm), field) = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
SLIST_FIRST((head)) = (elm); \
} while (0)
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_REMOVE(head, elm, type, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.sle_next); \
if (SLIST_FIRST((head)) == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = SLIST_FIRST((head)); \
while (SLIST_NEXT(curelm, field) != (elm)) \
curelm = SLIST_NEXT(curelm, field); \
SLIST_REMOVE_AFTER(curelm, field); \
} \
TRASHIT(*oldnext); \
} while (0)
#define SLIST_REMOVE_AFTER(elm, field) do { \
SLIST_NEXT(elm, field) = \
SLIST_NEXT(SLIST_NEXT(elm, field), field); \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
} while (0)
#define SLIST_SWAP(head1, head2, type) do { \
struct type *swap_first = SLIST_FIRST(head1); \
SLIST_FIRST(head1) = SLIST_FIRST(head2); \
SLIST_FIRST(head2) = swap_first; \
} while (0)
/*
* Singly-linked Tail queue declarations.
*/
#define STAILQ_HEAD(name, type) \
struct name { \
struct type *stqh_first;/* first element */ \
struct type **stqh_last;/* addr of last next element */ \
}
#define STAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).stqh_first }
#define STAILQ_ENTRY(type) \
struct { \
struct type *stqe_next; /* next element */ \
}
/*
* Singly-linked Tail queue functions.
*/
#define STAILQ_CONCAT(head1, head2) do { \
if (!STAILQ_EMPTY((head2))) { \
*(head1)->stqh_last = (head2)->stqh_first; \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_INIT((head2)); \
} \
} while (0)
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
#define STAILQ_FIRST(head) ((head)->stqh_first)
#define STAILQ_FOREACH(var, head, field) \
for((var) = STAILQ_FIRST((head)); \
(var); \
(var) = STAILQ_NEXT((var), field))
#define STAILQ_FOREACH_FROM(var, head, field) \
for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
(var); \
(var) = STAILQ_NEXT((var), field))
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = STAILQ_FIRST((head)); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define STAILQ_INIT(head) do { \
STAILQ_FIRST((head)) = NULL; \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_NEXT((tqelm), field) = (elm); \
} while (0)
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_FIRST((head)) = (elm); \
} while (0)
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
STAILQ_NEXT((elm), field) = NULL; \
*(head)->stqh_last = (elm); \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_LAST(head, type, field) \
(STAILQ_EMPTY((head)) ? NULL : \
__containerof((head)->stqh_last, struct type, field.stqe_next))
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
#define STAILQ_REMOVE(head, elm, type, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \
if (STAILQ_FIRST((head)) == (elm)) { \
STAILQ_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = STAILQ_FIRST((head)); \
while (STAILQ_NEXT(curelm, field) != (elm)) \
curelm = STAILQ_NEXT(curelm, field); \
STAILQ_REMOVE_AFTER(head, curelm, field); \
} \
TRASHIT(*oldnext); \
} while (0)
#define STAILQ_REMOVE_AFTER(head, elm, field) do { \
if ((STAILQ_NEXT(elm, field) = \
STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_REMOVE_HEAD(head, field) do { \
if ((STAILQ_FIRST((head)) = \
STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_SWAP(head1, head2, type) do { \
struct type *swap_first = STAILQ_FIRST(head1); \
struct type **swap_last = (head1)->stqh_last; \
STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_FIRST(head2) = swap_first; \
(head2)->stqh_last = swap_last; \
if (STAILQ_EMPTY(head1)) \
(head1)->stqh_last = &STAILQ_FIRST(head1); \
if (STAILQ_EMPTY(head2)) \
(head2)->stqh_last = &STAILQ_FIRST(head2); \
} while (0)
/*
* List declarations.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
#define QMD_LIST_CHECK_HEAD(head, field) do { \
if (LIST_FIRST((head)) != NULL && \
LIST_FIRST((head))->field.le_prev != \
&LIST_FIRST((head))) \
panic("Bad list head %p first->prev != head", (head)); \
} while (0)
#define QMD_LIST_CHECK_NEXT(elm, field) do { \
if (LIST_NEXT((elm), field) != NULL && \
LIST_NEXT((elm), field)->field.le_prev != \
&((elm)->field.le_next)) \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
#define QMD_LIST_CHECK_PREV(elm, field) do { \
if (*(elm)->field.le_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
} while (0)
#else
#define QMD_LIST_CHECK_HEAD(head, field)
#define QMD_LIST_CHECK_NEXT(elm, field)
#define QMD_LIST_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_FOREACH(var, head, field) \
for ((var) = LIST_FIRST((head)); \
(var); \
(var) = LIST_NEXT((var), field))
#define LIST_FOREACH_FROM(var, head, field) \
for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
(var); \
(var) = LIST_NEXT((var), field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST((head)); \
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
(var) = (tvar))
#define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
(var) = (tvar))
#define LIST_INIT(head) do { \
LIST_FIRST((head)) = NULL; \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
QMD_LIST_CHECK_NEXT(listelm, field); \
if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
LIST_NEXT((listelm), field)->field.le_prev = \
&LIST_NEXT((elm), field); \
LIST_NEXT((listelm), field) = (elm); \
(elm)->field.le_prev = &LIST_NEXT((listelm), field); \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
QMD_LIST_CHECK_PREV(listelm, field); \
(elm)->field.le_prev = (listelm)->field.le_prev; \
LIST_NEXT((elm), field) = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &LIST_NEXT((elm), field); \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
QMD_LIST_CHECK_HEAD((head), field); \
if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
LIST_FIRST((head)) = (elm); \
(elm)->field.le_prev = &LIST_FIRST((head)); \
} while (0)
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_PREV(elm, head, type, field) \
((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \
__containerof((elm)->field.le_prev, struct type, field.le_next))
#define LIST_REMOVE(elm, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.le_next); \
QMD_SAVELINK(oldprev, (elm)->field.le_prev); \
QMD_LIST_CHECK_NEXT(elm, field); \
QMD_LIST_CHECK_PREV(elm, field); \
if (LIST_NEXT((elm), field) != NULL) \
LIST_NEXT((elm), field)->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
TRASHIT(*oldnext); \
TRASHIT(*oldprev); \
} while (0)
#define LIST_SWAP(head1, head2, type, field) do { \
struct type *swap_tmp = LIST_FIRST((head1)); \
LIST_FIRST((head1)) = LIST_FIRST((head2)); \
LIST_FIRST((head2)) = swap_tmp; \
if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
swap_tmp->field.le_prev = &LIST_FIRST((head1)); \
if ((swap_tmp = LIST_FIRST((head2))) != NULL) \
swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
} while (0)
/*
* Tail queue declarations.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
TRACEBUF \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first, TRACEBUF_INITIALIZER }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
TRACEBUF \
}
/*
* Tail queue functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
#define QMD_TAILQ_CHECK_HEAD(head, field) do { \
if (!TAILQ_EMPTY(head) && \
TAILQ_FIRST((head))->field.tqe_prev != \
&TAILQ_FIRST((head))) \
panic("Bad tailq head %p first->prev != head", (head)); \
} while (0)
#define QMD_TAILQ_CHECK_TAIL(head, field) do { \
if (*(head)->tqh_last != NULL) \
panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
} while (0)
#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \
if (TAILQ_NEXT((elm), field) != NULL && \
TAILQ_NEXT((elm), field)->field.tqe_prev != \
&((elm)->field.tqe_next)) \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
#define QMD_TAILQ_CHECK_PREV(elm, field) do { \
if (*(elm)->field.tqe_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
} while (0)
#else
#define QMD_TAILQ_CHECK_HEAD(head, field)
#define QMD_TAILQ_CHECK_TAIL(head, headname)
#define QMD_TAILQ_CHECK_NEXT(elm, field)
#define QMD_TAILQ_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */
#define TAILQ_CONCAT(head1, head2, field) do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
QMD_TRACE_HEAD(head1); \
QMD_TRACE_HEAD(head2); \
} \
} while (0)
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_FOREACH(var, head, field) \
for ((var) = TAILQ_FIRST((head)); \
(var); \
(var) = TAILQ_NEXT((var), field))
#define TAILQ_FOREACH_FROM(var, head, field) \
for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
(var); \
(var) = TAILQ_NEXT((var), field))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST((head)); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for ((var) = TAILQ_LAST((head), headname); \
(var); \
(var) = TAILQ_PREV((var), headname, field))
#define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \
for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
(var); \
(var) = TAILQ_PREV((var), headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = TAILQ_LAST((head), headname); \
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \
for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
(var) = (tvar))
#define TAILQ_INIT(head) do { \
TAILQ_FIRST((head)) = NULL; \
(head)->tqh_last = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
QMD_TAILQ_CHECK_NEXT(listelm, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
TAILQ_NEXT((elm), field)->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else { \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
} \
TAILQ_NEXT((listelm), field) = (elm); \
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
QMD_TAILQ_CHECK_PREV(listelm, field); \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
TAILQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
QMD_TAILQ_CHECK_HEAD(head, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
TAILQ_FIRST((head))->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
TAILQ_FIRST((head)) = (elm); \
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
QMD_TAILQ_CHECK_TAIL(head, field); \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_REMOVE(head, elm, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \
QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \
QMD_TAILQ_CHECK_NEXT(elm, field); \
QMD_TAILQ_CHECK_PREV(elm, field); \
if ((TAILQ_NEXT((elm), field)) != NULL) \
TAILQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \
else { \
(head)->tqh_last = (elm)->field.tqe_prev; \
QMD_TRACE_HEAD(head); \
} \
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
TRASHIT(*oldnext); \
TRASHIT(*oldprev); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_SWAP(head1, head2, type, field) do { \
struct type *swap_first = (head1)->tqh_first; \
struct type **swap_last = (head1)->tqh_last; \
(head1)->tqh_first = (head2)->tqh_first; \
(head1)->tqh_last = (head2)->tqh_last; \
(head2)->tqh_first = swap_first; \
(head2)->tqh_last = swap_last; \
if ((swap_first = (head1)->tqh_first) != NULL) \
swap_first->field.tqe_prev = &(head1)->tqh_first; \
else \
(head1)->tqh_last = &(head1)->tqh_first; \
if ((swap_first = (head2)->tqh_first) != NULL) \
swap_first->field.tqe_prev = &(head2)->tqh_first; \
else \
(head2)->tqh_last = &(head2)->tqh_first; \
} while (0)
#endif /* !_SYS_QUEUE_H_ */
writexl/src/include/xlsxwriter/third_party/md5.h 0000644 0001762 0000144 00000002602 14747162622 021617 0 ustar ligges users /*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
* MD5 Message-Digest Algorithm (RFC 1321).
*
* Homepage:
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
*
* Author:
* Alexander Peslyak, better known as Solar Designer
*
* This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See md5.c for more information.
*/
#ifdef HAVE_OPENSSL
#include
#elif !defined(_MD5_H)
#define _MD5_H
/* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned int MD5_u32plus;
typedef struct {
MD5_u32plus lo, hi;
MD5_u32plus a, b, c, d;
unsigned char buffer[64];
MD5_u32plus block[16];
} MD5_CTX;
extern void MD5_Init(MD5_CTX *ctx);
extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);
#endif
writexl/src/include/xlsxwriter/third_party/tmpfileplus.h 0000644 0001762 0000144 00000004144 14747162622 023501 0 ustar ligges users /* $Id: tmpfileplus.h $ */
/*
* $Date: 2016-06-01 03:31Z $
* $Revision: 2.0.0 $
* $Author: dai $
*/
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright (c) 2012-16 David Ireland, DI Management Services Pty Ltd
* .
*/
#if _MSC_VER > 1000
#pragma once
#endif
#ifndef TMPFILEPLUS_H_
#define TMPFILEPLUS_H_
#include
/** Create a unique temporary file.
@param dir (optional) directory to create file. If NULL use default TMP directory.
@param prefix (optional) prefix for file name. If NULL use "tmp.".
@param pathname (optional) pointer to a buffer to receive the temp filename.
Allocated using `malloc()`; user to free. Ignored if NULL.
@param keep If `keep` is nonzero and `pathname` is not NULL, then keep the file after closing.
Otherwise file is automatically deleted when closed.
@return Pointer to stream opened in binary read/write (w+b) mode, or a null pointer on error.
@exception ENOMEM Not enough memory to allocate filename.
*/
FILE *tmpfileplus(const char *dir, const char *prefix, char **pathname, int keep);
/** Create a unique temporary file with filename stored in a fixed-length buffer.
@param dir (optional) directory to create file. If NULL use default directory.
@param prefix (optional) prefix for file name. If NULL use "tmp.".
@param pathnamebuf (optional) buffer to receive full pathname of temporary file. Ignored if NULL.
@param pathsize Size of buffer to receive filename and its terminating null character.
@param keep If `keep` is nonzero and `pathname` is not NULL, then keep the file after closing.
Otherwise file is automatically deleted when closed.
@return Pointer to stream opened in binary read/write (w+b) mode, or a null pointer on error.
@exception E2BIG Resulting filename is too big for the buffer `pathnamebuf`.
*/
FILE *tmpfileplus_f(const char *dir, const char *prefix, char *pathnamebuf, size_t pathsize, int keep);
#define TMPFILE_KEEP 1
#endif /* end TMPFILEPLUS_H_ */
writexl/src/include/xlsxwriter/utility.h 0000644 0001762 0000144 00000015662 14747162622 020316 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*/
/**
* @file utility.h
*
* @brief Utility functions for libxlsxwriter.
*
*
*
*/
#ifndef __LXW_UTILITY_H__
#define __LXW_UTILITY_H__
#include
#ifndef _MSC_VER
#include
#endif
#include "common.h"
#include "xmlwriter.h"
/**
* @brief Convert an Excel `A1` cell string into a `(row, col)` pair.
*
* Convert an Excel `A1` cell string into a `(row, col)` pair.
*
* This is a little syntactic shortcut to help with worksheet layout:
*
* @code
* worksheet_write_string(worksheet, CELL("A1"), "Foo", NULL);
*
* //Same as:
* worksheet_write_string(worksheet, 0, 0, "Foo", NULL);
* @endcode
*
* @note
*
* This macro shouldn't be used in performance critical situations since it
* expands to two function calls.
*/
#define CELL(cell) \
lxw_name_to_row(cell), lxw_name_to_col(cell)
/**
* @brief Convert an Excel `A:B` column range into a `(col1, col2)` pair.
*
* Convert an Excel `A:B` column range into a `(col1, col2)` pair.
*
* This is a little syntactic shortcut to help with worksheet layout:
*
* @code
* worksheet_set_column(worksheet, COLS("B:D"), 20, NULL, NULL);
*
* // Same as:
* worksheet_set_column(worksheet, 1, 3, 20, NULL, NULL);
* @endcode
*
*/
#define COLS(cols) \
lxw_name_to_col(cols), lxw_name_to_col_2(cols)
/**
* @brief Convert an Excel `A1:B2` range into a `(first_row, first_col,
* last_row, last_col)` sequence.
*
* Convert an Excel `A1:B2` range into a `(first_row, first_col, last_row,
* last_col)` sequence.
*
* This is a little syntactic shortcut to help with worksheet layout.
*
* @code
* worksheet_print_area(worksheet, 0, 0, 41, 10); // A1:K42.
*
* // Same as:
* worksheet_print_area(worksheet, RANGE("A1:K42"));
* @endcode
*/
#define RANGE(range) \
lxw_name_to_row(range), lxw_name_to_col(range), \
lxw_name_to_row_2(range), lxw_name_to_col_2(range)
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/**
* @brief Retrieve the library version.
*
* @return The "X.Y.Z" version string.
*
* Get the library version as a "X.Y.Z" version string
*
* @code
* printf("Libxlsxwriter version = %s\n", lxw_version());
* @endcode
*
*/
const char *lxw_version(void);
/**
* @brief Retrieve the library version ID.
*
* @return The version ID.
*
* Get the library version such as "X.Y.Z" as a XYZ integer.
*
* @code
* printf("Libxlsxwriter version id = %d\n", lxw_version_id());
* @endcode
*
*/
uint16_t lxw_version_id(void);
/**
* @brief Converts a libxlsxwriter error number to a string.
*
* The `%lxw_strerror` function converts a libxlsxwriter error number defined
* by #lxw_error to a pointer to a string description of the error.
* Similar to the standard library strerror(3) function.
*
* For example:
*
* @code
* lxw_error error = workbook_close(workbook);
*
* if (error)
* printf("Error in workbook_close().\n"
* "Error %d = %s\n", error, lxw_strerror(error));
* @endcode
*
* This would produce output like the following if the target file wasn't
* writable:
*
* Error in workbook_close().
* Error 2 = Error creating output xlsx file. Usually a permissions error.
*
* @param error_num The error number returned by a libxlsxwriter function.
*
* @return A pointer to a statically allocated string. Do not free.
*/
char *lxw_strerror(lxw_error error_num);
/* Create a quoted version of the worksheet name */
char *lxw_quote_sheetname(const char *str);
void lxw_col_to_name(char *col_name, lxw_col_t col_num, uint8_t absolute);
void lxw_rowcol_to_cell(char *cell_name, lxw_row_t row, lxw_col_t col);
void lxw_rowcol_to_cell_abs(char *cell_name,
lxw_row_t row,
lxw_col_t col, uint8_t abs_row, uint8_t abs_col);
void lxw_rowcol_to_range(char *range,
lxw_row_t first_row, lxw_col_t first_col,
lxw_row_t last_row, lxw_col_t last_col);
void lxw_rowcol_to_range_abs(char *range,
lxw_row_t first_row, lxw_col_t first_col,
lxw_row_t last_row, lxw_col_t last_col);
void lxw_rowcol_to_formula_abs(char *formula, const char *sheetname,
lxw_row_t first_row, lxw_col_t first_col,
lxw_row_t last_row, lxw_col_t last_col);
uint32_t lxw_name_to_row(const char *row_str);
uint16_t lxw_name_to_col(const char *col_str);
uint32_t lxw_name_to_row_2(const char *row_str);
uint16_t lxw_name_to_col_2(const char *col_str);
/**
* @brief Converts a #lxw_datetime to an Excel datetime number.
*
* @param datetime A pointer to a #lxw_datetime struct.
*
* @return A double representing an Excel datetime.
*
* The `%lxw_datetime_to_excel_datetime()` function converts a datetime in
* #lxw_datetime to an Excel datetime number:
*
* @code
* lxw_datetime datetime = {2013, 2, 28, 12, 0, 0.0};
*
* double excel_datetime = lxw_datetime_to_excel_date(&datetime);
* @endcode
*
* See @ref working_with_dates for more details on the Excel datetime format.
*/
double lxw_datetime_to_excel_datetime(lxw_datetime *datetime);
double lxw_datetime_to_excel_date_epoch(lxw_datetime *datetime,
uint8_t date_1904);
/**
* @brief Converts a unix datetime to an Excel datetime number.
*
* @param unixtime Unix time (seconds since 1970-01-01)
*
* @return A double representing an Excel datetime.
*
* The `%lxw_unixtime_to_excel_date()` function converts a unix datetime to
* an Excel datetime number:
*
* @code
* double excel_datetime = lxw_unixtime_to_excel_date(946684800);
* @endcode
*
* See @ref working_with_dates for more details.
*/
double lxw_unixtime_to_excel_date(int64_t unixtime);
double lxw_unixtime_to_excel_date_epoch(int64_t unixtime, uint8_t date_1904);
char *lxw_strdup(const char *str);
char *lxw_strdup_formula(const char *formula);
size_t lxw_utf8_strlen(const char *str);
void lxw_str_tolower(char *str);
/* Define a portable version of strcasecmp(). */
#ifdef _MSC_VER
#define lxw_strcasecmp _stricmp
#else
#define lxw_strcasecmp strcasecmp
#endif
FILE *lxw_tmpfile(const char *tmpdir);
FILE *lxw_get_filehandle(char **buf, size_t *size, const char *tmpdir);
FILE *lxw_fopen(const char *filename, const char *mode);
/* Use the third party dtoa function to avoid locale issues with sprintf
* double formatting. Otherwise we use a simple macro that falls back to the
* default c-lib sprintf.
*/
#ifdef USE_DTOA_LIBRARY
int lxw_sprintf_dbl(char *data, double number);
#else
#define lxw_sprintf_dbl(data, number) \
lxw_snprintf(data, LXW_ATTR_32, "%.16G", number)
#endif
uint16_t lxw_hash_password(const char *password);
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_UTILITY_H__ */
writexl/src/include/xlsxwriter/packager.h 0000644 0001762 0000144 00000004607 14747162622 020365 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* packager - A libxlsxwriter library for creating Excel XLSX packager files.
*
*/
#ifndef __LXW_PACKAGER_H__
#define __LXW_PACKAGER_H__
#include
#ifdef USE_SYSTEM_MINIZIP
#ifdef __GNUC__
#pragma GCC system_header
#endif
#include "minizip/zip.h"
#else
#include "third_party/zip.h"
#endif
#include "common.h"
#include "workbook.h"
#include "worksheet.h"
#include "shared_strings.h"
#include "app.h"
#include "core.h"
#include "custom.h"
#include "table.h"
#include "theme.h"
#include "styles.h"
#include "format.h"
#include "content_types.h"
#include "relationships.h"
#include "vml.h"
#include "comment.h"
#include "metadata.h"
#define LXW_ZIP_BUFFER_SIZE (16384)
/* If zip returns a ZIP_XXX error then errno is set and we can trap that in
* workbook.c. Otherwise return a default libxlsxwriter error. */
#define RETURN_ON_ZIP_ERROR(err, default_err) \
do { \
if (err == ZIP_ERRNO) \
return LXW_ERROR_ZIP_FILE_OPERATION; \
else if (err == ZIP_PARAMERROR) \
return LXW_ERROR_ZIP_PARAMETER_ERROR; \
else if (err == ZIP_BADZIPFILE) \
return LXW_ERROR_ZIP_BAD_ZIP_FILE; \
else if (err == ZIP_INTERNALERROR) \
return LXW_ERROR_ZIP_INTERNAL_ERROR; \
else \
return default_err; \
} while (0)
/*
* Struct to represent a packager.
*/
typedef struct lxw_packager {
FILE *file;
lxw_workbook *workbook;
size_t buffer_size;
size_t output_buffer_size;
zipFile zipfile;
zip_fileinfo zipfile_info;
const char *filename;
const char *buffer;
char *output_buffer;
const char *tmpdir;
uint8_t use_zip64;
} lxw_packager;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
lxw_packager *lxw_packager_new(const char *filename, const char *tmpdir,
uint8_t use_zip64);
void lxw_packager_free(lxw_packager *packager);
lxw_error lxw_create_package(lxw_packager *self);
/* Declarations required for unit testing. */
#ifdef TESTING
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_PACKAGER_H__ */
writexl/src/include/xlsxwriter/theme.h 0000644 0001762 0000144 00000001436 14747162622 017707 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* theme - A libxlsxwriter library for creating Excel XLSX theme files.
*
*/
#ifndef __LXW_THEME_H__
#define __LXW_THEME_H__
#include
#include "common.h"
/*
* Struct to represent a theme.
*/
typedef struct lxw_theme {
FILE *file;
} lxw_theme;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
lxw_theme *lxw_theme_new(void);
void lxw_theme_free(lxw_theme *theme);
void lxw_theme_xml_declaration(lxw_theme *self);
void lxw_theme_assemble_xml_file(lxw_theme *self);
/* Declarations required for unit testing. */
#ifdef TESTING
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_THEME_H__ */
writexl/src/include/xlsxwriter/comment.h 0000644 0001762 0000144 00000003511 14747162622 020243 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* comment - A libxlsxwriter library for creating Excel XLSX comment files.
*
*/
#ifndef __LXW_COMMENT_H__
#define __LXW_COMMENT_H__
#include
#include "common.h"
#include "worksheet.h"
/* Define the tree.h RB structs for the red-black head types. */
RB_HEAD(lxw_author_ids, lxw_author_id);
/*
* Struct to represent a comment object.
*/
typedef struct lxw_comment {
FILE *file;
struct lxw_comment_objs *comment_objs;
struct lxw_author_ids *author_ids;
char *comment_author;
uint32_t author_id;
} lxw_comment;
/* Struct to an author id */
typedef struct lxw_author_id {
uint32_t id;
char *author;
RB_ENTRY (lxw_author_id) tree_pointers;
} lxw_author_id;
#define LXW_RB_GENERATE_AUTHOR_IDS(name, type, field, cmp) \
RB_GENERATE_INSERT_COLOR(name, type, field, static) \
RB_GENERATE_REMOVE_COLOR(name, type, field, static) \
RB_GENERATE_INSERT(name, type, field, cmp, static) \
RB_GENERATE_REMOVE(name, type, field, static) \
RB_GENERATE_FIND(name, type, field, cmp, static) \
RB_GENERATE_NEXT(name, type, field, static) \
RB_GENERATE_MINMAX(name, type, field, static) \
/* Add unused struct to allow adding a semicolon */ \
struct lxw_rb_generate_author_ids{int unused;}
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
lxw_comment *lxw_comment_new(void);
void lxw_comment_free(lxw_comment *comment);
void lxw_comment_assemble_xml_file(lxw_comment *self);
/* Declarations required for unit testing. */
#ifdef TESTING
STATIC void _comment_xml_declaration(lxw_comment *self);
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_COMMENT_H__ */
writexl/src/include/xlsxwriter/shared_strings.h 0000644 0001762 0000144 00000004057 14747162622 021626 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* shared_strings - A libxlsxwriter library for creating Excel XLSX
* sst files.
*
*/
#ifndef __LXW_SST_H__
#define __LXW_SST_H__
#include
#include
#include "common.h"
/* Define a tree.h RB structure for storing shared strings. */
RB_HEAD(sst_rb_tree, sst_element);
/* Define a queue.h structure for storing shared strings in insertion order. */
STAILQ_HEAD(sst_order_list, sst_element);
/* Wrapper around RB_GENERATE_STATIC from tree.h to avoid unused function
* warnings and to avoid portability issues with the _unused attribute. */
#define LXW_RB_GENERATE_ELEMENT(name, type, field, cmp) \
RB_GENERATE_INSERT_COLOR(name, type, field, static) \
RB_GENERATE_INSERT(name, type, field, cmp, static) \
/* Add unused struct to allow adding a semicolon */ \
struct lxw_rb_generate_element{int unused;}
/*
* Elements of the SST table. They contain pointers to allow them to
* be stored in a RB tree and also pointers to track the insertion order
* in a separate list.
*/
struct sst_element {
uint32_t index;
char *string;
uint8_t is_rich_string;
STAILQ_ENTRY (sst_element) sst_order_pointers;
RB_ENTRY (sst_element) sst_tree_pointers;
};
/*
* Struct to represent a sst.
*/
typedef struct lxw_sst {
FILE *file;
uint32_t string_count;
uint32_t unique_count;
struct sst_order_list *order_list;
struct sst_rb_tree *rb_tree;
} lxw_sst;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
lxw_sst *lxw_sst_new(void);
void lxw_sst_free(lxw_sst *sst);
struct sst_element *lxw_get_sst_index(lxw_sst *sst, const char *string,
uint8_t is_rich_string);
void lxw_sst_assemble_xml_file(lxw_sst *self);
/* Declarations required for unit testing. */
#ifdef TESTING
STATIC void _sst_xml_declaration(lxw_sst *self);
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_SST_H__ */
writexl/src/include/xlsxwriter/vml.h 0000644 0001762 0000144 00000001731 14747162622 017401 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* vml - A libxlsxwriter library for creating Excel XLSX vml files.
*
*/
#ifndef __LXW_VML_H__
#define __LXW_VML_H__
#include
#include "common.h"
#include "worksheet.h"
/*
* Struct to represent a vml object.
*/
typedef struct lxw_vml {
FILE *file;
uint8_t type;
struct lxw_comment_objs *button_objs;
struct lxw_comment_objs *comment_objs;
struct lxw_comment_objs *image_objs;
char *vml_data_id_str;
uint32_t vml_shape_id;
uint8_t comment_display_default;
} lxw_vml;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
lxw_vml *lxw_vml_new(void);
void lxw_vml_free(lxw_vml *vml);
void lxw_vml_assemble_xml_file(lxw_vml *self);
/* Declarations required for unit testing. */
#ifdef TESTING
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_VML_H__ */
writexl/src/include/xlsxwriter/chartsheet.h 0000644 0001762 0000144 00000041623 14747162622 020741 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* chartsheet - A libxlsxwriter library for creating Excel XLSX chartsheet files.
*
*/
/**
* @page chartsheet_page The Chartsheet object
*
* The Chartsheet object represents an Excel chartsheet, which is a type of
* worksheet that only contains a chart. The Chartsheet object handles
* operations such as adding a chart and setting the page layout.
*
* See @ref chartsheet.h for full details of the functionality.
*
* @file chartsheet.h
*
* @brief Functions related to adding data and formatting to a chartsheet.
*
* The Chartsheet object represents an Excel chartsheet. It handles operations
* such as adding a chart and setting the page layout.
*
* A Chartsheet object isn't created directly. Instead a chartsheet is created
* by calling the workbook_add_chartsheet() function from a Workbook object. A
* chartsheet object functions as a worksheet and not as a chart. In order to
* have it display data a #lxw_chart object must be created and added to the
* chartsheet:
*
* @code
* #include "xlsxwriter.h"
*
* int main() {
*
* lxw_workbook *workbook = new_workbook("chartsheet.xlsx");
* lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
* lxw_chartsheet *chartsheet = workbook_add_chartsheet(workbook, NULL);
* lxw_chart *chart = workbook_add_chart(workbook, LXW_CHART_BAR);
*
* //... Set up the chart.
*
* // Add the chart to the chartsheet.
* return workbook_close(workbook);
*
* }
* @endcode
*
* @image html chartsheet.png
*
* The data for the chartsheet chart must be contained on a separate
* worksheet. That is why it is always created in conjunction with at least
* one data worksheet, as shown above.
*/
#ifndef __LXW_CHARTSHEET_H__
#define __LXW_CHARTSHEET_H__
#include
#include "common.h"
#include "worksheet.h"
#include "drawing.h"
#include "utility.h"
/**
* @brief Struct to represent an Excel chartsheet.
*
* The members of the lxw_chartsheet struct aren't modified directly. Instead
* the chartsheet properties are set by calling the functions shown in
* chartsheet.h.
*/
typedef struct lxw_chartsheet {
FILE *file;
lxw_worksheet *worksheet;
lxw_chart *chart;
struct lxw_protection_obj protection;
uint8_t is_protected;
const char *name;
const char *quoted_name;
const char *tmpdir;
uint16_t index;
uint8_t active;
uint8_t selected;
uint8_t hidden;
uint16_t *active_sheet;
uint16_t *first_sheet;
uint16_t rel_count;
STAILQ_ENTRY (lxw_chartsheet) list_pointers;
} lxw_chartsheet;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/**
* @brief Insert a chart object into a chartsheet.
*
* @param chartsheet Pointer to a lxw_chartsheet instance to be updated.
* @param chart A #lxw_chart object created via workbook_add_chart().
*
* @return A #lxw_error code.
*
* The `%chartsheet_set_chart()` function can be used to insert a chart into a
* chartsheet. The chart object must be created first using the
* `workbook_add_chart()` function and configured using the @ref chart.h
* functions.
*
* @code
* // Create the chartsheet.
* lxw_chartsheet *chartsheet = workbook_add_chartsheet(workbook, NULL);
*
* // Create a chart object.
* lxw_chart *chart = workbook_add_chart(workbook, LXW_CHART_LINE);
*
* // Add a data series to the chart.
* chart_add_series(chart, NULL, "=Sheet1!$A$1:$A$6");
*
* // Insert the chart into the chartsheet.
* chartsheet_set_chart(chartsheet, chart);
* @endcode
*
* @image html chartsheet2.png
*
* **Note:**
*
* A chart may only be inserted once into a chartsheet or a worksheet. If
* several similar charts are required then each one must be created
* separately.
*
*/
lxw_error chartsheet_set_chart(lxw_chartsheet *chartsheet, lxw_chart *chart);
/* Not currently required since scale options aren't useful in a chartsheet. */
lxw_error chartsheet_set_chart_opt(lxw_chartsheet *chartsheet,
lxw_chart *chart,
lxw_chart_options *user_options);
/**
* @brief Make a chartsheet the active, i.e., visible chartsheet.
*
* @param chartsheet Pointer to a lxw_chartsheet instance to be updated.
*
* The `%chartsheet_activate()` function is used to specify which chartsheet
* is initially visible in a multi-sheet workbook:
*
* @code
* lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, NULL);
* lxw_chartsheet *chartsheet1 = workbook_add_chartsheet(workbook, NULL);
* lxw_chartsheet *chartsheet2 = workbook_add_chartsheet(workbook, NULL);
* lxw_chartsheet *chartsheet3 = workbook_add_chartsheet(workbook, NULL);
*
* chartsheet_activate(chartsheet3);
* @endcode
*
* @image html chartsheet_activate.png
*
* More than one chartsheet can be selected via the `chartsheet_select()`
* function, see below, however only one chartsheet can be active.
*
* The default active chartsheet is the first chartsheet.
*
* See also `worksheet_activate()`.
*
*/
void chartsheet_activate(lxw_chartsheet *chartsheet);
/**
* @brief Set a chartsheet tab as selected.
*
* @param chartsheet Pointer to a lxw_chartsheet instance to be updated.
*
* The `%chartsheet_select()` function is used to indicate that a chartsheet
* is selected in a multi-sheet workbook:
*
* @code
* chartsheet_activate(chartsheet1);
* chartsheet_select(chartsheet2);
* chartsheet_select(chartsheet3);
*
* @endcode
*
* A selected chartsheet has its tab highlighted. Selecting chartsheets is a
* way of grouping them together so that, for example, several chartsheets
* could be printed in one go. A chartsheet that has been activated via the
* `chartsheet_activate()` function will also appear as selected.
*
* See also `worksheet_select()`.
*
*/
void chartsheet_select(lxw_chartsheet *chartsheet);
/**
* @brief Hide the current chartsheet.
*
* @param chartsheet Pointer to a lxw_chartsheet instance to be updated.
*
* The `%chartsheet_hide()` function is used to hide a chartsheet:
*
* @code
* chartsheet_hide(chartsheet2);
* @endcode
*
* You may wish to hide a chartsheet in order to avoid confusing a user with
* intermediate data or calculations.
*
* @image html hide_sheet.png
*
* A hidden chartsheet can not be activated or selected so this function is
* mutually exclusive with the `chartsheet_activate()` and
* `chartsheet_select()` functions. In addition, since the first chartsheet
* will default to being the active chartsheet, you cannot hide the first
* chartsheet without activating another sheet:
*
* @code
* chartsheet_activate(chartsheet2);
* chartsheet_hide(chartsheet1);
* @endcode
*
* See also `worksheet_hide()`.
*
*/
void chartsheet_hide(lxw_chartsheet *chartsheet);
/**
* @brief Set current chartsheet as the first visible sheet tab.
*
* @param chartsheet Pointer to a lxw_chartsheet instance to be updated.
*
* The `chartsheet_activate()` function determines which chartsheet is
* initially selected. However, if there are a large number of chartsheets the
* selected chartsheet may not appear on the screen. To avoid this you can
* select the leftmost visible chartsheet tab using
* `%chartsheet_set_first_sheet()`:
*
* @code
* chartsheet_set_first_sheet(chartsheet19); // First visible chartsheet tab.
* chartsheet_activate(chartsheet20); // First visible chartsheet.
* @endcode
*
* This function is not required very often. The default value is the first
* chartsheet.
*
* See also `worksheet_set_first_sheet()`.
*
*/
void chartsheet_set_first_sheet(lxw_chartsheet *chartsheet);
/**
* @brief Set the color of the chartsheet tab.
*
* @param chartsheet Pointer to a lxw_chartsheet instance to be updated.
* @param color The tab color.
*
* The `%chartsheet_set_tab_color()` function is used to change the color of
* the chartsheet tab:
*
* @code
* chartsheet_set_tab_color(chartsheet1, LXW_COLOR_RED);
* chartsheet_set_tab_color(chartsheet2, LXW_COLOR_GREEN);
* chartsheet_set_tab_color(chartsheet3, 0xFF9900); // Orange.
* @endcode
*
* The color should be an RGB integer value, see @ref working_with_colors.
*
* See also `worksheet_set_tab_color()`.
*/
void chartsheet_set_tab_color(lxw_chartsheet *chartsheet, lxw_color_t color);
/**
* @brief Protect elements of a chartsheet from modification.
*
* @param chartsheet Pointer to a lxw_chartsheet instance to be updated.
* @param password A chartsheet password.
* @param options Chartsheet elements to protect.
*
* The `%chartsheet_protect()` function protects chartsheet elements from
* modification:
*
* @code
* chartsheet_protect(chartsheet, "Some Password", options);
* @endcode
*
* The `password` and lxw_protection pointer are both optional:
*
* @code
* chartsheet_protect(chartsheet2, NULL, my_options);
* chartsheet_protect(chartsheet3, "password", NULL);
* chartsheet_protect(chartsheet4, "password", my_options);
* @endcode
*
* Passing a `NULL` password is the same as turning on protection without a
* password. Passing a `NULL` password and `NULL` options had no effect on
* chartsheets.
*
* You can specify which chartsheet elements you wish to protect by passing a
* lxw_protection pointer in the `options` argument. In Excel chartsheets only
* have two protection options:
*
* no_content
* no_objects
*
* All parameters are off by default. Individual elements can be protected as
* follows:
*
* @code
* lxw_protection options = {
* .no_content = 1,
* .no_objects = 1,
* };
*
* chartsheet_protect(chartsheet, NULL, &options);
*
* @endcode
*
* See also worksheet_protect().
*
* **Note:** Sheet level passwords in Excel offer **very** weak
* protection. They don't encrypt your data and are very easy to
* deactivate. Full workbook encryption is not supported by `libxlsxwriter`
* since it requires a completely different file format.
*/
void chartsheet_protect(lxw_chartsheet *chartsheet, const char *password,
lxw_protection *options);
/**
* @brief Set the chartsheet zoom factor.
*
* @param chartsheet Pointer to a lxw_chartsheet instance to be updated.
* @param scale Chartsheet zoom factor.
*
* Set the chartsheet zoom factor in the range `10 <= zoom <= 400`:
*
* @code
* chartsheet_set_zoom(chartsheet, 75);
* @endcode
*
* The default zoom factor is 100. It isn't possible to set the zoom to
* "Selection" because it is calculated by Excel at run-time.
*
* See also `worksheet_set_zoom()`.
*/
void chartsheet_set_zoom(lxw_chartsheet *chartsheet, uint16_t scale);
/**
* @brief Set the page orientation as landscape.
*
* @param chartsheet Pointer to a lxw_chartsheet instance to be updated.
*
* This function is used to set the orientation of a chartsheet's printed page
* to landscape. The default chartsheet orientation is landscape, so this
* function isn't generally required:
*
* @code
* chartsheet_set_landscape(chartsheet);
* @endcode
*/
void chartsheet_set_landscape(lxw_chartsheet *chartsheet);
/**
* @brief Set the page orientation as portrait.
*
* @param chartsheet Pointer to a lxw_chartsheet instance to be updated.
*
* This function is used to set the orientation of a chartsheet's printed page
* to portrait:
*
* @code
* chartsheet_set_portrait(chartsheet);
* @endcode
*/
void chartsheet_set_portrait(lxw_chartsheet *chartsheet);
/**
* @brief Set the paper type for printing.
*
* @param chartsheet Pointer to a lxw_chartsheet instance to be updated.
* @param paper_type The Excel paper format type.
*
* This function is used to set the paper format for the printed output of a
* chartsheet:
*
* @code
* chartsheet_set_paper(chartsheet1, 1); // US Letter
* chartsheet_set_paper(chartsheet2, 9); // A4
* @endcode
*
* If you do not specify a paper type the chartsheet will print using the
* printer's default paper style.
*
* See `worksheet_set_paper()` for a full list of available paper sizes.
*/
void chartsheet_set_paper(lxw_chartsheet *chartsheet, uint8_t paper_type);
/**
* @brief Set the chartsheet margins for the printed page.
*
* @param chartsheet Pointer to a lxw_chartsheet instance to be updated.
* @param left Left margin in inches. Excel default is 0.7.
* @param right Right margin in inches. Excel default is 0.7.
* @param top Top margin in inches. Excel default is 0.75.
* @param bottom Bottom margin in inches. Excel default is 0.75.
*
* The `%chartsheet_set_margins()` function is used to set the margins of the
* chartsheet when it is printed. The units are in inches. Specifying `-1` for
* any parameter will give the default Excel value as shown above.
*
* @code
* chartsheet_set_margins(chartsheet, 1.3, 1.2, -1, -1);
* @endcode
*
*/
void chartsheet_set_margins(lxw_chartsheet *chartsheet, double left,
double right, double top, double bottom);
/**
* @brief Set the printed page header caption.
*
* @param chartsheet Pointer to a lxw_chartsheet instance to be updated.
* @param string The header string.
*
* @return A #lxw_error code.
*
* Headers and footers are generated using a string which is a combination of
* plain text and control characters
*
* @code
* chartsheet_set_header(chartsheet, "&LHello");
*
* // ---------------------------------------------------------------
* // | |
* // | Hello |
* // | |
*
*
* chartsheet_set_header(chartsheet, "&CHello");
*
* // ---------------------------------------------------------------
* // | |
* // | Hello |
* // | |
*
*
* chartsheet_set_header(chartsheet, "&RHello");
*
* // ---------------------------------------------------------------
* // | |
* // | Hello |
* // | |
*
*
* @endcode
*
* See `worksheet_set_header()` for a full explanation of the syntax of
* Excel's header formatting and control characters.
*
*/
lxw_error chartsheet_set_header(lxw_chartsheet *chartsheet,
const char *string);
/**
* @brief Set the printed page footer caption.
*
* @param chartsheet Pointer to a lxw_chartsheet instance to be updated.
* @param string The footer string.
*
* @return A #lxw_error code.
*
* The syntax of this function is the same as chartsheet_set_header().
*
*/
lxw_error chartsheet_set_footer(lxw_chartsheet *chartsheet,
const char *string);
/**
* @brief Set the printed page header caption with additional options.
*
* @param chartsheet Pointer to a lxw_chartsheet instance to be updated.
* @param string The header string.
* @param options Header options.
*
* @return A #lxw_error code.
*
* The syntax of this function is the same as chartsheet_set_header() with an
* additional parameter to specify options for the header.
*
* Currently, the only available option is the header margin:
*
* @code
*
* lxw_header_footer_options header_options = { 0.2 };
*
* chartsheet_set_header_opt(chartsheet, "Some text", &header_options);
*
* @endcode
*
*/
lxw_error chartsheet_set_header_opt(lxw_chartsheet *chartsheet,
const char *string,
lxw_header_footer_options *options);
/**
* @brief Set the printed page footer caption with additional options.
*
* @param chartsheet Pointer to a lxw_chartsheet instance to be updated.
* @param string The footer string.
* @param options Footer options.
*
* @return A #lxw_error code.
*
* The syntax of this function is the same as chartsheet_set_header_opt().
*
*/
lxw_error chartsheet_set_footer_opt(lxw_chartsheet *chartsheet,
const char *string,
lxw_header_footer_options *options);
lxw_chartsheet *lxw_chartsheet_new(lxw_worksheet_init_data *init_data);
void lxw_chartsheet_free(lxw_chartsheet *chartsheet);
void lxw_chartsheet_assemble_xml_file(lxw_chartsheet *chartsheet);
/* Declarations required for unit testing. */
#ifdef TESTING
STATIC void _chartsheet_xml_declaration(lxw_chartsheet *chartsheet);
STATIC void _chartsheet_write_sheet_protection(lxw_chartsheet *chartsheet);
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_CHARTSHEET_H__ */
writexl/src/include/xlsxwriter/content_types.h 0000644 0001762 0000144 00000005240 14747162622 021500 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* content_types - A libxlsxwriter library for creating Excel XLSX
* content_types files.
*
*/
#ifndef __LXW_CONTENT_TYPES_H__
#define __LXW_CONTENT_TYPES_H__
#include
#include
#include "common.h"
#define LXW_APP_PACKAGE "application/vnd.openxmlformats-package."
#define LXW_APP_DOCUMENT "application/vnd.openxmlformats-officedocument."
#define LXW_APP_MSEXCEL "application/vnd.ms-excel."
/*
* Struct to represent a content_types.
*/
typedef struct lxw_content_types {
FILE *file;
struct lxw_tuples *default_types;
struct lxw_tuples *overrides;
} lxw_content_types;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
lxw_content_types *lxw_content_types_new(void);
void lxw_content_types_free(lxw_content_types *content_types);
void lxw_content_types_assemble_xml_file(lxw_content_types *content_types);
void lxw_ct_add_default(lxw_content_types *content_types, const char *key,
const char *value);
void lxw_ct_add_override(lxw_content_types *content_types, const char *key,
const char *value);
void lxw_ct_add_worksheet_name(lxw_content_types *content_types,
const char *name);
void lxw_ct_add_chartsheet_name(lxw_content_types *content_types,
const char *name);
void lxw_ct_add_chart_name(lxw_content_types *content_types,
const char *name);
void lxw_ct_add_drawing_name(lxw_content_types *content_types,
const char *name);
void lxw_ct_add_table_name(lxw_content_types *content_types,
const char *name);
void lxw_ct_add_comment_name(lxw_content_types *content_types,
const char *name);
void lxw_ct_add_vml_name(lxw_content_types *content_types);
void lxw_ct_add_shared_strings(lxw_content_types *content_types);
void lxw_ct_add_calc_chain(lxw_content_types *content_types);
void lxw_ct_add_custom_properties(lxw_content_types *content_types);
void lxw_ct_add_metadata(lxw_content_types *content_types);
/* Declarations required for unit testing. */
#ifdef TESTING
STATIC void _content_types_xml_declaration(lxw_content_types *self);
STATIC void _write_default(lxw_content_types *self, const char *ext,
const char *type);
STATIC void _write_override(lxw_content_types *self, const char *part_name,
const char *type);
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_CONTENT_TYPES_H__ */
writexl/src/include/xlsxwriter/hash_table.h 0000644 0001762 0000144 00000003710 14747162622 020674 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
* hash_table - Hash table functions for libxlsxwriter.
*
*/
#ifndef __LXW_HASH_TABLE_H__
#define __LXW_HASH_TABLE_H__
#include "common.h"
/* Macro to loop over hash table elements in insertion order. */
#define LXW_FOREACH_ORDERED(elem, hash_table) \
STAILQ_FOREACH((elem), (hash_table)->order_list, lxw_hash_order_pointers)
/* List declarations. */
STAILQ_HEAD(lxw_hash_order_list, lxw_hash_element);
SLIST_HEAD(lxw_hash_bucket_list, lxw_hash_element);
/* LXW_HASH hash table struct. */
typedef struct lxw_hash_table {
uint32_t num_buckets;
uint32_t used_buckets;
uint32_t unique_count;
uint8_t free_key;
uint8_t free_value;
struct lxw_hash_order_list *order_list;
struct lxw_hash_bucket_list **buckets;
} lxw_hash_table;
/*
* LXW_HASH table element struct.
*
* The hash elements contain pointers to allow them to be stored in
* lists in the the hash table buckets and also pointers to track the
* insertion order in a separate list.
*/
typedef struct lxw_hash_element {
void *key;
void *value;
STAILQ_ENTRY (lxw_hash_element) lxw_hash_order_pointers;
SLIST_ENTRY (lxw_hash_element) lxw_hash_list_pointers;
} lxw_hash_element;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
lxw_hash_element *lxw_hash_key_exists(lxw_hash_table *lxw_hash, void *key,
size_t key_len);
lxw_hash_element *lxw_insert_hash_element(lxw_hash_table *lxw_hash, void *key,
void *value, size_t key_len);
lxw_hash_table *lxw_hash_new(uint32_t num_buckets, uint8_t free_key,
uint8_t free_value);
void lxw_hash_free(lxw_hash_table *lxw_hash);
/* Declarations required for unit testing. */
#ifdef TESTING
#endif
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_HASH_TABLE_H__ */
writexl/src/include/xlsxwriter/format.h 0000644 0001762 0000144 00000114032 14747162622 020072 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*/
/**
* @page format_page The Format object
*
* The Format object represents an the formatting properties that can be
* applied to a cell including: fonts, colors, patterns,
* borders, alignment and number formatting.
*
* See @ref format.h for full details of the functionality.
*
* @file format.h
*
* @brief Functions and properties for adding formatting to cells in Excel.
*
* This section describes the functions and properties that are available for
* formatting cells in Excel.
*
* The properties of a cell that can be formatted include: fonts, colors,
* patterns, borders, alignment and number formatting.
*
* @image html formats_intro.png
*
* Formats in `libxlsxwriter` are accessed via the lxw_format
* struct. Throughout this document these will be referred to simply as
* *Formats*.
*
* Formats are created by calling the workbook_add_format() method as
* follows:
*
* @code
* lxw_format *format = workbook_add_format(workbook);
* @endcode
*
* The members of the lxw_format struct aren't modified directly. Instead the
* format properties are set by calling the functions shown in this section.
* For example:
*
* @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
*
* The full range of formatting options that can be applied using
* `libxlsxwriter` are shown below.
*
*/
#ifndef __LXW_FORMAT_H__
#define __LXW_FORMAT_H__
#include
#include
#include "hash_table.h"
#include "common.h"
/**
* @brief The type for RGB colors in libxlsxwriter.
*
* The type for RGB colors in libxlsxwriter. The valid range is `0x000000`
* (black) to `0xFFFFFF` (white). See @ref working_with_colors.
*/
typedef uint32_t lxw_color_t;
#define LXW_FORMAT_FIELD_LEN 128
#define LXW_DEFAULT_FONT_NAME "Calibri"
#define LXW_DEFAULT_FONT_FAMILY 2
#define LXW_DEFAULT_FONT_THEME 1
#define LXW_PROPERTY_UNSET -1
#define LXW_COLOR_UNSET 0x000000
#define LXW_COLOR_MASK 0xFFFFFF
#define LXW_MIN_FONT_SIZE 1.0
#define LXW_MAX_FONT_SIZE 409.0
#define LXW_FORMAT_FIELD_COPY(dst, src) \
do{ \
strncpy(dst, src, LXW_FORMAT_FIELD_LEN -1); \
dst[LXW_FORMAT_FIELD_LEN - 1] = '\0'; \
} while (0)
/** Format underline values for format_set_underline(). */
enum lxw_format_underlines {
LXW_UNDERLINE_NONE = 0,
/** Single underline */
LXW_UNDERLINE_SINGLE,
/** Double underline */
LXW_UNDERLINE_DOUBLE,
/** Single accounting underline */
LXW_UNDERLINE_SINGLE_ACCOUNTING,
/** Double accounting underline */
LXW_UNDERLINE_DOUBLE_ACCOUNTING
};
/** Superscript and subscript values for format_set_font_script(). */
enum lxw_format_scripts {
/** Superscript font */
LXW_FONT_SUPERSCRIPT = 1,
/** Subscript font */
LXW_FONT_SUBSCRIPT
};
/** Alignment values for format_set_align(). */
enum lxw_format_alignments {
/** No alignment. Cell will use Excel's default for the data type */
LXW_ALIGN_NONE = 0,
/** Left horizontal alignment */
LXW_ALIGN_LEFT,
/** Center horizontal alignment */
LXW_ALIGN_CENTER,
/** Right horizontal alignment */
LXW_ALIGN_RIGHT,
/** Cell fill horizontal alignment */
LXW_ALIGN_FILL,
/** Justify horizontal alignment */
LXW_ALIGN_JUSTIFY,
/** Center Across horizontal alignment */
LXW_ALIGN_CENTER_ACROSS,
/** Left horizontal alignment */
LXW_ALIGN_DISTRIBUTED,
/** Top vertical alignment */
LXW_ALIGN_VERTICAL_TOP,
/** Bottom vertical alignment */
LXW_ALIGN_VERTICAL_BOTTOM,
/** Center vertical alignment */
LXW_ALIGN_VERTICAL_CENTER,
/** Justify vertical alignment */
LXW_ALIGN_VERTICAL_JUSTIFY,
/** Distributed vertical alignment */
LXW_ALIGN_VERTICAL_DISTRIBUTED
};
/**
* Diagonal border types.
*
*/
enum lxw_format_diagonal_types {
/** Cell diagonal border from bottom left to top right. */
LXW_DIAGONAL_BORDER_UP = 1,
/** Cell diagonal border from top left to bottom right. */
LXW_DIAGONAL_BORDER_DOWN,
/** Cell diagonal border in both directions. */
LXW_DIAGONAL_BORDER_UP_DOWN
};
/** Predefined values for common colors. */
enum lxw_defined_colors {
/** Black */
LXW_COLOR_BLACK = 0x1000000,
/** Blue */
LXW_COLOR_BLUE = 0x0000FF,
/** Brown */
LXW_COLOR_BROWN = 0x800000,
/** Cyan */
LXW_COLOR_CYAN = 0x00FFFF,
/** Gray */
LXW_COLOR_GRAY = 0x808080,
/** Green */
LXW_COLOR_GREEN = 0x008000,
/** Lime */
LXW_COLOR_LIME = 0x00FF00,
/** Magenta */
LXW_COLOR_MAGENTA = 0xFF00FF,
/** Navy */
LXW_COLOR_NAVY = 0x000080,
/** Orange */
LXW_COLOR_ORANGE = 0xFF6600,
/** Pink */
LXW_COLOR_PINK = 0xFF00FF,
/** Purple */
LXW_COLOR_PURPLE = 0x800080,
/** Red */
LXW_COLOR_RED = 0xFF0000,
/** Silver */
LXW_COLOR_SILVER = 0xC0C0C0,
/** White */
LXW_COLOR_WHITE = 0xFFFFFF,
/** Yellow */
LXW_COLOR_YELLOW = 0xFFFF00
};
/** Pattern value for use with format_set_pattern(). */
enum lxw_format_patterns {
/** Empty pattern */
LXW_PATTERN_NONE = 0,
/** Solid pattern */
LXW_PATTERN_SOLID,
/** Medium gray pattern */
LXW_PATTERN_MEDIUM_GRAY,
/** Dark gray pattern */
LXW_PATTERN_DARK_GRAY,
/** Light gray pattern */
LXW_PATTERN_LIGHT_GRAY,
/** Dark horizontal line pattern */
LXW_PATTERN_DARK_HORIZONTAL,
/** Dark vertical line pattern */
LXW_PATTERN_DARK_VERTICAL,
/** Dark diagonal stripe pattern */
LXW_PATTERN_DARK_DOWN,
/** Reverse dark diagonal stripe pattern */
LXW_PATTERN_DARK_UP,
/** Dark grid pattern */
LXW_PATTERN_DARK_GRID,
/** Dark trellis pattern */
LXW_PATTERN_DARK_TRELLIS,
/** Light horizontal Line pattern */
LXW_PATTERN_LIGHT_HORIZONTAL,
/** Light vertical line pattern */
LXW_PATTERN_LIGHT_VERTICAL,
/** Light diagonal stripe pattern */
LXW_PATTERN_LIGHT_DOWN,
/** Reverse light diagonal stripe pattern */
LXW_PATTERN_LIGHT_UP,
/** Light grid pattern */
LXW_PATTERN_LIGHT_GRID,
/** Light trellis pattern */
LXW_PATTERN_LIGHT_TRELLIS,
/** 12.5% gray pattern */
LXW_PATTERN_GRAY_125,
/** 6.25% gray pattern */
LXW_PATTERN_GRAY_0625
};
/** Cell border styles for use with format_set_border(). */
enum lxw_format_borders {
/** No border */
LXW_BORDER_NONE,
/** Thin border style */
LXW_BORDER_THIN,
/** Medium border style */
LXW_BORDER_MEDIUM,
/** Dashed border style */
LXW_BORDER_DASHED,
/** Dotted border style */
LXW_BORDER_DOTTED,
/** Thick border style */
LXW_BORDER_THICK,
/** Double border style */
LXW_BORDER_DOUBLE,
/** Hair border style */
LXW_BORDER_HAIR,
/** Medium dashed border style */
LXW_BORDER_MEDIUM_DASHED,
/** Dash-dot border style */
LXW_BORDER_DASH_DOT,
/** Medium dash-dot border style */
LXW_BORDER_MEDIUM_DASH_DOT,
/** Dash-dot-dot border style */
LXW_BORDER_DASH_DOT_DOT,
/** Medium dash-dot-dot border style */
LXW_BORDER_MEDIUM_DASH_DOT_DOT,
/** Slant dash-dot border style */
LXW_BORDER_SLANT_DASH_DOT
};
/**
* @brief Struct to represent the formatting properties of an Excel format.
*
* Formats in `libxlsxwriter` are accessed via this struct.
*
* The members of the lxw_format struct aren't modified directly. Instead the
* format properties are set by calling the functions shown in format.h.
*
* For example:
*
* @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
*
*/
typedef struct lxw_format {
FILE *file;
lxw_hash_table *xf_format_indices;
lxw_hash_table *dxf_format_indices;
uint16_t *num_xf_formats;
uint16_t *num_dxf_formats;
int32_t xf_index;
int32_t dxf_index;
int32_t xf_id;
char num_format[LXW_FORMAT_FIELD_LEN];
char font_name[LXW_FORMAT_FIELD_LEN];
char font_scheme[LXW_FORMAT_FIELD_LEN];
uint16_t num_format_index;
uint16_t font_index;
uint8_t has_font;
uint8_t has_dxf_font;
double font_size;
uint8_t bold;
uint8_t italic;
lxw_color_t font_color;
uint8_t underline;
uint8_t font_strikeout;
uint8_t font_outline;
uint8_t font_shadow;
uint8_t font_script;
uint8_t font_family;
uint8_t font_charset;
uint8_t font_condense;
uint8_t font_extend;
uint8_t theme;
uint8_t hyperlink;
uint8_t hidden;
uint8_t locked;
uint8_t text_h_align;
uint8_t text_wrap;
uint8_t text_v_align;
uint8_t text_justlast;
int16_t rotation;
lxw_color_t fg_color;
lxw_color_t bg_color;
lxw_color_t dxf_fg_color;
lxw_color_t dxf_bg_color;
uint8_t pattern;
uint8_t has_fill;
uint8_t has_dxf_fill;
int32_t fill_index;
int32_t fill_count;
int32_t border_index;
uint8_t has_border;
uint8_t has_dxf_border;
int32_t border_count;
uint8_t bottom;
uint8_t diag_border;
uint8_t diag_type;
uint8_t left;
uint8_t right;
uint8_t top;
lxw_color_t bottom_color;
lxw_color_t diag_color;
lxw_color_t left_color;
lxw_color_t right_color;
lxw_color_t top_color;
uint8_t indent;
uint8_t shrink;
uint8_t merge_range;
uint8_t reading_order;
uint8_t just_distrib;
uint8_t color_indexed;
uint8_t font_only;
uint8_t quote_prefix;
STAILQ_ENTRY (lxw_format) list_pointers;
} lxw_format;
/*
* Struct to represent the font component of a format.
*/
typedef struct lxw_font {
char font_name[LXW_FORMAT_FIELD_LEN];
double font_size;
uint8_t bold;
uint8_t italic;
uint8_t underline;
uint8_t theme;
uint8_t font_strikeout;
uint8_t font_outline;
uint8_t font_shadow;
uint8_t font_script;
uint8_t font_family;
uint8_t font_charset;
uint8_t font_condense;
uint8_t font_extend;
lxw_color_t font_color;
} lxw_font;
/*
* Struct to represent the border component of a format.
*/
typedef struct lxw_border {
uint8_t bottom;
uint8_t diag_border;
uint8_t diag_type;
uint8_t left;
uint8_t right;
uint8_t top;
lxw_color_t bottom_color;
lxw_color_t diag_color;
lxw_color_t left_color;
lxw_color_t right_color;
lxw_color_t top_color;
} lxw_border;
/*
* Struct to represent the fill component of a format.
*/
typedef struct lxw_fill {
lxw_color_t fg_color;
lxw_color_t bg_color;
uint8_t pattern;
} lxw_fill;
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
lxw_format *lxw_format_new(void);
void lxw_format_free(lxw_format *format);
int32_t lxw_format_get_xf_index(lxw_format *format);
int32_t lxw_format_get_dxf_index(lxw_format *format);
lxw_font *lxw_format_get_font_key(lxw_format *format);
lxw_border *lxw_format_get_border_key(lxw_format *format);
lxw_fill *lxw_format_get_fill_key(lxw_format *format);
/**
* @brief Set the font used in the cell.
*
* @param format Pointer to a Format instance.
* @param font_name Cell font name.
*
* Specify the font used used in the cell format:
*
* @code
* format_set_font_name(format, "Avenir Black Oblique");
* @endcode
*
* @image html format_set_font_name.png
*
* Excel can only display fonts that are installed on the system that it is
* running on. Therefore it is generally best to use the fonts that come as
* standard with Excel such as Calibri, Times New Roman and Courier New.
*
* The default font in Excel 2007, and later, is Calibri.
*/
void format_set_font_name(lxw_format *format, const char *font_name);
/**
* @brief Set the size of the font used in the cell.
*
* @param format Pointer to a Format instance.
* @param size The cell font size.
*
* Set the font size of the cell format:
*
* @code
* format_set_font_size(format, 30);
* @endcode
*
* @image html format_font_size.png
*
* Excel adjusts the height of a row to accommodate the largest font
* size in the row. You can also explicitly specify the height of a
* row using the worksheet_set_row() function.
*/
void format_set_font_size(lxw_format *format, double size);
/**
* @brief Set the color of the font used in the cell.
*
* @param format Pointer to a Format instance.
* @param color The cell font color.
*
*
* Set the font color:
*
* @code
* format = workbook_add_format(workbook);
* format_set_font_color(format, LXW_COLOR_RED);
*
* worksheet_write_string(worksheet, 0, 0, "Wheelbarrow", format);
* @endcode
*
* @image html format_font_color.png
*
* The color should be an RGB integer value, see @ref working_with_colors.
*
* @note
* The format_set_font_color() method is used to set the font color in a
* cell. To set the color of a cell background use the format_set_bg_color()
* and format_set_pattern() methods.
*/
void format_set_font_color(lxw_format *format, lxw_color_t color);
/**
* @brief Turn on bold for the format font.
*
* @param format Pointer to a Format instance.
*
* Set the bold property of the font:
*
* @code
* format = workbook_add_format(workbook);
* format_set_bold(format);
*
* worksheet_write_string(worksheet, 0, 0, "Bold Text", format);
* @endcode
*
* @image html format_font_bold.png
*/
void format_set_bold(lxw_format *format);
/**
* @brief Turn on italic for the format font.
*
* @param format Pointer to a Format instance.
*
* Set the italic property of the font:
*
* @code
* format = workbook_add_format(workbook);
* format_set_italic(format);
*
* worksheet_write_string(worksheet, 0, 0, "Italic Text", format);
* @endcode
*
* @image html format_font_italic.png
*/
void format_set_italic(lxw_format *format);
/**
* @brief Turn on underline for the format:
*
* @param format Pointer to a Format instance.
* @param style Underline style.
*
* Set the underline property of the format:
*
* @code
* format_set_underline(format, LXW_UNDERLINE_SINGLE);
* @endcode
*
* @image html format_font_underlined.png
*
* The available underline styles are:
*
* - #LXW_UNDERLINE_SINGLE
* - #LXW_UNDERLINE_DOUBLE
* - #LXW_UNDERLINE_SINGLE_ACCOUNTING
* - #LXW_UNDERLINE_DOUBLE_ACCOUNTING
*
*/
void format_set_underline(lxw_format *format, uint8_t style);
/**
* @brief Set the strikeout property of the font.
*
* @param format Pointer to a Format instance.
*
* @image html format_font_strikeout.png
*
*/
void format_set_font_strikeout(lxw_format *format);
/**
* @brief Set the superscript/subscript property of the font.
*
* @param format Pointer to a Format instance.
* @param style Superscript or subscript style.
*
* Set the superscript o subscript property of the font.
*
* @image html format_font_script.png
*
* The available script styles are:
*
* - #LXW_FONT_SUPERSCRIPT
* - #LXW_FONT_SUBSCRIPT
*/
void format_set_font_script(lxw_format *format, uint8_t style);
/**
* @brief Set the number format for a cell.
*
* @param format Pointer to a Format instance.
* @param num_format The cell number format string.
*
* This method is used to define the numerical format of a number in
* Excel. It controls whether a number is displayed as an integer, a
* floating point number, a date, a currency value or some other user
* defined format.
*
* The numerical format of a cell can be specified by using a format
* string:
*
* @code
* format = workbook_add_format(workbook);
* format_set_num_format(format, "d mmm yyyy");
* @endcode
*
* Format strings can control any aspect of number formatting allowed by Excel:
*
* @dontinclude format_num_format.c
* @skipline set_num_format
* @until 1209
*
* @image html format_set_num_format.png
*
* To set a number format that matches an Excel format category such as "Date"
* or "Currency" see @ref ww_formats_categories.
*
* The number system used for dates is described in @ref working_with_dates.
*
* For more information on number formats in Excel refer to the
* [Microsoft documentation on cell formats](http://office.microsoft.com/en-gb/assistance/HP051995001033.aspx).
*/
void format_set_num_format(lxw_format *format, const char *num_format);
/**
* @brief Set the Excel built-in number format for a cell.
*
* @param format Pointer to a Format instance.
* @param index The built-in number format index for the cell.
*
* This function is similar to format_set_num_format() except that it takes an
* index to a limited number of Excel's built-in number formats instead of a
* user defined format string:
*
* @code
* format = workbook_add_format(workbook);
* format_set_num_format_index(format, 0x0F); // d-mmm-yy
* @endcode
*
* @note
* Unless you need to specifically access one of Excel's built-in number
* formats the format_set_num_format() function above is a better
* solution. The format_set_num_format_index() function is mainly included for
* backward compatibility and completeness.
*
* The Excel built-in number formats as shown in the table below:
*
* | Index | Index | Format String |
* | ----- | ----- | ---------------------------------------------------- |
* | 0 | 0x00 | `General` |
* | 1 | 0x01 | `0` |
* | 2 | 0x02 | `0.00` |
* | 3 | 0x03 | `#,##0` |
* | 4 | 0x04 | `#,##0.00` |
* | 5 | 0x05 | `($#,##0_);($#,##0)` |
* | 6 | 0x06 | `($#,##0_);[Red]($#,##0)` |
* | 7 | 0x07 | `($#,##0.00_);($#,##0.00)` |
* | 8 | 0x08 | `($#,##0.00_);[Red]($#,##0.00)` |
* | 9 | 0x09 | `0%` |
* | 10 | 0x0a | `0.00%` |
* | 11 | 0x0b | `0.00E+00` |
* | 12 | 0x0c | `# ?/?` |
* | 13 | 0x0d | `# ??/??` |
* | 14 | 0x0e | `m/d/yy` |
* | 15 | 0x0f | `d-mmm-yy` |
* | 16 | 0x10 | `d-mmm` |
* | 17 | 0x11 | `mmm-yy` |
* | 18 | 0x12 | `h:mm AM/PM` |
* | 19 | 0x13 | `h:mm:ss AM/PM` |
* | 20 | 0x14 | `h:mm` |
* | 21 | 0x15 | `h:mm:ss` |
* | 22 | 0x16 | `m/d/yy h:mm` |
* | ... | ... | ... |
* | 37 | 0x25 | `(#,##0_);(#,##0)` |
* | 38 | 0x26 | `(#,##0_);[Red](#,##0)` |
* | 39 | 0x27 | `(#,##0.00_);(#,##0.00)` |
* | 40 | 0x28 | `(#,##0.00_);[Red](#,##0.00)` |
* | 41 | 0x29 | `_(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)` |
* | 42 | 0x2a | `_($* #,##0_);_($* (#,##0);_($* "-"_);_(@_)` |
* | 43 | 0x2b | `_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)` |
* | 44 | 0x2c | `_($* #,##0.00_);_($* (#,##0.00);_($* "-"??_);_(@_)` |
* | 45 | 0x2d | `mm:ss` |
* | 46 | 0x2e | `[h]:mm:ss` |
* | 47 | 0x2f | `mm:ss.0` |
* | 48 | 0x30 | `##0.0E+0` |
* | 49 | 0x31 | `@` |
*
* @note
* - Numeric formats 23 to 36 are not documented by Microsoft and may differ
* in international versions. The listed date and currency formats may also
* vary depending on system settings.
* - The dollar sign in the above format appears as the defined local currency
* symbol.
* - These formats can also be set via format_set_num_format().
* - See also @ref ww_formats_categories.
*/
void format_set_num_format_index(lxw_format *format, uint8_t index);
/**
* @brief Set the cell unlocked state.
*
* @param format Pointer to a Format instance.
*
* This property can be used to allow modification of a cell in a protected
* worksheet. In Excel, cell locking is turned on by default for all
* cells. However, it only has an effect if the worksheet has been protected
* using the worksheet worksheet_protect() function:
*
* @code
* format = workbook_add_format(workbook);
* format_set_unlocked(format);
*
* // Enable worksheet protection, without password or options.
* worksheet_protect(worksheet, NULL, NULL);
*
* // This cell cannot be edited.
* worksheet_write_formula(worksheet, 0, 0, "=1+2", NULL);
*
* // This cell can be edited.
* worksheet_write_formula(worksheet, 1, 0, "=1+2", format);
* @endcode
*/
void format_set_unlocked(lxw_format *format);
/**
* @brief Hide formulas in a cell.
*
* @param format Pointer to a Format instance.
*
* This property is used to hide a formula while still displaying its
* result. This is generally used to hide complex calculations from end users
* who are only interested in the result. It only has an effect if the
* worksheet has been protected using the worksheet worksheet_protect()
* function:
*
* @code
* format = workbook_add_format(workbook);
* format_set_hidden(format);
*
* // Enable worksheet protection, without password or options.
* worksheet_protect(worksheet, NULL, NULL);
*
* // The formula in this cell isn't visible.
* worksheet_write_formula(worksheet, 0, 0, "=1+2", format);
* @endcode
*/
void format_set_hidden(lxw_format *format);
/**
* @brief Set the alignment for data in the cell.
*
* @param format Pointer to a Format instance.
* @param alignment The horizontal and or vertical alignment direction.
*
* This method is used to set the horizontal and vertical text alignment within a
* cell. The following are the available horizontal alignments:
*
* - #LXW_ALIGN_LEFT
* - #LXW_ALIGN_CENTER
* - #LXW_ALIGN_RIGHT
* - #LXW_ALIGN_FILL
* - #LXW_ALIGN_JUSTIFY
* - #LXW_ALIGN_CENTER_ACROSS
* - #LXW_ALIGN_DISTRIBUTED
*
* The following are the available vertical alignments:
*
* - #LXW_ALIGN_VERTICAL_TOP
* - #LXW_ALIGN_VERTICAL_BOTTOM
* - #LXW_ALIGN_VERTICAL_CENTER
* - #LXW_ALIGN_VERTICAL_JUSTIFY
* - #LXW_ALIGN_VERTICAL_DISTRIBUTED
*
* As in Excel, vertical and horizontal alignments can be combined:
*
* @code
* format = workbook_add_format(workbook);
*
* format_set_align(format, LXW_ALIGN_CENTER);
* format_set_align(format, LXW_ALIGN_VERTICAL_CENTER);
*
* worksheet_set_row(0, 30);
* worksheet_write_string(worksheet, 0, 0, "Some Text", format);
* @endcode
*
* @image html format_font_align.png
*
* Text can be aligned across two or more adjacent cells using the
* center_across property. However, for genuine merged cells it is better to
* use the worksheet_merge_range() worksheet method.
*
* The vertical justify option can be used to provide automatic text wrapping
* in a cell. The height of the cell will be adjusted to accommodate the
* wrapped text. To specify where the text wraps use the
* format_set_text_wrap() method.
*/
void format_set_align(lxw_format *format, uint8_t alignment);
/**
* @brief Wrap text in a cell.
*
* Turn text wrapping on for text in a cell.
*
* @code
* format = workbook_add_format(workbook);
* format_set_text_wrap(format);
*
* worksheet_write_string(worksheet, 0, 0, "Some long text to wrap in a cell", format);
* @endcode
*
* If you wish to control where the text is wrapped you can add newline characters
* to the string:
*
* @code
* format = workbook_add_format(workbook);
* format_set_text_wrap(format);
*
* worksheet_write_string(worksheet, 0, 0, "It's\na bum\nwrap", format);
* @endcode
*
* @image html format_font_text_wrap.png
*
* Excel will adjust the height of the row to accommodate the wrapped text. A
* similar effect can be obtained without newlines using the
* format_set_align() function with #LXW_ALIGN_VERTICAL_JUSTIFY.
*/
void format_set_text_wrap(lxw_format *format);
/**
* @brief Set the rotation of the text in a cell.
*
* @param format Pointer to a Format instance.
* @param angle Rotation angle in the range -90 to 90 and 270.
*
* Set the rotation of the text in a cell. The rotation can be any angle in the
* range -90 to 90 degrees:
*
* @code
* format = workbook_add_format(workbook);
* format_set_rotation(format, 30);
*
* worksheet_write_string(worksheet, 0, 0, "This text is rotated", format);
* @endcode
*
* @image html format_font_text_rotated.png
*
* The angle 270 is also supported. This indicates text where the letters run from
* top to bottom.
*/
void format_set_rotation(lxw_format *format, int16_t angle);
/**
* @brief Set the cell text indentation level.
*
* @param format Pointer to a Format instance.
* @param level Indentation level.
*
* This method can be used to indent text in a cell. The argument, which should be
* an integer, is taken as the level of indentation:
*
* @code
* format1 = workbook_add_format(workbook);
* format2 = workbook_add_format(workbook);
*
* format_set_indent(format1, 1);
* format_set_indent(format2, 2);
*
* worksheet_write_string(worksheet, 0, 0, "This text is indented 1 level", format1);
* worksheet_write_string(worksheet, 1, 0, "This text is indented 2 levels", format2);
* @endcode
*
* @image html text_indent.png
*
* @note
* Indentation is a horizontal alignment property. It will override any other
* horizontal properties but it can be used in conjunction with vertical
* properties.
*/
void format_set_indent(lxw_format *format, uint8_t level);
/**
* @brief Turn on the text "shrink to fit" for a cell.
*
* @param format Pointer to a Format instance.
*
* This method can be used to shrink text so that it fits in a cell:
*
* @code
* format = workbook_add_format(workbook);
* format_set_shrink(format);
*
* worksheet_write_string(worksheet, 0, 0, "Honey, I shrunk the text!", format);
* @endcode
*/
void format_set_shrink(lxw_format *format);
/**
* @brief Set the background fill pattern for a cell
*
* @param format Pointer to a Format instance.
* @param index Pattern index.
*
* Set the background pattern for a cell.
*
* The most common pattern is a solid fill of the background color:
*
* @code
* format = workbook_add_format(workbook);
*
* format_set_pattern (format, LXW_PATTERN_SOLID);
* format_set_bg_color(format, LXW_COLOR_YELLOW);
* @endcode
*
* The available fill patterns are:
*
* Fill Type | Define
* ----------------------------- | -----------------------------
* Solid | #LXW_PATTERN_SOLID
* Medium gray | #LXW_PATTERN_MEDIUM_GRAY
* Dark gray | #LXW_PATTERN_DARK_GRAY
* Light gray | #LXW_PATTERN_LIGHT_GRAY
* Dark horizontal line | #LXW_PATTERN_DARK_HORIZONTAL
* Dark vertical line | #LXW_PATTERN_DARK_VERTICAL
* Dark diagonal stripe | #LXW_PATTERN_DARK_DOWN
* Reverse dark diagonal stripe | #LXW_PATTERN_DARK_UP
* Dark grid | #LXW_PATTERN_DARK_GRID
* Dark trellis | #LXW_PATTERN_DARK_TRELLIS
* Light horizontal line | #LXW_PATTERN_LIGHT_HORIZONTAL
* Light vertical line | #LXW_PATTERN_LIGHT_VERTICAL
* Light diagonal stripe | #LXW_PATTERN_LIGHT_DOWN
* Reverse light diagonal stripe | #LXW_PATTERN_LIGHT_UP
* Light grid | #LXW_PATTERN_LIGHT_GRID
* Light trellis | #LXW_PATTERN_LIGHT_TRELLIS
* 12.5% gray | #LXW_PATTERN_GRAY_125
* 6.25% gray | #LXW_PATTERN_GRAY_0625
*
*/
void format_set_pattern(lxw_format *format, uint8_t index);
/**
* @brief Set the pattern background color for a cell.
*
* @param format Pointer to a Format instance.
* @param color The cell pattern background color.
*
* The format_set_bg_color() method can be used to set the background color of
* a pattern. Patterns are defined via the format_set_pattern() method. If a
* pattern hasn't been defined then a solid fill pattern is used as the
* default.
*
* Here is an example of how to set up a solid fill in a cell:
*
* @code
* format = workbook_add_format(workbook);
*
* format_set_pattern (format, LXW_PATTERN_SOLID);
* format_set_bg_color(format, LXW_COLOR_GREEN);
*
* worksheet_write_string(worksheet, 0, 0, "Ray", format);
* @endcode
*
* @image html formats_set_bg_color.png
*
* The color should be an RGB integer value, see @ref working_with_colors.
*
*/
void format_set_bg_color(lxw_format *format, lxw_color_t color);
/**
* @brief Set the pattern foreground color for a cell.
*
* @param format Pointer to a Format instance.
* @param color The cell pattern foreground color.
*
* The format_set_fg_color() method can be used to set the foreground color of
* a pattern.
*
* The color should be an RGB integer value, see @ref working_with_colors.
*
*/
void format_set_fg_color(lxw_format *format, lxw_color_t color);
/**
* @brief Set the cell border style.
*
* @param format Pointer to a Format instance.
* @param style Border style index.
*
* Set the cell border style:
*
* @code
* format_set_border(format, LXW_BORDER_THIN);
* @endcode
*
* Individual border elements can be configured using the following functions with
* the same parameters:
*
* - format_set_bottom()
* - format_set_top()
* - format_set_left()
* - format_set_right()
*
* A cell border is comprised of a border on the bottom, top, left and right.
* These can be set to the same value using format_set_border() or
* individually using the relevant method calls shown above.
*
* The following border styles are available:
*
* - #LXW_BORDER_THIN
* - #LXW_BORDER_MEDIUM
* - #LXW_BORDER_DASHED
* - #LXW_BORDER_DOTTED
* - #LXW_BORDER_THICK
* - #LXW_BORDER_DOUBLE
* - #LXW_BORDER_HAIR
* - #LXW_BORDER_MEDIUM_DASHED
* - #LXW_BORDER_DASH_DOT
* - #LXW_BORDER_MEDIUM_DASH_DOT
* - #LXW_BORDER_DASH_DOT_DOT
* - #LXW_BORDER_MEDIUM_DASH_DOT_DOT
* - #LXW_BORDER_SLANT_DASH_DOT
*
* The most commonly used style is the `thin` style.
*/
void format_set_border(lxw_format *format, uint8_t style);
/**
* @brief Set the cell bottom border style.
*
* @param format Pointer to a Format instance.
* @param style Border style index.
*
* Set the cell bottom border style. See format_set_border() for details on the
* border styles.
*/
void format_set_bottom(lxw_format *format, uint8_t style);
/**
* @brief Set the cell top border style.
*
* @param format Pointer to a Format instance.
* @param style Border style index.
*
* Set the cell top border style. See format_set_border() for details on the border
* styles.
*/
void format_set_top(lxw_format *format, uint8_t style);
/**
* @brief Set the cell left border style.
*
* @param format Pointer to a Format instance.
* @param style Border style index.
*
* Set the cell left border style. See format_set_border() for details on the
* border styles.
*/
void format_set_left(lxw_format *format, uint8_t style);
/**
* @brief Set the cell right border style.
*
* @param format Pointer to a Format instance.
* @param style Border style index.
*
* Set the cell right border style. See format_set_border() for details on the
* border styles.
*/
void format_set_right(lxw_format *format, uint8_t style);
/**
* @brief Set the color of the cell border.
*
* @param format Pointer to a Format instance.
* @param color The cell border color.
*
* Individual border elements can be configured using the following methods with
* the same parameters:
*
* - format_set_bottom_color()
* - format_set_top_color()
* - format_set_left_color()
* - format_set_right_color()
*
* Set the color of the cell borders. A cell border is comprised of a border
* on the bottom, top, left and right. These can be set to the same color
* using format_set_border_color() or individually using the relevant method
* calls shown above.
*
* The color should be an RGB integer value, see @ref working_with_colors.
*/
void format_set_border_color(lxw_format *format, lxw_color_t color);
/**
* @brief Set the color of the bottom cell border.
*
* @param format Pointer to a Format instance.
* @param color The cell border color.
*
* See format_set_border_color() for details on the border colors.
*/
void format_set_bottom_color(lxw_format *format, lxw_color_t color);
/**
* @brief Set the color of the top cell border.
*
* @param format Pointer to a Format instance.
* @param color The cell border color.
*
* See format_set_border_color() for details on the border colors.
*/
void format_set_top_color(lxw_format *format, lxw_color_t color);
/**
* @brief Set the color of the left cell border.
*
* @param format Pointer to a Format instance.
* @param color The cell border color.
*
* See format_set_border_color() for details on the border colors.
*/
void format_set_left_color(lxw_format *format, lxw_color_t color);
/**
* @brief Set the color of the right cell border.
*
* @param format Pointer to a Format instance.
* @param color The cell border color.
*
* See format_set_border_color() for details on the border colors.
*/
void format_set_right_color(lxw_format *format, lxw_color_t color);
/**
* @brief Set the diagonal cell border type.
*
* @param format Pointer to a Format instance.
* @param type The #lxw_format_diagonal_types diagonal border type.
*
* Set the diagonal cell border type:
*
* @code
* lxw_format *format1 = workbook_add_format(workbook);
* format_set_diag_type( format1, LXW_DIAGONAL_BORDER_UP);
*
* lxw_format *format2 = workbook_add_format(workbook);
* format_set_diag_type( format2, LXW_DIAGONAL_BORDER_DOWN);
*
* lxw_format *format3 = workbook_add_format(workbook);
* format_set_diag_type( format3, LXW_DIAGONAL_BORDER_UP_DOWN);
*
* lxw_format *format4 = workbook_add_format(workbook);
* format_set_diag_type( format4, LXW_DIAGONAL_BORDER_UP_DOWN);
* format_set_diag_border(format4, LXW_BORDER_HAIR);
* format_set_diag_color( format4, LXW_COLOR_RED);
*
* worksheet_write_string(worksheet, CELL("B3"), "Text", format1);
* worksheet_write_string(worksheet, CELL("B6"), "Text", format2);
* worksheet_write_string(worksheet, CELL("B9"), "Text", format3);
* worksheet_write_string(worksheet, CELL("B12"), "Text", format4);
* @endcode
*
* @image html diagonal_border.png
*
* The allowable border types are defined in #lxw_format_diagonal_types:
*
* - #LXW_DIAGONAL_BORDER_UP: Cell diagonal border from bottom left to top
* right.
*
* - #LXW_DIAGONAL_BORDER_DOWN: Cell diagonal border from top left to bottom
* right.
*
* - #LXW_DIAGONAL_BORDER_UP_DOWN: Cell diagonal border from top left to
* bottom right. A combination of the 2 previous types.
*
* If the border style isn't specified with `format_set_diag_border()` then it
* will default to #LXW_BORDER_THIN.
*/
void format_set_diag_type(lxw_format *format, uint8_t type);
/**
* @brief Set the diagonal cell border style.
*
* @param format Pointer to a Format instance.
* @param style The #lxw_format_borders style.
*
* Set the diagonal border style. This should be a #lxw_format_borders value.
* See the example above.
*
*/
void format_set_diag_border(lxw_format *format, uint8_t style);
/**
* @brief Set the diagonal cell border color.
*
* @param format Pointer to a Format instance.
* @param color The cell diagonal border color.
*
* Set the diagonal border color. The color should be an RGB integer value,
* see @ref working_with_colors and the above example.
*/
void format_set_diag_color(lxw_format *format, lxw_color_t color);
/**
* @brief Turn on quote prefix for the format.
*
* @param format Pointer to a Format instance.
*
* Set the quote prefix property of a format to ensure a string is treated
* as a string after editing. This is the same as prefixing the string with
* a single quote in Excel. You don't need to add the quote to the
* string but you do need to add the format.
*
* @code
* format = workbook_add_format(workbook);
* format_set_quote_prefix(format);
*
* worksheet_write_string(worksheet, 0, 0, "=Foo", format);
* @endcode
*
*/
void format_set_quote_prefix(lxw_format *format);
void format_set_font_outline(lxw_format *format);
void format_set_font_shadow(lxw_format *format);
void format_set_font_family(lxw_format *format, uint8_t value);
void format_set_font_charset(lxw_format *format, uint8_t value);
void format_set_font_scheme(lxw_format *format, const char *font_scheme);
void format_set_font_condense(lxw_format *format);
void format_set_font_extend(lxw_format *format);
void format_set_reading_order(lxw_format *format, uint8_t value);
void format_set_theme(lxw_format *format, uint8_t value);
void format_set_hyperlink(lxw_format *format);
void format_set_color_indexed(lxw_format *format, uint8_t value);
void format_set_font_only(lxw_format *format);
/* Declarations required for unit testing. */
#ifdef TESTING
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_FORMAT_H__ */
writexl/src/include/xlsxwriter/common.h 0000644 0001762 0000144 00000035034 14747162622 020076 0 ustar ligges users /*
* libxlsxwriter
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*/
/**
* @file common.h
*
* @brief Common functions and defines for the libxlsxwriter library.
*
*
*
*/
#ifndef __LXW_COMMON_H__
#define __LXW_COMMON_H__
#include
#include "third_party/queue.h"
#include "third_party/tree.h"
#ifndef TESTING
#define STATIC static
#else
#define STATIC
#endif
#if __GNUC__ >= 5
#define DEPRECATED(func, msg) func __attribute__ ((deprecated(msg)))
#elif defined(_MSC_VER)
#define DEPRECATED(func, msg) __declspec(deprecated, msg) func
#else
#define DEPRECATED(func, msg) func
#endif
/** Integer data type to represent a row value. Equivalent to `uint32_t`.
*
* The maximum row in Excel is 1,048,576.
*/
typedef uint32_t lxw_row_t;
/** Integer data type to represent a column value. Equivalent to `uint16_t`.
*
* The maximum column in Excel is 16,384.
*/
typedef uint16_t lxw_col_t;
/** Boolean values used in libxlsxwriter. */
enum lxw_boolean {
/** False value. */
LXW_FALSE,
/** True value. */
LXW_TRUE,
/** False value. Used to turn off a property that is default on, in order
* to distinguish it from an uninitialized value. */
LXW_EXPLICIT_FALSE
};
/**
* @brief Error codes from libxlsxwriter functions.
*
* See the `lxw_strerror()` function for an example of how to convert the
* enum number to a descriptive error message string.
*/
typedef enum lxw_error {
/** No error. */
LXW_NO_ERROR = 0,
/** Memory error, failed to malloc() required memory. */
LXW_ERROR_MEMORY_MALLOC_FAILED,
/** Error creating output xlsx file. Usually a permissions error. */
LXW_ERROR_CREATING_XLSX_FILE,
/** Error encountered when creating a tmpfile during file assembly. */
LXW_ERROR_CREATING_TMPFILE,
/** Error reading a tmpfile. */
LXW_ERROR_READING_TMPFILE,
/** Zip generic error ZIP_ERRNO while creating the xlsx file. */
LXW_ERROR_ZIP_FILE_OPERATION,
/** Zip error ZIP_PARAMERROR while creating the xlsx file. */
LXW_ERROR_ZIP_PARAMETER_ERROR,
/** Zip error ZIP_BADZIPFILE (use_zip64 option may be required). */
LXW_ERROR_ZIP_BAD_ZIP_FILE,
/** Zip error ZIP_INTERNALERROR while creating the xlsx file. */
LXW_ERROR_ZIP_INTERNAL_ERROR,
/** File error or unknown zip error when adding sub file to xlsx file. */
LXW_ERROR_ZIP_FILE_ADD,
/** Unknown zip error when closing xlsx file. */
LXW_ERROR_ZIP_CLOSE,
/** Feature is not currently supported in this configuration. */
LXW_ERROR_FEATURE_NOT_SUPPORTED,
/** NULL function parameter ignored. */
LXW_ERROR_NULL_PARAMETER_IGNORED,
/** Function parameter validation error. */
LXW_ERROR_PARAMETER_VALIDATION,
/** Worksheet name exceeds Excel's limit of 31 characters. */
LXW_ERROR_SHEETNAME_LENGTH_EXCEEDED,
/** Worksheet name cannot contain invalid characters: '[ ] : * ? / \\' */
LXW_ERROR_INVALID_SHEETNAME_CHARACTER,
/** Worksheet name cannot start or end with an apostrophe. */
LXW_ERROR_SHEETNAME_START_END_APOSTROPHE,
/** Worksheet name is already in use. */
LXW_ERROR_SHEETNAME_ALREADY_USED,
/** Parameter exceeds Excel's limit of 32 characters. */
LXW_ERROR_32_STRING_LENGTH_EXCEEDED,
/** Parameter exceeds Excel's limit of 128 characters. */
LXW_ERROR_128_STRING_LENGTH_EXCEEDED,
/** Parameter exceeds Excel's limit of 255 characters. */
LXW_ERROR_255_STRING_LENGTH_EXCEEDED,
/** String exceeds Excel's limit of 32,767 characters. */
LXW_ERROR_MAX_STRING_LENGTH_EXCEEDED,
/** Error finding internal string index. */
LXW_ERROR_SHARED_STRING_INDEX_NOT_FOUND,
/** Worksheet row or column index out of range. */
LXW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE,
/** Maximum hyperlink length (2079) exceeded. */
LXW_ERROR_WORKSHEET_MAX_URL_LENGTH_EXCEEDED,
/** Maximum number of worksheet URLs (65530) exceeded. */
LXW_ERROR_WORKSHEET_MAX_NUMBER_URLS_EXCEEDED,
/** Couldn't read image dimensions or DPI. */
LXW_ERROR_IMAGE_DIMENSIONS,
LXW_MAX_ERRNO
} lxw_error;
/** @brief Struct to represent a date and time in Excel.
*
* Struct to represent a date and time in Excel. See @ref working_with_dates.
*/
typedef struct lxw_datetime {
/** Year : 1900 - 9999 */
int year;
/** Month : 1 - 12 */
int month;
/** Day : 1 - 31 */
int day;
/** Hour : 0 - 23 */
int hour;
/** Minute : 0 - 59 */
int min;
/** Seconds : 0 - 59.999 */
double sec;
} lxw_datetime;
enum lxw_custom_property_types {
LXW_CUSTOM_NONE,
LXW_CUSTOM_STRING,
LXW_CUSTOM_DOUBLE,
LXW_CUSTOM_INTEGER,
LXW_CUSTOM_BOOLEAN,
LXW_CUSTOM_DATETIME
};
/* Size of MD5 byte arrays. */
#define LXW_MD5_SIZE 16
/* Excel sheetname max of 31 chars. */
#define LXW_SHEETNAME_MAX 31
/* Max with all worksheet chars 4xUTF-8 bytes + start and end quotes + \0. */
#define LXW_MAX_SHEETNAME_LENGTH ((LXW_SHEETNAME_MAX * 4) + 2 + 1)
/* Max col string length. */
#define LXW_MAX_COL_NAME_LENGTH sizeof("$XFD")
/* Max row string length. */
#define LXW_MAX_ROW_NAME_LENGTH sizeof("$1048576")
/* Max cell string length. */
#define LXW_MAX_CELL_NAME_LENGTH sizeof("$XFWD$1048576")
/* Max range: $XFWD$1048576:$XFWD$1048576\0 */
#define LXW_MAX_CELL_RANGE_LENGTH (LXW_MAX_CELL_NAME_LENGTH * 2)
/* Max range formula Sheet1!$A$1:$C$5$ style. */
#define LXW_MAX_FORMULA_RANGE_LENGTH (LXW_MAX_SHEETNAME_LENGTH + LXW_MAX_CELL_RANGE_LENGTH)
/* Datetime string length. */
#define LXW_DATETIME_LENGTH sizeof("2016-12-12T23:00:00Z")
/* GUID string length. */
#define LXW_GUID_LENGTH sizeof("{12345678-1234-1234-1234-1234567890AB}\0")
#define LXW_EPOCH_1900 0
#define LXW_EPOCH_1904 1
#define LXW_UINT32_T_LENGTH sizeof("4294967296")
#define LXW_FILENAME_LENGTH 128
#define LXW_IGNORE 1
#define LXW_PORTRAIT 1
#define LXW_LANDSCAPE 0
#define LXW_SCHEMA_MS "http://schemas.microsoft.com/office/2006/relationships"
#define LXW_SCHEMA_ROOT "http://schemas.openxmlformats.org"
#define LXW_SCHEMA_DRAWING LXW_SCHEMA_ROOT "/drawingml/2006"
#define LXW_SCHEMA_OFFICEDOC LXW_SCHEMA_ROOT "/officeDocument/2006"
#define LXW_SCHEMA_PACKAGE LXW_SCHEMA_ROOT "/package/2006/relationships"
#define LXW_SCHEMA_DOCUMENT LXW_SCHEMA_ROOT "/officeDocument/2006/relationships"
#define LXW_SCHEMA_CONTENT LXW_SCHEMA_ROOT "/package/2006/content-types"
/* Use REprintf() for error handling when compiled as an R library. */
#ifdef USE_R_LANG
#include
#define LXW_PRINTF REprintf
#define LXW_STDERR
#else
#define LXW_PRINTF fprintf
#define LXW_STDERR stderr,
#endif
#define LXW_ERROR(message) \
LXW_PRINTF(LXW_STDERR "[ERROR][%s:%d]: " message "\n", __FILE__, __LINE__)
#define LXW_MEM_ERROR() \
LXW_ERROR("Memory allocation failed.")
#define GOTO_LABEL_ON_MEM_ERROR(pointer, label) \
do { \
if (!pointer) { \
LXW_MEM_ERROR(); \
goto label; \
} \
} while (0)
#define RETURN_ON_MEM_ERROR(pointer, error) \
do { \
if (!pointer) { \
LXW_MEM_ERROR(); \
return error; \
} \
} while (0)
#define RETURN_VOID_ON_MEM_ERROR(pointer) \
do { \
if (!pointer) { \
LXW_MEM_ERROR(); \
return; \
} \
} while (0)
#define RETURN_ON_ERROR(error) \
do { \
if (error) \
return error; \
} while (0)
#define RETURN_AND_ZIPCLOSE_ON_ERROR(error) \
do { \
if (error) { \
zipClose(self->zipfile, NULL); \
return error; \
} \
} while (0)
#define LXW_WARN(message) \
LXW_PRINTF(LXW_STDERR "[WARNING]: " message "\n")
/* We can't use variadic macros here since we support ANSI C. */
#define LXW_WARN_FORMAT(message) \
LXW_PRINTF(LXW_STDERR "[WARNING]: " message "\n")
#define LXW_WARN_FORMAT1(message, var) \
LXW_PRINTF(LXW_STDERR "[WARNING]: " message "\n", var)
#define LXW_WARN_FORMAT2(message, var1, var2) \
LXW_PRINTF(LXW_STDERR "[WARNING]: " message "\n", var1, var2)
#define LXW_WARN_FORMAT3(message, var1, var2, var3) \
LXW_PRINTF(LXW_STDERR "[WARNING]: " message "\n", var1, var2, var3)
/* Chart axis type checks. */
#define LXW_WARN_CAT_AXIS_ONLY(function) \
do { \
if (!axis->is_category) { \
LXW_PRINTF(LXW_STDERR "[WARNING]: " \
function "() is only valid for category axes\n"); \
return; \
} \
} while (0)
#define LXW_WARN_VALUE_AXIS_ONLY(function) \
do { \
if (!axis->is_value) { \
LXW_PRINTF(LXW_STDERR "[WARNING]: " \
function "() is only valid for value axes\n"); \
return; \
} \
} while (0)
#define LXW_WARN_DATE_AXIS_ONLY(function) \
do { \
if (!axis->is_date) { \
LXW_PRINTF(LXW_STDERR "[WARNING]: " \
function "() is only valid for date axes\n"); \
return; \
} \
} while (0)
#define LXW_WARN_CAT_AND_DATE_AXIS_ONLY(function) \
do { \
if (!axis->is_category && !axis->is_date) { \
LXW_PRINTF(LXW_STDERR "[WARNING]: " \
function "() is only valid for category and date axes\n"); \
return; \
} \
} while (0)
#define LXW_WARN_VALUE_AND_DATE_AXIS_ONLY(function) \
do { \
if (!axis->is_value && !axis->is_date) { \
LXW_PRINTF(LXW_STDERR "[WARNING]: " \
function "() is only valid for value and date axes\n"); \
return; \
} \
} while (0)
#ifndef LXW_BIG_ENDIAN
#define LXW_UINT16_HOST(n) (n)
#define LXW_UINT32_HOST(n) (n)
#define LXW_UINT16_NETWORK(n) ((((n) & 0x00FF) << 8) | (((n) & 0xFF00) >> 8))
#define LXW_UINT32_NETWORK(n) ((((n) & 0xFF) << 24) | \
(((n) & 0xFF00) << 8) | \
(((n) & 0xFF0000) >> 8) | \
(((n) & 0xFF000000) >> 24))
#else
#define LXW_UINT16_NETWORK(n) (n)
#define LXW_UINT32_NETWORK(n) (n)
#define LXW_UINT16_HOST(n) ((((n) & 0x00FF) << 8) | (((n) & 0xFF00) >> 8))
#define LXW_UINT32_HOST(n) ((((n) & 0xFF) << 24) | \
(((n) & 0xFF00) << 8) | \
(((n) & 0xFF0000) >> 8) | \
(((n) & 0xFF000000) >> 24))
#endif
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* Compilers that have a native snprintf() can use it directly. */
#ifdef _MSC_VER
#define LXW_HAS_SNPRINTF
#endif
#ifdef LXW_HAS_SNPRINTF
#define lxw_snprintf snprintf
#else
#define lxw_snprintf __builtin_snprintf
#endif
/* Define a snprintf for MSVC 2010. */
#if defined(_MSC_VER) && _MSC_VER < 1900
#include
#define snprintf msvc2010_snprintf
#define vsnprintf msvc2010_vsnprintf
__inline int
msvc2010_vsnprintf(char *str, size_t size, const char *format, va_list ap)
{
int count = -1;
if (size != 0)
count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
if (count == -1)
count = _vscprintf(format, ap);
return count;
}
__inline int
msvc2010_snprintf(char *str, size_t size, const char *format, ...)
{
int count;
va_list ap;
va_start(ap, format);
count = msvc2010_vsnprintf(str, size, format, ap);
va_end(ap);
return count;
}
#endif
/* Safer strcpy for fixed width char arrays. */
#define lxw_strcpy(dest, src) \
lxw_snprintf(dest, sizeof(dest), "%s", src)
/* Define the queue.h structs for the formats list. */
STAILQ_HEAD(lxw_formats, lxw_format);
/* Define the queue.h structs for the generic data structs. */
STAILQ_HEAD(lxw_tuples, lxw_tuple);
STAILQ_HEAD(lxw_custom_properties, lxw_custom_property);
typedef struct lxw_tuple {
char *key;
char *value;
STAILQ_ENTRY (lxw_tuple) list_pointers;
} lxw_tuple;
/* Define custom property used in workbook.c and custom.c. */
typedef struct lxw_custom_property {
enum lxw_custom_property_types type;
char *name;
union {
char *string;
double number;
int32_t integer;
uint8_t boolean;
lxw_datetime datetime;
} u;
STAILQ_ENTRY (lxw_custom_property) list_pointers;
} lxw_custom_property;
/* Declarations required for unit testing. */
#ifdef TESTING
#endif /* TESTING */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* __LXW_COMMON_H__ */
writexl/src/tmpfileplus/ 0000755 0001762 0000144 00000000000 14766110233 015106 5 ustar ligges users writexl/src/tmpfileplus/tmpfileplus.c 0000644 0001762 0000144 00000021473 14747162622 017635 0 ustar ligges users /* $Id: tmpfileplus.c $ */
/*
* $Date: 2016-06-01 03:31Z $
* $Revision: 2.0.0 $
* $Author: dai $
*/
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright (c) 2012-16 David Ireland, DI Management Services Pty Ltd
* .
*/
/*
* NAME
* tmpfileplus - create a unique temporary file
*
* SYNOPSIS
* FILE *tmpfileplus(const char *dir, const char *prefix, char **pathname, int keep)
*
* DESCRIPTION
* The tmpfileplus() function opens a unique temporary file in binary
* read/write (w+b) mode. The file is opened with the O_EXCL flag,
* guaranteeing that the caller is the only user. The filename will consist
* of the string given by `prefix` followed by 10 random characters. If
* `prefix` is NULL, then the string "tmp." will be used instead. The file
* will be created in an appropriate directory chosen by the first
* successful attempt in the following sequence:
*
* a) The directory given by the `dir` argument (so the caller can specify
* a secure directory to take precedence).
*
* b) The directory name in the environment variables:
*
* (i) "TMP" [Windows only]
* (ii) "TEMP" [Windows only]
* (iii) "TMPDIR" [Unix only]
*
* c) `P_tmpdir` as defined in [Unix only] (in Windows, this is
* usually "\", which is no good).
*
* d) The current working directory.
*
* If a file cannot be created in any of the above directories, then the
* function fails and NULL is returned.
*
* If the argument `pathname` is not a null pointer, then it will point to
* the full pathname of the file. The pathname is allocated using `malloc`
* and therefore should be freed by `free`.
*
* If `keep` is nonzero and `pathname` is not a null pointer, then the file
* will be kept after it is closed. Otherwise the file will be
* automatically deleted when it is closed or the program terminates.
*
*
* RETURN VALUE
* The tmpfileplus() function returns a pointer to the open file stream,
* or NULL if a unique file cannot be opened.
*
*
* ERRORS
* ENOMEM Not enough memory to allocate filename.
*
*/
/* ADDED IN v2.0 */
/*
* NAME
* tmpfileplus_f - create a unique temporary file with filename stored in a fixed-length buffer
*
* SYNOPSIS
* FILE *tmpfileplus_f(const char *dir, const char *prefix, char *pathnamebuf, size_t pathsize, int keep);
*
* DESCRIPTION
* Same as tmpfileplus() except receives filename in a fixed-length buffer. No allocated memory to free.
* ERRORS
* E2BIG Resulting filename is too big for the buffer `pathnamebuf`.
*/
#include "tmpfileplus.h"
#include
#include
#include
#include
#include
/* Non-ANSI include files that seem to work in both MSVC and Linux */
#include
#include
#include
#ifdef _WIN32
#include
#else
#include
#endif
#ifdef _WIN32
/* MSVC nags to enforce ISO C++ conformant function names with leading "_",
* so we define our own function names to avoid whingeing compilers...
*/
#define OPEN_ _open
#define FDOPEN_ _fdopen
#else
#define OPEN_ open
#define FDOPEN_ fdopen
#endif
/* DEBUGGING STUFF */
#if defined(_DEBUG) && defined(SHOW_DPRINTF)
#define DPRINTF1(s, a1) printf(s, a1)
#else
#define DPRINTF1(s, a1)
#endif
#ifdef _WIN32
#define FILE_SEPARATOR "\\"
#else
#define FILE_SEPARATOR "/"
#endif
#define RANDCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
#define NRANDCHARS (sizeof(RANDCHARS) - 1)
/** Replace each byte in string s with a random character from TEMPCHARS */
static char *set_randpart(char *s)
{
size_t i;
unsigned int r;
static unsigned int seed; /* NB static */
if (seed == 0)
{ /* First time set our seed using current time and clock */
seed = ((unsigned)time(NULL)<<8) ^ (unsigned)clock();
}
srand(seed++);
for (i = 0; i < strlen(s); i++)
{
r = rand() % NRANDCHARS;
s[i] = (RANDCHARS)[r];
}
return s;
}
/** Return 1 if path is a valid directory otherwise 0 */
static int is_valid_dir(const char *path)
{
struct stat st;
if ((stat(path, &st) == 0) && (st.st_mode & S_IFDIR))
return 1;
return 0;
}
/** Call getenv and save a copy in buf */
static char *getenv_save(const char *varname, char *buf, size_t bufsize)
{
char *ptr = getenv(varname);
buf[0] = '\0';
if (ptr)
{
strncpy(buf, ptr, bufsize-1);
buf[bufsize-1] = '\0';
return buf;
}
return NULL;
}
/**
* Try and create a randomly-named file in directory `tmpdir`.
* If successful, allocate memory and set `tmpname_ptr` to full filepath, and return file pointer;
* otherwise return NULL.
* If `keep` is zero then create the file as temporary and it should not exist once closed.
*/
static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmpname_ptr, int keep)
/* PRE:
* pfx is not NULL and points to a valid null-terminated string
* tmpname_ptr is not NULL.
*/
{
FILE *fp;
int fd = 0;
char randpart[] = "1234567890";
size_t lentempname;
int i;
char *tmpname = NULL;
int oflag, pmode;
/* In Windows, we use the _O_TEMPORARY flag with `open` to ensure the file is deleted when closed.
* In Unix, we use the unlink function after opening the file. (This does not work in Windows,
* which does not allow an open file to be unlinked.)
*/
#ifdef _WIN32
/* MSVC flags */
oflag = _O_BINARY|_O_CREAT|_O_EXCL|_O_RDWR;
if (!keep)
oflag |= _O_TEMPORARY;
pmode = _S_IREAD | _S_IWRITE;
#else
/* Standard POSIX flags */
oflag = O_CREAT|O_EXCL|O_RDWR;
pmode = S_IRUSR|S_IWUSR;
#endif
if (!tmpdir || !is_valid_dir(tmpdir)) {
errno = ENOENT;
return NULL;
}
lentempname = strlen(tmpdir) + strlen(FILE_SEPARATOR) + strlen(pfx) + strlen(randpart);
DPRINTF1("lentempname=%d\n", lentempname);
tmpname = malloc(lentempname + 1);
if (!tmpname)
{
errno = ENOMEM;
return NULL;
}
/* If we don't manage to create a file after 10 goes, there is something wrong... */
for (i = 0; i < 10; i++)
{
sprintf(tmpname, "%s%s%s%s", tmpdir, FILE_SEPARATOR, pfx, set_randpart(randpart));
DPRINTF1("[%s]\n", tmpname);
fd = OPEN_(tmpname, oflag, pmode);
if (fd != -1) break;
}
DPRINTF1("strlen(tmpname)=%d\n", strlen(tmpname));
if (fd != -1)
{ /* Success, so return user a proper ANSI C file pointer */
fp = FDOPEN_(fd, "w+b");
errno = 0;
#ifndef _WIN32
/* [Unix only] And make sure the file will be deleted once closed */
if (!keep) unlink(tmpname);
#endif
}
else
{ /* We failed */
fp = NULL;
}
if (!fp)
{
free(tmpname);
tmpname = NULL;
}
*tmpname_ptr = tmpname;
return fp;
}
/**********************/
/* EXPORTED FUNCTIONS */
/**********************/
FILE *tmpfileplus(const char *dir, const char *prefix, char **pathname, int keep)
{
FILE *fp = NULL;
char *tmpname = NULL;
char *tmpdir = NULL;
const char *pfx = (prefix ? prefix : "tmp.");
char *tempdirs[12] = { 0 };
#ifdef _WIN32
char env1[FILENAME_MAX+1] = { 0 };
char env2[FILENAME_MAX+1] = { 0 };
#else
char env3[FILENAME_MAX+1] = { 0 };
#endif
int ntempdirs = 0;
int i;
/* Set up a list of temp directories we will try in order */
i = 0;
tempdirs[i++] = (char *)dir;
#ifdef _WIN32
tempdirs[i++] = getenv_save("TMP", env1, sizeof(env1));
tempdirs[i++] = getenv_save("TEMP", env2, sizeof(env2));
#else
tempdirs[i++] = getenv_save("TMPDIR", env3, sizeof(env3));
tempdirs[i++] = P_tmpdir;
#endif
tempdirs[i++] = ".";
ntempdirs = i;
errno = 0;
/* Work through list we set up before, and break once we are successful */
for (i = 0; i < ntempdirs; i++)
{
tmpdir = tempdirs[i];
DPRINTF1("Trying tmpdir=[%s]\n", tmpdir);
fp = mktempfile_internal(tmpdir, pfx, &tmpname, keep);
if (fp) break;
}
/* If we succeeded and the user passed a pointer, set it to the alloc'd pathname: the user must free this */
if (fp && pathname)
*pathname = tmpname;
else /* Otherwise, free the alloc'd memory */
free(tmpname);
return fp;
}
/* Same as tmpfileplus() but with fixed length buffer for output filename and no memory allocation */
FILE *tmpfileplus_f(const char *dir, const char *prefix, char *pathnamebuf, size_t pathsize, int keep)
{
char *tmpbuf = NULL;
FILE *fp;
/* If no buffer provided, do the normal way */
if (!pathnamebuf || (int)pathsize <= 0) {
return tmpfileplus(dir, prefix, NULL, keep);
}
/* Call with a temporary buffer */
fp = tmpfileplus(dir, prefix, &tmpbuf, keep);
if (fp && strlen(tmpbuf) > pathsize - 1) {
/* Succeeded but not enough room in output buffer, so clean up and return an error */
pathnamebuf[0] = 0;
fclose(fp);
if (keep) remove(tmpbuf);
free(tmpbuf);
errno = E2BIG;
return NULL;
}
/* Copy name into buffer */
strcpy(pathnamebuf, tmpbuf);
free(tmpbuf);
return fp;
}
writexl/src/tmpfileplus/tmpfileplus.h 0000644 0001762 0000144 00000004144 14747162622 017636 0 ustar ligges users /* $Id: tmpfileplus.h $ */
/*
* $Date: 2016-06-01 03:31Z $
* $Revision: 2.0.0 $
* $Author: dai $
*/
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright (c) 2012-16 David Ireland, DI Management Services Pty Ltd
* .
*/
#if _MSC_VER > 1000
#pragma once
#endif
#ifndef TMPFILEPLUS_H_
#define TMPFILEPLUS_H_
#include
/** Create a unique temporary file.
@param dir (optional) directory to create file. If NULL use default TMP directory.
@param prefix (optional) prefix for file name. If NULL use "tmp.".
@param pathname (optional) pointer to a buffer to receive the temp filename.
Allocated using `malloc()`; user to free. Ignored if NULL.
@param keep If `keep` is nonzero and `pathname` is not NULL, then keep the file after closing.
Otherwise file is automatically deleted when closed.
@return Pointer to stream opened in binary read/write (w+b) mode, or a null pointer on error.
@exception ENOMEM Not enough memory to allocate filename.
*/
FILE *tmpfileplus(const char *dir, const char *prefix, char **pathname, int keep);
/** Create a unique temporary file with filename stored in a fixed-length buffer.
@param dir (optional) directory to create file. If NULL use default directory.
@param prefix (optional) prefix for file name. If NULL use "tmp.".
@param pathnamebuf (optional) buffer to receive full pathname of temporary file. Ignored if NULL.
@param pathsize Size of buffer to receive filename and its terminating null character.
@param keep If `keep` is nonzero and `pathname` is not NULL, then keep the file after closing.
Otherwise file is automatically deleted when closed.
@return Pointer to stream opened in binary read/write (w+b) mode, or a null pointer on error.
@exception E2BIG Resulting filename is too big for the buffer `pathnamebuf`.
*/
FILE *tmpfileplus_f(const char *dir, const char *prefix, char *pathnamebuf, size_t pathsize, int keep);
#define TMPFILE_KEEP 1
#endif /* end TMPFILEPLUS_H_ */
writexl/src/write_xlsx.c 0000644 0001762 0000144 00000016504 14747162622 015134 0 ustar ligges users #define R_NO_REMAP
#define STRICT_R_HEADERS
#include
#include
#include
#include
#include
typedef enum {
COL_LOGICAL,
COL_REAL,
COL_INTEGER,
COL_STRING,
COL_DATE,
COL_POSIXCT,
COL_HYPERLINK,
COL_FORMULA,
COL_BLANK,
COL_UNKNOWN
} R_COL_TYPE;
#define assert_that(a, b) bail_if(!a, b)
#define max(a,b) (a > b) ? a : b
static void bail_if(int check, const char * error){
if(check)
Rf_errorcall(R_NilValue, "Error in writexl: %s", error);
}
static void assert_lxw(lxw_error err){
if(err != LXW_NO_ERROR)
Rf_errorcall(R_NilValue, "Error in libxlsxwriter: '%s'", lxw_strerror(err));
}
static R_COL_TYPE get_type(SEXP col){
if(Rf_inherits(col, "Date"))
return COL_DATE;
if(Rf_inherits(col, "POSIXct"))
return COL_POSIXCT;
if(Rf_inherits(col, "xl_hyperlink"))
return COL_HYPERLINK;
if(Rf_isString(col) && Rf_inherits(col, "xl_formula"))
return COL_FORMULA;
switch(TYPEOF(col)){
case STRSXP:
return COL_STRING;
case INTSXP:
return COL_INTEGER;
case REALSXP:
return COL_REAL;
case LGLSXP:
return COL_LOGICAL;
default:
return COL_UNKNOWN;
};
}
//global options
static char TEMPDIR[2048] = {0};
//set to R tempdir when pkg is loaded
SEXP C_set_tempdir(SEXP dir){
strcpy(TEMPDIR, Rf_translateChar(STRING_ELT(dir, 0)));
return Rf_mkString(TEMPDIR);
}
SEXP C_write_data_frame_list(SEXP df_list, SEXP file, SEXP col_names, SEXP format_headers, SEXP use_zip64){
assert_that(Rf_isVectorList(df_list), "Object is not a list");
assert_that(Rf_isString(file) && Rf_length(file), "Invalid file path");
assert_that(Rf_isLogical(col_names), "col_names must be logical");
assert_that(Rf_isLogical(format_headers), "format_headers must be logical");
//create workbook
lxw_workbook_options options = {
.constant_memory = 1,
.tmpdir = TEMPDIR,
.use_zip64 = Rf_asLogical(use_zip64)
};
lxw_workbook *workbook = workbook_new_opt(Rf_translateChar(STRING_ELT(file, 0)), &options);
assert_that(workbook, "failed to create workbook");
//how to format dates
lxw_format * date = workbook_add_format(workbook);
format_set_num_format(date, "yyyy-mm-dd");
//how to format timetamps
lxw_format * datetime = workbook_add_format(workbook);
format_set_num_format(datetime, "yyyy-mm-dd HH:mm:ss UTC");
//how to format headers (bold + center)
lxw_format * title = workbook_add_format(workbook);
format_set_bold(title);
format_set_align(title, LXW_ALIGN_CENTER);
//how to format hyperlinks (underline + blue)
lxw_format * hyperlink = workbook_add_format(workbook);
format_set_underline(hyperlink, LXW_UNDERLINE_SINGLE);
format_set_font_color(hyperlink, LXW_COLOR_BLUE);
//iterate over sheets
SEXP df_names = PROTECT(Rf_getAttrib(df_list, R_NamesSymbol));
for(size_t s = 0; s < Rf_length(df_list); s++){
//create sheet
const char * sheet_name = Rf_length(df_names) > s && Rf_length(STRING_ELT(df_names, s)) ? \
Rf_translateCharUTF8(STRING_ELT(df_names, s)) : NULL;
lxw_worksheet *sheet = workbook_add_worksheet(workbook, sheet_name);
assert_that(sheet, "failed to create workbook");
//get data frame
size_t cursor = 0;
SEXP df = VECTOR_ELT(df_list, s);
assert_that(Rf_inherits(df, "data.frame"), "object is not a data frame");
//create header row
if(Rf_asLogical(col_names)){
SEXP names = PROTECT(Rf_getAttrib(df, R_NamesSymbol));
for(size_t i = 0; i < Rf_length(names); i++)
worksheet_write_string(sheet, cursor, i, Rf_translateCharUTF8(STRING_ELT(names, i)), NULL);
if(Rf_asLogical(format_headers))
assert_lxw(worksheet_set_row(sheet, cursor, 15, title));
UNPROTECT(1);
cursor++;
}
// number of records
size_t cols = Rf_length(df);
size_t rows = 0;
// determinte how to format each column
R_COL_TYPE coltypes[cols];
for(size_t i = 0; i < cols; i++){
SEXP COL = VECTOR_ELT(df, i);
coltypes[i] = get_type(COL);
if(!Rf_isMatrix(COL) && !Rf_inherits(COL, "data.frame"))
rows = max(rows, Rf_length(COL));
if(coltypes[i] == COL_DATE)
assert_lxw(worksheet_set_column(sheet, i, i, 20, date));
if(coltypes[i] == COL_POSIXCT)
assert_lxw(worksheet_set_column(sheet, i, i, 20, datetime));
}
// Need to iterate by row first for performance
for (size_t i = 0; i < rows; i++) {
for(size_t j = 0; j < cols; j++){
SEXP col = VECTOR_ELT(df, j);
switch(coltypes[j]){
case COL_DATE:{
double val = Rf_isReal(col) ? REAL(col)[i] : INTEGER(col)[i];
if(Rf_isReal(col) ? R_FINITE(val) : val != NA_INTEGER)
assert_lxw(worksheet_write_number(sheet, cursor, j, 25569 + val, NULL));
}; continue;
case COL_POSIXCT: {
double val = REAL(col)[i];
if(R_FINITE(val)){
val = 25568.0 + val / (24*60*60);
if(val >= 60.0)
val = val + 1.0;
assert_lxw(worksheet_write_number(sheet, cursor, j, val , NULL));
}
}; continue;
case COL_STRING:{
SEXP val = STRING_ELT(col, i);
// NB: xlsx does distinguish between empty string and NA
if(val != NA_STRING && Rf_length(val))
assert_lxw(worksheet_write_string(sheet, cursor, j, Rf_translateCharUTF8(val), NULL));
}; continue;
case COL_FORMULA:{
SEXP val = STRING_ELT(col, i);
if(val != NA_STRING && Rf_length(val))
assert_lxw(worksheet_write_formula(sheet, cursor, j, Rf_translateCharUTF8(val), NULL));
}; continue;
case COL_HYPERLINK:{
SEXP val = STRING_ELT(col, i);
if(val != NA_STRING && Rf_length(val))
assert_lxw(worksheet_write_formula(sheet, cursor, j, Rf_translateCharUTF8(val), hyperlink));
}; continue;
case COL_REAL:{
double val = REAL(col)[i];
if(val == R_PosInf)
assert_lxw(worksheet_write_string(sheet, cursor, j, "Inf", NULL));
else if(val == R_NegInf)
assert_lxw(worksheet_write_string(sheet, cursor, j, "-Inf", NULL));
else if(R_FINITE(val)) // skips NA and NAN
assert_lxw(worksheet_write_number(sheet, cursor, j, val, NULL));
}; continue;
case COL_INTEGER:{
int val = INTEGER(col)[i];
if(val != NA_INTEGER)
assert_lxw(worksheet_write_number(sheet, cursor, j, val, NULL));
}; continue;
case COL_LOGICAL:{
int val = LOGICAL(col)[i];
if(val != NA_LOGICAL)
assert_lxw(worksheet_write_boolean(sheet, cursor, j, val, NULL));
}; continue;
default:
continue;
};
}
cursor++;
}
}
//this both writes the xlsx file and frees the memory
assert_lxw(workbook_close(workbook));
UNPROTECT(1);
return file;
}
SEXP C_lxw_version(void){
return Rf_mkString(LXW_VERSION);
}
static const R_CallMethodDef CallEntries[] = {
{"C_lxw_version", (DL_FUNC) &C_lxw_version, 0},
{"C_set_tempdir", (DL_FUNC) &C_set_tempdir, 1},
{"C_write_data_frame_list", (DL_FUNC) &C_write_data_frame_list, 5},
{NULL, NULL, 0}
};
attribute_visible void R_init_writexl(DllInfo *dll) {
R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
R_useDynamicSymbols(dll, FALSE);
R_forceSymbols(dll, TRUE);
}
writexl/src/libxlsxwriter/ 0000755 0001762 0000144 00000000000 14766110233 015464 5 ustar ligges users writexl/src/libxlsxwriter/content_types.c 0000644 0001762 0000144 00000023146 14747162622 020544 0 ustar ligges users /*****************************************************************************
* content_types - A library for creating Excel XLSX content_types files.
*
* Used in conjunction with the libxlsxwriter library.
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
*/
#include "xlsxwriter/xmlwriter.h"
#include "xlsxwriter/content_types.h"
#include "xlsxwriter/utility.h"
/*
* Forward declarations.
*/
/*****************************************************************************
*
* Private functions.
*
****************************************************************************/
/*
* Create a new content_types object.
*/
lxw_content_types *
lxw_content_types_new(void)
{
lxw_content_types *content_types = calloc(1, sizeof(lxw_content_types));
GOTO_LABEL_ON_MEM_ERROR(content_types, mem_error);
content_types->default_types = calloc(1, sizeof(struct lxw_tuples));
GOTO_LABEL_ON_MEM_ERROR(content_types->default_types, mem_error);
STAILQ_INIT(content_types->default_types);
content_types->overrides = calloc(1, sizeof(struct lxw_tuples));
GOTO_LABEL_ON_MEM_ERROR(content_types->overrides, mem_error);
STAILQ_INIT(content_types->overrides);
lxw_ct_add_default(content_types, "rels",
LXW_APP_PACKAGE "relationships+xml");
lxw_ct_add_default(content_types, "xml", "application/xml");
lxw_ct_add_override(content_types, "/docProps/app.xml",
LXW_APP_DOCUMENT "extended-properties+xml");
lxw_ct_add_override(content_types, "/docProps/core.xml",
LXW_APP_PACKAGE "core-properties+xml");
lxw_ct_add_override(content_types, "/xl/styles.xml",
LXW_APP_DOCUMENT "spreadsheetml.styles+xml");
lxw_ct_add_override(content_types, "/xl/theme/theme1.xml",
LXW_APP_DOCUMENT "theme+xml");
return content_types;
mem_error:
lxw_content_types_free(content_types);
return NULL;
}
/*
* Free a content_types object.
*/
void
lxw_content_types_free(lxw_content_types *content_types)
{
lxw_tuple *default_type;
lxw_tuple *override;
if (!content_types)
return;
if (content_types->default_types) {
while (!STAILQ_EMPTY(content_types->default_types)) {
default_type = STAILQ_FIRST(content_types->default_types);
STAILQ_REMOVE_HEAD(content_types->default_types, list_pointers);
free(default_type->key);
free(default_type->value);
free(default_type);
}
free(content_types->default_types);
}
if (content_types->overrides) {
while (!STAILQ_EMPTY(content_types->overrides)) {
override = STAILQ_FIRST(content_types->overrides);
STAILQ_REMOVE_HEAD(content_types->overrides, list_pointers);
free(override->key);
free(override->value);
free(override);
}
free(content_types->overrides);
}
free(content_types);
}
/*****************************************************************************
*
* XML functions.
*
****************************************************************************/
/*
* Write the XML declaration.
*/
STATIC void
_content_types_xml_declaration(lxw_content_types *self)
{
lxw_xml_declaration(self->file);
}
/*
* Write the element.
*/
STATIC void
_write_types(lxw_content_types *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("xmlns", LXW_SCHEMA_CONTENT);
lxw_xml_start_tag(self->file, "Types", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_default(lxw_content_types *self, const char *ext, const char *type)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("Extension", ext);
LXW_PUSH_ATTRIBUTES_STR("ContentType", type);
lxw_xml_empty_tag(self->file, "Default", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_override(lxw_content_types *self, const char *part_name,
const char *type)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("PartName", part_name);
LXW_PUSH_ATTRIBUTES_STR("ContentType", type);
lxw_xml_empty_tag(self->file, "Override", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*****************************************************************************
*
* XML file assembly functions.
*
****************************************************************************/
/*
* Write out all of the types.
*/
STATIC void
_write_defaults(lxw_content_types *self)
{
lxw_tuple *tuple;
STAILQ_FOREACH(tuple, self->default_types, list_pointers) {
_write_default(self, tuple->key, tuple->value);
}
}
/*
* Write out all of the types.
*/
STATIC void
_write_overrides(lxw_content_types *self)
{
lxw_tuple *tuple;
STAILQ_FOREACH(tuple, self->overrides, list_pointers) {
_write_override(self, tuple->key, tuple->value);
}
}
/*
* Assemble and write the XML file.
*/
void
lxw_content_types_assemble_xml_file(lxw_content_types *self)
{
/* Write the XML declaration. */
_content_types_xml_declaration(self);
_write_types(self);
_write_defaults(self);
_write_overrides(self);
/* Close the content_types tag. */
lxw_xml_end_tag(self->file, "Types");
}
/*****************************************************************************
*
* Public functions.
*
****************************************************************************/
/*
* Add elements to the ContentTypes defaults.
*/
void
lxw_ct_add_default(lxw_content_types *self, const char *key,
const char *value)
{
lxw_tuple *tuple;
if (!key || !value)
return;
tuple = calloc(1, sizeof(lxw_tuple));
GOTO_LABEL_ON_MEM_ERROR(tuple, mem_error);
tuple->key = lxw_strdup(key);
GOTO_LABEL_ON_MEM_ERROR(tuple->key, mem_error);
tuple->value = lxw_strdup(value);
GOTO_LABEL_ON_MEM_ERROR(tuple->value, mem_error);
STAILQ_INSERT_TAIL(self->default_types, tuple, list_pointers);
return;
mem_error:
if (tuple) {
free(tuple->key);
free(tuple->value);
free(tuple);
}
}
/*
* Add elements to the ContentTypes overrides.
*/
void
lxw_ct_add_override(lxw_content_types *self, const char *key,
const char *value)
{
lxw_tuple *tuple;
if (!key || !value)
return;
tuple = calloc(1, sizeof(lxw_tuple));
GOTO_LABEL_ON_MEM_ERROR(tuple, mem_error);
tuple->key = lxw_strdup(key);
GOTO_LABEL_ON_MEM_ERROR(tuple->key, mem_error);
tuple->value = lxw_strdup(value);
GOTO_LABEL_ON_MEM_ERROR(tuple->value, mem_error);
STAILQ_INSERT_TAIL(self->overrides, tuple, list_pointers);
return;
mem_error:
if (tuple) {
free(tuple->key);
free(tuple->value);
free(tuple);
}
}
/*
* Add the name of a worksheet to the ContentTypes overrides.
*/
void
lxw_ct_add_worksheet_name(lxw_content_types *self, const char *name)
{
lxw_ct_add_override(self, name,
LXW_APP_DOCUMENT "spreadsheetml.worksheet+xml");
}
/*
* Add the name of a chartsheet to the ContentTypes overrides.
*/
void
lxw_ct_add_chartsheet_name(lxw_content_types *self, const char *name)
{
lxw_ct_add_override(self, name,
LXW_APP_DOCUMENT "spreadsheetml.chartsheet+xml");
}
/*
* Add the name of a chart to the ContentTypes overrides.
*/
void
lxw_ct_add_chart_name(lxw_content_types *self, const char *name)
{
lxw_ct_add_override(self, name, LXW_APP_DOCUMENT "drawingml.chart+xml");
}
/*
* Add the name of a drawing to the ContentTypes overrides.
*/
void
lxw_ct_add_drawing_name(lxw_content_types *self, const char *name)
{
lxw_ct_add_override(self, name, LXW_APP_DOCUMENT "drawing+xml");
}
/*
* Add the name of a table to the ContentTypes overrides.
*/
void
lxw_ct_add_table_name(lxw_content_types *self, const char *name)
{
lxw_ct_add_override(self, name,
LXW_APP_DOCUMENT "spreadsheetml.table+xml");
}
/*
* Add the name of a VML drawing to the ContentTypes overrides.
*/
void
lxw_ct_add_vml_name(lxw_content_types *self)
{
lxw_ct_add_default(self, "vml", LXW_APP_DOCUMENT "vmlDrawing");
}
/*
* Add the name of a comment to the ContentTypes overrides.
*/
void
lxw_ct_add_comment_name(lxw_content_types *self, const char *name)
{
lxw_ct_add_override(self, name,
LXW_APP_DOCUMENT "spreadsheetml.comments+xml");
}
/*
* Add the sharedStrings link to the ContentTypes overrides.
*/
void
lxw_ct_add_shared_strings(lxw_content_types *self)
{
lxw_ct_add_override(self, "/xl/sharedStrings.xml",
LXW_APP_DOCUMENT "spreadsheetml.sharedStrings+xml");
}
/*
* Add the calcChain link to the ContentTypes overrides.
*/
void
lxw_ct_add_calc_chain(lxw_content_types *self)
{
lxw_ct_add_override(self, "/xl/calcChain.xml",
LXW_APP_DOCUMENT "spreadsheetml.calcChain+xml");
}
/*
* Add the custom properties to the ContentTypes overrides.
*/
void
lxw_ct_add_custom_properties(lxw_content_types *self)
{
lxw_ct_add_override(self, "/docProps/custom.xml",
LXW_APP_DOCUMENT "custom-properties+xml");
}
/*
* Add the metadata file to the ContentTypes overrides.
*/
void
lxw_ct_add_metadata(lxw_content_types *self)
{
lxw_ct_add_override(self, "/xl/metadata.xml",
LXW_APP_DOCUMENT "spreadsheetml.sheetMetadata+xml");
}
writexl/src/libxlsxwriter/utility.c 0000644 0001762 0000144 00000042171 14747162622 017350 0 ustar ligges users /*****************************************************************************
* utility - Utility functions for libxlsxwriter.
*
* Used in conjunction with the libxlsxwriter library.
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
*/
#ifdef USE_FMEMOPEN
#define _POSIX_C_SOURCE 200809L
#endif
#include
#include
#include
#include
#include
#include "xlsxwriter.h"
#include "xlsxwriter/common.h"
#include "xlsxwriter/third_party/tmpfileplus.h"
#ifdef USE_DTOA_LIBRARY
#include "xlsxwriter/third_party/emyg_dtoa.h"
#endif
char *error_strings[LXW_MAX_ERRNO + 1] = {
"No error.",
"Memory error, failed to malloc() required memory.",
"Error creating output xlsx file. Usually a permissions error.",
"Error encountered when creating a tmpfile during file assembly.",
"Error reading a tmpfile.",
"Zip generic error ZIP_ERRNO while creating the xlsx file.",
"Zip error ZIP_PARAMERROR while creating the xlsx file.",
"Zip error ZIP_BADZIPFILE (use_zip64 option may be required).",
"Zip error ZIP_INTERNALERROR while creating the xlsx file.",
"File error or unknown zip error when adding sub file to xlsx file.",
"Unknown zip error when closing xlsx file.",
"Feature is not currently supported in this configuration.",
"NULL function parameter ignored.",
"Function parameter validation error.",
"Worksheet name exceeds Excel's limit of 31 characters.",
"Worksheet name cannot contain invalid characters: '[ ] : * ? / \\'",
"Worksheet name cannot start or end with an apostrophe.",
"Worksheet name is already in use.",
"Parameter exceeds Excel's limit of 32 characters.",
"Parameter exceeds Excel's limit of 128 characters.",
"Parameter exceeds Excel's limit of 255 characters.",
"String exceeds Excel's limit of 32,767 characters.",
"Error finding internal string index.",
"Worksheet row or column index out of range.",
"Maximum hyperlink length (2079) exceeded.",
"Maximum number of worksheet URLs (65530) exceeded.",
"Couldn't read image dimensions or DPI.",
"Unknown error number."
};
char *
lxw_strerror(lxw_error error_num)
{
if (error_num > LXW_MAX_ERRNO)
error_num = LXW_MAX_ERRNO;
return error_strings[error_num];
}
/*
* Convert Excel A-XFD style column name to zero based number.
*/
void
lxw_col_to_name(char *col_name, lxw_col_t col_num, uint8_t absolute)
{
uint8_t pos = 0;
size_t len;
size_t i;
/* Change from 0 index to 1 index. */
col_num++;
/* Convert the column number to a string in reverse order. */
while (col_num) {
/* Get the remainder in base 26. */
int remainder = col_num % 26;
if (remainder == 0)
remainder = 26;
/* Convert the remainder value to a character. */
col_name[pos++] = 'A' + remainder - 1;
col_name[pos] = '\0';
/* Get the next order of magnitude. */
col_num = (col_num - 1) / 26;
}
if (absolute) {
col_name[pos] = '$';
col_name[pos + 1] = '\0';
}
/* Reverse the column name string. */
len = strlen(col_name);
for (i = 0; i < (len / 2); i++) {
char tmp = col_name[i];
col_name[i] = col_name[len - i - 1];
col_name[len - i - 1] = tmp;
}
}
/*
* Convert zero indexed row and column to an Excel style A1 cell reference.
*/
void
lxw_rowcol_to_cell(char *cell_name, lxw_row_t row, lxw_col_t col)
{
size_t pos;
/* Add the column to the cell. */
lxw_col_to_name(cell_name, col, 0);
/* Get the end of the cell. */
pos = strlen(cell_name);
/* Add the row to the cell. */
lxw_snprintf(&cell_name[pos], LXW_MAX_ROW_NAME_LENGTH, "%d", ++row);
}
/*
* Convert zero indexed row and column to an Excel style $A$1 cell with
* an absolute reference.
*/
void
lxw_rowcol_to_cell_abs(char *cell_name, lxw_row_t row, lxw_col_t col,
uint8_t abs_row, uint8_t abs_col)
{
size_t pos;
/* Add the column to the cell. */
lxw_col_to_name(cell_name, col, abs_col);
/* Get the end of the cell. */
pos = strlen(cell_name);
if (abs_row)
cell_name[pos++] = '$';
/* Add the row to the cell. */
lxw_snprintf(&cell_name[pos], LXW_MAX_ROW_NAME_LENGTH, "%d", ++row);
}
/*
* Convert zero indexed row and column pair to an Excel style A1:C5
* range reference.
*/
void
lxw_rowcol_to_range(char *range,
lxw_row_t first_row, lxw_col_t first_col,
lxw_row_t last_row, lxw_col_t last_col)
{
size_t pos;
/* Add the first cell to the range. */
lxw_rowcol_to_cell(range, first_row, first_col);
/* If the start and end cells are the same just return a single cell. */
if (first_row == last_row && first_col == last_col)
return;
/* Get the end of the cell. */
pos = strlen(range);
/* Add the range separator. */
range[pos++] = ':';
/* Add the first cell to the range. */
lxw_rowcol_to_cell(&range[pos], last_row, last_col);
}
/*
* Convert zero indexed row and column pairs to an Excel style $A$1:$C$5
* range reference with absolute values.
*/
void
lxw_rowcol_to_range_abs(char *range,
lxw_row_t first_row, lxw_col_t first_col,
lxw_row_t last_row, lxw_col_t last_col)
{
size_t pos;
/* Add the first cell to the range. */
lxw_rowcol_to_cell_abs(range, first_row, first_col, 1, 1);
/* If the start and end cells are the same just return a single cell. */
if (first_row == last_row && first_col == last_col)
return;
/* Get the end of the cell. */
pos = strlen(range);
/* Add the range separator. */
range[pos++] = ':';
/* Add the first cell to the range. */
lxw_rowcol_to_cell_abs(&range[pos], last_row, last_col, 1, 1);
}
/*
* Convert sheetname and zero indexed row and column pairs to an Excel style
* Sheet1!$A$1:$C$5 formula reference with absolute values.
*/
void
lxw_rowcol_to_formula_abs(char *formula, const char *sheetname,
lxw_row_t first_row, lxw_col_t first_col,
lxw_row_t last_row, lxw_col_t last_col)
{
size_t pos;
char *quoted_name = lxw_quote_sheetname(sheetname);
strncpy(formula, quoted_name, LXW_MAX_FORMULA_RANGE_LENGTH - 1);
free(quoted_name);
/* Get the end of the sheetname. */
pos = strlen(formula);
/* Add the range separator. */
formula[pos++] = '!';
/* Add the first cell to the range. */
lxw_rowcol_to_cell_abs(&formula[pos], first_row, first_col, 1, 1);
/* If the start and end cells are the same just return a single cell. */
if (first_row == last_row && first_col == last_col)
return;
/* Get the end of the cell. */
pos = strlen(formula);
/* Add the range separator. */
formula[pos++] = ':';
/* Add the first cell to the range. */
lxw_rowcol_to_cell_abs(&formula[pos], last_row, last_col, 1, 1);
}
/*
* Convert an Excel style A1 cell reference to a zero indexed row number.
*/
lxw_row_t
lxw_name_to_row(const char *row_str)
{
lxw_row_t row_num = 0;
const char *p = row_str;
/* Skip the column letters and absolute symbol of the A1 cell. */
while (p && !isdigit((unsigned char) *p))
p++;
/* Convert the row part of the A1 cell to a number. */
if (p)
row_num = atoi(p);
if (row_num)
return row_num - 1;
else
return 0;
}
/*
* Convert an Excel style A1 cell reference to a zero indexed column number.
*/
lxw_col_t
lxw_name_to_col(const char *col_str)
{
lxw_col_t col_num = 0;
const char *p = col_str;
/* Convert leading column letters of A1 cell. Ignore absolute $ marker. */
while (p && (isupper((unsigned char) *p) || *p == '$')) {
if (*p != '$')
col_num = (col_num * 26) + (*p - 'A' + 1);
p++;
}
return col_num - 1;
}
/*
* Convert the second row of an Excel range ref to a zero indexed number.
*/
uint32_t
lxw_name_to_row_2(const char *row_str)
{
const char *p = row_str;
/* Find the : separator in the range. */
while (p && *p != ':')
p++;
if (p)
return lxw_name_to_row(++p);
else
return -1;
}
/*
* Convert the second column of an Excel range ref to a zero indexed number.
*/
uint16_t
lxw_name_to_col_2(const char *col_str)
{
const char *p = col_str;
/* Find the : separator in the range. */
while (p && *p != ':')
p++;
if (p)
return lxw_name_to_col(++p);
else
return -1;
}
/*
* Convert a lxw_datetime struct to an Excel serial date, with a 1900
* or 1904 epoch.
*/
double
lxw_datetime_to_excel_date_epoch(lxw_datetime *datetime, uint8_t date_1904)
{
int year = datetime->year;
int month = datetime->month;
int day = datetime->day;
int hour = datetime->hour;
int min = datetime->min;
double sec = datetime->sec;
double seconds;
int epoch = date_1904 ? 1904 : 1900;
int offset = date_1904 ? 4 : 0;
int norm = 300;
int range;
/* Set month days and check for leap year. */
int mdays[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int leap = 0;
int days = 0;
int i;
/* For times without dates set the default date for the epoch. */
if (!year) {
if (!date_1904) {
year = 1899;
month = 12;
day = 31;
}
else {
year = 1904;
month = 1;
day = 1;
}
}
/* Convert the Excel seconds to a fraction of the seconds in 24 hours. */
seconds = (hour * 60 * 60 + min * 60 + sec) / (24 * 60 * 60.0);
/* Special cases for Excel dates in the 1900 epoch. */
if (!date_1904) {
/* Excel 1900 epoch. */
if (year == 1899 && month == 12 && day == 31)
return seconds;
/* Excel 1900 epoch. */
if (year == 1900 && month == 1 && day == 0)
return seconds;
/* Excel false leapday */
if (year == 1900 && month == 2 && day == 29)
return 60 + seconds;
}
/* We calculate the date by calculating the number of days since the */
/* epoch and adjust for the number of leap days. We calculate the */
/* number of leap days by normalizing the year in relation to the */
/* epoch. Thus the year 2000 becomes 100 for 4-year and 100-year */
/* leapdays and 400 for 400-year leapdays. */
range = year - epoch;
if (year % 4 == 0 && (year % 100 > 0 || year % 400 == 0)) {
leap = 1;
mdays[2] = 29;
}
/*
* Calculate the serial date by accumulating the number of days
* since the epoch.
*/
/* Add days for previous months. */
for (i = 0; i < month; i++) {
days += mdays[i];
}
/* Add days for current month. */
days += day;
/* Add days for all previous years. */
days += range * 365;
/* Add 4 year leapdays. */
days += range / 4;
/* Remove 100 year leapdays. */
days -= (range + offset) / 100;
/* Add 400 year leapdays. */
days += (range + offset + norm) / 400;
/* Remove leap days already counted. */
days -= leap;
/* Adjust for Excel erroneously treating 1900 as a leap year. */
if (!date_1904 && days > 59)
days++;
return days + seconds;
}
/*
* Convert a lxw_datetime struct to an Excel serial date, for the 1900 epoch.
*/
double
lxw_datetime_to_excel_datetime(lxw_datetime *datetime)
{
return lxw_datetime_to_excel_date_epoch(datetime, LXW_FALSE);
}
/*
* Convert a unix datetime (1970/01/01 epoch) to an Excel serial date, with a
* 1900 epoch.
*/
double
lxw_unixtime_to_excel_date(int64_t unixtime)
{
return lxw_unixtime_to_excel_date_epoch(unixtime, LXW_FALSE);
}
/*
* Convert a unix datetime (1970/01/01 epoch) to an Excel serial date, with a
* 1900 or 1904 epoch.
*/
double
lxw_unixtime_to_excel_date_epoch(int64_t unixtime, uint8_t date_1904)
{
double excel_datetime = 0.0;
double epoch = date_1904 ? 24107.0 : 25568.0;
excel_datetime = epoch + (unixtime / (24 * 60 * 60.0));
if (!date_1904 && excel_datetime >= 60.0)
excel_datetime = excel_datetime + 1.0;
return excel_datetime;
}
/* Simple strdup() implementation since it isn't ANSI C. */
char *
lxw_strdup(const char *str)
{
size_t len;
char *copy;
if (!str)
return NULL;
len = strlen(str) + 1;
copy = malloc(len);
if (copy)
memcpy(copy, str, len);
return copy;
}
/* Simple function to strdup() a formula string without the leading "=". */
char *
lxw_strdup_formula(const char *formula)
{
if (!formula)
return NULL;
if (formula[0] == '=')
return lxw_strdup(formula + 1);
else
return lxw_strdup(formula);
}
/* Simple strlen that counts UTF-8 characters. Assumes well formed UTF-8. */
size_t
lxw_utf8_strlen(const char *str)
{
size_t byte_count = 0;
size_t char_count = 0;
while (str[byte_count]) {
if ((str[byte_count] & 0xc0) != 0x80)
char_count++;
byte_count++;
}
return char_count;
}
/* Simple tolower() for strings. */
void
lxw_str_tolower(char *str)
{
int i;
for (i = 0; str[i]; i++)
str[i] = tolower(str[i]);
}
/* Create a quoted version of the worksheet name, or return an unmodified
* copy if it doesn't required quoting. */
char *
lxw_quote_sheetname(const char *str)
{
uint8_t needs_quoting = 0;
size_t number_of_quotes = 2;
size_t i, j;
size_t len = strlen(str);
/* Don't quote the sheetname if it is already quoted. */
if (str[0] == '\'')
return lxw_strdup(str);
/* Check if the sheetname contains any characters that require it
* to be quoted. Also check for single quotes within the string. */
for (i = 0; i < len; i++) {
if (!isalnum((unsigned char) str[i]) && str[i] != '_'
&& str[i] != '.')
needs_quoting = 1;
if (str[i] == '\'') {
needs_quoting = 1;
number_of_quotes++;
}
}
if (!needs_quoting) {
return lxw_strdup(str);
}
else {
/* Add single quotes to the start and end of the string. */
char *quoted_name = calloc(1, len + number_of_quotes + 1);
RETURN_ON_MEM_ERROR(quoted_name, NULL);
quoted_name[0] = '\'';
for (i = 0, j = 1; i < len; i++, j++) {
quoted_name[j] = str[i];
/* Double quote inline single quotes. */
if (str[i] == '\'') {
quoted_name[++j] = '\'';
}
}
quoted_name[j++] = '\'';
quoted_name[j++] = '\0';
return quoted_name;
}
}
/*
* Thin wrapper for tmpfile() so it can be over-ridden with a user defined
* version if required for safety or portability.
*/
FILE *
lxw_tmpfile(const char *tmpdir)
{
#ifndef USE_STANDARD_TMPFILE
return tmpfileplus(tmpdir, NULL, NULL, 0);
#else
(void) tmpdir;
return tmpfile();
#endif
}
/**
* Return a memory-backed file if supported, otherwise a temporary one
*/
FILE *
lxw_get_filehandle(char **buf, size_t *size, const char *tmpdir)
{
static size_t s;
if (!size)
size = &s;
*buf = NULL;
*size = 0;
#ifdef USE_FMEMOPEN
(void) tmpdir;
return open_memstream(buf, size);
#else
return lxw_tmpfile(tmpdir);
#endif
}
/*
* Use third party function to handle sprintf of doubles for locale portable
* code.
*/
#ifdef USE_DTOA_LIBRARY
int
lxw_sprintf_dbl(char *data, double number)
{
emyg_dtoa(number, data);
return 0;
}
#endif
/*
* Retrieve runtime library version.
*/
const char *
lxw_version(void)
{
return LXW_VERSION;
}
/*
* Retrieve runtime library version ID.
*/
uint16_t
lxw_version_id(void)
{
return LXW_VERSION_ID;
}
/*
* Hash a worksheet password. Based on the algorithm in ECMA-376-4:2016,
* Office Open XML File Formats - Transitional Migration Features,
* Additional attributes for workbookProtection element (Part 1, §18.2.29).
*/
uint16_t
lxw_hash_password(const char *password)
{
uint16_t byte_count = (uint16_t) strlen(password);
uint16_t hash = 0;
const char *p = &password[byte_count];
if (!byte_count)
return hash;
while (p-- != password) {
hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
hash ^= *p & 0xFF;
}
hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
hash ^= byte_count;
hash ^= 0xCE4B;
return hash;
}
/* Make a simple portable version of fopen() for Windows. */
#ifdef __MINGW32__
#undef _WIN32
#endif
#ifdef _WIN32
#include
FILE *
lxw_fopen(const char *filename, const char *mode)
{
int n;
wchar_t wide_filename[_MAX_PATH + 1] = L"";
wchar_t wide_mode[_MAX_PATH + 1] = L"";
n = MultiByteToWideChar(CP_UTF8, 0, filename, (int) strlen(filename),
wide_filename, _MAX_PATH);
if (n == 0) {
LXW_ERROR("MultiByteToWideChar error: filename");
return NULL;
}
n = MultiByteToWideChar(CP_UTF8, 0, mode, (int) strlen(mode),
wide_mode, _MAX_PATH);
if (n == 0) {
LXW_ERROR("MultiByteToWideChar error: mode");
return NULL;
}
return _wfopen(wide_filename, wide_mode);
}
#else
FILE *
lxw_fopen(const char *filename, const char *mode)
{
return fopen(filename, mode);
}
#endif
writexl/src/libxlsxwriter/table.c 0000644 0001762 0000144 00000020273 14747162622 016733 0 ustar ligges users /*****************************************************************************
* table - A library for creating Excel XLSX table files.
*
* Used in conjunction with the libxlsxwriter library.
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
*/
#include "xlsxwriter/xmlwriter.h"
#include "xlsxwriter/worksheet.h"
#include "xlsxwriter/table.h"
#include "xlsxwriter/utility.h"
/*
* Forward declarations.
*/
/*****************************************************************************
*
* Private functions.
*
****************************************************************************/
/*
* Create a new table object.
*/
lxw_table *
lxw_table_new(void)
{
lxw_table *table = calloc(1, sizeof(lxw_table));
GOTO_LABEL_ON_MEM_ERROR(table, mem_error);
return table;
mem_error:
lxw_table_free(table);
return NULL;
}
/*
* Free a table object.
*/
void
lxw_table_free(lxw_table *table)
{
if (!table)
return;
free(table);
}
/*****************************************************************************
*
* XML functions.
*
****************************************************************************/
/*
* Write the XML declaration.
*/
STATIC void
_table_xml_declaration(lxw_table *self)
{
lxw_xml_declaration(self->file);
}
/*
* Write the
element.
*/
STATIC void
_table_write_table(lxw_table *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char xmlns[] =
"http://schemas.openxmlformats.org/spreadsheetml/2006/main";
lxw_table_obj *table_obj = self->table_obj;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("xmlns", xmlns);
LXW_PUSH_ATTRIBUTES_INT("id", table_obj->id);
if (table_obj->name)
LXW_PUSH_ATTRIBUTES_STR("name", table_obj->name);
else
LXW_PUSH_ATTRIBUTES_STR("name", "Table1");
if (table_obj->name)
LXW_PUSH_ATTRIBUTES_STR("displayName", table_obj->name);
else
LXW_PUSH_ATTRIBUTES_STR("displayName", "Table1");
LXW_PUSH_ATTRIBUTES_STR("ref", table_obj->sqref);
if (table_obj->no_header_row)
LXW_PUSH_ATTRIBUTES_STR("headerRowCount", "0");
if (table_obj->total_row)
LXW_PUSH_ATTRIBUTES_STR("totalsRowCount", "1");
else
LXW_PUSH_ATTRIBUTES_STR("totalsRowShown", "0");
lxw_xml_start_tag(self->file, "table", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_table_write_auto_filter(lxw_table *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
if (self->table_obj->no_autofilter)
return;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("ref", self->table_obj->filter_sqref);
lxw_xml_empty_tag(self->file, "autoFilter", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_table_write_table_column(lxw_table *self, uint16_t id,
lxw_table_column *column)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
int32_t dfx_id;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_INT("id", id);
LXW_PUSH_ATTRIBUTES_STR("name", column->header);
if (column->total_string) {
LXW_PUSH_ATTRIBUTES_STR("totalsRowLabel", column->total_string);
}
else if (column->total_function) {
if (column->total_function == LXW_TABLE_FUNCTION_AVERAGE)
LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "average");
if (column->total_function == LXW_TABLE_FUNCTION_COUNT_NUMS)
LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "countNums");
if (column->total_function == LXW_TABLE_FUNCTION_COUNT)
LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "count");
if (column->total_function == LXW_TABLE_FUNCTION_MAX)
LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "max");
if (column->total_function == LXW_TABLE_FUNCTION_MIN)
LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "min");
if (column->total_function == LXW_TABLE_FUNCTION_STD_DEV)
LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "stdDev");
if (column->total_function == LXW_TABLE_FUNCTION_SUM)
LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "sum");
if (column->total_function == LXW_TABLE_FUNCTION_VAR)
LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "var");
}
if (column->format) {
dfx_id = lxw_format_get_dxf_index(column->format);
LXW_PUSH_ATTRIBUTES_INT("dataDxfId", dfx_id);
}
if (column->formula) {
lxw_xml_start_tag(self->file, "tableColumn", &attributes);
lxw_xml_data_element(self->file, "calculatedColumnFormula",
column->formula, NULL);
lxw_xml_end_tag(self->file, "tableColumn");
}
else {
lxw_xml_empty_tag(self->file, "tableColumn", &attributes);
}
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_table_write_table_columns(lxw_table *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
uint16_t i;
uint16_t num_cols = self->table_obj->num_cols;
lxw_table_column **columns = self->table_obj->columns;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_INT("count", num_cols);
lxw_xml_start_tag(self->file, "tableColumns", &attributes);
for (i = 0; i < num_cols; i++)
_table_write_table_column(self, i + 1, columns[i]);
lxw_xml_end_tag(self->file, "tableColumns");
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_table_write_table_style_info(lxw_table *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char name[LXW_ATTR_32];
lxw_table_obj *table_obj = self->table_obj;
LXW_INIT_ATTRIBUTES();
if (table_obj->style_type == LXW_TABLE_STYLE_TYPE_LIGHT) {
if (table_obj->style_type_number != 0) {
lxw_snprintf(name, LXW_ATTR_32, "TableStyleLight%d",
table_obj->style_type_number);
LXW_PUSH_ATTRIBUTES_STR("name", name);
}
}
else if (table_obj->style_type == LXW_TABLE_STYLE_TYPE_MEDIUM) {
lxw_snprintf(name, LXW_ATTR_32, "TableStyleMedium%d",
table_obj->style_type_number);
LXW_PUSH_ATTRIBUTES_STR("name", name);
}
else if (table_obj->style_type == LXW_TABLE_STYLE_TYPE_DARK) {
lxw_snprintf(name, LXW_ATTR_32, "TableStyleDark%d",
table_obj->style_type_number);
LXW_PUSH_ATTRIBUTES_STR("name", name);
}
else {
LXW_PUSH_ATTRIBUTES_STR("name", "TableStyleMedium9");
}
if (table_obj->first_column)
LXW_PUSH_ATTRIBUTES_STR("showFirstColumn", "1");
else
LXW_PUSH_ATTRIBUTES_STR("showFirstColumn", "0");
if (table_obj->last_column)
LXW_PUSH_ATTRIBUTES_STR("showLastColumn", "1");
else
LXW_PUSH_ATTRIBUTES_STR("showLastColumn", "0");
if (table_obj->no_banded_rows)
LXW_PUSH_ATTRIBUTES_STR("showRowStripes", "0");
else
LXW_PUSH_ATTRIBUTES_STR("showRowStripes", "1");
if (table_obj->banded_columns)
LXW_PUSH_ATTRIBUTES_STR("showColumnStripes", "1");
else
LXW_PUSH_ATTRIBUTES_STR("showColumnStripes", "0");
lxw_xml_empty_tag(self->file, "tableStyleInfo", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*****************************************************************************
*
* XML file assembly functions.
*
****************************************************************************/
/*
* Assemble and write the XML file.
*/
void
lxw_table_assemble_xml_file(lxw_table *self)
{
/* Write the XML declaration. */
_table_xml_declaration(self);
/* Write the table element. */
_table_write_table(self);
/* Write the autoFilter element. */
_table_write_auto_filter(self);
/* Write the tableColumns element. */
_table_write_table_columns(self);
/* Write the tableStyleInfo element. */
_table_write_table_style_info(self);
lxw_xml_end_tag(self->file, "table");
}
/*****************************************************************************
*
* Public functions.
*
****************************************************************************/
writexl/src/libxlsxwriter/relationships.c 0000644 0001762 0000144 00000014342 14747162622 020530 0 ustar ligges users /*****************************************************************************
* relationships - A library for creating Excel XLSX relationships files.
*
* Used in conjunction with the libxlsxwriter library.
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
*/
#include
#include "xlsxwriter/xmlwriter.h"
#include "xlsxwriter/relationships.h"
#include "xlsxwriter/utility.h"
/*
* Forward declarations.
*/
/*****************************************************************************
*
* Private functions.
*
****************************************************************************/
/*
* Create a new relationships object.
*/
lxw_relationships *
lxw_relationships_new(void)
{
lxw_relationships *rels = calloc(1, sizeof(lxw_relationships));
GOTO_LABEL_ON_MEM_ERROR(rels, mem_error);
rels->relationships = calloc(1, sizeof(struct lxw_rel_tuples));
GOTO_LABEL_ON_MEM_ERROR(rels->relationships, mem_error);
STAILQ_INIT(rels->relationships);
return rels;
mem_error:
lxw_free_relationships(rels);
return NULL;
}
/*
* Free a relationships object.
*/
void
lxw_free_relationships(lxw_relationships *rels)
{
lxw_rel_tuple *relationship;
if (!rels)
return;
if (rels->relationships) {
while (!STAILQ_EMPTY(rels->relationships)) {
relationship = STAILQ_FIRST(rels->relationships);
STAILQ_REMOVE_HEAD(rels->relationships, list_pointers);
free(relationship->type);
free(relationship->target);
free(relationship->target_mode);
free(relationship);
}
free(rels->relationships);
}
free(rels);
}
/*****************************************************************************
*
* XML functions.
*
****************************************************************************/
/*
* Write the XML declaration.
*/
STATIC void
_relationships_xml_declaration(lxw_relationships *self)
{
lxw_xml_declaration(self->file);
}
/*
* Write the element.
*/
STATIC void
_write_relationship(lxw_relationships *self, const char *type,
const char *target, const char *target_mode)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char r_id[LXW_MAX_ATTRIBUTE_LENGTH] = { 0 };
self->rel_id++;
lxw_snprintf(r_id, LXW_ATTR_32, "rId%d", self->rel_id);
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("Id", r_id);
LXW_PUSH_ATTRIBUTES_STR("Type", type);
LXW_PUSH_ATTRIBUTES_STR("Target", target);
if (target_mode)
LXW_PUSH_ATTRIBUTES_STR("TargetMode", target_mode);
lxw_xml_empty_tag(self->file, "Relationship", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_relationships(lxw_relationships *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
lxw_rel_tuple *rel;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("xmlns", LXW_SCHEMA_PACKAGE);
lxw_xml_start_tag(self->file, "Relationships", &attributes);
STAILQ_FOREACH(rel, self->relationships, list_pointers) {
_write_relationship(self, rel->type, rel->target, rel->target_mode);
}
LXW_FREE_ATTRIBUTES();
}
/*****************************************************************************
*
* XML file assembly functions.
*
****************************************************************************/
/*
* Assemble and write the XML file.
*/
void
lxw_relationships_assemble_xml_file(lxw_relationships *self)
{
/* Write the XML declaration. */
_relationships_xml_declaration(self);
_write_relationships(self);
/* Close the relationships tag. */
lxw_xml_end_tag(self->file, "Relationships");
}
/*
* Add a generic container relationship to XLSX .rels xml files.
*/
STATIC void
_add_relationship(lxw_relationships *self, const char *schema,
const char *type, const char *target,
const char *target_mode)
{
lxw_rel_tuple *relationship;
if (!schema || !type || !target)
return;
relationship = calloc(1, sizeof(lxw_rel_tuple));
GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
relationship->type = calloc(1, LXW_MAX_ATTRIBUTE_LENGTH);
GOTO_LABEL_ON_MEM_ERROR(relationship->type, mem_error);
/* Add the schema to the relationship type. */
lxw_snprintf(relationship->type, LXW_MAX_ATTRIBUTE_LENGTH, "%s%s",
schema, type);
relationship->target = lxw_strdup(target);
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
if (target_mode) {
relationship->target_mode = lxw_strdup(target_mode);
GOTO_LABEL_ON_MEM_ERROR(relationship->target_mode, mem_error);
}
STAILQ_INSERT_TAIL(self->relationships, relationship, list_pointers);
return;
mem_error:
if (relationship) {
free(relationship->type);
free(relationship->target);
free(relationship->target_mode);
free(relationship);
}
}
/*****************************************************************************
*
* Public functions.
*
****************************************************************************/
/*
* Add a document relationship to XLSX .rels xml files.
*/
void
lxw_add_document_relationship(lxw_relationships *self, const char *type,
const char *target)
{
_add_relationship(self, LXW_SCHEMA_DOCUMENT, type, target, NULL);
}
/*
* Add a package relationship to XLSX .rels xml files.
*/
void
lxw_add_package_relationship(lxw_relationships *self, const char *type,
const char *target)
{
_add_relationship(self, LXW_SCHEMA_PACKAGE, type, target, NULL);
}
/*
* Add a MS schema package relationship to XLSX .rels xml files.
*/
void
lxw_add_ms_package_relationship(lxw_relationships *self, const char *type,
const char *target)
{
_add_relationship(self, LXW_SCHEMA_MS, type, target, NULL);
}
/*
* Add a worksheet relationship to sheet .rels xml files.
*/
void
lxw_add_worksheet_relationship(lxw_relationships *self, const char *type,
const char *target, const char *target_mode)
{
_add_relationship(self, LXW_SCHEMA_DOCUMENT, type, target, target_mode);
}
writexl/src/libxlsxwriter/custom.c 0000644 0001762 0000144 00000012632 14747162622 017156 0 ustar ligges users /*****************************************************************************
* custom - A library for creating Excel custom property files.
*
* Used in conjunction with the libxlsxwriter library.
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
*/
#include "xlsxwriter/xmlwriter.h"
#include "xlsxwriter/custom.h"
#include "xlsxwriter/utility.h"
/*
* Forward declarations.
*/
/*****************************************************************************
*
* Private functions.
*
****************************************************************************/
/*
* Create a new custom object.
*/
lxw_custom *
lxw_custom_new(void)
{
lxw_custom *custom = calloc(1, sizeof(lxw_custom));
GOTO_LABEL_ON_MEM_ERROR(custom, mem_error);
return custom;
mem_error:
lxw_custom_free(custom);
return NULL;
}
/*
* Free a custom object.
*/
void
lxw_custom_free(lxw_custom *custom)
{
if (!custom)
return;
free(custom);
}
/*****************************************************************************
*
* XML functions.
*
****************************************************************************/
/*
* Write the XML declaration.
*/
STATIC void
_custom_xml_declaration(lxw_custom *self)
{
lxw_xml_declaration(self->file);
}
/*
* Write the element.
*/
STATIC void
_chart_write_vt_lpwstr(lxw_custom *self, char *value)
{
lxw_xml_data_element(self->file, "vt:lpwstr", value, NULL);
}
/*
* Write the element.
*/
STATIC void
_chart_write_vt_r_8(lxw_custom *self, double value)
{
char data[LXW_ATTR_32];
lxw_sprintf_dbl(data, value);
lxw_xml_data_element(self->file, "vt:r8", data, NULL);
}
/*
* Write the element.
*/
STATIC void
_custom_write_vt_i_4(lxw_custom *self, int32_t value)
{
char data[LXW_ATTR_32];
lxw_snprintf(data, LXW_ATTR_32, "%d", value);
lxw_xml_data_element(self->file, "vt:i4", data, NULL);
}
/*
* Write the element.
*/
STATIC void
_custom_write_vt_bool(lxw_custom *self, uint8_t value)
{
if (value)
lxw_xml_data_element(self->file, "vt:bool", "true", NULL);
else
lxw_xml_data_element(self->file, "vt:bool", "false", NULL);
}
/*
* Write the element.
*/
STATIC void
_custom_write_vt_filetime(lxw_custom *self, lxw_datetime *datetime)
{
char data[LXW_DATETIME_LENGTH];
lxw_snprintf(data, LXW_DATETIME_LENGTH, "%4d-%02d-%02dT%02d:%02d:%02dZ",
datetime->year, datetime->month, datetime->day,
datetime->hour, datetime->min, (int) datetime->sec);
lxw_xml_data_element(self->file, "vt:filetime", data, NULL);
}
/*
* Write the element.
*/
STATIC void
_chart_write_custom_property(lxw_custom *self,
lxw_custom_property *custom_property)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char fmtid[] = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}";
self->pid++;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("fmtid", fmtid);
LXW_PUSH_ATTRIBUTES_INT("pid", self->pid + 1);
LXW_PUSH_ATTRIBUTES_STR("name", custom_property->name);
lxw_xml_start_tag(self->file, "property", &attributes);
if (custom_property->type == LXW_CUSTOM_STRING) {
/* Write the vt:lpwstr element. */
_chart_write_vt_lpwstr(self, custom_property->u.string);
}
else if (custom_property->type == LXW_CUSTOM_DOUBLE) {
/* Write the vt:r8 element. */
_chart_write_vt_r_8(self, custom_property->u.number);
}
else if (custom_property->type == LXW_CUSTOM_INTEGER) {
/* Write the vt:i4 element. */
_custom_write_vt_i_4(self, custom_property->u.integer);
}
else if (custom_property->type == LXW_CUSTOM_BOOLEAN) {
/* Write the vt:bool element. */
_custom_write_vt_bool(self, custom_property->u.boolean);
}
else if (custom_property->type == LXW_CUSTOM_DATETIME) {
/* Write the vt:filetime element. */
_custom_write_vt_filetime(self, &custom_property->u.datetime);
}
lxw_xml_end_tag(self->file, "property");
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_custom_properties(lxw_custom *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char xmlns[] = LXW_SCHEMA_OFFICEDOC "/custom-properties";
char xmlns_vt[] = LXW_SCHEMA_OFFICEDOC "/docPropsVTypes";
lxw_custom_property *custom_property;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("xmlns", xmlns);
LXW_PUSH_ATTRIBUTES_STR("xmlns:vt", xmlns_vt);
lxw_xml_start_tag(self->file, "Properties", &attributes);
STAILQ_FOREACH(custom_property, self->custom_properties, list_pointers) {
_chart_write_custom_property(self, custom_property);
}
LXW_FREE_ATTRIBUTES();
}
/*****************************************************************************
*
* XML file assembly functions.
*
****************************************************************************/
/*
* Assemble and write the XML file.
*/
void
lxw_custom_assemble_xml_file(lxw_custom *self)
{
/* Write the XML declaration. */
_custom_xml_declaration(self);
_write_custom_properties(self);
lxw_xml_end_tag(self->file, "Properties");
}
/*****************************************************************************
*
* Public functions.
*
****************************************************************************/
writexl/src/libxlsxwriter/packager.c 0000644 0001762 0000144 00000153707 14747162622 017432 0 ustar ligges users /*****************************************************************************
* packager - A library for assembling xml files into an Excel XLSX file.
*
* A class for writing the Excel XLSX Packager file.
*
* This module is used in conjunction with libxlsxwriter to create an
* Excel XLSX container file.
*
* From Wikipedia: The Open Packaging Conventions (OPC) is a
* container-file technology initially created by Microsoft to store
* a combination of XML and non-XML files that together form a single
* entity such as an Open XML Paper Specification (OpenXPS)
* document. http://en.wikipedia.org/wiki/Open_Packaging_Conventions.
*
* At its simplest an Excel XLSX file contains the following elements::
*
* ____ [Content_Types].xml
* |
* |____ docProps
* | |____ app.xml
* | |____ core.xml
* |
* |____ xl
* | |____ workbook.xml
* | |____ worksheets
* | | |____ sheet1.xml
* | |
* | |____ styles.xml
* | |
* | |____ theme
* | | |____ theme1.xml
* | |
* | |_____rels
* | |____ workbook.xml.rels
* |
* |_____rels
* |____ .rels
*
* The Packager class coordinates the classes that represent the
* elements of the package and writes them into the XLSX file.
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
*/
#include
#include "xlsxwriter/xmlwriter.h"
#include "xlsxwriter/packager.h"
#include "xlsxwriter/hash_table.h"
#include "xlsxwriter/utility.h"
STATIC lxw_error _add_file_to_zip(lxw_packager *self, FILE * file,
const char *filename);
STATIC lxw_error _add_buffer_to_zip(lxw_packager *self, const char *buffer,
size_t buffer_size, const char *filename);
STATIC lxw_error _add_to_zip(lxw_packager *self, FILE * file,
char **buffer, size_t *buffer_size,
const char *filename);
STATIC lxw_error _write_vml_drawing_rels_file(lxw_packager *self,
lxw_worksheet *worksheet,
uint32_t index);
/*
* Forward declarations.
*/
/*****************************************************************************
*
* Private functions.
*
****************************************************************************/
/* Avoid non MSVC definition of _WIN32 in MinGW. */
#ifdef __MINGW32__
#undef _WIN32
#endif
#ifdef _WIN32
/* Silence Windows warning with duplicate symbol for SLIST_ENTRY in local
* queue.h and windows.h. */
#undef SLIST_ENTRY
#include
#ifdef USE_SYSTEM_MINIZIP
#include "minizip/iowin32.h"
#else
#include "../third_party/minizip/iowin32.h"
#endif
zipFile
_open_zipfile_win32(const char *filename)
{
int n;
zlib_filefunc64_def filefunc;
wchar_t wide_filename[_MAX_PATH + 1] = L"";
/* Build a UTF-16 filename for Win32. */
n = MultiByteToWideChar(CP_UTF8, 0, filename, (int) strlen(filename),
wide_filename, _MAX_PATH);
if (n == 0) {
LXW_ERROR("MultiByteToWideChar error");
return NULL;
}
/* Use the native Win32 file handling functions with minizip. */
fill_win32_filefunc64W(&filefunc);
return zipOpen2_64(wide_filename, 0, NULL, &filefunc);
}
#endif
STATIC voidpf ZCALLBACK
_fopen_memstream(voidpf opaque, const char *filename, int mode)
{
lxw_packager *packager = (lxw_packager *) opaque;
(void) filename;
(void) mode;
return lxw_get_filehandle(&packager->output_buffer,
&packager->output_buffer_size,
packager->tmpdir);
}
STATIC int ZCALLBACK
_fclose_memstream(voidpf opaque, voidpf stream)
{
lxw_packager *packager = (lxw_packager *) opaque;
FILE *file = (FILE *) stream;
long size;
/* Ensure memstream buffer is updated */
if (fflush(file))
goto mem_error;
/* If the memstream is backed by a temporary file, no buffer is created,
so create it manually. */
if (!packager->output_buffer) {
if (fseek(file, 0L, SEEK_END))
goto mem_error;
size = ftell(file);
if (size == -1)
goto mem_error;
packager->output_buffer = malloc(size);
GOTO_LABEL_ON_MEM_ERROR(packager->output_buffer, mem_error);
rewind(file);
if (fread((void *) packager->output_buffer, size, 1, file) < 1)
goto mem_error;
packager->output_buffer_size = size;
}
return fclose(file);
mem_error:
fclose(file);
return EOF;
}
/*
* Create a new packager object.
*/
lxw_packager *
lxw_packager_new(const char *filename, const char *tmpdir, uint8_t use_zip64)
{
zlib_filefunc_def filefunc;
lxw_packager *packager = calloc(1, sizeof(lxw_packager));
GOTO_LABEL_ON_MEM_ERROR(packager, mem_error);
packager->buffer = calloc(1, LXW_ZIP_BUFFER_SIZE);
GOTO_LABEL_ON_MEM_ERROR(packager->buffer, mem_error);
packager->filename = NULL;
packager->tmpdir = tmpdir;
if (filename) {
packager->filename = lxw_strdup(filename);
GOTO_LABEL_ON_MEM_ERROR(packager->filename, mem_error);
}
packager->buffer_size = LXW_ZIP_BUFFER_SIZE;
packager->use_zip64 = use_zip64;
/* Initialize the zip_fileinfo struct to Jan 1 1980 like Excel. */
packager->zipfile_info.tmz_date.tm_sec = 0;
packager->zipfile_info.tmz_date.tm_min = 0;
packager->zipfile_info.tmz_date.tm_hour = 0;
packager->zipfile_info.tmz_date.tm_mday = 1;
packager->zipfile_info.tmz_date.tm_mon = 0;
packager->zipfile_info.tmz_date.tm_year = 1980;
packager->zipfile_info.dosDate = 0;
packager->zipfile_info.internal_fa = 0;
packager->zipfile_info.external_fa = 0;
packager->output_buffer = NULL;
packager->output_buffer_size = 0;
/* Create a zip container for the xlsx file. */
if (packager->filename) {
#ifdef _WIN32
packager->zipfile = _open_zipfile_win32(packager->filename);
#else
packager->zipfile = zipOpen(packager->filename, 0);
#endif
}
else {
fill_fopen_filefunc(&filefunc);
filefunc.opaque = packager;
filefunc.zopen_file = _fopen_memstream;
filefunc.zclose_file = _fclose_memstream;
packager->zipfile = zipOpen2(packager->filename, 0, NULL, &filefunc);
}
if (packager->zipfile == NULL)
goto mem_error;
return packager;
mem_error:
lxw_packager_free(packager);
return NULL;
}
/*
* Free a packager object.
*/
void
lxw_packager_free(lxw_packager *packager)
{
if (!packager)
return;
free((void *) packager->buffer);
free((void *) packager->filename);
free(packager);
}
/*****************************************************************************
*
* File assembly functions.
*
****************************************************************************/
/*
* Write the workbook.xml file.
*/
STATIC lxw_error
_write_workbook_file(lxw_packager *self)
{
lxw_workbook *workbook = self->workbook;
lxw_error err;
char *buffer = NULL;
size_t buffer_size = 0;
workbook->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
if (!workbook->file)
return LXW_ERROR_CREATING_TMPFILE;
lxw_workbook_assemble_xml_file(workbook);
err = _add_to_zip(self, workbook->file, &buffer, &buffer_size,
"xl/workbook.xml");
fclose(workbook->file);
free(buffer);
RETURN_ON_ERROR(err);
return LXW_NO_ERROR;
}
/*
* Write the worksheet files.
*/
STATIC lxw_error
_write_worksheet_files(lxw_packager *self)
{
lxw_workbook *workbook = self->workbook;
lxw_sheet *sheet;
lxw_worksheet *worksheet;
char sheetname[LXW_FILENAME_LENGTH] = { 0 };
char *buffer = NULL;
size_t buffer_size = 0;
uint32_t index = 1;
lxw_error err;
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
if (sheet->is_chartsheet)
continue;
else
worksheet = sheet->u.worksheet;
lxw_snprintf(sheetname, LXW_FILENAME_LENGTH,
"xl/worksheets/sheet%d.xml", index++);
if (worksheet->optimize_row)
lxw_worksheet_write_single_row(worksheet);
worksheet->file = lxw_get_filehandle(&buffer, &buffer_size,
self->tmpdir);
if (!worksheet->file)
return LXW_ERROR_CREATING_TMPFILE;
lxw_worksheet_assemble_xml_file(worksheet);
err = _add_to_zip(self, worksheet->file, &buffer, &buffer_size,
sheetname);
fclose(worksheet->file);
free(buffer);
RETURN_ON_ERROR(err);
}
return LXW_NO_ERROR;
}
/*
* Write the chartsheet files.
*/
STATIC lxw_error
_write_chartsheet_files(lxw_packager *self)
{
lxw_workbook *workbook = self->workbook;
lxw_sheet *sheet;
lxw_chartsheet *chartsheet;
char sheetname[LXW_FILENAME_LENGTH] = { 0 };
char *buffer = NULL;
size_t buffer_size = 0;
uint32_t index = 1;
lxw_error err;
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
if (sheet->is_chartsheet)
chartsheet = sheet->u.chartsheet;
else
continue;
lxw_snprintf(sheetname, LXW_FILENAME_LENGTH,
"xl/chartsheets/sheet%d.xml", index++);
chartsheet->file = lxw_get_filehandle(&buffer, &buffer_size,
self->tmpdir);
if (!chartsheet->file)
return LXW_ERROR_CREATING_TMPFILE;
lxw_chartsheet_assemble_xml_file(chartsheet);
err = _add_to_zip(self, chartsheet->file, &buffer, &buffer_size,
sheetname);
fclose(chartsheet->file);
free(buffer);
RETURN_ON_ERROR(err);
}
return LXW_NO_ERROR;
}
/*
* Write the /xl/media/image?.xml files.
*/
STATIC lxw_error
_write_image_files(lxw_packager *self)
{
lxw_workbook *workbook = self->workbook;
lxw_sheet *sheet;
lxw_worksheet *worksheet;
lxw_object_properties *object_props;
lxw_error err;
FILE *image_stream;
char filename[LXW_FILENAME_LENGTH] = { 0 };
uint32_t index = 1;
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
if (sheet->is_chartsheet)
continue;
else
worksheet = sheet->u.worksheet;
if (STAILQ_EMPTY(worksheet->image_props))
continue;
STAILQ_FOREACH(object_props, worksheet->image_props, list_pointers) {
if (object_props->is_duplicate)
continue;
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
"xl/media/image%d.%s", index++,
object_props->extension);
if (!object_props->is_image_buffer) {
/* Check that the image file exists and can be opened. */
image_stream = lxw_fopen(object_props->filename, "rb");
if (!image_stream) {
LXW_WARN_FORMAT1("Error adding image to xlsx file: file "
"doesn't exist or can't be opened: %s.",
object_props->filename);
return LXW_ERROR_CREATING_TMPFILE;
}
err = _add_file_to_zip(self, image_stream, filename);
fclose(image_stream);
}
else {
err = _add_buffer_to_zip(self,
object_props->image_buffer,
object_props->image_buffer_size,
filename);
}
RETURN_ON_ERROR(err);
}
}
return LXW_NO_ERROR;
}
/*
* Write the xl/vbaProject.bin file.
*/
STATIC lxw_error
_add_vba_project(lxw_packager *self)
{
lxw_workbook *workbook = self->workbook;
lxw_error err;
FILE *image_stream;
if (!workbook->vba_project)
return LXW_NO_ERROR;
/* Check that the image file exists and can be opened. */
image_stream = lxw_fopen(workbook->vba_project, "rb");
if (!image_stream) {
LXW_WARN_FORMAT1("Error adding vbaProject.bin to xlsx file: "
"file doesn't exist or can't be opened: %s.",
workbook->vba_project);
return LXW_ERROR_CREATING_TMPFILE;
}
err = _add_file_to_zip(self, image_stream, "xl/vbaProject.bin");
fclose(image_stream);
RETURN_ON_ERROR(err);
return LXW_NO_ERROR;
}
/*
* Write the xl/vbaProjectSignature.bin file.
*/
STATIC lxw_error
_add_vba_project_signature(lxw_packager *self)
{
lxw_workbook *workbook = self->workbook;
lxw_error err;
FILE *image_stream;
if (!workbook->vba_project_signature)
return LXW_NO_ERROR;
/* Check that the image file exists and can be opened. */
image_stream = lxw_fopen(workbook->vba_project_signature, "rb");
if (!image_stream) {
LXW_WARN_FORMAT1("Error adding vbaProjectSignature.bin to xlsx file: "
"file doesn't exist or can't be opened: %s.",
workbook->vba_project_signature);
return LXW_ERROR_CREATING_TMPFILE;
}
err = _add_file_to_zip(self, image_stream, "xl/vbaProjectSignature.bin");
fclose(image_stream);
RETURN_ON_ERROR(err);
return LXW_NO_ERROR;
}
/*
* Write the chart files.
*/
STATIC lxw_error
_write_chart_files(lxw_packager *self)
{
lxw_workbook *workbook = self->workbook;
lxw_chart *chart;
char sheetname[LXW_FILENAME_LENGTH] = { 0 };
char *buffer = NULL;
size_t buffer_size = 0;
uint32_t index = 1;
lxw_error err;
STAILQ_FOREACH(chart, workbook->ordered_charts, ordered_list_pointers) {
lxw_snprintf(sheetname, LXW_FILENAME_LENGTH,
"xl/charts/chart%d.xml", index++);
chart->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
if (!chart->file)
return LXW_ERROR_CREATING_TMPFILE;
lxw_chart_assemble_xml_file(chart);
err = _add_to_zip(self, chart->file, &buffer, &buffer_size,
sheetname);
fclose(chart->file);
free(buffer);
RETURN_ON_ERROR(err);
}
return LXW_NO_ERROR;
}
/*
* Count the chart files.
*/
uint32_t
_get_chart_count(lxw_packager *self)
{
lxw_workbook *workbook = self->workbook;
lxw_chart *chart;
uint32_t chart_count = 0;
STAILQ_FOREACH(chart, workbook->ordered_charts, ordered_list_pointers) {
chart_count++;
}
return chart_count;
}
/*
* Write the drawing files.
*/
STATIC lxw_error
_write_drawing_files(lxw_packager *self)
{
lxw_workbook *workbook = self->workbook;
lxw_sheet *sheet;
lxw_worksheet *worksheet;
lxw_drawing *drawing;
char filename[LXW_FILENAME_LENGTH] = { 0 };
char *buffer = NULL;
size_t buffer_size = 0;
uint32_t index = 1;
lxw_error err;
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
if (sheet->is_chartsheet)
worksheet = sheet->u.chartsheet->worksheet;
else
worksheet = sheet->u.worksheet;
drawing = worksheet->drawing;
if (drawing) {
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
"xl/drawings/drawing%d.xml", index++);
drawing->file = lxw_get_filehandle(&buffer, &buffer_size,
self->tmpdir);
if (!drawing->file)
return LXW_ERROR_CREATING_TMPFILE;
lxw_drawing_assemble_xml_file(drawing);
err = _add_to_zip(self, drawing->file, &buffer, &buffer_size,
filename);
fclose(drawing->file);
free(buffer);
RETURN_ON_ERROR(err);
}
}
return LXW_NO_ERROR;
}
/*
* Count the drawing files.
*/
uint32_t
_get_drawing_count(lxw_packager *self)
{
lxw_workbook *workbook = self->workbook;
lxw_sheet *sheet;
lxw_worksheet *worksheet;
lxw_drawing *drawing;
uint32_t drawing_count = 0;
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
if (sheet->is_chartsheet)
worksheet = sheet->u.chartsheet->worksheet;
else
worksheet = sheet->u.worksheet;
drawing = worksheet->drawing;
if (drawing)
drawing_count++;
}
return drawing_count;
}
/*
* Write the worksheet table files.
*/
STATIC lxw_error
_write_table_files(lxw_packager *self)
{
lxw_workbook *workbook = self->workbook;
lxw_sheet *sheet;
lxw_worksheet *worksheet;
lxw_table *table;
lxw_table_obj *table_obj;
lxw_error err;
char filename[LXW_FILENAME_LENGTH] = { 0 };
char *buffer = NULL;
size_t buffer_size = 0;
uint32_t index = 1;
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
if (sheet->is_chartsheet)
continue;
else
worksheet = sheet->u.worksheet;
if (STAILQ_EMPTY(worksheet->table_objs))
continue;
STAILQ_FOREACH(table_obj, worksheet->table_objs, list_pointers) {
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
"xl/tables/table%d.xml", index++);
table = lxw_table_new();
if (!table) {
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
RETURN_ON_ERROR(err);
}
table->file = lxw_get_filehandle(&buffer, &buffer_size,
self->tmpdir);
if (!table->file) {
lxw_table_free(table);
return LXW_ERROR_CREATING_TMPFILE;
}
table->table_obj = table_obj;
lxw_table_assemble_xml_file(table);
err = _add_to_zip(self, table->file, &buffer, &buffer_size,
filename);
fclose(table->file);
free(buffer);
lxw_table_free(table);
RETURN_ON_ERROR(err);
}
}
return LXW_NO_ERROR;
}
/*
* Count the table files.
*/
uint32_t
_get_table_count(lxw_packager *self)
{
lxw_workbook *workbook = self->workbook;
lxw_sheet *sheet;
lxw_worksheet *worksheet;
uint32_t table_count = 0;
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
if (sheet->is_chartsheet)
worksheet = sheet->u.chartsheet->worksheet;
else
worksheet = sheet->u.worksheet;
table_count += worksheet->table_count;
}
return table_count;
}
/*
* Write the comment/header VML files.
*/
STATIC lxw_error
_write_vml_files(lxw_packager *self)
{
lxw_workbook *workbook = self->workbook;
lxw_sheet *sheet;
lxw_worksheet *worksheet;
lxw_vml *vml;
char filename[LXW_FILENAME_LENGTH] = { 0 };
char *buffer = NULL;
size_t buffer_size = 0;
uint32_t index = 1;
lxw_error err;
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
if (sheet->is_chartsheet)
continue;
else
worksheet = sheet->u.worksheet;
if (!worksheet->has_vml && !worksheet->has_header_vml)
continue;
if (worksheet->has_vml) {
vml = lxw_vml_new();
if (!vml)
return LXW_ERROR_MEMORY_MALLOC_FAILED;
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
"xl/drawings/vmlDrawing%d.vml", index++);
vml->file = lxw_get_filehandle(&buffer, &buffer_size,
self->tmpdir);
if (!vml->file) {
lxw_vml_free(vml);
return LXW_ERROR_CREATING_TMPFILE;
}
vml->comment_objs = worksheet->comment_objs;
vml->button_objs = worksheet->button_objs;
vml->vml_shape_id = worksheet->vml_shape_id;
vml->comment_display_default = worksheet->comment_display_default;
if (worksheet->vml_data_id_str) {
vml->vml_data_id_str = worksheet->vml_data_id_str;
}
else {
fclose(vml->file);
free(buffer);
lxw_vml_free(vml);
return LXW_ERROR_MEMORY_MALLOC_FAILED;
}
lxw_vml_assemble_xml_file(vml);
err = _add_to_zip(self, vml->file, &buffer, &buffer_size,
filename);
fclose(vml->file);
free(buffer);
lxw_vml_free(vml);
RETURN_ON_ERROR(err);
}
if (worksheet->has_header_vml) {
err = _write_vml_drawing_rels_file(self, worksheet, index);
RETURN_ON_ERROR(err);
vml = lxw_vml_new();
if (!vml)
return LXW_ERROR_MEMORY_MALLOC_FAILED;
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
"xl/drawings/vmlDrawing%d.vml", index++);
vml->file = lxw_get_filehandle(&buffer, &buffer_size,
self->tmpdir);
if (!vml->file) {
lxw_vml_free(vml);
return LXW_ERROR_CREATING_TMPFILE;
}
vml->image_objs = worksheet->header_image_objs;
vml->vml_shape_id = worksheet->vml_header_id * 1024;
if (worksheet->vml_header_id_str) {
vml->vml_data_id_str = worksheet->vml_header_id_str;
}
else {
fclose(vml->file);
free(buffer);
lxw_vml_free(vml);
return LXW_ERROR_MEMORY_MALLOC_FAILED;
}
lxw_vml_assemble_xml_file(vml);
err = _add_to_zip(self, vml->file, &buffer, &buffer_size,
filename);
fclose(vml->file);
free(buffer);
lxw_vml_free(vml);
RETURN_ON_ERROR(err);
}
}
return LXW_NO_ERROR;
}
/*
* Write the comment files.
*/
STATIC lxw_error
_write_comment_files(lxw_packager *self)
{
lxw_workbook *workbook = self->workbook;
lxw_sheet *sheet;
lxw_worksheet *worksheet;
lxw_comment *comment;
char filename[LXW_FILENAME_LENGTH] = { 0 };
char *buffer = NULL;
size_t buffer_size = 0;
uint32_t index = 1;
lxw_error err;
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
if (sheet->is_chartsheet)
continue;
else
worksheet = sheet->u.worksheet;
if (!worksheet->has_comments)
continue;
comment = lxw_comment_new();
if (!comment)
return LXW_ERROR_MEMORY_MALLOC_FAILED;
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
"xl/comments%d.xml", index++);
comment->file = lxw_get_filehandle(&buffer, &buffer_size,
self->tmpdir);
if (!comment->file) {
lxw_comment_free(comment);
return LXW_ERROR_CREATING_TMPFILE;
}
comment->comment_objs = worksheet->comment_objs;
comment->comment_author = worksheet->comment_author;
lxw_comment_assemble_xml_file(comment);
err = _add_to_zip(self, comment->file, &buffer, &buffer_size,
filename);
fclose(comment->file);
free(buffer);
lxw_comment_free(comment);
RETURN_ON_ERROR(err);
}
return LXW_NO_ERROR;
}
/*
* Write the sharedStrings.xml file.
*/
STATIC lxw_error
_write_shared_strings_file(lxw_packager *self)
{
lxw_sst *sst = self->workbook->sst;
char *buffer = NULL;
size_t buffer_size = 0;
lxw_error err;
/* Skip the sharedStrings file if there are no shared strings. */
if (!sst->string_count)
return LXW_NO_ERROR;
sst->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
if (!sst->file)
return LXW_ERROR_CREATING_TMPFILE;
lxw_sst_assemble_xml_file(sst);
err = _add_to_zip(self, sst->file, &buffer, &buffer_size,
"xl/sharedStrings.xml");
fclose(sst->file);
free(buffer);
RETURN_ON_ERROR(err);
return LXW_NO_ERROR;
}
/*
* Write the app.xml file.
*/
STATIC lxw_error
_write_app_file(lxw_packager *self)
{
lxw_workbook *workbook = self->workbook;
lxw_sheet *sheet;
lxw_worksheet *worksheet;
lxw_chartsheet *chartsheet;
lxw_defined_name *defined_name;
lxw_app *app;
char *buffer = NULL;
size_t buffer_size = 0;
uint32_t named_range_count = 0;
char *autofilter;
char *has_range;
char number[LXW_ATTR_32] = { 0 };
lxw_error err = LXW_NO_ERROR;
app = lxw_app_new();
if (!app) {
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
goto mem_error;
}
app->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
if (!app->file) {
err = LXW_ERROR_CREATING_TMPFILE;
goto mem_error;
}
if (self->workbook->num_worksheets) {
lxw_snprintf(number, LXW_ATTR_32, "%d",
self->workbook->num_worksheets);
lxw_app_add_heading_pair(app, "Worksheets", number);
}
if (self->workbook->num_chartsheets) {
lxw_snprintf(number, LXW_ATTR_32, "%d",
self->workbook->num_chartsheets);
lxw_app_add_heading_pair(app, "Charts", number);
}
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
if (!sheet->is_chartsheet) {
worksheet = sheet->u.worksheet;
lxw_app_add_part_name(app, worksheet->name);
}
}
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
if (sheet->is_chartsheet) {
chartsheet = sheet->u.chartsheet;
lxw_app_add_part_name(app, chartsheet->name);
}
}
/* Add the Named Ranges parts. */
TAILQ_FOREACH(defined_name, workbook->defined_names, list_pointers) {
has_range = strchr(defined_name->formula, '!');
autofilter = strstr(defined_name->app_name, "_FilterDatabase");
/* Only store defined names with ranges (except for autofilters). */
if (has_range && !autofilter) {
lxw_app_add_part_name(app, defined_name->app_name);
named_range_count++;
}
}
/* Add the Named Range heading pairs. */
if (named_range_count) {
lxw_snprintf(number, LXW_ATTR_32, "%d", named_range_count);
lxw_app_add_heading_pair(app, "Named Ranges", number);
}
/* Set the app/doc properties. */
app->properties = workbook->properties;
app->doc_security = workbook->read_only;
lxw_app_assemble_xml_file(app);
err = _add_to_zip(self, app->file, &buffer, &buffer_size,
"docProps/app.xml");
fclose(app->file);
free(buffer);
mem_error:
lxw_app_free(app);
return err;
}
/*
* Write the core.xml file.
*/
STATIC lxw_error
_write_core_file(lxw_packager *self)
{
lxw_error err = LXW_NO_ERROR;
lxw_core *core = lxw_core_new();
char *buffer = NULL;
size_t buffer_size = 0;
if (!core) {
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
goto mem_error;
}
core->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
if (!core->file) {
err = LXW_ERROR_CREATING_TMPFILE;
goto mem_error;
}
core->properties = self->workbook->properties;
lxw_core_assemble_xml_file(core);
err = _add_to_zip(self, core->file, &buffer, &buffer_size,
"docProps/core.xml");
fclose(core->file);
free(buffer);
mem_error:
lxw_core_free(core);
return err;
}
/*
* Write the metadata.xml file.
*/
STATIC lxw_error
_write_metadata_file(lxw_packager *self)
{
lxw_error err = LXW_NO_ERROR;
lxw_metadata *metadata;
char *buffer = NULL;
size_t buffer_size = 0;
if (!self->workbook->has_metadata)
return LXW_NO_ERROR;
metadata = lxw_metadata_new();
if (!metadata) {
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
goto mem_error;
}
metadata->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
if (!metadata->file) {
err = LXW_ERROR_CREATING_TMPFILE;
goto mem_error;
}
lxw_metadata_assemble_xml_file(metadata);
err = _add_to_zip(self, metadata->file, &buffer, &buffer_size,
"xl/metadata.xml");
fclose(metadata->file);
free(buffer);
mem_error:
lxw_metadata_free(metadata);
return err;
}
/*
* Write the custom.xml file.
*/
STATIC lxw_error
_write_custom_file(lxw_packager *self)
{
lxw_custom *custom;
char *buffer = NULL;
size_t buffer_size = 0;
lxw_error err = LXW_NO_ERROR;
if (STAILQ_EMPTY(self->workbook->custom_properties))
return LXW_NO_ERROR;
custom = lxw_custom_new();
if (!custom) {
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
goto mem_error;
}
custom->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
if (!custom->file) {
err = LXW_ERROR_CREATING_TMPFILE;
goto mem_error;
}
custom->custom_properties = self->workbook->custom_properties;
lxw_custom_assemble_xml_file(custom);
err = _add_to_zip(self, custom->file, &buffer, &buffer_size,
"docProps/custom.xml");
fclose(custom->file);
free(buffer);
mem_error:
lxw_custom_free(custom);
return err;
}
/*
* Write the theme.xml file.
*/
STATIC lxw_error
_write_theme_file(lxw_packager *self)
{
lxw_error err = LXW_NO_ERROR;
lxw_theme *theme = lxw_theme_new();
char *buffer = NULL;
size_t buffer_size = 0;
if (!theme) {
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
goto mem_error;
}
theme->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
if (!theme->file) {
err = LXW_ERROR_CREATING_TMPFILE;
goto mem_error;
}
lxw_theme_assemble_xml_file(theme);
err = _add_to_zip(self, theme->file, &buffer, &buffer_size,
"xl/theme/theme1.xml");
fclose(theme->file);
free(buffer);
mem_error:
lxw_theme_free(theme);
return err;
}
/*
* Write the styles.xml file.
*/
STATIC lxw_error
_write_styles_file(lxw_packager *self)
{
lxw_styles *styles = lxw_styles_new();
char *buffer = NULL;
size_t buffer_size = 0;
lxw_hash_element *hash_element;
lxw_error err = LXW_NO_ERROR;
if (!styles) {
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
goto mem_error;
}
/* Copy the unique and in-use formats from the workbook to the styles
* xf_format list. */
LXW_FOREACH_ORDERED(hash_element, self->workbook->used_xf_formats) {
lxw_format *workbook_format = (lxw_format *) hash_element->value;
lxw_format *style_format = lxw_format_new();
if (!style_format) {
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
goto mem_error;
}
memcpy(style_format, workbook_format, sizeof(lxw_format));
STAILQ_INSERT_TAIL(styles->xf_formats, style_format, list_pointers);
}
/* Copy the unique and in-use dxf formats from the workbook to the styles
* dxf_format list. */
LXW_FOREACH_ORDERED(hash_element, self->workbook->used_dxf_formats) {
lxw_format *workbook_format = (lxw_format *) hash_element->value;
lxw_format *style_format = lxw_format_new();
if (!style_format) {
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
goto mem_error;
}
memcpy(style_format, workbook_format, sizeof(lxw_format));
STAILQ_INSERT_TAIL(styles->dxf_formats, style_format, list_pointers);
}
styles->font_count = self->workbook->font_count;
styles->border_count = self->workbook->border_count;
styles->fill_count = self->workbook->fill_count;
styles->num_format_count = self->workbook->num_format_count;
styles->xf_count = self->workbook->used_xf_formats->unique_count;
styles->dxf_count = self->workbook->used_dxf_formats->unique_count;
styles->has_comments = self->workbook->has_comments;
styles->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
if (!styles->file) {
err = LXW_ERROR_CREATING_TMPFILE;
goto mem_error;
}
lxw_styles_assemble_xml_file(styles);
err = _add_to_zip(self, styles->file, &buffer, &buffer_size,
"xl/styles.xml");
fclose(styles->file);
free(buffer);
mem_error:
lxw_styles_free(styles);
return err;
}
/*
* Write the ContentTypes.xml file.
*/
STATIC lxw_error
_write_content_types_file(lxw_packager *self)
{
lxw_content_types *content_types = lxw_content_types_new();
char *buffer = NULL;
size_t buffer_size = 0;
lxw_workbook *workbook = self->workbook;
lxw_sheet *sheet;
char filename[LXW_MAX_ATTRIBUTE_LENGTH] = { 0 };
uint32_t index = 1;
uint32_t worksheet_index = 1;
uint32_t chartsheet_index = 1;
uint32_t drawing_count = _get_drawing_count(self);
uint32_t chart_count = _get_chart_count(self);
uint32_t table_count = _get_table_count(self);
lxw_error err = LXW_NO_ERROR;
if (!content_types) {
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
goto mem_error;
}
content_types->file = lxw_get_filehandle(&buffer, &buffer_size,
self->tmpdir);
if (!content_types->file) {
err = LXW_ERROR_CREATING_TMPFILE;
goto mem_error;
}
if (workbook->has_png)
lxw_ct_add_default(content_types, "png", "image/png");
if (workbook->has_jpeg)
lxw_ct_add_default(content_types, "jpeg", "image/jpeg");
if (workbook->has_bmp)
lxw_ct_add_default(content_types, "bmp", "image/bmp");
if (workbook->has_gif)
lxw_ct_add_default(content_types, "gif", "image/gif");
if (workbook->vba_project)
lxw_ct_add_default(content_types, "bin",
"application/vnd.ms-office.vbaProject");
if (workbook->vba_project)
lxw_ct_add_override(content_types, "/xl/workbook.xml",
LXW_APP_MSEXCEL "sheet.macroEnabled.main+xml");
else
lxw_ct_add_override(content_types, "/xl/workbook.xml",
LXW_APP_DOCUMENT "spreadsheetml.sheet.main+xml");
if (workbook->vba_project_signature)
lxw_ct_add_override(content_types, "/xl/vbaProjectSignature.bin",
"application/vnd.ms-office.vbaProjectSignature");
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
if (sheet->is_chartsheet) {
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
"/xl/chartsheets/sheet%d.xml", chartsheet_index++);
lxw_ct_add_chartsheet_name(content_types, filename);
}
else {
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
"/xl/worksheets/sheet%d.xml", worksheet_index++);
lxw_ct_add_worksheet_name(content_types, filename);
}
}
for (index = 1; index <= chart_count; index++) {
lxw_snprintf(filename, LXW_FILENAME_LENGTH, "/xl/charts/chart%d.xml",
index);
lxw_ct_add_chart_name(content_types, filename);
}
for (index = 1; index <= drawing_count; index++) {
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
"/xl/drawings/drawing%d.xml", index);
lxw_ct_add_drawing_name(content_types, filename);
}
for (index = 1; index <= table_count; index++) {
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
"/xl/tables/table%d.xml", index);
lxw_ct_add_table_name(content_types, filename);
}
if (workbook->has_vml)
lxw_ct_add_vml_name(content_types);
for (index = 1; index <= workbook->comment_count; index++) {
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
"/xl/comments%d.xml", index);
lxw_ct_add_comment_name(content_types, filename);
}
if (workbook->sst->string_count)
lxw_ct_add_shared_strings(content_types);
if (!STAILQ_EMPTY(self->workbook->custom_properties))
lxw_ct_add_custom_properties(content_types);
if (workbook->has_metadata)
lxw_ct_add_metadata(content_types);
lxw_content_types_assemble_xml_file(content_types);
err = _add_to_zip(self, content_types->file, &buffer, &buffer_size,
"[Content_Types].xml");
fclose(content_types->file);
free(buffer);
mem_error:
lxw_content_types_free(content_types);
return err;
}
/*
* Write the workbook .rels xml file.
*/
STATIC lxw_error
_write_workbook_rels_file(lxw_packager *self)
{
lxw_relationships *rels = lxw_relationships_new();
char *buffer = NULL;
size_t buffer_size = 0;
lxw_workbook *workbook = self->workbook;
lxw_sheet *sheet;
char sheetname[LXW_FILENAME_LENGTH] = { 0 };
uint32_t worksheet_index = 1;
uint32_t chartsheet_index = 1;
lxw_error err = LXW_NO_ERROR;
if (!rels) {
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
goto mem_error;
}
rels->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
if (!rels->file) {
err = LXW_ERROR_CREATING_TMPFILE;
goto mem_error;
}
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
if (sheet->is_chartsheet) {
lxw_snprintf(sheetname,
LXW_FILENAME_LENGTH,
"chartsheets/sheet%d.xml", chartsheet_index++);
lxw_add_document_relationship(rels, "/chartsheet", sheetname);
}
else {
lxw_snprintf(sheetname,
LXW_FILENAME_LENGTH,
"worksheets/sheet%d.xml", worksheet_index++);
lxw_add_document_relationship(rels, "/worksheet", sheetname);
}
}
lxw_add_document_relationship(rels, "/theme", "theme/theme1.xml");
lxw_add_document_relationship(rels, "/styles", "styles.xml");
if (workbook->sst->string_count)
lxw_add_document_relationship(rels, "/sharedStrings",
"sharedStrings.xml");
if (workbook->vba_project)
lxw_add_ms_package_relationship(rels, "/vbaProject",
"vbaProject.bin");
if (workbook->has_metadata)
lxw_add_document_relationship(rels, "/sheetMetadata", "metadata.xml");
lxw_relationships_assemble_xml_file(rels);
err = _add_to_zip(self, rels->file, &buffer, &buffer_size,
"xl/_rels/workbook.xml.rels");
fclose(rels->file);
free(buffer);
mem_error:
lxw_free_relationships(rels);
return err;
}
/*
* Write the worksheet .rels files for worksheets that contain links to
* external data such as hyperlinks or drawings.
*/
STATIC lxw_error
_write_worksheet_rels_file(lxw_packager *self)
{
lxw_relationships *rels;
char *buffer = NULL;
size_t buffer_size = 0;
lxw_rel_tuple *rel;
lxw_workbook *workbook = self->workbook;
lxw_sheet *sheet;
lxw_worksheet *worksheet;
char sheetname[LXW_FILENAME_LENGTH] = { 0 };
uint32_t index = 0;
lxw_error err;
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
if (sheet->is_chartsheet)
continue;
else
worksheet = sheet->u.worksheet;
index++;
if (STAILQ_EMPTY(worksheet->external_hyperlinks) &&
STAILQ_EMPTY(worksheet->external_drawing_links) &&
STAILQ_EMPTY(worksheet->external_table_links) &&
!worksheet->external_vml_header_link &&
!worksheet->external_vml_comment_link &&
!worksheet->external_background_link &&
!worksheet->external_comment_link)
continue;
rels = lxw_relationships_new();
rels->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
if (!rels->file) {
lxw_free_relationships(rels);
return LXW_ERROR_CREATING_TMPFILE;
}
STAILQ_FOREACH(rel, worksheet->external_hyperlinks, list_pointers) {
lxw_add_worksheet_relationship(rels, rel->type, rel->target,
rel->target_mode);
}
STAILQ_FOREACH(rel, worksheet->external_drawing_links, list_pointers) {
lxw_add_worksheet_relationship(rels, rel->type, rel->target,
rel->target_mode);
}
rel = worksheet->external_vml_comment_link;
if (rel)
lxw_add_worksheet_relationship(rels, rel->type, rel->target,
rel->target_mode);
rel = worksheet->external_vml_header_link;
if (rel)
lxw_add_worksheet_relationship(rels, rel->type, rel->target,
rel->target_mode);
rel = worksheet->external_background_link;
if (rel)
lxw_add_worksheet_relationship(rels, rel->type, rel->target,
rel->target_mode);
STAILQ_FOREACH(rel, worksheet->external_table_links, list_pointers) {
lxw_add_worksheet_relationship(rels, rel->type, rel->target,
rel->target_mode);
}
rel = worksheet->external_comment_link;
if (rel)
lxw_add_worksheet_relationship(rels, rel->type, rel->target,
rel->target_mode);
lxw_snprintf(sheetname, LXW_FILENAME_LENGTH,
"xl/worksheets/_rels/sheet%d.xml.rels", index);
lxw_relationships_assemble_xml_file(rels);
err = _add_to_zip(self, rels->file, &buffer, &buffer_size, sheetname);
fclose(rels->file);
free(buffer);
lxw_free_relationships(rels);
RETURN_ON_ERROR(err);
}
return LXW_NO_ERROR;
}
/*
* Write the chartsheet .rels files for chartsheets that contain links to
* external data such as drawings.
*/
STATIC lxw_error
_write_chartsheet_rels_file(lxw_packager *self)
{
lxw_relationships *rels;
char *buffer = NULL;
size_t buffer_size = 0;
lxw_rel_tuple *rel;
lxw_workbook *workbook = self->workbook;
lxw_sheet *sheet;
lxw_worksheet *worksheet;
char sheetname[LXW_FILENAME_LENGTH] = { 0 };
uint32_t index = 0;
lxw_error err;
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
if (sheet->is_chartsheet)
worksheet = sheet->u.chartsheet->worksheet;
else
continue;
index++;
if (STAILQ_EMPTY(worksheet->external_drawing_links))
continue;
rels = lxw_relationships_new();
rels->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
if (!rels->file) {
lxw_free_relationships(rels);
return LXW_ERROR_CREATING_TMPFILE;
}
STAILQ_FOREACH(rel, worksheet->external_hyperlinks, list_pointers) {
lxw_add_worksheet_relationship(rels, rel->type, rel->target,
rel->target_mode);
}
STAILQ_FOREACH(rel, worksheet->external_drawing_links, list_pointers) {
lxw_add_worksheet_relationship(rels, rel->type, rel->target,
rel->target_mode);
}
lxw_snprintf(sheetname, LXW_FILENAME_LENGTH,
"xl/chartsheets/_rels/sheet%d.xml.rels", index);
lxw_relationships_assemble_xml_file(rels);
err = _add_to_zip(self, rels->file, &buffer, &buffer_size, sheetname);
fclose(rels->file);
free(buffer);
lxw_free_relationships(rels);
RETURN_ON_ERROR(err);
}
return LXW_NO_ERROR;
}
/*
* Write the drawing .rels files for worksheets that contain charts or
* drawings.
*/
STATIC lxw_error
_write_drawing_rels_file(lxw_packager *self)
{
lxw_relationships *rels;
char *buffer = NULL;
size_t buffer_size = 0;
lxw_rel_tuple *rel;
lxw_workbook *workbook = self->workbook;
lxw_sheet *sheet;
lxw_worksheet *worksheet;
char sheetname[LXW_FILENAME_LENGTH] = { 0 };
uint32_t index = 1;
lxw_error err;
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
if (sheet->is_chartsheet)
worksheet = sheet->u.chartsheet->worksheet;
else
worksheet = sheet->u.worksheet;
if (STAILQ_EMPTY(worksheet->drawing_links))
continue;
rels = lxw_relationships_new();
rels->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
if (!rels->file) {
lxw_free_relationships(rels);
return LXW_ERROR_CREATING_TMPFILE;
}
STAILQ_FOREACH(rel, worksheet->drawing_links, list_pointers) {
lxw_add_worksheet_relationship(rels, rel->type, rel->target,
rel->target_mode);
}
lxw_snprintf(sheetname, LXW_FILENAME_LENGTH,
"xl/drawings/_rels/drawing%d.xml.rels", index++);
lxw_relationships_assemble_xml_file(rels);
err = _add_to_zip(self, rels->file, &buffer, &buffer_size, sheetname);
fclose(rels->file);
free(buffer);
lxw_free_relationships(rels);
RETURN_ON_ERROR(err);
}
return LXW_NO_ERROR;
}
/*
* Write the vmlDrawing .rels files for worksheets that contain images in
* headers or footers.
*/
STATIC lxw_error
_write_vml_drawing_rels_file(lxw_packager *self, lxw_worksheet *worksheet,
uint32_t index)
{
lxw_relationships *rels;
char *buffer = NULL;
size_t buffer_size = 0;
lxw_rel_tuple *rel;
char sheetname[LXW_FILENAME_LENGTH] = { 0 };
lxw_error err = LXW_NO_ERROR;
rels = lxw_relationships_new();
rels->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
if (!rels->file) {
lxw_free_relationships(rels);
return LXW_ERROR_CREATING_TMPFILE;
}
STAILQ_FOREACH(rel, worksheet->vml_drawing_links, list_pointers) {
lxw_add_worksheet_relationship(rels, rel->type, rel->target,
rel->target_mode);
}
lxw_snprintf(sheetname, LXW_FILENAME_LENGTH,
"xl/drawings/_rels/vmlDrawing%d.vml.rels", index);
lxw_relationships_assemble_xml_file(rels);
err = _add_to_zip(self, rels->file, &buffer, &buffer_size, sheetname);
fclose(rels->file);
free(buffer);
lxw_free_relationships(rels);
return err;
}
/*
* Write the vbaProject .rels xml file.
*/
STATIC lxw_error
_write_vba_project_rels_file(lxw_packager *self)
{
lxw_relationships *rels;
lxw_workbook *workbook = self->workbook;
lxw_error err = LXW_NO_ERROR;
char *buffer = NULL;
size_t buffer_size = 0;
if (!workbook->vba_project_signature)
return LXW_NO_ERROR;
rels = lxw_relationships_new();
if (!rels) {
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
goto mem_error;
}
rels->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
if (!rels->file) {
err = LXW_ERROR_CREATING_TMPFILE;
goto mem_error;
}
lxw_add_ms_package_relationship(rels, "/vbaProjectSignature",
"vbaProjectSignature.bin");
lxw_relationships_assemble_xml_file(rels);
err = _add_to_zip(self, rels->file, &buffer, &buffer_size,
"xl/_rels/vbaProject.bin.rels");
fclose(rels->file);
free(buffer);
mem_error:
lxw_free_relationships(rels);
return err;
}
/*
* Write the _rels/.rels xml file.
*/
STATIC lxw_error
_write_root_rels_file(lxw_packager *self)
{
lxw_relationships *rels = lxw_relationships_new();
char *buffer = NULL;
size_t buffer_size = 0;
lxw_error err = LXW_NO_ERROR;
if (!rels) {
err = LXW_ERROR_MEMORY_MALLOC_FAILED;
goto mem_error;
}
rels->file = lxw_get_filehandle(&buffer, &buffer_size, self->tmpdir);
if (!rels->file) {
err = LXW_ERROR_CREATING_TMPFILE;
goto mem_error;
}
lxw_add_document_relationship(rels, "/officeDocument", "xl/workbook.xml");
lxw_add_package_relationship(rels,
"/metadata/core-properties",
"docProps/core.xml");
lxw_add_document_relationship(rels,
"/extended-properties", "docProps/app.xml");
if (!STAILQ_EMPTY(self->workbook->custom_properties))
lxw_add_document_relationship(rels,
"/custom-properties",
"docProps/custom.xml");
lxw_relationships_assemble_xml_file(rels);
err = _add_to_zip(self, rels->file, &buffer, &buffer_size, "_rels/.rels");
fclose(rels->file);
free(buffer);
mem_error:
lxw_free_relationships(rels);
return err;
}
/*****************************************************************************
*
* Public functions.
*
****************************************************************************/
STATIC lxw_error
_add_file_to_zip(lxw_packager *self, FILE * file, const char *filename)
{
int16_t error = ZIP_OK;
size_t size_read;
error = zipOpenNewFileInZip4_64(self->zipfile,
filename,
&self->zipfile_info,
NULL, 0, NULL, 0, NULL,
Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0,
-MAX_WBITS, DEF_MEM_LEVEL,
Z_DEFAULT_STRATEGY, NULL, 0, 0, 0,
self->use_zip64);
if (error != ZIP_OK) {
LXW_ERROR("Error adding member to zipfile");
RETURN_ON_ZIP_ERROR(error, LXW_ERROR_ZIP_FILE_ADD);
}
fflush(file);
rewind(file);
size_read = fread((void *) self->buffer, 1, self->buffer_size, file);
while (size_read) {
if (size_read < self->buffer_size) {
if (ferror(file)) {
LXW_ERROR("Error reading member file data");
RETURN_ON_ZIP_ERROR(error, LXW_ERROR_ZIP_FILE_ADD);
}
}
error = zipWriteInFileInZip(self->zipfile,
self->buffer, (unsigned int) size_read);
if (error < 0) {
LXW_ERROR("Error in writing member in the zipfile");
RETURN_ON_ZIP_ERROR(error, LXW_ERROR_ZIP_FILE_ADD);
}
size_read =
fread((void *) (void *) self->buffer, 1, self->buffer_size, file);
}
error = zipCloseFileInZip(self->zipfile);
if (error != ZIP_OK) {
LXW_ERROR("Error in closing member in the zipfile");
RETURN_ON_ZIP_ERROR(error, LXW_ERROR_ZIP_FILE_ADD);
}
return LXW_NO_ERROR;
}
STATIC lxw_error
_add_buffer_to_zip(lxw_packager *self, const char *buffer, size_t buffer_size,
const char *filename)
{
int16_t error = ZIP_OK;
error = zipOpenNewFileInZip4_64(self->zipfile,
filename,
&self->zipfile_info,
NULL, 0, NULL, 0, NULL,
Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0,
-MAX_WBITS, DEF_MEM_LEVEL,
Z_DEFAULT_STRATEGY, NULL, 0, 0, 0,
self->use_zip64);
if (error != ZIP_OK) {
LXW_ERROR("Error adding member to zipfile");
RETURN_ON_ZIP_ERROR(error, LXW_ERROR_ZIP_FILE_ADD);
}
error = zipWriteInFileInZip(self->zipfile,
buffer, (unsigned int) buffer_size);
if (error < 0) {
LXW_ERROR("Error in writing member in the zipfile");
RETURN_ON_ZIP_ERROR(error, LXW_ERROR_ZIP_FILE_ADD);
}
error = zipCloseFileInZip(self->zipfile);
if (error != ZIP_OK) {
LXW_ERROR("Error in closing member in the zipfile");
RETURN_ON_ZIP_ERROR(error, LXW_ERROR_ZIP_FILE_ADD);
}
return LXW_NO_ERROR;
}
STATIC lxw_error
_add_to_zip(lxw_packager *self, FILE * file, char **buffer,
size_t *buffer_size, const char *filename)
{
/* Flush to ensure buffer is updated when using a memory-backed file. */
fflush(file);
return *buffer ?
_add_buffer_to_zip(self, *buffer, *buffer_size, filename) :
_add_file_to_zip(self, file, filename);
}
/*
* Write the xml files that make up the XLSX OPC package.
*/
lxw_error
lxw_create_package(lxw_packager *self)
{
lxw_error error;
int8_t zip_error;
error = _write_content_types_file(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_root_rels_file(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_workbook_rels_file(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_worksheet_files(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_chartsheet_files(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_workbook_file(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_chart_files(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_drawing_files(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_vml_files(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_comment_files(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_table_files(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_shared_strings_file(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_custom_file(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_theme_file(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_styles_file(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_worksheet_rels_file(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_chartsheet_rels_file(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_drawing_rels_file(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_image_files(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _add_vba_project(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _add_vba_project_signature(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_vba_project_rels_file(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_core_file(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_metadata_file(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
error = _write_app_file(self);
RETURN_AND_ZIPCLOSE_ON_ERROR(error);
zip_error = zipClose(self->zipfile, NULL);
if (zip_error) {
RETURN_ON_ZIP_ERROR(zip_error, LXW_ERROR_ZIP_CLOSE);
}
return LXW_NO_ERROR;
}
writexl/src/libxlsxwriter/app.c 0000644 0001762 0000144 00000024102 14747162622 016417 0 ustar ligges users /*****************************************************************************
* app - A library for creating Excel XLSX app files.
*
* Used in conjunction with the libxlsxwriter library.
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
*/
#include "xlsxwriter/xmlwriter.h"
#include "xlsxwriter/app.h"
#include "xlsxwriter/utility.h"
/*
* Forward declarations.
*/
/*****************************************************************************
*
* Private functions.
*
****************************************************************************/
/*
* Create a new app object.
*/
lxw_app *
lxw_app_new(void)
{
lxw_app *app = calloc(1, sizeof(lxw_app));
GOTO_LABEL_ON_MEM_ERROR(app, mem_error);
app->heading_pairs = calloc(1, sizeof(struct lxw_heading_pairs));
GOTO_LABEL_ON_MEM_ERROR(app->heading_pairs, mem_error);
STAILQ_INIT(app->heading_pairs);
app->part_names = calloc(1, sizeof(struct lxw_part_names));
GOTO_LABEL_ON_MEM_ERROR(app->part_names, mem_error);
STAILQ_INIT(app->part_names);
return app;
mem_error:
lxw_app_free(app);
return NULL;
}
/*
* Free a app object.
*/
void
lxw_app_free(lxw_app *app)
{
lxw_heading_pair *heading_pair;
lxw_part_name *part_name;
if (!app)
return;
/* Free the lists in the App object. */
if (app->heading_pairs) {
while (!STAILQ_EMPTY(app->heading_pairs)) {
heading_pair = STAILQ_FIRST(app->heading_pairs);
STAILQ_REMOVE_HEAD(app->heading_pairs, list_pointers);
free(heading_pair->key);
free(heading_pair->value);
free(heading_pair);
}
free(app->heading_pairs);
}
if (app->part_names) {
while (!STAILQ_EMPTY(app->part_names)) {
part_name = STAILQ_FIRST(app->part_names);
STAILQ_REMOVE_HEAD(app->part_names, list_pointers);
free(part_name->name);
free(part_name);
}
free(app->part_names);
}
free(app);
}
/*****************************************************************************
*
* XML functions.
*
****************************************************************************/
/*
* Write the XML declaration.
*/
STATIC void
_app_xml_declaration(lxw_app *self)
{
lxw_xml_declaration(self->file);
}
/*
* Write the element.
*/
STATIC void
_write_properties(lxw_app *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char xmlns[] = LXW_SCHEMA_OFFICEDOC "/extended-properties";
char xmlns_vt[] = LXW_SCHEMA_OFFICEDOC "/docPropsVTypes";
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("xmlns", xmlns);
LXW_PUSH_ATTRIBUTES_STR("xmlns:vt", xmlns_vt);
lxw_xml_start_tag(self->file, "Properties", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_application(lxw_app *self)
{
lxw_xml_data_element(self->file, "Application", "Microsoft Excel", NULL);
}
/*
* Write the element.
*/
STATIC void
_write_doc_security(lxw_app *self)
{
if (self->doc_security == 2)
lxw_xml_data_element(self->file, "DocSecurity", "2", NULL);
else
lxw_xml_data_element(self->file, "DocSecurity", "0", NULL);
}
/*
* Write the element.
*/
STATIC void
_write_scale_crop(lxw_app *self)
{
lxw_xml_data_element(self->file, "ScaleCrop", "false", NULL);
}
/*
* Write the element.
*/
STATIC void
_write_vt_lpstr(lxw_app *self, const char *str)
{
lxw_xml_data_element(self->file, "vt:lpstr", str, NULL);
}
/*
* Write the element.
*/
STATIC void
_write_vt_i4(lxw_app *self, const char *value)
{
lxw_xml_data_element(self->file, "vt:i4", value, NULL);
}
/*
* Write the element.
*/
STATIC void
_write_vt_variant(lxw_app *self, const char *key, const char *value)
{
/* Write the vt:lpstr element. */
lxw_xml_start_tag(self->file, "vt:variant", NULL);
_write_vt_lpstr(self, key);
lxw_xml_end_tag(self->file, "vt:variant");
/* Write the vt:i4 element. */
lxw_xml_start_tag(self->file, "vt:variant", NULL);
_write_vt_i4(self, value);
lxw_xml_end_tag(self->file, "vt:variant");
}
/*
* Write the element for the heading pairs.
*/
STATIC void
_write_vt_vector_heading_pairs(lxw_app *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
lxw_heading_pair *heading_pair;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_INT("size", self->num_heading_pairs * 2);
LXW_PUSH_ATTRIBUTES_STR("baseType", "variant");
lxw_xml_start_tag(self->file, "vt:vector", &attributes);
STAILQ_FOREACH(heading_pair, self->heading_pairs, list_pointers) {
_write_vt_variant(self, heading_pair->key, heading_pair->value);
}
lxw_xml_end_tag(self->file, "vt:vector");
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element for the named parts.
*/
STATIC void
_write_vt_vector_lpstr_named_parts(lxw_app *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
lxw_part_name *part_name;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_INT("size", self->num_part_names);
LXW_PUSH_ATTRIBUTES_STR("baseType", "lpstr");
lxw_xml_start_tag(self->file, "vt:vector", &attributes);
STAILQ_FOREACH(part_name, self->part_names, list_pointers) {
_write_vt_lpstr(self, part_name->name);
}
lxw_xml_end_tag(self->file, "vt:vector");
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_heading_pairs(lxw_app *self)
{
lxw_xml_start_tag(self->file, "HeadingPairs", NULL);
/* Write the vt:vector element. */
_write_vt_vector_heading_pairs(self);
lxw_xml_end_tag(self->file, "HeadingPairs");
}
/*
* Write the element.
*/
STATIC void
_write_titles_of_parts(lxw_app *self)
{
lxw_xml_start_tag(self->file, "TitlesOfParts", NULL);
/* Write the vt:vector element. */
_write_vt_vector_lpstr_named_parts(self);
lxw_xml_end_tag(self->file, "TitlesOfParts");
}
/*
* Write the element.
*/
STATIC void
_write_manager(lxw_app *self)
{
lxw_doc_properties *properties = self->properties;
if (!properties)
return;
if (properties->manager)
lxw_xml_data_element(self->file, "Manager", properties->manager,
NULL);
}
/*
* Write the element.
*/
STATIC void
_write_company(lxw_app *self)
{
lxw_doc_properties *properties = self->properties;
if (properties && properties->company)
lxw_xml_data_element(self->file, "Company", properties->company,
NULL);
else
lxw_xml_data_element(self->file, "Company", "", NULL);
}
/*
* Write the element.
*/
STATIC void
_write_links_up_to_date(lxw_app *self)
{
lxw_xml_data_element(self->file, "LinksUpToDate", "false", NULL);
}
/*
* Write the element.
*/
STATIC void
_write_shared_doc(lxw_app *self)
{
lxw_xml_data_element(self->file, "SharedDoc", "false", NULL);
}
/*
* Write the element.
*/
STATIC void
_write_hyperlink_base(lxw_app *self)
{
lxw_doc_properties *properties = self->properties;
if (!properties)
return;
if (properties->hyperlink_base)
lxw_xml_data_element(self->file, "HyperlinkBase",
properties->hyperlink_base, NULL);
}
/*
* Write the element.
*/
STATIC void
_write_hyperlinks_changed(lxw_app *self)
{
lxw_xml_data_element(self->file, "HyperlinksChanged", "false", NULL);
}
/*
* Write the element.
*/
STATIC void
_write_app_version(lxw_app *self)
{
lxw_xml_data_element(self->file, "AppVersion", "12.0000", NULL);
}
/*****************************************************************************
*
* XML file assembly functions.
*
****************************************************************************/
/*
* Assemble and write the XML file.
*/
void
lxw_app_assemble_xml_file(lxw_app *self)
{
/* Write the XML declaration. */
_app_xml_declaration(self);
_write_properties(self);
_write_application(self);
_write_doc_security(self);
_write_scale_crop(self);
_write_heading_pairs(self);
_write_titles_of_parts(self);
_write_manager(self);
_write_company(self);
_write_links_up_to_date(self);
_write_shared_doc(self);
_write_hyperlink_base(self);
_write_hyperlinks_changed(self);
_write_app_version(self);
lxw_xml_end_tag(self->file, "Properties");
}
/*****************************************************************************
*
* Public functions.
*
****************************************************************************/
/*
* Add the name of a workbook Part such as 'Sheet1' or 'Print_Titles'.
*/
void
lxw_app_add_part_name(lxw_app *self, const char *name)
{
lxw_part_name *part_name;
if (!name)
return;
part_name = calloc(1, sizeof(lxw_part_name));
GOTO_LABEL_ON_MEM_ERROR(part_name, mem_error);
part_name->name = lxw_strdup(name);
GOTO_LABEL_ON_MEM_ERROR(part_name->name, mem_error);
STAILQ_INSERT_TAIL(self->part_names, part_name, list_pointers);
self->num_part_names++;
return;
mem_error:
if (part_name) {
free(part_name->name);
free(part_name);
}
}
/*
* Add the name of a workbook Heading Pair such as 'Worksheets', 'Charts' or
* 'Named Ranges'.
*/
void
lxw_app_add_heading_pair(lxw_app *self, const char *key, const char *value)
{
lxw_heading_pair *heading_pair;
if (!key || !value)
return;
heading_pair = calloc(1, sizeof(lxw_heading_pair));
GOTO_LABEL_ON_MEM_ERROR(heading_pair, mem_error);
heading_pair->key = lxw_strdup(key);
GOTO_LABEL_ON_MEM_ERROR(heading_pair->key, mem_error);
heading_pair->value = lxw_strdup(value);
GOTO_LABEL_ON_MEM_ERROR(heading_pair->value, mem_error);
STAILQ_INSERT_TAIL(self->heading_pairs, heading_pair, list_pointers);
self->num_heading_pairs++;
return;
mem_error:
if (heading_pair) {
free(heading_pair->key);
free(heading_pair->value);
free(heading_pair);
}
}
writexl/src/libxlsxwriter/styles.c 0000644 0001762 0000144 00000107656 14747162622 017202 0 ustar ligges users /*****************************************************************************
* styles - A library for creating Excel XLSX styles files.
*
* Used in conjunction with the libxlsxwriter library.
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
*/
#include "xlsxwriter/xmlwriter.h"
#include "xlsxwriter/styles.h"
#include "xlsxwriter/utility.h"
/*
* Forward declarations.
*/
STATIC void _write_font(lxw_styles *self, lxw_format *format, uint8_t is_dxf,
uint8_t is_rich_string);
/*****************************************************************************
*
* Private functions.
*
****************************************************************************/
/*
* Create a new styles object.
*/
lxw_styles *
lxw_styles_new(void)
{
lxw_styles *styles = calloc(1, sizeof(lxw_styles));
GOTO_LABEL_ON_MEM_ERROR(styles, mem_error);
styles->xf_formats = calloc(1, sizeof(struct lxw_formats));
GOTO_LABEL_ON_MEM_ERROR(styles->xf_formats, mem_error);
STAILQ_INIT(styles->xf_formats);
styles->dxf_formats = calloc(1, sizeof(struct lxw_formats));
GOTO_LABEL_ON_MEM_ERROR(styles->dxf_formats, mem_error);
STAILQ_INIT(styles->dxf_formats);
return styles;
mem_error:
lxw_styles_free(styles);
return NULL;
}
/*
* Free a styles object.
*/
void
lxw_styles_free(lxw_styles *styles)
{
lxw_format *format;
if (!styles)
return;
/* Free the xf formats in the styles. */
if (styles->xf_formats) {
while (!STAILQ_EMPTY(styles->xf_formats)) {
format = STAILQ_FIRST(styles->xf_formats);
STAILQ_REMOVE_HEAD(styles->xf_formats, list_pointers);
free(format);
}
free(styles->xf_formats);
}
/* Free the dxf formats in the styles. */
if (styles->dxf_formats) {
while (!STAILQ_EMPTY(styles->dxf_formats)) {
format = STAILQ_FIRST(styles->dxf_formats);
STAILQ_REMOVE_HEAD(styles->dxf_formats, list_pointers);
free(format);
}
free(styles->dxf_formats);
}
free(styles);
}
/*
* Write the element for rich strings.
*/
void
lxw_styles_write_string_fragment(lxw_styles *self, const char *string)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
/* Add attribute to preserve leading or trailing whitespace. */
if (isspace((unsigned char) string[0])
|| isspace((unsigned char) string[strlen(string) - 1]))
LXW_PUSH_ATTRIBUTES_STR("xml:space", "preserve");
lxw_xml_data_element(self->file, "t", string, &attributes);
LXW_FREE_ATTRIBUTES();
}
void
lxw_styles_write_rich_font(lxw_styles *self, lxw_format *format)
{
_write_font(self, format, LXW_FALSE, LXW_TRUE);
}
/*****************************************************************************
*
* XML functions.
*
****************************************************************************/
/*
* Write the XML declaration.
*/
STATIC void
_styles_xml_declaration(lxw_styles *self)
{
lxw_xml_declaration(self->file);
}
/*
* Write the element.
*/
STATIC void
_write_style_sheet(lxw_styles *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("xmlns",
"http://schemas.openxmlformats.org/spreadsheetml/2006/main");
lxw_xml_start_tag(self->file, "styleSheet", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_num_fmt(lxw_styles *self, uint16_t num_fmt_id, char *format_code)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char *format_codes[] = {
"General",
"0",
"0.00",
"#,##0",
"#,##0.00",
"($#,##0_);($#,##0)",
"($#,##0_);[Red]($#,##0)",
"($#,##0.00_);($#,##0.00)",
"($#,##0.00_);[Red]($#,##0.00)",
"0%",
"0.00%",
"0.00E+00",
"# ?/?",
"# ?" "?/?" "?", /* Split string to avoid unintentional trigraph. */
"m/d/yy",
"d-mmm-yy",
"d-mmm",
"mmm-yy",
"h:mm AM/PM",
"h:mm:ss AM/PM",
"h:mm",
"h:mm:ss",
"m/d/yy h:mm",
"General",
"General",
"General",
"General",
"General",
"General",
"General",
"General",
"General",
"General",
"General",
"General",
"General",
"General",
"(#,##0_);(#,##0)",
"(#,##0_);[Red](#,##0)",
"(#,##0.00_);(#,##0.00)",
"(#,##0.00_);[Red](#,##0.00)",
"_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)",
"_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(@_)",
"_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)",
"_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(@_)",
"mm:ss",
"[h]:mm:ss",
"mm:ss.0",
"##0.0E+0",
"@"
};
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_INT("numFmtId", num_fmt_id);
if (num_fmt_id < 50)
LXW_PUSH_ATTRIBUTES_STR("formatCode", format_codes[num_fmt_id]);
else if (num_fmt_id < 164)
LXW_PUSH_ATTRIBUTES_STR("formatCode", "General");
else
LXW_PUSH_ATTRIBUTES_STR("formatCode", format_code);
lxw_xml_empty_tag(self->file, "numFmt", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_num_fmts(lxw_styles *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
lxw_format *format;
uint16_t last_format_index = 0;
if (!self->num_format_count)
return;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_INT("count", self->num_format_count);
lxw_xml_start_tag(self->file, "numFmts", &attributes);
/* Write the numFmts elements. */
STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
/* Ignore built-in number formats, i.e., < 164. */
if (format->num_format_index < 164)
continue;
/* Ignore duplicates which have an already used index. */
if (format->num_format_index <= last_format_index)
continue;
_write_num_fmt(self, format->num_format_index, format->num_format);
last_format_index = format->num_format_index;
}
lxw_xml_end_tag(self->file, "numFmts");
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_font_size(lxw_styles *self, double font_size)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_DBL("val", font_size);
lxw_xml_empty_tag(self->file, "sz", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element for themes.
*/
STATIC void
_write_font_color_theme(lxw_styles *self, uint8_t theme)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_INT("theme", theme);
lxw_xml_empty_tag(self->file, "color", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element for RGB colors.
*/
STATIC void
_write_font_color_rgb(lxw_styles *self, int32_t rgb)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char rgb_str[LXW_ATTR_32];
lxw_snprintf(rgb_str, LXW_ATTR_32, "FF%06X", rgb & LXW_COLOR_MASK);
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("rgb", rgb_str);
lxw_xml_empty_tag(self->file, "color", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element for indexed colors.
*/
STATIC void
_write_font_color_indexed(lxw_styles *self, uint8_t index)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_INT("indexed", index);
lxw_xml_empty_tag(self->file, "color", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_font_name(lxw_styles *self, const char *font_name,
uint8_t is_rich_string)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
if (*font_name)
LXW_PUSH_ATTRIBUTES_STR("val", font_name);
else
LXW_PUSH_ATTRIBUTES_STR("val", LXW_DEFAULT_FONT_NAME);
if (is_rich_string)
lxw_xml_empty_tag(self->file, "rFont", &attributes);
else
lxw_xml_empty_tag(self->file, "name", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_font_family(lxw_styles *self, uint8_t font_family)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_INT("val", font_family);
lxw_xml_empty_tag(self->file, "family", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_font_scheme(lxw_styles *self, const char *font_scheme)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
if (*font_scheme)
LXW_PUSH_ATTRIBUTES_STR("val", font_scheme);
else
LXW_PUSH_ATTRIBUTES_STR("val", "minor");
lxw_xml_empty_tag(self->file, "scheme", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the underline font element.
*/
STATIC void
_write_font_underline(lxw_styles *self, uint8_t underline)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
/* Handle the underline variants. */
if (underline == LXW_UNDERLINE_DOUBLE)
LXW_PUSH_ATTRIBUTES_STR("val", "double");
else if (underline == LXW_UNDERLINE_SINGLE_ACCOUNTING)
LXW_PUSH_ATTRIBUTES_STR("val", "singleAccounting");
else if (underline == LXW_UNDERLINE_DOUBLE_ACCOUNTING)
LXW_PUSH_ATTRIBUTES_STR("val", "doubleAccounting");
/* Default to single underline. */
lxw_xml_empty_tag(self->file, "u", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the font element.
*/
STATIC void
_write_font_condense(lxw_styles *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("val", "0");
lxw_xml_empty_tag(self->file, "condense", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the font element.
*/
STATIC void
_write_font_extend(lxw_styles *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("val", "0");
lxw_xml_empty_tag(self->file, "extend", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the font sub-element.
*/
STATIC void
_write_font_vert_align(lxw_styles *self, const char *align)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("val", align);
lxw_xml_empty_tag(self->file, "vertAlign", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_font(lxw_styles *self, lxw_format *format, uint8_t is_dxf,
uint8_t is_rich_string)
{
if (is_rich_string)
lxw_xml_start_tag(self->file, "rPr", NULL);
else
lxw_xml_start_tag(self->file, "font", NULL);
if (format->font_condense)
_write_font_condense(self);
if (format->font_extend)
_write_font_extend(self);
if (format->bold)
lxw_xml_empty_tag(self->file, "b", NULL);
if (format->italic)
lxw_xml_empty_tag(self->file, "i", NULL);
if (format->font_strikeout)
lxw_xml_empty_tag(self->file, "strike", NULL);
if (format->font_outline)
lxw_xml_empty_tag(self->file, "outline", NULL);
if (format->font_shadow)
lxw_xml_empty_tag(self->file, "shadow", NULL);
if (format->underline)
_write_font_underline(self, format->underline);
if (format->font_script == LXW_FONT_SUPERSCRIPT)
_write_font_vert_align(self, "superscript");
if (format->font_script == LXW_FONT_SUBSCRIPT)
_write_font_vert_align(self, "subscript");
if (!is_dxf && format->font_size > 0.0)
_write_font_size(self, format->font_size);
if (format->theme)
_write_font_color_theme(self, format->theme);
else if (format->color_indexed)
_write_font_color_indexed(self, format->color_indexed);
else if (format->font_color != LXW_COLOR_UNSET)
_write_font_color_rgb(self, format->font_color);
else if (!is_dxf)
_write_font_color_theme(self, LXW_DEFAULT_FONT_THEME);
if (!is_dxf) {
_write_font_name(self, format->font_name, is_rich_string);
_write_font_family(self, format->font_family);
/* Only write the scheme element for the default font type if it
* is a hyperlink. */
if ((!*format->font_name
|| strcmp(LXW_DEFAULT_FONT_NAME, format->font_name) == 0)
&& !format->hyperlink) {
_write_font_scheme(self, format->font_scheme);
}
}
if (format->hyperlink) {
self->has_hyperlink = LXW_TRUE;
if (self->hyperlink_font_id == 0)
self->hyperlink_font_id = format->font_index;
}
if (is_rich_string)
lxw_xml_end_tag(self->file, "rPr");
else
lxw_xml_end_tag(self->file, "font");
}
/*
* Write the element for comments.
*/
STATIC void
_write_comment_font(lxw_styles *self)
{
lxw_xml_start_tag(self->file, "font", NULL);
_write_font_size(self, 8);
_write_font_color_indexed(self, 81);
_write_font_name(self, "Tahoma", LXW_FALSE);
_write_font_family(self, 2);
lxw_xml_end_tag(self->file, "font");
}
/*
* Write the element.
*/
STATIC void
_write_fonts(lxw_styles *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
lxw_format *format;
uint32_t count;
LXW_INIT_ATTRIBUTES();
count = self->font_count;
if (self->has_comments)
count++;
LXW_PUSH_ATTRIBUTES_INT("count", count);
lxw_xml_start_tag(self->file, "fonts", &attributes);
STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
if (format->has_font)
_write_font(self, format, LXW_FALSE, LXW_FALSE);
}
if (self->has_comments)
_write_comment_font(self);
lxw_xml_end_tag(self->file, "fonts");
LXW_FREE_ATTRIBUTES();
}
/*
* Write the default element.
*/
STATIC void
_write_default_fill(lxw_styles *self, const char *pattern)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("patternType", pattern);
lxw_xml_start_tag(self->file, "fill", NULL);
lxw_xml_empty_tag(self->file, "patternFill", &attributes);
lxw_xml_end_tag(self->file, "fill");
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_fg_color(lxw_styles *self, lxw_color_t color)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char rgb_str[LXW_ATTR_32];
LXW_INIT_ATTRIBUTES();
lxw_snprintf(rgb_str, LXW_ATTR_32, "FF%06X", color & LXW_COLOR_MASK);
LXW_PUSH_ATTRIBUTES_STR("rgb", rgb_str);
lxw_xml_empty_tag(self->file, "fgColor", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_bg_color(lxw_styles *self, lxw_color_t color, uint8_t pattern)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char rgb_str[LXW_ATTR_32];
LXW_INIT_ATTRIBUTES();
if (color == LXW_COLOR_UNSET) {
if (pattern <= LXW_PATTERN_SOLID) {
LXW_PUSH_ATTRIBUTES_STR("indexed", "64");
lxw_xml_empty_tag(self->file, "bgColor", &attributes);
}
}
else {
lxw_snprintf(rgb_str, LXW_ATTR_32, "FF%06X", color & LXW_COLOR_MASK);
LXW_PUSH_ATTRIBUTES_STR("rgb", rgb_str);
lxw_xml_empty_tag(self->file, "bgColor", &attributes);
}
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_fill(lxw_styles *self, lxw_format *format, uint8_t is_dxf)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
uint8_t pattern = format->pattern;
lxw_color_t bg_color = format->bg_color;
lxw_color_t fg_color = format->fg_color;
char *patterns[] = {
"none",
"solid",
"mediumGray",
"darkGray",
"lightGray",
"darkHorizontal",
"darkVertical",
"darkDown",
"darkUp",
"darkGrid",
"darkTrellis",
"lightHorizontal",
"lightVertical",
"lightDown",
"lightUp",
"lightGrid",
"lightTrellis",
"gray125",
"gray0625",
};
if (is_dxf) {
bg_color = format->dxf_bg_color;
fg_color = format->dxf_fg_color;
}
LXW_INIT_ATTRIBUTES();
/* Special handling for pattern only case. */
if (!bg_color && !fg_color && pattern) {
_write_default_fill(self, patterns[pattern]);
LXW_FREE_ATTRIBUTES();
return;
}
lxw_xml_start_tag(self->file, "fill", NULL);
/* None/Solid patterns are handled differently for dxf formats. */
if (pattern && !(is_dxf && pattern <= LXW_PATTERN_SOLID))
LXW_PUSH_ATTRIBUTES_STR("patternType", patterns[pattern]);
lxw_xml_start_tag(self->file, "patternFill", &attributes);
if (fg_color != LXW_COLOR_UNSET)
_write_fg_color(self, fg_color);
_write_bg_color(self, bg_color, pattern);
lxw_xml_end_tag(self->file, "patternFill");
lxw_xml_end_tag(self->file, "fill");
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_fills(lxw_styles *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
lxw_format *format;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_INT("count", self->fill_count);
lxw_xml_start_tag(self->file, "fills", &attributes);
/* Write the default fills. */
_write_default_fill(self, "none");
_write_default_fill(self, "gray125");
STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
if (format->has_fill)
_write_fill(self, format, LXW_FALSE);
}
lxw_xml_end_tag(self->file, "fills");
LXW_FREE_ATTRIBUTES();
}
/*
* Write the border element.
*/
STATIC void
_write_border_color(lxw_styles *self, lxw_color_t color)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char rgb_str[LXW_ATTR_32];
LXW_INIT_ATTRIBUTES();
if (color != LXW_COLOR_UNSET) {
lxw_snprintf(rgb_str, LXW_ATTR_32, "FF%06X", color & LXW_COLOR_MASK);
LXW_PUSH_ATTRIBUTES_STR("rgb", rgb_str);
}
else {
LXW_PUSH_ATTRIBUTES_STR("auto", "1");
}
lxw_xml_empty_tag(self->file, "color", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the sub elements such as , , etc.
*/
STATIC void
_write_sub_border(lxw_styles *self, const char *type, uint8_t style,
lxw_color_t color)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char *border_styles[] = {
"none",
"thin",
"medium",
"dashed",
"dotted",
"thick",
"double",
"hair",
"mediumDashed",
"dashDot",
"mediumDashDot",
"dashDotDot",
"mediumDashDotDot",
"slantDashDot",
};
if (!style) {
lxw_xml_empty_tag(self->file, type, NULL);
return;
}
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("style", border_styles[style]);
lxw_xml_start_tag(self->file, type, &attributes);
_write_border_color(self, color);
lxw_xml_end_tag(self->file, type);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_border(lxw_styles *self, lxw_format *format, uint8_t is_dxf)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
/* Add attributes for diagonal borders. */
if (format->diag_type == LXW_DIAGONAL_BORDER_UP) {
LXW_PUSH_ATTRIBUTES_STR("diagonalUp", "1");
}
else if (format->diag_type == LXW_DIAGONAL_BORDER_DOWN) {
LXW_PUSH_ATTRIBUTES_STR("diagonalDown", "1");
}
else if (format->diag_type == LXW_DIAGONAL_BORDER_UP_DOWN) {
LXW_PUSH_ATTRIBUTES_STR("diagonalUp", "1");
LXW_PUSH_ATTRIBUTES_STR("diagonalDown", "1");
}
/* Ensure that a default diag border is set if the diag type is set. */
if (format->diag_type && !format->diag_border) {
format->diag_border = LXW_BORDER_THIN;
}
/* Write the start border tag. */
lxw_xml_start_tag(self->file, "border", &attributes);
/* Write the sub elements. */
_write_sub_border(self, "left", format->left, format->left_color);
_write_sub_border(self, "right", format->right, format->right_color);
_write_sub_border(self, "top", format->top, format->top_color);
_write_sub_border(self, "bottom", format->bottom, format->bottom_color);
if (is_dxf) {
_write_sub_border(self, "vertical", 0, LXW_COLOR_UNSET);
_write_sub_border(self, "horizontal", 0, LXW_COLOR_UNSET);
}
/* Conditional DXF formats don't allow diagonal borders. */
if (!is_dxf)
_write_sub_border(self, "diagonal",
format->diag_border, format->diag_color);
lxw_xml_end_tag(self->file, "border");
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_borders(lxw_styles *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
lxw_format *format;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_INT("count", self->border_count);
lxw_xml_start_tag(self->file, "borders", &attributes);
STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
if (format->has_border)
_write_border(self, format, LXW_FALSE);
}
lxw_xml_end_tag(self->file, "borders");
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element for hyperlinks.
*/
STATIC void
_write_hyperlink_alignment(lxw_styles *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("vertical", "top");
lxw_xml_empty_tag(self->file, "alignment", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element for hyperlinks.
*/
STATIC void
_write_hyperlink_protection(lxw_styles *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("locked", "0");
lxw_xml_empty_tag(self->file, "protection", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element for styles.
*/
STATIC void
_write_style_xf(lxw_styles *self, uint8_t has_hyperlink, uint16_t font_id)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("numFmtId", "0");
LXW_PUSH_ATTRIBUTES_INT("fontId", font_id);
LXW_PUSH_ATTRIBUTES_STR("fillId", "0");
LXW_PUSH_ATTRIBUTES_STR("borderId", "0");
if (has_hyperlink) {
LXW_PUSH_ATTRIBUTES_STR("applyNumberFormat", "0");
LXW_PUSH_ATTRIBUTES_STR("applyFill", "0");
LXW_PUSH_ATTRIBUTES_STR("applyBorder", "0");
LXW_PUSH_ATTRIBUTES_STR("applyAlignment", "0");
LXW_PUSH_ATTRIBUTES_STR("applyProtection", "0");
lxw_xml_start_tag(self->file, "xf", &attributes);
_write_hyperlink_alignment(self);
_write_hyperlink_protection(self);
lxw_xml_end_tag(self->file, "xf");
}
else {
lxw_xml_empty_tag(self->file, "xf", &attributes);
}
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_cell_style_xfs(lxw_styles *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
if (self->has_hyperlink)
LXW_PUSH_ATTRIBUTES_STR("count", "2");
else
LXW_PUSH_ATTRIBUTES_STR("count", "1");
lxw_xml_start_tag(self->file, "cellStyleXfs", &attributes);
_write_style_xf(self, LXW_FALSE, 0);
if (self->has_hyperlink)
_write_style_xf(self, self->has_hyperlink, self->hyperlink_font_id);
lxw_xml_end_tag(self->file, "cellStyleXfs");
LXW_FREE_ATTRIBUTES();
}
/*
* Check if a format struct has alignment properties set and the
* "applyAlignment" attribute should be set.
*/
STATIC uint8_t
_apply_alignment(lxw_format *format)
{
return format->text_h_align != LXW_ALIGN_NONE
|| format->text_v_align != LXW_ALIGN_NONE
|| format->indent != 0
|| format->rotation != 0
|| format->text_wrap != 0
|| format->shrink != 0 || format->reading_order != 0;
}
/*
* Check if a format struct has alignment properties set apart from the
* LXW_ALIGN_VERTICAL_BOTTOM which Excel treats as a default.
*/
STATIC uint8_t
_has_alignment(lxw_format *format)
{
return format->text_h_align != LXW_ALIGN_NONE
|| !(format->text_v_align == LXW_ALIGN_NONE ||
format->text_v_align == LXW_ALIGN_VERTICAL_BOTTOM)
|| format->indent != 0
|| format->rotation != 0
|| format->text_wrap != 0
|| format->shrink != 0 || format->reading_order != 0;
}
/*
* Write the element.
*/
STATIC void
_write_alignment(lxw_styles *self, lxw_format *format)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
int16_t rotation = format->rotation;
LXW_INIT_ATTRIBUTES();
/* Indent is only allowed for some alignment properties. */
/* If it is defined for any other alignment or no alignment has been */
/* set then default to left alignment. */
if (format->indent
&& format->text_h_align != LXW_ALIGN_LEFT
&& format->text_h_align != LXW_ALIGN_RIGHT
&& format->text_h_align != LXW_ALIGN_DISTRIBUTED
&& format->text_v_align != LXW_ALIGN_VERTICAL_TOP
&& format->text_v_align != LXW_ALIGN_VERTICAL_BOTTOM
&& format->text_v_align != LXW_ALIGN_VERTICAL_DISTRIBUTED) {
format->text_h_align = LXW_ALIGN_LEFT;
}
/* Check for properties that are mutually exclusive. */
if (format->text_wrap)
format->shrink = 0;
if (format->text_h_align == LXW_ALIGN_FILL)
format->shrink = 0;
if (format->text_h_align == LXW_ALIGN_JUSTIFY)
format->shrink = 0;
if (format->text_h_align == LXW_ALIGN_DISTRIBUTED)
format->shrink = 0;
if (format->text_h_align != LXW_ALIGN_DISTRIBUTED)
format->just_distrib = 0;
if (format->indent)
format->just_distrib = 0;
if (format->text_h_align == LXW_ALIGN_LEFT)
LXW_PUSH_ATTRIBUTES_STR("horizontal", "left");
if (format->text_h_align == LXW_ALIGN_CENTER)
LXW_PUSH_ATTRIBUTES_STR("horizontal", "center");
if (format->text_h_align == LXW_ALIGN_RIGHT)
LXW_PUSH_ATTRIBUTES_STR("horizontal", "right");
if (format->text_h_align == LXW_ALIGN_FILL)
LXW_PUSH_ATTRIBUTES_STR("horizontal", "fill");
if (format->text_h_align == LXW_ALIGN_JUSTIFY)
LXW_PUSH_ATTRIBUTES_STR("horizontal", "justify");
if (format->text_h_align == LXW_ALIGN_CENTER_ACROSS)
LXW_PUSH_ATTRIBUTES_STR("horizontal", "centerContinuous");
if (format->text_h_align == LXW_ALIGN_DISTRIBUTED)
LXW_PUSH_ATTRIBUTES_STR("horizontal", "distributed");
if (format->just_distrib)
LXW_PUSH_ATTRIBUTES_STR("justifyLastLine", "1");
if (format->text_v_align == LXW_ALIGN_VERTICAL_TOP)
LXW_PUSH_ATTRIBUTES_STR("vertical", "top");
if (format->text_v_align == LXW_ALIGN_VERTICAL_CENTER)
LXW_PUSH_ATTRIBUTES_STR("vertical", "center");
if (format->text_v_align == LXW_ALIGN_VERTICAL_JUSTIFY)
LXW_PUSH_ATTRIBUTES_STR("vertical", "justify");
if (format->text_v_align == LXW_ALIGN_VERTICAL_DISTRIBUTED)
LXW_PUSH_ATTRIBUTES_STR("vertical", "distributed");
/* Map rotation to Excel values. */
if (rotation) {
if (rotation == 270)
rotation = 255;
else if (rotation < 0)
rotation = -rotation + 90;
LXW_PUSH_ATTRIBUTES_INT("textRotation", rotation);
}
if (format->indent)
LXW_PUSH_ATTRIBUTES_INT("indent", format->indent);
if (format->text_wrap)
LXW_PUSH_ATTRIBUTES_STR("wrapText", "1");
if (format->shrink)
LXW_PUSH_ATTRIBUTES_STR("shrinkToFit", "1");
if (format->reading_order == 1)
LXW_PUSH_ATTRIBUTES_STR("readingOrder", "1");
if (format->reading_order == 2)
LXW_PUSH_ATTRIBUTES_STR("readingOrder", "2");
if (!STAILQ_EMPTY(&attributes))
lxw_xml_empty_tag(self->file, "alignment", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_protection(lxw_styles *self, lxw_format *format)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
if (!format->locked)
LXW_PUSH_ATTRIBUTES_STR("locked", "0");
if (format->hidden)
LXW_PUSH_ATTRIBUTES_STR("hidden", "1");
lxw_xml_empty_tag(self->file, "protection", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_xf(lxw_styles *self, lxw_format *format)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
uint8_t has_protection = (!format->locked) | format->hidden;
uint8_t has_alignment = _has_alignment(format);
uint8_t apply_alignment = _apply_alignment(format);
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_INT("numFmtId", format->num_format_index);
LXW_PUSH_ATTRIBUTES_INT("fontId", format->font_index);
LXW_PUSH_ATTRIBUTES_INT("fillId", format->fill_index);
LXW_PUSH_ATTRIBUTES_INT("borderId", format->border_index);
LXW_PUSH_ATTRIBUTES_INT("xfId", format->xf_id);
if (format->quote_prefix)
LXW_PUSH_ATTRIBUTES_STR("quotePrefix", "1");
if (format->num_format_index > 0)
LXW_PUSH_ATTRIBUTES_STR("applyNumberFormat", "1");
/* Add applyFont attribute if XF format uses a font element. */
if (format->font_index > 0 && !format->hyperlink)
LXW_PUSH_ATTRIBUTES_STR("applyFont", "1");
/* Add applyFill attribute if XF format uses a fill element. */
if (format->fill_index > 0)
LXW_PUSH_ATTRIBUTES_STR("applyFill", "1");
/* Add applyBorder attribute if XF format uses a border element. */
if (format->border_index > 0)
LXW_PUSH_ATTRIBUTES_STR("applyBorder", "1");
/* We can also have applyAlignment without a sub-element. */
if (apply_alignment || format->hyperlink)
LXW_PUSH_ATTRIBUTES_STR("applyAlignment", "1");
if (has_protection || format->hyperlink)
LXW_PUSH_ATTRIBUTES_STR("applyProtection", "1");
/* Write XF with sub-elements if required. */
if (has_alignment || has_protection) {
lxw_xml_start_tag(self->file, "xf", &attributes);
if (has_alignment)
_write_alignment(self, format);
if (has_protection)
_write_protection(self, format);
lxw_xml_end_tag(self->file, "xf");
}
else {
lxw_xml_empty_tag(self->file, "xf", &attributes);
}
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_cell_xfs(lxw_styles *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
lxw_format *format;
uint32_t count = self->xf_count;
uint32_t i = 0;
/* If the last format is "font_only" it is for the comment font and
* shouldn't be counted. This is a workaround to get the last object
* in the list since STAILQ_LAST() requires __containerof and isn't
* ANSI compatible. */
STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
i++;
if (i == self->xf_count && format->font_only)
count--;
}
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_INT("count", count);
lxw_xml_start_tag(self->file, "cellXfs", &attributes);
STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
if (!format->font_only)
_write_xf(self, format);
}
lxw_xml_end_tag(self->file, "cellXfs");
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_cell_style(lxw_styles *self, char *name, uint8_t xf_id,
uint8_t builtin_id)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("name", name);
LXW_PUSH_ATTRIBUTES_INT("xfId", xf_id);
LXW_PUSH_ATTRIBUTES_INT("builtinId", builtin_id);
lxw_xml_empty_tag(self->file, "cellStyle", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_cell_styles(lxw_styles *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
if (self->has_hyperlink)
LXW_PUSH_ATTRIBUTES_STR("count", "2");
else
LXW_PUSH_ATTRIBUTES_STR("count", "1");
lxw_xml_start_tag(self->file, "cellStyles", &attributes);
if (self->has_hyperlink)
_write_cell_style(self, "Hyperlink", 1, 8);
_write_cell_style(self, "Normal", 0, 0);
lxw_xml_end_tag(self->file, "cellStyles");
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*
*/
STATIC void
_write_dxfs(lxw_styles *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
lxw_format *format;
uint32_t count = self->dxf_count;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_INT("count", count);
if (count) {
lxw_xml_start_tag(self->file, "dxfs", &attributes);
STAILQ_FOREACH(format, self->dxf_formats, list_pointers) {
lxw_xml_start_tag(self->file, "dxf", NULL);
if (format->has_dxf_font)
_write_font(self, format, LXW_TRUE, LXW_FALSE);
if (format->num_format_index)
_write_num_fmt(self, format->num_format_index,
format->num_format);
if (format->has_dxf_fill)
_write_fill(self, format, LXW_TRUE);
if (format->has_dxf_border)
_write_border(self, format, LXW_TRUE);
lxw_xml_end_tag(self->file, "dxf");
}
lxw_xml_end_tag(self->file, "dxfs");
}
else {
lxw_xml_empty_tag(self->file, "dxfs", &attributes);
}
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_table_styles(lxw_styles *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("count", "0");
LXW_PUSH_ATTRIBUTES_STR("defaultTableStyle", "TableStyleMedium9");
LXW_PUSH_ATTRIBUTES_STR("defaultPivotStyle", "PivotStyleLight16");
lxw_xml_empty_tag(self->file, "tableStyles", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*****************************************************************************
*
* XML file assembly functions.
*
****************************************************************************/
/*
* Assemble and write the XML file.
*/
void
lxw_styles_assemble_xml_file(lxw_styles *self)
{
/* Write the XML declaration. */
_styles_xml_declaration(self);
/* Add the style sheet. */
_write_style_sheet(self);
/* Write the number formats. */
_write_num_fmts(self);
/* Write the fonts. */
_write_fonts(self);
/* Write the fills. */
_write_fills(self);
/* Write the borders element. */
_write_borders(self);
/* Write the cellStyleXfs element. */
_write_cell_style_xfs(self);
/* Write the cellXfs element. */
_write_cell_xfs(self);
/* Write the cellStyles element. */
_write_cell_styles(self);
/* Write the dxfs element. */
_write_dxfs(self);
/* Write the tableStyles element. */
_write_table_styles(self);
/* Close the style sheet tag. */
lxw_xml_end_tag(self->file, "styleSheet");
}
/*****************************************************************************
*
* Public functions.
*
****************************************************************************/
writexl/src/libxlsxwriter/worksheet.c 0000644 0001762 0000144 00001233260 14747162622 017662 0 ustar ligges users /*****************************************************************************
* worksheet - A library for creating Excel XLSX worksheet files.
*
* Used in conjunction with the libxlsxwriter library.
*
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
*
*/
#ifdef USE_FMEMOPEN
#define _POSIX_C_SOURCE 200809L
#endif
#include "xlsxwriter/xmlwriter.h"
#include "xlsxwriter/worksheet.h"
#include "xlsxwriter/format.h"
#include "xlsxwriter/utility.h"
#ifdef USE_OPENSSL_MD5
#include
#else
#ifndef USE_NO_MD5
#include "xlsxwriter/third_party/md5.h"
#endif
#endif
#define LXW_STR_MAX 32767
#define LXW_BUFFER_SIZE 4096
#define LXW_PRINT_ACROSS 1
#define LXW_VALIDATION_MAX_TITLE_LENGTH 32
#define LXW_VALIDATION_MAX_STRING_LENGTH 255
#define LXW_THIS_ROW "[#This Row],"
/*
* Forward declarations.
*/
STATIC void _worksheet_write_rows(lxw_worksheet *self);
STATIC int _row_cmp(lxw_row *row1, lxw_row *row2);
STATIC int _cell_cmp(lxw_cell *cell1, lxw_cell *cell2);
STATIC int _drawing_rel_id_cmp(lxw_drawing_rel_id *tuple1,
lxw_drawing_rel_id *tuple2);
STATIC int _cond_format_hash_cmp(lxw_cond_format_hash_element *elem_1,
lxw_cond_format_hash_element *elem_2);
#ifndef __clang_analyzer__
LXW_RB_GENERATE_ROW(lxw_table_rows, lxw_row, tree_pointers, _row_cmp);
LXW_RB_GENERATE_CELL(lxw_table_cells, lxw_cell, tree_pointers, _cell_cmp);
LXW_RB_GENERATE_DRAWING_REL_IDS(lxw_drawing_rel_ids, lxw_drawing_rel_id,
tree_pointers, _drawing_rel_id_cmp);
LXW_RB_GENERATE_VML_DRAWING_REL_IDS(lxw_vml_drawing_rel_ids,
lxw_drawing_rel_id, tree_pointers,
_drawing_rel_id_cmp);
LXW_RB_GENERATE_COND_FORMAT_HASH(lxw_cond_format_hash,
lxw_cond_format_hash_element, tree_pointers,
_cond_format_hash_cmp);
#endif
/*****************************************************************************
*
* Private functions.
*
****************************************************************************/
/*
* Find but don't create a row object for a given row number.
*/
lxw_row *
lxw_worksheet_find_row(lxw_worksheet *self, lxw_row_t row_num)
{
lxw_row tmp_row;
tmp_row.row_num = row_num;
return RB_FIND(lxw_table_rows, self->table, &tmp_row);
}
/*
* Find but don't create a cell object for a given row object and col number.
*/
lxw_cell *
lxw_worksheet_find_cell_in_row(lxw_row *row, lxw_col_t col_num)
{
lxw_cell tmp_cell;
if (!row)
return NULL;
tmp_cell.col_num = col_num;
return RB_FIND(lxw_table_cells, row->cells, &tmp_cell);
}
/*
* Create a new worksheet object.
*/
lxw_worksheet *
lxw_worksheet_new(lxw_worksheet_init_data *init_data)
{
lxw_worksheet *worksheet = calloc(1, sizeof(lxw_worksheet));
GOTO_LABEL_ON_MEM_ERROR(worksheet, mem_error);
worksheet->table = calloc(1, sizeof(struct lxw_table_rows));
GOTO_LABEL_ON_MEM_ERROR(worksheet->table, mem_error);
RB_INIT(worksheet->table);
worksheet->hyperlinks = calloc(1, sizeof(struct lxw_table_rows));
GOTO_LABEL_ON_MEM_ERROR(worksheet->hyperlinks, mem_error);
RB_INIT(worksheet->hyperlinks);
worksheet->comments = calloc(1, sizeof(struct lxw_table_rows));
GOTO_LABEL_ON_MEM_ERROR(worksheet->comments, mem_error);
RB_INIT(worksheet->comments);
/* Initialize the cached rows. */
worksheet->table->cached_row_num = LXW_ROW_MAX + 1;
worksheet->hyperlinks->cached_row_num = LXW_ROW_MAX + 1;
worksheet->comments->cached_row_num = LXW_ROW_MAX + 1;
if (init_data && init_data->optimize) {
worksheet->array = calloc(LXW_COL_MAX, sizeof(struct lxw_cell *));
GOTO_LABEL_ON_MEM_ERROR(worksheet->array, mem_error);
}
worksheet->col_options =
calloc(LXW_COL_META_MAX, sizeof(lxw_col_options *));
worksheet->col_options_max = LXW_COL_META_MAX;
GOTO_LABEL_ON_MEM_ERROR(worksheet->col_options, mem_error);
worksheet->col_formats = calloc(LXW_COL_META_MAX, sizeof(lxw_format *));
worksheet->col_formats_max = LXW_COL_META_MAX;
GOTO_LABEL_ON_MEM_ERROR(worksheet->col_formats, mem_error);
worksheet->optimize_row = calloc(1, sizeof(struct lxw_row));
GOTO_LABEL_ON_MEM_ERROR(worksheet->optimize_row, mem_error);
worksheet->optimize_row->height = LXW_DEF_ROW_HEIGHT;
worksheet->merged_ranges = calloc(1, sizeof(struct lxw_merged_ranges));
GOTO_LABEL_ON_MEM_ERROR(worksheet->merged_ranges, mem_error);
STAILQ_INIT(worksheet->merged_ranges);
worksheet->image_props = calloc(1, sizeof(struct lxw_image_props));
GOTO_LABEL_ON_MEM_ERROR(worksheet->image_props, mem_error);
STAILQ_INIT(worksheet->image_props);
worksheet->chart_data = calloc(1, sizeof(struct lxw_chart_props));
GOTO_LABEL_ON_MEM_ERROR(worksheet->chart_data, mem_error);
STAILQ_INIT(worksheet->chart_data);
worksheet->comment_objs = calloc(1, sizeof(struct lxw_comment_objs));
GOTO_LABEL_ON_MEM_ERROR(worksheet->comment_objs, mem_error);
STAILQ_INIT(worksheet->comment_objs);
worksheet->header_image_objs = calloc(1, sizeof(struct lxw_comment_objs));
GOTO_LABEL_ON_MEM_ERROR(worksheet->header_image_objs, mem_error);
STAILQ_INIT(worksheet->header_image_objs);
worksheet->button_objs = calloc(1, sizeof(struct lxw_comment_objs));
GOTO_LABEL_ON_MEM_ERROR(worksheet->button_objs, mem_error);
STAILQ_INIT(worksheet->button_objs);
worksheet->selections = calloc(1, sizeof(struct lxw_selections));
GOTO_LABEL_ON_MEM_ERROR(worksheet->selections, mem_error);
STAILQ_INIT(worksheet->selections);
worksheet->data_validations =
calloc(1, sizeof(struct lxw_data_validations));
GOTO_LABEL_ON_MEM_ERROR(worksheet->data_validations, mem_error);
STAILQ_INIT(worksheet->data_validations);
worksheet->table_objs = calloc(1, sizeof(struct lxw_table_objs));
GOTO_LABEL_ON_MEM_ERROR(worksheet->table_objs, mem_error);
STAILQ_INIT(worksheet->table_objs);
worksheet->external_hyperlinks = calloc(1, sizeof(struct lxw_rel_tuples));
GOTO_LABEL_ON_MEM_ERROR(worksheet->external_hyperlinks, mem_error);
STAILQ_INIT(worksheet->external_hyperlinks);
worksheet->external_drawing_links =
calloc(1, sizeof(struct lxw_rel_tuples));
GOTO_LABEL_ON_MEM_ERROR(worksheet->external_drawing_links, mem_error);
STAILQ_INIT(worksheet->external_drawing_links);
worksheet->drawing_links = calloc(1, sizeof(struct lxw_rel_tuples));
GOTO_LABEL_ON_MEM_ERROR(worksheet->drawing_links, mem_error);
STAILQ_INIT(worksheet->drawing_links);
worksheet->vml_drawing_links = calloc(1, sizeof(struct lxw_rel_tuples));
GOTO_LABEL_ON_MEM_ERROR(worksheet->vml_drawing_links, mem_error);
STAILQ_INIT(worksheet->vml_drawing_links);
worksheet->external_table_links =
calloc(1, sizeof(struct lxw_rel_tuples));
GOTO_LABEL_ON_MEM_ERROR(worksheet->external_table_links, mem_error);
STAILQ_INIT(worksheet->external_table_links);
if (init_data && init_data->optimize) {
FILE *tmpfile;
worksheet->optimize_buffer = NULL;
worksheet->optimize_buffer_size = 0;
tmpfile = lxw_get_filehandle(&worksheet->optimize_buffer,
&worksheet->optimize_buffer_size,
init_data->tmpdir);
if (!tmpfile) {
LXW_ERROR("Error creating tmpfile() for worksheet in "
"'constant_memory' mode.");
goto mem_error;
}
worksheet->optimize_tmpfile = tmpfile;
GOTO_LABEL_ON_MEM_ERROR(worksheet->optimize_tmpfile, mem_error);
worksheet->file = worksheet->optimize_tmpfile;
}
worksheet->drawing_rel_ids =
calloc(1, sizeof(struct lxw_drawing_rel_ids));
GOTO_LABEL_ON_MEM_ERROR(worksheet->drawing_rel_ids, mem_error);
RB_INIT(worksheet->drawing_rel_ids);
worksheet->vml_drawing_rel_ids =
calloc(1, sizeof(struct lxw_vml_drawing_rel_ids));
GOTO_LABEL_ON_MEM_ERROR(worksheet->vml_drawing_rel_ids, mem_error);
RB_INIT(worksheet->vml_drawing_rel_ids);
worksheet->conditional_formats =
calloc(1, sizeof(struct lxw_cond_format_hash));
GOTO_LABEL_ON_MEM_ERROR(worksheet->conditional_formats, mem_error);
RB_INIT(worksheet->conditional_formats);
/* Initialize the worksheet dimensions. */
worksheet->dim_rowmax = 0;
worksheet->dim_colmax = 0;
worksheet->dim_rowmin = LXW_ROW_MAX;
worksheet->dim_colmin = LXW_COL_MAX;
worksheet->default_row_height = LXW_DEF_ROW_HEIGHT;
worksheet->default_row_pixels = 20;
worksheet->default_col_pixels = 64;
/* Initialize the page setup properties. */
worksheet->fit_height = 0;
worksheet->fit_width = 0;
worksheet->page_start = 0;
worksheet->print_scale = 100;
worksheet->fit_page = 0;
worksheet->orientation = LXW_TRUE;
worksheet->page_order = 0;
worksheet->page_setup_changed = LXW_FALSE;
worksheet->page_view = LXW_FALSE;
worksheet->paper_size = 0;
worksheet->vertical_dpi = 0;
worksheet->horizontal_dpi = 0;
worksheet->margin_left = 0.7;
worksheet->margin_right = 0.7;
worksheet->margin_top = 0.75;
worksheet->margin_bottom = 0.75;
worksheet->margin_header = 0.3;
worksheet->margin_footer = 0.3;
worksheet->print_gridlines = 0;
worksheet->screen_gridlines = 1;
worksheet->print_options_changed = 0;
worksheet->zoom = 100;
worksheet->zoom_scale_normal = LXW_TRUE;
worksheet->show_zeros = LXW_TRUE;
worksheet->outline_on = LXW_TRUE;
worksheet->outline_style = LXW_TRUE;
worksheet->outline_below = LXW_TRUE;
worksheet->outline_right = LXW_FALSE;
worksheet->tab_color = LXW_COLOR_UNSET;
worksheet->max_url_length = 2079;
worksheet->comment_display_default = LXW_COMMENT_DISPLAY_HIDDEN;
worksheet->header_footer_objs[0] = &worksheet->header_left_object_props;
worksheet->header_footer_objs[1] = &worksheet->header_center_object_props;
worksheet->header_footer_objs[2] = &worksheet->header_right_object_props;
worksheet->header_footer_objs[3] = &worksheet->footer_left_object_props;
worksheet->header_footer_objs[4] = &worksheet->footer_center_object_props;
worksheet->header_footer_objs[5] = &worksheet->footer_right_object_props;
if (init_data) {
worksheet->name = init_data->name;
worksheet->quoted_name = init_data->quoted_name;
worksheet->tmpdir = init_data->tmpdir;
worksheet->index = init_data->index;
worksheet->hidden = init_data->hidden;
worksheet->sst = init_data->sst;
worksheet->optimize = init_data->optimize;
worksheet->active_sheet = init_data->active_sheet;
worksheet->first_sheet = init_data->first_sheet;
worksheet->default_url_format = init_data->default_url_format;
worksheet->max_url_length = init_data->max_url_length;
}
return worksheet;
mem_error:
lxw_worksheet_free(worksheet);
return NULL;
}
/*
* Free vml object.
*/
STATIC void
_free_vml_object(lxw_vml_obj *vml_obj)
{
if (!vml_obj)
return;
free(vml_obj->author);
free(vml_obj->font_name);
free(vml_obj->text);
free(vml_obj->image_position);
free(vml_obj->name);
free(vml_obj->macro);
free(vml_obj);
}
/*
* Free autofilter rule object.
*/
STATIC void
_free_filter_rule(lxw_filter_rule_obj *rule_obj)
{
uint16_t i;
if (!rule_obj)
return;
free(rule_obj->value1_string);
free(rule_obj->value2_string);
if (rule_obj->list) {
for (i = 0; i < rule_obj->num_list_filters; i++)
free(rule_obj->list[i]);
free(rule_obj->list);
}
free(rule_obj);
}
/*
* Free autofilter rules.
*/
STATIC void
_free_filter_rules(lxw_worksheet *worksheet)
{
uint16_t i;
if (!worksheet->filter_rules)
return;
for (i = 0; i < worksheet->num_filter_rules; i++)
_free_filter_rule(worksheet->filter_rules[i]);
free(worksheet->filter_rules);
}
/*
* Free a worksheet cell.
*/
STATIC void
_free_cell(lxw_cell *cell)
{
if (!cell)
return;
if (cell->type != NUMBER_CELL && cell->type != STRING_CELL
&& cell->type != BLANK_CELL && cell->type != BOOLEAN_CELL) {
free((void *) cell->u.string);
}
free(cell->user_data1);
free(cell->user_data2);
_free_vml_object(cell->comment);
free(cell);
}
/*
* Free a worksheet row.
*/
STATIC void
_free_row(lxw_row *row)
{
lxw_cell *cell;
lxw_cell *next_cell;
if (!row)
return;
for (cell = RB_MIN(lxw_table_cells, row->cells); cell; cell = next_cell) {
next_cell = RB_NEXT(lxw_table_cells, row->cells, cell);
RB_REMOVE(lxw_table_cells, row->cells, cell);
_free_cell(cell);
}
free(row->cells);
free(row);
}
/*
* Free a worksheet image_options.
*/
STATIC void
_free_object_properties(lxw_object_properties *object_property)
{
if (!object_property)
return;
free(object_property->filename);
free(object_property->description);
free(object_property->extension);
free(object_property->url);
free(object_property->tip);
free(object_property->image_buffer);
free(object_property->md5);
free(object_property->image_position);
free(object_property);
object_property = NULL;
}
/*
* Free a worksheet data_validation.
*/
STATIC void
_free_data_validation(lxw_data_val_obj *data_validation)
{
if (!data_validation)
return;
free(data_validation->value_formula);
free(data_validation->maximum_formula);
free(data_validation->input_title);
free(data_validation->input_message);
free(data_validation->error_title);
free(data_validation->error_message);
free(data_validation->minimum_formula);
free(data_validation);
}
/*
* Free a worksheet conditional format obj.
*/
STATIC void
_free_cond_format(lxw_cond_format_obj *cond_format)
{
if (!cond_format)
return;
free(cond_format->min_value_string);
free(cond_format->mid_value_string);
free(cond_format->max_value_string);
free(cond_format->type_string);
free(cond_format->guid);
free(cond_format);
}
/*
* Free a relationship structure.
*/
STATIC void
_free_relationship(lxw_rel_tuple *relationship)
{
if (!relationship)
return;
free(relationship->type);
free(relationship->target);
free(relationship->target_mode);
free(relationship);
}
/*
* Free a worksheet table column object.
*/
STATIC void
_free_worksheet_table_column(lxw_table_column *column)
{
if (!column)
return;
free((void *) column->header);
free((void *) column->formula);
free((void *) column->total_string);
free(column);
}
/*
* Free a worksheet table object.
*/
STATIC void
_free_worksheet_table(lxw_table_obj *table)
{
uint16_t i;
if (!table)
return;
for (i = 0; i < table->num_cols; i++)
_free_worksheet_table_column(table->columns[i]);
free(table->name);
free(table->total_string);
free(table->columns);
free(table);
}
/*
* Free a worksheet object.
*/
void
lxw_worksheet_free(lxw_worksheet *worksheet)
{
lxw_row *row;
lxw_row *next_row;
lxw_col_t col;
lxw_merged_range *merged_range;
lxw_object_properties *object_props;
lxw_vml_obj *vml_obj;
lxw_selection *selection;
lxw_data_val_obj *data_validation;
lxw_rel_tuple *relationship;
lxw_cond_format_obj *cond_format;
lxw_table_obj *table_obj;
struct lxw_drawing_rel_id *drawing_rel_id;
struct lxw_drawing_rel_id *next_drawing_rel_id;
struct lxw_cond_format_hash_element *cond_format_elem;
struct lxw_cond_format_hash_element *next_cond_format_elem;
if (!worksheet)
return;
if (worksheet->col_options) {
for (col = 0; col < worksheet->col_options_max; col++) {
if (worksheet->col_options[col])
free(worksheet->col_options[col]);
}
}
free(worksheet->col_options);
free(worksheet->col_sizes);
free(worksheet->col_formats);
if (worksheet->table) {
for (row = RB_MIN(lxw_table_rows, worksheet->table); row;
row = next_row) {
next_row = RB_NEXT(lxw_table_rows, worksheet->table, row);
RB_REMOVE(lxw_table_rows, worksheet->table, row);
_free_row(row);
}
free(worksheet->table);
}
if (worksheet->hyperlinks) {
for (row = RB_MIN(lxw_table_rows, worksheet->hyperlinks); row;
row = next_row) {
next_row = RB_NEXT(lxw_table_rows, worksheet->hyperlinks, row);
RB_REMOVE(lxw_table_rows, worksheet->hyperlinks, row);
_free_row(row);
}
free(worksheet->hyperlinks);
}
if (worksheet->comments) {
for (row = RB_MIN(lxw_table_rows, worksheet->comments); row;
row = next_row) {
next_row = RB_NEXT(lxw_table_rows, worksheet->comments, row);
RB_REMOVE(lxw_table_rows, worksheet->comments, row);
_free_row(row);
}
free(worksheet->comments);
}
if (worksheet->merged_ranges) {
while (!STAILQ_EMPTY(worksheet->merged_ranges)) {
merged_range = STAILQ_FIRST(worksheet->merged_ranges);
STAILQ_REMOVE_HEAD(worksheet->merged_ranges, list_pointers);
free(merged_range);
}
free(worksheet->merged_ranges);
}
if (worksheet->image_props) {
while (!STAILQ_EMPTY(worksheet->image_props)) {
object_props = STAILQ_FIRST(worksheet->image_props);
STAILQ_REMOVE_HEAD(worksheet->image_props, list_pointers);
_free_object_properties(object_props);
}
free(worksheet->image_props);
}
if (worksheet->chart_data) {
while (!STAILQ_EMPTY(worksheet->chart_data)) {
object_props = STAILQ_FIRST(worksheet->chart_data);
STAILQ_REMOVE_HEAD(worksheet->chart_data, list_pointers);
_free_object_properties(object_props);
}
free(worksheet->chart_data);
}
/* Just free the list. The list objects are freed from the RB tree. */
free(worksheet->comment_objs);
if (worksheet->header_image_objs) {
while (!STAILQ_EMPTY(worksheet->header_image_objs)) {
vml_obj = STAILQ_FIRST(worksheet->header_image_objs);
STAILQ_REMOVE_HEAD(worksheet->header_image_objs, list_pointers);
_free_vml_object(vml_obj);
}
free(worksheet->header_image_objs);
}
if (worksheet->button_objs) {
while (!STAILQ_EMPTY(worksheet->button_objs)) {
vml_obj = STAILQ_FIRST(worksheet->button_objs);
STAILQ_REMOVE_HEAD(worksheet->button_objs, list_pointers);
_free_vml_object(vml_obj);
}
free(worksheet->button_objs);
}
if (worksheet->selections) {
while (!STAILQ_EMPTY(worksheet->selections)) {
selection = STAILQ_FIRST(worksheet->selections);
STAILQ_REMOVE_HEAD(worksheet->selections, list_pointers);
free(selection);
}
free(worksheet->selections);
}
if (worksheet->table_objs) {
while (!STAILQ_EMPTY(worksheet->table_objs)) {
table_obj = STAILQ_FIRST(worksheet->table_objs);
STAILQ_REMOVE_HEAD(worksheet->table_objs, list_pointers);
_free_worksheet_table(table_obj);
}
free(worksheet->table_objs);
}
if (worksheet->data_validations) {
while (!STAILQ_EMPTY(worksheet->data_validations)) {
data_validation = STAILQ_FIRST(worksheet->data_validations);
STAILQ_REMOVE_HEAD(worksheet->data_validations, list_pointers);
_free_data_validation(data_validation);
}
free(worksheet->data_validations);
}
while (!STAILQ_EMPTY(worksheet->external_hyperlinks)) {
relationship = STAILQ_FIRST(worksheet->external_hyperlinks);
STAILQ_REMOVE_HEAD(worksheet->external_hyperlinks, list_pointers);
_free_relationship(relationship);
}
free(worksheet->external_hyperlinks);
while (!STAILQ_EMPTY(worksheet->external_drawing_links)) {
relationship = STAILQ_FIRST(worksheet->external_drawing_links);
STAILQ_REMOVE_HEAD(worksheet->external_drawing_links, list_pointers);
_free_relationship(relationship);
}
free(worksheet->external_drawing_links);
while (!STAILQ_EMPTY(worksheet->drawing_links)) {
relationship = STAILQ_FIRST(worksheet->drawing_links);
STAILQ_REMOVE_HEAD(worksheet->drawing_links, list_pointers);
_free_relationship(relationship);
}
free(worksheet->drawing_links);
while (!STAILQ_EMPTY(worksheet->vml_drawing_links)) {
relationship = STAILQ_FIRST(worksheet->vml_drawing_links);
STAILQ_REMOVE_HEAD(worksheet->vml_drawing_links, list_pointers);
_free_relationship(relationship);
}
free(worksheet->vml_drawing_links);
while (!STAILQ_EMPTY(worksheet->external_table_links)) {
relationship = STAILQ_FIRST(worksheet->external_table_links);
STAILQ_REMOVE_HEAD(worksheet->external_table_links, list_pointers);
_free_relationship(relationship);
}
free(worksheet->external_table_links);
if (worksheet->drawing_rel_ids) {
for (drawing_rel_id =
RB_MIN(lxw_drawing_rel_ids, worksheet->drawing_rel_ids);
drawing_rel_id; drawing_rel_id = next_drawing_rel_id) {
next_drawing_rel_id =
RB_NEXT(lxw_drawing_rel_ids, worksheet->drawing_rel_id,
drawing_rel_id);
RB_REMOVE(lxw_drawing_rel_ids, worksheet->drawing_rel_ids,
drawing_rel_id);
free(drawing_rel_id->target);
free(drawing_rel_id);
}
free(worksheet->drawing_rel_ids);
}
if (worksheet->vml_drawing_rel_ids) {
for (drawing_rel_id =
RB_MIN(lxw_vml_drawing_rel_ids, worksheet->vml_drawing_rel_ids);
drawing_rel_id; drawing_rel_id = next_drawing_rel_id) {
next_drawing_rel_id =
RB_NEXT(lxw_vml_drawing_rel_ids, worksheet->drawing_rel_id,
drawing_rel_id);
RB_REMOVE(lxw_vml_drawing_rel_ids, worksheet->vml_drawing_rel_ids,
drawing_rel_id);
free(drawing_rel_id->target);
free(drawing_rel_id);
}
free(worksheet->vml_drawing_rel_ids);
}
if (worksheet->conditional_formats) {
for (cond_format_elem =
RB_MIN(lxw_cond_format_hash, worksheet->conditional_formats);
cond_format_elem; cond_format_elem = next_cond_format_elem) {
next_cond_format_elem = RB_NEXT(lxw_cond_format_hash,
worksheet->conditional_formats,
cond_format_elem);
RB_REMOVE(lxw_cond_format_hash,
worksheet->conditional_formats, cond_format_elem);
while (!STAILQ_EMPTY(cond_format_elem->cond_formats)) {
cond_format = STAILQ_FIRST(cond_format_elem->cond_formats);
STAILQ_REMOVE_HEAD(cond_format_elem->cond_formats,
list_pointers);
_free_cond_format(cond_format);
}
free(cond_format_elem->cond_formats);
free(cond_format_elem);
}
free(worksheet->conditional_formats);
}
_free_relationship(worksheet->external_vml_comment_link);
_free_relationship(worksheet->external_comment_link);
_free_relationship(worksheet->external_vml_header_link);
_free_relationship(worksheet->external_background_link);
_free_filter_rules(worksheet);
if (worksheet->array) {
for (col = 0; col < LXW_COL_MAX; col++) {
_free_cell(worksheet->array[col]);
}
free(worksheet->array);
}
if (worksheet->optimize_row)
free(worksheet->optimize_row);
if (worksheet->drawing)
lxw_drawing_free(worksheet->drawing);
free(worksheet->hbreaks);
free(worksheet->vbreaks);
free((void *) worksheet->name);
free((void *) worksheet->quoted_name);
free(worksheet->vba_codename);
free(worksheet->vml_data_id_str);
free(worksheet->vml_header_id_str);
free(worksheet->comment_author);
free(worksheet->ignore_number_stored_as_text);
free(worksheet->ignore_eval_error);
free(worksheet->ignore_formula_differs);
free(worksheet->ignore_formula_range);
free(worksheet->ignore_formula_unlocked);
free(worksheet->ignore_empty_cell_reference);
free(worksheet->ignore_list_data_validation);
free(worksheet->ignore_calculated_column);
free(worksheet->ignore_two_digit_text_year);
free(worksheet->header);
free(worksheet->footer);
free(worksheet);
worksheet = NULL;
}
/*
* Create a new worksheet row object.
*/
STATIC lxw_row *
_new_row(lxw_row_t row_num)
{
lxw_row *row = calloc(1, sizeof(lxw_row));
if (row) {
row->row_num = row_num;
row->cells = calloc(1, sizeof(struct lxw_table_cells));
row->height = LXW_DEF_ROW_HEIGHT;
if (row->cells)
RB_INIT(row->cells);
else
LXW_MEM_ERROR();
}
else {
LXW_MEM_ERROR();
}
return row;
}
/*
* Create a new worksheet number cell object.
*/
STATIC lxw_cell *
_new_number_cell(lxw_row_t row_num,
lxw_col_t col_num, double value, lxw_format *format)
{
lxw_cell *cell = calloc(1, sizeof(lxw_cell));
RETURN_ON_MEM_ERROR(cell, cell);
cell->row_num = row_num;
cell->col_num = col_num;
cell->type = NUMBER_CELL;
cell->format = format;
cell->u.number = value;
return cell;
}
/*
* Create a new worksheet string cell object.
*/
STATIC lxw_cell *
_new_string_cell(lxw_row_t row_num,
lxw_col_t col_num, int32_t string_id, char *sst_string,
lxw_format *format)
{
lxw_cell *cell = calloc(1, sizeof(lxw_cell));
RETURN_ON_MEM_ERROR(cell, cell);
cell->row_num = row_num;
cell->col_num = col_num;
cell->type = STRING_CELL;
cell->format = format;
cell->u.string_id = string_id;
cell->sst_string = sst_string;
return cell;
}
/*
* Create a new worksheet inline_string cell object.
*/
STATIC lxw_cell *
_new_inline_string_cell(lxw_row_t row_num,
lxw_col_t col_num, char *string, lxw_format *format)
{
lxw_cell *cell = calloc(1, sizeof(lxw_cell));
RETURN_ON_MEM_ERROR(cell, cell);
cell->row_num = row_num;
cell->col_num = col_num;
cell->type = INLINE_STRING_CELL;
cell->format = format;
cell->u.string = string;
return cell;
}
/*
* Create a new worksheet inline_string cell object for rich strings.
*/
STATIC lxw_cell *
_new_inline_rich_string_cell(lxw_row_t row_num,
lxw_col_t col_num, const char *string,
lxw_format *format)
{
lxw_cell *cell = calloc(1, sizeof(lxw_cell));
RETURN_ON_MEM_ERROR(cell, cell);
cell->row_num = row_num;
cell->col_num = col_num;
cell->type = INLINE_RICH_STRING_CELL;
cell->format = format;
cell->u.string = string;
return cell;
}
/*
* Create a new worksheet formula cell object.
*/
STATIC lxw_cell *
_new_formula_cell(lxw_row_t row_num,
lxw_col_t col_num, char *formula, lxw_format *format)
{
lxw_cell *cell = calloc(1, sizeof(lxw_cell));
RETURN_ON_MEM_ERROR(cell, cell);
cell->row_num = row_num;
cell->col_num = col_num;
cell->type = FORMULA_CELL;
cell->format = format;
cell->u.string = formula;
return cell;
}
/*
* Create a new worksheet array formula cell object.
*/
STATIC lxw_cell *
_new_array_formula_cell(lxw_row_t row_num, lxw_col_t col_num, char *formula,
char *range, lxw_format *format, uint8_t is_dynamic)
{
lxw_cell *cell = calloc(1, sizeof(lxw_cell));
RETURN_ON_MEM_ERROR(cell, cell);
cell->row_num = row_num;
cell->col_num = col_num;
cell->format = format;
cell->u.string = formula;
cell->user_data1 = range;
if (is_dynamic)
cell->type = DYNAMIC_ARRAY_FORMULA_CELL;
else
cell->type = ARRAY_FORMULA_CELL;
return cell;
}
/*
* Create a new worksheet blank cell object.
*/
STATIC lxw_cell *
_new_blank_cell(lxw_row_t row_num, lxw_col_t col_num, lxw_format *format)
{
lxw_cell *cell = calloc(1, sizeof(lxw_cell));
RETURN_ON_MEM_ERROR(cell, cell);
cell->row_num = row_num;
cell->col_num = col_num;
cell->type = BLANK_CELL;
cell->format = format;
return cell;
}
/*
* Create a new worksheet boolean cell object.
*/
STATIC lxw_cell *
_new_boolean_cell(lxw_row_t row_num, lxw_col_t col_num, int value,
lxw_format *format)
{
lxw_cell *cell = calloc(1, sizeof(lxw_cell));
RETURN_ON_MEM_ERROR(cell, cell);
cell->row_num = row_num;
cell->col_num = col_num;
cell->type = BOOLEAN_CELL;
cell->format = format;
cell->u.number = value;
return cell;
}
/*
* Create a new comment cell object.
*/
STATIC lxw_cell *
_new_comment_cell(lxw_row_t row_num, lxw_col_t col_num,
lxw_vml_obj *comment_obj)
{
lxw_cell *cell = calloc(1, sizeof(lxw_cell));
RETURN_ON_MEM_ERROR(cell, cell);
cell->row_num = row_num;
cell->col_num = col_num;
cell->type = COMMENT;
cell->comment = comment_obj;
return cell;
}
/*
* Create a new worksheet hyperlink cell object.
*/
STATIC lxw_cell *
_new_hyperlink_cell(lxw_row_t row_num, lxw_col_t col_num,
enum cell_types link_type, char *url, char *string,
char *tooltip)
{
lxw_cell *cell = calloc(1, sizeof(lxw_cell));
RETURN_ON_MEM_ERROR(cell, cell);
cell->row_num = row_num;
cell->col_num = col_num;
cell->type = link_type;
cell->u.string = url;
cell->user_data1 = string;
cell->user_data2 = tooltip;
return cell;
}
/*
* Get or create the row object for a given row number.
*/
STATIC lxw_row *
_get_row_list(struct lxw_table_rows *table, lxw_row_t row_num)
{
lxw_row *row;
lxw_row *existing_row;
if (table->cached_row_num == row_num)
return table->cached_row;
/* Create a new row and try and insert it. */
row = _new_row(row_num);
existing_row = RB_INSERT(lxw_table_rows, table, row);
/* If existing_row is not NULL, then it already existed. Free new row */
/* and return existing_row. */
if (existing_row) {
_free_row(row);
row = existing_row;
}
table->cached_row = row;
table->cached_row_num = row_num;
return row;
}
/*
* Get or create the row object for a given row number.
*/
STATIC lxw_row *
_get_row(lxw_worksheet *self, lxw_row_t row_num)
{
lxw_row *row;
if (!self->optimize) {
row = _get_row_list(self->table, row_num);
return row;
}
else {
if (row_num < self->optimize_row->row_num) {
return NULL;
}
else if (row_num == self->optimize_row->row_num) {
return self->optimize_row;
}
else {
/* Flush row. */
lxw_worksheet_write_single_row(self);
row = self->optimize_row;
row->row_num = row_num;
return row;
}
}
}
/*
* Insert a cell object in the cell list of a row object.
*/
STATIC void
_insert_cell_list(struct lxw_table_cells *cell_list,
lxw_cell *cell, lxw_col_t col_num)
{
lxw_cell *existing_cell;
cell->col_num = col_num;
existing_cell = RB_INSERT(lxw_table_cells, cell_list, cell);
/* If existing_cell is not NULL, then that cell already existed. */
/* Remove existing_cell and add new one in again. */
if (existing_cell) {
RB_REMOVE(lxw_table_cells, cell_list, existing_cell);
/* Add it in again. */
RB_INSERT(lxw_table_cells, cell_list, cell);
_free_cell(existing_cell);
}
return;
}
/*
* Insert a cell object into the cell list or array.
*/
STATIC void
_insert_cell(lxw_worksheet *self, lxw_row_t row_num, lxw_col_t col_num,
lxw_cell *cell)
{
lxw_row *row = _get_row(self, row_num);
if (!self->optimize) {
row->data_changed = LXW_TRUE;
_insert_cell_list(row->cells, cell, col_num);
}
else {
if (row) {
row->data_changed = LXW_TRUE;
/* Overwrite an existing cell if necessary. */
if (self->array[col_num])
_free_cell(self->array[col_num]);
self->array[col_num] = cell;
}
}
}
/*
* Insert a blank placeholder cell in the cells RB tree in the same position
* as a comment so that the rows "spans" calculation is correct. Since the
* blank cell doesn't have a format it is ignored when writing. If there is
* already a cell in the required position we don't have add a new cell.
*/
STATIC void
_insert_cell_placeholder(lxw_worksheet *self, lxw_row_t row_num,
lxw_col_t col_num)
{
lxw_row *row;
lxw_cell *cell;
/* The spans calculation isn't required in constant_memory mode. */
if (self->optimize)
return;
cell = _new_blank_cell(row_num, col_num, NULL);
if (!cell)
return;
/* Only add a cell if one doesn't already exist. */
row = _get_row(self, row_num);
if (!RB_FIND(lxw_table_cells, row->cells, cell)) {
_insert_cell_list(row->cells, cell, col_num);
}
else {
_free_cell(cell);
}
}
/*
* Insert a hyperlink object into the hyperlink RB tree.
*/
STATIC void
_insert_hyperlink(lxw_worksheet *self, lxw_row_t row_num, lxw_col_t col_num,
lxw_cell *link)
{
lxw_row *row = _get_row_list(self->hyperlinks, row_num);
_insert_cell_list(row->cells, link, col_num);
}
/*
* Insert a comment into the comment RB tree.
*/
STATIC void
_insert_comment(lxw_worksheet *self, lxw_row_t row_num, lxw_col_t col_num,
lxw_cell *link)
{
lxw_row *row = _get_row_list(self->comments, row_num);
_insert_cell_list(row->cells, link, col_num);
}
/*
* Next power of two for column reallocs. Taken from bithacks in the public
* domain.
*/
STATIC lxw_col_t
_next_power_of_two(uint16_t col)
{
col--;
col |= col >> 1;
col |= col >> 2;
col |= col >> 4;
col |= col >> 8;
col++;
return col;
}
/*
* Check that row and col are within the allowed Excel range and store max
* and min values for use in other methods/elements.
*
* The ignore_row/ignore_col flags are used to indicate that we wish to
* perform the dimension check without storing the value.
*/
STATIC lxw_error
_check_dimensions(lxw_worksheet *self,
lxw_row_t row_num,
lxw_col_t col_num, int8_t ignore_row, int8_t ignore_col)
{
if (row_num >= LXW_ROW_MAX)
return LXW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE;
if (col_num >= LXW_COL_MAX)
return LXW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE;
/* In optimization mode we don't change dimensions for rows that are */
/* already written. */
if (!ignore_row && !ignore_col && self->optimize) {
if (row_num < self->optimize_row->row_num)
return LXW_ERROR_WORKSHEET_INDEX_OUT_OF_RANGE;
}
if (!ignore_row) {
if (row_num < self->dim_rowmin)
self->dim_rowmin = row_num;
if (row_num > self->dim_rowmax)
self->dim_rowmax = row_num;
}
if (!ignore_col) {
if (col_num < self->dim_colmin)
self->dim_colmin = col_num;
if (col_num > self->dim_colmax)
self->dim_colmax = col_num;
}
return LXW_NO_ERROR;
}
/*
* Comparator for the row structure red/black tree.
*/
STATIC int
_row_cmp(lxw_row *row1, lxw_row *row2)
{
if (row1->row_num > row2->row_num)
return 1;
if (row1->row_num < row2->row_num)
return -1;
return 0;
}
/*
* Comparator for the cell structure red/black tree.
*/
STATIC int
_cell_cmp(lxw_cell *cell1, lxw_cell *cell2)
{
if (cell1->col_num > cell2->col_num)
return 1;
if (cell1->col_num < cell2->col_num)
return -1;
return 0;
}
/*
* Comparator for the image/hyperlink relationship ids.
*/
STATIC int
_drawing_rel_id_cmp(lxw_drawing_rel_id *rel_id1, lxw_drawing_rel_id *rel_id2)
{
return strcmp(rel_id1->target, rel_id2->target);
}
/*
* Comparator for the conditional format RB hash elements.
*/
STATIC int
_cond_format_hash_cmp(lxw_cond_format_hash_element *elem_1,
lxw_cond_format_hash_element *elem_2)
{
return strcmp(elem_1->sqref, elem_2->sqref);
}
/*
* Get the index used to address a drawing rel link.
*/
STATIC uint32_t
_get_drawing_rel_index(lxw_worksheet *self, char *target)
{
lxw_drawing_rel_id tmp_drawing_rel_id;
lxw_drawing_rel_id *found_duplicate_target = NULL;
lxw_drawing_rel_id *new_drawing_rel_id = NULL;
if (target) {
tmp_drawing_rel_id.target = target;
found_duplicate_target = RB_FIND(lxw_drawing_rel_ids,
self->drawing_rel_ids,
&tmp_drawing_rel_id);
}
if (found_duplicate_target) {
return found_duplicate_target->id;
}
else {
self->drawing_rel_id++;
if (target) {
new_drawing_rel_id = calloc(1, sizeof(lxw_drawing_rel_id));
if (new_drawing_rel_id) {
new_drawing_rel_id->id = self->drawing_rel_id;
new_drawing_rel_id->target = lxw_strdup(target);
RB_INSERT(lxw_drawing_rel_ids, self->drawing_rel_ids,
new_drawing_rel_id);
}
}
return self->drawing_rel_id;
}
}
/*
* find the index used to address a drawing rel link.
*/
STATIC uint32_t
_find_drawing_rel_index(lxw_worksheet *self, char *target)
{
lxw_drawing_rel_id tmp_drawing_rel_id;
lxw_drawing_rel_id *found_duplicate_target = NULL;
if (!target)
return 0;
tmp_drawing_rel_id.target = target;
found_duplicate_target = RB_FIND(lxw_drawing_rel_ids,
self->drawing_rel_ids,
&tmp_drawing_rel_id);
if (found_duplicate_target)
return found_duplicate_target->id;
else
return 0;
}
/*
* Get the index used to address a VMLdrawing rel link.
*/
STATIC uint32_t
_get_vml_drawing_rel_index(lxw_worksheet *self, char *target)
{
lxw_drawing_rel_id tmp_drawing_rel_id;
lxw_drawing_rel_id *found_duplicate_target = NULL;
lxw_drawing_rel_id *new_drawing_rel_id = NULL;
if (target) {
tmp_drawing_rel_id.target = target;
found_duplicate_target = RB_FIND(lxw_vml_drawing_rel_ids,
self->vml_drawing_rel_ids,
&tmp_drawing_rel_id);
}
if (found_duplicate_target) {
return found_duplicate_target->id;
}
else {
self->vml_drawing_rel_id++;
if (target) {
new_drawing_rel_id = calloc(1, sizeof(lxw_drawing_rel_id));
if (new_drawing_rel_id) {
new_drawing_rel_id->id = self->vml_drawing_rel_id;
new_drawing_rel_id->target = lxw_strdup(target);
RB_INSERT(lxw_vml_drawing_rel_ids, self->vml_drawing_rel_ids,
new_drawing_rel_id);
}
}
return self->vml_drawing_rel_id;
}
}
/*
* find the index used to address a VML drawing rel link.
*/
STATIC uint32_t
_find_vml_drawing_rel_index(lxw_worksheet *self, char *target)
{
lxw_drawing_rel_id tmp_drawing_rel_id;
lxw_drawing_rel_id *found_duplicate_target = NULL;
if (!target)
return 0;
tmp_drawing_rel_id.target = target;
found_duplicate_target = RB_FIND(lxw_vml_drawing_rel_ids,
self->vml_drawing_rel_ids,
&tmp_drawing_rel_id);
if (found_duplicate_target)
return found_duplicate_target->id;
else
return 0;
}
/*
* Simple replacement for libgen.h basename() for compatibility with MSVC. It
* handles forward and back slashes. It doesn't copy exactly the return
* format of basename().
*/
const char *
lxw_basename(const char *path)
{
const char *forward_slash;
const char *back_slash;
if (!path)
return NULL;
forward_slash = strrchr(path, '/');
back_slash = strrchr(path, '\\');
if (!forward_slash && !back_slash)
return path;
if (forward_slash > back_slash)
return forward_slash + 1;
else
return back_slash + 1;
}
/* Function to count the total concatenated length of the strings in a
* validation list array, including commas. */
size_t
_validation_list_length(const char **list)
{
uint8_t i = 0;
size_t length = 0;
if (!list || !list[0])
return 0;
while (list[i] && length < LXW_VALIDATION_MAX_STRING_LENGTH) {
/* Include commas in the length. */
length += 1 + lxw_utf8_strlen(list[i]);
i++;
}
/* Adjust the count for extraneous comma at end. */
length--;
return length;
}
/* Function to convert an array of strings into a CSV string for data
* validation lists. */
char *
_validation_list_to_csv(const char **list)
{
uint8_t i = 0;
char *str;
/* Create a buffer for the concatenated, and quoted, string. */
/* Allow for 4 byte UTF-8 chars and add 3 bytes for quotes and EOL. */
str = calloc(1, LXW_VALIDATION_MAX_STRING_LENGTH * 4 + 3);
if (!str)
return NULL;
/* Add the start quote and first element. */
strcat(str, "\"");
strcat(str, list[0]);
/* Add the other elements preceded by a comma. */
i = 1;
while (list[i]) {
strcat(str, ",");
strcat(str, list[i]);
i++;
}
/* Add the end quote. */
strcat(str, "\"");
return str;
}
STATIC double
_pixels_to_width(double pixels)
{
double max_digit_width = 7.0;
double padding = 5.0;
double width;
if (pixels == LXW_DEF_COL_WIDTH_PIXELS)
width = LXW_DEF_COL_WIDTH;
else if (pixels <= 12.0)
width = pixels / (max_digit_width + padding);
else
width = (pixels - padding) / max_digit_width;
return width;
}
STATIC double
_pixels_to_height(double pixels)
{
if (pixels == LXW_DEF_ROW_HEIGHT_PIXELS)
return LXW_DEF_ROW_HEIGHT;
else
return pixels * 0.75;
}
/* Check and set if an autofilter is a standard or custom filter. */
void
_set_custom_filter(lxw_filter_rule_obj *rule_obj)
{
rule_obj->is_custom = LXW_TRUE;
if (rule_obj->criteria1 == LXW_FILTER_CRITERIA_EQUAL_TO)
rule_obj->is_custom = LXW_FALSE;
if (rule_obj->criteria1 == LXW_FILTER_CRITERIA_BLANKS)
rule_obj->is_custom = LXW_FALSE;
if (rule_obj->criteria2 != LXW_FILTER_CRITERIA_NONE) {
if (rule_obj->criteria1 == LXW_FILTER_CRITERIA_EQUAL_TO)
rule_obj->is_custom = LXW_FALSE;
if (rule_obj->criteria1 == LXW_FILTER_CRITERIA_BLANKS)
rule_obj->is_custom = LXW_FALSE;
if (rule_obj->type == LXW_FILTER_TYPE_AND)
rule_obj->is_custom = LXW_TRUE;
}
if (rule_obj->value1_string && strpbrk(rule_obj->value1_string, "*?"))
rule_obj->is_custom = LXW_TRUE;
if (rule_obj->value2_string && strpbrk(rule_obj->value2_string, "*?"))
rule_obj->is_custom = LXW_TRUE;
}
/* Check and copy user input for table styles in worksheet_add_table(). */
void
_check_and_copy_table_style(lxw_table_obj *table_obj,
lxw_table_options *user_options)
{
if (!user_options)
return;
/* Set the defaults. */
table_obj->style_type = LXW_TABLE_STYLE_TYPE_MEDIUM;
table_obj->style_type_number = 9;
if (user_options->style_type > LXW_TABLE_STYLE_TYPE_DARK) {
LXW_WARN_FORMAT1
("worksheet_add_table(): invalid style_type = %d. "
"Using default TableStyleMedium9", user_options->style_type);
table_obj->style_type = LXW_TABLE_STYLE_TYPE_MEDIUM;
table_obj->style_type_number = 9;
}
else {
table_obj->style_type = user_options->style_type;
}
/* Each type (light, medium and dark) has a different number of styles. */
if (user_options->style_type == LXW_TABLE_STYLE_TYPE_LIGHT) {
if (user_options->style_type_number > 21) {
LXW_WARN_FORMAT1("worksheet_add_table(): "
"invalid style_type_number = %d for style type "
"LXW_TABLE_STYLE_TYPE_LIGHT. "
"Using default TableStyleMedium9",
user_options->style_type);
table_obj->style_type = LXW_TABLE_STYLE_TYPE_MEDIUM;
table_obj->style_type_number = 9;
}
else {
table_obj->style_type_number = user_options->style_type_number;
}
}
if (user_options->style_type == LXW_TABLE_STYLE_TYPE_MEDIUM) {
if (user_options->style_type_number < 1
|| user_options->style_type_number > 28) {
LXW_WARN_FORMAT1("worksheet_add_table(): "
"invalid style_type_number = %d for style type "
"LXW_TABLE_STYLE_TYPE_MEDIUM. "
"Using default TableStyleMedium9",
user_options->style_type_number);
table_obj->style_type = LXW_TABLE_STYLE_TYPE_MEDIUM;
table_obj->style_type_number = 9;
}
else {
table_obj->style_type_number = user_options->style_type_number;
}
}
if (user_options->style_type == LXW_TABLE_STYLE_TYPE_DARK) {
if (user_options->style_type_number < 1
|| user_options->style_type_number > 11) {
LXW_WARN_FORMAT1("worksheet_add_table(): "
"invalid style_type_number = %d for style type "
"LXW_TABLE_STYLE_TYPE_DARK. "
"Using default TableStyleMedium9",
user_options->style_type_number);
table_obj->style_type = LXW_TABLE_STYLE_TYPE_MEDIUM;
table_obj->style_type_number = 9;
}
else {
table_obj->style_type_number = user_options->style_type_number;
}
}
}
/* Set the defaults for table columns in worksheet_add_table(). */
lxw_error
_set_default_table_columns(lxw_table_obj *table_obj)
{
char col_name[LXW_ATTR_32];
char *header;
uint16_t i;
lxw_table_column *column;
uint16_t num_cols = table_obj->num_cols;
lxw_table_column **columns = table_obj->columns;
for (i = 0; i < num_cols; i++) {
lxw_snprintf(col_name, LXW_ATTR_32, "Column%d", i + 1);
column = calloc(num_cols, sizeof(lxw_table_column));
RETURN_ON_MEM_ERROR(column, LXW_ERROR_MEMORY_MALLOC_FAILED);
header = lxw_strdup(col_name);
if (!header) {
free(column);
RETURN_ON_MEM_ERROR(header, LXW_ERROR_MEMORY_MALLOC_FAILED);
}
columns[i] = column;
columns[i]->header = header;
}
return LXW_NO_ERROR;
}
/* Convert Excel 2010 style "@" structural references to the Excel 2007 style
* "[#This Row]" in table formulas. This is the format that Excel uses to
* store the references. */
char *
_expand_table_formula(const char *formula)
{
char *expanded;
const char *ptr;
size_t i;
size_t ref_count = 0;
size_t expanded_len;
ptr = formula;
while (*ptr++) {
if (*ptr == '@')
ref_count++;
}
if (ref_count == 0) {
/* String doesn't need to be expanded. Just copy it. */
expanded = lxw_strdup_formula(formula);
}
else {
/* Convert "@" in the formula string to "[#This Row],". */
expanded_len = strlen(formula) + (sizeof(LXW_THIS_ROW) * ref_count);
expanded = calloc(1, expanded_len);
if (!expanded)
return NULL;
i = 0;
ptr = formula;
/* Ignore the = in the formula. */
if (*ptr == '=')
ptr++;
/* Do the "@" expansion. */
while (*ptr) {
if (*ptr == '@') {
strcat(&expanded[i], LXW_THIS_ROW);
i += sizeof(LXW_THIS_ROW) - 1;
}
else {
expanded[i] = *ptr;
i++;
}
ptr++;
}
}
return expanded;
}
/* Set user values for table columns in worksheet_add_table(). */
lxw_error
_set_custom_table_columns(lxw_table_obj *table_obj,
lxw_table_options *user_options)
{
char *str;
uint16_t i;
lxw_table_column *table_column;
lxw_table_column *user_column;
uint16_t num_cols = table_obj->num_cols;
lxw_table_column **user_columns = user_options->columns;
for (i = 0; i < num_cols; i++) {
user_column = user_columns[i];
table_column = table_obj->columns[i];
/* NULL indicates end of user input array. */
if (user_column == NULL)
return LXW_NO_ERROR;
if (user_column->header) {
if (lxw_utf8_strlen(user_column->header) > 255) {
LXW_WARN_FORMAT("worksheet_add_table(): column parameter "
"'header' exceeds Excel length limit of 255.");
return LXW_ERROR_255_STRING_LENGTH_EXCEEDED;
}
str = lxw_strdup(user_column->header);
RETURN_ON_MEM_ERROR(str, LXW_ERROR_MEMORY_MALLOC_FAILED);
/* Free the default column header. */
free((void *) table_column->header);
table_column->header = str;
}
if (user_column->total_string) {
str = lxw_strdup(user_column->total_string);
RETURN_ON_MEM_ERROR(str, LXW_ERROR_MEMORY_MALLOC_FAILED);
table_column->total_string = str;
}
if (user_column->formula) {
str = _expand_table_formula(user_column->formula);
RETURN_ON_MEM_ERROR(str, LXW_ERROR_MEMORY_MALLOC_FAILED);
table_column->formula = str;
}
table_column->format = user_column->format;
table_column->total_value = user_column->total_value;
table_column->header_format = user_column->header_format;
table_column->total_function = user_column->total_function;
}
return LXW_NO_ERROR;
}
/* Write a worksheet table column formula like SUBTOTAL(109,[Column1]). */
void
_write_column_function(lxw_worksheet *self, lxw_row_t row, lxw_col_t col,
lxw_table_column *column)
{
size_t offset;
char formula[LXW_MAX_ATTRIBUTE_LENGTH];
lxw_format *format = column->format;
uint8_t total_function = column->total_function;
double value = column->total_value;
const char *header = column->header;
/* Write the subtotal formula number. */
lxw_snprintf(formula, LXW_MAX_ATTRIBUTE_LENGTH, "SUBTOTAL(%d,[",
total_function);
/* Copy the header string but escape any special characters. Note, this is
* guaranteed to fit in the 2k buffer since the header is max 255
* characters, checked in _set_custom_table_columns(). */
offset = strlen(formula);
while (*header) {
switch (*header) {
case '\'':
case '#':
case '[':
case ']':
formula[offset++] = '\'';
formula[offset] = *header;
break;
default:
formula[offset] = *header;
break;
}
offset++;
header++;
}
/* Write the end of the string. */
memcpy(&formula[offset], "])\0", sizeof("])\0"));
worksheet_write_formula_num(self, row, col, formula, format, value);
}
/* Write a worksheet table column formula. */
void
_write_column_formula(lxw_worksheet *self, lxw_row_t first_row,
lxw_row_t last_row, lxw_col_t col,
lxw_table_column *column)
{
lxw_row_t row;
const char *formula = column->formula;
lxw_format *format = column->format;
for (row = first_row; row <= last_row; row++)
worksheet_write_formula(self, row, col, formula, format);
}
/* Set the defaults for table columns in worksheet_add_table(). */
void
_write_table_column_data(lxw_worksheet *self, lxw_table_obj *table_obj)
{
uint16_t i;
lxw_table_column *column;
lxw_table_column **columns = table_obj->columns;
lxw_col_t col;
lxw_row_t first_row = table_obj->first_row;
lxw_col_t first_col = table_obj->first_col;
lxw_row_t last_row = table_obj->last_row;
lxw_row_t first_data_row = first_row;
lxw_row_t last_data_row = last_row;
if (!table_obj->no_header_row)
first_data_row++;
if (table_obj->total_row)
last_data_row--;
for (i = 0; i < table_obj->num_cols; i++) {
col = first_col + i;
column = columns[i];
if (table_obj->no_header_row == LXW_FALSE)
worksheet_write_string(self, first_row, col, column->header,
column->header_format);
if (column->total_string)
worksheet_write_string(self, last_row, col, column->total_string,
NULL);
if (column->total_function)
_write_column_function(self, last_row, col, column);
if (column->formula)
_write_column_formula(self, first_data_row, last_data_row, col,
column);
}
}
/*
* Check that there are sufficient data rows in a worksheet table.
*/
lxw_error
_check_table_rows(lxw_row_t first_row, lxw_row_t last_row,
lxw_table_options *user_options)
{
lxw_row_t num_non_header_rows = last_row - first_row;
if (user_options && user_options->no_header_row == LXW_TRUE)
num_non_header_rows++;
if (num_non_header_rows == 0) {
LXW_WARN_FORMAT("worksheet_add_table(): "
"table must have at least 1 non-header row.");
return LXW_ERROR_PARAMETER_VALIDATION;
}
return LXW_NO_ERROR;
}
/*
* Check that the the table name is valid.
*/
lxw_error
_check_table_name(lxw_table_options *user_options)
{
const char *name;
char *ptr;
char first[2] = { 0, 0 };
if (!user_options)
return LXW_NO_ERROR;
if (!user_options->name)
return LXW_NO_ERROR;
name = user_options->name;
/* Check table name length. */
if (lxw_utf8_strlen(name) > 255) {
LXW_WARN_FORMAT("worksheet_add_table(): "
"Table name exceeds Excel's limit of 255.");
return LXW_ERROR_255_STRING_LENGTH_EXCEEDED;
}
/* Check some short invalid names. */
if (strlen(name) == 1
&& (name[0] == 'C' || name[0] == 'c' || name[0] == 'R'
|| name[0] == 'r')) {
LXW_WARN_FORMAT1("worksheet_add_table(): "
"invalid table name \"%s\".", name);
return LXW_ERROR_255_STRING_LENGTH_EXCEEDED;
}
/* Check for invalid characters in Table name, while trying to allow
* for utf8 strings. */
ptr = strpbrk(name, " !\"#$%&'()*+,-/:;<=>?@[\\]^`{|}~");
if (ptr) {
LXW_WARN_FORMAT2("worksheet_add_table(): "
"invalid character '%c' in table name \"%s\".",
*ptr, name);
return LXW_ERROR_PARAMETER_VALIDATION;
}
/* Check for invalid initial character in Table name, while trying to allow
* for utf8 strings. */
first[0] = name[0];
ptr = strpbrk(first, " !\"#$%&'()*+,-./0123456789:;<=>?@[\\]^`{|}~");
if (ptr) {
LXW_WARN_FORMAT2("worksheet_add_table(): "
"invalid first character '%c' in table name \"%s\".",
*ptr, name);
return LXW_ERROR_PARAMETER_VALIDATION;
}
return LXW_NO_ERROR;
}
/*****************************************************************************
*
* XML functions.
*
****************************************************************************/
/*
* Write the XML declaration.
*/
STATIC void
_worksheet_xml_declaration(lxw_worksheet *self)
{
lxw_xml_declaration(self->file);
}
/*
* Write the element.
*/
STATIC void
_worksheet_write_worksheet(lxw_worksheet *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char xmlns[] = "http://schemas.openxmlformats.org/"
"spreadsheetml/2006/main";
char xmlns_r[] = "http://schemas.openxmlformats.org/"
"officeDocument/2006/relationships";
char xmlns_mc[] = "http://schemas.openxmlformats.org/"
"markup-compatibility/2006";
char xmlns_x14ac[] = "http://schemas.microsoft.com/"
"office/spreadsheetml/2009/9/ac";
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("xmlns", xmlns);
LXW_PUSH_ATTRIBUTES_STR("xmlns:r", xmlns_r);
if (self->excel_version == 2010) {
LXW_PUSH_ATTRIBUTES_STR("xmlns:mc", xmlns_mc);
LXW_PUSH_ATTRIBUTES_STR("xmlns:x14ac", xmlns_x14ac);
LXW_PUSH_ATTRIBUTES_STR("mc:Ignorable", "x14ac");
}
lxw_xml_start_tag(self->file, "worksheet", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_worksheet_write_dimension(lxw_worksheet *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char ref[LXW_MAX_CELL_RANGE_LENGTH];
lxw_row_t dim_rowmin = self->dim_rowmin;
lxw_row_t dim_rowmax = self->dim_rowmax;
lxw_col_t dim_colmin = self->dim_colmin;
lxw_col_t dim_colmax = self->dim_colmax;
if (dim_rowmin == LXW_ROW_MAX && dim_colmin == LXW_COL_MAX) {
/* If the rows and cols are still the defaults then no dimensions have
* been set and we use the default range "A1". */
lxw_rowcol_to_range(ref, 0, 0, 0, 0);
}
else if (dim_rowmin == LXW_ROW_MAX && dim_colmin != LXW_COL_MAX) {
/* If the rows aren't set but the columns are then the dimensions have
* been changed via set_column(). */
lxw_rowcol_to_range(ref, 0, dim_colmin, 0, dim_colmax);
}
else {
lxw_rowcol_to_range(ref, dim_rowmin, dim_colmin, dim_rowmax,
dim_colmax);
}
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("ref", ref);
lxw_xml_empty_tag(self->file, "dimension", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element for freeze panes.
*/
STATIC void
_worksheet_write_freeze_panes(lxw_worksheet *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
lxw_selection *selection;
lxw_selection *user_selection;
lxw_row_t row = self->panes.first_row;
lxw_col_t col = self->panes.first_col;
lxw_row_t top_row = self->panes.top_row;
lxw_col_t left_col = self->panes.left_col;
char row_cell[LXW_MAX_CELL_NAME_LENGTH];
char col_cell[LXW_MAX_CELL_NAME_LENGTH];
char top_left_cell[LXW_MAX_CELL_NAME_LENGTH];
char active_pane[LXW_PANE_NAME_LENGTH];
/* If there is a user selection we remove it from the list and use it. */
if (!STAILQ_EMPTY(self->selections)) {
user_selection = STAILQ_FIRST(self->selections);
STAILQ_REMOVE_HEAD(self->selections, list_pointers);
}
else {
/* or else create a new blank selection. */
user_selection = calloc(1, sizeof(lxw_selection));
RETURN_VOID_ON_MEM_ERROR(user_selection);
}
LXW_INIT_ATTRIBUTES();
lxw_rowcol_to_cell(top_left_cell, top_row, left_col);
/* Set the active pane. */
if (row && col) {
lxw_strcpy(active_pane, "bottomRight");
lxw_rowcol_to_cell(row_cell, row, 0);
lxw_rowcol_to_cell(col_cell, 0, col);
selection = calloc(1, sizeof(lxw_selection));
if (selection) {
lxw_strcpy(selection->pane, "topRight");
lxw_strcpy(selection->active_cell, col_cell);
lxw_strcpy(selection->sqref, col_cell);
STAILQ_INSERT_TAIL(self->selections, selection, list_pointers);
}
selection = calloc(1, sizeof(lxw_selection));
if (selection) {
lxw_strcpy(selection->pane, "bottomLeft");
lxw_strcpy(selection->active_cell, row_cell);
lxw_strcpy(selection->sqref, row_cell);
STAILQ_INSERT_TAIL(self->selections, selection, list_pointers);
}
selection = calloc(1, sizeof(lxw_selection));
if (selection) {
lxw_strcpy(selection->pane, "bottomRight");
lxw_strcpy(selection->active_cell, user_selection->active_cell);
lxw_strcpy(selection->sqref, user_selection->sqref);
STAILQ_INSERT_TAIL(self->selections, selection, list_pointers);
}
}
else if (col) {
lxw_strcpy(active_pane, "topRight");
selection = calloc(1, sizeof(lxw_selection));
if (selection) {
lxw_strcpy(selection->pane, "topRight");
lxw_strcpy(selection->active_cell, user_selection->active_cell);
lxw_strcpy(selection->sqref, user_selection->sqref);
STAILQ_INSERT_TAIL(self->selections, selection, list_pointers);
}
}
else {
lxw_strcpy(active_pane, "bottomLeft");
selection = calloc(1, sizeof(lxw_selection));
if (selection) {
lxw_strcpy(selection->pane, "bottomLeft");
lxw_strcpy(selection->active_cell, user_selection->active_cell);
lxw_strcpy(selection->sqref, user_selection->sqref);
STAILQ_INSERT_TAIL(self->selections, selection, list_pointers);
}
}
if (col)
LXW_PUSH_ATTRIBUTES_INT("xSplit", col);
if (row)
LXW_PUSH_ATTRIBUTES_INT("ySplit", row);
LXW_PUSH_ATTRIBUTES_STR("topLeftCell", top_left_cell);
LXW_PUSH_ATTRIBUTES_STR("activePane", active_pane);
if (self->panes.type == FREEZE_PANES)
LXW_PUSH_ATTRIBUTES_STR("state", "frozen");
else if (self->panes.type == FREEZE_SPLIT_PANES)
LXW_PUSH_ATTRIBUTES_STR("state", "frozenSplit");
lxw_xml_empty_tag(self->file, "pane", &attributes);
free(user_selection);
LXW_FREE_ATTRIBUTES();
}
/*
* Convert column width from user units to pane split width.
*/
STATIC uint32_t
_worksheet_calculate_x_split_width(double x_split)
{
uint32_t width;
uint32_t pixels;
uint32_t points;
uint32_t twips;
double max_digit_width = 7.0; /* For Calabri 11. */
double padding = 5.0;
/* Convert to pixels. */
if (x_split < 1.0) {
pixels = (uint32_t) (x_split * (max_digit_width + padding) + 0.5);
}
else {
pixels = (uint32_t) (x_split * max_digit_width + 0.5) + 5;
}
/* Convert to points. */
points = (pixels * 3) / 4;
/* Convert to twips (twentieths of a point). */
twips = points * 20;
/* Add offset/padding. */
width = twips + 390;
return width;
}
/*
* Write the element for split panes.
*/
STATIC void
_worksheet_write_split_panes(lxw_worksheet *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
lxw_selection *selection;
lxw_selection *user_selection;
lxw_row_t row = self->panes.first_row;
lxw_col_t col = self->panes.first_col;
lxw_row_t top_row = self->panes.top_row;
lxw_col_t left_col = self->panes.left_col;
double x_split = self->panes.x_split;
double y_split = self->panes.y_split;
uint8_t has_selection = LXW_FALSE;
char row_cell[LXW_MAX_CELL_NAME_LENGTH];
char col_cell[LXW_MAX_CELL_NAME_LENGTH];
char top_left_cell[LXW_MAX_CELL_NAME_LENGTH];
char active_pane[LXW_PANE_NAME_LENGTH];
/* If there is a user selection we remove it from the list and use it. */
if (!STAILQ_EMPTY(self->selections)) {
user_selection = STAILQ_FIRST(self->selections);
STAILQ_REMOVE_HEAD(self->selections, list_pointers);
has_selection = LXW_TRUE;
}
else {
/* or else create a new blank selection. */
user_selection = calloc(1, sizeof(lxw_selection));
RETURN_VOID_ON_MEM_ERROR(user_selection);
}
LXW_INIT_ATTRIBUTES();
/* Convert the row and col to 1/20 twip units with padding. */
if (y_split > 0.0)
y_split = (uint32_t) (20 * y_split + 300);
if (x_split > 0.0)
x_split = _worksheet_calculate_x_split_width(x_split);
/* For non-explicit topLeft definitions, estimate the cell offset based on
* the pixels dimensions. This is only a workaround and doesn't take
* adjusted cell dimensions into account.
*/
if (top_row == row && left_col == col) {
top_row = (lxw_row_t) (0.5 + (y_split - 300.0) / 20.0 / 15.0);
left_col = (lxw_col_t) (0.5 + (x_split - 390.0) / 20.0 / 3.0 / 16.0);
}
lxw_rowcol_to_cell(top_left_cell, top_row, left_col);
/* If there is no selection set the active cell to the top left cell. */
if (!has_selection) {
lxw_strcpy(user_selection->active_cell, top_left_cell);
lxw_strcpy(user_selection->sqref, top_left_cell);
}
/* Set the active pane. */
if (y_split > 0.0 && x_split > 0.0) {
lxw_strcpy(active_pane, "bottomRight");
lxw_rowcol_to_cell(row_cell, top_row, 0);
lxw_rowcol_to_cell(col_cell, 0, left_col);
selection = calloc(1, sizeof(lxw_selection));
if (selection) {
lxw_strcpy(selection->pane, "topRight");
lxw_strcpy(selection->active_cell, col_cell);
lxw_strcpy(selection->sqref, col_cell);
STAILQ_INSERT_TAIL(self->selections, selection, list_pointers);
}
selection = calloc(1, sizeof(lxw_selection));
if (selection) {
lxw_strcpy(selection->pane, "bottomLeft");
lxw_strcpy(selection->active_cell, row_cell);
lxw_strcpy(selection->sqref, row_cell);
STAILQ_INSERT_TAIL(self->selections, selection, list_pointers);
}
selection = calloc(1, sizeof(lxw_selection));
if (selection) {
lxw_strcpy(selection->pane, "bottomRight");
lxw_strcpy(selection->active_cell, user_selection->active_cell);
lxw_strcpy(selection->sqref, user_selection->sqref);
STAILQ_INSERT_TAIL(self->selections, selection, list_pointers);
}
}
else if (x_split > 0.0) {
lxw_strcpy(active_pane, "topRight");
selection = calloc(1, sizeof(lxw_selection));
if (selection) {
lxw_strcpy(selection->pane, "topRight");
lxw_strcpy(selection->active_cell, user_selection->active_cell);
lxw_strcpy(selection->sqref, user_selection->sqref);
STAILQ_INSERT_TAIL(self->selections, selection, list_pointers);
}
}
else {
lxw_strcpy(active_pane, "bottomLeft");
selection = calloc(1, sizeof(lxw_selection));
if (selection) {
lxw_strcpy(selection->pane, "bottomLeft");
lxw_strcpy(selection->active_cell, user_selection->active_cell);
lxw_strcpy(selection->sqref, user_selection->sqref);
STAILQ_INSERT_TAIL(self->selections, selection, list_pointers);
}
}
if (x_split > 0.0)
LXW_PUSH_ATTRIBUTES_DBL("xSplit", x_split);
if (y_split > 0.0)
LXW_PUSH_ATTRIBUTES_DBL("ySplit", y_split);
LXW_PUSH_ATTRIBUTES_STR("topLeftCell", top_left_cell);
if (has_selection)
LXW_PUSH_ATTRIBUTES_STR("activePane", active_pane);
lxw_xml_empty_tag(self->file, "pane", &attributes);
free(user_selection);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_worksheet_write_selection(lxw_worksheet *self, lxw_selection *selection)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
if (*selection->pane)
LXW_PUSH_ATTRIBUTES_STR("pane", selection->pane);
if (*selection->active_cell)
LXW_PUSH_ATTRIBUTES_STR("activeCell", selection->active_cell);
if (*selection->sqref)
LXW_PUSH_ATTRIBUTES_STR("sqref", selection->sqref);
lxw_xml_empty_tag(self->file, "selection", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the elements.
*/
STATIC void
_worksheet_write_selections(lxw_worksheet *self)
{
lxw_selection *selection;
STAILQ_FOREACH(selection, self->selections, list_pointers) {
_worksheet_write_selection(self, selection);
}
}
/*
* Write the frozen or split elements.
*/
STATIC void
_worksheet_write_panes(lxw_worksheet *self)
{
if (self->panes.type == NO_PANES)
return;
else if (self->panes.type == FREEZE_PANES)
_worksheet_write_freeze_panes(self);
else if (self->panes.type == FREEZE_SPLIT_PANES)
_worksheet_write_freeze_panes(self);
else if (self->panes.type == SPLIT_PANES)
_worksheet_write_split_panes(self);
}
/*
* Write the element.
*/
STATIC void
_worksheet_write_sheet_view(lxw_worksheet *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
/* Hide screen gridlines if required */
if (!self->screen_gridlines)
LXW_PUSH_ATTRIBUTES_STR("showGridLines", "0");
/* Hide zeroes in cells. */
if (!self->show_zeros)
LXW_PUSH_ATTRIBUTES_STR("showZeros", "0");
/* Display worksheet right to left for Hebrew, Arabic and others. */
if (self->right_to_left)
LXW_PUSH_ATTRIBUTES_STR("rightToLeft", "1");
/* Show that the sheet tab is selected. */
if (self->selected)
LXW_PUSH_ATTRIBUTES_STR("tabSelected", "1");
/* Turn outlines off. Also required in the outlinePr element. */
if (!self->outline_on)
LXW_PUSH_ATTRIBUTES_STR("showOutlineSymbols", "0");
/* Set the page view/layout mode if required. */
if (self->page_view)
LXW_PUSH_ATTRIBUTES_STR("view", "pageLayout");
/* Set the top left cell if required. */
if (self->top_left_cell[0])
LXW_PUSH_ATTRIBUTES_STR("topLeftCell", self->top_left_cell);
/* Set the zoom level. */
if (self->zoom != 100 && !self->page_view) {
LXW_PUSH_ATTRIBUTES_INT("zoomScale", self->zoom);
if (self->zoom_scale_normal)
LXW_PUSH_ATTRIBUTES_INT("zoomScaleNormal", self->zoom);
}
LXW_PUSH_ATTRIBUTES_STR("workbookViewId", "0");
if (self->panes.type != NO_PANES || !STAILQ_EMPTY(self->selections)) {
lxw_xml_start_tag(self->file, "sheetView", &attributes);
_worksheet_write_panes(self);
_worksheet_write_selections(self);
lxw_xml_end_tag(self->file, "sheetView");
}
else {
lxw_xml_empty_tag(self->file, "sheetView", &attributes);
}
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_worksheet_write_sheet_views(lxw_worksheet *self)
{
lxw_xml_start_tag(self->file, "sheetViews", NULL);
/* Write the sheetView element. */
_worksheet_write_sheet_view(self);
lxw_xml_end_tag(self->file, "sheetViews");
}
/*
* Write the element.
*/
STATIC void
_worksheet_write_sheet_format_pr(lxw_worksheet *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_DBL("defaultRowHeight", self->default_row_height);
if (self->default_row_height != LXW_DEF_ROW_HEIGHT)
LXW_PUSH_ATTRIBUTES_STR("customHeight", "1");
if (self->default_row_zeroed)
LXW_PUSH_ATTRIBUTES_STR("zeroHeight", "1");
if (self->outline_row_level)
LXW_PUSH_ATTRIBUTES_INT("outlineLevelRow", self->outline_row_level);
if (self->outline_col_level)
LXW_PUSH_ATTRIBUTES_INT("outlineLevelCol", self->outline_col_level);
if (self->excel_version == 2010)
LXW_PUSH_ATTRIBUTES_STR("x14ac:dyDescent", "0.25");
lxw_xml_empty_tag(self->file, "sheetFormatPr", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_worksheet_write_sheet_data(lxw_worksheet *self)
{
if (RB_EMPTY(self->table)) {
lxw_xml_empty_tag(self->file, "sheetData", NULL);
}
else {
lxw_xml_start_tag(self->file, "sheetData", NULL);
_worksheet_write_rows(self);
lxw_xml_end_tag(self->file, "sheetData");
}
}
/*
* Write the element when the memory optimization is on. In which
* case we read the data stored in the temp file and rewrite it to the XML
* sheet file.
*/
STATIC void
_worksheet_write_optimized_sheet_data(lxw_worksheet *self)
{
size_t read_size = 1;
char buffer[LXW_BUFFER_SIZE];
if (self->dim_rowmin == LXW_ROW_MAX) {
/* If the dimensions aren't defined then there is no data to write. */
lxw_xml_empty_tag(self->file, "sheetData", NULL);
}
else {
lxw_xml_start_tag(self->file, "sheetData", NULL);
/* Flush the temp file. */
fflush(self->optimize_tmpfile);
if (self->optimize_buffer) {
/* Ignore return value. There is no easy way to raise error. */
(void) fwrite(self->optimize_buffer, self->optimize_buffer_size,
1, self->file);
}
else {
/* Rewind the temp file. */
rewind(self->optimize_tmpfile);
while (read_size) {
read_size =
fread(buffer, 1, LXW_BUFFER_SIZE, self->optimize_tmpfile);
/* Ignore return value. There is no easy way to raise error. */
(void) fwrite(buffer, 1, read_size, self->file);
}
}
fclose(self->optimize_tmpfile);
free(self->optimize_buffer);
lxw_xml_end_tag(self->file, "sheetData");
}
}
/*
* Write the element.
*/
STATIC void
_worksheet_write_page_margins(lxw_worksheet *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
double left = self->margin_left;
double right = self->margin_right;
double top = self->margin_top;
double bottom = self->margin_bottom;
double header = self->margin_header;
double footer = self->margin_footer;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_DBL("left", left);
LXW_PUSH_ATTRIBUTES_DBL("right", right);
LXW_PUSH_ATTRIBUTES_DBL("top", top);
LXW_PUSH_ATTRIBUTES_DBL("bottom", bottom);
LXW_PUSH_ATTRIBUTES_DBL("header", header);
LXW_PUSH_ATTRIBUTES_DBL("footer", footer);
lxw_xml_empty_tag(self->file, "pageMargins", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
* The following is an example taken from Excel.
*
*/
STATIC void
_worksheet_write_page_setup(lxw_worksheet *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
LXW_INIT_ATTRIBUTES();
if (!self->page_setup_changed)
return;
/* Set paper size. */
if (self->paper_size)
LXW_PUSH_ATTRIBUTES_INT("paperSize", self->paper_size);
/* Set the print_scale. */
if (self->print_scale != 100)
LXW_PUSH_ATTRIBUTES_INT("scale", self->print_scale);
/* Set the "Fit to page" properties. */
if (self->fit_page && self->fit_width != 1)
LXW_PUSH_ATTRIBUTES_INT("fitToWidth", self->fit_width);
if (self->fit_page && self->fit_height != 1)
LXW_PUSH_ATTRIBUTES_INT("fitToHeight", self->fit_height);
/* Set the page print direction. */
if (self->page_order)
LXW_PUSH_ATTRIBUTES_STR("pageOrder", "overThenDown");
/* Set start page. */
if (self->page_start > 1)
LXW_PUSH_ATTRIBUTES_INT("firstPageNumber", self->page_start);
/* Set page orientation. */
if (self->orientation)
LXW_PUSH_ATTRIBUTES_STR("orientation", "portrait");
else
LXW_PUSH_ATTRIBUTES_STR("orientation", "landscape");
if (self->black_white)
LXW_PUSH_ATTRIBUTES_STR("blackAndWhite", "1");
/* Set start page active flag. */
if (self->page_start)
LXW_PUSH_ATTRIBUTES_INT("useFirstPageNumber", 1);
/* Set the DPI. Mainly only for testing. */
if (self->horizontal_dpi)
LXW_PUSH_ATTRIBUTES_INT("horizontalDpi", self->horizontal_dpi);
if (self->vertical_dpi)
LXW_PUSH_ATTRIBUTES_INT("verticalDpi", self->vertical_dpi);
lxw_xml_empty_tag(self->file, "pageSetup", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_worksheet_write_print_options(lxw_worksheet *self)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
if (!self->print_options_changed)
return;
LXW_INIT_ATTRIBUTES();
/* Set horizontal centering. */
if (self->hcenter) {
LXW_PUSH_ATTRIBUTES_STR("horizontalCentered", "1");
}
/* Set vertical centering. */
if (self->vcenter) {
LXW_PUSH_ATTRIBUTES_STR("verticalCentered", "1");
}
/* Enable row and column headers. */
if (self->print_headers) {
LXW_PUSH_ATTRIBUTES_STR("headings", "1");
}
/* Set printed gridlines. */
if (self->print_gridlines) {
LXW_PUSH_ATTRIBUTES_STR("gridLines", "1");
}
lxw_xml_empty_tag(self->file, "printOptions", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Write the element.
*/
STATIC void
_write_row(lxw_worksheet *self, lxw_row *row, char *spans)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
int32_t xf_index = 0;
double height;
if (row->format) {
xf_index = lxw_format_get_xf_index(row->format);
}
if (row->height_changed)
height = row->height;
else
height = self->default_row_height;
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_INT("r", row->row_num + 1);
if (spans)
LXW_PUSH_ATTRIBUTES_STR("spans", spans);
if (xf_index)
LXW_PUSH_ATTRIBUTES_INT("s", xf_index);
if (row->format)
LXW_PUSH_ATTRIBUTES_STR("customFormat", "1");
if (height != LXW_DEF_ROW_HEIGHT)
LXW_PUSH_ATTRIBUTES_DBL("ht", height);
if (row->hidden)
LXW_PUSH_ATTRIBUTES_STR("hidden", "1");
if (height != LXW_DEF_ROW_HEIGHT)
LXW_PUSH_ATTRIBUTES_STR("customHeight", "1");
if (row->level)
LXW_PUSH_ATTRIBUTES_INT("outlineLevel", row->level);
if (row->collapsed)
LXW_PUSH_ATTRIBUTES_STR("collapsed", "1");
if (self->excel_version == 2010)
LXW_PUSH_ATTRIBUTES_STR("x14ac:dyDescent", "0.25");
if (!row->data_changed)
lxw_xml_empty_tag(self->file, "row", &attributes);
else
lxw_xml_start_tag(self->file, "row", &attributes);
LXW_FREE_ATTRIBUTES();
}
/*
* Convert the width of a cell from user's units to pixels. Excel rounds the
* column width to the nearest pixel. If the width hasn't been set by the user
* we use the default value. If the column is hidden it has a value of zero.
*/
STATIC int32_t
_worksheet_size_col(lxw_worksheet *self, lxw_col_t col_num, uint8_t anchor)
{
lxw_col_options *col_opt = NULL;
uint32_t pixels;
double width;
double max_digit_width = 7.0; /* For Calabri 11. */
double padding = 5.0;
lxw_col_t col_index;
/* Search for the col number in the array of col_options. Each col_option
* entry contains the start and end column for a range.
*/
for (col_index = 0; col_index < self->col_options_max; col_index++) {
col_opt = self->col_options[col_index];
if (col_opt) {
if (col_num >= col_opt->firstcol && col_num <= col_opt->lastcol)
break;
else
col_opt = NULL;
}
}
if (col_opt) {
width = col_opt->width;
/* Convert to pixels. */
if (col_opt->hidden && anchor != LXW_OBJECT_MOVE_AND_SIZE_AFTER) {
pixels = 0;
}
else if (width < 1.0) {
pixels = (uint32_t) (width * (max_digit_width + padding) + 0.5);
}
else {
pixels = (uint32_t) (width * max_digit_width + 0.5) + 5;
}
}
else {
pixels = self->default_col_pixels;
}
return pixels;
}
/*
* Convert the height of a cell from user's units to pixels. If the height
* hasn't been set by the user we use the default value. If the row is hidden
* it has a value of zero.
*/
STATIC int32_t
_worksheet_size_row(lxw_worksheet *self, lxw_row_t row_num, uint8_t anchor)
{
lxw_row *row;
uint32_t pixels;
row = lxw_worksheet_find_row(self, row_num);
/* Note, the 0.75 below is due to the difference between 72/96 DPI. */
if (row) {
if (row->hidden && anchor != LXW_OBJECT_MOVE_AND_SIZE_AFTER)
pixels = 0;
else
pixels = (uint32_t) (row->height / 0.75);
}
else {
pixels = (uint32_t) (self->default_row_height / 0.75);
}
return pixels;
}
/*
* Calculate the vertices that define the position of a graphical object
* within the worksheet in pixels.
* +------------+------------+
* | A | B |
* +-----+------------+------------+
* | |(x1,y1) | |
* | 1 |(A1)._______|______ |
* | | | | |
* | | | | |
* +-----+----| BITMAP |-----+
* | | | | |
* | 2 | |______________. |
* | | | (B2)|
* | | | (x2,y2)|
* +---- +------------+------------+
*
* Example of an object that covers some of the area from cell A1 to cell B2.
* Based on the width and height of the object we need to calculate 8 vars:
*
* col_start, row_start, col_end, row_end, x1, y1, x2, y2.
*
* We also calculate the absolute x and y position of the top left vertex of
* the object. This is required for images:
*
* x_abs, y_abs
*
* The width and height of the cells that the object occupies can be variable
* and have to be taken into account.
*
* The values of col_start and row_start are passed in from the calling
* function. The values of col_end and row_end are calculated by subtracting
* the width and height of the object from the width and height of the
* underlying cells.
*/
STATIC void
_worksheet_position_object_pixels(lxw_worksheet *self,
lxw_object_properties *object_props,
lxw_drawing_object *drawing_object)
{
lxw_col_t col_start; /* Column containing upper left corner. */
int32_t x1; /* Distance to left side of object. */
lxw_row_t row_start; /* Row containing top left corner. */
int32_t y1; /* Distance to top of object. */
lxw_col_t col_end; /* Column containing lower right corner. */
double x2; /* Distance to right side of object. */
lxw_row_t row_end; /* Row containing bottom right corner. */
double y2; /* Distance to bottom of object. */
double width; /* Width of object frame. */
double height; /* Height of object frame. */
uint32_t x_abs = 0; /* Abs. distance to left side of object. */
uint32_t y_abs = 0; /* Abs. distance to top side of object. */
uint32_t i;
uint8_t anchor = drawing_object->anchor;
uint8_t ignore_anchor = LXW_OBJECT_POSITION_DEFAULT;
col_start = object_props->col;
row_start = object_props->row;
x1 = object_props->x_offset;
y1 = object_props->y_offset;
width = object_props->width;
height = object_props->height;
/* Adjust start column for negative offsets. */
while (x1 < 0 && col_start > 0) {
x1 += _worksheet_size_col(self, col_start - 1, ignore_anchor);
col_start--;
}
/* Adjust start row for negative offsets. */
while (y1 < 0 && row_start > 0) {
y1 += _worksheet_size_row(self, row_start - 1, ignore_anchor);
row_start--;
}
/* Ensure that the image isn't shifted off the page at top left. */
if (x1 < 0)
x1 = 0;
if (y1 < 0)
y1 = 0;
/* Calculate the absolute x offset of the top-left vertex. */
if (self->col_size_changed) {
for (i = 0; i < col_start; i++)
x_abs += _worksheet_size_col(self, i, ignore_anchor);
}
else {
/* Optimization for when the column widths haven't changed. */
x_abs += self->default_col_pixels * col_start;
}
x_abs += x1;
/* Calculate the absolute y offset of the top-left vertex. */
/* Store the column change to allow optimizations. */
if (self->row_size_changed) {
for (i = 0; i < row_start; i++)
y_abs += _worksheet_size_row(self, i, ignore_anchor);
}
else {
/* Optimization for when the row heights haven"t changed. */
y_abs += self->default_row_pixels * row_start;
}
y_abs += y1;
/* Adjust start col for offsets that are greater than the col width. */
while (x1 >= _worksheet_size_col(self, col_start, anchor)) {
x1 -= _worksheet_size_col(self, col_start, ignore_anchor);
col_start++;
}
/* Adjust start row for offsets that are greater than the row height. */
while (y1 >= _worksheet_size_row(self, row_start, anchor)) {
y1 -= _worksheet_size_row(self, row_start, ignore_anchor);
row_start++;
}
/* Initialize end cell to the same as the start cell. */
col_end = col_start;
row_end = row_start;
/* Only offset the image in the cell if the row/col is hidden. */
if (_worksheet_size_col(self, col_start, anchor) > 0)
width = width + x1;
if (_worksheet_size_row(self, row_start, anchor) > 0)
height = height + y1;
/* Subtract the underlying cell widths to find the end cell. */
while (width >= _worksheet_size_col(self, col_end, anchor)) {
width -= _worksheet_size_col(self, col_end, anchor);
col_end++;
}
/* Subtract the underlying cell heights to find the end cell. */
while (height >= _worksheet_size_row(self, row_end, anchor)) {
height -= _worksheet_size_row(self, row_end, anchor);
row_end++;
}
/* The end vertices are whatever is left from the width and height. */
x2 = width;
y2 = height;
/* Add the dimensions to the drawing object. */
drawing_object->from.col = col_start;
drawing_object->from.row = row_start;
drawing_object->from.col_offset = x1;
drawing_object->from.row_offset = y1;
drawing_object->to.col = col_end;
drawing_object->to.row = row_end;
drawing_object->to.col_offset = x2;
drawing_object->to.row_offset = y2;
drawing_object->col_absolute = x_abs;
drawing_object->row_absolute = y_abs;
}
/*
* Calculate the vertices that define the position of a graphical object
* within the worksheet in EMUs. The vertices are expressed as English
* Metric Units (EMUs). There are 12,700 EMUs per point.
* Therefore, 12,700 * 3 /4 = 9,525 EMUs per pixel.
*/
STATIC void
_worksheet_position_object_emus(lxw_worksheet *self,
lxw_object_properties *image,
lxw_drawing_object *drawing_object)
{
_worksheet_position_object_pixels(self, image, drawing_object);
/* Convert the pixel values to EMUs. See above. */
drawing_object->from.col_offset *= 9525;
drawing_object->from.row_offset *= 9525;
drawing_object->to.col_offset *= 9525;
drawing_object->to.row_offset *= 9525;
drawing_object->to.col_offset += 0.5;
drawing_object->to.row_offset += 0.5;
drawing_object->col_absolute *= 9525;
drawing_object->row_absolute *= 9525;
}
/*
* This function handles the additional optional parameters to
* worksheet_write_comment_opt() as well as calculating the comment object
* position and vertices.
*/
void
_get_comment_params(lxw_vml_obj *comment, lxw_comment_options *options)
{
lxw_row_t start_row;
lxw_col_t start_col;
int32_t x_offset;
int32_t y_offset;
uint32_t height = 74;
uint32_t width = 128;
double x_scale = 1.0;
double y_scale = 1.0;
lxw_row_t row = comment->row;
lxw_col_t col = comment->col;;
/* Set the default start cell and offsets for the comment. These are
* generally fixed in relation to the parent cell. However there are some
* edge cases for cells at the, well yes, edges. */
if (row == 0)
y_offset = 2;
else if (row == LXW_ROW_MAX - 3)
y_offset = 16;
else if (row == LXW_ROW_MAX - 2)
y_offset = 16;
else if (row == LXW_ROW_MAX - 1)
y_offset = 14;
else
y_offset = 10;
if (col == LXW_COL_MAX - 3)
x_offset = 49;
else if (col == LXW_COL_MAX - 2)
x_offset = 49;
else if (col == LXW_COL_MAX - 1)
x_offset = 49;
else
x_offset = 15;
if (row == 0)
start_row = 0;
else if (row == LXW_ROW_MAX - 3)
start_row = LXW_ROW_MAX - 7;
else if (row == LXW_ROW_MAX - 2)
start_row = LXW_ROW_MAX - 6;
else if (row == LXW_ROW_MAX - 1)
start_row = LXW_ROW_MAX - 5;
else
start_row = row - 1;
if (col == LXW_COL_MAX - 3)
start_col = LXW_COL_MAX - 6;
else if (col == LXW_COL_MAX - 2)
start_col = LXW_COL_MAX - 5;
else if (col == LXW_COL_MAX - 1)
start_col = LXW_COL_MAX - 4;
else
start_col = col + 1;
/* Set the default font properties. */
comment->font_size = 8;
comment->font_family = 2;
/* Set any user defined options. */
if (options) {
if (options->width > 0.0)
width = options->width;
if (options->height > 0.0)
height = options->height;
if (options->x_scale > 0.0)
x_scale = options->x_scale;
if (options->y_scale > 0.0)
y_scale = options->y_scale;
if (options->x_offset != 0)
x_offset = options->x_offset;
if (options->y_offset != 0)
y_offset = options->y_offset;
if (options->start_row > 0 || options->start_col > 0) {
start_row = options->start_row;
start_col = options->start_col;
}
if (options->font_size > 0.0)
comment->font_size = options->font_size;
if (options->font_family > 0)
comment->font_family = options->font_family;
comment->visible = options->visible;
comment->color = options->color;
comment->author = lxw_strdup(options->author);
comment->font_name = lxw_strdup(options->font_name);
}
/* Scale the width/height to the default/user scale and round to the
* nearest pixel. */
width = (uint32_t) (0.5 + x_scale * width);
height = (uint32_t) (0.5 + y_scale * height);
comment->width = width;
comment->height = height;
comment->start_col = start_col;
comment->start_row = start_row;
comment->x_offset = x_offset;
comment->y_offset = y_offset;
}
/*
* This function handles the additional optional parameters to
* worksheet_insert_button() as well as calculating the button object
* position and vertices.
*/
lxw_error
_get_button_params(lxw_vml_obj *button, uint16_t button_number,
lxw_button_options *options)
{
int32_t x_offset = 0;
int32_t y_offset = 0;
uint32_t height = LXW_DEF_ROW_HEIGHT_PIXELS;
uint32_t width = LXW_DEF_COL_WIDTH_PIXELS;
double x_scale = 1.0;
double y_scale = 1.0;
lxw_row_t row = button->row;
lxw_col_t col = button->col;
char buffer[LXW_ATTR_32];
uint8_t has_caption = LXW_FALSE;
uint8_t has_macro = LXW_FALSE;
size_t len;
/* Set any user defined options. */
if (options) {
if (options->width > 0.0)
width = options->width;
if (options->height > 0.0)
height = options->height;
if (options->x_scale > 0.0)
x_scale = options->x_scale;
if (options->y_scale > 0.0)
y_scale = options->y_scale;
if (options->x_offset != 0)
x_offset = options->x_offset;
if (options->y_offset != 0)
y_offset = options->y_offset;
if (options->caption) {
button->name = lxw_strdup(options->caption);
RETURN_ON_MEM_ERROR(button->name, LXW_ERROR_MEMORY_MALLOC_FAILED);
has_caption = LXW_TRUE;
}
if (options->macro) {
len = sizeof("[0]!") + strlen(options->macro);
button->macro = calloc(1, len);
RETURN_ON_MEM_ERROR(button->macro,
LXW_ERROR_MEMORY_MALLOC_FAILED);
if (button->macro)
lxw_snprintf(button->macro, len, "[0]!%s", options->macro);
has_macro = LXW_TRUE;
}
if (options->description) {
button->text = lxw_strdup(options->description);
RETURN_ON_MEM_ERROR(button->text, LXW_ERROR_MEMORY_MALLOC_FAILED);
}
}
if (!has_caption) {
lxw_snprintf(buffer, LXW_ATTR_32, "Button %d", button_number);
button->name = lxw_strdup(buffer);
RETURN_ON_MEM_ERROR(button->name, LXW_ERROR_MEMORY_MALLOC_FAILED);
}
if (!has_macro) {
lxw_snprintf(buffer, LXW_ATTR_32, "[0]!Button%d_Click",
button_number);
button->macro = lxw_strdup(buffer);
RETURN_ON_MEM_ERROR(button->macro, LXW_ERROR_MEMORY_MALLOC_FAILED);
}
/* Scale the width/height to the default/user scale and round to the
* nearest pixel. */
width = (uint32_t) (0.5 + x_scale * width);
height = (uint32_t) (0.5 + y_scale * height);
button->width = width;
button->height = height;
button->start_col = col;
button->start_row = row;
button->x_offset = x_offset;
button->y_offset = y_offset;
return LXW_NO_ERROR;
}
/*
* Calculate the vml_obj object position and vertices.
*/
void
_worksheet_position_vml_object(lxw_worksheet *self, lxw_vml_obj *vml_obj)
{
lxw_object_properties object_props;
lxw_drawing_object drawing_object;
object_props.col = vml_obj->start_col;
object_props.row = vml_obj->start_row;
object_props.x_offset = vml_obj->x_offset;
object_props.y_offset = vml_obj->y_offset;
object_props.width = vml_obj->width;
object_props.height = vml_obj->height;
drawing_object.anchor = LXW_OBJECT_DONT_MOVE_DONT_SIZE;
_worksheet_position_object_pixels(self, &object_props, &drawing_object);
vml_obj->from.col = drawing_object.from.col;
vml_obj->from.row = drawing_object.from.row;
vml_obj->from.col_offset = drawing_object.from.col_offset;
vml_obj->from.row_offset = drawing_object.from.row_offset;
vml_obj->to.col = drawing_object.to.col;
vml_obj->to.row = drawing_object.to.row;
vml_obj->to.col_offset = drawing_object.to.col_offset;
vml_obj->to.row_offset = drawing_object.to.row_offset;
vml_obj->col_absolute = drawing_object.col_absolute;
vml_obj->row_absolute = drawing_object.row_absolute;
}
/*
* Set up image/drawings.
*/
void
lxw_worksheet_prepare_image(lxw_worksheet *self,
uint32_t image_ref_id, uint32_t drawing_id,
lxw_object_properties *object_props)
{
lxw_drawing_object *drawing_object;
lxw_rel_tuple *relationship;
double width;
double height;
char *url;
char *found_string;
size_t i;
char filename[LXW_FILENAME_LENGTH];
enum cell_types link_type = HYPERLINK_URL;
if (!self->drawing) {
self->drawing = lxw_drawing_new();
self->drawing->embedded = LXW_TRUE;
RETURN_VOID_ON_MEM_ERROR(self->drawing);
relationship = calloc(1, sizeof(lxw_rel_tuple));
GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
relationship->type = lxw_strdup("/drawing");
GOTO_LABEL_ON_MEM_ERROR(relationship->type, mem_error);
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
"../drawings/drawing%d.xml", drawing_id);
relationship->target = lxw_strdup(filename);
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
STAILQ_INSERT_TAIL(self->external_drawing_links, relationship,
list_pointers);
}
drawing_object = calloc(1, sizeof(lxw_drawing_object));
RETURN_VOID_ON_MEM_ERROR(drawing_object);
drawing_object->anchor = LXW_OBJECT_MOVE_DONT_SIZE;
if (object_props->object_position)
drawing_object->anchor = object_props->object_position;
drawing_object->type = LXW_DRAWING_IMAGE;
drawing_object->description = lxw_strdup(object_props->description);
drawing_object->tip = lxw_strdup(object_props->tip);
drawing_object->rel_index = 0;
drawing_object->url_rel_index = 0;
drawing_object->decorative = object_props->decorative;
/* Scale to user scale. */
width = object_props->width * object_props->x_scale;
height = object_props->height * object_props->y_scale;
/* Scale by non 96dpi resolutions. */
width *= 96.0 / object_props->x_dpi;
height *= 96.0 / object_props->y_dpi;
object_props->width = width;
object_props->height = height;
_worksheet_position_object_emus(self, object_props, drawing_object);
/* Convert from pixels to emus. */
drawing_object->width = (uint32_t) (0.5 + width * 9525);
drawing_object->height = (uint32_t) (0.5 + height * 9525);
lxw_add_drawing_object(self->drawing, drawing_object);
if (object_props->url) {
url = object_props->url;
relationship = calloc(1, sizeof(lxw_rel_tuple));
GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
relationship->type = lxw_strdup("/hyperlink");
GOTO_LABEL_ON_MEM_ERROR(relationship->type, mem_error);
/* Check the link type. Default to external hyperlinks. */
if (strstr(url, "internal:"))
link_type = HYPERLINK_INTERNAL;
else if (strstr(url, "external:"))
link_type = HYPERLINK_EXTERNAL;
else
link_type = HYPERLINK_URL;
/* Set the relationship object for each type of link. */
if (link_type == HYPERLINK_INTERNAL) {
relationship->target_mode = NULL;
relationship->target = lxw_strdup(url + sizeof("internal") - 1);
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
/* We need to prefix the internal link/range with #. */
relationship->target[0] = '#';
}
else if (link_type == HYPERLINK_EXTERNAL) {
relationship->target_mode = lxw_strdup("External");
GOTO_LABEL_ON_MEM_ERROR(relationship->target_mode, mem_error);
/* Look for Windows style "C:/" link or Windows share "\\" link. */
found_string = strchr(url + sizeof("external:") - 1, ':');
if (!found_string)
found_string = strstr(url, "\\\\");
if (found_string) {
/* Copy the url with some space at the start to overwrite
* "external:" with "file:///". */
relationship->target = lxw_escape_url_characters(url + 1,
LXW_TRUE);
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
/* Add the file:/// URI to the url if absolute path. */
memcpy(relationship->target, "file:///",
sizeof("file:///") - 1);
}
else {
/* Copy the relative url without "external:". */
relationship->target =
lxw_escape_url_characters(url + sizeof("external:") - 1,
LXW_TRUE);
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
/* Switch backslash to forward slash. */
for (i = 0; i <= strlen(relationship->target); i++)
if (relationship->target[i] == '\\')
relationship->target[i] = '/';
}
}
else {
relationship->target_mode = lxw_strdup("External");
GOTO_LABEL_ON_MEM_ERROR(relationship->target_mode, mem_error);
relationship->target =
lxw_escape_url_characters(object_props->url, LXW_FALSE);
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
}
/* Check if URL exceeds Excel's length limit. */
if (lxw_utf8_strlen(url) > self->max_url_length) {
LXW_WARN_FORMAT2("worksheet_insert_image()/_opt(): URL exceeds "
"Excel's allowable length of %d characters: %s",
self->max_url_length, url);
goto mem_error;
}
if (!_find_drawing_rel_index(self, url)) {
STAILQ_INSERT_TAIL(self->drawing_links, relationship,
list_pointers);
}
else {
free(relationship->type);
free(relationship->target);
free(relationship->target_mode);
free(relationship);
}
drawing_object->url_rel_index = _get_drawing_rel_index(self, url);
}
if (!_find_drawing_rel_index(self, object_props->md5)) {
relationship = calloc(1, sizeof(lxw_rel_tuple));
GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
relationship->type = lxw_strdup("/image");
GOTO_LABEL_ON_MEM_ERROR(relationship->type, mem_error);
lxw_snprintf(filename, 32, "../media/image%d.%s", image_ref_id,
object_props->extension);
relationship->target = lxw_strdup(filename);
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
STAILQ_INSERT_TAIL(self->drawing_links, relationship, list_pointers);
}
drawing_object->rel_index =
_get_drawing_rel_index(self, object_props->md5);
return;
mem_error:
if (relationship) {
free(relationship->type);
free(relationship->target);
free(relationship->target_mode);
free(relationship);
}
}
/*
* Set up image/drawings for header/footer images.
*/
void
lxw_worksheet_prepare_header_image(lxw_worksheet *self,
uint32_t image_ref_id,
lxw_object_properties *object_props)
{
lxw_rel_tuple *relationship = NULL;
char filename[LXW_FILENAME_LENGTH];
lxw_vml_obj *header_image_vml;
char *extension;
STAILQ_INSERT_TAIL(self->image_props, object_props, list_pointers);
if (!_find_vml_drawing_rel_index(self, object_props->md5)) {
relationship = calloc(1, sizeof(lxw_rel_tuple));
RETURN_VOID_ON_MEM_ERROR(relationship);
relationship->type = lxw_strdup("/image");
GOTO_LABEL_ON_MEM_ERROR(relationship->type, mem_error);
lxw_snprintf(filename, 32, "../media/image%d.%s", image_ref_id,
object_props->extension);
relationship->target = lxw_strdup(filename);
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
STAILQ_INSERT_TAIL(self->vml_drawing_links, relationship,
list_pointers);
}
header_image_vml = calloc(1, sizeof(lxw_vml_obj));
GOTO_LABEL_ON_MEM_ERROR(header_image_vml, mem_error);
header_image_vml->width = (uint32_t) object_props->width;
header_image_vml->height = (uint32_t) object_props->height;
header_image_vml->x_dpi = object_props->x_dpi;
header_image_vml->y_dpi = object_props->y_dpi;
header_image_vml->rel_index = 1;
header_image_vml->image_position =
lxw_strdup(object_props->image_position);
header_image_vml->name = lxw_strdup(object_props->description);
/* Strip the extension from the filename. */
extension = strchr(header_image_vml->name, '.');
if (extension)
*extension = '\0';
header_image_vml->rel_index =
_get_vml_drawing_rel_index(self, object_props->md5);
STAILQ_INSERT_TAIL(self->header_image_objs, header_image_vml,
list_pointers);
return;
mem_error:
if (relationship) {
free(relationship->type);
free(relationship->target);
free(relationship->target_mode);
free(relationship);
}
}
/*
* Set up background image.
*/
void
lxw_worksheet_prepare_background(lxw_worksheet *self,
uint32_t image_ref_id,
lxw_object_properties *object_props)
{
lxw_rel_tuple *relationship = NULL;
char filename[LXW_FILENAME_LENGTH];
STAILQ_INSERT_TAIL(self->image_props, object_props, list_pointers);
relationship = calloc(1, sizeof(lxw_rel_tuple));
RETURN_VOID_ON_MEM_ERROR(relationship);
relationship->type = lxw_strdup("/image");
GOTO_LABEL_ON_MEM_ERROR(relationship->type, mem_error);
lxw_snprintf(filename, 32, "../media/image%d.%s", image_ref_id,
object_props->extension);
relationship->target = lxw_strdup(filename);
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
self->external_background_link = relationship;
return;
mem_error:
if (relationship) {
free(relationship->type);
free(relationship->target);
free(relationship->target_mode);
free(relationship);
}
}
/*
* Set up chart/drawings.
*/
void
lxw_worksheet_prepare_chart(lxw_worksheet *self,
uint32_t chart_ref_id,
uint32_t drawing_id,
lxw_object_properties *object_props,
uint8_t is_chartsheet)
{
lxw_drawing_object *drawing_object;
lxw_rel_tuple *relationship;
double width;
double height;
char filename[LXW_FILENAME_LENGTH];
if (!self->drawing) {
self->drawing = lxw_drawing_new();
RETURN_VOID_ON_MEM_ERROR(self->drawing);
if (is_chartsheet) {
self->drawing->embedded = LXW_FALSE;
self->drawing->orientation = self->orientation;
}
else {
self->drawing->embedded = LXW_TRUE;
}
relationship = calloc(1, sizeof(lxw_rel_tuple));
GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
relationship->type = lxw_strdup("/drawing");
GOTO_LABEL_ON_MEM_ERROR(relationship->type, mem_error);
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
"../drawings/drawing%d.xml", drawing_id);
relationship->target = lxw_strdup(filename);
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
STAILQ_INSERT_TAIL(self->external_drawing_links, relationship,
list_pointers);
}
drawing_object = calloc(1, sizeof(lxw_drawing_object));
RETURN_VOID_ON_MEM_ERROR(drawing_object);
drawing_object->anchor = LXW_OBJECT_MOVE_AND_SIZE;
if (object_props->object_position)
drawing_object->anchor = object_props->object_position;
drawing_object->type = LXW_DRAWING_CHART;
drawing_object->description = lxw_strdup(object_props->description);
drawing_object->tip = NULL;
drawing_object->rel_index = _get_drawing_rel_index(self, NULL);
drawing_object->url_rel_index = 0;
drawing_object->decorative = object_props->decorative;
/* Scale to user scale. */
width = object_props->width * object_props->x_scale;
height = object_props->height * object_props->y_scale;
/* Convert to the nearest pixel. */
object_props->width = width;
object_props->height = height;
_worksheet_position_object_emus(self, object_props, drawing_object);
/* Convert from pixels to emus. */
drawing_object->width = (uint32_t) (0.5 + width * 9525);
drawing_object->height = (uint32_t) (0.5 + height * 9525);
lxw_add_drawing_object(self->drawing, drawing_object);
relationship = calloc(1, sizeof(lxw_rel_tuple));
GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
relationship->type = lxw_strdup("/chart");
GOTO_LABEL_ON_MEM_ERROR(relationship->type, mem_error);
lxw_snprintf(filename, 32, "../charts/chart%d.xml", chart_ref_id);
relationship->target = lxw_strdup(filename);
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
STAILQ_INSERT_TAIL(self->drawing_links, relationship, list_pointers);
return;
mem_error:
if (relationship) {
free(relationship->type);
free(relationship->target);
free(relationship->target_mode);
free(relationship);
}
}
/*
* Set up VML objects, such as comments, in the worksheet.
*/
uint32_t
lxw_worksheet_prepare_vml_objects(lxw_worksheet *self,
uint32_t vml_data_id,
uint32_t vml_shape_id,
uint32_t vml_drawing_id,
uint32_t comment_id)
{
lxw_row *row;
lxw_cell *cell;
lxw_rel_tuple *relationship;
char filename[LXW_FILENAME_LENGTH];
uint32_t comment_count = 0;
uint32_t i;
uint32_t tmp_data_id;
size_t data_str_len = 0;
size_t used = 0;
char *vml_data_id_str;
RB_FOREACH(row, lxw_table_rows, self->comments) {
RB_FOREACH(cell, lxw_table_cells, row->cells) {
/* Calculate the worksheet position of the comment. */
_worksheet_position_vml_object(self, cell->comment);
/* Store comment in a simple list for use by packager. */
STAILQ_INSERT_TAIL(self->comment_objs, cell->comment,
list_pointers);
comment_count++;
}
}
/* Set up the VML relationship for comments/buttons/header images. */
relationship = calloc(1, sizeof(lxw_rel_tuple));
GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
relationship->type = lxw_strdup("/vmlDrawing");
GOTO_LABEL_ON_MEM_ERROR(relationship->type, mem_error);
lxw_snprintf(filename, 32, "../drawings/vmlDrawing%d.vml",
vml_drawing_id);
relationship->target = lxw_strdup(filename);
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
self->external_vml_comment_link = relationship;
if (self->has_comments) {
/* Only need this relationship object for comment VMLs. */
relationship = calloc(1, sizeof(lxw_rel_tuple));
GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
relationship->type = lxw_strdup("/comments");
GOTO_LABEL_ON_MEM_ERROR(relationship->type, mem_error);
lxw_snprintf(filename, 32, "../comments%d.xml", comment_id);
relationship->target = lxw_strdup(filename);
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
self->external_comment_link = relationship;
}
/* The vml.c element data id contains a comma separated range
* when there is more than one 1024 block of comments, like this:
* data="1,2,3". Since this could potentially (but unlikely) exceed
* LXW_MAX_ATTRIBUTE_LENGTH we need to allocate space dynamically. */
/* Calculate the total space required for the ID for each 1024 block. */
for (i = 0; i <= comment_count / 1024; i++) {
tmp_data_id = vml_data_id + i;
/* Calculate the space required for the digits in the id. */
while (tmp_data_id) {
data_str_len++;
tmp_data_id /= 10;
}
/* Add an extra char for comma separator or '\O'. */
data_str_len++;
};
/* If this allocation fails it will be dealt with in packager.c. */
vml_data_id_str = calloc(1, data_str_len + 2);
GOTO_LABEL_ON_MEM_ERROR(vml_data_id_str, mem_error);
/* Create the CSV list in the allocated space. */
for (i = 0; i <= comment_count / 1024; i++) {
tmp_data_id = vml_data_id + i;
lxw_snprintf(vml_data_id_str + used, data_str_len - used, "%d,",
tmp_data_id);
used = strlen(vml_data_id_str);
};
self->vml_shape_id = vml_shape_id;
self->vml_data_id_str = vml_data_id_str;
return comment_count;
mem_error:
if (relationship) {
free(relationship->type);
free(relationship->target);
free(relationship->target_mode);
free(relationship);
}
return 0;
}
/*
* Set up external linkage for VML header/footer images.
*/
void
lxw_worksheet_prepare_header_vml_objects(lxw_worksheet *self,
uint32_t vml_header_id,
uint32_t vml_drawing_id)
{
lxw_rel_tuple *relationship;
char filename[LXW_FILENAME_LENGTH];
char *vml_data_id_str;
self->vml_header_id = vml_header_id;
/* Set up the VML relationship for header images. */
relationship = calloc(1, sizeof(lxw_rel_tuple));
GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
relationship->type = lxw_strdup("/vmlDrawing");
GOTO_LABEL_ON_MEM_ERROR(relationship->type, mem_error);
lxw_snprintf(filename, 32, "../drawings/vmlDrawing%d.vml",
vml_drawing_id);
relationship->target = lxw_strdup(filename);
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
self->external_vml_header_link = relationship;
/* If this allocation fails it will be dealt with in packager.c. */
vml_data_id_str = calloc(1, sizeof("4294967295"));
GOTO_LABEL_ON_MEM_ERROR(vml_data_id_str, mem_error);
lxw_snprintf(vml_data_id_str, sizeof("4294967295"), "%d", vml_header_id);
self->vml_header_id_str = vml_data_id_str;
return;
mem_error:
if (relationship) {
free(relationship->type);
free(relationship->target);
free(relationship->target_mode);
free(relationship);
}
return;
}
/*
* Set up external linkage for VML header/footer images.
*/
void
lxw_worksheet_prepare_tables(lxw_worksheet *self, uint32_t table_id)
{
lxw_table_obj *table_obj;
lxw_rel_tuple *relationship;
char name[LXW_ATTR_32];
char filename[LXW_FILENAME_LENGTH];
STAILQ_FOREACH(table_obj, self->table_objs, list_pointers) {
relationship = calloc(1, sizeof(lxw_rel_tuple));
GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
relationship->type = lxw_strdup("/table");
GOTO_LABEL_ON_MEM_ERROR(relationship->type, mem_error);
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
"../tables/table%d.xml", table_id);
relationship->target = lxw_strdup(filename);
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
STAILQ_INSERT_TAIL(self->external_table_links, relationship,
list_pointers);
if (!table_obj->name) {
lxw_snprintf(name, LXW_ATTR_32, "Table%d", table_id);
table_obj->name = lxw_strdup(name);
GOTO_LABEL_ON_MEM_ERROR(table_obj->name, mem_error);
}
table_obj->id = table_id;
table_id++;
}
return;
mem_error:
if (relationship) {
free(relationship->type);
free(relationship->target);
free(relationship->target_mode);
free(relationship);
}
return;
}
/*
* Extract width and height information from a PNG file.
*/
STATIC lxw_error
_process_png(lxw_object_properties *object_props)
{
uint32_t length;
uint32_t offset;
char type[4];
uint32_t width = 0;
uint32_t height = 0;
double x_dpi = 96;
double y_dpi = 96;
int fseek_err;
FILE *stream = object_props->stream;
/* Skip another 4 bytes to the end of the PNG header. */
fseek_err = fseek(stream, 4, SEEK_CUR);
if (fseek_err)
goto file_error;
while (!feof(stream)) {
/* Read the PNG length and type fields for the sub-section. */
if (fread(&length, sizeof(length), 1, stream) < 1)
break;
if (fread(&type, 1, 4, stream) < 4)
break;
/* Convert the length to network order. */
length = LXW_UINT32_NETWORK(length);
/* The offset for next fseek() is the field length + type length. */
offset = length + 4;
if (memcmp(type, "IHDR", 4) == 0) {
if (fread(&width, sizeof(width), 1, stream) < 1)
break;
if (fread(&height, sizeof(height), 1, stream) < 1)
break;
width = LXW_UINT32_NETWORK(width);
height = LXW_UINT32_NETWORK(height);
/* Reduce the offset by the length of previous freads(). */
offset -= 8;
}
if (memcmp(type, "pHYs", 4) == 0) {
uint32_t x_ppu = 0;
uint32_t y_ppu = 0;
uint8_t units = 1;
if (fread(&x_ppu, sizeof(x_ppu), 1, stream) < 1)
break;
if (fread(&y_ppu, sizeof(y_ppu), 1, stream) < 1)
break;
if (fread(&units, sizeof(units), 1, stream) < 1)
break;
if (units == 1) {
x_ppu = LXW_UINT32_NETWORK(x_ppu);
y_ppu = LXW_UINT32_NETWORK(y_ppu);
x_dpi = (double) x_ppu *0.0254;
y_dpi = (double) y_ppu *0.0254;
}
/* Reduce the offset by the length of previous freads(). */
offset -= 9;
}
if (memcmp(type, "IEND", 4) == 0)
break;
if (!feof(stream)) {
fseek_err = fseek(stream, offset, SEEK_CUR);
if (fseek_err)
goto file_error;
}
}
/* Ensure that we read some valid data from the file. */
if (width == 0)
goto file_error;
/* Set the image metadata. */
object_props->image_type = LXW_IMAGE_PNG;
object_props->width = width;
object_props->height = height;
object_props->x_dpi = x_dpi ? x_dpi : 96;
object_props->y_dpi = y_dpi ? y_dpi : 96;
object_props->extension = lxw_strdup("png");
return LXW_NO_ERROR;
file_error:
LXW_WARN_FORMAT1("worksheet image insertion: "
"no size data found in: %s.", object_props->filename);
return LXW_ERROR_IMAGE_DIMENSIONS;
}
/*
* Extract width and height information from a JPEG file.
*/
STATIC lxw_error
_process_jpeg(lxw_object_properties *image_props)
{
uint16_t length;
uint16_t marker;
uint32_t offset;
uint16_t width = 0;
uint16_t height = 0;
double x_dpi = 96;
double y_dpi = 96;
int fseek_err;
FILE *stream = image_props->stream;
/* Read back 2 bytes to the end of the initial 0xFFD8 marker. */
fseek_err = fseek(stream, -2, SEEK_CUR);
if (fseek_err)
goto file_error;
/* Search through the image data and read the JPEG markers. */
while (!feof(stream)) {
/* Read the JPEG marker and length fields for the sub-section. */
if (fread(&marker, sizeof(marker), 1, stream) < 1)
break;
if (fread(&length, sizeof(length), 1, stream) < 1)
break;
/* Convert the marker and length to network order. */
marker = LXW_UINT16_NETWORK(marker);
length = LXW_UINT16_NETWORK(length);
/* The offset for next fseek() is the field length + type length. */
offset = length - 2;
/* Read the height and width in the 0xFFCn elements (except C4, C8 */
/* and CC which aren't SOF markers). */
if ((marker & 0xFFF0) == 0xFFC0 && marker != 0xFFC4
&& marker != 0xFFC8 && marker != 0xFFCC) {
/* Skip 1 byte to height and width. */
fseek_err = fseek(stream, 1, SEEK_CUR);
if (fseek_err)
goto file_error;
if (fread(&height, sizeof(height), 1, stream) < 1)
break;
if (fread(&width, sizeof(width), 1, stream) < 1)
break;
height = LXW_UINT16_NETWORK(height);
width = LXW_UINT16_NETWORK(width);
offset -= 9;
}
/* Read the DPI in the 0xFFE0 element. */
if (marker == 0xFFE0) {
uint16_t x_density = 0;
uint16_t y_density = 0;
uint8_t units = 1;
fseek_err = fseek(stream, 7, SEEK_CUR);
if (fseek_err)
goto file_error;
if (fread(&units, sizeof(units), 1, stream) < 1)
break;
if (fread(&x_density, sizeof(x_density), 1, stream) < 1)
break;
if (fread(&y_density, sizeof(y_density), 1, stream) < 1)
break;
x_density = LXW_UINT16_NETWORK(x_density);
y_density = LXW_UINT16_NETWORK(y_density);
if (units == 1) {
x_dpi = x_density;
y_dpi = y_density;
}
if (units == 2) {
x_dpi = x_density * 2.54;
y_dpi = y_density * 2.54;
}
offset -= 12;
}
if (marker == 0xFFDA)
break;
if (!feof(stream)) {
fseek_err = fseek(stream, offset, SEEK_CUR);
if (fseek_err)
break;
}
}
/* Ensure that we read some valid data from the file. */
if (width == 0)
goto file_error;
/* Set the image metadata. */
image_props->image_type = LXW_IMAGE_JPEG;
image_props->width = width;
image_props->height = height;
image_props->x_dpi = x_dpi ? x_dpi : 96;
image_props->y_dpi = y_dpi ? y_dpi : 96;
image_props->extension = lxw_strdup("jpeg");
return LXW_NO_ERROR;
file_error:
LXW_WARN_FORMAT1("worksheet image insertion: "
"no size data found in: %s.", image_props->filename);
return LXW_ERROR_IMAGE_DIMENSIONS;
}
/*
* Extract width and height information from a BMP file.
*/
STATIC lxw_error
_process_bmp(lxw_object_properties *image_props)
{
uint32_t width = 0;
uint32_t height = 0;
double x_dpi = 96;
double y_dpi = 96;
int fseek_err;
FILE *stream = image_props->stream;
/* Skip another 14 bytes to the start of the BMP height/width. */
fseek_err = fseek(stream, 14, SEEK_CUR);
if (fseek_err)
goto file_error;
if (fread(&width, sizeof(width), 1, stream) < 1)
width = 0;
if (fread(&height, sizeof(height), 1, stream) < 1)
height = 0;
/* Ensure that we read some valid data from the file. */
if (width == 0)
goto file_error;
height = LXW_UINT32_HOST(height);
width = LXW_UINT32_HOST(width);
/* Set the image metadata. */
image_props->image_type = LXW_IMAGE_BMP;
image_props->width = width;
image_props->height = height;
image_props->x_dpi = x_dpi;
image_props->y_dpi = y_dpi;
image_props->extension = lxw_strdup("bmp");
return LXW_NO_ERROR;
file_error:
LXW_WARN_FORMAT1("worksheet image insertion: "
"no size data found in: %s.", image_props->filename);
return LXW_ERROR_IMAGE_DIMENSIONS;
}
/*
* Extract width and height information from a GIF file.
*/
STATIC lxw_error
_process_gif(lxw_object_properties *image_props)
{
uint16_t width = 0;
uint16_t height = 0;
double x_dpi = 96;
double y_dpi = 96;
int fseek_err;
FILE *stream = image_props->stream;
/* Skip another 2 bytes to the start of the GIF height/width. */
fseek_err = fseek(stream, 2, SEEK_CUR);
if (fseek_err)
goto file_error;
if (fread(&width, sizeof(width), 1, stream) < 1)
width = 0;
if (fread(&height, sizeof(height), 1, stream) < 1)
height = 0;
/* Ensure that we read some valid data from the file. */
if (width == 0)
goto file_error;
height = LXW_UINT16_HOST(height);
width = LXW_UINT16_HOST(width);
/* Set the image metadata. */
image_props->image_type = LXW_IMAGE_GIF;
image_props->width = width;
image_props->height = height;
image_props->x_dpi = x_dpi;
image_props->y_dpi = y_dpi;
image_props->extension = lxw_strdup("gif");
return LXW_NO_ERROR;
file_error:
LXW_WARN_FORMAT1("worksheet image insertion: "
"no size data found in: %s.", image_props->filename);
return LXW_ERROR_IMAGE_DIMENSIONS;
}
/*
* Extract information from the image file such as dimension, type, filename,
* and extension.
*/
STATIC lxw_error
_get_image_properties(lxw_object_properties *image_props)
{
unsigned char signature[4];
#ifndef USE_NO_MD5
uint8_t i;
MD5_CTX md5_context;
size_t size_read;
char buffer[LXW_IMAGE_BUFFER_SIZE];
unsigned char md5_checksum[LXW_MD5_SIZE];
#endif
/* Read 4 bytes to look for the file header/signature. */
if (fread(signature, 1, 4, image_props->stream) < 4) {
LXW_WARN_FORMAT1("worksheet image insertion: "
"couldn't read image type for: %s.",
image_props->filename);
return LXW_ERROR_IMAGE_DIMENSIONS;
}
if (memcmp(&signature[1], "PNG", 3) == 0) {
if (_process_png(image_props) != LXW_NO_ERROR)
return LXW_ERROR_IMAGE_DIMENSIONS;
}
else if (signature[0] == 0xFF && signature[1] == 0xD8) {
if (_process_jpeg(image_props) != LXW_NO_ERROR)
return LXW_ERROR_IMAGE_DIMENSIONS;
}
else if (memcmp(signature, "BM", 2) == 0) {
if (_process_bmp(image_props) != LXW_NO_ERROR)
return LXW_ERROR_IMAGE_DIMENSIONS;
}
else if (memcmp(signature, "GIF8", 4) == 0) {
if (_process_gif(image_props) != LXW_NO_ERROR)
return LXW_ERROR_IMAGE_DIMENSIONS;
}
else {
LXW_WARN_FORMAT1("worksheet image insertion: "
"unsupported image format for: %s.",
image_props->filename);
return LXW_ERROR_IMAGE_DIMENSIONS;
}
#ifndef USE_NO_MD5
/* Calculate an MD5 checksum for the image so that we can remove duplicate
* images to reduce the xlsx file size.*/
rewind(image_props->stream);
MD5_Init(&md5_context);
size_read = fread(buffer, 1, LXW_IMAGE_BUFFER_SIZE, image_props->stream);
while (size_read) {
MD5_Update(&md5_context, buffer, (unsigned long) size_read);
size_read =
fread(buffer, 1, LXW_IMAGE_BUFFER_SIZE, image_props->stream);
}
MD5_Final(md5_checksum, &md5_context);
/* Create a 32 char hex string buffer for the MD5 checksum. */
image_props->md5 = calloc(1, LXW_MD5_SIZE * 2 + 1);
/* If this calloc fails we just return and don't remove duplicates. */
RETURN_ON_MEM_ERROR(image_props->md5, LXW_NO_ERROR);
/* Convert the 16 byte MD5 buffer to a 32 char hex string. */
for (i = 0; i < LXW_MD5_SIZE; i++) {
lxw_snprintf(&image_props->md5[2 * i], 3, "%02x", md5_checksum[i]);
}
#endif
return LXW_NO_ERROR;
}
/* Conditional formats that refer to the same cell sqref range, like A or
* B1:B9, need to be written as part of one xml structure. Therefore we need
* to store them in a RB hash/tree keyed by sqref. Within the RB hash element
* we then store conditional formats that refer to sqref in a STAILQ list. */
lxw_error
_store_conditional_format_object(lxw_worksheet *self,
lxw_cond_format_obj *cond_format)
{
lxw_cond_format_hash_element tmp_hash_element;
lxw_cond_format_hash_element *found_hash_element = NULL;
lxw_cond_format_hash_element *new_hash_element = NULL;
/* Create a temp hash element to do the lookup. */
LXW_ATTRIBUTE_COPY(tmp_hash_element.sqref, cond_format->sqref);
found_hash_element = RB_FIND(lxw_cond_format_hash,
self->conditional_formats,
&tmp_hash_element);
if (found_hash_element) {
/* If the RB element exists then add the conditional format to the
* list for the sqref range.*/
STAILQ_INSERT_TAIL(found_hash_element->cond_formats, cond_format,
list_pointers);
}
else {
/* Create a new RB hash element. */
new_hash_element = calloc(1, sizeof(lxw_cond_format_hash_element));
GOTO_LABEL_ON_MEM_ERROR(new_hash_element, mem_error);
/* Use the sqref as the key. */
LXW_ATTRIBUTE_COPY(new_hash_element->sqref, cond_format->sqref);
/* Also create the list where we store the cond format objects. */
new_hash_element->cond_formats =
calloc(1, sizeof(struct lxw_cond_format_list));
GOTO_LABEL_ON_MEM_ERROR(new_hash_element->cond_formats, mem_error);
/* Initialize the list and add the conditional format object. */
STAILQ_INIT(new_hash_element->cond_formats);
STAILQ_INSERT_TAIL(new_hash_element->cond_formats, cond_format,
list_pointers);
/* Now insert the RB hash element into the tree. */
RB_INSERT(lxw_cond_format_hash, self->conditional_formats,
new_hash_element);
}
return LXW_NO_ERROR;
mem_error:
free(new_hash_element);
return LXW_ERROR_MEMORY_MALLOC_FAILED;
}
/*****************************************************************************
*
* XML file assembly functions.
*
****************************************************************************/
/*
* Write out a number worksheet cell. Doesn't use the xml functions as an
* optimization in the inner cell writing loop.
*/
STATIC void
_write_number_cell(lxw_worksheet *self, char *range,
int32_t style_index, lxw_cell *cell)
{
#ifdef USE_DTOA_LIBRARY
char data[LXW_ATTR_32];
lxw_sprintf_dbl(data, cell->u.number);
if (style_index)
fprintf(self->file,
"%s",
range, style_index, data);
else
fprintf(self->file, "%s", range, data);
#else
if (style_index)
fprintf(self->file,
"%.16G",
range, style_index, cell->u.number);
else
fprintf(self->file,
"%.16G", range, cell->u.number);
#endif
}
/*
* Write out a string worksheet cell. Doesn't use the xml functions as an
* optimization in the inner cell writing loop.
*/
STATIC void
_write_string_cell(lxw_worksheet *self, char *range,
int32_t style_index, lxw_cell *cell)
{
if (style_index)
fprintf(self->file,
"%d",
range, style_index, cell->u.string_id);
else
fprintf(self->file,
"%d",
range, cell->u.string_id);
}
/*
* Write out an inline string. Doesn't use the xml functions as an
* optimization in the inner cell writing loop.
*/
STATIC void
_write_inline_string_cell(lxw_worksheet *self, char *range,
int32_t style_index, lxw_cell *cell)
{
char *string = lxw_escape_data(cell->u.string);
/* Add attribute to preserve leading or trailing whitespace. */
if (isspace((unsigned char) string[0])
|| isspace((unsigned char) string[strlen(string) - 1])) {
if (style_index)
fprintf(self->file,
""
"%s",
range, style_index, string);
else
fprintf(self->file,
""
"%s",
range, string);
}
else {
if (style_index)
fprintf(self->file,
""
"%s", range, style_index, string);
else
fprintf(self->file,
""
"%s", range, string);
}
free(string);
}
/*
* Write out an inline rich string. Doesn't use the xml functions as an
* optimization in the inner cell writing loop.
*/
STATIC void
_write_inline_rich_string_cell(lxw_worksheet *self, char *range,
int32_t style_index, lxw_cell *cell)
{
const char *string = cell->u.string;
if (style_index)
fprintf(self->file,
""
"%s", range, style_index, string);
else
fprintf(self->file,
""
"%s", range, string);
}
/*
* Write out a formula worksheet cell with a numeric result.
*/
STATIC void
_write_formula_num_cell(lxw_worksheet *self, lxw_cell *cell)
{
char data[LXW_ATTR_32];
lxw_sprintf_dbl(data, cell->formula_result);
lxw_xml_data_element(self->file, "f", cell->u.string, NULL);
lxw_xml_data_element(self->file, "v", data, NULL);
}
/*
* Write out a formula worksheet cell with a numeric result.
*/
STATIC void
_write_formula_str_cell(lxw_worksheet *self, lxw_cell *cell)
{
lxw_xml_data_element(self->file, "f", cell->u.string, NULL);
lxw_xml_data_element(self->file, "v", cell->user_data2, NULL);
}
/*
* Write out an array formula worksheet cell with a numeric result.
*/
STATIC void
_write_array_formula_num_cell(lxw_worksheet *self, lxw_cell *cell)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char data[LXW_ATTR_32];
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("t", "array");
LXW_PUSH_ATTRIBUTES_STR("ref", cell->user_data1);
lxw_sprintf_dbl(data, cell->formula_result);
lxw_xml_data_element(self->file, "f", cell->u.string, &attributes);
lxw_xml_data_element(self->file, "v", data, NULL);
LXW_FREE_ATTRIBUTES();
}
/*
* Write out a boolean worksheet cell.
*/
STATIC void
_write_boolean_cell(lxw_worksheet *self, lxw_cell *cell)
{
char data[LXW_ATTR_32];
if (cell->u.number == 0.0)
data[0] = '0';
else
data[0] = '1';
data[1] = '\0';
lxw_xml_data_element(self->file, "v", data, NULL);
}
/*
* Calculate the "spans" attribute of the tag. This is an XLSX
* optimization and isn't strictly required. However, it makes comparing
* files easier.
*
* The span is the same for each block of 16 rows.
*/
STATIC void
_calculate_spans(struct lxw_row *row, char *span, int32_t *block_num)
{
lxw_cell *cell_min = RB_MIN(lxw_table_cells, row->cells);
lxw_cell *cell_max = RB_MAX(lxw_table_cells, row->cells);
lxw_col_t span_col_min = cell_min->col_num;
lxw_col_t span_col_max = cell_max->col_num;
lxw_col_t col_min;
lxw_col_t col_max;
*block_num = row->row_num / 16;
row = RB_NEXT(lxw_table_rows, root, row);
while (row && (int32_t) (row->row_num / 16) == *block_num) {
if (!RB_EMPTY(row->cells)) {
cell_min = RB_MIN(lxw_table_cells, row->cells);
cell_max = RB_MAX(lxw_table_cells, row->cells);
col_min = cell_min->col_num;
col_max = cell_max->col_num;
if (col_min < span_col_min)
span_col_min = col_min;
if (col_max > span_col_max)
span_col_max = col_max;
}
row = RB_NEXT(lxw_table_rows, root, row);
}
lxw_snprintf(span, LXW_MAX_CELL_RANGE_LENGTH,
"%d:%d", span_col_min + 1, span_col_max + 1);
}
/*
* Write out a generic worksheet cell.
*/
STATIC void
_write_cell(lxw_worksheet *self, lxw_cell *cell, lxw_format *row_format)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char range[LXW_MAX_CELL_NAME_LENGTH] = { 0 };
lxw_row_t row_num = cell->row_num;
lxw_col_t col_num = cell->col_num;
int32_t style_index = 0;
lxw_rowcol_to_cell(range, row_num, col_num);
if (cell->format) {
style_index = lxw_format_get_xf_index(cell->format);
}
else if (row_format) {
style_index = lxw_format_get_xf_index(row_format);
}
else if (col_num < self->col_formats_max && self->col_formats[col_num]) {
style_index = lxw_format_get_xf_index(self->col_formats[col_num]);
}
/* Unrolled optimization for most commonly written cell types. */
if (cell->type == NUMBER_CELL) {
_write_number_cell(self, range, style_index, cell);
return;
}
if (cell->type == STRING_CELL) {
_write_string_cell(self, range, style_index, cell);
return;
}
if (cell->type == INLINE_STRING_CELL) {
_write_inline_string_cell(self, range, style_index, cell);
return;
}
if (cell->type == INLINE_RICH_STRING_CELL) {
_write_inline_rich_string_cell(self, range, style_index, cell);
return;
}
/* For other cell types use the general functions. */
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("r", range);
if (style_index)
LXW_PUSH_ATTRIBUTES_INT("s", style_index);
if (cell->type == FORMULA_CELL) {
/* If user_data2 is set then the formula has a string result. */
if (cell->user_data2)
LXW_PUSH_ATTRIBUTES_STR("t", "str");
lxw_xml_start_tag(self->file, "c", &attributes);
if (cell->user_data2)
_write_formula_str_cell(self, cell);
else
_write_formula_num_cell(self, cell);
lxw_xml_end_tag(self->file, "c");
}
else if (cell->type == BLANK_CELL) {
if (cell->format)
lxw_xml_empty_tag(self->file, "c", &attributes);
}
else if (cell->type == BOOLEAN_CELL) {
LXW_PUSH_ATTRIBUTES_STR("t", "b");
lxw_xml_start_tag(self->file, "c", &attributes);
_write_boolean_cell(self, cell);
lxw_xml_end_tag(self->file, "c");
}
else if (cell->type == ARRAY_FORMULA_CELL) {
lxw_xml_start_tag(self->file, "c", &attributes);
_write_array_formula_num_cell(self, cell);
lxw_xml_end_tag(self->file, "c");
}
else if (cell->type == DYNAMIC_ARRAY_FORMULA_CELL) {
LXW_PUSH_ATTRIBUTES_STR("cm", "1");
lxw_xml_start_tag(self->file, "c", &attributes);
_write_array_formula_num_cell(self, cell);
lxw_xml_end_tag(self->file, "c");
}
LXW_FREE_ATTRIBUTES();
}
/*
* Write out the worksheet data as a series of rows and cells.
*/
STATIC void
_worksheet_write_rows(lxw_worksheet *self)
{
lxw_row *row;
lxw_cell *cell;
int32_t block_num = -1;
char spans[LXW_MAX_CELL_RANGE_LENGTH] = { 0 };
RB_FOREACH(row, lxw_table_rows, self->table) {
if (RB_EMPTY(row->cells)) {
/* Row contains no cells but has height, format or other data. */
/* Write a default span for default rows. */
if (self->default_row_set)
_write_row(self, row, "1:1");
else
_write_row(self, row, NULL);
}
else {
/* Row and cell data. */
if ((int32_t) row->row_num / 16 > block_num)
_calculate_spans(row, spans, &block_num);
_write_row(self, row, spans);
if (row->data_changed) {
RB_FOREACH(cell, lxw_table_cells, row->cells) {
_write_cell(self, cell, row->format);
}
lxw_xml_end_tag(self->file, "row");
}
}
}
}
/*
* Write out the worksheet data as a single row with cells. This method is
* used when memory optimization is on. A single row is written and the data
* array is reset. That way only one row of data is kept in memory at any one
* time. We don't write span data in the optimized case since it is optional.
*/
void
lxw_worksheet_write_single_row(lxw_worksheet *self)
{
lxw_row *row = self->optimize_row;
lxw_col_t col;
/* skip row if it doesn't contain row formatting, cell data or a comment. */
if (!(row->row_changed || row->data_changed))
return;
/* Write the cells if the row contains data. */
if (!row->data_changed) {
/* Row data only. No cells. */
_write_row(self, row, NULL);
}
else {
/* Row and cell data. */
_write_row(self, row, NULL);
for (col = self->dim_colmin; col <= self->dim_colmax; col++) {
if (self->array[col]) {
_write_cell(self, self->array[col], row->format);
_free_cell(self->array[col]);
self->array[col] = NULL;
}
}
lxw_xml_end_tag(self->file, "row");
}
/* Reset the row. */
row->height = LXW_DEF_ROW_HEIGHT;
row->format = NULL;
row->hidden = LXW_FALSE;
row->level = 0;
row->collapsed = LXW_FALSE;
row->data_changed = LXW_FALSE;
row->row_changed = LXW_FALSE;
}
/* Process a header/footer image and store it in the correct slot. */
lxw_error
_worksheet_set_header_footer_image(lxw_worksheet *self, const char *filename,
uint8_t image_position)
{
FILE *image_stream;
const char *description;
lxw_object_properties *object_props;
char *image_strings[] = { "LH", "CH", "RH", "LF", "CF", "RF" };
/* Not all slots will have image files. */
if (!filename)
return LXW_NO_ERROR;
/* Check that the image file exists and can be opened. */
image_stream = lxw_fopen(filename, "rb");
if (!image_stream) {
LXW_WARN_FORMAT1("worksheet_set_header_opt/footer_opt(): "
"file doesn't exist or can't be opened: %s.",
filename);
return LXW_ERROR_PARAMETER_VALIDATION;
}
/* Use the filename as the default description, like Excel. */
description = lxw_basename(filename);
if (!description) {
LXW_WARN_FORMAT1("worksheet_set_header_opt/footer_opt(): "
"couldn't get basename for file: %s.", filename);
fclose(image_stream);
return LXW_ERROR_PARAMETER_VALIDATION;
}
/* Create a new object to hold the image properties. */
object_props = calloc(1, sizeof(lxw_object_properties));
if (!object_props) {
fclose(image_stream);
return LXW_ERROR_MEMORY_MALLOC_FAILED;
}
/* Copy other options or set defaults. */
object_props->filename = lxw_strdup(filename);
object_props->description = lxw_strdup(description);
object_props->stream = image_stream;
/* Set VML image position string based on the header/footer/position. */
object_props->image_position = lxw_strdup(image_strings[image_position]);
if (_get_image_properties(object_props) == LXW_NO_ERROR) {
*self->header_footer_objs[image_position] = object_props;
self->has_header_vml = LXW_TRUE;
fclose(image_stream);
return LXW_NO_ERROR;
}
else {
_free_object_properties(object_props);
fclose(image_stream);
return LXW_ERROR_IMAGE_DIMENSIONS;
}
}
/*
* Write the