Forráskód Böngészése

Style(Config.w32): Format

viest 6 éve
szülő
commit
b1a74ec0bf

+ 0 - 1
.gitignore

@@ -16,7 +16,6 @@ config.sub
 configure
 configure.ac
 configure.in
-include
 install-sh
 libtool
 ltmain.sh

+ 131 - 0
include/crypt.h

@@ -0,0 +1,131 @@
+/* crypt.h -- base code for crypt/uncrypt ZIPfile
+
+
+   Version 1.01e, February 12th, 2005
+
+   Copyright (C) 1998-2005 Gilles Vollant
+
+   This code is a modified version of crypting code in Infozip distribution
+
+   The encryption/decryption parts of this source code (as opposed to the
+   non-echoing password parts) were originally written in Europe.  The
+   whole source package can be freely distributed, including from the USA.
+   (Prior to January 2000, re-export from the US was a violation of US law.)
+
+   This encryption code is a direct transcription of the algorithm from
+   Roger Schlafly, described by Phil Katz in the file appnote.txt.  This
+   file (appnote.txt) is distributed with the PKZIP program (even in the
+   version without encryption capabilities).
+
+   If you don't need crypting in your application, just define symbols
+   NOCRYPT and NOUNCRYPT.
+
+   This code support the "Traditional PKWARE Encryption".
+
+   The new AES encryption added on Zip format by Winzip (see the page
+   http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
+   Encryption is not supported.
+*/
+
+#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
+
+/***********************************************************************
+ * Return the next byte in the pseudo-random sequence
+ */
+static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab)
+{
+    unsigned temp;  /* POTENTIAL BUG:  temp*(temp^1) may overflow in an
+                     * unpredictable manner on 16-bit systems; not a problem
+                     * with any known compiler so far, though */
+
+    temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;
+    return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
+}
+
+/***********************************************************************
+ * Update the encryption keys with the next byte of plain text
+ */
+static int update_keys(unsigned long* pkeys,const z_crc_t* pcrc_32_tab,int c)
+{
+    (*(pkeys+0)) = CRC32((*(pkeys+0)), c);
+    (*(pkeys+1)) += (*(pkeys+0)) & 0xff;
+    (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
+    {
+      register int keyshift = (int)((*(pkeys+1)) >> 24);
+      (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
+    }
+    return c;
+}
+
+
+/***********************************************************************
+ * Initialize the encryption keys and the random header according to
+ * the given password.
+ */
+static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t* pcrc_32_tab)
+{
+    *(pkeys+0) = 305419896L;
+    *(pkeys+1) = 591751049L;
+    *(pkeys+2) = 878082192L;
+    while (*passwd != '\0') {
+        update_keys(pkeys,pcrc_32_tab,(int)*passwd);
+        passwd++;
+    }
+}
+
+#define zdecode(pkeys,pcrc_32_tab,c) \
+    (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))
+
+#define zencode(pkeys,pcrc_32_tab,c,t) \
+    (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c))
+
+#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED
+
+#define RAND_HEAD_LEN  12
+   /* "last resort" source for second part of crypt seed pattern */
+#  ifndef ZCR_SEED2
+#    define ZCR_SEED2 3141592654UL     /* use PI as default pattern */
+#  endif
+
+static int crypthead(const char* passwd,      /* password string */
+                     unsigned char* buf,      /* where to write header */
+                     int bufSize,
+                     unsigned long* pkeys,
+                     const z_crc_t* pcrc_32_tab,
+                     unsigned long crcForCrypting)
+{
+    int n;                       /* index in random header */
+    int t;                       /* temporary */
+    int c;                       /* random byte */
+    unsigned char header[RAND_HEAD_LEN-2]; /* random header */
+    static unsigned calls = 0;   /* ensure different random header each time */
+
+    if (bufSize<RAND_HEAD_LEN)
+      return 0;
+
+    /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
+     * output of rand() to get less predictability, since rand() is
+     * often poorly implemented.
+     */
+    if (++calls == 1)
+    {
+        srand((unsigned)(time(NULL) ^ ZCR_SEED2));
+    }
+    init_keys(passwd, pkeys, pcrc_32_tab);
+    for (n = 0; n < RAND_HEAD_LEN-2; n++)
+    {
+        c = (rand() >> 7) & 0xff;
+        header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);
+    }
+    /* Encrypt random header (last two bytes is high word of crc) */
+    init_keys(passwd, pkeys, pcrc_32_tab);
+    for (n = 0; n < RAND_HEAD_LEN-2; n++)
+    {
+        buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);
+    }
+    buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);
+    buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);
+    return n;
+}
+
+#endif

+ 208 - 0
include/ioapi.h

@@ -0,0 +1,208 @@
+/* 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)
+
+*/
+
+#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 <stdio.h>
+#include <stdlib.h>
+#include "zlib.h"
+
+#if defined(USE_FILE32API)
+#define fopen64 fopen
+#define ftello64 ftell
+#define fseeko64 fseek
+#else
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+#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 <stdint.h>
+    #define ZPOS64_T uint64_t
+  #endif
+#endif
+*/
+
+#ifdef HAVE_MINIZIP64_CONF_H
+#include "mz64conf.h"
+#endif
+
+/* a type choosen 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
+
+/* Maximum unsigned 32-bit value used as placeholder for zip64 */
+#define MAXU32 0xffffffff
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef unsigned __int64 ZPOS64_T;
+#else
+typedef unsigned long long int ZPOS64_T;
+#endif
+#endif
+#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)      OF((voidpf opaque, const char* filename, int mode));
+typedef uLong    (ZCALLBACK *read_file_func)      OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+typedef uLong    (ZCALLBACK *write_file_func)     OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
+typedef int      (ZCALLBACK *close_file_func)     OF((voidpf opaque, voidpf stream));
+typedef int      (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
+
+typedef long     (ZCALLBACK *tell_file_func)      OF((voidpf opaque, voidpf stream));
+typedef long     (ZCALLBACK *seek_file_func)      OF((voidpf opaque, voidpf stream, uLong offset, int origin));
+
+
+/* here is the "old" 32 bits structure 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)    OF((voidpf opaque, voidpf stream));
+typedef long     (ZCALLBACK *seek64_file_func)    OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
+typedef voidpf   (ZCALLBACK *open64_file_func)    OF((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 OF((zlib_filefunc64_def* pzlib_filefunc_def));
+void fill_fopen_filefunc OF((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 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode));
+long    call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin));
+ZPOS64_T call_ztell64 OF((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

+ 28 - 0
include/iowin32.h

@@ -0,0 +1,28 @@
+/* iowin32.h -- IO base function header for compress/uncompress .zip
+     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
+
+*/
+
+#include <windows.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
+void fill_win32_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def));
+void fill_win32_filefunc64A OF((zlib_filefunc64_def* pzlib_filefunc_def));
+void fill_win32_filefunc64W OF((zlib_filefunc64_def* pzlib_filefunc_def));
+
+#ifdef __cplusplus
+}
+#endif

+ 37 - 0
include/mztools.h

@@ -0,0 +1,37 @@
+/*
+  Additional tools for Minizip
+  Code: Xavier Roche '2004
+  License: Same as ZLIB (www.gzip.org)
+*/
+
+#ifndef _zip_tools_H
+#define _zip_tools_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#include "unzip.h"
+
+/* Repair a ZIP file (missing central directory)
+   file: file to recover
+   fileOut: output file after recovery
+   fileOutTmp: temporary file name used for recovery
+*/
+extern int ZEXPORT unzRepair(const char* file,
+                             const char* fileOut,
+                             const char* fileOutTmp,
+                             uLong* nRecovered,
+                             uLong* bytesRecovered);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif

