/*
    SPDX-FileCopyrightText: 2008-2017 jerome DOT laurens AT u-bourgogne DOT fr
    SPDX-License-Identifier: X11

    This file is part of the __SyncTeX__ package.

    [//]: # (Latest Revision: Fri Jul 14 16:20:41 UTC 2017)
    [//]: # (Version: 1.19)

    See `synctex_parser_readme.md` for more details

    Acknowledgments:
    ----------------
    The author received useful remarks from the pdfTeX developers, especially Hahn The Thanh,
    and significant help from XeTeX developer Jonathan Kew

    Nota Bene:
    ----------
    If you include or use a significant part of the synctex package into a software,
    I would appreciate to be listed as contributor and see "SyncTeX" highlighted.
*/

/*  We assume that high level application like pdf viewers will want
 *  to embed this code as is. We assume that they also have locale.h and setlocale.
 *  For other tools such as TeXLive tools, you must define SYNCTEX_USE_LOCAL_HEADER,
 *  when building. You also have to create and customize synctex_parser_local.h to fit your system.
 *  In particular, the HAVE_LOCALE_H and HAVE_SETLOCALE macros should be properly defined.
 *  With this design, you should not need to edit this file. */

/**
 *  \file synctex_parser.c
 *  \brief SyncTeX file parser and controller.
 *  - author: Jérôme LAURENS
 *  \version 1.19
 *  \date Mon Apr 24 07:08:56 UTC 2017
 *
 *  Reads and parse *.synctex[.gz] files,
 *  performs edit and display queries.
 *
 *  See
 *  - synctex_scanner_new_with_output_file
 *  - synctex_scanner_parse
 *  - synctex_scanner_free
 *  - synctex_display_query
 *  - synctex_edit_query
 *  - synctex_scanner_next_result
 *  - synctex_scanner_reset_result
 *
 *  The data is organized in a graph with multiple entries.
 *  The root object is a scanner, it is created with the contents on a synctex file.
 *  Each node of the tree is a synctex_node_t object.
 *  There are 3 subtrees, two of them sharing the same leaves.
 *  The first tree is the list of input records, where input file names are associated with tags.
 *  The second tree is the box tree as given by TeX when shipping pages out.
 *  First level objects are sheets and forms, containing boxes, glues, kerns...
 *  The third tree allows to browse leaves according to tag and line.
 */
#if defined(SYNCTEX_USE_LOCAL_HEADER)
#include "synctex_parser_local.h"
#else
#define HAVE_LOCALE_H 1
#define HAVE_SETLOCALE 1
#if defined(_MSC_VER)
#define SYNCTEX_INLINE __inline
#else
#define SYNCTEX_INLINE
#endif
#endif

#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if defined(HAVE_LOCALE_H)
#include <locale.h>
#endif

#include "synctex_parser_advanced.h"

SYNCTEX_INLINE static int _synctex_abs(int x)
{
    return x > 0 ? x : -x;
}
/*  These are the possible extensions of the synctex file */
const char *synctex_suffix = ".synctex";
const char *synctex_suffix_gz = ".gz";

typedef synctex_node_p (*synctex_node_new_f)(synctex_scanner_p);
typedef void (*synctex_node_fld_f)(synctex_node_p);
typedef char *(*synctex_node_str_f)(synctex_node_p);

/**
 *  Pseudo class.
 *  - author: J. Laurens
 *
 *  Each nodes has a class, it is therefore called an object.
 *  Each class has a unique scanner.
 *  Each class has a type which is a unique identifier.
 *  Each class has a node mask which identifies node's attributes.
 *  Each class has an info mask which info's attributes.
 *  The class points to various methods,
 *  each of them vary amongst objects.
 *  The navigator records the offsets of the tree members getters.
 *  The modelator records the offsets of the data members getters, relative to the last navigator getter.
 */

/*  8 fields + size: spcflnat */
typedef struct synctex_tree_model_t {
    int sibling;
    int parent;
    int child;
    int friend;
    int last;
    int next_hbox;
    int arg_sibling;
    int target;
    int size;
} synctex_tree_model_s;
typedef const synctex_tree_model_s *synctex_tree_model_p;

typedef struct synctex_data_model_t {
    int tag;
    int line;
    int column;
    int h;
    int v;
    int width;
    int height;
    int depth;
    int mean_line;
    int weight;
    int h_V;
    int v_V;
    int width_V;
    int height_V;
    int depth_V;
    int name;
    int page;
    int size;
} synctex_data_model_s;

static const synctex_data_model_s synctex_data_model_none = {-1, /* tag */
                                                             -1, /* line */
                                                             -1, /* column */
                                                             -1, /* h */
                                                             -1, /* v */
                                                             -1, /* width */
                                                             -1, /* height */
                                                             -1, /* depth */
                                                             -1, /* mean_line */
                                                             -1, /* weight */
                                                             -1, /* h_V */
                                                             -1, /* v_V */
                                                             -1, /* width_V */
                                                             -1, /* height_V */
                                                             -1, /* depth_V */
                                                             -1, /* name */
                                                             -1, /* page */
                                                             0};
typedef const synctex_data_model_s *synctex_data_model_p;

typedef int (*synctex_int_getter_f)(synctex_node_p);
typedef struct synctex_tlcpector_t {
    synctex_int_getter_f tag;
    synctex_int_getter_f line;
    synctex_int_getter_f column;
} synctex_tlcpector_s;
typedef const synctex_tlcpector_s *synctex_tlcpector_p;
static int _synctex_int_none(synctex_node_p node)
{
    (void)node; /* unused */
    return 0;
}
static const synctex_tlcpector_s synctex_tlcpector_none = {
    &_synctex_int_none, /* tag */
    &_synctex_int_none, /* line */
    &_synctex_int_none, /* column */
};

typedef struct synctex_inspector_t {
    synctex_int_getter_f h;
    synctex_int_getter_f v;
    synctex_int_getter_f width;
    synctex_int_getter_f height;
    synctex_int_getter_f depth;
} synctex_inspector_s;
typedef const synctex_inspector_s *synctex_inspector_p;
static const synctex_inspector_s synctex_inspector_none = {
    &_synctex_int_none, /* h */
    &_synctex_int_none, /* v */
    &_synctex_int_none, /* width */
    &_synctex_int_none, /* height */
    &_synctex_int_none, /* depth */
};

typedef float (*synctex_float_getter_f)(synctex_node_p);
typedef struct synctex_vispector_t {
    synctex_float_getter_f h;
    synctex_float_getter_f v;
    synctex_float_getter_f width;
    synctex_float_getter_f height;
    synctex_float_getter_f depth;
} synctex_vispector_s;
static float _synctex_float_none(synctex_node_p node)
{
    (void)node; /* unused */
    return 0;
}
static const synctex_vispector_s synctex_vispector_none = {
    &_synctex_float_none, /* h */
    &_synctex_float_none, /* v */
    &_synctex_float_none, /* width */
    &_synctex_float_none, /* height */
    &_synctex_float_none, /* depth */
};
typedef const synctex_vispector_s *synctex_vispector_p;

struct synctex_class_t {
    synctex_scanner_p scanner;
    synctex_node_type_t type;
    synctex_node_new_f new;
    synctex_node_fld_f free;
    synctex_node_fld_f log;
    synctex_node_fld_f display;
    synctex_node_str_f abstract;
    synctex_tree_model_p navigator;
    synctex_data_model_p modelator;
    synctex_tlcpector_p tlcpector;
    synctex_inspector_p inspector;
    synctex_vispector_p vispector;
};

/**
 *  Nota bene: naming convention.
 *  For static API, when the name contains proxy, it applies to proxies.
 *  When the name contains noxy, it applies to non proxies only.
 *  When the name contains node, weel it depends...
 */

typedef synctex_node_p synctex_proxy_p;
typedef synctex_node_p synctex_noxy_p;

#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark Abstract OBJECTS and METHODS
#endif

/**
 *  \def SYNCTEX_MSG_SEND
 *  \brief Takes care of sending the given message if possible.
 *  - parameter NODE: of type synctex_node_p
 *  - parameter SELECTOR: one of the class pointer properties
 */
#define SYNCTEX_MSG_SEND(NODE, SELECTOR)                                                                                                                                                                                                       \
    do {                                                                                                                                                                                                                                       \
        synctex_node_p N__ = NODE;                                                                                                                                                                                                             \
        if (N__ && N__->class->SELECTOR) {                                                                                                                                                                                                     \
            (*(N__->class->SELECTOR))(N__);                                                                                                                                                                                                    \
        }                                                                                                                                                                                                                                      \
    } while (synctex_NO)

/**
 *  Free the given node by sending the free message.
 *  - parameter NODE: of type synctex_node_p
 */
void synctex_node_free(synctex_node_p node)
{
    SYNCTEX_MSG_SEND(node, free);
}
#if defined(SYNCTEX_TESTING)
#if !defined(SYNCTEX_USE_HANDLE)
#define SYNCTEX_USE_HANDLE 1
#endif
#if !defined(SYNCTEX_USE_CHARINDEX)
#define SYNCTEX_USE_CHARINDEX 1
#endif
#endif
SYNCTEX_INLINE static synctex_node_p _synctex_new_handle_with_target(synctex_node_p target);
#if defined(SYNCTEX_USE_HANDLE)
#define SYNCTEX_SCANNER_FREE_HANDLE(SCANR) __synctex_scanner_free_handle(SCANR)
#define SYNCTEX_SCANNER_REMOVE_HANDLE_TO(WHAT) __synctex_scanner_remove_handle_to(WHAT)
#define SYNCTEX_REGISTER_HANDLE_TO(NODE) __synctex_scanner_register_handle_to(NODE)
#else
#define SYNCTEX_SCANNER_FREE_HANDLE(SCANR)
#define SYNCTEX_SCANNER_REMOVE_HANDLE_TO(WHAT)
#define SYNCTEX_REGISTER_HANDLE_TO(NODE)
#endif

#if defined(SYNCTEX_USE_CHARINDEX)
#define SYNCTEX_CHARINDEX(NODE) (NODE->char_index)
#define SYNCTEX_LINEINDEX(NODE) (NODE->line_index)
#define SYNCTEX_PRINT_CHARINDEX_FMT "#%i"
#define SYNCTEX_PRINT_CHARINDEX_WHAT , SYNCTEX_CHARINDEX(node)
#define SYNCTEX_PRINT_CHARINDEX printf(SYNCTEX_PRINT_CHARINDEX_FMT SYNCTEX_PRINT_CHARINDEX_WHAT)
#define SYNCTEX_PRINT_LINEINDEX_FMT "L#%i"
#define SYNCTEX_PRINT_LINEINDEX_WHAT , SYNCTEX_LINEINDEX(node)
#define SYNCTEX_PRINT_LINEINDEX printf(SYNCTEX_PRINT_LINEINDEX_FMT SYNCTEX_PRINT_LINEINDEX_WHAT)
#define SYNCTEX_PRINT_CHARINDEX_NL printf(SYNCTEX_PRINT_CHARINDEX_FMT "\n" SYNCTEX_PRINT_CHARINDEX_WHAT)
#define SYNCTEX_PRINT_LINEINDEX_NL printf(SYNCTEX_PRINT_CHARINDEX_FMT "\n" SYNCTEX_PRINT_LINEINDEX_WHAT)
#define SYNCTEX_IMPLEMENT_CHARINDEX(NODE, CORRECTION)                                                                                                                                                                                          \
    NODE->char_index = (synctex_charindex_t)(scanner->reader->charindex_offset + SYNCTEX_CUR - SYNCTEX_START + (CORRECTION));                                                                                                                  \
    NODE->line_index = scanner->reader->line_number;
#else
#define SYNCTEX_CHARINDEX(NODE) 0
#define SYNCTEX_LINEINDEX(NODE) 0
#define SYNCTEX_PRINT_CHARINDEX_FMT
#define SYNCTEX_PRINT_CHARINDEX_WHAT
#define SYNCTEX_PRINT_CHARINDEX
#define SYNCTEX_PRINT_CHARINDEX
#define SYNCTEX_PRINT_LINEINDEX_FMT
#define SYNCTEX_PRINT_LINEINDEX_WHAT
#define SYNCTEX_PRINT_LINEINDEX
#define SYNCTEX_PRINT_CHARINDEX_NL printf("\n")
#define SYNCTEX_PRINT_LINEINDEX_NL printf("\n")
#define SYNCTEX_IMPLEMENT_CHARINDEX(NODE, CORRECTION)
#endif

/**
 *  The next macros are used to access the node tree info
 *  SYNCTEX_DATA(node) points to the first synctex integer or pointer data of node
 *  SYNCTEX_DATA(node)[index] is the information at index
 *  for example, the page of a sheet is stored in SYNCTEX_DATA(sheet)[_synctex_data_page_idx]
 *  - parameter NODE: of type synctex_node_p
 *  If the name starts with "__", the argument is nonullable
 */
#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark Tree SETGET
#endif

#if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 1000
#define SYNCTEX_PARAMETER_ASSERT(WHAT)                                                                                                                                                                                                         \
    do {                                                                                                                                                                                                                                       \
        if (!(WHAT)) {                                                                                                                                                                                                                         \
            printf("! Parameter failure: %s\n", #WHAT);                                                                                                                                                                                        \
        }                                                                                                                                                                                                                                      \
    } while (synctex_NO)
#define DEFINE_SYNCTEX_TREE_HAS(WHAT)                                                                                                                                                                                                          \
    static synctex_bool_t _synctex_tree_has_##WHAT(synctex_node_p node)                                                                                                                                                                        \
    {                                                                                                                                                                                                                                          \
        if (node) {                                                                                                                                                                                                                            \
            if (node->class->navigator->WHAT >= 0) {                                                                                                                                                                                           \
                return synctex_YES;                                                                                                                                                                                                            \
            } else {                                                                                                                                                                                                                           \
                printf("WARNING: NO tree %s for %s\n", #WHAT, synctex_node_isa(node));                                                                                                                                                         \
            }                                                                                                                                                                                                                                  \
        }                                                                                                                                                                                                                                      \
        return synctex_NO;                                                                                                                                                                                                                     \
    }
#else
#define SYNCTEX_PARAMETER_ASSERT(WHAT)
#define DEFINE_SYNCTEX_TREE_HAS(WHAT)                                                                                                                                                                                                          \
    static synctex_bool_t _synctex_tree_has_##WHAT(synctex_node_p node)                                                                                                                                                                        \
    {                                                                                                                                                                                                                                          \
        return (node && (node->class->navigator->WHAT >= 0));                                                                                                                                                                                  \
    }
#endif

#define DEFINE_SYNCTEX_TREE__GET(WHAT)                                                                                                                                                                                                         \
    SYNCTEX_INLINE static synctex_node_p __synctex_tree_##WHAT(synctex_non_null_node_p node)                                                                                                                                                   \
    {                                                                                                                                                                                                                                          \
        return node->data[node->class->navigator->WHAT].as_node;                                                                                                                                                                               \
    }
#define DEFINE_SYNCTEX_TREE_GET(WHAT)                                                                                                                                                                                                          \
    DEFINE_SYNCTEX_TREE__GET(WHAT)                                                                                                                                                                                                             \
    static synctex_node_p _synctex_tree_##WHAT(synctex_node_p node)                                                                                                                                                                            \
    {                                                                                                                                                                                                                                          \
        if (_synctex_tree_has_##WHAT(node)) {                                                                                                                                                                                                  \
            return __synctex_tree_##WHAT(node);                                                                                                                                                                                                \
        }                                                                                                                                                                                                                                      \
        return 0;                                                                                                                                                                                                                              \
    }
#define DEFINE_SYNCTEX_TREE__RESET(WHAT)                                                                                                                                                                                                       \
    SYNCTEX_INLINE static synctex_node_p __synctex_tree_reset_##WHAT(synctex_non_null_node_p node)                                                                                                                                             \
    {                                                                                                                                                                                                                                          \
        synctex_node_p old = node->data[node->class->navigator->WHAT].as_node;                                                                                                                                                                 \
        node->data[node->class->navigator->WHAT].as_node = NULL;                                                                                                                                                                               \
        return old;                                                                                                                                                                                                                            \
    }
#define DEFINE_SYNCTEX_TREE_RESET(WHAT)                                                                                                                                                                                                        \
    DEFINE_SYNCTEX_TREE__RESET(WHAT)                                                                                                                                                                                                           \
    SYNCTEX_INLINE static synctex_node_p _synctex_tree_reset_##WHAT(synctex_node_p node)                                                                                                                                                       \
    {                                                                                                                                                                                                                                          \
        return _synctex_tree_has_##WHAT(node) ? __synctex_tree_reset_##WHAT(node) : NULL;                                                                                                                                                      \
    }
#define DEFINE_SYNCTEX_TREE__SET(WHAT)                                                                                                                                                                                                         \
    SYNCTEX_INLINE static synctex_node_p __synctex_tree_set_##WHAT(synctex_non_null_node_p node, synctex_node_p new_value)                                                                                                                     \
    {                                                                                                                                                                                                                                          \
        synctex_node_p old = __synctex_tree_##WHAT(node);                                                                                                                                                                                      \
        node->data[node->class->navigator->WHAT].as_node = new_value;                                                                                                                                                                          \
        return old;                                                                                                                                                                                                                            \
    }
#define DEFINE_SYNCTEX_TREE_SET(WHAT)                                                                                                                                                                                                          \
    DEFINE_SYNCTEX_TREE__SET(WHAT)                                                                                                                                                                                                             \
    SYNCTEX_INLINE static synctex_node_p _synctex_tree_set_##WHAT(synctex_node_p node, synctex_node_p new_value)                                                                                                                               \
    {                                                                                                                                                                                                                                          \
        return _synctex_tree_has_##WHAT(node) ? __synctex_tree_set_##WHAT(node, new_value) : NULL;                                                                                                                                             \
    }
#define DEFINE_SYNCTEX_TREE__GETSETRESET(WHAT)                                                                                                                                                                                                 \
    DEFINE_SYNCTEX_TREE__GET(WHAT)                                                                                                                                                                                                             \
    DEFINE_SYNCTEX_TREE__SET(WHAT)                                                                                                                                                                                                             \
    DEFINE_SYNCTEX_TREE__RESET(WHAT)

#define DEFINE_SYNCTEX_TREE_GETSET(WHAT)                                                                                                                                                                                                       \
    DEFINE_SYNCTEX_TREE_HAS(WHAT)                                                                                                                                                                                                              \
    DEFINE_SYNCTEX_TREE_GET(WHAT)                                                                                                                                                                                                              \
    DEFINE_SYNCTEX_TREE_SET(WHAT)

#define DEFINE_SYNCTEX_TREE_GETRESET(WHAT)                                                                                                                                                                                                     \
    DEFINE_SYNCTEX_TREE_HAS(WHAT)                                                                                                                                                                                                              \
    DEFINE_SYNCTEX_TREE_GET(WHAT)                                                                                                                                                                                                              \
    DEFINE_SYNCTEX_TREE_RESET(WHAT)

#define DEFINE_SYNCTEX_TREE_GETSETRESET(WHAT)                                                                                                                                                                                                  \
    DEFINE_SYNCTEX_TREE_HAS(WHAT)                                                                                                                                                                                                              \
    DEFINE_SYNCTEX_TREE_GET(WHAT)                                                                                                                                                                                                              \
    DEFINE_SYNCTEX_TREE_SET(WHAT)                                                                                                                                                                                                              \
    DEFINE_SYNCTEX_TREE_RESET(WHAT)

/*
 *  _synctex_tree_set_... methods return the old value.
 *  The return value of _synctex_tree_set_child and
 *  _synctex_tree_set_sibling must be released somehown.
 */
DEFINE_SYNCTEX_TREE__GETSETRESET(sibling)
DEFINE_SYNCTEX_TREE_GETSETRESET(parent)
DEFINE_SYNCTEX_TREE_GETSETRESET(child)
DEFINE_SYNCTEX_TREE_GETSETRESET(friend)
DEFINE_SYNCTEX_TREE_GETSET(last)
DEFINE_SYNCTEX_TREE_GETSET(next_hbox)
DEFINE_SYNCTEX_TREE_GETSET(arg_sibling)
DEFINE_SYNCTEX_TREE_GETSET(target)

#if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 1000
#undef SYNCTEX_USE_NODE_COUNT
#define SYNCTEX_USE_NODE_COUNT 1
#endif
#if defined SYNCTEX_USE_NODE_COUNT && SYNCTEX_USE_NODE_COUNT > 0
#define SYNCTEX_DECLARE_NODE_COUNT int node_count;
#define SYNCTEX_INIT_NODE_COUNT                                                                                                                                                                                                                \
    do {                                                                                                                                                                                                                                       \
        node_count = 0;                                                                                                                                                                                                                        \
    } while (synctex_NO)
#else
#define SYNCTEX_DECLARE_NODE_COUNT
#define SYNCTEX_INIT_NODE_COUNT
#endif

#if defined SYNCTEX_USE_NODE_COUNT && SYNCTEX_USE_NODE_COUNT > 10
#define SYNCTEX_DID_NEW(N) _synctex_did_new(N)
#define SYNCTEX_WILL_FREE(N) _synctex_will_free(N)
#else
#define SYNCTEX_DID_NEW(N)
#define SYNCTEX_WILL_FREE(N)
#endif

#define SYNCTEX_HAS_CHILDREN(NODE) (NODE && _synctex_tree_child(NODE))
#ifdef __SYNCTEX_WORK__
#include "/usr/include/zlib.h"
#else
#include <zlib.h>
#endif

#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark STATUS
#endif
/*  When the end of the synctex file has been reached: */
#define SYNCTEX_STATUS_EOF 0
/*  When the function could not return the value it was asked for: */
#define SYNCTEX_STATUS_NOT_OK (SYNCTEX_STATUS_EOF + 1)
/*  When the function returns the value it was asked for:
 It must be the biggest one */
#define SYNCTEX_STATUS_OK (SYNCTEX_STATUS_NOT_OK + 1)
/*  Generic error: */
#define SYNCTEX_STATUS_ERROR (SYNCTEX_STATUS_EOF - 1)
/*  Parameter error: */
#define SYNCTEX_STATUS_BAD_ARGUMENT (SYNCTEX_STATUS_ERROR - 1)

#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark File reader
#endif

/*  We ensure that SYNCTEX_BUFFER_SIZE < UINT_MAX, I don't know if it makes sense... */
/*  Actually, the minimum buffer size is driven by integer and float parsing, including the unit.
 *  ±0.123456789e123??
 */
#define SYNCTEX_BUFFER_MIN_SIZE 32
#define SYNCTEX_BUFFER_SIZE 32768

#if SYNCTEX_BUFFER_SIZE >= UINT_MAX
#error BAD BUFFER SIZE(1)
#endif
#if SYNCTEX_BUFFER_SIZE < SYNCTEX_BUFFER_MIN_SIZE
#error BAD BUFFER SIZE(2)
#endif

typedef struct synctex_reader_t {
    gzFile file; /*  The (possibly compressed) file */
    char *output;
    char *synctex;
    char *current; /*  current location in the buffer */
    char *start;   /*  start of the buffer */
    char *end;     /*  end of the buffer */
    size_t min_size;
    size_t size;
    int lastv;
    int line_number;
    SYNCTEX_DECLARE_CHAR_OFFSET
} synctex_reader_s;

typedef synctex_reader_s *synctex_reader_p;

typedef struct {
    synctex_status_t status;
    char *synctex;
    gzFile file;
    synctex_io_mode_t io_mode;
} synctex_open_s;

/*	This functions opens the file at the "output" given location.
 *  It manages the problem of quoted filenames that appear with pdftex and filenames containing the space character.
 *  In TeXLive 2008, the synctex file created with pdftex did contain unexpected quotes.
 *	This function will remove them if possible.
 *  All the reference arguments will take a value on return. They must be non NULL.
 *	- returns: an open structure which status is
 *      SYNCTEX_STATUS_OK on success,
 *      SYNCTEX_STATUS_ERROR on failure.
 *  - note: on success, the caller is the owner
 *      of the fields of the returned open structure.
 */
static synctex_open_s __synctex_open_v2(const char *output, synctex_io_mode_t io_mode, synctex_bool_t add_quotes)
{
    synctex_open_s open = {SYNCTEX_STATUS_ERROR, NULL, NULL, io_mode};
    char *quoteless_synctex_name = NULL;
    const char *mode = _synctex_get_io_mode_name(open.io_mode);
    size_t size = strlen(output) + strlen(synctex_suffix) + strlen(synctex_suffix_gz) + 1;
    if (NULL == (open.synctex = (char *)malloc(size))) {
        _synctex_error("!  __synctex_open_v2: Memory problem (1)\n");
        return open;
    }
    /*  we have reserved for synctex enough memory to copy output (including its 2 eventual quotes), both suffices,
     *  including the terminating character. size is free now. */
    if (open.synctex != strcpy(open.synctex, output)) {
        _synctex_error("!  __synctex_open_v2: Copy problem\n");
    return_on_error:
        free(open.synctex);
        open.synctex = NULL;
        free(quoteless_synctex_name); /* We MUST have quoteless_synctex_name<>synctex_name */
        return open;
    }
    /*  remove the last path extension if any */
    _synctex_strip_last_path_extension(open.synctex);
    if (!strlen(open.synctex)) {
        goto return_on_error;
    }
    /*  now insert quotes. */
    if (add_quotes) {
        char *quoted = NULL;
        if (_synctex_copy_with_quoting_last_path_component(open.synctex, &quoted, size) || quoted == NULL) {
            /*	There was an error or quoting does not make sense: */
            goto return_on_error;
        }
        quoteless_synctex_name = open.synctex;
        open.synctex = quoted;
    }
    /*	Now add to open.synctex the first path extension. */
    if (open.synctex != strcat(open.synctex, synctex_suffix)) {
        _synctex_error("!  __synctex_open_v2: Concatenation problem (can't add suffix '%s')\n", synctex_suffix);
        goto return_on_error;
    }
    /*	Add to quoteless_synctex_name as well, if relevant. */
    if (quoteless_synctex_name && (quoteless_synctex_name != strcat(quoteless_synctex_name, synctex_suffix))) {
        free(quoteless_synctex_name);
        quoteless_synctex_name = NULL;
    }
    if (NULL == (open.file = gzopen(open.synctex, mode))) {
        /*  Could not open this file */
        if (errno != ENOENT) {
            /*  The file does exist, this is a lower level error, I can't do anything. */
            _synctex_error("could not open %s, error %i\n", open.synctex, errno);
            goto return_on_error;
        }
        /*  Apparently, there is no uncompressed synctex file. Try the compressed version */
        if (open.synctex != strcat(open.synctex, synctex_suffix_gz)) {
            _synctex_error("!  __synctex_open_v2: Concatenation problem (can't add suffix '%s')\n", synctex_suffix_gz);
            goto return_on_error;
        }
        open.io_mode |= synctex_io_gz_mask;
        mode = _synctex_get_io_mode_name(open.io_mode); /* the file is a compressed and is a binary file, this caused errors on Windows */
        /*	Add the suffix to the quoteless_synctex_name as well. */
        if (quoteless_synctex_name && (quoteless_synctex_name != strcat(quoteless_synctex_name, synctex_suffix_gz))) {
            free(quoteless_synctex_name);
            quoteless_synctex_name = NULL;
        }
        if (NULL == (open.file = gzopen(open.synctex, mode))) {
            /*  Could not open this file */
            if (errno != ENOENT) {
                /*  The file does exist, this is a lower level error, I can't do anything. */
                _synctex_error("Could not open %s, error %i\n", open.synctex, errno);
            }
            goto return_on_error;
        }
    }
    /*	At this point, the file is properly open.
     *  If we are in the add_quotes mode, we change the file name by removing the quotes. */
    if (quoteless_synctex_name) {
        gzclose(open.file);
        if (rename(open.synctex, quoteless_synctex_name)) {
            _synctex_error("Could not rename %s to %s, error %i\n", open.synctex, quoteless_synctex_name, errno);
            /*	We could not rename, reopen the file with the quoted name. */
            if (NULL == (open.file = gzopen(open.synctex, mode))) {
                /*  No luck, could not re open this file, something has happened meanwhile */
                if (errno != ENOENT) {
                    /*  The file does not exist any more, it has certainly be removed somehow
                     *  this is a lower level error, I can't do anything. */
                    _synctex_error("Could not open again %s, error %i\n", open.synctex, errno);
                }
                goto return_on_error;
            }
        } else {
            /*  The file has been successfully renamed */
            if (NULL == (open.file = gzopen(quoteless_synctex_name, mode))) {
                /*  Could not open this file */
                if (errno != ENOENT) {
                    /*  The file does exist, this is a lower level error, I can't do anything. */
                    _synctex_error("Could not open renamed %s, error %i\n", quoteless_synctex_name, errno);
                }
                goto return_on_error;
            }
            /*  The quote free file name should replace the old one:*/
            free(open.synctex);
            open.synctex = quoteless_synctex_name;
            quoteless_synctex_name = NULL;
        }
    }
    /*  The operation is successful, return the arguments by value.    */
    open.status = SYNCTEX_STATUS_OK;
    return open;
}

/*	Opens the output file, taking into account the eventual build_directory.
 *	- returns: an open structure which status is
 *      SYNCTEX_STATUS_OK on success,
 *      SYNCTEX_STATUS_ERROR on failure.
 *  - note: on success, the caller is the owner
 *      of the fields of the returned open structure.
 */
static synctex_open_s _synctex_open_v2(const char *output, const char *build_directory, synctex_io_mode_t io_mode, synctex_bool_t add_quotes)
{
    synctex_open_s open = __synctex_open_v2(output, io_mode, add_quotes);
    if (open.status == SYNCTEX_STATUS_OK) {
        return open;
    }
    if (build_directory && strlen(build_directory)) {
        char *build_output;
        const char *lpc;
        size_t size;
        synctex_bool_t is_absolute;
        build_output = NULL;
        lpc = _synctex_last_path_component(output);
        size = strlen(build_directory) + strlen(lpc) + 2; /*  One for the '/' and one for the '\0'.   */
        is_absolute = _synctex_path_is_absolute(build_directory);
        if (!is_absolute) {
            size += strlen(output);
        }
        if ((build_output = (char *)_synctex_malloc(size))) {
            if (is_absolute) {
                build_output[0] = '\0';
            } else {
                if (build_output != strcpy(build_output, output)) {
                    _synctex_free(build_output);
                    return open;
                }
                build_output[lpc - output] = '\0';
            }
            if (build_output == strcat(build_output, build_directory)) {
                /*	Append a path separator if necessary. */
                if (!SYNCTEX_IS_PATH_SEPARATOR(build_output[strlen(build_directory) - 1])) {
                    if (build_output != strcat(build_output, "/")) {
                        _synctex_free(build_output);
                        return open;
                    }
                }
                /*	Append the last path component of the output. */
                if (build_output != strcat(build_output, lpc)) {
                    _synctex_free(build_output);
                    return open;
                }
                open = __synctex_open_v2(build_output, io_mode, add_quotes);
            }
            _synctex_free(build_output);
        } /* if ((build_output... */
    } /* if (build_directory...) */
    return open;
}
void synctex_reader_free(synctex_reader_p reader)
{
    if (reader) {
        _synctex_free(reader->output);
        _synctex_free(reader->synctex);
        _synctex_free(reader->start);
        gzclose(reader->file);
        _synctex_free(reader);
    }
}
/*
 *  Return reader on success.
 *  Deallocate reader and return NULL on failure.
 */
synctex_reader_p synctex_reader_init_with_output_file(synctex_reader_p reader, const char *output, const char *build_directory)
{
    if (reader) {
        /*  now open the synctex file */
        synctex_open_s open = _synctex_open_v2(output, build_directory, 0, synctex_ADD_QUOTES);
        if (open.status < SYNCTEX_STATUS_OK) {
            open = _synctex_open_v2(output, build_directory, 0, synctex_DONT_ADD_QUOTES);
            if (open.status < SYNCTEX_STATUS_OK) {
                synctex_reader_free(reader);
                return NULL;
            }
        }
        reader->synctex = open.synctex;
        reader->file = open.file;
        /*  make a private copy of output */
        if (NULL == (reader->output = (char *)_synctex_malloc(strlen(output) + 1))) {
            _synctex_error("!  synctex_scanner_new_with_output_file: Memory problem (2), reader's output is not reliable.");
        } else if (reader->output != strcpy(reader->output, output)) {
            _synctex_free(reader->output);
            reader->output = NULL;
            _synctex_error("!  synctex_scanner_new_with_output_file: Copy problem, reader's output is not reliable.");
        }
        reader->start = reader->end = reader->current = NULL;
        reader->min_size = SYNCTEX_BUFFER_MIN_SIZE;
        reader->size = SYNCTEX_BUFFER_SIZE;
        reader->start = reader->current = (char *)_synctex_malloc(reader->size + 1); /*  one more character for null termination */
        if (NULL == reader->start) {
            _synctex_error("!  malloc error in synctex_reader_init_with_output_file.");
#ifdef SYNCTEX_DEBUG
            return reader;
#else
            synctex_reader_free(reader);
            return NULL;
#endif
        }
        reader->end = reader->start + reader->size;
        /*  reader->end always points to a null terminating character.
         *  Maybe there is another null terminating character between reader->current and reader->end-1.
         *  At least, we are sure that reader->current points to a string covering a valid part of the memory. */
#if defined(SYNCTEX_USE_CHARINDEX)
        reader->charindex_offset = -reader->size;
#endif
    }
    return reader;
}

#if defined(SYNCTEX_USE_HANDLE)
#define SYNCTEX_DECLARE_HANDLE synctex_node_p handle;
#else
#define SYNCTEX_DECLARE_HANDLE
#endif

#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark SCANNER
#endif
/**
 *  The synctex scanner is the root object.
 *  Is is initialized with the contents of a text file or a gzipped file.
 *  The buffer_.* are first used to parse the text.
 */
struct synctex_scanner_t {
    synctex_reader_p reader;
    SYNCTEX_DECLARE_NODE_COUNT
    SYNCTEX_DECLARE_HANDLE
    char *output_fmt;            /*  dvi or pdf, not yet used */
    synctex_iterator_p iterator; /*  result iterator */
    int version;                 /*  1, not yet used */
    struct {
        unsigned has_parsed : 1;                  /*  Whether the scanner has parsed its underlying synctex file. */
        unsigned postamble : 1;                   /*  Whether the scanner has parsed its underlying synctex file. */
        unsigned reserved : sizeof(unsigned) - 2; /*  alignment */
    } flags;
    int pre_magnification;                               /*  magnification from the synctex preamble */
    int pre_unit;                                        /*  unit from the synctex preamble */
    int pre_x_offset;                                    /*  X offset from the synctex preamble */
    int pre_y_offset;                                    /*  Y offset from the synctex preamble */
    int count;                                           /*  Number of records, from the synctex postamble */
    float unit;                                          /*  real unit, from synctex preamble or post scriptum */
    float x_offset;                                      /*  X offset, from synctex preamble or post scriptum */
    float y_offset;                                      /*  Y Offset, from synctex preamble or post scriptum */
    synctex_node_p input;                                /*  The first input node, its siblings are the other input nodes */
    synctex_node_p sheet;                                /*  The first sheet node, its siblings are the other sheet nodes */
    synctex_node_p form;                                 /*  The first form, its siblings are the other forms */
    synctex_node_p ref_in_sheet;                         /*  The first form ref node in sheet, its friends are the other form ref nodes */
    synctex_node_p ref_in_form;                          /*  The first form ref node, its friends are the other form ref nodes in sheet */
    int number_of_lists;                                 /*  The number of friend lists */
    synctex_node_r lists_of_friends;                     /*  The friend lists */
    synctex_class_s class[synctex_node_number_of_types]; /*  The classes of the nodes of the scanner */
    int display_switcher;
    char *display_prompt;
};

/**
 *  Create a new node of the given type.
 *  - parameter scanner: of type synctex_node_p
 *  - parameter type: a type, the client is responsible
 *  to ask for an acceptable type.
 */
synctex_node_p synctex_node_new(synctex_scanner_p scanner, synctex_node_type_t type)
{
    return scanner ? scanner->class[type].new(scanner) : NULL;
}
#if defined(SYNCTEX_USE_HANDLE)
SYNCTEX_INLINE static void __synctex_scanner_free_handle(synctex_scanner_p scanner)
{
    synctex_node_free(scanner->handle);
}
SYNCTEX_INLINE static void __synctex_scanner_remove_handle_to(synctex_node_p node)
{
    synctex_node_p arg_sibling = NULL;
    synctex_node_p handle = node->class->scanner->handle;
    while (handle) {
        synctex_node_p sibling;
        if (node == _synctex_tree_target(handle)) {
            sibling = __synctex_tree_reset_sibling(handle);
            if (arg_sibling) {
                __synctex_tree_set_sibling(arg_sibling, sibling);
            } else {
                node->class->scanner->handle = sibling;
            }
            synctex_node_free(handle);
            break;
        } else {
            sibling = __synctex_tree_sibling(handle);
        }
        arg_sibling = handle;
        handle = sibling;
    }
}
SYNCTEX_INLINE static void __synctex_scanner_register_handle_to(synctex_node_p node)
{
    synctex_node_p NNN = _synctex_new_handle_with_target(node);
    __synctex_tree_set_sibling(NNN, node->class->scanner->handle);
    node->class->scanner->handle = NNN;
}
#endif
#if defined SYNCTEX_USE_NODE_COUNT && SYNCTEX_USE_NODE_COUNT > 10
SYNCTEX_INLINE static void _synctex_did_new(synctex_node_p node)
{
    printf("NODE CREATED # %i, %s, %p\n", (node->class->scanner->node_count)++, synctex_node_isa(node), node);
}
SYNCTEX_INLINE static void _synctex_will_free(synctex_node_p node)
{
    printf("NODE DELETED # %i, %s, %p\n", --(node->class->scanner->node_count), synctex_node_isa(node), node);
}
#endif

/**
 *  Free the given node.
 *  - parameter node: of type synctex_node_p
 *  - note: a node is meant to own its child and sibling.
 *  It is not owned by its parent, unless it is its first child.
 *  This destructor is for all nodes with children.
 */
static void _synctex_free_node(synctex_node_p node)
{
    if (node) {
        SYNCTEX_SCANNER_REMOVE_HANDLE_TO(node);
        SYNCTEX_WILL_FREE(node);
        synctex_node_free(__synctex_tree_sibling(node));
        synctex_node_free(_synctex_tree_child(node));
        _synctex_free(node);
    }
    return;
}

/**
 *  Free the given leaf node.
 *  - parameter node: of type synctex_node_p, with no child nor sibling.
 *  - note: a node is meant to own its child and sibling.
 *  It is not owned by its parent, unless it is its first child.
 *  This destructor is for all nodes with no children.
 */
static void _synctex_free_leaf(synctex_node_p node)
{
    if (node) {
        SYNCTEX_SCANNER_REMOVE_HANDLE_TO(node);
        SYNCTEX_WILL_FREE(node);
        synctex_node_free(__synctex_tree_sibling(node));
        _synctex_free(node);
    }
    return;
}

/**
 SYNCTEX_CUR, SYNCTEX_START and SYNCTEX_END are convenient shortcuts
 */
#define SYNCTEX_CUR (scanner->reader->current)
#define SYNCTEX_START (scanner->reader->start)
#define SYNCTEX_END (scanner->reader->end)

/*  Here are gathered all the possible status that the next scanning functions will return.
 *  All these functions return a status, and pass their result through pointers.
 *  Negative values correspond to errors.
 *  The management of the buffer is causing some significant overhead.
 *  Every function that may access the buffer returns a status related to the buffer and file state.
 *  status >= SYNCTEX_STATUS_OK means the function worked as expected
 *  status < SYNCTEX_STATUS_OK means the function did not work as expected
 *  status == SYNCTEX_STATUS_NOT_OK means the function did not work as expected but there is still some material to parse.
 *  status == SYNCTEX_STATUS_EOF means the function did not work as expected and there is no more material.
 *  status<SYNCTEX_STATUS_EOF means an error
 */
#if defined(SYNCTEX_USE_CHARINDEX)
synctex_node_p synctex_scanner_handle(synctex_scanner_p scanner)
{
    return scanner ? scanner->handle : NULL;
}
#endif

#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark Decoding prototypes
#endif

typedef struct {
    int integer;
    synctex_status_t status;
} synctex_is_s;

static synctex_is_s _synctex_decode_int(synctex_scanner_p scanner);
static synctex_is_s _synctex_decode_int_opt(synctex_scanner_p scanner, int default_value);
static synctex_is_s _synctex_decode_int_v(synctex_scanner_p scanner);

typedef struct {
    char *string;
    synctex_status_t status;
} synctex_ss_s;

static synctex_ss_s _synctex_decode_string(synctex_scanner_p scanner);

#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark Data SETGET
#endif

/**
 *  The next macros are used to access the node data info
 *  through the class modelator integer fields.
 *  - parameter NODE: of type synctex_node_p
 */
#define SYNCTEX_DATA(NODE) ((*((((NODE)->class))->info))(NODE))
#if defined SYNCTEX_DEBUG > 1000
#define DEFINE_SYNCTEX_DATA_HAS(WHAT)                                                                                                                                                                                                          \
    SYNCTEX_INLINE static synctex_bool_t __synctex_data_has_##WHAT(synctex_node_p node)                                                                                                                                                        \
    {                                                                                                                                                                                                                                          \
        return (node && (node->class->modelator->WHAT >= 0));                                                                                                                                                                                  \
    }                                                                                                                                                                                                                                          \
    SYNCTEX_INLINE static synctex_bool_t _synctex_data_has_##WHAT(synctex_node_p node)                                                                                                                                                         \
    {                                                                                                                                                                                                                                          \
        if (node && (node->class->modelator->WHAT < 0)) {                                                                                                                                                                                      \
            printf("WARNING: NO %s for %s\n", #WHAT, synctex_node_isa(node));                                                                                                                                                                  \
        }                                                                                                                                                                                                                                      \
        return __synctex_data_has_##WHAT(node);                                                                                                                                                                                                \
    }
#else
#define DEFINE_SYNCTEX_DATA_HAS(WHAT)                                                                                                                                                                                                          \
    SYNCTEX_INLINE static synctex_bool_t __synctex_data_has_##WHAT(synctex_node_p node)                                                                                                                                                        \
    {                                                                                                                                                                                                                                          \
        return (node && (node->class->modelator->WHAT >= 0));                                                                                                                                                                                  \
    }                                                                                                                                                                                                                                          \
    SYNCTEX_INLINE static synctex_bool_t _synctex_data_has_##WHAT(synctex_node_p node)                                                                                                                                                         \
    {                                                                                                                                                                                                                                          \
        return __synctex_data_has_##WHAT(node);                                                                                                                                                                                                \
    }
#endif

SYNCTEX_INLINE static synctex_data_p __synctex_data(synctex_node_p node)
{
    return node->data + node->class->navigator->size;
}
#define DEFINE_SYNCTEX_DATA_INT_GETSET(WHAT)                                                                                                                                                                                                   \
    DEFINE_SYNCTEX_DATA_HAS(WHAT)                                                                                                                                                                                                              \
    static int _synctex_data_##WHAT(synctex_node_p node)                                                                                                                                                                                       \
    {                                                                                                                                                                                                                                          \
        if (_synctex_data_has_##WHAT(node)) {                                                                                                                                                                                                  \
            return __synctex_data(node)[node->class->modelator->WHAT].as_integer;                                                                                                                                                              \
        }                                                                                                                                                                                                                                      \
        return 0;                                                                                                                                                                                                                              \
    }                                                                                                                                                                                                                                          \
    static int _synctex_data_set_##WHAT(synctex_node_p node, int new_value)                                                                                                                                                                    \
    {                                                                                                                                                                                                                                          \
        int old = 0;                                                                                                                                                                                                                           \
        if (_synctex_data_has_##WHAT(node)) {                                                                                                                                                                                                  \
            old = __synctex_data(node)[node->class->modelator->WHAT].as_integer;                                                                                                                                                               \
            __synctex_data(node)[node->class->modelator->WHAT].as_integer = new_value;                                                                                                                                                         \
        }                                                                                                                                                                                                                                      \
        return old;                                                                                                                                                                                                                            \
    }
#define DEFINE_SYNCTEX_DATA_INT_DECODE(WHAT)                                                                                                                                                                                                   \
    static synctex_status_t _synctex_data_decode_##WHAT(synctex_node_p node)                                                                                                                                                                   \
    {                                                                                                                                                                                                                                          \
        if (_synctex_data_has_##WHAT(node)) {                                                                                                                                                                                                  \
            synctex_is_s is = _synctex_decode_int(node->class->scanner);                                                                                                                                                                       \
            if (is.status == SYNCTEX_STATUS_OK) {                                                                                                                                                                                              \
                _synctex_data_set_##WHAT(node, is.integer);                                                                                                                                                                                    \
            }                                                                                                                                                                                                                                  \
            return is.status;                                                                                                                                                                                                                  \
        }                                                                                                                                                                                                                                      \
        return SYNCTEX_STATUS_BAD_ARGUMENT;                                                                                                                                                                                                    \
    }
#define DEFINE_SYNCTEX_DATA_INT_DECODE_v(WHAT)                                                                                                                                                                                                 \
    static synctex_status_t _synctex_data_decode_##WHAT##_v(synctex_node_p node)                                                                                                                                                               \
    {                                                                                                                                                                                                                                          \
        if (_synctex_data_has_##WHAT(node)) {                                                                                                                                                                                                  \
            synctex_is_s is = _synctex_decode_int_v(node->class->scanner);                                                                                                                                                                     \
            if (is.status == SYNCTEX_STATUS_OK) {                                                                                                                                                                                              \
                _synctex_data_set_##WHAT(node, is.integer);                                                                                                                                                                                    \
            }                                                                                                                                                                                                                                  \
            return is.status;                                                                                                                                                                                                                  \
        }                                                                                                                                                                                                                                      \
        return SYNCTEX_STATUS_BAD_ARGUMENT;                                                                                                                                                                                                    \
    }
#define DEFINE_SYNCTEX_DATA_STR_GETSET(WHAT)                                                                                                                                                                                                   \
    DEFINE_SYNCTEX_DATA_HAS(WHAT)                                                                                                                                                                                                              \
    static char *_synctex_data_##WHAT(synctex_node_p node)                                                                                                                                                                                     \
    {                                                                                                                                                                                                                                          \
        if (_synctex_data_has_##WHAT(node)) {                                                                                                                                                                                                  \
            return node->data[node->class->navigator->size + node->class->modelator->WHAT].as_string;                                                                                                                                          \
        }                                                                                                                                                                                                                                      \
        return NULL;                                                                                                                                                                                                                           \
    }                                                                                                                                                                                                                                          \
    static const char *_synctex_data_set_##WHAT(synctex_node_p node, char *new_value)                                                                                                                                                          \
    {                                                                                                                                                                                                                                          \
        const char *old = "";                                                                                                                                                                                                                  \
        if (_synctex_data_has_##WHAT(node)) {                                                                                                                                                                                                  \
            old = node->data[node->class->navigator->size + node->class->modelator->WHAT].as_string;                                                                                                                                           \
            node->data[node->class->navigator->size + node->class->modelator->WHAT].as_string = new_value;                                                                                                                                     \
        }                                                                                                                                                                                                                                      \
        return old;                                                                                                                                                                                                                            \
    }
#define DEFINE_SYNCTEX_DATA_STR_DECODE(WHAT)                                                                                                                                                                                                   \
    static synctex_status_t _synctex_data_decode_##WHAT(synctex_node_p node)                                                                                                                                                                   \
    {                                                                                                                                                                                                                                          \
        if (_synctex_data_has_##WHAT(node)) {                                                                                                                                                                                                  \
            synctex_ss_s ss = _synctex_decode_string(node->class->scanner);                                                                                                                                                                    \
            if (ss.status == SYNCTEX_STATUS_OK) {                                                                                                                                                                                              \
                _synctex_data_set_##WHAT(node, ss.string);                                                                                                                                                                                     \
            }                                                                                                                                                                                                                                  \
            return ss.status;                                                                                                                                                                                                                  \
        }                                                                                                                                                                                                                                      \
        return SYNCTEX_STATUS_BAD_ARGUMENT;                                                                                                                                                                                                    \
    }
#define DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(WHAT)                                                                                                                                                                                            \
    DEFINE_SYNCTEX_DATA_INT_GETSET(WHAT)                                                                                                                                                                                                       \
    DEFINE_SYNCTEX_DATA_INT_DECODE(WHAT)
#define DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE_v(WHAT)                                                                                                                                                                                          \
    DEFINE_SYNCTEX_DATA_INT_GETSET(WHAT)                                                                                                                                                                                                       \
    DEFINE_SYNCTEX_DATA_INT_DECODE_v(WHAT)
#define DEFINE_SYNCTEX_DATA_STR_GETSET_DECODE(WHAT)                                                                                                                                                                                            \
    DEFINE_SYNCTEX_DATA_STR_GETSET(WHAT)                                                                                                                                                                                                       \
    DEFINE_SYNCTEX_DATA_STR_DECODE(WHAT)

#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark OBJECTS, their creators and destructors.
#endif

#ifdef SYNCTEX_NOTHING
#pragma mark input.
#endif

DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(tag)
DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(line)
DEFINE_SYNCTEX_DATA_STR_GETSET_DECODE(name)

/*  Input nodes only know about their sibling, which is another input node.
 *  The synctex information is the _synctex_data_tag and _synctex_data_name
 *  note: the input owns its name. */

#define SYNCTEX_INPUT_MARK "Input:"

static const synctex_tree_model_s synctex_tree_model_input = {synctex_tree_sibling_idx, /* sibling */
                                                              -1,                       /* parent */
                                                              -1,                       /* child */
                                                              -1,                       /* friend */
                                                              -1,                       /* last */
                                                              -1,                       /* next_hbox */
                                                              -1,                       /* arg_sibling */
                                                              -1,                       /* target */
                                                              synctex_tree_s_input_max};
static const synctex_data_model_s synctex_data_model_input = {synctex_data_input_tag_idx,  /* tag */
                                                              synctex_data_input_line_idx, /* line */
                                                              -1,                          /* column */
                                                              -1,                          /* h */
                                                              -1,                          /* v */
                                                              -1,                          /* width */
                                                              -1,                          /* height */
                                                              -1,                          /* depth */
                                                              -1,                          /* mean_line */
                                                              -1,                          /* weight */
                                                              -1,                          /* h_V */
                                                              -1,                          /* v_V */
                                                              -1,                          /* width_V */
                                                              -1,                          /* height_V */
                                                              -1,                          /* depth_V */
                                                              synctex_data_input_name_idx, /* name */
                                                              -1,                          /* page */
                                                              synctex_data_input_tln_max};

#define SYNCTEX_INSPECTOR_GETTER_F(WHAT) &_synctex_data_##WHAT, &_synctex_data_set_##WHAT

static synctex_node_p _synctex_new_input(synctex_scanner_p scanner);
static void _synctex_free_input(synctex_node_p node);
static void _synctex_log_input(synctex_node_p node);
static char *_synctex_abstract_input(synctex_node_p node);
static void _synctex_display_input(synctex_node_p node);

static const synctex_tlcpector_s synctex_tlcpector_input = {
    &_synctex_data_tag, /* tag */
    &_synctex_int_none, /* line */
    &_synctex_int_none, /* column */
};

static synctex_class_s synctex_class_input = {
    NULL,                      /*  No scanner yet */
    synctex_node_type_input,   /*  Node type */
    &_synctex_new_input,       /*  creator */
    &_synctex_free_input,      /*  destructor */
    &_synctex_log_input,       /*  log */
    &_synctex_display_input,   /*  display */
    &_synctex_abstract_input,  /*  abstract */
    &synctex_tree_model_input, /*  tree model */
    &synctex_data_model_input, /*  data model */
    &synctex_tlcpector_input,  /*  inspector */
    &synctex_inspector_none,   /*  inspector */
    &synctex_vispector_none,   /*  vispector */
};

typedef struct {
    SYNCTEX_DECLARE_CHARINDEX
    synctex_class_p class;
    synctex_data_u data[synctex_tree_s_input_max + synctex_data_input_tln_max];
} synctex_input_s;

static synctex_node_p _synctex_new_input(synctex_scanner_p scanner)
{
    if (scanner) {
        synctex_node_p node = _synctex_malloc(sizeof(synctex_input_s));
        if (node) {
            node->class = scanner->class + synctex_node_type_input;
            SYNCTEX_DID_NEW(node);
            SYNCTEX_IMPLEMENT_CHARINDEX(node, 0);
            SYNCTEX_REGISTER_HANDLE_TO(node);
        }
        return node;
    }
    return NULL;
}

static void _synctex_free_input(synctex_node_p node)
{
    if (node) {
        SYNCTEX_SCANNER_REMOVE_HANDLE_TO(node);
        SYNCTEX_WILL_FREE(node);
        synctex_node_free(__synctex_tree_sibling(node));
        _synctex_free(_synctex_data_name(node));
        _synctex_free(node);
    }
}

/*  The sheet is a first level node.
 *  It has no parent (the owner is the scanner itself)
 *  Its sibling points to another sheet.
 *  Its child points to its first child, in general a box.
 *  A sheet node contains only one synctex information: the page.
 *  This is the 1 based page index as given by TeX.
 */

#ifdef SYNCTEX_NOTHING
#pragma mark sheet.
#endif
/**
 *  Every node has the same structure, but not the same size.
 */

DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(page)

typedef struct {
    SYNCTEX_DECLARE_CHARINDEX
    synctex_class_p class;
    synctex_data_u data[synctex_tree_scn_sheet_max + synctex_data_p_sheet_max];
} synctex_node_sheet_s;

/*  sheet node creator */

#define DEFINE_synctex_new_scanned_NODE(NAME)                                                                                                                                                                                                  \
    static synctex_node_p _synctex_new_##NAME(synctex_scanner_p scanner)                                                                                                                                                                       \
    {                                                                                                                                                                                                                                          \
        if (scanner) {                                                                                                                                                                                                                         \
            ++SYNCTEX_CUR;                                                                                                                                                                                                                     \
            synctex_node_p node = _synctex_malloc(sizeof(synctex_node_##NAME##_s));                                                                                                                                                            \
            if (node) {                                                                                                                                                                                                                        \
                node->class = scanner->class + synctex_node_type_##NAME;                                                                                                                                                                       \
                SYNCTEX_DID_NEW(node);                                                                                                                                                                                                         \
                SYNCTEX_IMPLEMENT_CHARINDEX(node, -1);                                                                                                                                                                                         \
                SYNCTEX_REGISTER_HANDLE_TO(node);                                                                                                                                                                                              \
            }                                                                                                                                                                                                                                  \
            return node;                                                                                                                                                                                                                       \
        }                                                                                                                                                                                                                                      \
        return NULL;                                                                                                                                                                                                                           \
    }
/*  NB: -1 in SYNCTEX_IMPLEMENT_CHARINDEX above because
 *  the first char of the line has been scanned
 */
DEFINE_synctex_new_scanned_NODE(sheet) static void _synctex_log_sheet(synctex_node_p node);
static char *_synctex_abstract_sheet(synctex_node_p node);
static void _synctex_display_sheet(synctex_node_p node);

static const synctex_tree_model_s synctex_tree_model_sheet = {synctex_tree_sibling_idx,      /* sibling */
                                                              -1,                            /* parent */
                                                              synctex_tree_s_child_idx,      /* child */
                                                              -1,                            /* friend */
                                                              -1,                            /* last */
                                                              synctex_tree_sc_next_hbox_idx, /* next_hbox */
                                                              -1,                            /* arg_sibling */
                                                              -1,                            /* target */
                                                              synctex_tree_scn_sheet_max};
static const synctex_data_model_s synctex_data_model_sheet = {-1,                          /* tag */
                                                              -1,                          /* line */
                                                              -1,                          /* column */
                                                              -1,                          /* h */
                                                              -1,                          /* v */
                                                              -1,                          /* width */
                                                              -1,                          /* height */
                                                              -1,                          /* depth */
                                                              -1,                          /* mean_line */
                                                              -1,                          /* weight */
                                                              -1,                          /* h_V */
                                                              -1,                          /* v_V */
                                                              -1,                          /* width_V */
                                                              -1,                          /* height_V */
                                                              -1,                          /* depth_V */
                                                              -1,                          /* name */
                                                              synctex_data_sheet_page_idx, /* page */
                                                              synctex_data_p_sheet_max};
static synctex_class_s synctex_class_sheet = {
    NULL,                      /*  No scanner yet */
    synctex_node_type_sheet,   /*  Node type */
    &_synctex_new_sheet,       /*  creator */
    &_synctex_free_node,       /*  destructor */
    &_synctex_log_sheet,       /*  log */
    &_synctex_display_sheet,   /*  display */
    &_synctex_abstract_sheet,  /*  abstract */
    &synctex_tree_model_sheet, /*  tree model */
    &synctex_data_model_sheet, /*  data model */
    &synctex_tlcpector_none,   /*  tlcpector */
    &synctex_inspector_none,   /*  inspector */
    &synctex_vispector_none,   /*  vispector */
};

#ifdef SYNCTEX_NOTHING
#pragma mark form.
#endif
/**
 *  Every node has the same structure, but not the same size.
 */
typedef struct {
    SYNCTEX_DECLARE_CHARINDEX
    synctex_class_p class;
    synctex_data_u data[synctex_tree_sct_form_max + synctex_data_t_form_max];
} synctex_node_form_s;

DEFINE_synctex_new_scanned_NODE(form)

    static char *_synctex_abstract_form(synctex_node_p node);
static void _synctex_display_form(synctex_node_p node);
static void _synctex_log_form(synctex_node_p node);

static const synctex_tree_model_s synctex_tree_model_form = {synctex_tree_sibling_idx,   /* sibling */
                                                             -1,                         /* parent */
                                                             synctex_tree_s_child_idx,   /* child */
                                                             -1,                         /* friend */
                                                             -1,                         /* last */
                                                             -1,                         /* next_hbox */
                                                             -1,                         /* arg_sibling */
                                                             synctex_tree_sc_target_idx, /* target */
                                                             synctex_tree_sct_form_max};
static const synctex_data_model_s synctex_data_model_form = {synctex_data_form_tag_idx, /* tag */
                                                             -1,                        /* line */
                                                             -1,                        /* column */
                                                             -1,                        /* h */
                                                             -1,                        /* v */
                                                             -1,                        /* width */
                                                             -1,                        /* height */
                                                             -1,                        /* depth */
                                                             -1,                        /* mean_line */
                                                             -1,                        /* weight */
                                                             -1,                        /* h_V */
                                                             -1,                        /* v_V */
                                                             -1,                        /* width_V */
                                                             -1,                        /* height_V */
                                                             -1,                        /* depth_V */
                                                             -1,                        /* name */
                                                             -1,                        /* page */
                                                             synctex_data_t_form_max};
static synctex_class_s synctex_class_form = {
    NULL,                     /*  No scanner yet */
    synctex_node_type_form,   /*  Node type */
    &_synctex_new_form,       /*  creator */
    &_synctex_free_node,      /*  destructor */
    &_synctex_log_form,       /*  log */
    &_synctex_display_form,   /*  display */
    &_synctex_abstract_form,  /*  abstract */
    &synctex_tree_model_form, /*  tree model */
    &synctex_data_model_form, /*  data model */
    &synctex_tlcpector_none,  /*  tlcpector */
    &synctex_inspector_none,  /*  inspector */
    &synctex_vispector_none,  /*  vispector */
};

#ifdef SYNCTEX_NOTHING
#pragma mark vbox.
#endif

/*  A box node contains navigation and synctex information
 *  There are different kinds of boxes.
 *  Only horizontal boxes are treated differently because of their visible size.
 */
typedef struct {
    SYNCTEX_DECLARE_CHARINDEX
    synctex_class_p class;
    synctex_data_u data[synctex_tree_spcfl_vbox_max + synctex_data_box_max];
} synctex_node_vbox_s;

/*  vertical box node creator */
DEFINE_synctex_new_scanned_NODE(vbox)

    static char *_synctex_abstract_vbox(synctex_node_p node);
static void _synctex_display_vbox(synctex_node_p node);
static void _synctex_log_vbox(synctex_node_p node);

static const synctex_tree_model_s synctex_tree_model_vbox = {synctex_tree_sibling_idx,    /* sibling */
                                                             synctex_tree_s_parent_idx,   /* parent */
                                                             synctex_tree_sp_child_idx,   /* child */
                                                             synctex_tree_spc_friend_idx, /* friend */
                                                             synctex_tree_spcf_last_idx,  /* last */
                                                             -1,                          /* next_hbox */
                                                             -1,                          /* arg_sibling */
                                                             -1,                          /* target */
                                                             synctex_tree_spcfl_vbox_max};

DEFINE_SYNCTEX_DATA_INT_GETSET(column)
static synctex_status_t _synctex_data_decode_column(synctex_node_p node)
{
    if (_synctex_data_has_column(node)) {
        synctex_is_s is = _synctex_decode_int_opt(node->class->scanner, -1);
        if (is.status == SYNCTEX_STATUS_OK) {
            _synctex_data_set_column(node, is.integer);
        }
        return is.status;
    }
    return SYNCTEX_STATUS_BAD_ARGUMENT;
}
DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(h)
DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE_v(v) DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(width) DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(height) DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(depth)

    static const synctex_data_model_s synctex_data_model_box = {synctex_data_tag_idx,    /* tag */
                                                                synctex_data_line_idx,   /* line */
                                                                synctex_data_column_idx, /* column */
                                                                synctex_data_h_idx,      /* h */
                                                                synctex_data_v_idx,      /* v */
                                                                synctex_data_width_idx,  /* width */
                                                                synctex_data_height_idx, /* height */
                                                                synctex_data_depth_idx,  /* depth */
                                                                -1,                      /* mean_line */
                                                                -1,                      /* weight */
                                                                -1,                      /* h_V */
                                                                -1,                      /* v_V */
                                                                -1,                      /* width_V */
                                                                -1,                      /* height_V */
                                                                -1,                      /* depth_V */
                                                                -1,                      /* name */
                                                                -1,                      /* page */
                                                                synctex_data_box_max};
static const synctex_tlcpector_s synctex_tlcpector_default = {
    &_synctex_data_tag,    /* tag */
    &_synctex_data_line,   /* line */
    &_synctex_data_column, /* column */
};
static const synctex_inspector_s synctex_inspector_box = {
    &_synctex_data_h,
    &_synctex_data_v,
    &_synctex_data_width,
    &_synctex_data_height,
    &_synctex_data_depth,
};
static float __synctex_node_visible_h(synctex_node_p node);
static float __synctex_node_visible_v(synctex_node_p node);
static float __synctex_node_visible_width(synctex_node_p node);
static float __synctex_node_visible_height(synctex_node_p node);
static float __synctex_node_visible_depth(synctex_node_p node);
static synctex_vispector_s synctex_vispector_box = {
    &__synctex_node_visible_h,
    &__synctex_node_visible_v,
    &__synctex_node_visible_width,
    &__synctex_node_visible_height,
    &__synctex_node_visible_depth,
};
/*  These are static class objects, each scanner will make a copy of them and setup the scanner field.
 */
static synctex_class_s synctex_class_vbox = {
    NULL,                       /*  No scanner yet */
    synctex_node_type_vbox,     /*  Node type */
    &_synctex_new_vbox,         /*  creator */
    &_synctex_free_node,        /*  destructor */
    &_synctex_log_vbox,         /*  log */
    &_synctex_display_vbox,     /*  display */
    &_synctex_abstract_vbox,    /*  abstract */
    &synctex_tree_model_vbox,   /*  tree model */
    &synctex_data_model_box,    /*  data model */
    &synctex_tlcpector_default, /*  tlcpector */
    &synctex_inspector_box,     /*  inspector */
    &synctex_vispector_box,     /*  vispector */
};

#ifdef SYNCTEX_NOTHING
#pragma mark hbox.
#endif

/*  Horizontal boxes must contain visible size, because 0 width does not mean emptiness.
 *  They also contain an average of the line numbers of the containing nodes. */

static const synctex_tree_model_s synctex_tree_model_hbox = {synctex_tree_sibling_idx,         /* sibling */
                                                             synctex_tree_s_parent_idx,        /* parent */
                                                             synctex_tree_sp_child_idx,        /* child */
                                                             synctex_tree_spc_friend_idx,      /* friend */
                                                             synctex_tree_spcf_last_idx,       /* last */
                                                             synctex_tree_spcfl_next_hbox_idx, /* next_hbox */
                                                             -1,                               /* arg_sibling */
                                                             -1,                               /* target */
                                                             synctex_tree_spcfln_hbox_max};

DEFINE_SYNCTEX_DATA_INT_GETSET(mean_line)
DEFINE_SYNCTEX_DATA_INT_GETSET(weight)
DEFINE_SYNCTEX_DATA_INT_GETSET(h_V)
DEFINE_SYNCTEX_DATA_INT_GETSET(v_V)
DEFINE_SYNCTEX_DATA_INT_GETSET(width_V)
DEFINE_SYNCTEX_DATA_INT_GETSET(height_V)
DEFINE_SYNCTEX_DATA_INT_GETSET(depth_V)

/**
 *  The hbox model.
 *  It contains V variants of geometrical information.
 *  It happens that hboxes contain material that is not used to compute
 *  the bounding box. Some letters may appear out of the box given by TeX.
 *  In such a situation, the visible bounding box is bigger than the V variant.
 *  Only hboxes have such variant. It does not make sense for void boxes
 *  and it is not used here for vboxes.
 *  - author: JL
 */

static const synctex_data_model_s synctex_data_model_hbox = {synctex_data_tag_idx,       /* tag */
                                                             synctex_data_line_idx,      /* line */
                                                             synctex_data_column_idx,    /* column */
                                                             synctex_data_h_idx,         /* h */
                                                             synctex_data_v_idx,         /* v */
                                                             synctex_data_width_idx,     /* width */
                                                             synctex_data_height_idx,    /* height */
                                                             synctex_data_depth_idx,     /* depth */
                                                             synctex_data_mean_line_idx, /* mean_line */
                                                             synctex_data_weight_idx,    /* weight */
                                                             synctex_data_h_V_idx,       /* h_V */
                                                             synctex_data_v_V_idx,       /* v_V */
                                                             synctex_data_width_V_idx,   /* width_V */
                                                             synctex_data_height_V_idx,  /* height_V */
                                                             synctex_data_depth_V_idx,   /* depth_V */
                                                             -1,                         /* name */
                                                             -1,                         /* page */
                                                             synctex_data_hbox_max};

typedef struct {
    SYNCTEX_DECLARE_CHARINDEX
    synctex_class_p class;
    synctex_data_u data[synctex_tree_spcfln_hbox_max + synctex_data_hbox_max];
} synctex_node_hbox_s;

/*  horizontal box node creator */
DEFINE_synctex_new_scanned_NODE(hbox)

    static void _synctex_log_hbox(synctex_node_p node);
static char *_synctex_abstract_hbox(synctex_node_p node);
static void _synctex_display_hbox(synctex_node_p node);

static synctex_class_s synctex_class_hbox = {
    NULL,                       /*  No scanner yet */
    synctex_node_type_hbox,     /*  Node type */
    &_synctex_new_hbox,         /*  creator */
    &_synctex_free_node,        /*  destructor */
    &_synctex_log_hbox,         /*  log */
    &_synctex_display_hbox,     /*  display */
    &_synctex_abstract_hbox,    /*  abstract */
    &synctex_tree_model_hbox,   /*  tree model */
    &synctex_data_model_hbox,   /*  data model */
    &synctex_tlcpector_default, /*  tlcpector */
    &synctex_inspector_box,     /*  inspector */
    &synctex_vispector_box,     /*  vispector */
};

#ifdef SYNCTEX_NOTHING
#pragma mark void vbox.
#endif

/*  This void box node implementation is either horizontal or vertical
 *  It does not contain a child field.
 */
static const synctex_tree_model_s synctex_tree_model_spf = {synctex_tree_sibling_idx,   /* sibling */
                                                            synctex_tree_s_parent_idx,  /* parent */
                                                            -1,                         /* child */
                                                            synctex_tree_sp_friend_idx, /* friend */
                                                            -1,                         /* last */
                                                            -1,                         /* next_hbox */
                                                            -1,                         /* arg_sibling */
                                                            -1,                         /* target */
                                                            synctex_tree_spf_max};
typedef struct {
    SYNCTEX_DECLARE_CHARINDEX
    synctex_class_p class;
    synctex_data_u data[synctex_tree_spf_max + synctex_data_box_max];
} synctex_node_void_vbox_s;

/*  vertical void box node creator */
DEFINE_synctex_new_scanned_NODE(void_vbox)

    static void _synctex_log_void_box(synctex_node_p node);
static char *_synctex_abstract_void_vbox(synctex_node_p node);
static void _synctex_display_void_vbox(synctex_node_p node);

static synctex_class_s synctex_class_void_vbox = {
    NULL,                         /*  No scanner yet */
    synctex_node_type_void_vbox,  /*  Node type */
    &_synctex_new_void_vbox,      /*  creator */
    &_synctex_free_leaf,          /*  destructor */
    &_synctex_log_void_box,       /*  log */
    &_synctex_display_void_vbox,  /*  display */
    &_synctex_abstract_void_vbox, /*  abstract */
    &synctex_tree_model_spf,      /*  tree model */
    &synctex_data_model_box,      /*  data model */
    &synctex_tlcpector_default,   /*  tlcpector */
    &synctex_inspector_box,       /*  inspector */
    &synctex_vispector_box,       /*  vispector */
};

#ifdef SYNCTEX_NOTHING
#pragma mark void hbox.
#endif

typedef synctex_node_void_vbox_s synctex_node_void_hbox_s;

/*  horizontal void box node creator */
DEFINE_synctex_new_scanned_NODE(void_hbox)

    static char *_synctex_abstract_void_hbox(synctex_node_p node);
static void _synctex_display_void_hbox(synctex_node_p node);

static synctex_class_s synctex_class_void_hbox = {
    NULL,                         /*  No scanner yet */
    synctex_node_type_void_hbox,  /*  Node type */
    &_synctex_new_void_hbox,      /*  creator */
    &_synctex_free_leaf,          /*  destructor */
    &_synctex_log_void_box,       /*  log */
    &_synctex_display_void_hbox,  /*  display */
    &_synctex_abstract_void_hbox, /*  abstract */
    &synctex_tree_model_spf,      /*  tree model */
    &synctex_data_model_box,      /*  data model */
    &synctex_tlcpector_default,   /*  tlcpector */
    &synctex_inspector_box,       /*  inspector */
    &synctex_vispector_box,       /*  vispector */
};

#ifdef SYNCTEX_NOTHING
#pragma mark form ref.
#endif

/*  The form ref node.  */
typedef struct {
    SYNCTEX_DECLARE_CHARINDEX
    synctex_class_p class;
    synctex_data_u data[synctex_tree_spfa_max + synctex_data_ref_thv_max];
} synctex_node_ref_s;

/*  form ref node creator */
DEFINE_synctex_new_scanned_NODE(ref)

    static void _synctex_log_ref(synctex_node_p node);
static char *_synctex_abstract_ref(synctex_node_p node);
static void _synctex_display_ref(synctex_node_p node);

static const synctex_tree_model_s synctex_tree_model_spfa = {synctex_tree_sibling_idx,         /* sibling */
                                                             synctex_tree_s_parent_idx,        /* parent */
                                                             -1,                               /* child */
                                                             synctex_tree_sp_friend_idx,       /* friend */
                                                             -1,                               /* last */
                                                             -1,                               /* next_hbox */
                                                             synctex_tree_spf_arg_sibling_idx, /* arg_sibling */
                                                             -1,                               /* target */
                                                             synctex_tree_spfa_max};
static const synctex_data_model_s synctex_data_model_ref = {synctex_data_tag_idx,   /* tag */
                                                            -1,                     /* line */
                                                            -1,                     /* column */
                                                            synctex_data_ref_h_idx, /* h */
                                                            synctex_data_ref_v_idx, /* v */
                                                            -1,                     /* width */
                                                            -1,                     /* height */
                                                            -1,                     /* depth */
                                                            -1,                     /* mean_line */
                                                            -1,                     /* weight */
                                                            -1,                     /* h_V */
                                                            -1,                     /* v_V */
                                                            -1,                     /* width_V */
                                                            -1,                     /* height_V */
                                                            -1,                     /* depth_V */
                                                            synctex_data_ref_thv_max};
static synctex_class_s synctex_class_ref = {
    NULL,                     /*  No scanner yet */
    synctex_node_type_ref,    /*  Node type */
    &_synctex_new_ref,        /*  creator */
    &_synctex_free_leaf,      /*  destructor */
    &_synctex_log_ref,        /*  log */
    &_synctex_display_ref,    /*  display */
    &_synctex_abstract_ref,   /*  abstract */
    &synctex_tree_model_spfa, /*  navigator */
    &synctex_data_model_ref,  /*  data model */
    &synctex_tlcpector_none,  /*  tlcpector */
    &synctex_inspector_none,  /*  inspector */
    &synctex_vispector_none,  /*  vispector */
};
#ifdef SYNCTEX_NOTHING
#pragma mark small node.
#endif

/*  The small nodes correspond to glue, penalty, math and boundary nodes. */
static const synctex_data_model_s synctex_data_model_tlchv = {synctex_data_tag_idx,    /* tag */
                                                              synctex_data_line_idx,   /* line */
                                                              synctex_data_column_idx, /* column */
                                                              synctex_data_h_idx,      /* h */
                                                              synctex_data_v_idx,      /* v */
                                                              -1,                      /* width */
                                                              -1,                      /* height */
                                                              -1,                      /* depth */
                                                              -1,                      /* mean_line */
                                                              -1,                      /* weight */
                                                              -1,                      /* h_V */
                                                              -1,                      /* v_V */
                                                              -1,                      /* width_V */
                                                              -1,                      /* height_V */
                                                              -1,                      /* depth_V */
                                                              -1,                      /* name */
                                                              -1,                      /* page */
                                                              synctex_data_tlchv_max};

typedef struct {
    SYNCTEX_DECLARE_CHARINDEX
    synctex_class_p class;
    synctex_data_u data[synctex_tree_spf_max + synctex_data_tlchv_max];
} synctex_node_tlchv_s;

static void _synctex_log_tlchv_node(synctex_node_p node);

#ifdef SYNCTEX_NOTHING
#pragma mark math.
#endif

typedef synctex_node_tlchv_s synctex_node_math_s;

/*  math node creator */
DEFINE_synctex_new_scanned_NODE(math)

    static char *_synctex_abstract_math(synctex_node_p node);
static void _synctex_display_math(synctex_node_p node);
static synctex_inspector_s synctex_inspector_hv = {
    &_synctex_data_h,
    &_synctex_data_v,
    &_synctex_int_none,
    &_synctex_int_none,
    &_synctex_int_none,
};
static synctex_vispector_s synctex_vispector_hv = {
    &__synctex_node_visible_h,
    &__synctex_node_visible_v,
    &_synctex_float_none,
    &_synctex_float_none,
    &_synctex_float_none,
};

static synctex_class_s synctex_class_math = {
    NULL,                       /*  No scanner yet */
    synctex_node_type_math,     /*  Node type */
    &_synctex_new_math,         /*  creator */
    &_synctex_free_leaf,        /*  destructor */
    &_synctex_log_tlchv_node,   /*  log */
    &_synctex_display_math,     /*  display */
    &_synctex_abstract_math,    /*  abstract */
    &synctex_tree_model_spf,    /*  tree model */
    &synctex_data_model_tlchv,  /*  data model */
    &synctex_tlcpector_default, /*  tlcpector */
    &synctex_inspector_hv,      /*  inspector */
    &synctex_vispector_hv,      /*  vispector */
};

#ifdef SYNCTEX_NOTHING
#pragma mark kern node.
#endif

static const synctex_data_model_s synctex_data_model_tlchvw = {synctex_data_tag_idx,    /* tag */
                                                               synctex_data_line_idx,   /* line */
                                                               synctex_data_column_idx, /* column */
                                                               synctex_data_h_idx,      /* h */
                                                               synctex_data_v_idx,      /* v */
                                                               synctex_data_width_idx,  /* width */
                                                               -1,                      /* height */
                                                               -1,                      /* depth */
                                                               -1,                      /* mean_line */
                                                               -1,                      /* weight */
                                                               -1,                      /* h_V */
                                                               -1,                      /* v_V */
                                                               -1,                      /* width_V */
                                                               -1,                      /* height_V */
                                                               -1,                      /* depth_V */
                                                               -1,                      /* name */
                                                               -1,                      /* page */
                                                               synctex_data_tlchvw_max};
typedef struct {
    SYNCTEX_DECLARE_CHARINDEX
    synctex_class_p class;
    synctex_data_u data[synctex_tree_spf_max + synctex_data_tlchvw_max];
} synctex_node_kern_s;

/*  kern node creator */
DEFINE_synctex_new_scanned_NODE(kern)

    static void _synctex_log_kern_node(synctex_node_p node);
static char *_synctex_abstract_kern(synctex_node_p node);
static void _synctex_display_kern(synctex_node_p node);

static synctex_inspector_s synctex_inspector_kern = {
    &_synctex_data_h,
    &_synctex_data_v,
    &_synctex_data_width,
    &_synctex_int_none,
    &_synctex_int_none,
};
static float __synctex_kern_visible_h(synctex_node_p node);
static float __synctex_kern_visible_width(synctex_node_p node);
static synctex_vispector_s synctex_vispector_kern = {
    &__synctex_kern_visible_h,
    &__synctex_node_visible_v,
    &__synctex_kern_visible_width,
    &_synctex_float_none,
    &_synctex_float_none,
};

static synctex_class_s synctex_class_kern = {
    NULL,                       /*  No scanner yet */
    synctex_node_type_kern,     /*  Node type */
    &_synctex_new_kern,         /*  creator */
    &_synctex_free_leaf,        /*  destructor */
    &_synctex_log_kern_node,    /*  log */
    &_synctex_display_kern,     /*  display */
    &_synctex_abstract_kern,    /*  abstract */
    &synctex_tree_model_spf,    /*  tree model */
    &synctex_data_model_tlchvw, /*  data model */
    &synctex_tlcpector_default, /*  tlcpector */
    &synctex_inspector_kern,    /*  inspector */
    &synctex_vispector_kern,    /*  vispector */
};

#ifdef SYNCTEX_NOTHING
#pragma mark glue.
#endif

/*  glue node creator */
typedef synctex_node_tlchv_s synctex_node_glue_s;
DEFINE_synctex_new_scanned_NODE(glue)

    static char *_synctex_abstract_glue(synctex_node_p node);
static void _synctex_display_glue(synctex_node_p node);

static synctex_class_s synctex_class_glue = {
    NULL,                       /*  No scanner yet */
    synctex_node_type_glue,     /*  Node type */
    &_synctex_new_glue,         /*  creator */
    &_synctex_free_leaf,        /*  destructor */
    &_synctex_log_tlchv_node,   /*  log */
    &_synctex_display_glue,     /*  display */
    &_synctex_abstract_glue,    /*  abstract */
    &synctex_tree_model_spf,    /*  tree model */
    &synctex_data_model_tlchv,  /*  data model */
    &synctex_tlcpector_default, /*  tlcpector */
    &synctex_inspector_hv,      /*  inspector */
    &synctex_vispector_hv,      /*  vispector */
};

/*  The small nodes correspond to glue and boundary nodes.  */

#ifdef SYNCTEX_NOTHING
#pragma mark rule.
#endif

typedef struct {
    SYNCTEX_DECLARE_CHARINDEX
    synctex_class_p class;
    synctex_data_u data[synctex_tree_spf_max + synctex_data_box_max];
} synctex_node_rule_s;

DEFINE_synctex_new_scanned_NODE(rule)

    static void _synctex_log_rule(synctex_node_p node);
static char *_synctex_abstract_rule(synctex_node_p node);
static void _synctex_display_rule(synctex_node_p node);

static float __synctex_rule_visible_h(synctex_node_p node);
static float __synctex_rule_visible_v(synctex_node_p node);
static float __synctex_rule_visible_width(synctex_node_p node);
static float __synctex_rule_visible_height(synctex_node_p node);
static float __synctex_rule_visible_depth(synctex_node_p node);
static synctex_vispector_s synctex_vispector_rule = {
    &__synctex_rule_visible_h,
    &__synctex_rule_visible_v,
    &__synctex_rule_visible_width,
    &__synctex_rule_visible_height,
    &__synctex_rule_visible_depth,
};

static synctex_class_s synctex_class_rule = {
    NULL,                       /*  No scanner yet */
    synctex_node_type_rule,     /*  Node type */
    &_synctex_new_rule,         /*  creator */
    &_synctex_free_leaf,        /*  destructor */
    &_synctex_log_rule,         /*  log */
    &_synctex_display_rule,     /*  display */
    &_synctex_abstract_rule,    /*  abstract */
    &synctex_tree_model_spf,    /*  tree model */
    &synctex_data_model_box,    /*  data model */
    &synctex_tlcpector_default, /*  tlcpector */
    &synctex_inspector_box,     /*  inspector */
    &synctex_vispector_rule,    /*  vispector */
};

#ifdef SYNCTEX_NOTHING
#pragma mark boundary.
#endif

/*  boundary node creator */
typedef synctex_node_tlchv_s synctex_node_boundary_s;
DEFINE_synctex_new_scanned_NODE(boundary)

    static char *_synctex_abstract_boundary(synctex_node_p node);
static void _synctex_display_boundary(synctex_node_p node);

static synctex_class_s synctex_class_boundary = {
    NULL,                        /*  No scanner yet */
    synctex_node_type_boundary,  /*  Node type */
    &_synctex_new_boundary,      /*  creator */
    &_synctex_free_leaf,         /*  destructor */
    &_synctex_log_tlchv_node,    /*  log */
    &_synctex_display_boundary,  /*  display */
    &_synctex_abstract_boundary, /*  abstract */
    &synctex_tree_model_spf,     /*  tree model */
    &synctex_data_model_tlchv,   /*  data model */
    &synctex_tlcpector_default,  /*  tlcpector */
    &synctex_inspector_hv,       /*  inspector */
    &synctex_vispector_hv,       /*  vispector */
};

#ifdef SYNCTEX_NOTHING
#pragma mark box boundary.
#endif

typedef struct {
    SYNCTEX_DECLARE_CHARINDEX
    synctex_class_p class;
    synctex_data_u data[synctex_tree_spfa_max + synctex_data_tlchv_max];
} synctex_node_box_bdry_s;

#define DEFINE_synctex_new_unscanned_NODE(NAME)                                                                                                                                                                                                \
    SYNCTEX_INLINE static synctex_node_p _synctex_new_##NAME(synctex_scanner_p scanner)                                                                                                                                                        \
    {                                                                                                                                                                                                                                          \
        if (scanner) {                                                                                                                                                                                                                         \
            synctex_node_p node = _synctex_malloc(sizeof(synctex_node_##NAME##_s));                                                                                                                                                            \
            if (node) {                                                                                                                                                                                                                        \
                node->class = scanner->class + synctex_node_type_##NAME;                                                                                                                                                                       \
                SYNCTEX_DID_NEW(node);                                                                                                                                                                                                         \
            }                                                                                                                                                                                                                                  \
            return node;                                                                                                                                                                                                                       \
        }                                                                                                                                                                                                                                      \
        return NULL;                                                                                                                                                                                                                           \
    }
DEFINE_synctex_new_unscanned_NODE(box_bdry)

    static char *_synctex_abstract_box_bdry(synctex_node_p node);
static void _synctex_display_box_bdry(synctex_node_p node);

static synctex_class_s synctex_class_box_bdry = {
    NULL,                        /*  No scanner yet */
    synctex_node_type_box_bdry,  /*  Node type */
    &_synctex_new_box_bdry,      /*  creator */
    &_synctex_free_leaf,         /*  destructor */
    &_synctex_log_tlchv_node,    /*  log */
    &_synctex_display_box_bdry,  /*  display */
    &_synctex_abstract_box_bdry, /*  display */
    &synctex_tree_model_spfa,    /*  tree model */
    &synctex_data_model_tlchv,   /*  data model */
    &synctex_tlcpector_default,  /*  tlcpector */
    &synctex_inspector_hv,       /*  inspector */
    &synctex_vispector_hv,       /*  vispector */
};

#ifdef SYNCTEX_NOTHING
#pragma mark hbox proxy.
#endif

/**
 *  Standard nodes refer to TeX nodes: math, kern, boxes...
 *  Proxy nodes are used to support forms.
 *  A form is parsed as a tree of standard nodes starting
 *  at the top left position.
 *  When a reference is used, the form is duplicated
 *  to the location specified by the reference.
 *  As the same form can be duplicated at different locations,
 *  the geometrical information is relative to its own top left point.
 *  As we need absolute locations, we use proxy nodes.
 *  A proxy node records an offset and the target node.
 *  The target partly acts as a delegate.
 *  The h and v position of the proxy node is the h and v
 *  position of the target shifted by the proxy's offset.
 *  The width, height and depth are not sensitive to offsets.
 *  When are proxies created ?
 *  1)  when the synctex file has been parsed, all the form refs
 *  are replaced by proxies to the content of a form.
 *  This content is a node with siblings (actually none).
 *  Those root proxies have the parent of the ref they replace,
 *  so their parents exist and are no proxy.
 *  Moreover, if they have no sibling, it means that their target have no
 *  sibling as well.
 *  Such nodes are called root proxies.
 *  2)  On the fly, when a proxy is asked for its child
 *  (or sibling) and has none, a proxy to its target's child
 *  (or sibling) is created if any. There are only 2 possible situations:
 *  either the newly created proxy is the child of a proxy,
 *  or it is the sibling of a proxy created on the fly.
 *  In both cases, the parent is a proxy with children.
 *  Such nodes are called child proxies.
 *  How to compute the offset of a proxy ?
 *  The offset of root proxy objects is exactly
 *  the offset of the ref they replace.
 *  The offset of other proxies is their owner's,
 *  except when pointing to a root proxy.
 *  What happens for cascading forms ?
 *  Here is an example diagram
 *
 *  At parse time, the arrow means "owns":
 *  sheet0 -> ref_to1
 *
 *            target1 -> ref_to2
 *
 *                       target2 -> child22
 *
 *  After replacing the refs:
 *  sheet0 -> proxy00 -> proxy01 -> proxy02
 *               |          |          |
 *            target1 -> proxy11 -> proxy12
 *                          |          |
 *                       target2 -> proxy22
 *
 *  proxy00, proxy11 and proxy22 are root proxies.
 *  Their offset is the one of the ref they replace
 *  proxy01, proxy02 and proxy12 are child proxies.
 *  Their proxy is the one of their parent.
 *  Optimization.
 *  After all the refs are replaced, there are only root nodes
 *  targeting standard node. We make sure that each child proxy
 *  also targets a standard node.
 *  It is possible for a proxy to have a standard sibling
 *  whereas its target has no sibling at all. Root proxies
 *  are such nodes, and are the only ones.
 *  The consequence is that proxies created on the fly
 *  must take into account this situation.
 */

/*  A proxy to a hbox.
 *  A proxy do have a target, which can be a proxy
 */

static const synctex_tree_model_s synctex_tree_model_proxy_hbox = {synctex_tree_sibling_idx,         /* sibling */
                                                                   synctex_tree_s_parent_idx,        /* parent */
                                                                   synctex_tree_sp_child_idx,        /* child */
                                                                   synctex_tree_spc_friend_idx,      /* friend */
                                                                   synctex_tree_spcf_last_idx,       /* last */
                                                                   synctex_tree_spcfl_next_hbox_idx, /* next_hbox */
                                                                   -1,                               /* arg_sibling */
                                                                   synctex_tree_spcfln_target_idx,   /* target */
                                                                   synctex_tree_spcflnt_proxy_hbox_max};
static const synctex_data_model_s synctex_data_model_proxy = {-1,                       /* tag */
                                                              -1,                       /* line */
                                                              -1,                       /* column */
                                                              synctex_data_proxy_h_idx, /* h */
                                                              synctex_data_proxy_v_idx, /* v */
                                                              -1,                       /* width */
                                                              -1,                       /* height */
                                                              -1,                       /* depth */
                                                              -1,                       /* mean_line */
                                                              -1,                       /* weight */
                                                              -1,                       /* h_V */
                                                              -1,                       /* v_V */
                                                              -1,                       /* width_V */
                                                              -1,                       /* height_V */
                                                              -1,                       /* depth_V */
                                                              -1,                       /* name */
                                                              -1,                       /* page */
                                                              synctex_data_proxy_hv_max};
typedef struct {
    SYNCTEX_DECLARE_CHARINDEX
    synctex_class_p class;
    synctex_data_u data[synctex_tree_spcflnt_proxy_hbox_max + synctex_data_proxy_hv_max];
} synctex_node_proxy_hbox_s;

/*  box proxy node creator */
DEFINE_synctex_new_unscanned_NODE(proxy_hbox)

    static void _synctex_log_proxy(synctex_node_p node);
static char *_synctex_abstract_proxy_hbox(synctex_node_p node);
static void _synctex_display_proxy_hbox(synctex_node_p node);

static int _synctex_proxy_tag(synctex_node_p);
static int _synctex_proxy_line(synctex_node_p);
static int _synctex_proxy_column(synctex_node_p);

static synctex_tlcpector_s synctex_tlcpector_proxy = {
    &_synctex_proxy_tag,
    &_synctex_proxy_line,
    &_synctex_proxy_column,
};
static int _synctex_proxy_h(synctex_node_p);
static int _synctex_proxy_v(synctex_node_p);
static int _synctex_proxy_width(synctex_node_p);
static int _synctex_proxy_height(synctex_node_p);
static int _synctex_proxy_depth(synctex_node_p);
static synctex_inspector_s synctex_inspector_proxy_box = {
    &_synctex_proxy_h,
    &_synctex_proxy_v,
    &_synctex_proxy_width,
    &_synctex_proxy_height,
    &_synctex_proxy_depth,
};

static float __synctex_proxy_visible_h(synctex_node_p);
static float __synctex_proxy_visible_v(synctex_node_p);
static float __synctex_proxy_visible_width(synctex_node_p);
static float __synctex_proxy_visible_height(synctex_node_p);
static float __synctex_proxy_visible_depth(synctex_node_p);

static synctex_vispector_s synctex_vispector_proxy_box = {
    &__synctex_proxy_visible_h,
    &__synctex_proxy_visible_v,
    &__synctex_proxy_visible_width,
    &__synctex_proxy_visible_height,
    &__synctex_proxy_visible_depth,
};

static synctex_class_s synctex_class_proxy_hbox = {
    NULL,                           /*  No scanner yet */
    synctex_node_type_proxy_hbox,   /*  Node type */
    &_synctex_new_proxy_hbox,       /*  creator */
    &_synctex_free_node,            /*  destructor */
    &_synctex_log_proxy,            /*  log */
    &_synctex_display_proxy_hbox,   /*  display */
    &_synctex_abstract_proxy_hbox,  /*  abstract */
    &synctex_tree_model_proxy_hbox, /*  tree model */
    &synctex_data_model_proxy,      /*  data model */
    &synctex_tlcpector_proxy,       /*  tlcpector */
    &synctex_inspector_proxy_box,   /*  inspector */
    &synctex_vispector_proxy_box,   /*  vispector */
};

#ifdef SYNCTEX_NOTHING
#pragma mark vbox proxy.
#endif

/*  A proxy to a vbox. */

static const synctex_tree_model_s synctex_tree_model_proxy_vbox = {synctex_tree_sibling_idx,      /* sibling */
                                                                   synctex_tree_s_parent_idx,     /* parent */
                                                                   synctex_tree_sp_child_idx,     /* child */
                                                                   synctex_tree_spc_friend_idx,   /* friend */
                                                                   synctex_tree_spcf_last_idx,    /* last */
                                                                   -1,                            /* next_hbox */
                                                                   -1,                            /* arg_sibling */
                                                                   synctex_tree_spcfl_target_idx, /* target */
                                                                   synctex_tree_spcflt_proxy_vbox_max};

typedef struct {
    SYNCTEX_DECLARE_CHARINDEX
    synctex_class_p class;
    synctex_data_u data[synctex_tree_spcflt_proxy_vbox_max + synctex_data_proxy_hv_max];
} synctex_node_proxy_vbox_s;

/*  box proxy node creator */
DEFINE_synctex_new_unscanned_NODE(proxy_vbox)

    static void _synctex_log_proxy(synctex_node_p node);
static char *_synctex_abstract_proxy_vbox(synctex_node_p node);
static void _synctex_display_proxy_vbox(synctex_node_p node);

static synctex_class_s synctex_class_proxy_vbox = {
    NULL,                           /*  No scanner yet */
    synctex_node_type_proxy_vbox,   /*  Node type */
    &_synctex_new_proxy_vbox,       /*  creator */
    &_synctex_free_node,            /*  destructor */
    &_synctex_log_proxy,            /*  log */
    &_synctex_display_proxy_vbox,   /*  display */
    &_synctex_abstract_proxy_vbox,  /*  abstract */
    &synctex_tree_model_proxy_vbox, /*  tree model */
    &synctex_data_model_proxy,      /*  data model */
    &synctex_tlcpector_proxy,       /*  tlcpector */
    &synctex_inspector_proxy_box,   /*  inspector */
    &synctex_vispector_proxy_box,   /*  vispector */
};

#ifdef SYNCTEX_NOTHING
#pragma mark proxy.
#endif

/**
 *  A proxy to a node but a box.
 */

static const synctex_tree_model_s synctex_tree_model_proxy = {synctex_tree_sibling_idx,    /* sibling */
                                                              synctex_tree_s_parent_idx,   /* parent */
                                                              -1,                          /* child */
                                                              synctex_tree_sp_friend_idx,  /* friend */
                                                              -1,                          /* last */
                                                              -1,                          /* next_hbox */
                                                              -1,                          /* arg_sibling */
                                                              synctex_tree_spf_target_idx, /* target */
                                                              synctex_tree_spft_proxy_max};

typedef struct {
    SYNCTEX_DECLARE_CHARINDEX
    synctex_class_p class;
    synctex_data_u data[synctex_tree_spft_proxy_max + synctex_data_proxy_hv_max];
} synctex_node_proxy_s;

/*  proxy node creator */
DEFINE_synctex_new_unscanned_NODE(proxy)

    static void _synctex_log_proxy(synctex_node_p node);
static char *_synctex_abstract_proxy(synctex_node_p node);
static void _synctex_display_proxy(synctex_node_p node);

static synctex_vispector_s synctex_vispector_proxy = {
    &__synctex_proxy_visible_h,
    &__synctex_proxy_visible_v,
    &__synctex_proxy_visible_width,
    &_synctex_float_none,
    &_synctex_float_none,
};

static synctex_class_s synctex_class_proxy = {
    NULL,                         /*  No scanner yet */
    synctex_node_type_proxy,      /*  Node type */
    &_synctex_new_proxy,          /*  creator */
    &_synctex_free_leaf,          /*  destructor */
    &_synctex_log_proxy,          /*  log */
    &_synctex_display_proxy,      /*  display */
    &_synctex_abstract_proxy,     /*  abstract */
    &synctex_tree_model_proxy,    /*  tree model */
    &synctex_data_model_proxy,    /*  data model */
    &synctex_tlcpector_proxy,     /*  tlcpector */
    &synctex_inspector_proxy_box, /*  inspector */
    &synctex_vispector_proxy,     /*  vispector */
};

#ifdef SYNCTEX_NOTHING
#pragma mark last proxy.
#endif

/**
 *  A proxy to the last proxy/box boundary.
 */

static const synctex_tree_model_s synctex_tree_model_proxy_last = {synctex_tree_sibling_idx,         /* sibling */
                                                                   synctex_tree_s_parent_idx,        /* parent */
                                                                   -1,                               /* child */
                                                                   synctex_tree_sp_friend_idx,       /* friend */
                                                                   -1,                               /* last */
                                                                   -1,                               /* next_hbox */
                                                                   synctex_tree_spf_arg_sibling_idx, /* arg_sibling */
                                                                   synctex_tree_spfa_target_idx,     /* target */
                                                                   synctex_tree_spfat_proxy_last_max};

typedef struct {
    SYNCTEX_DECLARE_CHARINDEX
    synctex_class_p class;
    synctex_data_u data[synctex_tree_spfat_proxy_last_max + synctex_data_proxy_hv_max];
} synctex_node_proxy_last_s;

/*  proxy node creator */
DEFINE_synctex_new_unscanned_NODE(proxy_last)

    static void _synctex_log_proxy(synctex_node_p node);
static char *_synctex_abstract_proxy(synctex_node_p node);
static void _synctex_display_proxy(synctex_node_p node);

static synctex_class_s synctex_class_proxy_last = {
    NULL,                           /*  No scanner yet */
    synctex_node_type_proxy_last,   /*  Node type */
    &_synctex_new_proxy,            /*  creator */
    &_synctex_free_leaf,            /*  destructor */
    &_synctex_log_proxy,            /*  log */
    &_synctex_display_proxy,        /*  display */
    &_synctex_abstract_proxy,       /*  abstract */
    &synctex_tree_model_proxy_last, /*  tree model */
    &synctex_data_model_proxy,      /*  data model */
    &synctex_tlcpector_proxy,       /*  tlcpector */
    &synctex_inspector_proxy_box,   /*  inspector */
    &synctex_vispector_proxy,       /*  vispector */
};

#ifdef SYNCTEX_NOTHING
#pragma mark handle.
#endif

/**
 *  A result node.
 */

static const synctex_tree_model_s synctex_tree_model_handle = {synctex_tree_sibling_idx,    /* sibling */
                                                               synctex_tree_s_parent_idx,   /* parent */
                                                               synctex_tree_sp_child_idx,   /* child */
                                                               -1,                          /* friend */
                                                               -1,                          /* last */
                                                               -1,                          /* next_hbox */
                                                               -1,                          /* arg_sibling */
                                                               synctex_tree_spc_target_idx, /* target */
                                                               synctex_tree_spct_handle_max};

typedef struct {
    SYNCTEX_DECLARE_CHARINDEX
    synctex_class_p class;
    synctex_data_u data[synctex_tree_spct_handle_max + 0];
} synctex_node_handle_s;

/*  result node creator */
DEFINE_synctex_new_unscanned_NODE(handle)

    static void _synctex_log_handle(synctex_node_p node);
static char *_synctex_abstract_handle(synctex_node_p node);
static void _synctex_display_handle(synctex_node_p node);

static synctex_class_s synctex_class_handle = {
    NULL,                         /*  No scanner yet */
    synctex_node_type_handle,     /*  Node type */
    &_synctex_new_handle,         /*  creator */
    &_synctex_free_node,          /*  destructor */
    &_synctex_log_handle,         /*  log */
    &_synctex_display_handle,     /*  display */
    &_synctex_abstract_handle,    /*  abstract */
    &synctex_tree_model_handle,   /*  tree model */
    &synctex_data_model_none,     /*  data model */
    &synctex_tlcpector_proxy,     /*  tlcpector */
    &synctex_inspector_proxy_box, /*  inspector */
    &synctex_vispector_proxy_box, /*  vispector */
};

SYNCTEX_INLINE static synctex_node_p _synctex_new_handle_with_target(synctex_node_p target)
{
    if (target) {
        synctex_node_p result = _synctex_new_handle(target->class->scanner);
        if (result) {
            _synctex_tree_set_target(result, target);
            return result;
        }
    }
    return NULL;
}

#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark Navigation
#endif
synctex_node_p synctex_node_parent(synctex_node_p node)
{
    return _synctex_tree_parent(node);
}
synctex_node_p synctex_node_parent_sheet(synctex_node_p node)
{
    while (node && synctex_node_type(node) != synctex_node_type_sheet) {
        node = _synctex_tree_parent(node);
    }
    /*  exit the while loop either when node is NULL or node is a sheet */
    return node;
}
synctex_node_p synctex_node_parent_form(synctex_node_p node)
{
    while (node && synctex_node_type(node) != synctex_node_type_form) {
        node = _synctex_tree_parent(node);
    }
    /*  exit the while loop either when node is NULL or node is a form */
    return node;
}

/**
 *  The returned proxy will be the child or a sibling of source.
 *  The returned proxy has no parent, child nor sibling.
 *  Used only by __synctex_replace_ref.
 *  argument to_node: a box, not a proxy nor anything else.
 */
SYNCTEX_INLINE static synctex_node_p __synctex_new_proxy_from_ref_to(synctex_node_p ref, synctex_node_p to_node)
{
    synctex_node_p proxy = NULL;
    if (!ref || !to_node) {
        return NULL;
    }
    switch (synctex_node_type(to_node)) {
    case synctex_node_type_vbox:
        proxy = _synctex_new_proxy_vbox(ref->class->scanner);
        break;
    case synctex_node_type_hbox:
        proxy = _synctex_new_proxy_hbox(ref->class->scanner);
        break;
    default:
        _synctex_error("!  __synctex_new_proxy_from_ref_to. Unexpected form child (%s). Please report.", synctex_node_isa(to_node));
        return NULL;
    }
    if (!proxy) {
        _synctex_error("!  __synctex_new_proxy_from_ref_to. Internal error. Please report.");
        return NULL;
    }
    _synctex_data_set_h(proxy, _synctex_data_h(ref));
    _synctex_data_set_v(proxy, _synctex_data_v(ref));
    _synctex_tree_set_target(proxy, to_node);
#if defined(SYNCTEX_USE_CHARINDEX)
    proxy->line_index = to_node ? to_node->line_index : 0;
    proxy->char_index = to_node ? to_node->char_index : 0;
#endif
    return proxy;
}
/**
 *  The returned proxy will be the child or a sibling of owning_proxy.
 *  The returned proxy has no parent, nor child.
 *  Used only by synctex_node_child and synctex_node_sibling
 *  to create proxies on the fly.
 *  If the to_node has an already computed sibling,
 *  then the returned proxy has itself a sibling
 *  pointing to that already computed sibling.
 */
SYNCTEX_INLINE static synctex_node_p __synctex_new_child_proxy_to(synctex_node_p owner, synctex_node_p to_node)
{
    synctex_node_p proxy = NULL;
    synctex_node_p target = to_node;
    if (!owner) {
        return NULL;
    }
    switch (synctex_node_type(target)) {
    case synctex_node_type_vbox:
        if ((proxy = _synctex_new_proxy_vbox(owner->class->scanner))) {
        exit_standard:
            _synctex_data_set_h(proxy, _synctex_data_h(owner));
            _synctex_data_set_v(proxy, _synctex_data_v(owner));
        exit0:
            _synctex_tree_set_target(proxy, target);
#if defined(SYNCTEX_USE_CHARINDEX)
            proxy->line_index = to_node ? to_node->line_index : 0;
            proxy->char_index = to_node ? to_node->char_index : 0;
#endif
            return proxy;
        };
        break;
    case synctex_node_type_proxy_vbox:
        if ((proxy = _synctex_new_proxy_vbox(owner->class->scanner))) {
        exit_proxy:
            target = _synctex_tree_target(to_node);
            _synctex_data_set_h(proxy, _synctex_data_h(owner) + _synctex_data_h(to_node));
            _synctex_data_set_v(proxy, _synctex_data_v(owner) + _synctex_data_v(to_node));
            goto exit0;
        };
        break;
    case synctex_node_type_hbox:
        if ((proxy = _synctex_new_proxy_hbox(owner->class->scanner))) {
            goto exit_standard;
        };
        break;
    case synctex_node_type_proxy_hbox:
        if ((proxy = _synctex_new_proxy_hbox(owner->class->scanner))) {
            goto exit_proxy;
        };
        break;
    case synctex_node_type_proxy:
    case synctex_node_type_proxy_last:
        if ((proxy = _synctex_new_proxy(owner->class->scanner))) {
            goto exit_proxy;
        };
        break;
    default:
        if ((proxy = _synctex_new_proxy(owner->class->scanner))) {
            goto exit_standard;
        };
        break;
    }
    _synctex_error(
        "!  __synctex_new_child_proxy_to. "
        "Internal error. "
        "Please report.");
    return NULL;
}
SYNCTEX_INLINE static synctex_node_p _synctex_tree_set_sibling(synctex_node_p node, synctex_node_p new_sibling);
typedef struct synctex_nns_t {
    synctex_node_p first;
    synctex_node_p last;
    synctex_status_t status;
} synctex_nns_s;
/**
 *  Given a target node, create a list of proxies.
 *  The first proxy points to the target node,
 *  its sibling points to the target's sibling and so on.
 *  Returns the first created proxy, the last one and
 *  an error status.
 */
SYNCTEX_INLINE static synctex_nns_s _synctex_new_child_proxies_to(synctex_node_p owner, synctex_node_p to_node)
{
    synctex_nns_s nns = {NULL, NULL, SYNCTEX_STATUS_OK};
    if ((nns.first = nns.last = __synctex_new_child_proxy_to(owner, to_node))) {
        synctex_node_p to_next_sibling = __synctex_tree_sibling(to_node);
        synctex_node_p to_sibling;
        while ((to_sibling = to_next_sibling)) {
            synctex_node_p sibling;
            if ((to_next_sibling = __synctex_tree_sibling(to_sibling))) {
                /*  This is not the last sibling */
                if ((sibling = __synctex_new_child_proxy_to(owner, to_sibling))) {
                    _synctex_tree_set_sibling(nns.last, sibling);
                    nns.last = sibling;
                    continue;
                } else {
                    _synctex_error(
                        "!  _synctex_new_child_proxy_to. "
                        "Internal error (1). "
                        "Please report.");
                    nns.status = SYNCTEX_STATUS_ERROR;
                }
            } else if ((sibling = _synctex_new_proxy_last(owner->class->scanner))) {
                _synctex_tree_set_sibling(nns.last, sibling);
                nns.last = sibling;
                _synctex_data_set_h(nns.last, _synctex_data_h(nns.first));
                _synctex_data_set_v(nns.last, _synctex_data_v(nns.first));
                _synctex_tree_set_target(nns.last, to_sibling);
#if defined(SYNCTEX_USE_CHARINDEX)
                nns.last->line_index = to_sibling->line_index;
                nns.last->char_index = to_sibling->char_index;
#endif
            } else {
                _synctex_error(
                    "!  _synctex_new_child_proxy_to. "
                    "Internal error (2). "
                    "Please report.");
                nns.status = SYNCTEX_STATUS_ERROR;
            }
            break;
        }
    }
    return nns;
}
static const char *_synctex_node_abstract(synctex_node_p node);
SYNCTEX_INLINE static synctex_node_p synctex_tree_set_friend(synctex_node_p node, synctex_node_p new_friend)
{
#if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG
    synctex_node_p F = new_friend;
    while (F) {
        if (node == F) {
            printf("THIS IS AN ERROR\n");
            F = new_friend;
            while (F) {
                printf("%s\n", _synctex_node_abstract(F));
                if (node == F) {
                    return NULL;
                }
                F = _synctex_tree_friend(F);
            }
            return NULL;
        }
        F = _synctex_tree_friend(F);
    }
#endif
    return new_friend ? _synctex_tree_set_friend(node, new_friend) : _synctex_tree_reset_friend(node);
}
/**
 *
 */
SYNCTEX_INLINE static synctex_node_p __synctex_node_make_friend(synctex_node_p node, int i)
{
    synctex_node_p old = NULL;
    if (i >= 0) {
        i = i % (node->class->scanner->number_of_lists);
        old = synctex_tree_set_friend(node, (node->class->scanner->lists_of_friends)[i]);
        (node->class->scanner->lists_of_friends)[i] = node;
#if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500
        printf("tl(%i)=>", i);
        synctex_node_log(node);
        if (synctex_node_parent_form(node)) {
            printf("!  ERROR. No registration expected!\n");
        }
#endif
    }
    return old;
}
/**
 *  All proxies have tlc attributes, on behalf of their target.
 *  The purpose is to register all af them.
 *  - argument node: is the proxy, must not be NULL
 */
SYNCTEX_INLINE static synctex_node_p __synctex_proxy_make_friend_and_next_hbox(synctex_node_p node)
{
    synctex_node_p old = NULL;
    synctex_node_p target = _synctex_tree_target(node);
    if (target) {
        int i = _synctex_data_tag(target) + _synctex_data_line(target);
        old = __synctex_node_make_friend(node, i);
    } else {
        old = __synctex_tree_reset_friend(node);
    }
    if (synctex_node_type(node) == synctex_node_type_proxy_hbox) {
        synctex_node_p sheet = synctex_node_parent_sheet(node);
        if (sheet) {
            _synctex_tree_set_next_hbox(node, _synctex_tree_next_hbox(sheet));
            _synctex_tree_set_next_hbox(sheet, node);
        }
    }
    return old;
}
/**
 *  Register a node which have tag, line and column.
 *  - argument node: the node
 */
SYNCTEX_INLINE static synctex_node_p __synctex_node_make_friend_tlc(synctex_node_p node)
{
    int i = synctex_node_tag(node) + synctex_node_line(node);
    return __synctex_node_make_friend(node, i);
}
/**
 *  Register a node which have tag, line and column.
 *  Does nothing if the argument is NULL.
 *  Calls __synctex_node_make_friend_tlc.
 *  - argument node: the node
 */
SYNCTEX_INLINE static void _synctex_node_make_friend_tlc(synctex_node_p node)
{
    if (node) {
        __synctex_node_make_friend_tlc(node);
    }
}
static synctex_node_p _synctex_node_set_child(synctex_node_p node, synctex_node_p new_child);
/**
 *  The (first) child of the node, if any, NULL otherwise.
 *  At parse time, non void box nodes have children.
 *  All other nodes have no children.
 *  In order to support pdf forms, proxies are created
 *  to place form nodes at real locations.
 *  Ref nodes are replaced by root proxies targeting
 *  form contents. If root proxies have no children,
 *  they are created on the fly as proxies to the
 *  children of the targeted box.
 *  As such, proxies created here are targeting a
 *  node that belongs to a form.
 *  This is the only place where child proxies are created.
 */
synctex_node_p synctex_node_child(synctex_node_p node)
{
    synctex_node_p child = NULL;
    synctex_node_p target = NULL;
    if ((child = _synctex_tree_child(node))) {
        return child;
    } else if ((target = _synctex_tree_target(node))) {
        if ((child = synctex_node_child(target))) {
            /*  This is a proxy with no child
             *  which target does have a child. */
            synctex_nns_s nns = _synctex_new_child_proxies_to(node, child);
            if (nns.first) {
                _synctex_node_set_child(node, nns.first);
                return nns.first;
            } else {
                _synctex_error("!  synctex_node_child. Internal inconsistency. Please report.");
            }
        }
    }
    return NULL;
}
/*
 *  Set the parent/child bound.
 *  Things get complicated when new_child has siblings.
 *  The caller is responsible for releasing the returned value.
 */
static synctex_node_p _synctex_node_set_child(synctex_node_p parent, synctex_node_p new_child)
{
    if (parent) {
        synctex_node_p old = _synctex_tree_set_child(parent, new_child);
        synctex_node_p last_child = NULL;
        synctex_node_p child;
        if ((child = old)) {
            do {
                _synctex_tree_reset_parent(child);
            } while ((child = __synctex_tree_sibling(child)));
        }
        if ((child = new_child)) {
            do {
                _synctex_tree_set_parent(child, parent);
                last_child = child;
            } while ((child = __synctex_tree_sibling(child)));
        }
        _synctex_tree_set_last(parent, last_child);
        return old;
    }
    return NULL;
}

/*  The last child of the given node, or NULL.
 */
synctex_node_p synctex_node_last_child(synctex_node_p node)
{
    return _synctex_tree_last(node);
}
/**
 *  All nodes siblings are properly set up at parse time
 *  except for non root proxies.
 */
synctex_node_p synctex_node_sibling(synctex_node_p node)
{
    return node ? __synctex_tree_sibling(node) : NULL;
}
/**
 *  All the _synctex_tree_... methods refer to the tree model.
 *  __synctex_tree_... methods are low level.
 */
/**
 *  Replace the sibling.
 *  Connect to the arg_sibling of the new_sibling if relevant.
 *  - returns the old sibling.
 *  The caller is responsible for releasing the old sibling.
 *  The bound to the parent is managed below.
 */
SYNCTEX_INLINE static synctex_node_p _synctex_tree_set_sibling(synctex_node_p node, synctex_node_p new_sibling)
{
    if (node == new_sibling) {
        printf("BOF\n");
    }
    synctex_node_p old = node ? __synctex_tree_set_sibling(node, new_sibling) : NULL;
    _synctex_tree_set_arg_sibling(new_sibling, node);
    return old;
}
/**
 *  Replace the sibling.
 *  Set the parent of the new sibling (and further siblings)
 *  to the parent of the receiver.
 *  Also set the last sibling of parent.
 *  - argument new_sibling: must not be NULL.
 *  - returns the old sibling.
 *  The caller is responsible for releasing the old sibling.
 */
static synctex_node_p _synctex_node_set_sibling(synctex_node_p node, synctex_node_p new_sibling)
{
    if (node && new_sibling) {
        synctex_node_p old = _synctex_tree_set_sibling(node, new_sibling);
        if (_synctex_tree_has_parent(node)) {
            synctex_node_p parent = __synctex_tree_parent(node);
            if (parent) {
                synctex_node_p N = new_sibling;
                while (synctex_YES) {
                    if (_synctex_tree_has_parent(N)) {
                        __synctex_tree_set_parent(N, parent);
                        _synctex_tree_set_last(parent, N);
                        N = __synctex_tree_sibling(N);
                        continue;
                    } else if (N) {
                        _synctex_error(
                            "!  synctex_node_sibling. "
                            "Internal inconsistency. "
                            "Please report.");
                    }
                    break;
                }
            }
        }
        return old;
    }
    return NULL;
}
/**
 *  The last sibling of the given node, or NULL with node.
 */
synctex_node_p synctex_node_last_sibling(synctex_node_p node)
{
    synctex_node_p sibling;
    do {
        sibling = node;
    } while ((node = synctex_node_sibling(node)));
    return sibling;
}
/**
 *  The next nodes corresponds to a deep first tree traversal.
 *  Does not create child proxies as side effect contrary to
 *  the synctex_node_next method above.
 *  May loop infinitely many times if the tree
 *  is not properly built (contains loops).
 */
SYNCTEX_INLINE static synctex_node_p _synctex_node_sibling_or_parents(synctex_node_p node)
{
    while (node) {
        synctex_node_p N;
        if ((N = __synctex_tree_sibling(node))) {
            return N;
        } else if ((node = _synctex_tree_parent(node))) {
            if (synctex_node_type(node) == synctex_node_type_sheet) { /*  EXC_BAD_ACCESS? */
                return NULL;
            } else if (synctex_node_type(node) == synctex_node_type_form) {
                return NULL;
            }
        } else {
            return NULL;
        }
    }
    return NULL;
}
/**
 *  The next nodes corresponds to a deep first tree traversal.
 *  Creates child proxies as side effect.
 *  May loop infinitely many times if the tree
 *  is not properly built (contains loops).
 */
synctex_node_p synctex_node_next(synctex_node_p node)
{
    synctex_node_p N = synctex_node_child(node);
    if (N) {
        return N;
    }
    return _synctex_node_sibling_or_parents(node);
}
/**
 *  The next nodes corresponds to a deep first tree traversal.
 *  Does not create child proxies as side effect contrary to
 *  the synctex_node_next method above.
 *  May loop infinitely many times if the tree
 *  is not properly built (contains loops).
 */
synctex_node_p _synctex_node_next(synctex_node_p node)
{
    synctex_node_p N = _synctex_tree_child(node);
    if (N) {
        return N;
    }
    return _synctex_node_sibling_or_parents(node);
}
/**
 *  The node which argument is the sibling.
 *  - return: NULL if the argument has no parent or
 *      is the first child of its parent.
 *  - Input nodes have no arg siblings
 */
synctex_node_p synctex_node_arg_sibling(synctex_node_p node)
{
#if 1
    return _synctex_tree_arg_sibling(node);
#else
    synctex_node_p N = _synctex_tree_parent(node);
    if ((N = _synctex_tree_child(N))) {
        do {
            synctex_node_p NN = __synctex_tree_sibling(N);
            if (NN == node) {
                return N;
            }
            N = NN;
        } while (N);
    }
    return N;
#endif
}
#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark CLASS
#endif

/*  Public node accessor: the type  */
synctex_node_type_t synctex_node_type(synctex_node_p node)
{
    return node ? node->class->type : synctex_node_type_none;
}

/*  Public node accessor: the type  */
synctex_node_type_t synctex_node_target_type(synctex_node_p node)
{
    synctex_node_p target = _synctex_tree_target(node);
    if (target) {
        return (((target)->class))->type;
    } else if (node) {
        return (((node)->class))->type;
    }
    return synctex_node_type_none;
}

/*  Public node accessor: the human readable type  */
const char *synctex_node_isa(synctex_node_p node)
{
    static const char *isa[synctex_node_number_of_types] = {"Not a node", "input", "sheet", "form",     "ref",      "vbox",  "void vbox",  "hbox",       "void hbox",  "kern",
                                                            "glue",       "rule",  "math",  "boundary", "box_bdry", "proxy", "last proxy", "vbox proxy", "hbox proxy", "handle"};
    return isa[synctex_node_type(node)];
}

#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark LOG
#endif

/*  Public node logger  */
void synctex_node_log(synctex_node_p node)
{
    SYNCTEX_MSG_SEND(node, log);
}

static void _synctex_log_input(synctex_node_p node)
{
    if (node) {
        printf("%s:%i,%s(%i)\n", synctex_node_isa(node), _synctex_data_tag(node), _synctex_data_name(node), _synctex_data_line(node));
        printf("SELF:%p\n", (void *)node);
        printf("    SIBLING:%p\n", (void *)__synctex_tree_sibling(node));
    }
}

static void _synctex_log_sheet(synctex_node_p node)
{
    if (node) {
        printf("%s:%i", synctex_node_isa(node), _synctex_data_page(node));
        SYNCTEX_PRINT_CHARINDEX_NL;
        printf("SELF:%p\n", (void *)node);
        printf("    SIBLING:%p\n", (void *)__synctex_tree_sibling(node));
        printf("    PARENT:%p\n", (void *)_synctex_tree_parent(node));
        printf("    CHILD:%p\n", (void *)_synctex_tree_child(node));
        printf("    LEFT:%p\n", (void *)_synctex_tree_friend(node));
        printf("    NEXT_hbox:%p\n", (void *)_synctex_tree_next_hbox(node));
    }
}

static void _synctex_log_form(synctex_node_p node)
{
    if (node) {
        printf("%s:%i", synctex_node_isa(node), _synctex_data_tag(node));
        SYNCTEX_PRINT_CHARINDEX_NL;
        printf("SELF:%p\n", (void *)node);
        printf("    SIBLING:%p\n", (void *)__synctex_tree_sibling(node));
        printf("    PARENT:%p\n", (void *)_synctex_tree_parent(node));
        printf("    CHILD:%p\n", (void *)_synctex_tree_child(node));
        printf("    LEFT:%p\n", (void *)_synctex_tree_friend(node));
    }
}

static void _synctex_log_ref(synctex_node_p node)
{
    if (node) {
        printf("%s:%i:%i,%i", synctex_node_isa(node), _synctex_data_tag(node), _synctex_data_h(node), _synctex_data_v(node));
        SYNCTEX_PRINT_CHARINDEX_NL;
        printf("SELF:%p\n", (void *)node);
        printf("    SIBLING:%p\n", (void *)__synctex_tree_sibling(node));
        printf("    PARENT:%p\n", (void *)_synctex_tree_parent(node));
    }
}

static void _synctex_log_tlchv_node(synctex_node_p node)
{
    if (node) {
        printf("%s:%i,%i:%i,%i", synctex_node_isa(node), _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node));
        SYNCTEX_PRINT_CHARINDEX_NL;
        printf("SELF:%p\n", (void *)node);
        printf("    SIBLING:%p\n", (void *)__synctex_tree_sibling(node));
        printf("    PARENT:%p\n", (void *)_synctex_tree_parent(node));
        printf("    CHILD:%p\n", (void *)_synctex_tree_child(node));
        printf("    LEFT:%p\n", (void *)_synctex_tree_friend(node));
    }
}

static void _synctex_log_kern_node(synctex_node_p node)
{
    if (node) {
        printf("%s:%i,%i:%i,%i:%i", synctex_node_isa(node), _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node), _synctex_data_width(node));
        SYNCTEX_PRINT_CHARINDEX_NL;
        printf("SELF:%p\n", (void *)node);
        printf("    SIBLING:%p\n", (void *)__synctex_tree_sibling(node));
        printf("    PARENT:%p\n", (void *)_synctex_tree_parent(node));
        printf("    CHILD:%p\n", (void *)_synctex_tree_child(node));
        printf("    LEFT:%p\n", (void *)_synctex_tree_friend(node));
    }
}

static void _synctex_log_rule(synctex_node_p node)
{
    if (node) {
        printf("%s:%i,%i:%i,%i", synctex_node_isa(node), _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node));
        printf(":%i", _synctex_data_width(node));
        printf(",%i", _synctex_data_height(node));
        printf(",%i", _synctex_data_depth(node));
        SYNCTEX_PRINT_CHARINDEX_NL;
        printf("SELF:%p\n", (void *)node);
        printf("    SIBLING:%p\n", (void *)__synctex_tree_sibling(node));
        printf("    PARENT:%p\n", (void *)_synctex_tree_parent(node));
        printf("    LEFT:%p\n", (void *)_synctex_tree_friend(node));
    }
}

static void _synctex_log_void_box(synctex_node_p node)
{
    if (node) {
        printf("%s", synctex_node_isa(node));
        printf(":%i", _synctex_data_tag(node));
        printf(",%i", _synctex_data_line(node));
        printf(",%i", 0);
        printf(":%i", _synctex_data_h(node));
        printf(",%i", _synctex_data_v(node));
        printf(":%i", _synctex_data_width(node));
        printf(",%i", _synctex_data_height(node));
        printf(",%i", _synctex_data_depth(node));
        SYNCTEX_PRINT_CHARINDEX_NL;
        printf("SELF:%p\n", (void *)node);
        printf("    SIBLING:%p\n", (void *)__synctex_tree_sibling(node));
        printf("    PARENT:%p\n", (void *)_synctex_tree_parent(node));
        printf("    CHILD:%p\n", (void *)_synctex_tree_child(node));
        printf("    LEFT:%p\n", (void *)_synctex_tree_friend(node));
    }
}

static void _synctex_log_vbox(synctex_node_p node)
{
    if (node) {
        printf("%s", synctex_node_isa(node));
        printf(":%i", _synctex_data_tag(node));
        printf(",%i", _synctex_data_line(node));
        printf(",%i", 0);
        printf(":%i", _synctex_data_h(node));
        printf(",%i", _synctex_data_v(node));
        printf(":%i", _synctex_data_width(node));
        printf(",%i", _synctex_data_height(node));
        printf(",%i", _synctex_data_depth(node));
        SYNCTEX_PRINT_CHARINDEX_NL;
        printf("SELF:%p\n", (void *)node);
        printf("    SIBLING:%p\n", (void *)__synctex_tree_sibling(node));
        printf("    PARENT:%p\n", (void *)_synctex_tree_parent(node));
        printf("    CHILD:%p\n", (void *)_synctex_tree_child(node));
        printf("    LEFT:%p\n", (void *)_synctex_tree_friend(node));
        printf("    NEXT_hbox:%p\n", (void *)_synctex_tree_next_hbox(node));
    }
}

static void _synctex_log_hbox(synctex_node_p node)
{
    if (node) {
        printf("%s", synctex_node_isa(node));
        printf(":%i", _synctex_data_tag(node));
        printf(",%i~%i*%i", _synctex_data_line(node), _synctex_data_mean_line(node), _synctex_data_weight(node));
        printf(",%i", 0);
        printf(":%i", _synctex_data_h(node));
        printf(",%i", _synctex_data_v(node));
        printf(":%i", _synctex_data_width(node));
        printf(",%i", _synctex_data_height(node));
        printf(",%i", _synctex_data_depth(node));
        printf("/%i", _synctex_data_h_V(node));
        printf(",%i", _synctex_data_v_V(node));
        printf(":%i", _synctex_data_width_V(node));
        printf(",%i", _synctex_data_height_V(node));
        printf(",%i", _synctex_data_depth_V(node));
        SYNCTEX_PRINT_CHARINDEX_NL;
        printf("SELF:%p\n", (void *)node);
        printf("    SIBLING:%p\n", (void *)__synctex_tree_sibling(node));
        printf("    PARENT:%p\n", (void *)_synctex_tree_parent(node));
        printf("    CHILD:%p\n", (void *)_synctex_tree_child(node));
        printf("    LEFT:%p\n", (void *)_synctex_tree_friend(node));
        printf("    NEXT_hbox:%p\n", (void *)_synctex_tree_next_hbox(node));
    }
}
static void _synctex_log_proxy(synctex_node_p node)
{
    if (node) {
        synctex_node_p N = _synctex_tree_target(node);
        printf("%s", synctex_node_isa(node));
        printf(":%i", _synctex_data_h(node));
        printf(",%i", _synctex_data_v(node));
        SYNCTEX_PRINT_CHARINDEX_NL;
        printf("SELF:%p\n", (void *)node);
        printf("    SIBLING:%p\n", (void *)__synctex_tree_sibling(node));
        printf("    LEFT:%p\n", (void *)_synctex_tree_friend(node));
        printf("    ->%s\n", _synctex_node_abstract(N));
    }
}
static void _synctex_log_handle(synctex_node_p node)
{
    if (node) {
        synctex_node_p N = _synctex_tree_target(node);
        printf("%s", synctex_node_isa(node));
        SYNCTEX_PRINT_CHARINDEX_NL;
        printf("SELF:%p\n", (void *)node);
        printf("    SIBLING:%p\n", (void *)__synctex_tree_sibling(node));
        printf("    ->%s\n", _synctex_node_abstract(N));
    }
}

#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark SYNCTEX_DISPLAY
#endif

int synctex_scanner_display_switcher(synctex_scanner_p scanR)
{
    return scanR->display_switcher;
}
void synctex_scanner_set_display_switcher(synctex_scanner_p scanR, int switcher)
{
    scanR->display_switcher = switcher;
}
static const char *const _synctex_display_prompt = "................................";

static char *_synctex_scanner_display_prompt_down(synctex_scanner_p scanR)
{
    if (scanR->display_prompt > _synctex_display_prompt) {
        --scanR->display_prompt;
    }
    return scanR->display_prompt;
}
static char *_synctex_scanner_display_prompt_up(synctex_scanner_p scanR)
{
    if (scanR->display_prompt + 1 < _synctex_display_prompt + strlen(_synctex_display_prompt)) {
        ++scanR->display_prompt;
    }
    return scanR->display_prompt;
}

void synctex_node_display(synctex_node_p node)
{
    if (node) {
        synctex_scanner_p scanR = node->class->scanner;
        if (scanR) {
            if (scanR->display_switcher < 0) {
                SYNCTEX_MSG_SEND(node, display);
            } else if (scanR->display_switcher > 0 && --scanR->display_switcher > 0) {
                SYNCTEX_MSG_SEND(node, display);
            } else if (scanR->display_switcher-- >= 0) {
                printf("%s Next display skipped. Reset display switcher.\n", node->class->scanner->display_prompt);
            }
        } else {
            SYNCTEX_MSG_SEND(node, display);
        }
    }
}
static const char *_synctex_node_abstract(synctex_node_p node)
{
    SYNCTEX_PARAMETER_ASSERT(node || node->class);
    return (node && node->class->abstract) ? node->class->abstract(node) : "none";
}

SYNCTEX_INLINE static void _synctex_display_child(synctex_node_p node)
{
    synctex_node_p N = _synctex_tree_child(node);
    if (N) {
        _synctex_scanner_display_prompt_down(N->class->scanner);
        synctex_node_display(N);
        _synctex_scanner_display_prompt_up(N->class->scanner);
    }
}

SYNCTEX_INLINE static void _synctex_display_sibling(synctex_node_p node)
{
    synctex_node_display(__synctex_tree_sibling(node));
}
#define SYNCTEX_ABSTRACT_MAX 128
static char *_synctex_abstract_input(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "Input:%i:%s(%i)" SYNCTEX_PRINT_CHARINDEX_FMT, _synctex_data_tag(node), _synctex_data_name(node), _synctex_data_line(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
    }
    return abstract;
}

static void _synctex_display_input(synctex_node_p node)
{
    if (node) {
        printf("Input:%i:%s(%i)" SYNCTEX_PRINT_CHARINDEX_FMT "\n", _synctex_data_tag(node), _synctex_data_name(node), _synctex_data_line(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
        synctex_node_display(__synctex_tree_sibling(node));
    }
}

static char *_synctex_abstract_sheet(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "{%i...}" SYNCTEX_PRINT_CHARINDEX_FMT, _synctex_data_page(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
    }
    return abstract;
}

static void _synctex_display_sheet(synctex_node_p node)
{
    if (node) {
        printf("%s{%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", node->class->scanner->display_prompt, _synctex_data_page(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
        _synctex_display_child(node);
        printf("%s}\n", node->class->scanner->display_prompt);
        _synctex_display_sibling(node);
    }
}

static char *_synctex_abstract_form(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "<%i...>" SYNCTEX_PRINT_CHARINDEX_FMT, _synctex_data_tag(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
        SYNCTEX_PRINT_CHARINDEX;
    }
    return abstract;
}

static void _synctex_display_form(synctex_node_p node)
{
    if (node) {
        printf("%s<%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", node->class->scanner->display_prompt, _synctex_data_tag(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
        _synctex_display_child(node);
        printf("%s>\n", node->class->scanner->display_prompt);
        _synctex_display_sibling(node);
    }
}

static char *_synctex_abstract_vbox(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        snprintf(abstract,
                 SYNCTEX_ABSTRACT_MAX,
                 "[%i,%i:%i,%i:%i,%i,%i...]" SYNCTEX_PRINT_CHARINDEX_FMT,
                 _synctex_data_tag(node),
                 _synctex_data_line(node),
                 _synctex_data_h(node),
                 _synctex_data_v(node),
                 _synctex_data_width(node),
                 _synctex_data_height(node),
                 _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
    }
    return abstract;
}

static void _synctex_display_vbox(synctex_node_p node)
{
    if (node) {
        printf("%s[%i,%i:%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n",
               node->class->scanner->display_prompt,
               _synctex_data_tag(node),
               _synctex_data_line(node),
               _synctex_data_h(node),
               _synctex_data_v(node),
               _synctex_data_width(node),
               _synctex_data_height(node),
               _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
        _synctex_display_child(node);
        printf("%s]\n%slast:%s\n", node->class->scanner->display_prompt, node->class->scanner->display_prompt, _synctex_node_abstract(_synctex_tree_last(node)));
        _synctex_display_sibling(node);
    }
}

static char *_synctex_abstract_hbox(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        snprintf(abstract,
                 SYNCTEX_ABSTRACT_MAX,
                 "(%i,%i~%i*%i:%i,%i:%i,%i,%i...)" SYNCTEX_PRINT_CHARINDEX_FMT,
                 _synctex_data_tag(node),
                 _synctex_data_line(node),
                 _synctex_data_mean_line(node),
                 _synctex_data_weight(node),
                 _synctex_data_h(node),
                 _synctex_data_v(node),
                 _synctex_data_width(node),
                 _synctex_data_height(node),
                 _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
    }
    return abstract;
}

static void _synctex_display_hbox(synctex_node_p node)
{
    if (node) {
        printf("%s(%i,%i~%i*%i:%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n",
               node->class->scanner->display_prompt,
               _synctex_data_tag(node),
               _synctex_data_line(node),
               _synctex_data_mean_line(node),
               _synctex_data_weight(node),
               _synctex_data_h(node),
               _synctex_data_v(node),
               _synctex_data_width(node),
               _synctex_data_height(node),
               _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
        _synctex_display_child(node);
        printf("%s)\n%slast:%s\n", node->class->scanner->display_prompt, node->class->scanner->display_prompt, _synctex_node_abstract(_synctex_tree_last(node)));
        _synctex_display_sibling(node);
    }
}

static char *_synctex_abstract_void_vbox(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        snprintf(abstract,
                 SYNCTEX_ABSTRACT_MAX,
                 "v%i,%i;%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n",
                 _synctex_data_tag(node),
                 _synctex_data_line(node),
                 _synctex_data_h(node),
                 _synctex_data_v(node),
                 _synctex_data_width(node),
                 _synctex_data_height(node),
                 _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
    }
    return abstract;
}

static void _synctex_display_void_vbox(synctex_node_p node)
{
    if (node) {
        printf("%sv%i,%i;%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n",
               node->class->scanner->display_prompt,
               _synctex_data_tag(node),
               _synctex_data_line(node),
               _synctex_data_h(node),
               _synctex_data_v(node),
               _synctex_data_width(node),
               _synctex_data_height(node),
               _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
        _synctex_display_sibling(node);
    }
}

static char *_synctex_abstract_void_hbox(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        snprintf(abstract,
                 SYNCTEX_ABSTRACT_MAX,
                 "h%i,%i:%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT,
                 _synctex_data_tag(node),
                 _synctex_data_line(node),
                 _synctex_data_h(node),
                 _synctex_data_v(node),
                 _synctex_data_width(node),
                 _synctex_data_height(node),
                 _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
    }
    return abstract;
}

static void _synctex_display_void_hbox(synctex_node_p node)
{
    if (node) {
        printf("%sh%i,%i:%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n",
               node->class->scanner->display_prompt,
               _synctex_data_tag(node),
               _synctex_data_line(node),
               _synctex_data_h(node),
               _synctex_data_v(node),
               _synctex_data_width(node),
               _synctex_data_height(node),
               _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
        _synctex_display_sibling(node);
    }
}

static char *_synctex_abstract_glue(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "glue:%i,%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT, _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
    }
    return abstract;
}

static void _synctex_display_glue(synctex_node_p node)
{
    if (node) {
        printf("%sglue:%i,%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", node->class->scanner->display_prompt, _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
        _synctex_display_sibling(node);
    }
}

static char *_synctex_abstract_rule(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        snprintf(abstract,
                 SYNCTEX_ABSTRACT_MAX,
                 "rule:%i,%i:%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT,
                 _synctex_data_tag(node),
                 _synctex_data_line(node),
                 _synctex_data_h(node),
                 _synctex_data_v(node),
                 _synctex_data_width(node),
                 _synctex_data_height(node),
                 _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
    }
    return abstract;
}

static void _synctex_display_rule(synctex_node_p node)
{
    if (node) {
        printf("%srule:%i,%i:%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n",
               node->class->scanner->display_prompt,
               _synctex_data_tag(node),
               _synctex_data_line(node),
               _synctex_data_h(node),
               _synctex_data_v(node),
               _synctex_data_width(node),
               _synctex_data_height(node),
               _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
        _synctex_display_sibling(node);
    }
}

static char *_synctex_abstract_math(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "math:%i,%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT, _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
    }
    return abstract;
}

static void _synctex_display_math(synctex_node_p node)
{
    if (node) {
        printf("%smath:%i,%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", node->class->scanner->display_prompt, _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
        _synctex_display_sibling(node);
    }
}

static char *_synctex_abstract_kern(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        snprintf(abstract,
                 SYNCTEX_ABSTRACT_MAX,
                 "kern:%i,%i:%i,%i:%i" SYNCTEX_PRINT_CHARINDEX_FMT,
                 _synctex_data_tag(node),
                 _synctex_data_line(node),
                 _synctex_data_h(node),
                 _synctex_data_v(node),
                 _synctex_data_width(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
    }
    return abstract;
}

static void _synctex_display_kern(synctex_node_p node)
{
    if (node) {
        printf("%skern:%i,%i:%i,%i:%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n",
               node->class->scanner->display_prompt,
               _synctex_data_tag(node),
               _synctex_data_line(node),
               _synctex_data_h(node),
               _synctex_data_v(node),
               _synctex_data_width(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
        _synctex_display_sibling(node);
    }
}

static char *_synctex_abstract_boundary(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "boundary:%i,%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT, _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
    }
    return abstract;
}

static void _synctex_display_boundary(synctex_node_p node)
{
    if (node) {
        printf("%sboundary:%i,%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", node->class->scanner->display_prompt, _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
        _synctex_display_sibling(node);
    }
}

static char *_synctex_abstract_box_bdry(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "box bdry:%i,%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT, _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
    }
    return abstract;
}

static void _synctex_display_box_bdry(synctex_node_p node)
{
    if (node) {
        printf("%sbox bdry:%i,%i:%i,%i", node->class->scanner->display_prompt, _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node));
        SYNCTEX_PRINT_CHARINDEX_NL;
        _synctex_display_sibling(node);
    }
}

static char *_synctex_abstract_ref(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "form ref:%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT, _synctex_data_tag(node), _synctex_data_h(node), _synctex_data_v(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
    }
    return abstract;
}

static void _synctex_display_ref(synctex_node_p node)
{
    if (node) {
        printf("%sform ref:%i:%i,%i", node->class->scanner->display_prompt, _synctex_data_tag(node), _synctex_data_h(node), _synctex_data_v(node));
        SYNCTEX_PRINT_CHARINDEX_NL;
        _synctex_display_sibling(node);
    }
}
static char *_synctex_abstract_proxy(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        synctex_node_p N = _synctex_tree_target(node);
        snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "%s:%i,%i:%i,%i/%p%s", synctex_node_isa(node), synctex_node_tag(node), synctex_node_line(node), _synctex_data_h(node), _synctex_data_v(node), node, _synctex_node_abstract(N));
    }
    return abstract;
}
static void _synctex_display_proxy(synctex_node_p node)
{
    if (node) {
        synctex_node_p N = _synctex_tree_target(node);
        printf("%s%s:%i,%i:%i,%i", node->class->scanner->display_prompt, synctex_node_isa(node), synctex_node_tag(node), synctex_node_line(node), _synctex_data_h(node), _synctex_data_v(node));
        if (N) {
            printf("=%i,%i:%i,%i,%i->%s", synctex_node_h(node), synctex_node_v(node), synctex_node_width(node), synctex_node_height(node), synctex_node_depth(node), _synctex_node_abstract(N));
        }
        printf("\n");
        _synctex_display_child(node);
        _synctex_display_sibling(node);
    }
}
static char *_synctex_abstract_proxy_vbox(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        snprintf(abstract,
                 SYNCTEX_ABSTRACT_MAX,
                 "[*%i,%i:%i,%i:%i,%i,%i...*]" SYNCTEX_PRINT_CHARINDEX_FMT,
                 synctex_node_tag(node),
                 synctex_node_line(node),
                 synctex_node_h(node),
                 synctex_node_v(node),
                 synctex_node_width(node),
                 synctex_node_height(node),
                 synctex_node_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
    }
    return abstract;
}

static void _synctex_display_proxy_vbox(synctex_node_p node)
{
    if (node) {
        printf("%s[*%i,%i:%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n",
               node->class->scanner->display_prompt,
               synctex_node_tag(node),
               synctex_node_line(node),
               synctex_node_h(node),
               synctex_node_v(node),
               synctex_node_width(node),
               synctex_node_height(node),
               synctex_node_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
        _synctex_display_child(node);
        printf("%s*]\n%slast:%s\n", node->class->scanner->display_prompt, node->class->scanner->display_prompt, _synctex_node_abstract(_synctex_tree_last(node)));
        _synctex_display_sibling(node);
    }
}

static char *_synctex_abstract_proxy_hbox(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        snprintf(abstract,
                 SYNCTEX_ABSTRACT_MAX,
                 "(*%i,%i~%i*%i:%i,%i:%i,%i,%i...*)/%p" SYNCTEX_PRINT_CHARINDEX_FMT,
                 synctex_node_tag(node),
                 synctex_node_line(node),
                 synctex_node_mean_line(node),
                 synctex_node_weight(node),
                 synctex_node_h(node),
                 synctex_node_v(node),
                 synctex_node_width(node),
                 synctex_node_height(node),
                 synctex_node_depth(node),
                 node SYNCTEX_PRINT_CHARINDEX_WHAT);
    }
    return abstract;
}

static void _synctex_display_proxy_hbox(synctex_node_p node)
{
    if (node) {
        printf("%s(*%i,%i~%i*%i:%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n",
               node->class->scanner->display_prompt,
               synctex_node_tag(node),
               synctex_node_line(node),
               synctex_node_mean_line(node),
               synctex_node_weight(node),
               synctex_node_h(node),
               synctex_node_v(node),
               synctex_node_width(node),
               synctex_node_height(node),
               synctex_node_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT);
        _synctex_display_child(node);
        printf("%s*)\n%slast:%s\n", node->class->scanner->display_prompt, node->class->scanner->display_prompt, _synctex_node_abstract(_synctex_tree_last(node)));
        _synctex_display_sibling(node);
    }
}

static char *_synctex_abstract_handle(synctex_node_p node)
{
    static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
    if (node) {
        synctex_node_p N = _synctex_tree_target(node);
        if (N && !N->class) {
            exit(1);
        }
        snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "%s:%s", synctex_node_isa(node), (N ? _synctex_node_abstract(N) : ""));
    }
    return abstract;
}
static void _synctex_display_handle(synctex_node_p node)
{
    if (node) {
        synctex_node_p N = _synctex_tree_target(node);
        printf("%s%s:->%s\n", node->class->scanner->display_prompt, synctex_node_isa(node), _synctex_node_abstract(N));
        _synctex_display_child(node);
        _synctex_display_sibling(node);
    }
}
#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark STATUS
#endif

#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark Prototypes
#endif
typedef struct {
    size_t size;
    synctex_status_t status;
} synctex_zs_s;
static synctex_zs_s _synctex_buffer_get_available_size(synctex_scanner_p scanner, size_t size);
static synctex_status_t _synctex_next_line(synctex_scanner_p scanner);
static synctex_status_t _synctex_match_string(synctex_scanner_p scanner, const char *the_string);

typedef struct synctex_ns_t {
    synctex_node_p node;
    synctex_status_t status;
} synctex_ns_s;
static synctex_ns_s __synctex_parse_new_input(synctex_scanner_p scanner);
static synctex_status_t _synctex_scan_preamble(synctex_scanner_p scanner);
typedef struct {
    float value;
    synctex_status_t status;
} synctex_fs_s;
static synctex_fs_s _synctex_scan_float_and_dimension(synctex_scanner_p scanner);
static synctex_status_t _synctex_scan_post_scriptum(synctex_scanner_p scanner);
static synctex_status_t _synctex_scan_postamble(synctex_scanner_p scanner);
static synctex_status_t _synctex_setup_visible_hbox(synctex_node_p box);
static synctex_status_t _synctex_scan_content(synctex_scanner_p scanner);
int synctex_scanner_pre_x_offset(synctex_scanner_p scanner);
int synctex_scanner_pre_y_offset(synctex_scanner_p scanner);
const char *synctex_scanner_get_output_fmt(synctex_scanner_p scanner);

#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark SCANNER UTILITIES
#endif

#define SYNCTEX_FILE (scanner->reader->file)

/**
 *  Try to ensure that the buffer contains at least size bytes.
 *  Passing a huge size argument means the whole buffer length.
 *  Passing a 0 size argument means return the available buffer length, without reading the file.
 *  In that case, the return status is always SYNCTEX_STATUS_OK unless the given scanner is NULL.
 *  The size_t value returned is the number of bytes now available in the buffer. This is a nonnegative integer, it may take the value 0.
 *  It is the responsibility of the caller to test whether this size is conforming to its needs.
 *  Negative values may return in case of error, actually
 *  when there was an error reading the synctex file.
 *  - parameter scanner: The owning scanner. When NULL, returns SYNCTEX_STATUS_BAD_ARGUMENT.
 *  - parameter expected: expected number of bytes.
 *  - returns: a size and a status.
 */
static synctex_zs_s _synctex_buffer_get_available_size(synctex_scanner_p scanner, size_t expected)
{
    size_t size = 0;
    if (NULL == scanner) {
        return (synctex_zs_s) {0, SYNCTEX_STATUS_BAD_ARGUMENT};
    }
    if (expected > scanner->reader->size) {
        expected = scanner->reader->size;
    }
    size = SYNCTEX_END - SYNCTEX_CUR; /*  available is the number of unparsed chars in the buffer */
    if (expected <= size) {
        /*  There are already sufficiently many characters in the buffer */
        return (synctex_zs_s) {size, SYNCTEX_STATUS_OK};
    }
    if (SYNCTEX_FILE) {
        /*  Copy the remaining part of the buffer to the beginning,
         *  then read the next part of the file */
        int already_read = 0;
#if defined(SYNCTEX_USE_CHARINDEX)
        scanner->reader->charindex_offset += SYNCTEX_CUR - SYNCTEX_START;
#endif
        if (size) {
            memmove(SYNCTEX_START, SYNCTEX_CUR, size);
        }
        SYNCTEX_CUR = SYNCTEX_START + size; /*  the next character after the move, will change. */
        /*  Fill the buffer up to its end */
        already_read = gzread(SYNCTEX_FILE, (void *)SYNCTEX_CUR, (int)(SYNCTEX_BUFFER_SIZE - size));
        if (already_read > 0) {
            /*  We assume that 0<already_read<=SYNCTEX_BUFFER_SIZE - size, such that
             *  SYNCTEX_CUR + already_read = SYNCTEX_START + size  + already_read <= SYNCTEX_START + SYNCTEX_BUFFER_SIZE */
            SYNCTEX_END = SYNCTEX_CUR + already_read;
            /*  If the end of the file was reached, all the required SYNCTEX_BUFFER_SIZE - available
             *  may not be filled with values from the file.
             *  In that case, the buffer should stop properly after already_read characters. */
            *SYNCTEX_END = '\0'; /* there is enough room */
            SYNCTEX_CUR = SYNCTEX_START;
            /*  May be available is less than size, the caller will have to test. */
            return (synctex_zs_s) {SYNCTEX_END - SYNCTEX_CUR, SYNCTEX_STATUS_OK};
        } else if (0 > already_read) {
            /*  There is a possible error in reading the file */
            int errnum = 0;
            const char *error_string = gzerror(SYNCTEX_FILE, &errnum);
            if (Z_ERRNO == errnum) {
                /*  There is an error in zlib caused by the file system */
                _synctex_error("gzread error from the file system (%i)", errno);
                return (synctex_zs_s) {0, SYNCTEX_STATUS_ERROR};
            } else if (errnum) {
                _synctex_error("gzread error (%i:%i,%s)", already_read, errnum, error_string);
                return (synctex_zs_s) {0, SYNCTEX_STATUS_ERROR};
            }
        }
        /*  Nothing was read, we are at the end of the file. */
        gzclose(SYNCTEX_FILE);
        SYNCTEX_FILE = NULL;
        SYNCTEX_END = SYNCTEX_CUR;
        SYNCTEX_CUR = SYNCTEX_START;
        *SYNCTEX_END = '\0'; /*  Terminate the string properly.*/
        /*  there might be a bit of text left */
        return (synctex_zs_s) {SYNCTEX_END - SYNCTEX_CUR, SYNCTEX_STATUS_EOF};
    }
    /*  We cannot enlarge the buffer because the end of the file was reached. */
    return (synctex_zs_s) {size, SYNCTEX_STATUS_EOF};
}

/*  Used when parsing the synctex file.
 *  Advance to the next character starting a line.
 *  Actually, only '\n' is recognized as end of line marker.
 *  On normal completion, the returned value is the number of unparsed characters available in the buffer.
 *  In general, it is a positive value, 0 meaning that the end of file was reached.
 *  -1 is returned in case of error, actually because there was an error while feeding the buffer.
 *  When the function returns with no error, SYNCTEX_CUR points to the first character of the next line, if any.
 *  J. Laurens: Sat May 10 07:52:31 UTC 2008
 */
static synctex_status_t _synctex_next_line(synctex_scanner_p scanner)
{
    synctex_status_t status = SYNCTEX_STATUS_OK;
    if (NULL == scanner) {
        return SYNCTEX_STATUS_BAD_ARGUMENT;
    }
infinite_loop:
    while (SYNCTEX_CUR < SYNCTEX_END) {
        if (*SYNCTEX_CUR == '\n') {
            ++SYNCTEX_CUR;
            ++scanner->reader->line_number;
            return _synctex_buffer_get_available_size(scanner, 1).status;
        }
        ++SYNCTEX_CUR;
    }
    /*  Here, we have SYNCTEX_CUR == SYNCTEX_END, such that the next call to _synctex_buffer_get_available_size
     *  will read another bunch of synctex file. Little by little, we advance to the end of the file. */
    status = _synctex_buffer_get_available_size(scanner, 1).status;
    if (status <= SYNCTEX_STATUS_EOF) {
        return status;
    }
    goto infinite_loop;
}

/*  Scan the given string.
 *  Both scanner and the_string must not be NULL, and the_string must not be 0 length.
 *  SYNCTEX_STATUS_OK is returned if the string is found,
 *  SYNCTEX_STATUS_EOF is returned when the EOF is reached,
 *  SYNCTEX_STATUS_NOT_OK is returned is the string is not found,
 *  an error status is returned otherwise.
 *  This is a critical method because buffering renders things more difficult.
 *  The given string might be as long as the maximum size_t value.
 *  As side effect, the buffer state may have changed if the given argument string can't fit into the buffer.
 */
static synctex_status_t _synctex_match_string(synctex_scanner_p scanner, const char *the_string)
{
    size_t tested_len = 0;    /*  the number of characters at the beginning of the_string that match */
    size_t remaining_len = 0; /*  the number of remaining characters of the_string that should match */
    size_t available = 0;
    synctex_zs_s zs = {0, 0};
    if (NULL == scanner || NULL == the_string) {
        return SYNCTEX_STATUS_BAD_ARGUMENT;
    }
    remaining_len = strlen(the_string); /*  All the_string should match */
    if (0 == remaining_len) {
        return SYNCTEX_STATUS_BAD_ARGUMENT;
    }
    /*  How many characters available in the buffer? */
    zs = _synctex_buffer_get_available_size(scanner, remaining_len);
    if (zs.status < SYNCTEX_STATUS_EOF) {
        return zs.status;
    }
    /*  Maybe we have less characters than expected because the buffer is too small. */
    if (zs.size >= remaining_len) {
        /*  The buffer is sufficiently big to hold the expected number of characters. */
        if (strncmp((char *)SYNCTEX_CUR, the_string, remaining_len)) {
            return SYNCTEX_STATUS_NOT_OK;
        }
    return_OK:
        /*  Advance SYNCTEX_CUR to the next character after the_string. */
        SYNCTEX_CUR += remaining_len;
        return SYNCTEX_STATUS_OK;
    } else if (strncmp((char *)SYNCTEX_CUR, the_string, zs.size)) {
        /*  No need to go further, this is not the expected string in the buffer. */
        return SYNCTEX_STATUS_NOT_OK;
    } else if (SYNCTEX_FILE) {
        /*  The buffer was too small to contain remaining_len characters.
         *  We have to cut the string into pieces. */
        z_off_t offset = 0L;
        /*  the first part of the string is found, advance the_string to the next untested character. */
        the_string += zs.size;
        /*  update the remaining length and the parsed length. */
        remaining_len -= zs.size;
        tested_len += zs.size;
        SYNCTEX_CUR += zs.size; /*  We validate the tested characters. */
        if (0 == remaining_len) {
            /*  Nothing left to test, we have found the given string. */
            return SYNCTEX_STATUS_OK;
        }
        /*  We also have to record the current state of the file cursor because
         *  if the_string does not match, all this should be a totally blank operation,
         *  for which the file and buffer states should not be modified at all.
         *  In fact, the states of the buffer before and after this function are in general different
         *  but they are totally equivalent as long as the values of the buffer before SYNCTEX_CUR
         *  can be safely discarded.  */
        offset = gztell(SYNCTEX_FILE);
        /*  offset now corresponds to the first character of the file that was not buffered. */
        /*  SYNCTEX_CUR - SYNCTEX_START is the number of chars that where already buffered and
         *  that match the head of the_string. If in fine the_string does not match, all these chars must be recovered
         *  because the whole buffer contents is replaced in _synctex_buffer_get_available_size.
         *  They were buffered from offset-len location in the file. */
        offset -= SYNCTEX_CUR - SYNCTEX_START;
    more_characters:
        /*  There is still some work to be done, so read another bunch of file.
         *  This is the second call to _synctex_buffer_get_available_size,
         *  which means that the actual contents of the buffer will be discarded.
         *  We will definitely have to recover the previous state in case we do not find the expected string. */
        zs = _synctex_buffer_get_available_size(scanner, remaining_len);
        if (zs.status < SYNCTEX_STATUS_EOF) {
            return zs.status; /*  This is an error, no need to go further. */
        }
        if (zs.size == 0) {
            /*  Missing characters: recover the initial state of the file and return. */
        return_NOT_OK:
            if (offset != gzseek(SYNCTEX_FILE, offset, SEEK_SET)) {
                /*  This is a critical error, we could not recover the previous state. */
                _synctex_error("Can't seek file");
                return SYNCTEX_STATUS_ERROR;
            }
            /*  Next time we are asked to fill the buffer,
             *  we will read a complete bunch of text from the file. */
            SYNCTEX_CUR = SYNCTEX_END;
            return SYNCTEX_STATUS_NOT_OK;
        }
        if (zs.size < remaining_len) {
            /*  We'll have to loop one more time. */
            if (strncmp((char *)SYNCTEX_CUR, the_string, zs.size)) {
                /*  This is not the expected string, recover the previous state and return. */
                goto return_NOT_OK;
            }
            /*  Advance the_string to the first untested character. */
            the_string += available;
            /*  update the remaining length and the parsed length. */
            remaining_len -= zs.size;
            tested_len += zs.size;
            SYNCTEX_CUR += zs.size; /*  We validate the tested characters. */
            goto more_characters;
        }
        /*  This is the last step. */
        if (strncmp((char *)SYNCTEX_CUR, the_string, remaining_len)) {
            /*  This is not the expected string, recover the previous state and return. */
            goto return_NOT_OK;
        }
        goto return_OK;
    } else {
        /*  The buffer can't contain the given string argument, and the EOF was reached */
        return SYNCTEX_STATUS_EOF;
    }
}

/*  Used when parsing the synctex file.
 *  Decode an integer.
 *  First, field separators, namely ':' and ',' characters are skipped
 *  The returned value is negative if there is an unrecoverable error.
 *  It is SYNCTEX_STATUS_NOT_OK if an integer could not be parsed, for example
 *  if the characters at the current cursor position are not digits or
 *  if the end of the file has been reached.
 *  It is SYNCTEX_STATUS_OK if an int has been successfully parsed.
 *  The given scanner argument must not be NULL, on the contrary, value_ref may be NULL.
 */
static synctex_is_s _synctex_decode_int(synctex_scanner_p scanner)
{
    char *ptr = NULL;
    char *end = NULL;
    synctex_zs_s zs = {0, 0};
    int result;
    if (NULL == scanner) {
        return (synctex_is_s) {0, SYNCTEX_STATUS_BAD_ARGUMENT};
    }
    zs = _synctex_buffer_get_available_size(scanner, SYNCTEX_BUFFER_MIN_SIZE);
    if (zs.status < SYNCTEX_STATUS_EOF) {
        return (synctex_is_s) {0, zs.status};
    }
    if (zs.size == 0) {
        return (synctex_is_s) {0, SYNCTEX_STATUS_NOT_OK};
    }
    ptr = SYNCTEX_CUR;
    /*  Optionally parse the separator */
    if (*ptr == ':' || *ptr == ',') {
        ++ptr;
        --zs.size;
        if (zs.size == 0) {
            return (synctex_is_s) {0, SYNCTEX_STATUS_NOT_OK};
        }
    }
    result = (int)strtol(ptr, &end, 10);
    if (end > ptr) {
        SYNCTEX_CUR = end;
        return (synctex_is_s) {result, SYNCTEX_STATUS_OK};
    }
    return (synctex_is_s) {result, SYNCTEX_STATUS_NOT_OK};
}
static synctex_is_s _synctex_decode_int_opt(synctex_scanner_p scanner, int default_value)
{
    char *ptr = NULL;
    char *end = NULL;
    synctex_zs_s zs = {0, 0};
    if (NULL == scanner) {
        return (synctex_is_s) {default_value, SYNCTEX_STATUS_BAD_ARGUMENT};
    }
    zs = _synctex_buffer_get_available_size(scanner, SYNCTEX_BUFFER_MIN_SIZE);
    if (zs.status < SYNCTEX_STATUS_EOF) {
        return (synctex_is_s) {default_value, zs.status};
    }
    if (zs.size == 0) {
        return (synctex_is_s) {default_value, SYNCTEX_STATUS_OK};
    }
    ptr = SYNCTEX_CUR;
    /*  Comma separator required */
    if (*ptr == ',') {
        int result;
        ++ptr;
        --zs.size;
        if (zs.size == 0) {
            return (synctex_is_s) {default_value, SYNCTEX_STATUS_NOT_OK};
        }
        result = (int)strtol(ptr, &end, 10);
        if (end > ptr) {
            SYNCTEX_CUR = end;
            return (synctex_is_s) {result, SYNCTEX_STATUS_OK};
        }
        return (synctex_is_s) {default_value, SYNCTEX_STATUS_NOT_OK};
    }
    return (synctex_is_s) {default_value, SYNCTEX_STATUS_OK};
}
/*  Used when parsing the synctex file.
 *  Decode an integer for a v field.
 *  Try the _synctex_decode_int version and set the last v field scanned.
 *  If it does not succeed, tries to match an '=' sign,
 *  which is a shortcut for the last v field scanned.
 */
#define SYNCTEX_INPUT_COMEQUALS ",="
static synctex_is_s _synctex_decode_int_v(synctex_scanner_p scanner)
{
    synctex_is_s is = _synctex_decode_int(scanner);
    if (SYNCTEX_STATUS_OK == is.status) {
        scanner->reader->lastv = is.integer;
        return is;
    }
    is.status = _synctex_match_string(scanner, SYNCTEX_INPUT_COMEQUALS);
    if (is.status < SYNCTEX_STATUS_OK) {
        return is;
    }
    is.integer = scanner->reader->lastv;
    return is;
}

/*  The purpose of this function is to read a string.
 *  A string is an array of characters from the current parser location
 *  and before the next '\n' character.
 *  If a string was properly decoded, it is returned in value_ref and
 *  the cursor points to the new line marker.
 *  The returned string was alloced on the heap, the caller is the owner and
 *  is responsible to free it in due time,
 *  unless it transfers the ownership to another object.
 *  If no string is parsed, * value_ref is undefined.
 *  The maximum length of a string that a scanner can decode is platform dependent, namely UINT_MAX.
 *  If you just want to blindly parse the file up to the end of the current line,
 *  use _synctex_next_line instead.
 *  On return, the scanner cursor is unchanged if a string could not be scanned or
 *  points to the terminating '\n' character otherwise. As a consequence,
 *  _synctex_next_line is necessary after.
 *  If either scanner or value_ref is NULL, it is considered as an error and
 *  SYNCTEX_STATUS_BAD_ARGUMENT is returned.
 */
static synctex_ss_s _synctex_decode_string(synctex_scanner_p scanner)
{
    char *end = NULL;
    size_t len = 0; /*  The number of bytes to copy */
    size_t already_len = 0;
    synctex_zs_s zs = {0, 0};
    char *string = NULL;
    char *new_string = NULL;
    if (NULL == scanner) {
        return (synctex_ss_s) {NULL, SYNCTEX_STATUS_BAD_ARGUMENT};
    }
    /*  The buffer must at least contain one character: the '\n' end of line marker */
    if (SYNCTEX_CUR >= SYNCTEX_END) {
    more_characters:
        zs = _synctex_buffer_get_available_size(scanner, 1);
        if (zs.status < SYNCTEX_STATUS_EOF) {
            free(string);
            return (synctex_ss_s) {NULL, zs.status};
        } else if (0 == zs.size) {
            free(string);
            return (synctex_ss_s) {NULL, SYNCTEX_STATUS_EOF};
        }
    }
    /*  Now we are sure that there is at least one available character, either because
     *  SYNCTEX_CUR was already < SYNCTEX_END, or because the buffer has been properly filled. */
    /*  end will point to the next unparsed '\n' character in the file, when mapped to the buffer. */
    end = SYNCTEX_CUR;
    /*  We scan all the characters up to the next '\n' */
    while (end < SYNCTEX_END && *end != '\n') {
        ++end;
    }
    /*  OK, we found where to stop:
     *      either end == SYNCTEX_END
     *      or *end == '\n' */
    len = end - SYNCTEX_CUR;
    if (len < UINT_MAX - already_len) {
        if ((new_string = realloc(string, len + already_len + 1)) != NULL) {
            string = new_string;
            new_string = NULL;
            if (memcpy(string + already_len, SYNCTEX_CUR, len)) {
                already_len += len;
                string[already_len] = '\0'; /*  Terminate the string */
                SYNCTEX_CUR += len;         /*  Eventually advance to the terminating '\n' */
                if (SYNCTEX_CUR == SYNCTEX_END) {
                    /* No \n found*/
                    goto more_characters;
                }
                /* trim the trailing whites */
                len = already_len;
                while (len > 0) {
                    already_len = len--;
                    if (string[len] != ' ') {
                        break;
                    }
                }
                string[already_len] = '\0';
                return (synctex_ss_s) {string, SYNCTEX_STATUS_OK};
            }
            free(string);
            _synctex_error("could not copy memory (1).");
            return (synctex_ss_s) {NULL, SYNCTEX_STATUS_ERROR};
        }
    }
    free(string);
    _synctex_error("could not (re)allocate memory (1).");
    return (synctex_ss_s) {NULL, SYNCTEX_STATUS_ERROR};
}

/*  Used when parsing the synctex file.
 *  Read an Input record.
 *  - parameter scanner: non NULL scanner
 *  - returns SYNCTEX_STATUS_OK on successful completions, others values otherwise.
 */
static synctex_ns_s __synctex_parse_new_input(synctex_scanner_p scanner)
{
    synctex_node_p input = NULL;
    synctex_status_t status = SYNCTEX_STATUS_BAD_ARGUMENT;
    synctex_zs_s zs = {0, 0};
    if (NULL == scanner) {
        return (synctex_ns_s) {NULL, status};
    }
    if ((status = _synctex_match_string(scanner, SYNCTEX_INPUT_MARK)) < SYNCTEX_STATUS_OK) {
        return (synctex_ns_s) {NULL, status};
    }
    /*  Create a node */
    if (NULL == (input = _synctex_new_input(scanner))) {
        _synctex_error("Could not create an input node.");
        return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
    }
    /*  Decode the tag  */
    if ((status = _synctex_data_decode_tag(input)) < SYNCTEX_STATUS_OK) {
        _synctex_error("Bad format of input node.");
        synctex_node_free(input);
        return (synctex_ns_s) {NULL, status};
    }
    /*  The next character is a field separator, we expect one character in the buffer. */
    zs = _synctex_buffer_get_available_size(scanner, 1);
    if (zs.status <= SYNCTEX_STATUS_ERROR) {
        return (synctex_ns_s) {NULL, status};
    }
    if (0 == zs.size) {
        return (synctex_ns_s) {NULL, SYNCTEX_STATUS_EOF};
    }
    /*  We can now safely advance to the next character, stepping over the field separator. */
    ++SYNCTEX_CUR;
    --zs.size;
    /*  Then we scan the file name */
    if ((status = _synctex_data_decode_name(input)) < SYNCTEX_STATUS_OK) {
        synctex_node_free(input);
        _synctex_next_line(scanner); /* Ignore this whole line */
        return (synctex_ns_s) {NULL, status};
    }
    /*  Prepend this input node to the input linked list of the scanner */
    __synctex_tree_set_sibling(input, scanner->input); /* input has no parent */
    scanner->input = input;
#ifdef SYNCTEX_VERBOSE
    synctex_node_log(input);
#endif
    return (synctex_ns_s) {input, _synctex_next_line(scanner)}; /*  read the line termination character, if any */
}

typedef synctex_is_s (*synctex_decoder_t)(synctex_scanner_p);

/*  Used when parsing the synctex file.
 *  Read one of the settings.
 *  On normal completion, returns SYNCTEX_STATUS_OK.
 *  On error, returns SYNCTEX_STATUS_ERROR.
 *  Both arguments must not be NULL.
 *  On return, the scanner points to the next character after the decoded object whatever it is.
 *  It is the responsibility of the caller to prepare the scanner for the next line.
 */
static synctex_status_t _synctex_scan_named(synctex_scanner_p scanner, const char *name)
{
    synctex_status_t status = 0;
    if (NULL == scanner || NULL == name) {
        return SYNCTEX_STATUS_BAD_ARGUMENT;
    }
not_found:
    status = _synctex_match_string(scanner, name);
    if (status < SYNCTEX_STATUS_NOT_OK) {
        return status;
    } else if (status == SYNCTEX_STATUS_NOT_OK) {
        status = _synctex_next_line(scanner);
        if (status < SYNCTEX_STATUS_OK) {
            return status;
        }
        goto not_found;
    }
    return SYNCTEX_STATUS_OK;
}

/*  Used when parsing the synctex file.
 *  Read the preamble.
 */
static synctex_status_t _synctex_scan_preamble(synctex_scanner_p scanner)
{
    synctex_status_t status = 0;
    synctex_is_s is = {0, 0};
    synctex_ss_s ss = {NULL, 0};
    if (NULL == scanner) {
        return SYNCTEX_STATUS_BAD_ARGUMENT;
    }
    status = _synctex_scan_named(scanner, "SyncTeX Version:");
    if (status < SYNCTEX_STATUS_OK) {
        return status;
    }
    is = _synctex_decode_int(scanner);
    if (is.status < SYNCTEX_STATUS_OK) {
        return is.status;
    }
    status = _synctex_next_line(scanner);
    if (status < SYNCTEX_STATUS_OK) {
        return status;
    }
    scanner->version = is.integer;
    /*  Read all the input records */
    do {
        status = __synctex_parse_new_input(scanner).status;
        if (status < SYNCTEX_STATUS_NOT_OK) {
            return status;
        }
    } while (status == SYNCTEX_STATUS_OK);
    /*  the loop exits when status == SYNCTEX_STATUS_NOT_OK */
    /*  Now read all the required settings. */
    if ((status = _synctex_scan_named(scanner, "Output:")) < SYNCTEX_STATUS_OK) {
        return status;
    }
    if ((ss = _synctex_decode_string(scanner)).status < SYNCTEX_STATUS_OK) {
        return is.status;
    }
    if ((status = _synctex_next_line(scanner)) < SYNCTEX_STATUS_OK) {
        return status;
    }
    scanner->output_fmt = ss.string;
    if ((status = _synctex_scan_named(scanner, "Magnification:")) < SYNCTEX_STATUS_OK) {
        return status;
    }
    if ((is = _synctex_decode_int(scanner)).status < SYNCTEX_STATUS_OK) {
        return is.status;
    }
    if ((status = _synctex_next_line(scanner)) < SYNCTEX_STATUS_OK) {
        return status;
    }
    scanner->pre_magnification = is.integer;
    if ((status = _synctex_scan_named(scanner, "Unit:")) < SYNCTEX_STATUS_OK) {
        return status;
    }
    if ((is = _synctex_decode_int(scanner)).status < SYNCTEX_STATUS_OK) {
        return is.status;
    }
    if ((status = _synctex_next_line(scanner)) < SYNCTEX_STATUS_OK) {
        return status;
    }
    scanner->pre_unit = is.integer;
    if ((status = _synctex_scan_named(scanner, "X Offset:")) < SYNCTEX_STATUS_OK) {
        return status;
    }
    if ((is = _synctex_decode_int(scanner)).status < SYNCTEX_STATUS_OK) {
        return is.status;
    }
    if ((status = _synctex_next_line(scanner)) < SYNCTEX_STATUS_OK) {
        return status;
    }
    scanner->pre_x_offset = is.integer;
    if ((status = _synctex_scan_named(scanner, "Y Offset:")) < SYNCTEX_STATUS_OK) {
        return status;
    }
    if ((is = _synctex_decode_int(scanner)).status < SYNCTEX_STATUS_OK) {
        return is.status;
    }
    if ((status = _synctex_next_line(scanner)) < SYNCTEX_STATUS_OK) {
        return status;
    }
    scanner->pre_y_offset = is.integer;
    return SYNCTEX_STATUS_OK;
}

/*  parse a float with a dimension */
static synctex_fs_s _synctex_scan_float_and_dimension(synctex_scanner_p scanner)
{
    synctex_fs_s fs = {0, 0};
    synctex_zs_s zs = {0, 0};
    char *endptr = NULL;
#ifdef HAVE_SETLOCALE
    char *loc = setlocale(LC_NUMERIC, NULL);
#endif
    if (NULL == scanner) {
        return (synctex_fs_s) {0, SYNCTEX_STATUS_BAD_ARGUMENT};
    }
    zs = _synctex_buffer_get_available_size(scanner, SYNCTEX_BUFFER_MIN_SIZE);
    if (zs.status < SYNCTEX_STATUS_EOF) {
        _synctex_error("Problem with float.");
        return (synctex_fs_s) {0, zs.status};
    }
#ifdef HAVE_SETLOCALE
    setlocale(LC_NUMERIC, "C");
#endif
    fs.value = strtod(SYNCTEX_CUR, &endptr);
#ifdef HAVE_SETLOCALE
    setlocale(LC_NUMERIC, loc);
#endif
    if (endptr == SYNCTEX_CUR) {
        _synctex_error("A float was expected.");
        return (synctex_fs_s) {0, SYNCTEX_STATUS_ERROR};
    }
    SYNCTEX_CUR = endptr;
    if ((fs.status = _synctex_match_string(scanner, "in")) >= SYNCTEX_STATUS_OK) {
        fs.value *= 72.27f * 65536;
    } else if (fs.status < SYNCTEX_STATUS_EOF) {
    report_unit_error:
        _synctex_error("problem with unit.");
        return fs;
    } else if ((fs.status = _synctex_match_string(scanner, "cm")) >= SYNCTEX_STATUS_OK) {
        fs.value *= 72.27f * 65536 / 2.54f;
    } else if (fs.status < SYNCTEX_STATUS_EOF) {
        goto report_unit_error;
    } else if ((fs.status = _synctex_match_string(scanner, "mm")) >= SYNCTEX_STATUS_OK) {
        fs.value *= 72.27f * 65536 / 25.4f;
    } else if (fs.status < SYNCTEX_STATUS_EOF) {
        goto report_unit_error;
    } else if ((fs.status = _synctex_match_string(scanner, "pt")) >= SYNCTEX_STATUS_OK) {
        fs.value *= 65536.0f;
    } else if (fs.status < SYNCTEX_STATUS_EOF) {
        goto report_unit_error;
    } else if ((fs.status = _synctex_match_string(scanner, "bp")) >= SYNCTEX_STATUS_OK) {
        fs.value *= 72.27f / 72 * 65536.0f;
    } else if (fs.status < SYNCTEX_STATUS_EOF) {
        goto report_unit_error;
    } else if ((fs.status = _synctex_match_string(scanner, "pc")) >= SYNCTEX_STATUS_OK) {
        fs.value *= 12.0 * 65536.0f;
    } else if (fs.status < SYNCTEX_STATUS_EOF) {
        goto report_unit_error;
    } else if ((fs.status = _synctex_match_string(scanner, "sp")) >= SYNCTEX_STATUS_OK) {
        fs.value *= 1.0f;
    } else if (fs.status < SYNCTEX_STATUS_EOF) {
        goto report_unit_error;
    } else if ((fs.status = _synctex_match_string(scanner, "dd")) >= SYNCTEX_STATUS_OK) {
        fs.value *= 1238.0f / 1157 * 65536.0f;
    } else if (fs.status < SYNCTEX_STATUS_EOF) {
        goto report_unit_error;
    } else if ((fs.status = _synctex_match_string(scanner, "cc")) >= SYNCTEX_STATUS_OK) {
        fs.value *= 14856.0f / 1157 * 65536;
    } else if (fs.status < SYNCTEX_STATUS_EOF) {
        goto report_unit_error;
    } else if ((fs.status = _synctex_match_string(scanner, "nd")) >= SYNCTEX_STATUS_OK) {
        fs.value *= 685.0f / 642 * 65536;
    } else if (fs.status < SYNCTEX_STATUS_EOF) {
        goto report_unit_error;
    } else if ((fs.status = _synctex_match_string(scanner, "nc")) >= SYNCTEX_STATUS_OK) {
        fs.value *= 1370.0f / 107 * 65536;
    } else if (fs.status < SYNCTEX_STATUS_EOF) {
        goto report_unit_error;
    }
    return fs;
}

/*  parse the post scriptum
 *  SYNCTEX_STATUS_OK is returned on completion
 *  a negative error is returned otherwise */
static synctex_status_t _synctex_scan_post_scriptum(synctex_scanner_p scanner)
{
    synctex_status_t status = 0;
    synctex_fs_s fs = {0, 0};
    char *endptr = NULL;
#ifdef HAVE_SETLOCALE
    char *loc = setlocale(LC_NUMERIC, NULL);
#endif
    if (NULL == scanner) {
        return SYNCTEX_STATUS_BAD_ARGUMENT;
    }
    /*  Scan the file until a post scriptum line is found */
post_scriptum_not_found:
    status = _synctex_match_string(scanner, "Post scriptum:");
    if (status < SYNCTEX_STATUS_NOT_OK) {
        return status;
    }
    if (status == SYNCTEX_STATUS_NOT_OK) {
        status = _synctex_next_line(scanner);
        if (status < SYNCTEX_STATUS_EOF) {
            return status;
        } else if (status < SYNCTEX_STATUS_OK) {
            return SYNCTEX_STATUS_OK; /*  The EOF is found, we have properly scanned the file */
        }
        goto post_scriptum_not_found;
    }
    /*  We found the name, advance to the next line. */
next_line:
    status = _synctex_next_line(scanner);
    if (status < SYNCTEX_STATUS_EOF) {
        return status;
    } else if (status < SYNCTEX_STATUS_OK) {
        return SYNCTEX_STATUS_OK; /*  The EOF is found, we have properly scanned the file */
    }
    /*  Scanning the information */
    status = _synctex_match_string(scanner, "Magnification:");
    if (status == SYNCTEX_STATUS_OK) {
#ifdef HAVE_SETLOCALE
        setlocale(LC_NUMERIC, "C");
#endif
        scanner->unit = strtod(SYNCTEX_CUR, &endptr);
#ifdef HAVE_SETLOCALE
        setlocale(LC_NUMERIC, loc);
#endif
        if (endptr == SYNCTEX_CUR) {
            _synctex_error("bad magnification in the post scriptum, a float was expected.");
            return SYNCTEX_STATUS_ERROR;
        }
        if (scanner->unit <= 0) {
            _synctex_error("bad magnification in the post scriptum, a positive float was expected.");
            return SYNCTEX_STATUS_ERROR;
        }
        SYNCTEX_CUR = endptr;
        goto next_line;
    }
    if (status < SYNCTEX_STATUS_EOF) {
    report_record_problem:
        _synctex_error("Problem reading the Post Scriptum records");
        return status; /*  echo the error. */
    }
    status = _synctex_match_string(scanner, "X Offset:");
    if (status == SYNCTEX_STATUS_OK) {
        fs = _synctex_scan_float_and_dimension(scanner);
        if (fs.status < SYNCTEX_STATUS_OK) {
            _synctex_error("Problem with X offset in the Post Scriptum.");
            return fs.status;
        }
        scanner->x_offset = fs.value;
        goto next_line;
    } else if (status < SYNCTEX_STATUS_EOF) {
        goto report_record_problem;
    }
    status = _synctex_match_string(scanner, "Y Offset:");
    if (status == SYNCTEX_STATUS_OK) {
        fs = _synctex_scan_float_and_dimension(scanner);
        if (fs.status < SYNCTEX_STATUS_OK) {
            _synctex_error("Problem with Y offset in the Post Scriptum.");
            return fs.status;
        }
        scanner->x_offset = fs.value;
        goto next_line;
    } else if (status < SYNCTEX_STATUS_EOF) {
        goto report_record_problem;
    }
    goto next_line;
}

/*  SYNCTEX_STATUS_OK is returned if the postamble is read
 *  SYNCTEX_STATUS_NOT_OK is returned if the postamble is not at the current location
 *  a negative error otherwise
 *  The postamble comprises the post scriptum section.
 */
static synctex_status_t _synctex_scan_postamble(synctex_scanner_p scanner)
{
    synctex_status_t status = 0;
    synctex_is_s is = {0, 0};
    if (NULL == scanner) {
        return SYNCTEX_STATUS_BAD_ARGUMENT;
    }
    if (!scanner->flags.postamble && (status = _synctex_match_string(scanner, "Postamble:")) < SYNCTEX_STATUS_OK) {
        return status;
    }
count_again:
    if ((status = _synctex_next_line(scanner)) < SYNCTEX_STATUS_OK) {
        return status;
    }
    if ((status = _synctex_scan_named(scanner, "Count:")) < SYNCTEX_STATUS_EOF) {
        return status;                       /*  forward the error */
    } else if (status < SYNCTEX_STATUS_OK) { /*  No Count record found */
        goto count_again;
    }
    if ((is = _synctex_decode_int(scanner)).status < SYNCTEX_STATUS_OK) {
        return is.status;
    }
    if ((status = _synctex_next_line(scanner)) < SYNCTEX_STATUS_OK) {
        return status;
    }
    scanner->count = is.integer;
    /*  Now we scan the last part of the SyncTeX file: the Post Scriptum section. */
    return _synctex_scan_post_scriptum(scanner);
}

/*  Horizontal boxes also have visible size.
 *  Visible size are bigger than real size.
 *  For example 0 width boxes may contain text.
 *  At creation time, the visible size is set to the values of the real size.
 */
static synctex_status_t _synctex_setup_visible_hbox(synctex_node_p box)
{
    if (box) {
        switch (synctex_node_type(box)) {
        case synctex_node_type_hbox:
            _synctex_data_set_h_V(box, _synctex_data_h(box));
            _synctex_data_set_v_V(box, _synctex_data_v(box));
            _synctex_data_set_width_V(box, _synctex_data_width(box));
            _synctex_data_set_height_V(box, _synctex_data_height(box));
            _synctex_data_set_depth_V(box, _synctex_data_depth(box));
            return SYNCTEX_STATUS_OK;
        default:
            break;
        }
    }
    return SYNCTEX_STATUS_BAD_ARGUMENT;
}

/*  This method is sent to an horizontal box to setup the visible size
 *  Some box have 0 width but do contain text material.
 *  With this method, one can enlarge the box to contain the given point (h,v).
 */
static synctex_status_t _synctex_make_hbox_contain_point(synctex_node_p node, synctex_point_s point)
{
    int min, max, n;
    if (NULL == node || synctex_node_type(node) != synctex_node_type_hbox) {
        return SYNCTEX_STATUS_BAD_ARGUMENT;
    }
    if ((n = _synctex_data_width_V(node)) < 0) {
        max = _synctex_data_h_V(node);
        min = max + n;
        if (point.h < min) {
            _synctex_data_set_width_V(node, point.h - max);
        } else if (point.h > max) {
            _synctex_data_set_h_V(node, point.h);
            _synctex_data_set_width_V(node, min - point.h);
        }
    } else {
        min = _synctex_data_h_V(node);
        max = min + n;
        if (point.h < min) {
            _synctex_data_set_h_V(node, point.h);
            _synctex_data_set_width_V(node, max - point.h);
        } else if (point.h > max) {
            _synctex_data_set_width_V(node, point.h - min);
        }
    }
    n = _synctex_data_v_V(node);
    min = n - _synctex_data_height_V(node);
    max = n + _synctex_data_depth_V(node);
    if (point.v < min) {
        _synctex_data_set_height_V(node, n - point.v);
    } else if (point.v > max) {
        _synctex_data_set_depth_V(node, point.v - n);
    }
    return SYNCTEX_STATUS_OK;
}
static synctex_status_t _synctex_make_hbox_contain_box(synctex_node_p node, synctex_box_s box)
{
    int min, max, n;
    if (NULL == node || synctex_node_type(node) != synctex_node_type_hbox) {
        return SYNCTEX_STATUS_BAD_ARGUMENT;
    }
    if ((n = _synctex_data_width_V(node)) < 0) {
        max = _synctex_data_h_V(node);
        min = max + n;
        if (box.min.h < min) {
            _synctex_data_set_width_V(node, box.min.h - max);
        } else if (box.max.h > max) {
            _synctex_data_set_h_V(node, box.max.h);
            _synctex_data_set_width_V(node, min - box.max.h);
        }
    } else {
        min = _synctex_data_h_V(node);
        max = min + n;
        if (box.min.h < min) {
            _synctex_data_set_h_V(node, box.min.h);
            _synctex_data_set_width_V(node, max - box.min.h);
        } else if (box.max.h > max) {
            _synctex_data_set_width_V(node, box.max.h - min);
        }
    }
    n = _synctex_data_v_V(node);
    min = n - _synctex_data_height_V(node);
    max = n + _synctex_data_depth_V(node);
    if (box.min.v < min) {
        _synctex_data_set_height_V(node, n - box.min.v);
    } else if (box.max.v > max) {
        _synctex_data_set_depth_V(node, box.max.v - n);
    }
    return SYNCTEX_STATUS_OK;
}
#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark SPECIAL CHARACTERS
#endif

/*  Here are the control characters that strat each line of the synctex output file.
 *  Their values define the meaning of the line.
 */
#define SYNCTEX_CHAR_BEGIN_SHEET '{'
#define SYNCTEX_CHAR_END_SHEET '}'
#define SYNCTEX_CHAR_BEGIN_FORM '<'
#define SYNCTEX_CHAR_END_FORM '>'
#define SYNCTEX_CHAR_BEGIN_VBOX '['
#define SYNCTEX_CHAR_END_VBOX ']'
#define SYNCTEX_CHAR_BEGIN_HBOX '('
#define SYNCTEX_CHAR_END_HBOX ')'
#define SYNCTEX_CHAR_ANCHOR '!'
#define SYNCTEX_CHAR_VOID_VBOX 'v'
#define SYNCTEX_CHAR_VOID_HBOX 'h'
#define SYNCTEX_CHAR_KERN 'k'
#define SYNCTEX_CHAR_GLUE 'g'
#define SYNCTEX_CHAR_RULE 'r'
#define SYNCTEX_CHAR_MATH '$'
#define SYNCTEX_CHAR_FORM_REF 'f'
#define SYNCTEX_CHAR_BOUNDARY 'x'
#define SYNCTEX_CHAR_CHARACTER 'c'
#define SYNCTEX_CHAR_COMMENT '%'

#define SYNCTEX_RETURN(STATUS) return STATUS;

#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark SCANNERS & PARSERS
#endif

#define SYNCTEX_DECODE_FAILED(NODE, WHAT) (_synctex_data_decode_##WHAT(NODE) < SYNCTEX_STATUS_OK)
#define SYNCTEX_DECODE_FAILED_V(NODE, WHAT) (_synctex_data_decode_##WHAT##_v(NODE) < SYNCTEX_STATUS_OK)

#define SYNCTEX_NS_NULL                                                                                                                                                                                                                        \
    (synctex_ns_s)                                                                                                                                                                                                                             \
    {                                                                                                                                                                                                                                          \
        NULL, SYNCTEX_STATUS_NOT_OK                                                                                                                                                                                                            \
    }
static synctex_ns_s _synctex_parse_new_sheet(synctex_scanner_p scanner)
{
    synctex_node_p node;
    if ((node = _synctex_new_sheet(scanner))) {
        if (SYNCTEX_DECODE_FAILED(node, page)) {
            _synctex_error("Bad sheet record.");
        } else if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
            _synctex_error("Missing end of sheet.");
        } else {
            /* Now set the owner */
            if (scanner->sheet) {
                synctex_node_p last_sheet = scanner->sheet;
                synctex_node_p next_sheet = NULL;
                while ((next_sheet = __synctex_tree_sibling(last_sheet))) {
                    last_sheet = next_sheet;
                }
                __synctex_tree_set_sibling(last_sheet, node); /* sheets have no parent */
            } else {
                scanner->sheet = node;
            }
            return (synctex_ns_s) {node, SYNCTEX_STATUS_OK};
        }
        _synctex_free_node(node);
    }
    return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
}
/**
 *  - requirement: scanner != NULL
 */
static synctex_ns_s _synctex_parse_new_form(synctex_scanner_p scanner)
{
    synctex_node_p node;
    if ((node = _synctex_new_form(scanner))) {
        if (SYNCTEX_DECODE_FAILED(node, tag)) {
            _synctex_error("Bad sheet record.");
        } else if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
            _synctex_error("Missing end of form.");
        } else {
            /* Now set the owner */
            if (scanner->form) {
                synctex_node_p last_form = scanner->form;
                synctex_node_p next_form = NULL;
                while ((next_form = __synctex_tree_sibling(last_form))) {
                    last_form = next_form;
                }
                __synctex_tree_set_sibling(last_form, node);
            } else {
                scanner->form = node;
            }
            return (synctex_ns_s) {node, SYNCTEX_STATUS_OK};
        }
        _synctex_free_node(node);
    }
    return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
}
#define SYNCTEX_SHOULD_DECODE_FAILED(NODE, WHAT) (_synctex_data_has_##WHAT(NODE) && (_synctex_data_decode_##WHAT(NODE) < SYNCTEX_STATUS_OK))
#define SYNCTEX_SHOULD_DECODE_FAILED_V(NODE, WHAT) (_synctex_data_has_##WHAT(NODE) && (_synctex_data_decode_##WHAT##_v(NODE) < SYNCTEX_STATUS_OK))

static synctex_status_t _synctex_data_decode_tlchvwhd(synctex_node_p node)
{
    return SYNCTEX_SHOULD_DECODE_FAILED(node, tag) || SYNCTEX_SHOULD_DECODE_FAILED(node, line) || SYNCTEX_SHOULD_DECODE_FAILED(node, column) || SYNCTEX_SHOULD_DECODE_FAILED(node, h) || SYNCTEX_SHOULD_DECODE_FAILED_V(node, v) ||
        SYNCTEX_SHOULD_DECODE_FAILED(node, width) || SYNCTEX_SHOULD_DECODE_FAILED(node, height) || SYNCTEX_SHOULD_DECODE_FAILED(node, depth);
}
static synctex_ns_s _synctex_parse_new_vbox(synctex_scanner_p scanner)
{
    synctex_node_p node;
    if ((node = _synctex_new_vbox(scanner))) {
        if (_synctex_data_decode_tlchvwhd(node)) {
            _synctex_error("Bad vbox record.");
            _synctex_next_line(scanner);
        out:
            _synctex_free_node(node);
            return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
        }
        if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
            _synctex_error("Missing end of vbox.");
            goto out;
        }
        return (synctex_ns_s) {node, SYNCTEX_STATUS_OK};
    }
    _synctex_next_line(scanner);
    return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
}
SYNCTEX_INLINE static synctex_node_p __synctex_node_make_friend_tlc(synctex_node_p node);
static synctex_ns_s _synctex_parse_new_hbox(synctex_scanner_p scanner)
{
    synctex_node_p node;
    if ((node = _synctex_new_hbox(scanner))) {
        if (_synctex_data_decode_tlchvwhd(node)) {
            _synctex_error("Bad hbox record.");
            _synctex_next_line(scanner);
        out:
            _synctex_free_node(node);
            return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
        }
        if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
            _synctex_error("Missing end of hbox.");
            goto out;
        }
        if (_synctex_setup_visible_hbox(node) < SYNCTEX_STATUS_OK) {
            _synctex_error("Unexpected error (_synctex_parse_new_hbox).");
            goto out;
        }
        return (synctex_ns_s) {node, SYNCTEX_STATUS_OK};
    }
    _synctex_next_line(scanner);
    return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
}
static synctex_ns_s _synctex_parse_new_void_vbox(synctex_scanner_p scanner)
{
    synctex_node_p node;
    if ((node = _synctex_new_void_vbox(scanner))) {
        if (_synctex_data_decode_tlchvwhd(node)) {
            _synctex_error("Bad void vbox record.");
            _synctex_next_line(scanner);
        out:
            _synctex_free_node(node);
            return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
        }
        if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
            _synctex_error("Missing end of container.");
            goto out;
        }
        return (synctex_ns_s) {node, SYNCTEX_STATUS_OK};
    }
    _synctex_next_line(scanner);
    return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
}
static synctex_ns_s _synctex_parse_new_void_hbox(synctex_scanner_p scanner)
{
    synctex_node_p node;
    if ((node = _synctex_new_void_hbox(scanner))) {
        if (_synctex_data_decode_tlchvwhd(node)) {
            _synctex_error("Bad void hbox record.");
            _synctex_next_line(scanner);
        out:
            _synctex_free_node(node);
            return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
        }
        if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
            _synctex_error("Missing end of container.");
            goto out;
        }
        return (synctex_ns_s) {node, SYNCTEX_STATUS_OK};
    }
    _synctex_next_line(scanner);
    return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
}
static synctex_ns_s _synctex_parse_new_kern(synctex_scanner_p scanner)
{
    synctex_node_p node;
    if ((node = _synctex_new_kern(scanner))) {
        if (_synctex_data_decode_tlchvwhd(node)) {
            _synctex_error("Bad kern record.");
            _synctex_next_line(scanner);
        out:
            _synctex_free_node(node);
            return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
        }
        if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
            _synctex_error("Missing end of container.");
            goto out;
        }
        return (synctex_ns_s) {node, SYNCTEX_STATUS_OK};
    }
    _synctex_next_line(scanner);
    return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
}
static synctex_ns_s _synctex_parse_new_glue(synctex_scanner_p scanner)
{
    synctex_node_p node;
    if ((node = _synctex_new_glue(scanner))) {
        if (_synctex_data_decode_tlchvwhd(node)) {
            _synctex_error("Bad glue record.");
            _synctex_next_line(scanner);
        out:
            _synctex_free_node(node);
            return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
        }
        if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
            _synctex_error("Missing end of container.");
            goto out;
        }
        return (synctex_ns_s) {node, SYNCTEX_STATUS_OK};
    }
    _synctex_next_line(scanner);
    return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
}
static synctex_ns_s _synctex_parse_new_rule(synctex_scanner_p scanner)
{
    synctex_node_p node;
    if ((node = _synctex_new_rule(scanner))) {
        if (_synctex_data_decode_tlchvwhd(node)) {
            _synctex_error("Bad rule record.");
            _synctex_next_line(scanner);
        out:
            _synctex_free_node(node);
            return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
        }
        if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
            _synctex_error("Missing end of container.");
            goto out;
        }
        return (synctex_ns_s) {node, SYNCTEX_STATUS_OK};
    }
    _synctex_next_line(scanner);
    return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
}
static synctex_ns_s _synctex_parse_new_math(synctex_scanner_p scanner)
{
    synctex_node_p node;
    if ((node = _synctex_new_math(scanner))) {
        if (_synctex_data_decode_tlchvwhd(node)) {
            _synctex_error("Bad math record.");
            _synctex_next_line(scanner);
        out:
            _synctex_free_node(node);
            return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
        }
        if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
            _synctex_error("Missing end of container.");
            goto out;
        }
        return (synctex_ns_s) {node, SYNCTEX_STATUS_OK};
    }
    _synctex_next_line(scanner);
    return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
}
static synctex_ns_s _synctex_parse_new_boundary(synctex_scanner_p scanner)
{
    synctex_node_p node;
    if ((node = _synctex_new_boundary(scanner))) {
        if (_synctex_data_decode_tlchvwhd(node)) {
            _synctex_error("Bad boundary record.");
            _synctex_next_line(scanner);
        out:
            _synctex_free_node(node);
            return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
        }
        if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
            _synctex_error("Missing end of container.");
            goto out;
        }
        return (synctex_ns_s) {node, SYNCTEX_STATUS_OK};
    }
    _synctex_next_line(scanner);
    return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
}
SYNCTEX_INLINE static synctex_ns_s _synctex_parse_new_ref(synctex_scanner_p scanner)
{
    synctex_node_p node;
    if ((node = _synctex_new_ref(scanner))) {
        if (SYNCTEX_DECODE_FAILED(node, tag) || SYNCTEX_DECODE_FAILED(node, h) || SYNCTEX_DECODE_FAILED_V(node, v)) {
            _synctex_error("Bad form ref record.");
            _synctex_next_line(scanner);
        out:
            _synctex_free_node(node);
            return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
        }
        if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
            _synctex_error("Missing end of container.");
            goto out;
        }
        return (synctex_ns_s) {node, SYNCTEX_STATUS_OK};
    }
    _synctex_next_line(scanner);
    return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR};
}
#undef SYNCTEX_DECODE_FAILED
#undef SYNCTEX_DECODE_FAILED_V

SYNCTEX_INLINE static synctex_point_s _synctex_data_point(synctex_node_p node);
SYNCTEX_INLINE static synctex_point_s _synctex_data_point_V(synctex_node_p node);
SYNCTEX_INLINE static synctex_point_s _synctex_data_set_point(synctex_node_p node, synctex_point_s point);
SYNCTEX_INLINE static synctex_box_s _synctex_data_box(synctex_node_p node);
SYNCTEX_INLINE static synctex_box_s _synctex_data_xob(synctex_node_p node);
SYNCTEX_INLINE static synctex_box_s _synctex_data_box_V(synctex_node_p node);

SYNCTEX_INLINE static synctex_node_p _synctex_input_register_line(synctex_node_p input, synctex_node_p node)
{
    if (node && _synctex_data_tag(input) != _synctex_data_tag(node)) {
        input = synctex_scanner_input_with_tag(node->class->scanner, _synctex_data_tag(node));
    }
    if (_synctex_data_line(node) > _synctex_data_line(input)) {
        _synctex_data_set_line(input, _synctex_data_line(node));
    }
    return input;
}
/**
 *  Scan sheets, forms and input records.
 *  - parameter scanner: owning scanner
 *  - returns: status
 */
static synctex_status_t __synctex_parse_sfi(synctex_scanner_p scanner)
{
    synctex_status_t status = SYNCTEX_STATUS_OK;
    synctex_zs_s zs = {0, 0};
    synctex_ns_s input = SYNCTEX_NS_NULL;
    synctex_node_p sheet = NULL;
    synctex_node_p form = NULL;
    synctex_node_p parent = NULL;
    synctex_node_p child = NULL;
    synctex_ns_s ns = SYNCTEX_NS_NULL;
    int form_depth = 0;
    int ignored_form_depth = 0;
    synctex_bool_t try_input = synctex_YES;
#ifdef SYNCTEX_NOTHING
#pragma mark MAIN LOOP
#endif
main_loop:
    status = SYNCTEX_STATUS_OK;
    sheet = form = parent = child = NULL;
#define SYNCTEX_START_SCAN(WHAT) (*SYNCTEX_CUR == SYNCTEX_CHAR_##WHAT)
    if (SYNCTEX_CUR < SYNCTEX_END) {
        if (SYNCTEX_START_SCAN(BEGIN_FORM)) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN FORM
#endif
        scan_form:
            ns = _synctex_parse_new_form(scanner);
            if (ns.status == SYNCTEX_STATUS_OK) {
                ++form_depth;
                if (_synctex_tree_parent(form)) {
                    /* This form is already being parsed */
                    ++ignored_form_depth;
                    goto ignore_loop;
                }
                _synctex_tree_set_parent(ns.node, form);
                form = ns.node;
                parent = form;
                child = NULL;
                goto content_loop;
            }
            if (form || sheet) {
                goto content_loop;
            }
            try_input = synctex_YES;
            goto main_loop;
        } else if (SYNCTEX_START_SCAN(BEGIN_SHEET)) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN SHEET
#endif
            try_input = synctex_YES;
            ns = _synctex_parse_new_sheet(scanner);
            if (ns.status == SYNCTEX_STATUS_OK) {
                sheet = ns.node;
                parent = sheet;
                goto content_loop;
            }
            goto main_loop;
        } else if (SYNCTEX_START_SCAN(ANCHOR)) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN ANCHOR
#endif
        scan_anchor:
            ++SYNCTEX_CUR;
            if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
                _synctex_error("Missing anchor.");
                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
            }
            if (form || sheet) {
                goto content_loop;
            }
            try_input = synctex_YES;
            goto main_loop;
        } else if (SYNCTEX_START_SCAN(ANCHOR)) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN COMMENT
#endif
            ++SYNCTEX_CUR;
            _synctex_next_line(scanner);
            try_input = synctex_YES;
            goto main_loop;
        } else if (try_input) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN INPUT
#endif
            try_input = synctex_NO;
            do {
                input = __synctex_parse_new_input(scanner);
            } while (input.status == SYNCTEX_STATUS_OK);
            goto main_loop;
        }
        status = _synctex_match_string(scanner, "Postamble:");
        if (status == SYNCTEX_STATUS_OK) {
            scanner->flags.postamble = 1;
            return status;
        }
        status = _synctex_next_line(scanner);
        if (status < SYNCTEX_STATUS_OK) {
            return status;
        }
    }
    /* At least 1 more character */
    zs = _synctex_buffer_get_available_size(scanner, 1);
    if (zs.size == 0) {
        _synctex_error("Uncomplete synctex file, postamble missing.");
        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
    }
    goto main_loop;
    /*  Unreachable. */
#ifdef SYNCTEX_NOTHING
#pragma mark IGNORE LOOP
#endif
ignore_loop:
    ns = SYNCTEX_NS_NULL;
    if (SYNCTEX_CUR < SYNCTEX_END) {
        if (SYNCTEX_START_SCAN(BEGIN_FORM)) {
            ++ignored_form_depth;
        } else if (SYNCTEX_START_SCAN(END_FORM)) {
            --ignored_form_depth;
        }
        if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
            _synctex_error("Uncomplete container.");
            SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
        }
    } else {
        zs = _synctex_buffer_get_available_size(scanner, 1);
        if (zs.size == 0) {
            _synctex_error("Uncomplete synctex file, postamble missing.");
            SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
        }
    }
    if (ignored_form_depth) {
        goto ignore_loop;
    } else {
        goto content_loop;
    }

#ifdef SYNCTEX_NOTHING
#pragma mark CONTENT LOOP
#endif
content_loop:
    /*  Either in a form, a sheet or a box.
     *  - in a sheet, "{" is not possible, only boxes and "}" at top level.
     *  - in a form, "{" is not possible, only boxes, "<" and ">" at top level.
     *  - in a box, the unique possibility is '<', '[', '(' or ">".
     *  We still keep the '(' for a sheet, because that dos not cost too much.
     *  We must also consider void boxes as children.
     */
    /* forms are everywhere */
    ns = SYNCTEX_NS_NULL;
#ifdef SYNCTEX_VERBOSE
    synctex_scanner_set_display_switcher(scanner, -1);
    printf("NEW CONTENT LOOP\n");
#if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500
    synctex_node_display(sheet);
#endif
#endif
    if (SYNCTEX_CUR < SYNCTEX_END) {
        if (SYNCTEX_START_SCAN(BEGIN_FORM)) {
            goto scan_form;
        } else if (SYNCTEX_START_SCAN(BEGIN_VBOX)) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN VBOX
#endif
            ns = _synctex_parse_new_vbox(scanner);
            if (ns.status == SYNCTEX_STATUS_OK) {
                if (child) {
                    _synctex_node_set_sibling(child, ns.node);
                } else {
                    _synctex_node_set_child(parent, ns.node);
                }
                parent = ns.node;
                child = _synctex_tree_last(parent);
#ifdef SYNCTEX_VERBOSE
                synctex_node_log(parent);
#endif
                input.node = _synctex_input_register_line(input.node, parent);
                goto content_loop;
            }
        } else if (SYNCTEX_START_SCAN(END_VBOX)) {
            if (synctex_node_type(parent) == synctex_node_type_vbox) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN XOBV
#endif
                ++SYNCTEX_CUR;
                if (NULL == _synctex_tree_child(parent) && !form) {
                    /*  only void v boxes are friends */
                    _synctex_node_make_friend_tlc(parent);
                }
                child = parent;
                parent = _synctex_tree_parent(child);
#ifdef SYNCTEX_VERBOSE
                synctex_node_log(child);
#endif
                if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
                    _synctex_error("Uncomplete container.");
                    SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
                }
                goto content_loop;
            }
        } else if (SYNCTEX_START_SCAN(BEGIN_HBOX)) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN HBOX
#endif
#if defined(SYNCTEX_USE_CHARINDEX)
            synctex_charindex_t char_index = (synctex_charindex_t)(scanner->reader->charindex_offset + SYNCTEX_CUR - SYNCTEX_START);
            synctex_lineindex_t line_index = scanner->reader->line_number;
#endif
            ns = _synctex_parse_new_hbox(scanner);
            if (ns.status == SYNCTEX_STATUS_OK) {
                if (child) {
                    _synctex_node_set_sibling(child, ns.node);
                } else {
                    _synctex_node_set_child(parent, ns.node);
                }
                parent = ns.node;
                /*  add a box boundary node at the start */
                if ((child = _synctex_new_box_bdry(scanner))) {
#if defined(SYNCTEX_USE_CHARINDEX)
                    child->line_index = line_index;
                    child->char_index = char_index;
#endif
                    _synctex_node_set_child(parent, child);
                    _synctex_data_set_tag(child, _synctex_data_tag(parent));
                    _synctex_data_set_line(child, _synctex_data_line(parent));
                    _synctex_data_set_h(child, _synctex_data_h(parent));
                    _synctex_data_set_v(child, _synctex_data_v(parent));
                    if (!form) {
                        __synctex_node_make_friend_tlc(child);
                    }
                } else {
                    _synctex_error("Can't create box bdry record.");
                }
#ifdef SYNCTEX_VERBOSE
                synctex_node_log(parent);
#endif
                input.node = _synctex_input_register_line(input.node, parent);
                goto content_loop;
            }
        } else if (SYNCTEX_START_SCAN(END_HBOX)) {
            if (synctex_node_type(parent) == synctex_node_type_hbox) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN XOBH
#endif
                ++SYNCTEX_CUR;
                {
                    /*  setting the next horizontal box at the end ensures
                     * that a child is recorded before any of its ancestors.
                     */
                    if (form == NULL /* && sheet != NULL*/) {
                        _synctex_tree_set_next_hbox(parent, _synctex_tree_next_hbox(sheet));
                        _synctex_tree_set_next_hbox(sheet, parent);
                    }
                    /*  Update the mean line number */
                    synctex_node_p node = _synctex_tree_child(parent);
                    synctex_node_p sibling = NULL;
                    /*  Ignore the first node (a box_bdry) */
                    if (node && (node = __synctex_tree_sibling(node))) {
                        unsigned int node_weight = 0;
                        unsigned int cumulated_line_numbers = 0;
                        do {
                            if (synctex_node_type(node) == synctex_node_type_hbox) {
                                if (_synctex_data_weight(node)) {
                                    node_weight += _synctex_data_weight(node);
                                    cumulated_line_numbers += _synctex_data_mean_line(node) * _synctex_data_weight(node);
                                } else {
                                    ++node_weight;
                                    cumulated_line_numbers += _synctex_data_mean_line(node);
                                }
                            } else {
                                ++node_weight;
                                cumulated_line_numbers += synctex_node_line(node);
                            }
                        } while ((node = __synctex_tree_sibling(node)));
                        _synctex_data_set_mean_line(parent, (cumulated_line_numbers + node_weight / 2) / node_weight);
                        _synctex_data_set_weight(parent, node_weight);
                    } else {
                        _synctex_data_set_mean_line(parent, _synctex_data_line(parent));
                        _synctex_data_set_weight(parent, 1);
                    }
                    if ((sibling = _synctex_new_box_bdry(scanner))) {
#if defined(SYNCTEX_USE_CHARINDEX)
                        sibling->line_index = child->line_index;
                        sibling->char_index = child->char_index;
#endif
                        _synctex_node_set_sibling(child, sibling);
                        {
                            synctex_node_p N = child;
                            while (synctex_node_type(N) == synctex_node_type_ref) {
                                N = _synctex_tree_arg_sibling(N);
                            }
                            _synctex_data_set_tag(sibling, _synctex_data_tag(N));
                            _synctex_data_set_line(sibling, _synctex_data_line(N));
                        }
                        _synctex_data_set_h(sibling, _synctex_data_h_V(parent) + _synctex_data_width_V(parent));
                        _synctex_data_set_v(sibling, _synctex_data_v_V(parent));
                        child = sibling;
                    } else {
                        _synctex_error("Can't create box bdry record.");
                    }
                    sibling = _synctex_tree_child(parent);
                    _synctex_data_set_point(sibling, _synctex_data_point_V(parent));
                    child = parent;
                    parent = _synctex_tree_parent(child);
                    _synctex_make_hbox_contain_box(parent, _synctex_data_box_V(child));
#ifdef SYNCTEX_VERBOSE
                    synctex_node_log(child);
#endif
                }
                if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
                    _synctex_error("Uncomplete container.");
                    SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
                }
                goto content_loop;
            }
        } else if (SYNCTEX_START_SCAN(VOID_VBOX)) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN VOID VBOX
#endif
            ns = _synctex_parse_new_void_vbox(scanner);
            if (ns.status == SYNCTEX_STATUS_OK) {
                if (child) {
                    _synctex_node_set_sibling(child, ns.node);
                } else {
                    _synctex_node_set_child(parent, ns.node);
                }
                child = ns.node;
#ifdef SYNCTEX_VERBOSE
                synctex_node_log(child);
#endif
                input.node = _synctex_input_register_line(input.node, child);
                goto content_loop;
            }
        } else if (SYNCTEX_START_SCAN(VOID_HBOX)) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN VOID HBOX
#endif
            ns = _synctex_parse_new_void_hbox(scanner);
            if (ns.status == SYNCTEX_STATUS_OK) {
                if (_synctex_data_width(ns.node) < 0) {
                    printf("Negative width\n");
                }
                if (child) {
                    _synctex_node_set_sibling(child, ns.node);
                } else {
                    _synctex_node_set_child(parent, ns.node);
                }
                child = ns.node;
                _synctex_make_hbox_contain_box(parent, _synctex_data_box(child));
#ifdef SYNCTEX_VERBOSE
                synctex_node_log(child);
#endif
                input.node = _synctex_input_register_line(input.node, child);
                goto content_loop;
            }
        } else if (SYNCTEX_START_SCAN(KERN)) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN KERN
#endif
            ns = _synctex_parse_new_kern(scanner);
            /* continue_scan: */
            if (ns.status == SYNCTEX_STATUS_OK) {
                if (child) {
                    _synctex_node_set_sibling(child, ns.node);
                } else {
                    _synctex_node_set_child(parent, ns.node);
                }
                child = ns.node;
                if (!form) {
                    __synctex_node_make_friend_tlc(child);
                }
                _synctex_make_hbox_contain_box(parent, _synctex_data_xob(child));
#ifdef SYNCTEX_VERBOSE
                synctex_node_log(child);
#endif
                input.node = _synctex_input_register_line(input.node, child);
                goto content_loop;
            }
        } else if (SYNCTEX_START_SCAN(GLUE)) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN GLUE
#endif
            ns = _synctex_parse_new_glue(scanner);
            if (ns.status == SYNCTEX_STATUS_OK) {
                if (child) {
                    _synctex_node_set_sibling(child, ns.node);
                } else {
                    _synctex_node_set_child(parent, ns.node);
                }
                child = ns.node;
                if (!form) {
                    __synctex_node_make_friend_tlc(child);
                }
                _synctex_make_hbox_contain_point(parent, _synctex_data_point(child));
#ifdef SYNCTEX_VERBOSE
                synctex_node_log(child);
#endif
                input.node = _synctex_input_register_line(input.node, child);
                goto content_loop;
            }
        } else if (SYNCTEX_START_SCAN(RULE)) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN RULE
#endif
            ns = _synctex_parse_new_rule(scanner);
            if (ns.status == SYNCTEX_STATUS_OK) {
                if (child) {
                    _synctex_node_set_sibling(child, ns.node);
                } else {
                    _synctex_node_set_child(parent, ns.node);
                }
                child = ns.node;
                if (!form) {
                    __synctex_node_make_friend_tlc(child);
                }
                /* Rules are sometimes far too big
_synctex_make_hbox_contain_box(parent,_synctex_data_box(child));
                 */
#ifdef SYNCTEX_VERBOSE
                synctex_node_log(child);
#endif
                input.node = _synctex_input_register_line(input.node, child);
                goto content_loop;
            }
        } else if (SYNCTEX_START_SCAN(MATH)) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN MATH
#endif
            ns = _synctex_parse_new_math(scanner);
            if (ns.status == SYNCTEX_STATUS_OK) {
                if (child) {
                    _synctex_node_set_sibling(child, ns.node);
                } else {
                    _synctex_node_set_child(parent, ns.node);
                }
                child = ns.node;
                if (!form) {
                    __synctex_node_make_friend_tlc(child);
                }
                _synctex_make_hbox_contain_point(parent, _synctex_data_point(child));
#ifdef SYNCTEX_VERBOSE
                synctex_node_log(child);
#endif
                input.node = _synctex_input_register_line(input.node, child);
                goto content_loop;
            }
        } else if (SYNCTEX_START_SCAN(FORM_REF)) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN FORM REF
#endif
#if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500
            synctex_node_display(parent);
            synctex_node_display(child);
#endif
            ns = _synctex_parse_new_ref(scanner);
            if (ns.status == SYNCTEX_STATUS_OK) {
                if (child) {
                    _synctex_node_set_sibling(child, ns.node);
                } else {
                    _synctex_node_set_child(parent, ns.node);
                }
                child = ns.node;
                if (form) {
                    if (scanner->ref_in_form) {
                        synctex_tree_set_friend(child, scanner->ref_in_form);
                    }
                    scanner->ref_in_form = child;
                } else {
                    if (scanner->ref_in_sheet) {
                        synctex_tree_set_friend(child, scanner->ref_in_sheet);
                    }
                    scanner->ref_in_sheet = child;
                }
#ifdef SYNCTEX_VERBOSE
                synctex_node_log(child);
#endif
                goto content_loop;
            }
        } else if (SYNCTEX_START_SCAN(BOUNDARY)) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN BOUNDARY
#endif
            ns = _synctex_parse_new_boundary(scanner);
            if (ns.status == SYNCTEX_STATUS_OK) {
                if (child) {
                    _synctex_node_set_sibling(child, ns.node);
                } else {
                    _synctex_node_set_child(parent, ns.node);
                }
                child = ns.node;
                if (!form) {
                    __synctex_node_make_friend_tlc(child);
                }
                _synctex_make_hbox_contain_point(parent, _synctex_data_point(child));
#ifdef SYNCTEX_VERBOSE
                synctex_node_log(child);
#endif
                input.node = _synctex_input_register_line(input.node, child);
                goto content_loop;
            }
        } else if (SYNCTEX_START_SCAN(CHARACTER)) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN CHARACTER
#endif
            ++SYNCTEX_CUR;
            if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
                _synctex_error("Missing end of container.");
                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
            }
            goto content_loop;
        } else if (SYNCTEX_START_SCAN(ANCHOR)) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN ANCHOR
#endif
            goto scan_anchor;
        } else if (SYNCTEX_START_SCAN(END_SHEET)) {
            if (sheet && parent == sheet) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN TEEHS
#endif
                ++SYNCTEX_CUR;
                if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
                    _synctex_error("Missing anchor.");
                }
                parent = sheet = NULL;
                goto main_loop;
            }
        } else if (SYNCTEX_START_SCAN(END_FORM)) {
            if (parent == form && form_depth > 0) {
#ifdef SYNCTEX_NOTHING
#pragma mark + SCAN MROF
#endif
                ++SYNCTEX_CUR;
                --form_depth;
                if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK && (form_depth || sheet)) {
                    _synctex_error("Missing end of container.");
                    return SYNCTEX_STATUS_ERROR;
                }
                if ((parent = _synctex_tree_parent(form))) {
                    _synctex_tree_reset_parent(form);
                    child = form;
                    form = parent;
                    goto content_loop;
                } else if (sheet) {
                    form = NULL;
                    parent = sheet;
                    child = synctex_node_last_sibling(child);
                    goto content_loop;
                }
                goto main_loop;
            }
        }
        _synctex_error("Ignored record <%.20s...>(line %i)\n", SYNCTEX_CUR, scanner->reader->line_number + 1);
        if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
            _synctex_error("Missing end of sheet/form.");
            SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
        }
        goto content_loop;
    }
    zs = _synctex_buffer_get_available_size(scanner, 1);
    if (zs.size == 0) {
        _synctex_error("Uncomplete synctex file, postamble missing.");
        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
    }
    goto content_loop;
}
/**
 *  Replace ref in its tree hierarchy by a single box
 *  proxy to the contents of the associated form.
 *  - argument ref: a ref node with no friend
 *  - return the proxy created.
 *  - note: Does nothing if ref is not owned.
 *  - note: On return, ref will have no parent nor sibling.
 *      The caller is responsible for releasing ref.
 *  - note: this is where root proxies are created.
 *  - note: the target of the root proxy is the content
 *      of a form.
 */
SYNCTEX_INLINE static synctex_ns_s __synctex_replace_ref(synctex_node_p ref)
{
    synctex_ns_s ns = {NULL, SYNCTEX_STATUS_OK};
    synctex_node_p parent;
    if ((parent = _synctex_tree_parent(ref))) {
        synctex_node_p sibling = __synctex_tree_reset_sibling(ref);
        synctex_node_p arg_sibling = synctex_node_arg_sibling(ref);
        /*  arg_sibling != NULL because the child of a box
         *  is always a box boundary, not a ref. */
        synctex_node_p target = synctex_form_content(ref->class->scanner, _synctex_data_tag(ref));
        /*  The target is a single node (box)
         *  with children and no siblings. */
        if ((ns.node = __synctex_new_proxy_from_ref_to(ref, target))) {
            /*  Insert this proxy instead of ref. */
            _synctex_node_set_sibling(arg_sibling, ns.node);
            /*  Then append the original sibling of ref. */
            _synctex_node_set_sibling(ns.node, sibling);
#if defined(SYNCTEX_USE_CHARINDEX)
            if (synctex_node_type(sibling) == synctex_node_type_box_bdry) {
                /*  The sibling is the last box boundary
                 *  which may have a less accurate information */
                sibling->char_index = arg_sibling->char_index;
                sibling->line_index = arg_sibling->line_index;
            }
#endif
#if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500
            printf("!  Ref replacement:\n");
            synctex_node_log(ref);
            synctex_node_display(synctex_node_sibling(ref));
#endif
        } else /*  simply remove ref */ {
            _synctex_tree_set_sibling(arg_sibling, sibling);
        }
        __synctex_tree_reset_parent(ref);
    } else {
        _synctex_error(
            "!  Missing parent in __synctex_replace_ref. "
            "Please report.");
        ns.status = SYNCTEX_STATUS_BAD_ARGUMENT;
    }
    return ns;
}
/**
 *  - argument ref: is the starting point of a linked list
 *      of refs. The link is made through the friend field.
 *  - returns: the status and the list of all the proxies
 *      created. The link is made through the friend field.
 *  - note: All refs are freed
 */
SYNCTEX_INLINE static synctex_ns_s _synctex_post_process_ref(synctex_node_p ref)
{
    synctex_ns_s ns = {NULL, SYNCTEX_STATUS_OK};
    while (ref) {
        synctex_node_p next_ref = _synctex_tree_reset_friend(ref);
        synctex_ns_s sub_ns = __synctex_replace_ref(ref);
        if (sub_ns.status < ns.status) {
            ns.status = sub_ns.status;
        } else {
            /*  Insert all the created proxies in the list
             *  sub_ns.node is the last friend,
             */
            synctex_tree_set_friend(sub_ns.node, ns.node);
            ns.node = sub_ns.node;
        }
        synctex_node_free(ref);
        ref = next_ref;
    }
    return ns;
}
typedef synctex_node_p (*synctex_processor_f)(synctex_node_p node);
/**
 *  Apply the processor f to the tree hierarchy rooted at proxy.
 *  proxy has replaced a form ref, no children yet.
 *  As a side effect all the hierarchy of nodes will be created.
 */
SYNCTEX_INLINE static synctex_status_t _synctex_post_process_proxy(synctex_node_p proxy, synctex_processor_f f)
{
    while (proxy) {
        synctex_node_p next_proxy = _synctex_tree_friend(proxy);
        synctex_node_p halt = __synctex_tree_sibling(proxy);
        /*  if proxy is the last sibling, halt is NULL.
         *  Find what should be a next node,
         *  without creating new nodes. */
        if (!halt) {
            synctex_node_p parent = _synctex_tree_parent(proxy);
            halt = __synctex_tree_sibling(parent);
            while (!halt && parent) {
                parent = _synctex_tree_parent(parent);
                halt = __synctex_tree_sibling(parent);
            }
        }
        do {
#if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500
            printf("POST PROCESSING %s\n", _synctex_node_abstract(proxy));
            {
                int i, j = 0;
                for (i = 0; i < proxy->class->scanner->number_of_lists; ++i) {
                    synctex_node_p N = proxy->class->scanner->lists_of_friends[i];
                    do {
                        if (N == proxy) {
                            ++j;
                            printf("%s", _synctex_node_abstract(N));
                        }
                    } while ((N = _synctex_tree_friend(N)));
                }
                if (j) {
                    printf("\nBeforehand %i match\n", j);
                }
            }
#endif
            f(proxy);
#if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500
            {
                int i, j = 0;
                for (i = 0; i < proxy->class->scanner->number_of_lists; ++i) {
                    synctex_node_p N = proxy->class->scanner->lists_of_friends[i];
                    do {
                        if (N == proxy) {
                            ++j;
                            printf("%s", _synctex_node_abstract(N));
                        }
                    } while ((N = _synctex_tree_friend(N)));
                }
                if (j) {
                    printf("\n%i match\n", j);
                }
            }
#endif
            /*  Side effect: create the hierarchy on the fly */
            proxy = synctex_node_next(proxy); /*  Change is here */
#if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500
            if (proxy) {
                int i, j = 0;
                for (i = 0; i < proxy->class->scanner->number_of_lists; ++i) {
                    synctex_node_p N = proxy->class->scanner->lists_of_friends[i];
                    do {
                        if (N == proxy) {
                            ++j;
                            printf("%s", _synctex_node_abstract(N));
                        }
                    } while ((N = _synctex_tree_friend(N)));
                }
                if (j) {
                    printf("\nnext %i match\n", j);
                }
            }
#endif
        } while (proxy && proxy != halt);
        proxy = next_proxy;
    }
    return SYNCTEX_STATUS_OK;
}
/**
 *  Replace all the form refs by root box proxies.
 *  Create the node hierarchy and update the friends.
 *  On entry, the refs are collected as a friend list
 *  in either a form or a sheet
 *  - parameter: the owning scanner
 */
SYNCTEX_INLINE static synctex_status_t _synctex_post_process(synctex_scanner_p scanner)
{
    synctex_status_t status = SYNCTEX_STATUS_OK;
    synctex_ns_s ns = {NULL, SYNCTEX_STATUS_NOT_OK};
#if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500
    printf("!  entering _synctex_post_process.\n");
    synctex_node_display(scanner->sheet);
    synctex_node_display(scanner->form);
#endif
    /*  replace form refs inside forms by box proxies */
    ns = _synctex_post_process_ref(scanner->ref_in_form);
    scanner->ref_in_form = NULL; /*  it was just released */
    if (ns.status < status) {
        status = ns.status;
    }
#if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500
    printf("!  ref replaced in form _synctex_post_process.\n");
    synctex_node_display(scanner->form);
#endif
    /*  Create all the form proxy nodes on the fly.
     *  ns.node is the root of the list of
     *  newly created proxies.
     *  There might be a problem with cascading proxies.
     *  In order to be properly managed, the data must
     *  be organized in the right way.
     *  The inserted form must be defined before
     *  the inserting one. *TeX will take care of that.   */
    ns.status = _synctex_post_process_proxy(ns.node, &_synctex_tree_reset_friend);
    if (ns.status < status) {
        status = ns.status;
    }
    /*  replace form refs inside sheets by box proxies */
    ns = _synctex_post_process_ref(scanner->ref_in_sheet);
    if (ns.status < status) {
        status = ns.status;
    }
    scanner->ref_in_sheet = NULL;
#if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500
    printf("!  ref replaced in sheet _synctex_post_process.\n");
    synctex_node_display(scanner->sheet);
#endif

#if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 10000
    {
        int i;
        for (i = 0; i < scanner->number_of_lists; ++i) {
            synctex_node_p P = scanner->lists_of_friends[i];
            int j = 0;
            while (P) {
                ++j;
                synctex_node_log(P);
                P = _synctex_tree_friend(P);
            }
            if (j) {
                printf("friends %i -> # %i\n", i, j);
            }
        }
    }
#endif
    ns.status = _synctex_post_process_proxy(ns.node, &__synctex_proxy_make_friend_and_next_hbox);
    if (ns.status < status) {
        status = ns.status;
    }
#if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500
    printf("!  exiting _synctex_post_process.\n");
    synctex_node_display(scanner->sheet);
    synctex_node_display(scanner->form);
    printf("!  display all.\n");
    synctex_node_display(scanner->sheet);
    synctex_node_display(scanner->form);
#endif
    return status;
}
/*  Used when parsing the synctex file
 */
static synctex_status_t _synctex_scan_content(synctex_scanner_p scanner)
{
    scanner->reader->lastv = -1;
    synctex_status_t status = 0;
    if (NULL == scanner) {
        return SYNCTEX_STATUS_BAD_ARGUMENT;
    }
    /*  Find where this section starts */
content_not_found:
    status = _synctex_match_string(scanner, "Content:");
    if (status < SYNCTEX_STATUS_EOF) {
        return status;
    }
    if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) {
        _synctex_error("Uncomplete Content.");
        return SYNCTEX_STATUS_ERROR;
    }
    if (status == SYNCTEX_STATUS_NOT_OK) {
        goto content_not_found;
    }
    status = __synctex_parse_sfi(scanner);
    if (status == SYNCTEX_STATUS_OK) {
        status = _synctex_post_process(scanner);
    }
    return status;
}
synctex_scanner_p synctex_scanner_new()
{
    synctex_scanner_p scanner = (synctex_scanner_p)_synctex_malloc(sizeof(synctex_scanner_s));
    if (scanner) {
        if (!(scanner->reader = _synctex_malloc(sizeof(synctex_reader_s)))) {
            _synctex_free(scanner);
            return NULL;
        }
#ifdef SYNCTEX_NOTHING
#pragma mark -
#endif
#define DEFINE_synctex_scanner_class(NAME)                                                                                                                                                                                                     \
    scanner->class[synctex_node_type_##NAME] = synctex_class_##NAME;                                                                                                                                                                           \
    (scanner->class[synctex_node_type_##NAME]).scanner = scanner
        DEFINE_synctex_scanner_class(input);
        DEFINE_synctex_scanner_class(sheet);
        DEFINE_synctex_scanner_class(form);
        DEFINE_synctex_scanner_class(hbox);
        DEFINE_synctex_scanner_class(void_hbox);
        DEFINE_synctex_scanner_class(vbox);
        DEFINE_synctex_scanner_class(void_vbox);
        DEFINE_synctex_scanner_class(kern);
        DEFINE_synctex_scanner_class(glue);
        DEFINE_synctex_scanner_class(rule);
        DEFINE_synctex_scanner_class(math);
        DEFINE_synctex_scanner_class(boundary);
        DEFINE_synctex_scanner_class(box_bdry);
        DEFINE_synctex_scanner_class(ref);
        DEFINE_synctex_scanner_class(proxy_hbox);
        DEFINE_synctex_scanner_class(proxy_vbox);
        DEFINE_synctex_scanner_class(proxy);
        DEFINE_synctex_scanner_class(proxy_last);
        DEFINE_synctex_scanner_class(handle);
        /*  set up the lists of friends */
        scanner->number_of_lists = 1024;
        scanner->lists_of_friends = (synctex_node_r)_synctex_malloc(scanner->number_of_lists * sizeof(synctex_node_p));
        if (NULL == scanner->lists_of_friends) {
            synctex_scanner_free(scanner);
            _synctex_error("malloc:2");
            return NULL;
        }
        scanner->display_switcher = 100;
        scanner->display_prompt = (char *)_synctex_display_prompt + strlen(_synctex_display_prompt) - 1;
    }
    return scanner;
}
/*  Where the synctex scanner is created. */
synctex_scanner_p synctex_scanner_new_with_output_file(const char *output, const char *build_directory, int parse)
{
    synctex_scanner_p scanner = synctex_scanner_new();
    if (NULL == scanner) {
        _synctex_error("malloc problem");
        return NULL;
    }
    if ((scanner->reader = synctex_reader_init_with_output_file(scanner->reader, output, build_directory))) {
        return parse ? synctex_scanner_parse(scanner) : scanner;
    }
#if defined(SYNCTEX_DEBUG)
    _synctex_error("No file?");
#endif
    synctex_scanner_free(scanner);
    return NULL;
}

/*  The scanner destructor
 */
int synctex_scanner_free(synctex_scanner_p scanner)
{
    int node_count = 0;
    if (scanner) {
        if (scanner->reader && SYNCTEX_FILE) {
            gzclose(SYNCTEX_FILE);
            SYNCTEX_FILE = NULL;
        }
        synctex_node_free(scanner->sheet);
        synctex_node_free(scanner->form);
        synctex_node_free(scanner->input);
        synctex_reader_free(scanner->reader);
        SYNCTEX_SCANNER_FREE_HANDLE(scanner);
        synctex_iterator_free(scanner->iterator);
        free(scanner->output_fmt);
        free(scanner->lists_of_friends);
#if defined SYNCTEX_USE_NODE_COUNT && SYNCTEX_USE_NODE_COUNT > 0
        node_count = scanner->node_count;
#endif
        free(scanner);
    }
    return node_count;
}

/*  Where the synctex scanner parses the contents of the file. */
synctex_scanner_p synctex_scanner_parse(synctex_scanner_p scanner)
{
    synctex_status_t status = 0;
    if (!scanner || scanner->flags.has_parsed) {
        return scanner;
    }
    scanner->flags.has_parsed = 1;
    scanner->pre_magnification = 1000;
    scanner->pre_unit = 8192;
    scanner->pre_x_offset = scanner->pre_y_offset = 578;
    /*  initialize the offset with a fake unprobable value,
     *  If there is a post scriptum section, this value will be overridden by the real life value */
    scanner->x_offset = scanner->y_offset = 6.027e23f;
    scanner->reader->line_number = 1;

    /* TODO: cleanup
     * In some (all?) cases SYNCTEX_START is already initialized
     * in synctex_reader_init_with_output_file(). Much of the
     * following code seems like a duplicate and is perhaps a
     * candidate for deletion. To be on the safe side though, we
     * keep it for now and just free() any prior malloc() if
     * existing. */
    _synctex_free(SYNCTEX_START);

    SYNCTEX_START = (char *)malloc(SYNCTEX_BUFFER_SIZE + 1); /*  one more character for null termination */
    if (NULL == SYNCTEX_START) {
        _synctex_error("!  malloc error in synctex_scanner_parse.");
    bailey:
#ifdef SYNCTEX_DEBUG
        return scanner;
#else
        synctex_scanner_free(scanner);
        return NULL;
#endif
    }
    synctex_scanner_set_display_switcher(scanner, 1000);
    SYNCTEX_END = SYNCTEX_START + SYNCTEX_BUFFER_SIZE;
    /*  SYNCTEX_END always points to a null terminating character.
     *  Maybe there is another null terminating character between SYNCTEX_CUR and SYNCTEX_END-1.
     *  At least, we are sure that SYNCTEX_CUR points to a string covering a valid part of the memory. */
    *SYNCTEX_END = '\0';
    SYNCTEX_CUR = SYNCTEX_END;
#if defined(SYNCTEX_USE_CHARINDEX)
    scanner->reader->charindex_offset = -SYNCTEX_BUFFER_SIZE;
#endif
    status = _synctex_scan_preamble(scanner);
    if (status < SYNCTEX_STATUS_OK) {
        _synctex_error("Bad preamble\n");
        goto bailey;
    }
    status = _synctex_scan_content(scanner);
    if (status < SYNCTEX_STATUS_OK) {
        _synctex_error("Bad content\n");
        goto bailey;
    }
    status = _synctex_scan_postamble(scanner);
    if (status < SYNCTEX_STATUS_OK) {
        _synctex_error("Bad postamble. Ignored\n");
    }
#if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500
    synctex_scanner_set_display_switcher(scanner, 100);
    synctex_node_display(scanner->sheet);
    synctex_node_display(scanner->form);
#endif
    synctex_scanner_set_display_switcher(scanner, 1000);
    /*  Everything is finished, free the buffer, close the file */
    free((void *)SYNCTEX_START);
    SYNCTEX_START = SYNCTEX_CUR = SYNCTEX_END = NULL;
    gzclose(SYNCTEX_FILE);
    SYNCTEX_FILE = NULL;
    /*  Final tuning: set the default values for various parameters */
    /*  1 pre_unit = (scanner->pre_unit)/65536 pt = (scanner->pre_unit)/65781.76 bp
     * 1 pt = 65536 sp */
    if (scanner->pre_unit <= 0) {
        scanner->pre_unit = 8192;
    }
    if (scanner->pre_magnification <= 0) {
        scanner->pre_magnification = 1000;
    }
    if (scanner->unit <= 0) {
        /*  no post magnification */
        scanner->unit = scanner->pre_unit / 65781.76; /*  65781.76 or 65536.0*/
    } else {
        /*  post magnification */
        scanner->unit *= scanner->pre_unit / 65781.76;
    }
    scanner->unit *= scanner->pre_magnification / 1000.0;
    if (scanner->x_offset > 6e23) {
        /*  no post offset */
        scanner->x_offset = scanner->pre_x_offset * (scanner->pre_unit / 65781.76);
        scanner->y_offset = scanner->pre_y_offset * (scanner->pre_unit / 65781.76);
    } else {
        /*  post offset */
        scanner->x_offset /= 65781.76f;
        scanner->y_offset /= 65781.76f;
    }
    return scanner;
#undef SYNCTEX_FILE
}

/*  Scanner accessors.
 */
int synctex_scanner_pre_x_offset(synctex_scanner_p scanner)
{
    return scanner ? scanner->pre_x_offset : 0;
}
int synctex_scanner_pre_y_offset(synctex_scanner_p scanner)
{
    return scanner ? scanner->pre_y_offset : 0;
}
int synctex_scanner_x_offset(synctex_scanner_p scanner)
{
    return scanner ? scanner->x_offset : 0;
}
int synctex_scanner_y_offset(synctex_scanner_p scanner)
{
    return scanner ? scanner->y_offset : 0;
}
float synctex_scanner_magnification(synctex_scanner_p scanner)
{
    return scanner ? scanner->unit : 1;
}
void synctex_scanner_display(synctex_scanner_p scanner)
{
    if (NULL == scanner) {
        return;
    }
    printf("The scanner:\noutput:%s\noutput_fmt:%s\nversion:%i\n", scanner->reader->output, scanner->output_fmt, scanner->version);
    printf("pre_unit:%i\nx_offset:%i\ny_offset:%i\n", scanner->pre_unit, scanner->pre_x_offset, scanner->pre_y_offset);
    printf("count:%i\npost_magnification:%f\npost_x_offset:%f\npost_y_offset:%f\n", scanner->count, scanner->unit, scanner->x_offset, scanner->y_offset);
    printf("The input:\n");
    synctex_node_display(scanner->input);
    if (scanner->count < 1000) {
        printf("The sheets:\n");
        synctex_node_display(scanner->sheet);
        printf("The friends:\n");
        if (scanner->lists_of_friends) {
            int i = scanner->number_of_lists;
            synctex_node_p node;
            while (i--) {
                printf("Friend index:%i\n", i);
                node = (scanner->lists_of_friends)[i];
                while (node) {
                    printf("%s:%i,%i\n", synctex_node_isa(node), _synctex_data_tag(node), _synctex_data_line(node));
                    node = _synctex_tree_friend(node);
                }
            }
        }
    } else {
        printf("SyncTeX Warning: Too many objects\n");
    }
}
/*  Public */
const char *synctex_scanner_get_name(synctex_scanner_p scanner, int tag)
{
    synctex_node_p input = NULL;
    if (NULL == scanner) {
        return NULL;
    }
    if ((input = scanner->input)) {
        ;
        do {
            if (tag == _synctex_data_tag(input)) {
                return (_synctex_data_name(input));
            }
        } while ((input = __synctex_tree_sibling(input)));
    }
    return NULL;
}
const char *synctex_node_get_name(synctex_node_p node)
{
    if (node) {
        return synctex_scanner_get_name(node->class->scanner, _synctex_data_tag(node));
    }
    return NULL;
}

static int _synctex_scanner_get_tag(synctex_scanner_p scanner, const char *name);
static int _synctex_scanner_get_tag(synctex_scanner_p scanner, const char *name)
{
    synctex_node_p input = NULL;
    if (NULL == scanner) {
        return 0;
    }
    if ((input = scanner->input)) {
        do {
            if (_synctex_is_equivalent_file_name(name, (_synctex_data_name(input)))) {
                return _synctex_data_tag(input);
            }
        } while ((input = __synctex_tree_sibling(input)));
    }
    /* 2011 version */
    name = _synctex_base_name(name);
    if ((input = scanner->input)) {
        do {
            if (_synctex_is_equivalent_file_name(name, _synctex_base_name(_synctex_data_name(input)))) {
                synctex_node_p other_input = input;
                while ((other_input = __synctex_tree_sibling(other_input))) {
                    if (_synctex_is_equivalent_file_name(name, _synctex_base_name(_synctex_data_name(other_input))) &&
                        (strlen(_synctex_data_name(input)) != strlen(_synctex_data_name(other_input)) || strncmp(_synctex_data_name(other_input), _synctex_data_name(input), strlen(_synctex_data_name(input))))) {
                        /* There is a second possible candidate */
                        return 0;
                    }
                }
                return _synctex_data_tag(input);
            }
        } while ((input = __synctex_tree_sibling(input)));
    }
    return 0;
}

int synctex_scanner_get_tag(synctex_scanner_p scanner, const char *name)
{
    size_t char_index = strlen(name);
    if ((scanner = synctex_scanner_parse(scanner)) && (0 < char_index)) {
        /*  the name is not void */
        char_index -= 1;
        if (!SYNCTEX_IS_PATH_SEPARATOR(name[char_index])) {
            /*  the last character of name is not a path separator */
            int result = _synctex_scanner_get_tag(scanner, name);
            if (result) {
                return result;
            } else {
                /*  the given name was not the one known by TeX
                 *  try a name relative to the enclosing directory of the scanner->output file */
                const char *relative = name;
                const char *ptr = scanner->reader->output;
                while ((strlen(relative) > 0) && (strlen(ptr) > 0) && (*relative == *ptr)) {
                    relative += 1;
                    ptr += 1;
                }
                /*  Find the last path separator before relative */
                while (relative > name) {
                    if (SYNCTEX_IS_PATH_SEPARATOR(*(relative - 1))) {
                        break;
                    }
                    relative -= 1;
                }
                if ((relative > name) && (result = _synctex_scanner_get_tag(scanner, relative))) {
                    return result;
                }
                if (SYNCTEX_IS_PATH_SEPARATOR(name[0])) {
                    /*  No tag found for the given absolute name,
                     *  Try each relative path starting from the shortest one */
                    while (0 < char_index) {
                        char_index -= 1;
                        if (SYNCTEX_IS_PATH_SEPARATOR(name[char_index]) && (result = _synctex_scanner_get_tag(scanner, name + char_index + 1))) {
                            return result;
                        }
                    }
                }
            }
            return result;
        }
    }
    return 0;
}
synctex_node_p synctex_scanner_input(synctex_scanner_p scanner)
{
    return scanner ? scanner->input : NULL;
}
synctex_node_p synctex_scanner_input_with_tag(synctex_scanner_p scanner, int tag)
{
    synctex_node_p input = scanner ? scanner->input : NULL;
    while (_synctex_data_tag(input) != tag) {
        if ((input = __synctex_tree_sibling(input))) {
            continue;
        }
        break;
    }
    return input;
}
const char *synctex_scanner_get_output_fmt(synctex_scanner_p scanner)
{
    return NULL != scanner && scanner->output_fmt ? scanner->output_fmt : "";
}
const char *synctex_scanner_get_output(synctex_scanner_p scanner)
{
    return NULL != scanner && scanner->reader->output ? scanner->reader->output : "";
}
const char *synctex_scanner_get_synctex(synctex_scanner_p scanner)
{
    return NULL != scanner && scanner->reader->synctex ? scanner->reader->synctex : "";
}
#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark Public node attributes
#endif

#define SYNCTEX_DEFINE_NODE_HVWHD(WHAT)                                                                                                                                                                                                        \
    int synctex_node_##WHAT(synctex_node_p node)                                                                                                                                                                                               \
    {                                                                                                                                                                                                                                          \
        return (node && node->class->inspector->WHAT) ? node->class->inspector->WHAT(node) : 0;                                                                                                                                                \
    }
#define SYNCTEX_DEFINE_PROXY_HV(WHAT)                                                                                                                                                                                                          \
    static int _synctex_proxy_##WHAT(synctex_proxy_p proxy)                                                                                                                                                                                    \
    {                                                                                                                                                                                                                                          \
        synctex_node_p target = _synctex_tree_target(proxy);                                                                                                                                                                                   \
        if (target) {                                                                                                                                                                                                                          \
            return _synctex_data_##WHAT(proxy) + synctex_node_##WHAT(target);                                                                                                                                                                  \
        } else {                                                                                                                                                                                                                               \
            return proxy ? _synctex_data_##WHAT(proxy) : 0;                                                                                                                                                                                    \
        }                                                                                                                                                                                                                                      \
    }
#define SYNCTEX_DEFINE_PROXY_TLCWVD(WHAT)                                                                                                                                                                                                      \
    static int _synctex_proxy_##WHAT(synctex_proxy_p proxy)                                                                                                                                                                                    \
    {                                                                                                                                                                                                                                          \
        synctex_node_p target = _synctex_tree_target(proxy);                                                                                                                                                                                   \
        return target ? synctex_node_##WHAT(target) : 0;                                                                                                                                                                                       \
    }

/**
 *  The horizontal location of the node.
 *  Idem for v, width, height and depth.
 *  - parameter node: a node with geometrical information.
 *  - returns: an integer.
 *  - requires: every proxy node has a target.
 *  - note: recursive call if the parameter has a proxy.
 *  - author: JL
 */
SYNCTEX_DEFINE_NODE_HVWHD(h)
SYNCTEX_DEFINE_NODE_HVWHD(v)
SYNCTEX_DEFINE_NODE_HVWHD(width)
SYNCTEX_DEFINE_NODE_HVWHD(height)
SYNCTEX_DEFINE_NODE_HVWHD(depth)
SYNCTEX_DEFINE_PROXY_TLCWVD(tag)
SYNCTEX_DEFINE_PROXY_TLCWVD(line)
SYNCTEX_DEFINE_PROXY_TLCWVD(column)
SYNCTEX_DEFINE_PROXY_HV(h)
SYNCTEX_DEFINE_PROXY_HV(v)
SYNCTEX_DEFINE_PROXY_TLCWVD(width)
SYNCTEX_DEFINE_PROXY_TLCWVD(height)
SYNCTEX_DEFINE_PROXY_TLCWVD(depth)

/**
 *  Whether the argument is a box,
 *  either vertical or horizontal,
 *  either void or not,
 *  or a proxy to such a box.
 *  - parameter NODE: of type synctex_node_p
 *  - returns: yorn
 */

SYNCTEX_INLINE static synctex_bool_t _synctex_node_is_box(synctex_node_p node)
{
    return node &&
        (node->class->type == synctex_node_type_hbox || node->class->type == synctex_node_type_void_hbox || node->class->type == synctex_node_type_vbox || node->class->type == synctex_node_type_void_vbox ||
         _synctex_node_is_box(_synctex_tree_target(node)));
}

/**
 *  Whether the argument is a handle.
 *  Handles are similar to proxies because they have a target.
 *  They are used for query results.
 *  - parameter NODE: of type synctex_node_p
 *  - returns: yorn
 */

SYNCTEX_INLINE static synctex_bool_t _synctex_node_is_handle(synctex_node_p node)
{
    return node && (node->class->type == synctex_node_type_handle);
}

/**
 *  Resolves handle indirection.
 *  - parameter node: of type synctex_node_p
 *  - returns: node if it is not a handle,
 *  its target otherwise.
 */

SYNCTEX_INLINE static synctex_node_p _synctex_node_or_handle_target(synctex_node_p node)
{
    return _synctex_node_is_handle(node) ? _synctex_tree_target(node) : node;
}

/**
 *  Whether the argument is an hbox.
 *  - parameter NODE: of type synctex_node_p
 *  - returns: yorn
 */

SYNCTEX_INLINE static synctex_bool_t _synctex_node_is_hbox(synctex_node_p node)
{
    return node && (node->class->type == synctex_node_type_hbox || node->class->type == synctex_node_type_void_hbox || _synctex_node_is_hbox(_synctex_tree_target(node)));
}

/**
 *  The horizontal location of the first box enclosing node.
 *  - parameter node: a node with geometrical information.
 *  - returns: an integer.
 *  - author: JL
 */
int synctex_node_box_h(synctex_node_p node)
{
    if (_synctex_node_is_box(node) || (node = _synctex_tree_parent(node))) {
        return synctex_node_h(node);
    }
    return 0;
}
/**
 *  The vertical location of the first box enclosing node.
 *  - parameter node: a node with geometrical information.
 *  - returns: an integer.
 *  - author: JL
 */
int synctex_node_box_v(synctex_node_p node)
{
    if (_synctex_node_is_box(node) || (node = _synctex_tree_parent(node))) {
        return synctex_node_v(node);
    }
    return 0;
}
/**
 *  The width of the first box enclosing node.
 *  - parameter node: a node with geometrical information.
 *  - returns: an integer.
 *  - author: JL
 */
int synctex_node_box_width(synctex_node_p node)
{
    if (_synctex_node_is_box(node) || (node = _synctex_tree_parent(node))) {
        return synctex_node_width(node);
    }
    return 0;
}
/**
 *  The height of the first box enclosing node.
 *  - parameter node: a node with geometrical information.
 *  - returns: an integer.
 *  - author: JL
 */
int synctex_node_box_height(synctex_node_p node)
{
    if (_synctex_node_is_box(node) || (node = _synctex_tree_parent(node))) {
        return synctex_node_height(node);
    }
    return 0;
}
/**
 *  The depth of the first box enclosing node.
 *  - parameter node: a node with geometrical information.
 *  - returns: an integer.
 *  - author: JL
 */
int synctex_node_box_depth(synctex_node_p node)
{
    if (_synctex_node_is_box(node) || (node = _synctex_tree_parent(node))) {
        return synctex_node_depth(node);
    }
    return 0;
}
/**
 *  The horizontal location of an hbox, corrected with contents.
 *  - parameter node: an hbox node.
 *  - returns: an integer, 0 if node is not an hbox or an hbox proxy.
 *  - note: recursive call when node is an hbox proxy.
 *  - author: JL
 */
int synctex_node_hbox_h(synctex_node_p node)
{
    switch (synctex_node_type(node)) {
    case synctex_node_type_hbox:
        return _synctex_data_h_V(node);
    case synctex_node_type_proxy_hbox:
        return _synctex_data_h(node) + synctex_node_hbox_h(_synctex_tree_target(node));
    default:
        return 0;
    }
}
/**
 *  The vertical location of an hbox, corrected with contents.
 *  - parameter node: an hbox node.
 *  - returns: an integer, 0 if node is not an hbox or an hbox proxy.
 *  - note: recursive call when node is an hbox proxy.
 *  - author: JL
 */
int synctex_node_hbox_v(synctex_node_p node)
{
    switch (synctex_node_type(node)) {
    case synctex_node_type_hbox:
        return _synctex_data_v_V(node);
    case synctex_node_type_proxy_hbox:
        return _synctex_data_v(node) + synctex_node_hbox_v(_synctex_tree_target(node));
    default:
        return 0;
    }
}
/**
 *  The width of an hbox, corrected with contents.
 *  - parameter node: an hbox node, 0 if node is not an hbox or an hbox proxy.
 *  - returns: an integer.
 *  - author: JL
 */
int synctex_node_hbox_width(synctex_node_p node)
{
    synctex_node_p target = _synctex_tree_target(node);
    if (target) {
        node = target;
    }
    return synctex_node_type(node) == synctex_node_type_hbox ? _synctex_data_width_V(node) : 0;
}
/**
 *  The height of an hbox, corrected with contents.
 *  - parameter node: an hbox node.
 *  - returns: an integer, 0 if node is not an hbox or an hbox proxy.
 *  - author: JL
 */
int synctex_node_hbox_height(synctex_node_p node)
{
    synctex_node_p target = _synctex_tree_target(node);
    if (target) {
        node = target;
    }
    return synctex_node_type(node) == synctex_node_type_hbox ? _synctex_data_height_V(node) : 0;
}
/**
 *  The depth of an hbox, corrected with contents.
 *  - parameter node: an hbox node.
 *  - returns: an integer, 0 if node is not an hbox or an hbox proxy.
 *  - note: recursive call when node is an hbox proxy.
 *  - author: JL
 */
int synctex_node_hbox_depth(synctex_node_p node)
{
    synctex_node_p target = _synctex_tree_target(node);
    if (target) {
        node = target;
    }
    return synctex_node_type(node) == synctex_node_type_hbox ? _synctex_data_depth_V(node) : 0;
}
#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark Public node visible attributes
#endif

#define SYNCTEX_VISIBLE_SIZE(node, s) (s) * node->class->scanner->unit
#define SYNCTEX_VISIBLE_DISTANCE_h(node, d) ((d) * node->class->scanner->unit + node->class->scanner->x_offset)
#define SYNCTEX_VISIBLE_DISTANCE_v(node, d) ((d) * node->class->scanner->unit + node->class->scanner->y_offset)
static float __synctex_node_visible_h(synctex_node_p node)
{
    return SYNCTEX_VISIBLE_DISTANCE_h(node, synctex_node_h(node));
}
static float __synctex_node_visible_v(synctex_node_p node)
{
    return SYNCTEX_VISIBLE_DISTANCE_v(node, synctex_node_v(node));
}
static float __synctex_node_visible_width(synctex_node_p node)
{
    return SYNCTEX_VISIBLE_SIZE(node, synctex_node_width(node));
}
static float __synctex_node_visible_height(synctex_node_p node)
{
    return SYNCTEX_VISIBLE_SIZE(node, synctex_node_height(node));
}
static float __synctex_node_visible_depth(synctex_node_p node)
{
    return SYNCTEX_VISIBLE_SIZE(node, synctex_node_depth(node));
}
static float __synctex_proxy_visible_h(synctex_node_p node)
{
    return SYNCTEX_VISIBLE_DISTANCE_h(node, synctex_node_h(node));
}
static float __synctex_proxy_visible_v(synctex_node_p node)
{
    return SYNCTEX_VISIBLE_DISTANCE_v(node, synctex_node_v(node));
}
static float __synctex_proxy_visible_width(synctex_node_p node)
{
    synctex_node_p target = _synctex_tree_target(node);
    return __synctex_node_visible_width(target);
}
static float __synctex_proxy_visible_height(synctex_node_p node)
{
    synctex_node_p target = _synctex_tree_target(node);
    return __synctex_node_visible_height(target);
}
static float __synctex_proxy_visible_depth(synctex_node_p node)
{
    synctex_node_p target = _synctex_tree_target(node);
    return __synctex_node_visible_depth(target);
}
static float __synctex_kern_visible_h(synctex_noxy_p noxy)
{
    int h = _synctex_data_h(noxy);
    int width = _synctex_data_width(noxy);
    return SYNCTEX_VISIBLE_DISTANCE_h(noxy, width > 0 ? h - width : h);
}
static float __synctex_kern_visible_width(synctex_noxy_p noxy)
{
    int width = _synctex_data_width(noxy);
    return SYNCTEX_VISIBLE_SIZE(noxy, width > 0 ? width : -width);
}
static float __synctex_rule_visible_h(synctex_noxy_p noxy)
{
    int h = _synctex_data_h(noxy);
    int width = _synctex_data_width(noxy);
    return SYNCTEX_VISIBLE_DISTANCE_h(noxy, width > 0 ? h : h - width);
}
static float __synctex_rule_visible_width(synctex_noxy_p noxy)
{
    int width = _synctex_data_width(noxy);
    return SYNCTEX_VISIBLE_SIZE(noxy, width > 0 ? width : -width);
}
static float __synctex_rule_visible_v(synctex_noxy_p noxy)
{
    return __synctex_node_visible_v(noxy);
}
static float __synctex_rule_visible_height(synctex_noxy_p noxy)
{
    return __synctex_node_visible_height(noxy);
}
static float __synctex_rule_visible_depth(synctex_noxy_p noxy)
{
    return __synctex_node_visible_depth(noxy);
}

/**
 *  The horizontal location of node, in page coordinates.
 *  - parameter node: a node.
 *  - returns: a float.
 *  - author: JL
 */
float synctex_node_visible_h(synctex_node_p node)
{
    return node ? node->class->vispector->h(node) : 0;
}
/**
 *  The vertical location of node, in page coordinates.
 *  - parameter node: a node.
 *  - returns: a float.
 *  - author: JL
 */
float synctex_node_visible_v(synctex_node_p node)
{
    return node ? node->class->vispector->v(node) : 0;
}
/**
 *  The width of node, in page coordinates.
 *  - parameter node: a node.
 *  - returns: a float.
 *  - author: JL
 */
float synctex_node_visible_width(synctex_node_p node)
{
    return node ? node->class->vispector->width(node) : 0;
}
/**
 *  The height of node, in page coordinates.
 *  - parameter node: a node.
 *  - returns: a float.
 *  - author: JL
 */
float synctex_node_visible_height(synctex_node_p node)
{
    return node ? node->class->vispector->height(node) : 0;
}
/**
 *  The depth of node, in page coordinates.
 *  - parameter node: a node.
 *  - returns: a float.
 *  - author: JL
 */
float synctex_node_visible_depth(synctex_node_p node)
{
    return node ? node->class->vispector->depth(node) : 0;
}

/**
 *  The V variant of geometrical information.
 *  - parameter node: a node.
 *  - returns: an integer.
 *  - author: JL
 */
#define SYNCTEX_DEFINE_V(WHAT)                                                                                                                                                                                                                 \
    SYNCTEX_INLINE static int _synctex_node_##WHAT##_V(synctex_node_p node)                                                                                                                                                                    \
    {                                                                                                                                                                                                                                          \
        synctex_node_p target = _synctex_tree_target(node);                                                                                                                                                                                    \
        if (target) {                                                                                                                                                                                                                          \
            return _synctex_data_##WHAT(node) + _synctex_node_##WHAT##_V(target);                                                                                                                                                              \
        } else if (_synctex_data_has_##WHAT##_V(node)) {                                                                                                                                                                                       \
            return _synctex_data_##WHAT##_V(node);                                                                                                                                                                                             \
        } else {                                                                                                                                                                                                                               \
            return _synctex_data_##WHAT(node);                                                                                                                                                                                                 \
        }                                                                                                                                                                                                                                      \
    }
SYNCTEX_DEFINE_V(h)
SYNCTEX_DEFINE_V(v)
SYNCTEX_DEFINE_V(width)
SYNCTEX_DEFINE_V(height)
SYNCTEX_DEFINE_V(depth)

SYNCTEX_INLINE static synctex_point_s _synctex_data_point(synctex_node_p node)
{
    return (synctex_point_s) {synctex_node_h(node), synctex_node_v(node)};
}
SYNCTEX_INLINE static synctex_point_s _synctex_data_point_V(synctex_node_p node)
{
    return (synctex_point_s) {_synctex_node_h_V(node), _synctex_node_v_V(node)};
}
SYNCTEX_INLINE static synctex_point_s _synctex_data_set_point(synctex_node_p node, synctex_point_s point)
{
    synctex_point_s old = _synctex_data_point(node);
    _synctex_data_set_h(node, point.h);
    _synctex_data_set_v(node, point.v);
    return old;
}
SYNCTEX_INLINE static synctex_box_s _synctex_data_box(synctex_node_p node)
{
    synctex_box_s box = {{0, 0}, {0, 0}};
    int n;
    n = synctex_node_width(node);
    if (n < 0) {
        box.max.h = synctex_node_h(node);
        box.min.h = box.max.h + n;
    } else {
        box.min.h = synctex_node_h(node);
        box.max.h = box.min.h + n;
    }
    n = synctex_node_v(node);
    box.min.v = n - synctex_node_height(node);
    box.max.v = n + synctex_node_depth(node);
    return box;
}
SYNCTEX_INLINE static synctex_box_s _synctex_data_xob(synctex_node_p node)
{
    synctex_box_s box = {{0, 0}, {0, 0}};
    int n;
    n = synctex_node_width(node);
    if (n > 0) {
        box.max.h = synctex_node_h(node);
        box.min.h = box.max.h - n;
    } else {
        box.min.h = synctex_node_h(node);
        box.max.h = box.min.h - n;
    }
    n = synctex_node_v(node);
    box.min.v = n - synctex_node_height(node);
    box.max.v = n + synctex_node_depth(node);
    return box;
}
SYNCTEX_INLINE static synctex_box_s _synctex_data_box_V(synctex_node_p node)
{
    synctex_box_s box = {{0, 0}, {0, 0}};
    int n;
    n = _synctex_node_width_V(node);
    if (n < 0) {
        box.max.h = _synctex_node_h_V(node);
        box.min.h = box.max.h + n;
    } else {
        box.min.h = _synctex_node_h_V(node);
        box.max.h = box.min.h + n;
    }
    n = _synctex_node_v_V(node);
    box.min.v = n - _synctex_node_height_V(node);
    box.max.v = n + _synctex_node_depth_V(node);
    return box;
}

/**
 *  The higher box node in the parent hierarchy which
 *  mean line number is the one of node ±1.
 *  This enclosing box is computed as follows
 *  1) get the first hbox in the parent linked list
 *  starting at node.
 *  If there is none, simply return the parent of node.
 *  2) compute the mean line number
 *  3) scans up the tree for the higher hbox with
 *  the same mean line number, ±1 eventually
 *  - parameter node: a node.
 *  - returns: a (proxy to a) box node.
 *  - author: JL
 */
static synctex_node_p _synctex_node_box_visible(synctex_node_p node)
{
    if ((node = _synctex_node_or_handle_target(node))) {
        int mean = 0;
        int bound = 1500000 / (node->class->scanner->pre_magnification / 1000);
        synctex_node_p parent = NULL;
        /*  get the first enclosing parent
         *  then get the highest enclosing parent with the same mean line ±1 */
        node = _synctex_node_or_handle_target(node);
        if (!_synctex_node_is_box(node)) {
            if ((parent = _synctex_tree_parent(node))) {
                node = parent;
            } else if ((node = _synctex_tree_target(node))) {
                if (!_synctex_node_is_box(node)) {
                    if ((parent = _synctex_tree_parent(node))) {
                        node = parent;
                    } else {
                        return NULL;
                    }
                }
            }
        }
        parent = node;
        mean = synctex_node_mean_line(node);
        while ((parent = _synctex_tree_parent(parent))) {
            if (_synctex_node_is_hbox(parent)) {
                if (_synctex_abs(mean - synctex_node_mean_line(parent)) > 1) {
                    return node;
                } else if (synctex_node_width(parent) > bound) {
                    return parent;
                } else if (synctex_node_height(parent) + synctex_node_depth(parent) > bound) {
                    return parent;
                }
                node = parent;
            }
        }
    }
    return node;
}
/**
 *  The horizontal location of the first box enclosing node, in page coordinates.
 *  - parameter node: a node.
 *  - returns: a float.
 *  - author: JL
 */
float synctex_node_box_visible_h(synctex_node_p node)
{
    return SYNCTEX_VISIBLE_DISTANCE_h(node, _synctex_node_h_V(_synctex_node_box_visible(node)));
}
/**
 *  The vertical location of the first box enclosing node, in page coordinates.
 *  - parameter node: a node.
 *  - returns: a float.
 *  - author: JL
 */
float synctex_node_box_visible_v(synctex_node_p node)
{
    return SYNCTEX_VISIBLE_DISTANCE_v(node, _synctex_node_v_V(_synctex_node_box_visible(node)));
}
/**
 *  The width of the first box enclosing node, in page coordinates.
 *  - parameter node: a node.
 *  - returns: a float.
 *  - author: JL
 */
float synctex_node_box_visible_width(synctex_node_p node)
{
    return SYNCTEX_VISIBLE_SIZE(node, _synctex_node_width_V(_synctex_node_box_visible(node)));
}
/**
 *  The height of the first box enclosing node, in page coordinates.
 *  - parameter node: a node.
 *  - returns: a float.
 *  - author: JL
 */
float synctex_node_box_visible_height(synctex_node_p node)
{
    return SYNCTEX_VISIBLE_SIZE(node, _synctex_node_height_V(_synctex_node_box_visible(node)));
}
/**
 *  The depth of the first box enclosing node, in page coordinates.
 *  - parameter node: a node.
 *  - returns: a float.
 *  - author: JL
 */
float synctex_node_box_visible_depth(synctex_node_p node)
{
    return SYNCTEX_VISIBLE_SIZE(node, _synctex_node_depth_V(_synctex_node_box_visible(node)));
}
#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark Other public node attributes
#endif

/**
 *  The page number of the sheet enclosing node.
 *  - parameter node: a node.
 *  - returns: the page number or -1 if node does not belong to a sheet tree.
 *  - note: a proxy target does not belong to a sheet
 *      but a form, its page number is always -1.
 *  - note: a handles does not belong to a sheet not a form.
 *      its page number is -1.
 *  - author: JL
 */
int synctex_node_page(synctex_node_p node)
{
    synctex_node_p parent = NULL;
    while ((parent = _synctex_tree_parent(node))) {
        node = parent;
    }
    if (synctex_node_type(node) == synctex_node_type_sheet) {
        return _synctex_data_page(node);
    }
    return -1;
}
/**
 *  The page number of the target.
 *  - author: JL
 */
SYNCTEX_INLINE static int _synctex_node_target_page(synctex_node_p node)
{
    return synctex_node_page(_synctex_tree_target(node));
}

#if defined(SYNCTEX_USE_CHARINDEX)
synctex_charindex_t synctex_node_charindex(synctex_node_p node)
{
    synctex_node_p target = _synctex_tree_target(node);
    return target ? SYNCTEX_CHARINDEX(target) : (node ? SYNCTEX_CHARINDEX(node) : 0);
}
#endif

/**
 *  The tag of the node.
 *  - parameter node: a node.
 *  - returns: the tag or -1 if node is NULL.
 *  - author: JL
 */
int synctex_node_tag(synctex_node_p node)
{
    return node ? node->class->tlcpector->tag(node) : -1;
}
/**
 *  The line of the node.
 *  - parameter node: a node.
 *  - returns: the line or -1 if node is NULL.
 *  - author: JL
 */
int synctex_node_line(synctex_node_p node)
{
    return node ? node->class->tlcpector->line(node) : -1;
}
/**
 *  The column of the node.
 *  - parameter node: a node.
 *  - returns: the column or -1 if node is NULL.
 *  - author: JL
 */
int synctex_node_column(synctex_node_p node)
{
    return node ? node->class->tlcpector->column(node) : -1;
}
/**
 *  The mean line number of the node.
 *  - parameter node: a node.
 *  - returns: the mean line or -1 if node is NULL.
 *  - author: JL
 */
int synctex_node_mean_line(synctex_node_p node)
{
    synctex_node_p target = _synctex_tree_target(node);
    if (target) {
        node = target;
    }
    return _synctex_data_has_mean_line(node) ? _synctex_data_mean_line(node) : _synctex_data_line(node);
}
/**
 *  The weight of the node.
 *  - parameter node: a node.
 *  - returns: the weight or -1 if node is NULL.
 *  - author: JL
 */
int synctex_node_weight(synctex_node_p node)
{
    synctex_node_p target = _synctex_tree_target(node);
    if (target) {
        node = target;
    }
    return node ? (synctex_node_type(node) == synctex_node_type_hbox ? _synctex_data_weight(node) : 0) : -1;
}
/**
 *  The number of children of the node.
 *  - parameter node: a node.
 *  - returns: the count or -1 if node is NULL.
 *  - author: JL
 */
int synctex_node_child_count(synctex_node_p node)
{
    synctex_node_p target = _synctex_tree_target(node);
    if (target) {
        node = target;
    }
    return node ? (synctex_node_type(node) == synctex_node_type_hbox ? _synctex_data_weight(node) : 0) : -1;
}
#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark Sheet & Form
#endif

/**
 *  The sheet of the scanner with a given page number.
 *  - parameter scanner: a scanner.
 *  - parameter page: a 1 based page number.
 *      If page == 0, returns the first sheet.
 *  - returns: a sheet or NULL.
 *  - author: JL
 */
synctex_node_p synctex_sheet(synctex_scanner_p scanner, int page)
{
    if (scanner) {
        synctex_node_p sheet = scanner->sheet;
        while (sheet) {
            if (page == _synctex_data_page(sheet)) {
                return sheet;
            }
            sheet = __synctex_tree_sibling(sheet);
        }
        if (page == 0) {
            return scanner->sheet;
        }
    }
    return NULL;
}
/**
 *  The form of the scanner with a given tag.
 *  - parameter scanner: a scanner.
 *  - parameter tag: an integer identifier.
 *      If tag == 0, returns the first form.
 *  - returns: a form.
 *  - author: JL
 */
synctex_node_p synctex_form(synctex_scanner_p scanner, int tag)
{
    if (scanner) {
        synctex_node_p form = scanner->form;
        while (form) {
            if (tag == _synctex_data_tag(form)) {
                return form;
            }
            form = __synctex_tree_sibling(form);
        }
        if (tag == 0) {
            return scanner->form;
        }
    }
    return NULL;
}

/**
 *  The content of the sheet with given page number.
 *  - parameter scanner: a scanner.
 *  - parameter page: a 1 based page number.
 *  - returns: a (vertical) box node.
 *  - author: JL
 */
synctex_node_p synctex_sheet_content(synctex_scanner_p scanner, int page)
{
    if (scanner) {
        return _synctex_tree_child(synctex_sheet(scanner, page));
    }
    return NULL;
}

/**
 *  The content of the sheet with given page number.
 *  - parameter scanner: a scanner.
 *  - parameter tag: an integer identifier.
 *  - returns: a box node.
 *  - author: JL
 */
synctex_node_p synctex_form_content(synctex_scanner_p scanner, int tag)
{
    if (scanner) {
        return _synctex_tree_child(synctex_form(scanner, tag));
    }
    return NULL;
}

SYNCTEX_INLINE static synctex_node_p _synctex_scanner_friend(synctex_scanner_p scanner, int i)
{
    if (i >= 0) {
        i = _synctex_abs(i) % (scanner->number_of_lists);
        return (scanner->lists_of_friends)[i];
    }
    return NULL;
}
SYNCTEX_INLINE static synctex_bool_t _synctex_nodes_are_friend(synctex_node_p left, synctex_node_p right)
{
    return synctex_node_tag(left) == synctex_node_tag(right) && synctex_node_line(left) == synctex_node_line(right);
}
SYNCTEX_INLINE static synctex_node_p _synctex_vertically_sorted_v2(synctex_node_p sibling)
{
    synctex_node_p child = NULL;
    synctex_node_p best_child = sibling;
    synctex_node_p next_child = _synctex_tree_reset_child(best_child);
    synctex_node_p target = _synctex_tree_target(best_child);
    synctex_node_p parent = _synctex_tree_parent(target);
    unsigned int best_count = 0;
    unsigned int count = 0;
    synctex_node_p N = _synctex_tree_child(parent);
    do {
        if (_synctex_nodes_are_friend(N, best_child)) {
            ++best_count;
        }
    } while ((N = __synctex_tree_sibling(N)));
    /*  Navigate through the other children */
    while ((child = next_child)) {
        next_child = _synctex_tree_reset_child(child);
        target = _synctex_tree_target(child);
        parent = _synctex_tree_parent(target);
        count = 0;
        N = _synctex_tree_child(parent);
        do {
            if (_synctex_nodes_are_friend(N, best_child)) {
                ++count;
            }
        } while ((N = __synctex_tree_sibling(N)));
        if (count > best_count) {
            best_count = count;
            synctex_node_free(best_child);
            best_child = child;
        } else {
            synctex_node_free(child);
        }
    }
    return best_child;
}

SYNCTEX_INLINE static synctex_bool_t _synctex_point_in_box_v2(synctex_point_p hitP, synctex_node_p node);

/*  This struct records distances, the left one is non negative and the right one is non positive.
 *  When comparing the locations of 2 different graphical objects on the page, we will have to also record the
 *  horizontal distance as signed to keep track of the typesetting order.*/

typedef struct {
    synctex_node_p node;
    int distance;
} synctex_nd_s;

#define SYNCTEX_ND_0                                                                                                                                                                                                                           \
    (synctex_nd_s)                                                                                                                                                                                                                             \
    {                                                                                                                                                                                                                                          \
        NULL, INT_MAX                                                                                                                                                                                                                          \
    }

typedef synctex_nd_s *synctex_nd_p;

typedef struct {
    synctex_nd_s l;
    synctex_nd_s r;
} synctex_nd_lr_s;

/*  The best container is the deeper box that contains the hit point (H,V).
 *  _synctex_eq_deepest_container_v2 starts with node whereas
 *  _synctex_box_child_deepest starts with node's children, if any
 *  if node is not a box, or a void box, NULL is returned.
 *  We traverse the node tree in a deep first manner and stop as soon as a result is found. */
static synctex_node_p _synctex_eq_deepest_container_v2(synctex_point_p hitP, synctex_node_p node);

SYNCTEX_INLINE static synctex_nd_lr_s _synctex_eq_get_closest_children_in_box_v2(synctex_point_p hitP, synctex_node_p node);

/*  Closest child, recursive.  */
static synctex_nd_s __synctex_closest_deep_child_v2(synctex_point_p hitP, synctex_node_p node);

/*  The smallest container between two has the smallest width or height.
 *  This comparison is used when there are 2 overlapping boxes that contain the hit point.
 *  For ConTeXt, the problem appears at each page.
 *  The chosen box is the one with the smallest height, then the smallest width. */
SYNCTEX_INLINE static synctex_node_p _synctex_smallest_container_v2(synctex_node_p node, synctex_node_p other_node);

/*  Returns the distance between the hit point hit point=(H,V) and the given node. */

static int _synctex_point_node_distance_v2(synctex_point_p hitP, synctex_node_p node);

/*  The closest container is the box that is the one closest to the given point.
 *  The "visible" version takes into account the visible dimensions instead of the real ones given by TeX. */
static synctex_nd_s _synctex_eq_closest_child_v2(synctex_point_p hitP, synctex_node_p node);

#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark Queries
#endif

struct synctex_iterator_t {
    synctex_node_p seed;
    synctex_node_p next;
    int count0;
    int count;
};

SYNCTEX_INLINE static synctex_iterator_p _synctex_iterator_new(synctex_node_p result, int count)
{
    synctex_iterator_p iterator;
    if ((iterator = _synctex_malloc(sizeof(synctex_iterator_s)))) {
        iterator->seed = iterator->next = result;
        iterator->count0 = iterator->count = count;
    }
    return iterator;
};

void synctex_iterator_free(synctex_iterator_p iterator)
{
    if (iterator) {
        synctex_node_free(iterator->seed);
        _synctex_free(iterator);
    }
}
synctex_bool_t synctex_iterator_has_next(synctex_iterator_p iterator)
{
    return iterator ? iterator->count > 0 : 0;
}
int synctex_iterator_count(synctex_iterator_p iterator)
{
    return iterator ? iterator->count : 0;
}

/**
 *  The next result of the iterator.
 *  Internally, the iterator stores handles to nodes.
 *  Externally, it returns the targets,
 *  such that the caller only sees nodes.
 */
synctex_node_p synctex_iterator_next_result(synctex_iterator_p iterator)
{
    if (iterator && iterator->count > 0) {
        synctex_node_p N = iterator->next;
        iterator->next = __synctex_tree_sibling(N);
        --iterator->count;
        return _synctex_tree_target(N);
    }
    return NULL;
}
int synctex_iterator_reset(synctex_iterator_p iterator)
{
    if (iterator) {
        iterator->next = iterator->seed;
        return iterator->count = iterator->count0;
    }
    return 0;
}

synctex_iterator_p synctex_iterator_new_edit(synctex_scanner_p scanner, int page, float h, float v)
{
    if (scanner) {
        synctex_node_p sheet = NULL;
        synctex_point_s hit;
        synctex_node_p node = NULL;
        synctex_nd_lr_s nds = {{NULL, 0}, {NULL, 0}};
        if (NULL == (scanner = synctex_scanner_parse(scanner)) || 0 >= scanner->unit) { /*  scanner->unit must be >0 */
            return NULL;
        }
        /*  Find the proper sheet */
        sheet = synctex_sheet(scanner, page);
        if (NULL == sheet) {
            return NULL;
        }
        /*  Now sheet points to the sheet node with proper page number. */
        /*  Now that scanner has been initialized, we can convert
         *  the given point to scanner integer coordinates */
        hit = (synctex_point_s) {(h - scanner->x_offset) / scanner->unit, (v - scanner->y_offset) / scanner->unit};
        /*  At first, we browse all the horizontal boxes of the sheet
         *  until we find one containing the hit point. */
        if ((node = _synctex_tree_next_hbox(sheet))) {
            do {
                if (_synctex_point_in_box_v2(&hit, node)) {
                    /*  Maybe the hit point belongs to a contained vertical box.
                     *  This is the most likely situation.
                     */
                    synctex_node_p next = node;
#if defined(SYNCTEX_DEBUG)
                    printf("--- We are lucky\n");
#endif
                    /*  This trick is for catching overlapping boxes */
                    while ((next = _synctex_tree_next_hbox(next))) {
                        if (_synctex_point_in_box_v2(&hit, next)) {
                            node = _synctex_smallest_container_v2(next, node);
                        }
                    }
                    /*  node is the smallest horizontal box that contains hit,
                     *  unless there is no hbox at all.
                     */
                    node = _synctex_eq_deepest_container_v2(&hit, node);
                    nds = _synctex_eq_get_closest_children_in_box_v2(&hit, node);
                end:
                    if (nds.r.node && nds.l.node) {
                        if ((_synctex_data_tag(nds.r.node) != _synctex_data_tag(nds.l.node)) || (_synctex_data_line(nds.r.node) != _synctex_data_line(nds.l.node)) || (_synctex_data_column(nds.r.node) != _synctex_data_column(nds.l.node))) {
                            if (nds.l.distance > nds.r.distance) {
                                node = nds.r.node;
                                nds.r.node = nds.l.node;
                                nds.l.node = node;
                            }
                            if ((node = _synctex_new_handle_with_target(nds.l.node))) {
                                synctex_node_p other_handle;
                                if ((other_handle = _synctex_new_handle_with_target(nds.r.node))) {
                                    _synctex_tree_set_sibling(node, other_handle);
                                    return _synctex_iterator_new(node, 2);
                                }
                                return _synctex_iterator_new(node, 1);
                            }
                            return NULL;
                        }
                        /*  both nodes have the same input coordinates
                         *  We choose the one closest to the hit point  */
                        if (nds.l.distance > nds.r.distance) {
                            nds.l.node = nds.r.node;
                        }
                        nds.r.node = NULL;
                    } else if (nds.r.node) {
                        nds.l = nds.r;
                    } else if (!nds.l.node) {
                        nds.l.node = node;
                    }
                    if ((node = _synctex_new_handle_with_target(nds.l.node))) {
                        return _synctex_iterator_new(node, 1);
                    }
                    return 0;
                }
            } while ((node = _synctex_tree_next_hbox(node)));
            /*  All the horizontal boxes have been tested,
             *  None of them contains the hit point.
             */
        }
        /*  We are not lucky,
         *  we test absolutely all the node
         *  to find the closest... */
        if ((node = _synctex_tree_child(sheet))) {
#if defined(SYNCTEX_DEBUG)
            printf("--- We are not lucky\n");
#endif
            nds.l = __synctex_closest_deep_child_v2(&hit, node);
#if defined(SYNCTEX_DEBUG)
            printf("Edit query best: %i\n", nds.l.distance);
#endif
            goto end;
        }
    }
    return NULL;
}

/**
 *  Loop the candidate friendly list to find the ones with the proper
 *  tag and line.
 *  Returns a tree of results targeting the found candidates.
 *  At the top level each sibling has its own page number.
 *  All the results with the same page number are linked by child/parent entry.
 *  - parameter candidate: a friendly list of candidates
 */
static synctex_node_p _synctex_display_query_v2(synctex_node_p target, int tag, int line, synctex_bool_t exclude_box)
{
    synctex_node_p first_handle = NULL;
    /*  Search the first match */
    if (target == NULL) {
        return first_handle;
    }
    do {
        int page;
        if ((exclude_box && _synctex_node_is_box(target)) || (tag != synctex_node_tag(target)) || (line != synctex_node_line(target))) {
            continue;
        }
        /*  We found a first match, create
         *  a result handle targeting that candidate. */
        first_handle = _synctex_new_handle_with_target(target);
        if (first_handle == NULL) {
            return first_handle;
        }
        /*  target is either a node,
         *  or a proxy to some node, in which case,
         *  the target's target belongs to a form,
         *  not a sheet. */
        page = synctex_node_page(target);
        /*  Now create all the other results  */
        while ((target = _synctex_tree_friend(target))) {
            synctex_node_p result = NULL;
            if ((exclude_box && _synctex_node_is_box(target)) || (tag != synctex_node_tag(target)) || (line != synctex_node_line(target))) {
                continue;
            }
            /*  Another match, same page number ? */
            result = _synctex_new_handle_with_target(target);
            if (NULL == result) {
                return first_handle;
            }
            /*  is it the same page number ? */
            if (synctex_node_page(target) == page) {
                __synctex_tree_set_child(result, first_handle);
                first_handle = result;
            } else {
                /*  We have 2 page numbers involved */
                __synctex_tree_set_sibling(first_handle, result);
                while ((target = _synctex_tree_friend(target))) {
                    synctex_node_p same_page_node;
                    if ((exclude_box && _synctex_node_is_box(target)) || (tag != synctex_node_tag(target)) || (line != synctex_node_line(target))) {
                        continue;
                    }
                    /*  New match found, which page? */
                    result = _synctex_new_handle_with_target(target);
                    if (NULL == result) {
                        return first_handle;
                    }
                    same_page_node = first_handle;
                    page = synctex_node_page(target);
                    /*  Find a result with the same page number */;
                    do {
                        if (_synctex_node_target_page(same_page_node) == page) {
                            _synctex_tree_set_child(result, _synctex_tree_set_child(same_page_node, result));
                        } else if ((same_page_node = __synctex_tree_sibling(same_page_node))) {
                            continue;
                        } else {
                            /*  This is a new page number */
                            __synctex_tree_set_sibling(result, first_handle);
                            first_handle = result;
                        }
                        break;
                    } while (synctex_YES);
                }
                return first_handle;
            }
        }
    } while ((target = _synctex_tree_friend(target)));
    return first_handle;
}
synctex_iterator_p synctex_iterator_new_display(synctex_scanner_p scanner, const char *name, int line, int column, int page_hint)
{
    (void)column; /* unused */
    if (scanner) {
        int tag = synctex_scanner_get_tag(scanner, name); /* parse if necessary */
        int max_line = 0;
        int line_offset = 1;
        int try_count = 100;
        synctex_node_p node = NULL;
        synctex_node_p result = NULL;
        if (tag == 0) {
            printf("SyncTeX Warning: No tag for %s\n", name);
            return NULL;
        }
        node = synctex_scanner_input_with_tag(scanner, tag);
        max_line = _synctex_data_line(node);
        /*  node = NULL; */
        if (line > max_line) {
            line = max_line;
        }
        while (try_count--) {
            if (line <= max_line) {
                /*  This loop will only be performed once for advanced viewers */
                synctex_node_p friend = _synctex_scanner_friend(scanner, tag + line);
                if ((node = friend)) {
                    result = _synctex_display_query_v2(node, tag, line, synctex_YES);
                    if (!result) {
                        /*  We did not find any matching boundary, retry including boxes */
                        node = friend; /*  no need to test it again, already done */
                        result = _synctex_display_query_v2(node, tag, line, synctex_NO);
                    }
                    /*  Now reverse the order to have nodes in display order, and then keep just a few nodes.
                     *  Order first the best node. */
                    /*  The result is a tree. At the root level, all nodes
                     *  correspond to different page numbers.
                     *  Each node has a child which corresponds to the same
                     *  page number if relevant.
                     *  Then reorder the nodes to put first the one which fits best.
                     *  The idea is to count the number of nodes
                     *  with the same tag and line number in the parents
                     *  and choose the one with the biggest count.
                     */
                    if (result) {
                        /*  navigate through siblings,
                         then children   */
                        int count = 1;
                        synctex_node_p next_sibling = __synctex_tree_reset_sibling(result);
                        int best_match = abs(page_hint - _synctex_node_target_page(result));
                        synctex_node_p sibling;
                        int match;
                        result = _synctex_vertically_sorted_v2(result);
                        while ((sibling = next_sibling)) {
                            /* What is next? Do not miss that step! */
                            next_sibling = __synctex_tree_reset_sibling(sibling);
                            sibling = _synctex_vertically_sorted_v2(sibling);
                            match = abs(page_hint - _synctex_node_target_page(sibling));
                            if (match < best_match) {
                                /*  Order this node first */
                                __synctex_tree_set_sibling(sibling, result);
                                result = sibling;
                                best_match = match;
                            } else /*if (match>best_match)*/ {
                                __synctex_tree_set_sibling(sibling, __synctex_tree_sibling(result));
                                __synctex_tree_set_sibling(result, sibling);
                            }
                            ++count;
                        }
                        /*  Now order first the result closest to the page hint */
                        return _synctex_iterator_new(result, count);
                    }
                }
#if defined(__SYNCTEX_STRONG_DISPLAY_QUERY__)
                break;
#else
                line += line_offset;
                line_offset = line_offset < 0 ? -(line_offset - 1) : -(line_offset + 1);
                if (line <= 0) {
                    line += line_offset;
                    line_offset = line_offset < 0 ? -(line_offset - 1) : -(line_offset + 1);
                }
#endif
            }
        }
    }
    return NULL;
}
synctex_status_t synctex_display_query(synctex_scanner_p scanner, const char *name, int line, int column, int page_hint)
{
    if (scanner) {
        synctex_iterator_free(scanner->iterator);
        scanner->iterator = synctex_iterator_new_display(scanner, name, line, column, page_hint);
        return synctex_iterator_count(scanner->iterator);
    }
    return SYNCTEX_STATUS_ERROR;
}
synctex_status_t synctex_edit_query(synctex_scanner_p scanner, int page, float h, float v)
{
    if (scanner) {
        synctex_iterator_free(scanner->iterator);
        scanner->iterator = synctex_iterator_new_edit(scanner, page, h, v);
        return synctex_iterator_count(scanner->iterator);
    }
    return SYNCTEX_STATUS_ERROR;
}
/**
 *  The next result of a query.
 */
synctex_node_p synctex_scanner_next_result(synctex_scanner_p scanner)
{
    return scanner ? synctex_iterator_next_result(scanner->iterator) : NULL;
}
synctex_status_t synctex_scanner_reset_result(synctex_scanner_p scanner)
{
    return scanner ? synctex_iterator_reset(scanner->iterator) : SYNCTEX_STATUS_ERROR;
}

synctex_node_p synctex_node_target(synctex_node_p node)
{
    return _synctex_tree_target(node);
}

#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark Geometric utilities
#endif

/** Rougly speaking, this is:
 *  node's h coordinate - hit point's h coordinate.
 *  If node is to the right of the hit point, then this distance is positive,
 *  if node is to the left of the hit point, this distance is negative.
 *  If the argument is a pdf form reference, then the child is used and returned instead.
 *  Last Revision: Mon Apr 24 07:05:27 UTC 2017
 */
static synctex_nd_s _synctex_point_h_ordered_distance_v2(synctex_point_p hit, synctex_node_p node)
{
    synctex_nd_s nd = {node, INT_MAX};
    if (node) {
        int min, med, max, width;
        switch (synctex_node_type(node)) {
            /*  The distance between a point and a box is special.
             *  It is not the euclidian distance, nor something similar.
             *  We have to take into account the particular layout,
             *  and the box hierarchy.
             *  Given a box, there are 9 regions delimited by the lines of the edges of the box.
             *  The origin being at the top left corner of the page,
             *  we also give names to the vertices of the box.
             *
             *   1 | 2 | 3
             *  ---A---B--->
             *   4 | 5 | 6
             *  ---C---D--->
             *   7 | 8 | 9
             *     v   v
             */
        case synctex_node_type_vbox:
        case synctex_node_type_void_vbox:
        case synctex_node_type_void_hbox:
            /*  getting the box bounds, taking into account negative width, height and depth. */
            width = _synctex_data_width(node);
            min = _synctex_data_h(node);
            max = min + (width > 0 ? width : -width);
            /*  We always have min <= max */
            if (hit->h < min) {
                nd.distance = min - hit->h; /*  regions 1+4+7, result is > 0 */
            } else if (hit->h > max) {
                nd.distance = max - hit->h; /*  regions 3+6+9, result is < 0 */
            } else {
                nd.distance = 0; /*  regions 2+5+8, inside the box, except for vertical coordinates */
            }
            break;
        case synctex_node_type_proxy_vbox:
            /*  getting the box bounds, taking into account negative width, height and depth. */
            width = synctex_node_width(node);
            min = synctex_node_h(node);
            max = min + (width > 0 ? width : -width);
            /*  We always have min <= max */
            if (hit->h < min) {
                nd.distance = min - hit->h; /*  regions 1+4+7, result is > 0 */
            } else if (hit->h > max) {
                nd.distance = max - hit->h; /*  regions 3+6+9, result is < 0 */
            } else {
                nd.distance = 0; /*  regions 2+5+8, inside the box, except for vertical coordinates */
            }
            break;
        case synctex_node_type_hbox:
        case synctex_node_type_proxy_hbox:
            /*  getting the box bounds, taking into account negative width, height and depth. */
            width = synctex_node_hbox_width(node);
            min = synctex_node_hbox_h(node);
            max = min + (width > 0 ? width : -width);
            /*  We always have min <= max */
            if (hit->h < min) {
                nd.distance = min - hit->h; /*  regions 1+4+7, result is > 0 */
            } else if (hit->h > max) {
                nd.distance = max - hit->h; /*  regions 3+6+9, result is < 0 */
            } else {
                nd.distance = 0; /*  regions 2+5+8, inside the box, except for vertical coordinates */
            }
            break;
        case synctex_node_type_kern:
            /*  IMPORTANT NOTICE: the location of the kern is recorded AFTER the move.
             *  The distance to the kern is very special,
             *  in general, there is no text material in the kern,
             *  this is why we compute the offset relative to the closest edge of the kern.*/
            max = _synctex_data_width(node);
            if (max < 0) {
                min = _synctex_data_h(node);
                max = min - max;
            } else {
                min = -max;
                max = _synctex_data_h(node);
                min += max;
            }
            med = (min + max) / 2;
            /*  positive kern: '.' means text, '>' means kern offset
             *      .............
             *                   min>>>>med>>>>max
             *                                    ...............
             *  negative kern: '.' means text, '<' means kern offset
             *      ............................
             *                 min<<<<med<<<<max
             *                 .................................
             *  Actually, we do not take into account negative widths.
             *  There is a problem for such situation when there is effectively overlapping text.
             *  But this should be extremely rare. I guess that in that case, many different choices
             *  could be made, one being in contradiction with the other.
             *  It means that the best choice should be made according to the situation that occurs
             *  most frequently.
             */
            if (hit->h < min) {
                nd.distance = min - hit->h + 1; /*  penalty to ensure other nodes are chosen first in case of overlapping ones */
            } else if (hit->h > max) {
                nd.distance = max - hit->h - 1; /*  same kind of penalty */
            } else if (hit->h > med) {
                /*  do things like if the node had 0 width and was placed at the max edge + 1*/
                nd.distance = max - hit->h + 1; /*  positive, the kern is to the right of the hit point */
            } else {
                nd.distance = min - hit->h - 1; /*  negative, the kern is to the left of the hit point */
            }
            break;
        case synctex_node_type_rule: /* to do: special management */
        case synctex_node_type_glue:
        case synctex_node_type_math:
        case synctex_node_type_boundary:
        case synctex_node_type_box_bdry:
            nd.distance = _synctex_data_h(node) - hit->h;
            break;
        case synctex_node_type_ref:
            nd.node = synctex_node_child(node);
            nd = _synctex_point_h_ordered_distance_v2(hit, nd.node);
            break;
        case synctex_node_type_proxy:
        case synctex_node_type_proxy_last: {
            /* shift the hit point to be relative to the proxy origin,
             *  then compute the distance to the target
             */
            synctex_point_s otherHit = *hit;
            otherHit.h -= _synctex_data_h(node);
            otherHit.v -= _synctex_data_v(node);
            nd.node = _synctex_tree_target(node);
            nd = _synctex_point_h_ordered_distance_v2(&otherHit, nd.node);
            nd.node = node;
        }
        default:
            break;
        }
    }
    return nd;
}
/** Rougly speaking, this is:
 *  node's v coordinate - hit point's v coordinate.
 *  If node is at the top of the hit point, then this distance is positive,
 *  if node is at the bottom of the hit point, this distance is negative.
 */
static synctex_nd_s _synctex_point_v_ordered_distance_v2(synctex_point_p hit, synctex_node_p node)
{
    synctex_nd_s nd = {node, INT_MAX};
    int min, max, depth, height;
    switch (synctex_node_type(node)) {
        /*  The distance between a point and a box is special.
         *  It is not the euclidian distance, nor something similar.
         *  We have to take into account the particular layout,
         *  and the box hierarchy.
         *  Given a box, there are 9 regions delimited by the lines of the edges of the box.
         *  The origin being at the top left corner of the page,
         *  we also give names to the vertices of the box.
         *
         *   1 | 2 | 3
         *  ---A---B--->
         *   4 | 5 | 6
         *  ---C---D--->
         *   7 | 8 | 9
         *     v   v
         */
    case synctex_node_type_vbox:
    case synctex_node_type_void_vbox:
    case synctex_node_type_void_hbox:
        /*  getting the box bounds, taking into account negative width, height and depth. */
        min = synctex_node_v(node);
        max = min + _synctex_abs(_synctex_data_depth(node));
        min -= _synctex_abs(_synctex_data_height(node));
        /*  We always have min <= max */
        if (hit->v < min) {
            nd.distance = min - hit->v; /*  regions 1+2+3, result is > 0 */
        } else if (hit->v > max) {
            nd.distance = max - hit->v; /*  regions 7+8+9, result is < 0 */
        } else {
            nd.distance = 0; /*  regions 4.5.6, inside the box, except for horizontal coordinates */
        }
        break;
    case synctex_node_type_proxy_vbox:
        /*  getting the box bounds, taking into account negative width, height and depth. */
        min = synctex_node_v(node);
        max = min + _synctex_abs(synctex_node_depth(node));
        min -= _synctex_abs(synctex_node_height(node));
        /*  We always have min <= max */
        if (hit->v < min) {
            nd.distance = min - hit->v; /*  regions 1+2+3, result is > 0 */
        } else if (hit->v > max) {
            nd.distance = max - hit->v; /*  regions 7+8+9, result is < 0 */
        } else {
            nd.distance = 0; /*  regions 4.5.6, inside the box, except for horizontal coordinates */
        }
        break;
    case synctex_node_type_hbox:
    case synctex_node_type_proxy_hbox:
        /*  getting the box bounds, taking into account negative height and depth. */
        min = synctex_node_hbox_v(node);
        depth = synctex_node_hbox_depth(node);
        max = min + (depth > 0 ? depth : -depth);
        height = synctex_node_hbox_height(node);
        min -= (height > 0 ? height : -height);
        /*  We always have min <= max */
        if (hit->v < min) {
            nd.distance = min - hit->v; /*  regions 1+2+3, result is > 0 */
        } else if (hit->v > max) {
            nd.distance = max - hit->v; /*  regions 7+8+9, result is < 0 */
        } else {
            nd.distance = 0; /*  regions 4.5.6, inside the box, except for horizontal coordinates */
        }
        break;
    case synctex_node_type_rule: /* to do: special management */
    case synctex_node_type_kern:
    case synctex_node_type_glue:
    case synctex_node_type_math:
        min = _synctex_data_v(node);
        max = min + _synctex_abs(_synctex_data_depth(_synctex_tree_parent(node)));
        min -= _synctex_abs(_synctex_data_height(_synctex_tree_parent(node)));
        /*  We always have min <= max */
        if (hit->v < min) {
            nd.distance = min - hit->v; /*  regions 1+2+3, result is > 0 */
        } else if (hit->v > max) {
            nd.distance = max - hit->v; /*  regions 7+8+9, result is < 0 */
        } else {
            nd.distance = 0; /*  regions 4.5.6, inside the box, except for horizontal coordinates */
        }
        break;
    case synctex_node_type_ref:
        nd.node = synctex_node_child(node);
        nd = _synctex_point_v_ordered_distance_v2(hit, nd.node);
        break;
    case synctex_node_type_proxy:
    case synctex_node_type_proxy_last: {
        synctex_point_s otherHit = *hit;
        otherHit.h -= _synctex_data_h(node);
        otherHit.v -= _synctex_data_v(node);
        nd.node = _synctex_tree_target(node);
        nd = _synctex_point_v_ordered_distance_v2(&otherHit, nd.node);
        nd.node = node;
    }
    default:
        break;
    }
    return nd;
}
/**
 *  The best is the one with the smallest area.
 *  The area is width*height where width and height may be big.
 *  So there is a real risk of overflow if we stick with ints.
 */
SYNCTEX_INLINE static synctex_node_p _synctex_smallest_container_v2(synctex_node_p node, synctex_node_p other_node)
{
    long total_height, other_total_height;
    unsigned long area, other_area;
    long width = synctex_node_hbox_width(node);
    long other_width = synctex_node_hbox_width(other_node);
    if (width < 0) {
        width = -width;
    }
    if (other_width < 0) {
        other_width = -other_width;
    }
    total_height = _synctex_abs(synctex_node_hbox_depth(node)) + _synctex_abs(synctex_node_hbox_height(node));
    other_total_height = _synctex_abs(synctex_node_hbox_depth(other_node)) + _synctex_abs(synctex_node_hbox_height(other_node));
    area = total_height * width;
    other_area = other_total_height * other_width;
    if (area < other_area) {
        return node;
    }
    if (area > other_area) {
        return other_node;
    }
    if (_synctex_abs(_synctex_data_width(node)) > _synctex_abs(_synctex_data_width(other_node))) {
        return node;
    }
    if (_synctex_abs(_synctex_data_width(node)) < _synctex_abs(_synctex_data_width(other_node))) {
        return other_node;
    }
    if (total_height < other_total_height) {
        return node;
    }
    if (total_height > other_total_height) {
        return other_node;
    }
    return node;
}

SYNCTEX_INLINE static synctex_bool_t _synctex_point_in_box_v2(synctex_point_p hit, synctex_node_p node)
{
    if (node) {
        if (0 == _synctex_point_h_ordered_distance_v2(hit, node).distance && 0 == _synctex_point_v_ordered_distance_v2(hit, node).distance) {
            return synctex_YES;
        }
    }
    return synctex_NO;
}

static int _synctex_distance_to_box_v2(synctex_point_p hit, synctex_box_p box)
{
    /*  The distance between a point and a box is special.
     *  It is not the euclidian distance, nor something similar.
     *  We have to take into account the particular layout,
     *  and the box hierarchy.
     *  Given a box, there are 9 regions delimited by the lines of the edges of the box.
     *  The origin being at the top left corner of the page,
     *  we also give names to the vertices of the box.
     *
     *   1 | 2 | 3
     *  ---A---B--->
     *   4 | 5 | 6
     *  ---C---D--->
     *   7 | 8 | 9
     *     v   v
     *  In each region, there is a different formula.
     *  In the end we have a continuous distance which may not be a mathematical distance but who cares. */
    if (hit->v < box->min.v) {
        /*  Regions 1, 2 or 3 */
        if (hit->h < box->min.h) {
            /*  This is region 1. The distance to the box is the L1 distance PA. */
            return box->min.v - hit->v + box->min.h - hit->h; /*  Integer overflow? probability epsilon */
        } else if (hit->h <= box->max.h) {
            /*  This is region 2. The distance to the box is the geometrical distance to the top edge.  */
            return box->min.v - hit->v;
        } else {
            /*  This is region 3. The distance to the box is the L1 distance PB. */
            return box->min.v - hit->v + hit->h - box->max.h;
        }
    } else if (hit->v <= box->max.v) {
        /*  Regions 4, 5 or 6 */
        if (hit->h < box->min.h) {
            /*  This is region 4. The distance to the box is the geometrical distance to the left edge.  */
            return box->min.h - hit->h;
        } else if (hit->h <= box->max.h) {
            /*  This is region 5. We are inside the box.  */
            return 0;
        } else {
            /*  This is region 6. The distance to the box is the geometrical distance to the right edge.  */
            return hit->h - box->max.h;
        }
    } else {
        /*  Regions 7, 8 or 9 */
        if (hit->h < box->min.h) {
            /*  This is region 7. The distance to the box is the L1 distance PC. */
            return hit->v - box->max.v + box->min.h - hit->h;
        } else if (hit->h <= box->max.h) {
            /*  This is region 8. The distance to the box is the geometrical distance to the top edge.  */
            return hit->v - box->max.v;
        } else {
            /*  This is region 9. The distance to the box is the L1 distance PD. */
            return hit->v - box->max.v + hit->h - box->max.h;
        }
    }
}

/**
 *  The distance from the hit point to the node.
 */
static int _synctex_point_node_distance_v2(synctex_point_p hit, synctex_node_p node)
{
    int d = INT_MAX;
    if (node) {
        synctex_box_s box = {{0, 0}, {0, 0}};
        int dd = INT_MAX;
        switch (synctex_node_type(node)) {
        case synctex_node_type_vbox:
            box.min.h = _synctex_data_h(node);
            box.max.h = box.min.h + _synctex_abs(_synctex_data_width(node));
            box.min.v = synctex_node_v(node);
            box.max.v = box.min.v + _synctex_abs(_synctex_data_depth(node));
            box.min.v -= _synctex_abs(_synctex_data_height(node));
            return _synctex_distance_to_box_v2(hit, &box);
        case synctex_node_type_proxy_vbox:
            box.min.h = synctex_node_h(node);
            box.max.h = box.min.h + _synctex_abs(synctex_node_width(node));
            box.min.v = synctex_node_v(node);
            box.max.v = box.min.v + _synctex_abs(synctex_node_depth(node));
            box.min.v -= _synctex_abs(synctex_node_height(node));
            return _synctex_distance_to_box_v2(hit, &box);
        case synctex_node_type_hbox:
        case synctex_node_type_proxy_hbox:
            box.min.h = synctex_node_hbox_h(node);
            box.max.h = box.min.h + _synctex_abs(synctex_node_hbox_width(node));
            box.min.v = synctex_node_hbox_v(node);
            box.max.v = box.min.v + _synctex_abs(synctex_node_hbox_depth(node));
            box.min.v -= _synctex_abs(synctex_node_hbox_height(node));
            return _synctex_distance_to_box_v2(hit, &box);
        case synctex_node_type_void_vbox:
        case synctex_node_type_void_hbox:
            /*  best of distances from the left edge and right edge*/
            box.min.h = _synctex_data_h(node);
            box.max.h = box.min.h;
            box.min.v = _synctex_data_v(node);
            box.max.v = box.min.v + _synctex_abs(_synctex_data_depth(node));
            box.min.v -= _synctex_abs(_synctex_data_height(node));
            d = _synctex_distance_to_box_v2(hit, &box);
            box.min.h = box.min.h + _synctex_abs(_synctex_data_width(node));
            box.max.h = box.min.h;
            dd = _synctex_distance_to_box_v2(hit, &box);
            return d < dd ? d : dd;
        case synctex_node_type_kern:
            box.min.h = _synctex_data_h(node);
            box.max.h = box.min.h;
            box.max.v = _synctex_data_v(node);
            box.min.v = box.max.v - _synctex_abs(_synctex_data_height(_synctex_tree_parent(node)));
            d = _synctex_distance_to_box_v2(hit, &box);
            box.min.h -= _synctex_data_width(node);
            box.max.h = box.min.h;
            dd = _synctex_distance_to_box_v2(hit, &box);
            return d < dd ? d : dd;
        case synctex_node_type_glue:
        case synctex_node_type_math:
        case synctex_node_type_boundary:
        case synctex_node_type_box_bdry:
            box.min.h = _synctex_data_h(node);
            box.max.h = box.min.h;
            box.max.v = _synctex_data_v(node);
            box.min.v = box.max.v - _synctex_abs(_synctex_data_height(_synctex_tree_parent(node)));
            return _synctex_distance_to_box_v2(hit, &box);
        case synctex_node_type_proxy:
        case synctex_node_type_proxy_last: {
            synctex_point_s otherHit = *hit;
            otherHit.h -= _synctex_data_h(node);
            otherHit.v -= _synctex_data_v(node);
            return _synctex_point_node_distance_v2(&otherHit, _synctex_tree_target(node));
        }
        default:
            break;
        }
    }
    return d;
}
static synctex_node_p _synctex_eq_deepest_container_v2(synctex_point_p hit, synctex_node_p node)
{
    if (node) {
        /**/
        synctex_node_p child;
        if ((child = synctex_node_child(node))) {
            /*  Non void hbox or vbox, form ref or proxy */
            /*  We go deep first because some boxes have 0 dimensions
             *  despite they do contain some black material.
             */
            do {
                if ((_synctex_point_in_box_v2(hit, child))) {
                    synctex_node_p deep = _synctex_eq_deepest_container_v2(hit, child);
                    if (deep) {
                        /*  One of the children contains the hit. */
                        return deep;
                    }
                }
            } while ((child = synctex_node_sibling(child)));
            /*  is the hit point inside the box? */
            if (synctex_node_type(node) == synctex_node_type_vbox || synctex_node_type(node) == synctex_node_type_proxy_vbox) {
                /*  For vboxes we try to use some node inside.
                 *  Walk through the list of siblings until we find the closest one.
                 *  Only consider siblings with children inside. */
                if ((child = _synctex_tree_child(node))) {
                    synctex_nd_s best = SYNCTEX_ND_0;
                    do {
                        if (_synctex_tree_child(child)) {
                            int d = _synctex_point_node_distance_v2(hit, child);
                            if (d <= best.distance) {
                                best = (synctex_nd_s) {child, d};
                            }
                        }
                    } while ((child = __synctex_tree_sibling(child)));
                    if (best.node) {
                        return best.node;
                    }
                }
            }
            if (_synctex_point_in_box_v2(hit, node)) {
                return node;
            }
        }
    }
    return NULL;
}
static synctex_nd_s _synctex_eq_deepest_container_v3(synctex_point_p hit, synctex_node_p node)
{
    if (node) {
        synctex_node_p child = NULL;
        if ((child = synctex_node_child(node))) {
            /*  Non void hbox, vbox, box proxy or form ref */
            /*  We go deep first because some boxes have 0 dimensions
             *  despite they do contain some black material.
             */
            do {
                synctex_nd_s deep = _synctex_eq_deepest_container_v3(hit, child);
                if (deep.node) {
                    /*  One of the children contains the hit-> */
                    return deep;
                }
            } while ((child = synctex_node_sibling(child)));
            /*  For vboxes we try to use some node inside.
             *  Walk through the list of siblings until we find the closest one.
             *  Only consider siblings with children inside. */
            if (synctex_node_type(node) == synctex_node_type_vbox || synctex_node_type(node) == synctex_node_type_proxy_vbox) {
                if ((child = synctex_node_child(node))) {
                    synctex_nd_s best = SYNCTEX_ND_0;
                    do {
                        if (synctex_node_child(child)) {
                            int d = _synctex_point_node_distance_v2(hit, child);
                            if (d < best.distance) {
                                best = (synctex_nd_s) {child, d};
                            }
                        }
                    } while ((child = synctex_node_sibling(child)));
                    if (best.node) {
                        return best;
                    }
                }
            }
            /*  is the hit point inside the box? */
            if (_synctex_point_in_box_v2(hit, node)) {
                return (synctex_nd_s) {node, 0};
            }
        }
    }
    return SYNCTEX_ND_0;
}

/*  Compares the locations of the hit point with the locations of
 *  the various nodes contained in the box.
 *  As it is an horizontal box, we only compare horizontal coordinates.
 */
SYNCTEX_INLINE static synctex_nd_lr_s __synctex_eq_get_closest_children_in_hbox_v2(synctex_point_p hitP, synctex_node_p node)
{
    synctex_nd_s childd = SYNCTEX_ND_0;
    synctex_nd_lr_s nds = {SYNCTEX_ND_0, SYNCTEX_ND_0};
    if ((childd.node = synctex_node_child(node))) {
        synctex_nd_s nd = SYNCTEX_ND_0;
        do {
            childd = _synctex_point_h_ordered_distance_v2(hitP, childd.node);
            if (childd.distance > 0) {
                /*  node is to the right of the hit point.
                 *  We compare node and the previously recorded one, through the recorded distance.
                 *  If the nodes have the same tag, prefer the one with the smallest line number,
                 *  if the nodes also have the same line number, prefer the one with the smallest column. */
                if (nds.r.distance > childd.distance) {
                    nds.r = childd;
                } else if (nds.r.distance == childd.distance && nds.r.node) {
                    if (_synctex_data_tag(nds.r.node) == _synctex_data_tag(childd.node) &&
                        (_synctex_data_line(nds.r.node) > _synctex_data_line(childd.node) || (_synctex_data_line(nds.r.node) == _synctex_data_line(childd.node) && _synctex_data_column(nds.r.node) > _synctex_data_column(childd.node)))) {
                        nds.r = childd;
                    }
                }
            } else if (childd.distance == 0) {
                /*  hit point is inside node. */
                return _synctex_eq_get_closest_children_in_box_v2(hitP, childd.node);
            } else { /*  here childd.distance < 0, the hit point is to the right of node */
                childd.distance = -childd.distance;
                if (nds.l.distance > childd.distance) {
                    nds.l = childd;
                } else if (nds.l.distance == childd.distance && nds.l.node) {
                    if (_synctex_data_tag(nds.l.node) == _synctex_data_tag(childd.node) &&
                        (_synctex_data_line(nds.l.node) > _synctex_data_line(childd.node) || (_synctex_data_line(nds.l.node) == _synctex_data_line(childd.node) && _synctex_data_column(nds.l.node) > _synctex_data_column(childd.node)))) {
                        nds.l = childd;
                    }
                }
            }
        } while ((childd.node = synctex_node_sibling(childd.node)));
        if (nds.l.node) {
            /*  the left node is new, try to narrow the result */
            if ((nd = _synctex_eq_deepest_container_v3(hitP, nds.l.node)).node) {
                nds.l = nd;
            }
            if ((nd = __synctex_closest_deep_child_v2(hitP, nds.l.node)).node) {
                nds.l.node = nd.node;
            }
        }
        if (nds.r.node) {
            /*  the right node is new, try to narrow the result */
            if ((nd = _synctex_eq_deepest_container_v3(hitP, nds.r.node)).node) {
                nds.r = nd;
            }
            if ((nd = __synctex_closest_deep_child_v2(hitP, nds.r.node)).node) {
                nds.r.node = nd.node;
            }
        }
    }
    return nds;
}

SYNCTEX_INLINE static synctex_nd_lr_s __synctex_eq_get_closest_children_in_vbox_v2(synctex_point_p hitP, synctex_node_p nodeP)
{
    (void)nodeP; /* unused */
    synctex_nd_lr_s nds = {SYNCTEX_ND_0, SYNCTEX_ND_0};
    synctex_nd_s nd = SYNCTEX_ND_0;
    if ((nd.node = synctex_node_child(nd.node))) {
        do {
            nd = _synctex_point_v_ordered_distance_v2(hitP, nd.node);
            /*  this is what makes the difference with the h version above */
            if (nd.distance > 0) {
                /*  node is to the top of the hit point (below because TeX is oriented from top to bottom.
                 *  We compare node and the previously recorded one, through the recorded distance.
                 *  If the nodes have the same tag, prefer the one with the smallest line number,
                 *  if the nodes also have the same line number, prefer the one with the smallest column. */
                if (nds.r.distance > nd.distance) {
                    nds.r = nd;
                } else if (nds.r.distance == nd.distance && nds.r.node) {
                    if (_synctex_data_tag(nds.r.node) == _synctex_data_tag(nd.node) &&
                        (_synctex_data_line(nds.r.node) > _synctex_data_line(nd.node) || (_synctex_data_line(nds.r.node) == _synctex_data_line(nd.node) && _synctex_data_column(nds.r.node) > _synctex_data_column(nd.node)))) {
                        nds.r = nd;
                    }
                }
            } else if (nd.distance == 0) {
                nds.l = nd;
            } else { /*  here nd < 0 */
                nd.distance = -nd.distance;
                if (nds.l.distance > nd.distance) {
                    nds.l = nd;
                } else if (nds.l.distance == nd.distance && nds.l.node) {
                    if (_synctex_data_tag(nds.l.node) == _synctex_data_tag(nd.node) &&
                        (_synctex_data_line(nds.l.node) > _synctex_data_line(nd.node) || (_synctex_data_line(nds.l.node) == _synctex_data_line(nd.node) && _synctex_data_column(nds.l.node) > _synctex_data_column(nd.node)))) {
                        nds.l = nd;
                    }
                }
            }
        } while ((nd.node = synctex_node_sibling(nd.node)));
        if (nds.l.node) {
            if ((nd.node = _synctex_eq_deepest_container_v2(hitP, nds.l.node))) {
                nds.l.node = nd.node;
            }
            if ((nd = _synctex_eq_closest_child_v2(hitP, nds.l.node)).node) {
                nds.l.node = nd.node;
            }
        }
        if (nds.r.node) {
            if ((nd.node = _synctex_eq_deepest_container_v2(hitP, nds.r.node))) {
                nds.r.node = nd.node;
            }
            if ((nd = _synctex_eq_closest_child_v2(hitP, nds.r.node)).node) {
                nds.r.node = nd.node;
            }
        }
    }
    return nds;
}

/**
 *  Get the child closest to the hit point.
 *  - parameter: hit point
 *  - parameter: containing node
 *  - returns: the child and the distance to the hit point.
 *      SYNCTEX_ND_0 if the parameter node has no children.
 *  - note: recursive call.
 */
static synctex_nd_s __synctex_closest_deep_child_v2(synctex_point_p hitP, synctex_node_p node)
{
    synctex_nd_s best = SYNCTEX_ND_0;
    synctex_node_p child = NULL;
    if ((child = synctex_node_child(node))) {
#if defined(SYNCTEX_DEBUG)
        printf("Closest deep child on box at line %i\n", SYNCTEX_LINEINDEX(node));
#endif
        do {
#if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500
            synctex_node_display(child);
#endif
            synctex_nd_s nd = SYNCTEX_ND_0;
            if (_synctex_node_is_box(child)) {
                nd = __synctex_closest_deep_child_v2(hitP, child);
            } else {
                nd = (synctex_nd_s) {child, _synctex_point_node_distance_v2(hitP, child)};
            }
            if (nd.distance < best.distance || (nd.distance == best.distance && synctex_node_type(nd.node) != synctex_node_type_kern)) {
#if defined(SYNCTEX_DEBUG)
                if (nd.node) {
                    printf("New best %i<=%i line %i\n", nd.distance, best.distance, SYNCTEX_LINEINDEX(nd.node));
                }
#endif
                best = nd;
            }
        } while ((child = synctex_node_sibling(child)));
#if defined(SYNCTEX_DEBUG)
        if (best.node) {
            printf("Found new best %i line %i\n", best.distance, SYNCTEX_LINEINDEX(best.node));
        }
#endif
    }
    return best;
}

/**
 *  Return the closest child.
 *  - parameter: a pointer to the hit point,
 *  - parameter: the container
 *  - return: SYNCTEX_ND_0 if node has no child,
 *      the __synctex_closest_deep_child_v2 otherwise.
 */
static synctex_nd_s _synctex_eq_closest_child_v2(synctex_point_p hitP, synctex_node_p node)
{
    synctex_nd_s nd = SYNCTEX_ND_0;
    if (_synctex_node_is_box(node)) {
        nd = __synctex_closest_deep_child_v2(hitP, node);
        if (_synctex_node_is_box(nd.node)) {
            synctex_node_p child = NULL;
            if ((child = synctex_node_child(nd.node))) {
                synctex_nd_s best = {child, _synctex_point_node_distance_v2(hitP, child)};
                while ((child = synctex_node_sibling(child))) {
                    int d = _synctex_point_node_distance_v2(hitP, child);
                    if (d < best.distance) {
                        best = (synctex_nd_s) {child, d};
                    } else if (d == best.distance && synctex_node_type(child) != synctex_node_type_kern) {
                        best.node = child;
                    }
                }
                return best;
            }
        }
        return nd;
    }
    return SYNCTEX_ND_0;
}
SYNCTEX_INLINE static synctex_nd_lr_s _synctex_eq_get_closest_children_in_box_v2(synctex_point_p hitP, synctex_node_p node)
{
    synctex_nd_lr_s nds = {SYNCTEX_ND_0, SYNCTEX_ND_0};
    if (_synctex_tree_has_child(node)) { /* node != NULL */
        if (node->class->type == synctex_node_type_hbox || node->class->type == synctex_node_type_proxy_hbox) {
            return __synctex_eq_get_closest_children_in_hbox_v2(hitP, node);
        } else {
            return __synctex_eq_get_closest_children_in_vbox_v2(hitP, node);
        }
    }
    return nds;
}

#ifndef SYNCTEX_NO_UPDATER

#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark Updater
#endif

typedef int (*synctex_print_f)(synctex_updater_p, const char *, ...); /*  print formatted to either FILE *  or gzFile */
typedef void (*synctex_close_f)(synctex_updater_p);                   /*  close FILE *  or gzFile */

#define SYNCTEX_BITS_PER_BYTE 8

typedef union {
    gzFile as_gzFile;
    FILE *as_FILE_p;
    void *as_ptr;
} syncex_file_u;

struct synctex_updater_t {
    syncex_file_u file;
    synctex_print_f print;
    synctex_close_f close;
    int length; /*  the number of chars appended */
};

static int _synctex_updater_print(synctex_updater_p updater, const char *format, ...) SYNCTEX_PRINTF_FORMAT(2, 3);
static int _synctex_updater_print(synctex_updater_p updater, const char *format, ...)
{
    int result = 0;
    if (updater) {
        va_list va;
        va_start(va, format);
        result = vfprintf(updater->file.as_FILE_p, format, va);
        va_end(va);
    }
    return result;
}
#if defined(_MSC_VER) || defined(__MINGW32__)
#include <stdio.h>
#include <stdlib.h>

static int vasprintf(char **ret, const char *format, va_list ap)
{
    int len;
    len = _vsnprintf(NULL, 0, format, ap);
    if (len < 0)
        return -1;
    *ret = malloc(len + 1);
    if (!*ret)
        return -1;
    _vsnprintf(*ret, len + 1, format, ap);
    (*ret)[len] = '\0';
    return len;
}

#endif

/**
 *  gzvprintf is not available until OSX 10.10
 */
static int _synctex_updater_print_gz(synctex_updater_p updater, const char *format, ...) SYNCTEX_PRINTF_FORMAT(2, 3);
static int _synctex_updater_print_gz(synctex_updater_p updater, const char *format, ...)
{
    int result = 0;
    if (updater) {
        char *buffer;
        va_list va;
        va_start(va, format);
        if (vasprintf(&buffer, format, va) < 0) {
            _synctex_error("Out of memory...");
        } else if ((result = (int)strlen(buffer))) {
            result = gzwrite(updater->file.as_gzFile, buffer, (unsigned)result);
        }
        va_end(va);
        free(buffer);
    }
    return result;
}

static void _synctex_updater_close(synctex_updater_p updater)
{
    if (updater) {
        fclose(updater->file.as_FILE_p);
    }
}

static void _synctex_updater_close_gz(synctex_updater_p updater)
{
    if (updater) {
        gzclose(updater->file.as_gzFile);
    }
}

synctex_updater_p synctex_updater_new_with_output_file(const char *output, const char *build_directory)
{
    synctex_updater_p updater = NULL;
    const char *mode = NULL;
    synctex_open_s open;
    /*  prepare the updater, the memory is the only one dynamically allocated */
    updater = (synctex_updater_p)_synctex_malloc(sizeof(synctex_updater_s));
    if (NULL == updater) {
        _synctex_error("!  synctex_updater_new_with_file: malloc problem");
        return NULL;
    }
    open = _synctex_open_v2(output, build_directory, 0, synctex_ADD_QUOTES);
    if (open.status < SYNCTEX_STATUS_OK) {
        open = _synctex_open_v2(output, build_directory, 0, synctex_DONT_ADD_QUOTES);
        if (open.status < SYNCTEX_STATUS_OK) {
        return_on_error:
            _synctex_free(updater);
            return updater = NULL;
        }
    }
    /*  OK, the file exists, we close it and reopen it with the correct mode.
     *  The receiver is now the owner of the "synctex" variable. */
    gzclose(open.file);
    updater->file.as_ptr = NULL;
    mode = _synctex_get_io_mode_name(open.io_mode | synctex_io_append_mask); /* either "a" or "ab", depending on the file extension */
    if (open.io_mode & synctex_io_gz_mask) {
        if (NULL == (updater->file.as_FILE_p = fopen(open.synctex, mode))) {
        no_write_error:
            _synctex_error("!  synctex_updater_new_with_file: Can't append to %s", open.synctex);
            free(open.synctex);
            goto return_on_error;
        }
        updater->print = &_synctex_updater_print;
        updater->close = &_synctex_updater_close;
    } else {
        if (NULL == (updater->file.as_gzFile = gzopen(open.synctex, mode))) {
            goto no_write_error;
        }
        updater->print = &_synctex_updater_print_gz;
        updater->close = &_synctex_updater_close_gz;
    }
    printf("SyncTeX: updating %s...", open.synctex);
    _synctex_free(open.synctex);
    return updater;
}

void synctex_updater_append_magnification(synctex_updater_p updater, char *magnification)
{
    if (NULL == updater) {
        return;
    }
    if (magnification && strlen(magnification)) {
        updater->length += updater->print(updater, "Magnification:%s\n", magnification);
    }
}

void synctex_updater_append_x_offset(synctex_updater_p updater, char *x_offset)
{
    if (NULL == updater) {
        return;
    }
    if (x_offset && strlen(x_offset)) {
        updater->length += updater->print(updater, "X Offset:%s\n", x_offset);
    }
}

void synctex_updater_append_y_offset(synctex_updater_p updater, char *y_offset)
{
    if (NULL == updater) {
        return;
    }
    if (y_offset && strlen(y_offset)) {
        updater->length += updater->print(updater, "Y Offset:%s\n", y_offset);
    }
}

void synctex_updater_free(synctex_updater_p updater)
{
    if (NULL == updater) {
        return;
    }
    if (updater->length > 0) {
        updater->print(updater, "!%i\n", updater->length);
    }
    updater->close(updater);
    _synctex_free(updater);
    printf("... done.\n");
    return;
}
#endif

#if defined(SYNCTEX_TESTING)
#ifdef SYNCTEX_NOTHING
#pragma mark -
#pragma mark Testers
#endif
static int _synctex_input_copy_name(synctex_node_p input, char *name)
{
    char *copy = _synctex_malloc(strlen(name) + 1);
    memcpy(copy, name, strlen(name) + 1);
    _synctex_data_set_name(input, copy);
    return 0;
}
int synctex_test_setup_scanner_sheets_421(synctex_scanner_p scanner)
{
    int TC = 0;
    synctex_node_p sheet = synctex_node_new(scanner, synctex_node_type_sheet);
    _synctex_data_set_page(sheet, 4);
    SYNCTEX_TEST_BODY(TC, _synctex_data_page(sheet) == 4, "");
    synctex_node_free(scanner->sheet);
    scanner->sheet = sheet;
    sheet = synctex_node_new(scanner, synctex_node_type_sheet);
    _synctex_data_set_page(sheet, 2);
    SYNCTEX_TEST_BODY(TC, _synctex_data_page(sheet) == 2, "");
    __synctex_tree_set_sibling(sheet, scanner->sheet);
    scanner->sheet = sheet;
    sheet = synctex_node_new(scanner, synctex_node_type_sheet);
    _synctex_data_set_page(sheet, 1);
    SYNCTEX_TEST_BODY(TC, _synctex_data_page(sheet) == 1, "");
    __synctex_tree_set_sibling(sheet, scanner->sheet);
    scanner->sheet = sheet;
    return TC;
}
int synctex_test_input(synctex_scanner_p scanner)
{
    int TC = 0;
    synctex_node_p input = synctex_node_new(scanner, synctex_node_type_input);
    _synctex_data_set_tag(input, 421);
    SYNCTEX_TEST_BODY(TC, _synctex_data_tag(input) == 421, "");
    _synctex_data_set_tag(input, 124);
    SYNCTEX_TEST_BODY(TC, _synctex_data_tag(input) == 124, "");
    _synctex_data_set_line(input, 421);
    SYNCTEX_TEST_BODY(TC, _synctex_data_line(input) == 421, "");
    _synctex_data_set_line(input, 214);
    SYNCTEX_TEST_BODY(TC, _synctex_data_line(input) == 214, "");
    _synctex_data_set_line(input, 214);
    SYNCTEX_TEST_BODY(TC, _synctex_data_line(input) == 214, "");
    _synctex_input_copy_name(input, "214");
    SYNCTEX_TEST_BODY(TC, 0 == memcmp(_synctex_data_name(input), "214", 4), "");
    _synctex_input_copy_name(input, "421421");

    SYNCTEX_TEST_BODY(TC, 0 == memcmp(_synctex_data_name(input), "421421", 4), "");
    synctex_node_free(input);
    return TC;
}
int synctex_test_proxy(synctex_scanner_p scanner)
{
    int TC = 0;
    synctex_node_p proxy = synctex_node_new(scanner, synctex_node_type_proxy);
    synctex_node_p target = synctex_node_new(scanner, synctex_node_type_rule);
    _synctex_tree_set_target(proxy, target);
    _synctex_data_set_tag(target, 421);
    SYNCTEX_TEST_BODY(TC, _synctex_data_tag(target) == 421, "");
    SYNCTEX_TEST_BODY(TC, synctex_node_tag(target) == 421, "");
    SYNCTEX_TEST_BODY(TC, synctex_node_tag(proxy) == 421, "");
    synctex_node_free(proxy);
    synctex_node_free(target);
    return TC;
}
int synctex_test_handle(synctex_scanner_p scanner)
{
    int TC = 0;
    synctex_node_p handle = synctex_node_new(scanner, synctex_node_type_handle);
    synctex_node_p proxy = synctex_node_new(scanner, synctex_node_type_proxy);
    synctex_node_p target = synctex_node_new(scanner, synctex_node_type_rule);
    _synctex_tree_set_target(handle, target);
    _synctex_data_set_tag(target, 421);
    SYNCTEX_TEST_BODY(TC, _synctex_data_tag(target) == 421, "");
    SYNCTEX_TEST_BODY(TC, synctex_node_tag(target) == 421, "");
    SYNCTEX_TEST_BODY(TC, synctex_node_tag(handle) == 421, "");
    _synctex_data_set_line(target, 214);
    SYNCTEX_TEST_BODY(TC, _synctex_data_line(target) == 214, "");
    SYNCTEX_TEST_BODY(TC, synctex_node_line(target) == 214, "");
    SYNCTEX_TEST_BODY(TC, synctex_node_line(handle) == 214, "");
    _synctex_data_set_column(target, 142);
    SYNCTEX_TEST_BODY(TC, _synctex_data_column(target) == 142, "");
    SYNCTEX_TEST_BODY(TC, synctex_node_column(target) == 142, "");
    SYNCTEX_TEST_BODY(TC, synctex_node_column(handle) == 142, "");
    _synctex_tree_set_target(proxy, target);
    _synctex_tree_set_target(handle, proxy);
    _synctex_data_set_tag(target, 412);
    SYNCTEX_TEST_BODY(TC, _synctex_data_tag(target) == 412, "");
    SYNCTEX_TEST_BODY(TC, synctex_node_tag(target) == 412, "");
    SYNCTEX_TEST_BODY(TC, synctex_node_tag(handle) == 412, "");
    _synctex_data_set_line(target, 124);
    SYNCTEX_TEST_BODY(TC, _synctex_data_line(target) == 124, "");
    SYNCTEX_TEST_BODY(TC, synctex_node_line(target) == 124, "");
    SYNCTEX_TEST_BODY(TC, synctex_node_line(handle) == 124, "");
    _synctex_data_set_column(target, 241);
    SYNCTEX_TEST_BODY(TC, _synctex_data_column(target) == 241, "");
    SYNCTEX_TEST_BODY(TC, synctex_node_column(target) == 241, "");
    SYNCTEX_TEST_BODY(TC, synctex_node_column(handle) == 241, "");
    synctex_node_free(handle);
    synctex_node_free(proxy);
    synctex_node_free(target);
    return TC;
}
int synctex_test_setup_scanner_input(synctex_scanner_p scanner)
{
    int TC = 0;
    synctex_node_p input = synctex_node_new(scanner, synctex_node_type_input);
    _synctex_data_set_tag(input, 4);
    _synctex_input_copy_name(input, "21");
    _synctex_data_set_line(input, 421);
    synctex_node_free(scanner->input);
    scanner->input = input;
    SYNCTEX_TEST_BODY(TC, _synctex_data_tag(input) == 4, "");
    SYNCTEX_TEST_BODY(TC, strcmp(_synctex_data_name(input), "21") == 0, "");
    SYNCTEX_TEST_BODY(TC, _synctex_data_line(input) == 421, "");
    return TC;
}
int synctex_test_setup_nodes(synctex_scanner_p scanner, synctex_node_r nodes)
{
    int TC = 0;
    int n;
    for (n = 0; n < synctex_node_number_of_types; ++n) {
        nodes[n] = synctex_node_new(scanner, n);
        SYNCTEX_TEST_BODY(TC, nodes[n] != NULL, "");
    }
    return TC;
}
int synctex_test_teardown_nodes(synctex_scanner_p scanner, synctex_node_r nodes)
{
    int n;
    for (n = 0; n < synctex_node_number_of_types; ++n) {
        synctex_node_free(nodes[n]);
        nodes[n] = NULL;
    }
    return 1;
}
int synctex_test_tree(synctex_scanner_p scanner)
{
    int TC = 0;
    synctex_node_p nodes1[synctex_node_number_of_types];
    synctex_node_p nodes2[synctex_node_number_of_types];
    synctex_node_p nodes3[synctex_node_number_of_types];
    int i, j;
    TC += synctex_test_setup_nodes(scanner, nodes1);
    TC += synctex_test_setup_nodes(scanner, nodes2);
    TC += synctex_test_setup_nodes(scanner, nodes3);
    /*  Every node has a sibling */
    for (i = 0; i < synctex_node_number_of_types; ++i) {
        for (j = 0; j < synctex_node_number_of_types; ++j) {
            _synctex_tree_set_sibling(nodes1[i], nodes2[i]);
            SYNCTEX_TEST_BODY(TC, nodes2[i] == synctex_node_sibling(nodes1[i]), "");
        }
    }
    synctex_test_teardown_nodes(scanner, nodes3);
    synctex_test_teardown_nodes(scanner, nodes2);
    synctex_test_teardown_nodes(scanner, nodes1);
    return TC;
}
int synctex_test_page(synctex_scanner_p scanner)
{
    int TC = synctex_test_setup_scanner_sheets_421(scanner);
    synctex_node_p sheet = scanner->sheet;
    synctex_node_p node = synctex_node_new(scanner, synctex_node_type_rule);
    _synctex_data_set_tag(node, 4);
    _synctex_data_set_line(node, 21);
    synctex_node_free(_synctex_node_set_child(sheet, node));
    SYNCTEX_TEST_BODY(TC, synctex_node_page(node) == synctex_node_page(sheet), "");
    return TC;
}
int synctex_test_display_query(synctex_scanner_p scanner)
{
    int TC = synctex_test_setup_scanner_sheets_421(scanner);
    synctex_node_p sheet = scanner->sheet;
    synctex_node_p node = synctex_node_new(scanner, synctex_node_type_rule);
    _synctex_data_set_tag(node, 4);
    _synctex_data_set_line(node, 21);
    synctex_node_free(_synctex_node_set_child(sheet, node));
    SYNCTEX_TEST_BODY(TC, node == synctex_node_child(sheet), "");
    __synctex_node_make_friend_tlc(node);
    SYNCTEX_TEST_BODY(TC, _synctex_scanner_friend(scanner, 25) == node, "");
    sheet = __synctex_tree_sibling(sheet);
    node = synctex_node_new(scanner, synctex_node_type_rule);
    _synctex_data_set_tag(node, 4);
    _synctex_data_set_line(node, 21);
    synctex_node_free(_synctex_node_set_child(sheet, node));
    SYNCTEX_TEST_BODY(TC, node == synctex_node_child(sheet), "");
    __synctex_node_make_friend_tlc(node);
    SYNCTEX_TEST_BODY(TC, _synctex_scanner_friend(scanner, 25) == node, "");
    sheet = __synctex_tree_sibling(sheet);
    node = synctex_node_new(scanner, synctex_node_type_rule);
    _synctex_data_set_tag(node, 4);
    _synctex_data_set_line(node, 21);
    synctex_node_free(_synctex_node_set_child(sheet, node));
    SYNCTEX_TEST_BODY(TC, node == synctex_node_child(sheet), "");
    __synctex_node_make_friend_tlc(node);
    SYNCTEX_TEST_BODY(TC, (_synctex_scanner_friend(scanner, 25) == node), "");
    synctex_test_setup_scanner_input(scanner);
    scanner->flags.has_parsed = synctex_YES;
#if 1
    SYNCTEX_TEST_BODY(TC, (synctex_display_query(scanner, "21", 21, 4, -1) == 3), "");
#endif
    return TC;
}
typedef struct {
    int s;      /* status */
    char n[25]; /* name */
} synctex_test_sn_s;

synctex_test_sn_s synctex_test_tmp_sn(char *content)
{
    synctex_test_sn_s sn = {0, "/tmp/test.XXXXXX.synctex"};
    FILE *sfp;
    int fd = mkstemps(sn.n, 8);
    if (fd < 0) {
        fprintf(stderr, "%s: %s\n", sn.n, strerror(errno));
        sn.s = -1;
        return sn;
    }
    if ((sfp = fdopen(fd, "w+")) == NULL) {
        unlink(sn.n);
        close(fd);
        fprintf(stderr, "%s: %s\n", sn.n, strerror(errno));
        sn.s = -2;
        return sn;
    }
    sn.s = fputs(content, sfp);
    printf("temp:%s\n%i\n", sn.n, sn.s);
    fclose(sfp);
    if (sn.s == 0) {
        sn.s = -2;
        unlink(sn.n);
    }
    return sn;
}
int synctex_test_sheet_1()
{
    int TC = 0;
    char *content =
        "SyncTeX Version:1  \n"           /*00-19*/
        "Input:1:./1.tex    \n"           /*20-39*/
        "Output:pdf         \n"           /*40-59*/
        "Magnification:100000000      \n" /*60-89*/
        "Unit:1   \n"                     /*90-99*/
        "X Offset:0         \n"           /*00-19*/
        "Y Offset:0         \n"           /*20-39*/
        "Content: \n"                     /*40-49*/
        "{1       \n"                     /*50-59*/
        "[1,10:20,350:330,330,0       \n" /*60-89*/
        "]        \n"                     /*90-99*/
        "}        \n"                     /*00-09*/
        "Postamble:\n";
    synctex_test_sn_s sn = synctex_test_tmp_sn(content);
    if (sn.s > 0) {
        synctex_scanner_p scanner = synctex_scanner_new_with_output_file(sn.n, NULL, synctex_YES);
        synctex_node_p node = synctex_scanner_handle(scanner);
        printf("Created nodes:\n");
        while (node) {
            printf("%s\n", _synctex_node_abstract(node));
            node = synctex_node_next(node);
        }
        synctex_scanner_free(scanner);
        unlink(sn.n);
    } else {
        ++TC;
    }
    return TC;
}
int synctex_test_sheet_2()
{
    int TC = 0;
    char *content =
        "SyncTeX Version:1  \n"           /*00-19*/
        "Input:1:./1.tex    \n"           /*20-39*/
        "Output:pdf         \n"           /*40-59*/
        "Magnification:100000000      \n" /*60-89*/
        "Unit:1   \n"                     /*90-99*/
        "X Offset:0         \n"           /*00-19*/
        "Y Offset:0         \n"           /*20-39*/
        "Content: \n"                     /*40-49*/
        "{1       \n"                     /*50-59*/
        "(1,10:20,350:330,330,0       \n" /*60-89*/
        ")        \n"                     /*90-99*/
        "}        \n"                     /*00-09*/
        "Postamble:\n";
    synctex_test_sn_s sn = synctex_test_tmp_sn(content);
    if (sn.s > 0) {
        synctex_scanner_p scanner = synctex_scanner_new_with_output_file(sn.n, NULL, synctex_YES);
        synctex_node_p node = synctex_scanner_handle(scanner);
        printf("Created nodes:\n");
        while (node) {
            printf("%s\n", _synctex_node_abstract(node));
            node = _synctex_node_next(node);
        }
        TC += synctex_scanner_free(scanner);
        unlink(sn.n);
    } else {
        ++TC;
    }
    return TC;
}
int synctex_test_charindex()
{
    int TC = 0;
    char *content =
        "SyncTeX Version:1  \n"           /*00-19*/
        "Input:1:./1.tex    \n"           /*20-39*/
        "Output:pdf         \n"           /*40-59*/
        "Magnification:100000000      \n" /*60-89*/
        "Unit:1   \n"                     /*90-99*/
        "X Offset:0         \n"           /*00-19*/
        "Y Offset:0         \n"           /*20-39*/
        "Content: \n"                     /*40-49*/
        "{1       \n"                     /*50-59*/
        "[1,10:20,350:330,330,0       \n" /*60-89*/
        "(1,58:20,100:250,10,5        \n" /*90-119*/
        "f1000:50,100       \n"           /*20-39*/
        ")        \n"                     /*40-49*/
        "]        \n"                     /*50-59*/
        "}        \n"                     /*60-69*/
        "Postamble:\n";
    synctex_test_sn_s sn = synctex_test_tmp_sn(content);
    if (sn.s > 0) {
        synctex_scanner_p scanner = synctex_scanner_new_with_output_file(sn.n, NULL, synctex_YES);
        synctex_node_p node = synctex_scanner_handle(scanner);
        printf("Created nodes:\n");
        while (node) {
            printf("%s\n", _synctex_node_abstract(node));
            node = synctex_node_next(node);
        }
        TC += synctex_scanner_free(scanner);
        unlink(sn.n);
    } else {
        ++TC;
    }
    return TC;
}
int synctex_test_form()
{
    int TC = 0;
    char *content =
        "SyncTeX Version:1  \n"           /*00-19*/
        "Input:1:./1.tex    \n"           /*20-39*/
        "Output:pdf         \n"           /*40-59*/
        "Magnification:100000000      \n" /*60-89*/
        "Unit:1   \n"                     /*90-99*/
        "X Offset:0         \n"           /*00-19*/
        "Y Offset:0         \n"           /*20-39*/
        "Content: \n"                     /*40-49*/
        "{1       \n"                     /*50-59*/
        "[1,10:20,350:330,330,0       \n" /*60-89*/
        "(1,58:20,100:250,10,5        \n" /*90-119*/
        "f1000:50,100       \n"           /*20-39*/
        ")        \n"                     /*40-49*/
        "]        \n"                     /*50-59*/
        "}        \n"                     /*60-69*/
        "<1000    \n"                     /*70-79*/
        "(1,63:0,0:100,8,3  \n"           /*80-99*/
        ")        \n"                     /*00-09*/
        ">        \n"                     /*10-19*/
        "Postamble:\n";
    synctex_test_sn_s sn = synctex_test_tmp_sn(content);
    if (sn.s > 0) {
        synctex_scanner_p scanner = synctex_scanner_new_with_output_file(sn.n, NULL, synctex_YES);
        synctex_node_p node = synctex_scanner_handle(scanner);
        while (node) {
            printf("%s\n", _synctex_node_abstract(node));
            node = _synctex_node_next(node);
        }
        TC += synctex_scanner_free(scanner);
        unlink(sn.n);
    } else {
        ++TC;
    }
    return TC;
}
#endif