+ 53 - 0
include/tmpfileplus.h

@@ -0,0 +1,53 @@
+/* $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
+ * <http://www.di-mgt.com.au/contact/>.
+ */
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#ifndef TMPFILEPLUS_H_
+#define TMPFILEPLUS_H_
+
+#include <stdio.h>
+
+/** 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_ */

+ 437 - 0
include/unzip.h

@@ -0,0 +1,437 @@
+/* unzip.h -- IO for uncompress .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 of Unzip for Zip64
+         Copyright (C) 2007-2008 Even Rouault
+
+         Modifications for Zip64 support on both zip and unzip
+         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 unzip64.c
+
+*/
+
+#ifndef _unz64_H
+#define _unz64_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#ifndef  _ZLIBIOAPI_H
+#include "ioapi.h"
+#endif
+
+#ifdef HAVE_BZIP2
+#include "bzlib.h"
+#endif
+
+#define Z_BZIP2ED 12
+
+#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+    from (void*) without cast */
+typedef struct TagunzFile__ { int unused; } unzFile__;
+typedef unzFile__ *unzFile;
+#else
+typedef voidp unzFile;
+#endif
+
+
+#define UNZ_OK                          (0)
+#define UNZ_END_OF_LIST_OF_FILE         (-100)
+#define UNZ_ERRNO                       (Z_ERRNO)
+#define UNZ_EOF                         (0)
+#define UNZ_PARAMERROR                  (-102)
+#define UNZ_BADZIPFILE                  (-103)
+#define UNZ_INTERNALERROR               (-104)
+#define UNZ_CRCERROR                    (-105)
+
+/* tm_unz contain date/time info */
+typedef struct tm_unz_s
+{
+    uInt tm_sec;            /* seconds after the minute - [0,59] */
+    uInt tm_min;            /* minutes after the hour - [0,59] */
+    uInt tm_hour;           /* hours since midnight - [0,23] */
+    uInt tm_mday;           /* day of the month - [1,31] */
+    uInt tm_mon;            /* months since January - [0,11] */
+    uInt tm_year;           /* years - [1980..2044] */
+} tm_unz;
+
+/* unz_global_info structure contain global data about the ZIPfile
+   These data comes from the end of central dir */
+typedef struct unz_global_info64_s
+{
+    ZPOS64_T number_entry;         /* total number of entries in
+                                     the central dir on this disk */
+    uLong size_comment;         /* size of the global comment of the zipfile */
+} unz_global_info64;
+
+typedef struct unz_global_info_s
+{
+    uLong number_entry;         /* total number of entries in
+                                     the central dir on this disk */
+    uLong size_comment;         /* size of the global comment of the zipfile */
+} unz_global_info;
+
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_info64_s
+{
+    uLong version;              /* version made by                 2 bytes */
+    uLong version_needed;       /* version needed to extract       2 bytes */
+    uLong flag;                 /* general purpose bit flag        2 bytes */
+    uLong compression_method;   /* compression method              2 bytes */
+    uLong dosDate;              /* last mod file date in Dos fmt   4 bytes */
+    uLong crc;                  /* crc-32                          4 bytes */
+    ZPOS64_T compressed_size;   /* compressed size                 8 bytes */
+    ZPOS64_T uncompressed_size; /* uncompressed size               8 bytes */
+    uLong size_filename;        /* filename length                 2 bytes */
+    uLong size_file_extra;      /* extra field length              2 bytes */
+    uLong size_file_comment;    /* file comment length             2 bytes */
+
+    uLong disk_num_start;       /* disk number start               2 bytes */
+    uLong internal_fa;          /* internal file attributes        2 bytes */
+    uLong external_fa;          /* external file attributes        4 bytes */
+
+    tm_unz tmu_date;
+} unz_file_info64;
+
+typedef struct unz_file_info_s
+{
+    uLong version;              /* version made by                 2 bytes */
+    uLong version_needed;       /* version needed to extract       2 bytes */
+    uLong flag;                 /* general purpose bit flag        2 bytes */
+    uLong compression_method;   /* compression method              2 bytes */
+    uLong dosDate;              /* last mod file date in Dos fmt   4 bytes */
+    uLong crc;                  /* crc-32                          4 bytes */
+    uLong compressed_size;      /* compressed size                 4 bytes */
+    uLong uncompressed_size;    /* uncompressed size               4 bytes */
+    uLong size_filename;        /* filename length                 2 bytes */
+    uLong size_file_extra;      /* extra field length              2 bytes */
+    uLong size_file_comment;    /* file comment length             2 bytes */
+
+    uLong disk_num_start;       /* disk number start               2 bytes */
+    uLong internal_fa;          /* internal file attributes        2 bytes */
+    uLong external_fa;          /* external file attributes        4 bytes */
+
+    tm_unz tmu_date;
+} unz_file_info;
+
+extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
+                                                 const char* fileName2,
+                                                 int iCaseSensitivity));
+/*
+   Compare two filename (fileName1,fileName2).
+   If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+   If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+                                or strcasecmp)
+   If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+    (like 1 on Unix, 2 on Windows)
+*/
+
+
+extern unzFile ZEXPORT unzOpen OF((const char *path));
+extern unzFile ZEXPORT unzOpen64 OF((const void *path));
+/*
+  Open a Zip file. path contain the full pathname (by example,
+     on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer
+     "zlib/zlib113.zip".
+     If the zipfile cannot be opened (file don't exist or in not valid), the
+       return value is NULL.
+     Else, the return value is a unzFile Handle, usable with other function
+       of this unzip package.
+     the "64" function take a const void* pointer, because the path is just the
+       value passed to the open64_file_func callback.
+     Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path
+       is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char*
+       does not describe the reality
+*/
+
+
+extern unzFile ZEXPORT unzOpen2 OF((const char *path,
+                                    zlib_filefunc_def* pzlib_filefunc_def));
+/*
+   Open a Zip file, like unzOpen, but provide a set of file low level API
+      for read/write the zip file (see ioapi.h)
+*/
+
+extern unzFile ZEXPORT unzOpen2_64 OF((const void *path,
+                                    zlib_filefunc64_def* pzlib_filefunc_def));
+/*
+   Open a Zip file, like unz64Open, but provide a set of file low level API
+      for read/write the zip file (see ioapi.h)
+*/
+
+extern int ZEXPORT unzClose OF((unzFile file));
+/*
+  Close a ZipFile opened with unzOpen.
+  If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
+    these files MUST be closed with unzCloseCurrentFile before call unzClose.
+  return UNZ_OK if there is no problem. */
+
+extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
+                                        unz_global_info *pglobal_info));
+
+extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file,
+                                        unz_global_info64 *pglobal_info));
+/*
+  Write info about the ZipFile in the *pglobal_info structure.
+  No preparation of the structure is needed
+  return UNZ_OK if there is no problem. */
+
+
+extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
+                                           char *szComment,
+                                           uLong uSizeBuf));
+/*
+  Get the global comment string of the ZipFile, in the szComment buffer.
+  uSizeBuf is the size of the szComment buffer.
+  return the number of byte copied or an error code <0
+*/
+
+
+/***************************************************************************/
+/* Unzip package allow you browse the directory of the zipfile */
+
+extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
+/*
+  Set the current file of the zipfile to the first file.
+  return UNZ_OK if there is no problem
+*/
+
+extern int ZEXPORT unzGoToNextFile OF((unzFile file));
+/*
+  Set the current file of the zipfile to the next file.
+  return UNZ_OK if there is no problem
+  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+
+extern int ZEXPORT unzLocateFile OF((unzFile file,
+                     const char *szFileName,
+                     int iCaseSensitivity));
+/*
+  Try locate the file szFileName in the zipfile.
+  For the iCaseSensitivity signification, see unzStringFileNameCompare
+
+  return value :
+  UNZ_OK if the file is found. It becomes the current file.
+  UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+
+
+/* ****************************************** */
+/* Ryan supplied functions */
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_pos_s
+{
+    uLong pos_in_zip_directory;   /* offset in zip file directory */
+    uLong num_of_file;            /* # of file */
+} unz_file_pos;
+
+extern int ZEXPORT unzGetFilePos(
+    unzFile file,
+    unz_file_pos* file_pos);
+
+extern int ZEXPORT unzGoToFilePos(
+    unzFile file,
+    unz_file_pos* file_pos);
+
+typedef struct unz64_file_pos_s
+{
+    ZPOS64_T pos_in_zip_directory;   /* offset in zip file directory */
+    ZPOS64_T num_of_file;            /* # of file */
+} unz64_file_pos;
+
+extern int ZEXPORT unzGetFilePos64(
+    unzFile file,
+    unz64_file_pos* file_pos);
+
+extern int ZEXPORT unzGoToFilePos64(
+    unzFile file,
+    const unz64_file_pos* file_pos);
+
+/* ****************************************** */
+
+extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file,
+                         unz_file_info64 *pfile_info,
+                         char *szFileName,
+                         uLong fileNameBufferSize,
+                         void *extraField,
+                         uLong extraFieldBufferSize,
+                         char *szComment,
+                         uLong commentBufferSize));
+
+extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
+                         unz_file_info *pfile_info,
+                         char *szFileName,
+                         uLong fileNameBufferSize,
+                         void *extraField,
+                         uLong extraFieldBufferSize,
+                         char *szComment,
+                         uLong commentBufferSize));
+/*
+  Get Info about the current file
+  if pfile_info!=NULL, the *pfile_info structure will contain somes info about
+        the current file
+  if szFileName!=NULL, the filemane string will be copied in szFileName
+            (fileNameBufferSize is the size of the buffer)
+  if extraField!=NULL, the extra field information will be copied in extraField
+            (extraFieldBufferSize is the size of the buffer).
+            This is the Central-header version of the extra field
+  if szComment!=NULL, the comment string of the file will be copied in szComment
+            (commentBufferSize is the size of the buffer)
+*/
+
+
+/** Addition for GDAL : START */
+
+extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file));
+
+/** Addition for GDAL : END */
+
+
+/***************************************************************************/
+/* for reading the content of the current zipfile, you can open it, read data
+   from it, and close it (you can close it before reading all the file)
+   */
+
+extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
+/*
+  Open for reading data the current file in the zipfile.
+  If there is no error, the return value is UNZ_OK.
+*/
+
+extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file,
+                                                  const char* password));
+/*
+  Open for reading data the current file in the zipfile.
+  password is a crypting password
+  If there is no error, the return value is UNZ_OK.
+*/
+
+extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,
+                                           int* method,
+                                           int* level,
+                                           int raw));
+/*
+  Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
+    if raw==1
+  *method will receive method of compression, *level will receive level of
+     compression
+  note : you can set level parameter as NULL (if you did not want known level,
+         but you CANNOT set method parameter as NULL
+*/
+
+extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,
+                                           int* method,
+                                           int* level,
+                                           int raw,
+                                           const char* password));
+/*
+  Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
+    if raw==1
+  *method will receive method of compression, *level will receive level of
+     compression
+  note : you can set level parameter as NULL (if you did not want known level,
+         but you CANNOT set method parameter as NULL
+*/
+
+
+extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
+/*
+  Close the file in zip opened with unzOpenCurrentFile
+  Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+
+extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
+                      voidp buf,
+                      unsigned len));
+/*
+  Read bytes from the current file (opened by unzOpenCurrentFile)
+  buf contain buffer where data must be copied
+  len the size of buf.
+
+  return the number of byte copied if somes bytes are copied
+  return 0 if the end of file was reached
+  return <0 with error code if there is an error
+    (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+
+extern z_off_t ZEXPORT unztell OF((unzFile file));
+
+extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file));
+/*
+  Give the current position in uncompressed data
+*/
+
+extern int ZEXPORT unzeof OF((unzFile file));
+/*
+  return 1 if the end of file was reached, 0 elsewhere
+*/
+
+extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
+                                             voidp buf,
+                                             unsigned len));
+/*
+  Read extra field from the current file (opened by unzOpenCurrentFile)
+  This is the local-header version of the extra field (sometimes, there is
+    more info in the local-header version than in the central-header)
+
+  if buf==NULL, it return the size of the local extra field
+
+  if buf!=NULL, len is the size of the buffer, the extra header is copied in
+    buf.
+  the return value is the number of bytes copied in buf, or (if <0)
+    the error code
+*/
+
+/***************************************************************************/
+
+/* Get the current file offset */
+extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file);
+extern uLong ZEXPORT unzGetOffset (unzFile file);
+
+/* Set the current file offset */
+extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos);
+extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _unz64_H */

+ 23 - 0
include/xlsxwriter.h

@@ -0,0 +1,23 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. 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 "0.7.7"
+
+#endif /* __LXW_XLSXWRITER_H__ */

+ 79 - 0
include/xlsxwriter/app.h

@@ -0,0 +1,79 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. See LICENSE.txt.
+ *
+ * app - A libxlsxwriter library for creating Excel XLSX app files.
+ *
+ */
+#ifndef __LXW_APP_H__
+#define __LXW_APP_H__
+
+#include <stdint.h>
+#include <string.h>
+#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;
+
+} lxw_app;
+
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* *INDENT-ON* */
+
+lxw_app *lxw_app_new();
+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__ */

+ 3577 - 0
include/xlsxwriter/chart.h

@@ -0,0 +1,3577 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. 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 <stdint.h>
+#include <string.h>
+
+#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,
+
+    /** 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 overlaid at right side. */
+    LXW_CHART_LEGEND_OVERLAY_RIGHT,
+
+    /** Chart legend overlaid at left side. */
+    LXW_CHART_LEGEND_OVERLAY_LEFT
+} 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 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;
+
+    /* Members for internal use only. */
+    uint8_t has_color;
+
+} 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;
+
+    /* Members for internal use only. */
+    uint8_t has_color;
+
+} 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;
+
+    /* Members for internal use only. */
+    uint8_t has_fg_color;
+    uint8_t has_bg_color;
+
+} 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". */
+    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. */
+    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;
+
+    /* Members for internal use only. */
+
+    uint8_t has_color;
+
+} 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 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;
+    uint16_t point_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_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 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_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 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;
+
+    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!$B1$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_labels1.png
+ *
+ * By default data labels are displayed in Excel with only the values shown:
+ *
+ * @image html chart_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_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 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_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_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_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_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_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_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 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!$B1$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 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 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!$B1$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 = {.bold = LXW_TRUE, .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
+ *
+ * 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_OVERLAY_RIGHT
+ *     LXW_CHART_LEGEND_OVERLAY_LEFT
+ *
+ * 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__ */

+ 380 - 0
include/xlsxwriter/common.h

@@ -0,0 +1,380 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. See LICENSE.txt.
+ */
+
+/**
+ * @file common.h
+ *
+ * @brief Common functions and defines for the libxlsxwriter library.
+ *
+ * <!-- Copyright 2014-2018, John McNamara, [email protected] -->
+ *
+ */
+#ifndef __LXW_COMMON_H__
+#define __LXW_COMMON_H__
+
+#include <time.h>
+#include "third_party/queue.h"
+#include "third_party/tree.h"
+
+#ifndef TESTING
+#define STATIC static
+#else
+#define STATIC
+#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
+};
+
+/**
+ * @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,
+
+    /** Zlib error with a file operation while creating xlsx file. */
+    LXW_ERROR_ZIP_FILE_OPERATION,
+
+    /** Zlib error when adding sub file to xlsx file. */
+    LXW_ERROR_ZIP_FILE_ADD,
+
+    /** Zlib error when closing xlsx file. */
+    LXW_ERROR_ZIP_CLOSE,
+
+    /** 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 contains invalid Excel character: '[]:*?/\\' */
+    LXW_ERROR_INVALID_SHEETNAME_CHARACTER,
+
+    /** 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 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
+};
+
+/* 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")
+
+#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_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"
+
+#define LXW_ERROR(message)                      \
+    fprintf(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) \
+    if (!pointer) {                             \
+        LXW_MEM_ERROR();                        \
+        goto label;                             \
+    }
+
+#define RETURN_ON_MEM_ERROR(pointer, error)     \
+    if (!pointer) {                             \
+        LXW_MEM_ERROR();                        \
+        return error;                           \
+    }
+
+#define RETURN_VOID_ON_MEM_ERROR(pointer)       \
+    if (!pointer) {                             \
+        LXW_MEM_ERROR();                        \
+        return;                                 \
+    }
+
+#define RETURN_ON_ERROR(error)                  \
+    if (error)                                  \
+        return error;
+
+#define LXW_WARN(message)                       \
+    fprintf(stderr, "[WARNING]: " message "\n")
+
+/* We can't use variadic macros here since we support ANSI C. */
+#define LXW_WARN_FORMAT(message)                \
+    fprintf(stderr, "[WARNING]: " message "\n")
+
+#define LXW_WARN_FORMAT1(message, var)          \
+    fprintf(stderr, "[WARNING]: " message "\n", var)
+
+#define LXW_WARN_FORMAT2(message, var1, var2)    \
+    fprintf(stderr, "[WARNING]: " message "\n", var1, var2)
+
+/* Chart axis type checks. */
+#define LXW_WARN_CAT_AXIS_ONLY(function)                                   \
+    if (!axis->is_category) {                                              \
+        fprintf(stderr, "[WARNING]: "                                      \
+                function "() is only valid for category axes\n");          \
+       return;                                                             \
+    }
+
+#define LXW_WARN_VALUE_AXIS_ONLY(function)                                 \
+    if (!axis->is_value) {                                                 \
+        fprintf(stderr, "[WARNING]: "                                      \
+                function "() is only valid for value axes\n");             \
+       return;                                                             \
+    }
+
+#define LXW_WARN_DATE_AXIS_ONLY(function)                                  \
+    if (!axis->is_date) {                                                  \
+        fprintf(stderr, "[WARNING]: "                                      \
+                function "() is only valid for date axes\n");              \
+       return;                                                             \
+    }
+
+#define LXW_WARN_CAT_AND_DATE_AXIS_ONLY(function)                          \
+    if (!axis->is_category && !axis->is_date) {                            \
+        fprintf(stderr, "[WARNING]: "                                      \
+                function "() is only valid for category and date axes\n"); \
+       return;                                                             \
+    }
+
+#define LXW_WARN_VALUE_AND_DATE_AXIS_ONLY(function)                        \
+    if (!axis->is_value && !axis->is_date) {                               \
+        fprintf(stderr, "[WARNING]: "                                      \
+                function "() is only valid for value and date axes\n");    \
+       return;                                                             \
+    }
+
+#ifndef LXW_BIG_ENDIAN
+#define LXW_UINT32_NETWORK(n) ((((n) & 0xFF)       << 24) | \
+                               (((n) & 0xFF00)     <<  8) | \
+                               (((n) & 0xFF0000)   >>  8) | \
+                               (((n) & 0xFF000000) >> 24))
+#define LXW_UINT16_NETWORK(n) ((((n) & 0x00FF) << 8) | (((n) & 0xFF00) >> 8))
+#define LXW_UINT32_HOST(n)    (n)
+#else
+#define LXW_UINT32_NETWORK(n) (n)
+#define LXW_UINT16_NETWORK(n) (n)
+#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 <stdarg.h>
+#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__ */

+ 74 - 0
include/xlsxwriter/content_types.h

@@ -0,0 +1,74 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. 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 <stdint.h>
+#include <string.h>
+
+#include "common.h"
+
+#define LXW_APP_PACKAGE  "application/vnd.openxmlformats-package."
+#define LXW_APP_DOCUMENT "application/vnd.openxmlformats-officedocument."
+
+/*
+ * 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 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_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_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);
+
+/* 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__ */

+ 51 - 0
include/xlsxwriter/core.h

@@ -0,0 +1,51 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. See LICENSE.txt.
+ *
+ * core - A libxlsxwriter library for creating Excel XLSX core files.
+ *
+ */
+#ifndef __LXW_CORE_H__
+#define __LXW_CORE_H__
+
+#include <stdint.h>
+
+#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 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__ */

+ 52 - 0
include/xlsxwriter/custom.h

@@ -0,0 +1,52 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. See LICENSE.txt.
+ *
+ * custom - A libxlsxwriter library for creating Excel custom property files.
+ *
+ */
+#ifndef __LXW_CUSTOM_H__
+#define __LXW_CUSTOM_H__
+
+#include <stdint.h>
+
+#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 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__ */

+ 111 - 0
include/xlsxwriter/drawing.h

@@ -0,0 +1,111 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. See LICENSE.txt.
+ *
+ * drawing - A libxlsxwriter library for creating Excel XLSX drawing files.
+ *
+ */
+#ifndef __LXW_DRAWING_H__
+#define __LXW_DRAWING_H__
+
+#include <stdint.h>
+
+#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 lxw_anchor_types {
+    LXW_ANCHOR_TYPE_NONE = 0,
+    LXW_ANCHOR_TYPE_IMAGE,
+    LXW_ANCHOR_TYPE_CHART
+};
+
+enum lxw_anchor_edit_types {
+    LXW_ANCHOR_EDIT_AS_NONE = 0,
+    LXW_ANCHOR_EDIT_AS_RELATIVE,
+    LXW_ANCHOR_EDIT_AS_ONE_CELL,
+    LXW_ANCHOR_EDIT_AS_ABSOLUTE
+};
+
+enum image_types {
+    LXW_IMAGE_UNKNOWN = 0,
+    LXW_IMAGE_PNG,
+    LXW_IMAGE_JPEG,
+    LXW_IMAGE_BMP
+};
+
+/* 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 anchor_type;
+    uint8_t edit_as;
+    struct lxw_drawing_coords from;
+    struct lxw_drawing_coords to;
+    uint32_t col_absolute;
+    uint32_t row_absolute;
+    uint32_t width;
+    uint32_t height;
+    uint8_t shape;
+    char *description;
+    char *url;
+    char *tip;
+
+    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;
+
+    struct lxw_drawing_objects *drawing_objects;
+
+} lxw_drawing;
+
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* *INDENT-ON* */
+
+lxw_drawing *lxw_drawing_new();
+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__ */

+ 1214 - 0
include/xlsxwriter/format.h

@@ -0,0 +1,1214 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. 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 <stdint.h>
+#include <string.h>
+#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 int32_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                 -1
+#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 {
+    /** Single underline */
+    LXW_UNDERLINE_SINGLE = 1,
+
+    /** 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
+};
+
+enum lxw_format_diagonal_types {
+    LXW_DIAGONAL_BORDER_UP = 1,
+    LXW_DIAGONAL_BORDER_DOWN,
+    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;
+    uint16_t *num_xf_formats;
+
+    int32_t xf_index;
+    int32_t dxf_index;
+
+    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;
+    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;
+
+    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 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 lxw_format_free(lxw_format *format);
+int32_t lxw_format_get_xf_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);
+
+lxw_color_t lxw_format_check_color(lxw_color_t color);
+
+/**
+ * @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
+ *
+ * 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(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().
+ */
+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);
+
+void format_set_diag_type(lxw_format *format, uint8_t value);
+void format_set_diag_color(lxw_format *format, lxw_color_t color);
+void format_set_diag_border(lxw_format *format, uint8_t value);
+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);
+
+/* Declarations required for unit testing. */
+#ifdef TESTING
+
+#endif /* TESTING */
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+}
+#endif
+/* *INDENT-ON* */
+
+#endif /* __LXW_FORMAT_H__ */

+ 76 - 0
include/xlsxwriter/hash_table.h

@@ -0,0 +1,76 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. 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__ */

+ 85 - 0
include/xlsxwriter/packager.h

@@ -0,0 +1,85 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. See LICENSE.txt.
+ *
+ * packager - A libxlsxwriter library for creating Excel XLSX packager files.
+ *
+ */
+#ifndef __LXW_PACKAGER_H__
+#define __LXW_PACKAGER_H__
+
+#include <stdint.h>
+
+#ifdef USE_SYSTEM_MINIZIP
+#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 "theme.h"
+#include "styles.h"
+#include "format.h"
+#include "content_types.h"
+#include "relationships.h"
+
+#define LXW_ZIP_BUFFER_SIZE (16384)
+
+/* If zlib returns Z_ERRNO then errno is set and we can trap that. Otherwise
+ * return a default libxlsxwriter error. */
+#define RETURN_ON_ZIP_ERROR(err, default_err)   \
+    if (err == Z_ERRNO)                         \
+        return LXW_ERROR_ZIP_FILE_OPERATION;    \
+    else                                        \
+        return default_err;
+
+/*
+ * Struct to represent a packager.
+ */
+typedef struct lxw_packager {
+
+    FILE *file;
+    lxw_workbook *workbook;
+
+    size_t buffer_size;
+    zipFile zipfile;
+    zip_fileinfo zipfile_info;
+    char *filename;
+    char *buffer;
+    char *tmpdir;
+
+    uint16_t chart_count;
+    uint16_t drawing_count;
+
+} lxw_packager;
+
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* *INDENT-ON* */
+
+lxw_packager *lxw_packager_new(const char *filename, char *tmpdir);
+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__ */

+ 77 - 0
include/xlsxwriter/relationships.h

@@ -0,0 +1,77 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. See LICENSE.txt.
+ *
+ * relationships - A libxlsxwriter library for creating Excel XLSX
+ *                 relationships files.
+ *
+ */
+#ifndef __LXW_RELATIONSHIPS_H__
+#define __LXW_RELATIONSHIPS_H__
+
+#include <stdint.h>
+
+#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 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__ */

+ 83 - 0
include/xlsxwriter/shared_strings.h

@@ -0,0 +1,83 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. See LICENSE.txt.
+ *
+ * shared_strings - A libxlsxwriter library for creating Excel XLSX
+ *                  sst files.
+ *
+ */
+#ifndef __LXW_SST_H__
+#define __LXW_SST_H__
+
+#include <string.h>
+#include <stdint.h>
+
+#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;
+
+    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 lxw_sst_free(lxw_sst *sst);
+struct sst_element *lxw_get_sst_index(lxw_sst *sst, const char *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__ */

+ 77 - 0
include/xlsxwriter/styles.h

@@ -0,0 +1,77 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. See LICENSE.txt.
+ *
+ * styles - A libxlsxwriter library for creating Excel XLSX styles files.
+ *
+ */
+#ifndef __LXW_STYLES_H__
+#define __LXW_STYLES_H__
+
+#include <stdint.h>
+
+#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;
+
+} lxw_styles;
+
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* *INDENT-ON* */
+
+lxw_styles *lxw_styles_new();
+void lxw_styles_free(lxw_styles *styles);
+void lxw_styles_assemble_xml_file(lxw_styles *self);
+
+/* 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);
+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);
+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);
+STATIC void _write_borders(lxw_styles *self);
+STATIC void _write_style_xf(lxw_styles *self);
+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);
+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__ */

+ 47 - 0
include/xlsxwriter/theme.h

@@ -0,0 +1,47 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. See LICENSE.txt.
+ *
+ * theme - A libxlsxwriter library for creating Excel XLSX theme files.
+ *
+ */
+#ifndef __LXW_THEME_H__
+#define __LXW_THEME_H__
+
+#include <stdint.h>
+
+#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 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__ */

+ 214 - 0
include/xlsxwriter/third_party/ioapi.h

@@ -0,0 +1,214 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include "zlib.h"
+
+#if defined(USE_FILE32API)
+#define fopen64 fopen
+#define ftello64 ftell
+#define fseeko64 fseek
+#else
+#ifdef __FreeBSD__
+#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 <stdint.h>
+    #define ZPOS64_T uint64_t
+  #endif
+#endif
+*/
+
+#ifdef HAVE_MINIZIP64_CONF_H
+#include "mz64conf.h"
+#endif
+
+/* a type choosen 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
+
+/* Maximum unsigned 32-bit value used as placeholder for zip64 */
+#define MAXU32 0xffffffff
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef unsigned __int64 ZPOS64_T;
+#else
+typedef unsigned long long int ZPOS64_T;
+#endif
+#endif
+#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)      OF((voidpf opaque, const char* filename, int mode));
+typedef uLong    (ZCALLBACK *read_file_func)      OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+typedef uLong    (ZCALLBACK *write_file_func)     OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
+typedef int      (ZCALLBACK *close_file_func)     OF((voidpf opaque, voidpf stream));
+typedef int      (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
+
+typedef long     (ZCALLBACK *tell_file_func)      OF((voidpf opaque, voidpf stream));
+typedef long     (ZCALLBACK *seek_file_func)      OF((voidpf opaque, voidpf stream, uLong offset, int origin));
+
+
+/* here is the "old" 32 bits structure 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)    OF((voidpf opaque, voidpf stream));
+typedef long     (ZCALLBACK *seek64_file_func)    OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
+typedef voidpf   (ZCALLBACK *open64_file_func)    OF((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 OF((zlib_filefunc64_def* pzlib_filefunc_def));
+void fill_fopen_filefunc OF((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 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode));
+long    call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin));
+ZPOS64_T call_ztell64 OF((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

+ 694 - 0
include/xlsxwriter/third_party/queue.h

@@ -0,0 +1,694 @@
+/*-
+ * 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 <sys/cdefs.h> */
+
+/*
+ * 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_ */

+ 53 - 0
include/xlsxwriter/third_party/tmpfileplus.h

@@ -0,0 +1,53 @@
+/* $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
+ * <http://www.di-mgt.com.au/contact/>.
+ */
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#ifndef TMPFILEPLUS_H_
+#define TMPFILEPLUS_H_
+
+#include <stdio.h>
+
+/** 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_ */

+ 801 - 0
include/xlsxwriter/third_party/tree.h

@@ -0,0 +1,801 @@
+/*	$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 <[email protected]>
+ * 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 <sys/cdefs.h> */
+
+/*
+ * 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_ */

+ 375 - 0
include/xlsxwriter/third_party/zip.h

@@ -0,0 +1,375 @@
+/* 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
+{
+    uInt tm_sec;            /* seconds after the minute - [0,59] */
+    uInt tm_min;            /* minutes after the hour - [0,59] */
+    uInt tm_hour;           /* hours since midnight - [0,23] */
+    uInt tm_mday;           /* day of the month - [1,31] */
+    uInt tm_mon;            /* months since January - [0,11] */
+    uInt 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 OF((const char *pathname, int append));
+extern zipFile ZEXPORT zipOpen64 OF((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 couse, you can use RAW reading and writing to copy the file you did not want delte
+*/
+
+extern zipFile ZEXPORT zipOpen2 OF((const char *pathname,
+                                   int append,
+                                   zipcharpc* globalcomment,
+                                   zlib_filefunc_def* pzlib_filefunc_def));
+
+extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname,
+                                   int append,
+                                   zipcharpc* globalcomment,
+                                   zlib_filefunc64_def* pzlib_filefunc_def));
+
+extern int ZEXPORT zipOpenNewFileInZip OF((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 OF((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 the the local header
+  if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global
+    contains the extrafield data the the local 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 OF((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 OF((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 OF((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 OF((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 OF((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 OF((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 OF((zipFile file,
+                       const void* buf,
+                       unsigned len));
+/*
+  Write data in the zipfile
+*/
+
+extern int ZEXPORT zipCloseFileInZip OF((zipFile file));
+/*
+  Close the current file in the zipfile
+*/
+
+extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file,
+                                            uLong uncompressed_size,
+                                            uLong crc32));
+
+extern int ZEXPORT zipCloseFileInZipRaw64 OF((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 OF((zipFile file,
+                const char* global_comment));
+/*
+  Close the zipfile
+*/
+
+
+extern int ZEXPORT zipRemoveExtraInfoBlock OF((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 */

+ 172 - 0
include/xlsxwriter/utility.h

@@ -0,0 +1,172 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. See LICENSE.txt.
+ */
+
+/**
+ * @file utility.h
+ *
+ * @brief Utility functions for libxlsxwriter.
+ *
+ * <!-- Copyright 2014-2018, John McNamara, [email protected] -->
+ *
+ */
+
+#ifndef __LXW_UTILITY_H__
+#define __LXW_UTILITY_H__
+
+#include <stdint.h>
+#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 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);
+
+double lxw_datetime_to_excel_date(lxw_datetime *datetime, 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);
+
+FILE *lxw_tmpfile(char *tmpdir);
+
+/* Use a user defined function to format doubles in sprintf or else a simple
+ * macro (the default). */
+#ifdef USE_DOUBLE_FUNCTION
+int lxw_sprintf_dbl(char *data, double number);
+#else
+#define lxw_sprintf_dbl(data, number) \
+        lxw_snprintf(data, LXW_ATTR_32, "%.16g", number)
+#endif
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+}
+#endif
+/* *INDENT-ON* */
+
+#endif /* __LXW_UTILITY_H__ */

+ 751 - 0
include/xlsxwriter/workbook.h

@@ -0,0 +1,751 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. 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 <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "worksheet.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);
+
+/* Define the queue.h structs for the workbook lists. */
+STAILQ_HEAD(lxw_worksheets, lxw_worksheet);
+STAILQ_HEAD(lxw_charts, lxw_chart);
+TAILQ_HEAD(lxw_defined_names, lxw_defined_name);
+
+/* 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;
+
+/* 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_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_names{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.
+ */
+typedef struct lxw_doc_properties {
+    /** The title of the Excel Document. */
+    char *title;
+
+    /** The subject of the Excel Document. */
+    char *subject;
+
+    /** The author of the Excel Document. */
+    char *author;
+
+    /** The manager field of the Excel Document. */
+    char *manager;
+
+    /** The company field of the Excel Document. */
+    char *company;
+
+    /** The category of the Excel Document. */
+    char *category;
+
+    /** The keywords of the Excel Document. */
+    char *keywords;
+
+    /** The comment field of the Excel Document. */
+    char *comments;
+
+    /** The status of the Excel Document. */
+    char *status;
+
+    /** The hyperlink base url of the Excel Document. */
+    char *hyperlink_base;
+
+    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`: Reduces the amount of data stored in memory so that
+ *   large files can be written efficiently.
+ *
+ *   @note In this mode a row of data is written and then discarded when a
+ *   cell in a new row is added via one of the `worksheet_write_*()`
+ *   functions. Therefore, once this option is active, data should be written in
+ *   sequential row order. For this reason the `worksheet_merge_range()`
+ *   doesn't work in this mode. See also @ref ww_mem_constant.
+ *
+ * - `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 `tempdir` option.
+ */
+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. */
+    char *tmpdir;
+} lxw_workbook_options;
+
+/**
+ * @brief Struct to represent an Excel workbook.
+ *
+ * The members of the lxw_workbook struct aren't modified directly. Instead
+ * the workbook properties are set by calling the functions shown in
+ * workbook.h.
+ */
+typedef struct lxw_workbook {
+
+    FILE *file;
+    struct lxw_worksheets *worksheets;
+    struct lxw_worksheet_names *worksheet_names;
+    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 first_sheet;
+    uint16_t active_sheet;
+    uint16_t num_xf_formats;
+    uint16_t num_format_count;
+    uint16_t drawing_count;
+
+    uint16_t font_count;
+    uint16_t border_count;
+    uint16_t fill_count;
+    uint8_t optimize;
+
+    uint8_t has_png;
+    uint8_t has_jpeg;
+    uint8_t has_bmp;
+
+    lxw_hash_table *used_xf_formats;
+
+} lxw_workbook;
+
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* *INDENT-ON* */
+
+/**
+ * @brief Create a new workbook object.
+ *
+ * @param filename The name of the new Excel file to create.
+ *
+ * @return A lxw_workbook instance.
+ *
+ * The `%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 = 1,
+ *                                    .tmpdir = "C:\\Temp"};
+ *
+ *    lxw_workbook  *workbook  = workbook_new_opt("filename.xlsx", &options);
+ * @endcode
+ *
+ * The options that can be set via #lxw_workbook_options are:
+ *
+ * - `constant_memory`: Reduces the amount of data stored in memory so that
+ *   large files can be written efficiently.
+ *
+ *   @note In this mode a row of data is written and then discarded when a
+ *   cell in a new row is added via one of the `worksheet_write_*()`
+ *   functions. Therefore, once this option is active, data should be written in
+ *   sequential row order. For this reason the `worksheet_merge_range()`
+ *   doesn't work in this mode. See also @ref ww_mem_constant.
+ *
+ * - `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 `tempdir` option.*
+ *
+ * See @ref working_with_memory for more details.
+ *
+ */
+lxw_workbook *workbook_new_opt(const char *filename,
+                               lxw_workbook_options *options);
+
+/* Deprecated function name for backwards compatibility. */
+lxw_workbook *new_workbook(const char *filename);
+
+/* Deprecated function name for backwards compatibility. */
+lxw_workbook *new_workbook_opt(const char *filename,
+                               lxw_workbook_options *options);
+
+/**
+ * @brief Add a new worksheet to a workbook.
+ *
+ * @param workbook  Pointer to a lxw_workbook instance.
+ * @param sheetname Optional worksheet name, defaults to Sheet1, etc.
+ *
+ * @return A lxw_worksheet 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. it must be
+ * less than 32 character and it cannot contain any of the characters:
+ *
+ *     / \ [ ] : * ?
+ *
+ * In addition, you cannot use the same, case insensitive, `sheetname` for more
+ * than one worksheet.
+ *
+ */
+lxw_worksheet *workbook_add_worksheet(lxw_workbook *workbook,
+                                      const char *sheetname);
+
+/**
+ * @brief Create a new @ref format.h "Format" object to formats cells in
+ *        worksheets.
+ *
+ * @param workbook Pointer to a lxw_workbook instance.
+ *
+ * @return A lxw_format instance.
+ *
+ * The `workbook_add_format()` function can be used to create new @ref
+ * format.h "Format" objects which are used to apply formatting to a cell.
+ *
+ * @code
+ *    // Create the Format.
+ *    lxw_format *format = workbook_add_format(workbook);
+ *
+ *    // Set some of the format properties.
+ *    format_set_bold(format);
+ *    format_set_font_color(format, LXW_COLOR_RED);
+ *
+ *    // Use the format to change the text format in a cell.
+ *    worksheet_write_string(worksheet, 0, 0, "Hello", format);
+ * @endcode
+ *
+ * See @ref format.h "the Format object" and @ref working_with_formats
+ * sections for more details about Format properties and how to set them.
+ *
+ */
+lxw_format *workbook_add_format(lxw_workbook *workbook);
+
+/**
+ * @brief 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_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`
+ *
+ * The properties are specified via a `lxw_doc_properties` struct. All the
+ * members are `char *` and they 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
+ *
+ */
+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 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 Validate a worksheet name.
+ *
+ * @param workbook  Pointer to a lxw_workbook instance.
+ * @param sheetname Worksheet name to validate.
+ *
+ * @return A #lxw_error.
+ *
+ * This function is used to validate a worksheet 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 isn't already in use.
+ *
+ * @code
+ *     lxw_error err = workbook_validate_worksheet_name(workbook, "Foglio");
+ * @endcode
+ *
+ * This function is called by `workbook_add_worksheet()` but it can be
+ * explicitly called by the user beforehand to ensure that the worksheet
+ * name is valid.
+ *
+ */
+lxw_error workbook_validate_worksheet_name(lxw_workbook *workbook,
+                                           const char *sheetname);
+
+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);
+
+/* 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__ */

+ 3119 - 0
include/xlsxwriter/worksheet.h

@@ -0,0 +1,3119 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "shared_strings.h"
+#include "chart.h"
+#include "drawing.h"
+#include "common.h"
+#include "format.h"
+#include "utility.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 */
+
+/* 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 column width in Excel */
+#define LXW_DEF_COL_WIDTH (double)8.43
+
+/** Default row height in Excel */
+#define LXW_DEF_ROW_HEIGHT (double)15.0
+
+/** 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
+};
+
+enum cell_types {
+    NUMBER_CELL = 1,
+    STRING_CELL,
+    INLINE_STRING_CELL,
+    FORMULA_CELL,
+    ARRAY_FORMULA_CELL,
+    BLANK_CELL,
+    BOOLEAN_CELL,
+    HYPERLINK_URL,
+    HYPERLINK_INTERNAL,
+    HYPERLINK_EXTERNAL
+};
+
+enum pane_types {
+    NO_PANES = 0,
+    FREEZE_PANES,
+    SPLIT_PANES,
+    FREEZE_SPLIT_PANES
+};
+
+/* Define the tree.h RB structs for the red-black head types. */
+RB_HEAD(lxw_table_cells, lxw_cell);
+
+/* 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;}
+
+STAILQ_HEAD(lxw_merged_ranges, lxw_merged_range);
+STAILQ_HEAD(lxw_selections, lxw_selection);
+STAILQ_HEAD(lxw_data_validations, lxw_data_validation);
+STAILQ_HEAD(lxw_image_data, lxw_image_options);
+STAILQ_HEAD(lxw_chart_data, lxw_image_options);
+
+/**
+ * @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 */
+    uint8_t hidden;
+    uint8_t level;
+    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;
+    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;
+
+    uint8_t is_between;
+
+    /**
+     * 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.
+     */
+    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.
+     */
+    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.
+     */
+    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.
+     */
+    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.
+     */
+    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.
+     */
+    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.
+     */
+    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.
+     */
+    char *error_message;
+
+    char sqref[LXW_MAX_CELL_RANGE_LENGTH];
+
+    STAILQ_ENTRY (lxw_data_validation) list_pointers;
+
+} lxw_data_validation;
+
+/**
+ * @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;
+
+    lxw_row_t row;
+    lxw_col_t col;
+    char *filename;
+    char *url;
+    char *tip;
+    uint8_t anchor;
+
+    /* Internal metadata. */
+    FILE *stream;
+    uint8_t image_type;
+    double width;
+    double height;
+    char *short_name;
+    char *extension;
+    double x_dpi;
+    double y_dpi;
+    lxw_chart *chart;
+
+    STAILQ_ENTRY (lxw_image_options) list_pointers;
+
+} lxw_image_options;
+
+/**
+ * @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. */
+    double margin;
+} 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. */
+    uint8_t objects;
+
+    uint8_t no_sheet;
+    uint8_t content;
+    uint8_t is_configured;
+    char hash[5];
+} lxw_protection;
+
+/**
+ * @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;
+    struct lxw_table_rows *table;
+    struct lxw_table_rows *hyperlinks;
+    struct lxw_cell **array;
+    struct lxw_merged_ranges *merged_ranges;
+    struct lxw_selections *selections;
+    struct lxw_data_validations *data_validations;
+    struct lxw_image_data *image_data;
+    struct lxw_chart_data *chart_data;
+
+    lxw_row_t dim_rowmin;
+    lxw_row_t dim_rowmax;
+    lxw_col_t dim_colmin;
+    lxw_col_t dim_colmax;
+
+    lxw_sst *sst;
+    char *name;
+    char *quoted_name;
+    char *tmpdir;
+
+    uint32_t index;
+    uint8_t active;
+    uint8_t selected;
+    uint8_t hidden;
+    uint16_t *active_sheet;
+    uint16_t *first_sheet;
+
+    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 vba_codename;
+    uint8_t vcenter;
+    uint8_t zoom_scale_normal;
+    uint8_t num_validations;
+
+    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[LXW_HEADER_FOOTER_MAX];
+    char footer[LXW_HEADER_FOOTER_MAX];
+
+    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;
+
+    lxw_row_t *hbreaks;
+    lxw_col_t *vbreaks;
+    uint16_t hbreaks_count;
+    uint16_t vbreaks_count;
+
+    struct lxw_rel_tuples *external_hyperlinks;
+    struct lxw_rel_tuples *external_drawing_links;
+    struct lxw_rel_tuples *drawing_links;
+
+    struct lxw_panes panes;
+
+    struct lxw_protection protection;
+
+    lxw_drawing *drawing;
+
+    STAILQ_ENTRY (lxw_worksheet) list_pointers;
+
+} lxw_worksheet;
+
+/*
+ * Worksheet initialization data.
+ */
+typedef struct lxw_worksheet_init_data {
+    uint32_t index;
+    uint8_t hidden;
+    uint8_t optimize;
+    uint16_t *active_sheet;
+    uint16_t *first_sheet;
+    lxw_sst *sst;
+    char *name;
+    char *quoted_name;
+    char *tmpdir;
+
+} 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;
+
+    union {
+        double number;
+        int32_t string_id;
+        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;
+
+/* *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);
+
+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);
+
+/**
+ * @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);
+
+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);
+/**
+ *
+ * @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", url_format);
+ * @endcode
+ *
+ * @image html hyperlinks_short.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. The typical worksheet format for a hyperlink is a
+ * blue 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_BLUE);
+ *
+ * @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/",     url_format);
+ *     worksheet_write_url(worksheet, 1, 0, "http://www.python.org/",    url_format);
+ *     worksheet_write_url(worksheet, 2, 0, "https://www.python.org/",   url_format);
+ *     worksheet_write_url(worksheet, 3, 0, "mailto:[email protected]", url_format);
+ *
+ * @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:
+ *
+ * @code
+ *  // Write a hyperlink but overwrite the displayed string.
+ *  worksheet_write_url   (worksheet, 2, 0, "http://libxlsxwriter.github.io", url_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",                url_format);
+ *     worksheet_write_url(worksheet, 1, 0, "internal:Sheet2!B2",                url_format);
+ *     worksheet_write_url(worksheet, 2, 0, "internal:Sheet2!A1:B2",             url_format);
+ *     worksheet_write_url(worksheet, 3, 0, "internal:'Sales Data'!A1",          url_format);
+ *     worksheet_write_url(worksheet, 4, 0, "external:c:\\temp\\foo.xlsx",       url_format);
+ *     worksheet_write_url(worksheet, 5, 0, "external:c:\\foo.xlsx#Sheet2!A1",   url_format);
+ *     worksheet_write_url(worksheet, 6, 0, "external:..\\foo.xlsx",             url_format);
+ *     worksheet_write_url(worksheet, 7, 0, "external:..\\foo.xlsx#Sheet2!A1",   url_format);
+ *     worksheet_write_url(worksheet, 8, 0, "external:\\\\NET\\share\\foo.xlsx", url_format);
+ *
+ * @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",   url_format);
+ * @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", url_format);
+ *
+ * @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", url_format);
+ * @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", url_format);
+ * @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",     url_format);
+ *     worksheet_write_url(worksheet, 1, 0, "external://NET/share/foo.xlsx", url_format);
+ *
+ * @endcode
+ *
+ *
+ * **Note:**
+ *
+ *    libxlsxwriter will escape the following characters in URLs as required
+ *    by Excel: `\s " < > \ [ ]  ^ { }` unless the URL already contains `%%xx`
+ *    style escapes. In which case it is assumed that the URL was escaped
+ *    correctly by the user and will by passed directly to Excel.
+ *
+ */
+lxw_error worksheet_write_url(lxw_worksheet *worksheet,
+                              lxw_row_t row,
+                              lxw_col_t col, const char *url,
+                              lxw_format *format);
+
+/**
+ * @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 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 result for a 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
+ * 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 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.
+ *
+ * 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 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.
+ *
+ * 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 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.
+ *
+ * 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.
+ *
+ * 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_HEIGHT, 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.
+ *
+ * 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 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 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.
+ *
+ * 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 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
+ *
+ * @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 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()` 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_image_options struct to scale and position the image of the chart:
+ *
+ * @code
+ *    lxw_image_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
+ *
+ * The #lxw_image_options struct is the same struct used in
+ * `worksheet_insert_image_opt()` to position and scale images.
+ *
+ */
+lxw_error worksheet_insert_chart_opt(lxw_worksheet *worksheet,
+                                     lxw_row_t row, lxw_col_t col,
+                                     lxw_chart *chart,
+                                     lxw_image_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 autofilter.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
+ *
+ * Note: it isn't currently possible to apply filter conditions to the
+ * autofilter.
+ */
+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 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 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 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 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   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 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             |
+ *
+ *
+ * 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"
+ *
+ *      <headerFooter scaleWithDoc="0">
+ *        <oddHeader>&amp;L&amp;P</oddHeader>
+ *      </headerFooter>
+ *
+ * @endcode
+ *
+ * Note that in this case you need to unescape the Html. In the above example
+ * the header string would be `&L&P`.
+ *
+ * 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, the header or footer string must be less than 255 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.
+ *
+ * Currently, the only available option is the header margin:
+ *
+ * @code
+ *
+ *    lxw_header_footer_options header_options = { 0.2 };
+ *
+ *    worksheet_set_header_opt(worksheet, "Some text", &header_options);
+ *
+ * @endcode
+ *
+ */
+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 page number when printing.
+ *
+ * @param worksheet  Pointer to a lxw_worksheet instance to be updated.
+ * @param start_page Starting page number.
+ *
+ * The `%worksheet_set_start_page()` function is used to set the number of
+ * the starting page when the worksheet is printed out:
+ *
+ * @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 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:** Worksheet 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 and would take several
+ * man months to implement.
+ */
+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);
+
+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,
+                                 uint16_t image_ref_id, uint16_t drawing_id,
+                                 lxw_image_options *image_data);
+
+void lxw_worksheet_prepare_chart(lxw_worksheet *worksheet,
+                                 uint16_t chart_ref_id, uint16_t drawing_id,
+                                 lxw_image_options *image_data);
+
+lxw_row *lxw_worksheet_find_row(lxw_worksheet *worksheet, lxw_row_t row_num);
+lxw_cell *lxw_worksheet_find_cell(lxw_row *row, lxw_col_t col_num);
+
+/* 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);
+STATIC void _worksheet_write_data_validations(lxw_worksheet *self);
+#endif /* TESTING */
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+}
+#endif
+/* *INDENT-ON* */
+
+#endif /* __LXW_WORKSHEET_H__ */

+ 178 - 0
include/xlsxwriter/xmlwriter.h

@@ -0,0 +1,178 @@
+/*
+ * libxlsxwriter
+ *
+ * Copyright 2014-2018, John McNamara, [email protected]. 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "utility.h"
+
+#define LXW_MAX_ATTRIBUTE_LENGTH 256
+#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, uint32_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()                                 \
+    while (!STAILQ_EMPTY(&attributes)) {                      \
+        attribute = STAILQ_FIRST(&attributes);                \
+        STAILQ_REMOVE_HEAD(&attributes, list_entries);        \
+        free(attribute);                                      \
+    }
+
+/**
+ * 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);
+
+char *lxw_escape_control_characters(const char *string);
+
+char *lxw_escape_data(const char *data);
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+}
+#endif
+/* *INDENT-ON* */
+
+#endif /* __XMLWRITER_H__ */

+ 367 - 0
include/zip.h

@@ -0,0 +1,367 @@
+/* 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 project 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
+
+#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
+{
+    uInt tm_sec;            /* seconds after the minute - [0,59] */
+    uInt tm_min;            /* minutes after the hour - [0,59] */
+    uInt tm_hour;           /* hours since midnight - [0,23] */
+    uInt tm_mday;           /* day of the month - [1,31] */
+    uInt tm_mon;            /* months since January - [0,11] */
+    uInt 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 OF((const char *pathname, int append));
+extern zipFile ZEXPORT zipOpen64 OF((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 couse, you can use RAW reading and writing to copy the file you did not want delte
+*/
+
+extern zipFile ZEXPORT zipOpen2 OF((const char *pathname,
+                                   int append,
+                                   zipcharpc* globalcomment,
+                                   zlib_filefunc_def* pzlib_filefunc_def));
+
+extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname,
+                                   int append,
+                                   zipcharpc* globalcomment,
+                                   zlib_filefunc64_def* pzlib_filefunc_def));
+
+extern int ZEXPORT zipOpenNewFileInZip OF((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 OF((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 the the local header
+  if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global
+    contains the extrafield data the the local 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 OF((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 OF((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 OF((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 OF((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 OF((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 OF((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 OF((zipFile file,
+                       const void* buf,
+                       unsigned len));
+/*
+  Write data in the zipfile
+*/
+
+extern int ZEXPORT zipCloseFileInZip OF((zipFile file));
+/*
+  Close the current file in the zipfile
+*/
+
+extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file,
+                                            uLong uncompressed_size,
+                                            uLong crc32));
+
+extern int ZEXPORT zipCloseFileInZipRaw64 OF((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 OF((zipFile file,
+                const char* global_comment));
+/*
+  Close the zipfile
+*/
+
+
+extern int ZEXPORT zipRemoveExtraInfoBlock OF((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 */