summaryrefslogtreecommitdiff
path: root/cut-n-paste/synctex/synctex_parser.c
diff options
context:
space:
mode:
authorrbuj <[email protected]>2019-08-21 23:07:52 +0200
committerraveit65 <[email protected]>2019-08-29 12:00:35 +0200
commit6061cf30d7a351d7214ee074e4530fb8b9d4e94c (patch)
tree017eb17cf1f61084b9162a52834ac06a83dcc088 /cut-n-paste/synctex/synctex_parser.c
parent7dc6ac4dde817633a82f35cfb4f19102ea94b272 (diff)
downloadatril-6061cf30d7a351d7214ee074e4530fb8b9d4e94c.tar.bz2
atril-6061cf30d7a351d7214ee074e4530fb8b9d4e94c.tar.xz
Bump synctex to 1.21
$ cd cut-n-paste/synctex $ rm synctex_* $ ./update-synctex-from-TL.sh Test on Fedora: 1. Install required packages $ sudo dnf install texlive-scheme-basic texlive-lipsum -y 2. Build a pdf with synctex enabled $ cat <<EOF >> file.tex \documentclass[12pt]{report} \usepackage{lipsum} \begin{document} \chapter{Introduction} \lipsum[2-4] \end{document} EOF $ pdflatex -synctex=1 file.tex 3. Open file.pdf using atril 4. Search any text string
Diffstat (limited to 'cut-n-paste/synctex/synctex_parser.c')
-rw-r--r--cut-n-paste/synctex/synctex_parser.c12284
1 files changed, 8398 insertions, 3886 deletions
diff --git a/cut-n-paste/synctex/synctex_parser.c b/cut-n-paste/synctex/synctex_parser.c
index 830961a3..f4f7d848 100644
--- a/cut-n-paste/synctex/synctex_parser.c
+++ b/cut-n-paste/synctex/synctex_parser.c
@@ -1,56 +1,52 @@
/*
-Copyright (c) 2008, 2009, 2010 , 2011 jerome DOT laurens AT u-bourgogne DOT fr
-
-This file is part of the SyncTeX package.
-
-Latest Revision: Tue Jun 14 08:23:30 UTC 2011
-
-Version: 1.18
-
-See synctex_parser_readme.txt for more details
-
-License:
---------
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE
-
-Except as contained in this notice, the name of the copyright holder
-shall not be used in advertising or otherwise to promote the sale,
-use or other dealings in this Software without prior written
-authorization from the copyright holder.
-
-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.
-
-Version 1
-Thu Jun 19 09:39:21 UTC 2008
-
-*/
+ Copyright (c) 2008-2017 jerome DOT laurens AT u-bourgogne DOT fr
+
+ This file is part of the __SyncTeX__ package.
+
+ [//]: # (Latest Revision: Sun Oct 15 15:09:55 UTC 2017)
+ [//]: # (Version: 1.21)
+
+ See `synctex_parser_readme.md` for more details
+
+ ## License
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE
+
+ Except as contained in this notice, the name of the copyright holder
+ shall not be used in advertising or otherwise to promote the sale,
+ use or other dealings in this Software without prior written
+ authorization from the copyright holder.
+
+ 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.
@@ -59,6 +55,34 @@ Thu Jun 19 09:39:21 UTC 2008
* 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.21
+ * \date Sun Oct 15 15:09:55 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
@@ -72,6 +96,7 @@ Thu Jun 19 09:39:21 UTC 2008
# endif
#include <stdlib.h>
+#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
@@ -81,688 +106,2763 @@ Thu Jun 19 09:39:21 UTC 2008
#include <locale.h>
#endif
-/* 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 leaf 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, containing boxes, glues, kerns...
- * The third tree allows to browse leaves according to tag and line.
- */
+/* Mark unused parameters, so that there will be no compile warnings. */
+#ifdef __DARWIN_UNIX03
+# define SYNCTEX_UNUSED(x) SYNCTEX_PRAGMA(unused(x))
+# define SYNCTEX_PRAGMA(x) _Pragma ( #x )
+#else
+# define SYNCTEX_UNUSED(x) (void)(x);
+#endif
-#include "synctex_parser.h"
-#include "synctex_parser_utils.h"
+#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";
-/* each synctex node has a class */
-typedef struct __synctex_class_t _synctex_class_t;
-typedef _synctex_class_t * synctex_class_t;
+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.
+ * The class points to various methods,
+ * each of them vary amongst objects.
+ * Each class has a data model which stores node's attributes.
+ * Each class has an tree model which stores children and parent.
+ * Inspectors give access to data and tree elements.
+ */
+
+/* 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;
+
+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) {
+ SYNCTEX_UNUSED(node)
+ 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) {
+ SYNCTEX_UNUSED(node)
+ 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", well 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
-/* synctex_node_t is a pointer to a node
- * _synctex_node is the target of the synctex_node_t pointer
- * It is a pseudo object oriented program.
- * class is a pointer to the class object the node belongs to.
- * implementation is meant to contain the private data of the node
- * basically, there are 2 kinds of information: navigation information and
- * synctex information. Both will depend on the type of the node,
- * thus different nodes will have different private data.
- * There is no inheritancy overhead.
+/**
+ * \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
*/
-typedef union _synctex_info_t {
- int INT;
- char * PTR;
-} synctex_info_t;
+# 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_DECLARE_CHARINDEX synctex_charindex_t char_index;
# define SYNCTEX_CHARINDEX(NODE) (NODE->char_index)
-# define SYNCTEX_PRINT_CHARINDEX printf("#%i\n",SYNCTEX_CHARINDEX(node))
-# define SYNCTEX_DECLARE_CHAR_OFFSET synctex_charindex_t charindex_offset
-# define SYNCTEX_IMPLEMENT_CHARINDEX(NODE,CORRECTION) NODE->char_index = (synctex_charindex_t)(scanner->charindex_offset+SYNCTEX_CUR-SYNCTEX_START+(CORRECTION));
+# 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_DECLARE_CHARINDEX
# define SYNCTEX_CHARINDEX(NODE) 0
-# define SYNCTEX_PRINT_CHARINDEX printf("\n")
-# define SYNCTEX_DECLARE_CHAR_OFFSET synctex_charindex_t charindex_offset
+# 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
-struct _synctex_node {
- SYNCTEX_DECLARE_CHARINDEX
- synctex_class_t class;
- synctex_info_t * implementation;
-};
+/**
+ * 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
-/* Each node of the tree, except the scanner itself belongs to a class.
- * The class object is just a struct declaring the owning scanner
- * This is a pointer to the scanner as root of the tree.
- * The type is used to identify the kind of node.
- * The class declares pointers to a creator and a destructor method.
- * The log and display fields are used to log and display the node.
- * display will also display the child, sibling and parent sibling.
- * parent, child and sibling are used to navigate the tree,
- * from TeX box hierarchy point of view.
- * The friend field points to a method which allows to navigate from friend to friend.
- * A friend is a node with very close tag and line numbers.
- * Finally, the info field point to a method giving the private node info offset.
- */
-
-typedef synctex_node_t *(*_synctex_node_getter_t)(synctex_node_t);
-typedef synctex_info_t *(*_synctex_info_getter_t)(synctex_node_t);
-
-struct __synctex_class_t {
- synctex_scanner_t scanner;
- int type;
- synctex_node_t (*new)(synctex_scanner_t scanner);
- void (*free)(synctex_node_t);
- void (*log)(synctex_node_t);
- void (*display)(synctex_node_t);
- _synctex_node_getter_t parent;
- _synctex_node_getter_t child;
- _synctex_node_getter_t sibling;
- _synctex_node_getter_t friend;
- _synctex_node_getter_t next_hbox;
- _synctex_info_getter_t info;
-};
+#if 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_GETSETRESET(target)
+
+#if SYNCTEX_DEBUG>1000
+# undef SYNCTEX_USE_NODE_COUNT
+# define SYNCTEX_USE_NODE_COUNT 1
+#endif
+#if 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 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 Abstract OBJECTS and METHODS
+# 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)
-/* These macros are shortcuts
- * This macro checks if a message can be sent.
- */
-# define SYNCTEX_CAN_PERFORM(NODE,SELECTOR)\
- (NULL!=((((NODE)->class))->SELECTOR))
+# ifdef SYNCTEX_NOTHING
+# pragma mark -
+# pragma mark File reader
+# endif
-/* This macro is some kind of objc_msg_send.
- * It takes care of sending the proper message if possible.
+/* 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_MSG_SEND(NODE,SELECTOR) if (NODE && SYNCTEX_CAN_PERFORM(NODE,SELECTOR)) {\
- (*((((NODE)->class))->SELECTOR))(NODE);\
- }
+# define SYNCTEX_BUFFER_MIN_SIZE 32
+# define SYNCTEX_BUFFER_SIZE 32768
-/* read only safe getter
- */
-# define SYNCTEX_GET(NODE,SELECTOR)((NODE && SYNCTEX_CAN_PERFORM(NODE,SELECTOR))?SYNCTEX_GETTER(NODE,SELECTOR)[0]:(NULL))
+#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
-/* read/write getter
- */
-# define SYNCTEX_GETTER(NODE,SELECTOR)\
- ((synctex_node_t *)((*((((NODE)->class))->SELECTOR))(NODE)))
+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;
-# define SYNCTEX_FREE(NODE) SYNCTEX_MSG_SEND(NODE,free);
+typedef struct {
+ synctex_status_t status;
+ char * synctex;
+ gzFile file;
+ synctex_io_mode_t io_mode;
+} synctex_open_s;
-/* Parent getter and setter
+/* 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.
*/
-# define SYNCTEX_PARENT(NODE) SYNCTEX_GET(NODE,parent)
-# define SYNCTEX_SET_PARENT(NODE,NEW_PARENT) if (NODE && NEW_PARENT && SYNCTEX_CAN_PERFORM(NODE,parent)){\
- SYNCTEX_GETTER(NODE,parent)[0]=NEW_PARENT;\
- }
+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 successfull, return the arguments by value. */
+ open.status = SYNCTEX_STATUS_OK;
+ return open;
+}
-/* Child getter and setter
+/* Opens the ouput 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.
*/
-# define SYNCTEX_CHILD(NODE) SYNCTEX_GET(NODE,child)
-# define SYNCTEX_SET_CHILD(NODE,NEW_CHILD) if (NODE && NEW_CHILD){\
- SYNCTEX_GETTER(NODE,child)[0]=NEW_CHILD;\
- SYNCTEX_GETTER(NEW_CHILD,parent)[0]=NODE;\
- }
-
-/* Sibling getter and setter
+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.
*/
-# define SYNCTEX_SIBLING(NODE) SYNCTEX_GET(NODE,sibling)
-# define SYNCTEX_SET_SIBLING(NODE,NEW_SIBLING) if (NODE && NEW_SIBLING) {\
- SYNCTEX_GETTER(NODE,sibling)[0]=NEW_SIBLING;\
- if (SYNCTEX_CAN_PERFORM(NEW_SIBLING,parent) && SYNCTEX_CAN_PERFORM(NODE,parent)) {\
- SYNCTEX_GETTER(NEW_SIBLING,parent)[0]=SYNCTEX_GETTER(NODE,parent)[0];\
- }\
- }
-/* Friend getter and setter. A friend is a kern, math, glue or void box node which tag and line numbers are similar.
- * This is a first filter on the nodes that avoids testing all of them.
- * Friends are used mainly in forward synchronization aka from source to output.
+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) {
+ 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.");
+ bailey:
+#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.
*/
-# define SYNCTEX_FRIEND(NODE) SYNCTEX_GET(NODE,friend)
-# define SYNCTEX_SET_FRIEND(NODE,NEW_FRIEND) if (NODE && NEW_FRIEND){\
- SYNCTEX_GETTER(NODE,friend)[0]=NEW_FRIEND;\
- }
+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;
+};
-/* Next box getter and setter. The box tree can be traversed from one horizontal box to the other.
- * Navigation starts with the deeper boxes.
+/**
+ * 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.
*/
-# define SYNCTEX_NEXT_hbox(NODE) SYNCTEX_GET(NODE,next_hbox)
-# define SYNCTEX_SET_NEXT_hbox(NODE,NEXT_HBOX) if (NODE && NEXT_HBOX){\
- SYNCTEX_GETTER(NODE,next_hbox)[0]=NEXT_HBOX;\
- }
+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 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
-/* A node is meant to own its child and sibling.
+/**
+ * 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_t node) {
- if (node) {
- (*((node->class)->sibling))(node);
- SYNCTEX_FREE(SYNCTEX_SIBLING(node));
- SYNCTEX_FREE(SYNCTEX_CHILD(node));
- free(node);
- }
- return;
+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 handle.
+ * - 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 handles.
+ */
+static void _synctex_free_handle(synctex_node_p handle) {
+ if (handle) {
+ _synctex_free_handle(__synctex_tree_sibling(handle));
+ _synctex_free_handle(_synctex_tree_child(handle));
+ _synctex_free(handle);
+ }
+ return;
}
-/* A node is meant to own its child and sibling.
+/**
+ * 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 nodes with no child.
- * The first sheet is onwned by the scanner.
+ * This destructor is for all nodes with no children.
*/
-static void _synctex_free_leaf(synctex_node_t node) {
- if (node) {
- SYNCTEX_FREE(SYNCTEX_SIBLING(node));
- free(node);
- }
- return;
+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;
}
-# ifdef __SYNCTEX_WORK__
-# include "/usr/include/zlib.h"
-# else
-# include <zlib.h>
-# 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 {
- gzFile file; /* The (possibly compressed) file */
- SYNCTEX_DECLARE_CHAR_OFFSET;
- char * buffer_cur; /* current location in the buffer */
- char * buffer_start; /* start of the buffer */
- char * buffer_end; /* end of the buffer */
- char * output_fmt; /* dvi or pdf, not yet used */
- char * output; /* the output name used to create the scanner */
- char * synctex; /* the .synctex or .synctex.gz name used to create the scanner */
- int version; /* 1, not yet used */
- struct {
- unsigned has_parsed:1; /* Whether the scanner has parsed its underlying synctex file. */
- unsigned reserved:sizeof(unsigned)-1; /* alignment */
- } flags;
- int pre_magnification; /* magnification from the synctex preamble */
- int pre_unit; /* unit from the synctex preamble */
- int pre_x_offset; /* X offste 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_t sheet; /* The first sheet node, its siblings are the other sheet nodes */
- synctex_node_t input; /* The first input node, its siblings are the other input nodes */
- int number_of_lists; /* The number of friend lists */
- synctex_node_t * lists_of_friends;/* The friend lists */
- _synctex_class_t class[synctex_node_number_of_types]; /* The classes of the nodes of the scanner */
-};
+/**
+ 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)
-/* SYNCTEX_CUR, SYNCTEX_START and SYNCTEX_END are convenient shortcuts
+/* 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
*/
-# define SYNCTEX_CUR (scanner->buffer_cur)
-# define SYNCTEX_START (scanner->buffer_start)
-# define SYNCTEX_END (scanner->buffer_end)
+#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 OBJECTS, their creators and destructors.
+# 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
-/* Here, we define the indices for the different informations.
- * They are used to declare the size of the implementation.
- * For example, if one object uses SYNCTEX_HORIZ_IDX is its size,
- * then its info will contain a tag, line, column, horiz but no width nor height nor depth
+/**
+ * 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 char * _synctex_data_set_##WHAT(synctex_node_p node, char * new_value) {\
+ 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 parent is the scanner itself)
+ * 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.
*/
-/* The next macros are used to access the node info
- * SYNCTEX_INFO(node) points to the first synctex integer or pointer data of node
- * SYNCTEX_INFO(node)[index] is the information at index
- * for example, the page of a sheet is stored in SYNCTEX_INFO(sheet)[SYNCTEX_PAGE_IDX]
- */
-# define SYNCTEX_INFO(NODE) ((*((((NODE)->class))->info))(NODE))
-# define SYNCTEX_PAGE_IDX 0
-# define SYNCTEX_PAGE(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_PAGE_IDX].INT
-/* This macro defines implementation offsets
- * It is only used for pointer values
+# ifdef SYNCTEX_NOTHING
+# pragma mark sheet.
+# endif
+/**
+ * Every node has the same structure, but not the same size.
*/
-# define SYNCTEX_MAKE_GET(SYNCTEX_GETTER,OFFSET)\
-static synctex_node_t * SYNCTEX_GETTER (synctex_node_t node) {\
- return node?(synctex_node_t *)((&((node)->implementation))+OFFSET):NULL;\
-}
-SYNCTEX_MAKE_GET(_synctex_implementation_0,0)
-SYNCTEX_MAKE_GET(_synctex_implementation_1,1)
-SYNCTEX_MAKE_GET(_synctex_implementation_2,2)
-SYNCTEX_MAKE_GET(_synctex_implementation_3,3)
-SYNCTEX_MAKE_GET(_synctex_implementation_4,4)
-SYNCTEX_MAKE_GET(_synctex_implementation_5,5)
+
+DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(page)
typedef struct {
SYNCTEX_DECLARE_CHARINDEX
- synctex_class_t class;
- synctex_info_t implementation[3+SYNCTEX_PAGE_IDX+1];/* child, sibling, next box,
- * SYNCTEX_PAGE_IDX */
-} synctex_node_sheet_t;
+ 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_NODE(NAME)\
-static synctex_node_t _synctex_new_##NAME(synctex_scanner_t scanner) {\
- if (scanner) {\
- synctex_node_t node = _synctex_malloc(sizeof(synctex_node_##NAME##_t));\
- if (node) {\
- SYNCTEX_IMPLEMENT_CHARINDEX(node,0);\
- ++SYNCTEX_CUR;\
- node->class = scanner->class+synctex_node_type_##NAME;\
- }\
- return node;\
- }\
- return NULL;\
-}
-DEFINE_synctex_new_NODE(sheet)
-
-static void _synctex_display_sheet(synctex_node_t node);
-static void _synctex_log_sheet(synctex_node_t node);
-
-static _synctex_class_t 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 */
- NULL, /* No parent */
- &_synctex_implementation_0, /* child */
- &_synctex_implementation_1, /* sibling */
- NULL, /* No friend */
- &_synctex_implementation_2, /* Next hbox */
- (_synctex_info_getter_t)&_synctex_implementation_3 /* info */
+#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 kind of boxes.
+ * There are different kinds of boxes.
* Only horizontal boxes are treated differently because of their visible size.
*/
-# define SYNCTEX_TAG_IDX 0
-# define SYNCTEX_LINE_IDX (SYNCTEX_TAG_IDX+1)
-# define SYNCTEX_COLUMN_IDX (SYNCTEX_LINE_IDX+1)
-# define SYNCTEX_HORIZ_IDX (SYNCTEX_COLUMN_IDX+1)
-# define SYNCTEX_VERT_IDX (SYNCTEX_HORIZ_IDX+1)
-# define SYNCTEX_WIDTH_IDX (SYNCTEX_VERT_IDX+1)
-# define SYNCTEX_HEIGHT_IDX (SYNCTEX_WIDTH_IDX+1)
-# define SYNCTEX_DEPTH_IDX (SYNCTEX_HEIGHT_IDX+1)
-/* the corresponding info accessors */
-# define SYNCTEX_TAG(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_TAG_IDX].INT
-# define SYNCTEX_LINE(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_LINE_IDX].INT
-# define SYNCTEX_COLUMN(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_COLUMN_IDX].INT
-# define SYNCTEX_HORIZ(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HORIZ_IDX].INT
-# define SYNCTEX_VERT(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_VERT_IDX].INT
-# define SYNCTEX_WIDTH(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_WIDTH_IDX].INT
-# define SYNCTEX_HEIGHT(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HEIGHT_IDX].INT
-# define SYNCTEX_DEPTH(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_DEPTH_IDX].INT
-# define SYNCTEX_ABS_WIDTH(NODE) ((SYNCTEX_WIDTH(NODE)>0?SYNCTEX_WIDTH(NODE):-SYNCTEX_WIDTH(NODE)))
-# define SYNCTEX_ABS_HEIGHT(NODE) ((SYNCTEX_HEIGHT(NODE)>0?SYNCTEX_HEIGHT(NODE):-SYNCTEX_HEIGHT(NODE)))
-# define SYNCTEX_ABS_DEPTH(NODE) ((SYNCTEX_DEPTH(NODE)>0?SYNCTEX_DEPTH(NODE):-SYNCTEX_DEPTH(NODE)))
-
typedef struct {
SYNCTEX_DECLARE_CHARINDEX
- synctex_class_t class;
- synctex_info_t implementation[5+SYNCTEX_DEPTH_IDX+1]; /* parent,child,sibling,friend,next box,
- * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
- * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH */
-} synctex_node_vbox_t;
+ 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_NODE(vbox)
+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
+};
-static void _synctex_log_vbox(synctex_node_t node);
-static void _synctex_display_vbox(synctex_node_t node);
+#define SYNCTEX_DFLT_COLUMN -1
+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,
+ SYNCTEX_DFLT_COLUMN);
+ 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)
+
+SYNCTEX_INLINE static void _synctex_data_set_tlc(synctex_node_p node, synctex_node_p model) {
+ _synctex_data_set_tag(node, _synctex_data_tag(model));
+ _synctex_data_set_line(node, _synctex_data_line(model));
+ _synctex_data_set_column(node, _synctex_data_column(model));
+}
+SYNCTEX_INLINE static void _synctex_data_set_tlchv(synctex_node_p node, synctex_node_p model) {
+ _synctex_data_set_tlc(node,model);
+ _synctex_data_set_h(node, _synctex_data_h(model));
+ _synctex_data_set_v(node, _synctex_data_v(model));
+}
+
+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_t 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_implementation_0, /* parent */
- &_synctex_implementation_1, /* child */
- &_synctex_implementation_2, /* sibling */
- &_synctex_implementation_3, /* friend */
- &_synctex_implementation_4, /* next hbox */
- (_synctex_info_getter_t)&_synctex_implementation_5
+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. */
-# define SYNCTEX_MEAN_LINE_IDX (SYNCTEX_DEPTH_IDX+1)
-# define SYNCTEX_NODE_WEIGHT_IDX (SYNCTEX_MEAN_LINE_IDX+1)
-# define SYNCTEX_HORIZ_V_IDX (SYNCTEX_NODE_WEIGHT_IDX+1)
-# define SYNCTEX_VERT_V_IDX (SYNCTEX_HORIZ_V_IDX+1)
-# define SYNCTEX_WIDTH_V_IDX (SYNCTEX_VERT_V_IDX+1)
-# define SYNCTEX_HEIGHT_V_IDX (SYNCTEX_WIDTH_V_IDX+1)
-# define SYNCTEX_DEPTH_V_IDX (SYNCTEX_HEIGHT_V_IDX+1)
-/* the corresponding info accessors */
-# define SYNCTEX_MEAN_LINE(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_MEAN_LINE_IDX].INT
-# define SYNCTEX_NODE_WEIGHT(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_NODE_WEIGHT_IDX].INT
-# define SYNCTEX_HORIZ_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HORIZ_V_IDX].INT
-# define SYNCTEX_VERT_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_VERT_V_IDX].INT
-# define SYNCTEX_WIDTH_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_WIDTH_V_IDX].INT
-# define SYNCTEX_HEIGHT_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HEIGHT_V_IDX].INT
-# define SYNCTEX_DEPTH_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_DEPTH_V_IDX].INT
-# define SYNCTEX_ABS_WIDTH_V(NODE) ((SYNCTEX_WIDTH_V(NODE)>0?SYNCTEX_WIDTH_V(NODE):-SYNCTEX_WIDTH_V(NODE)))
-# define SYNCTEX_ABS_HEIGHT_V(NODE) ((SYNCTEX_HEIGHT_V(NODE)>0?SYNCTEX_HEIGHT_V(NODE):-SYNCTEX_HEIGHT_V(NODE)))
-# define SYNCTEX_ABS_DEPTH_V(NODE) ((SYNCTEX_DEPTH_V(NODE)>0?SYNCTEX_DEPTH_V(NODE):-SYNCTEX_DEPTH_V(NODE)))
+
+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 bouding box is bigger ence 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_t class;
- synctex_info_t implementation[5+SYNCTEX_DEPTH_V_IDX+1]; /*parent,child,sibling,friend,next box,
- * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
- * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH,
- * SYNCTEX_MEAN_LINE,SYNCTEX_NODE_WEIGHT,
- * SYNCTEX_HORIZ_V,SYNCTEX_VERT_V,SYNCTEX_WIDTH_V,SYNCTEX_HEIGHT_V,SYNCTEX_DEPTH_V*/
-} synctex_node_hbox_t;
+ 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_NODE(hbox)
-
-static void _synctex_display_hbox(synctex_node_t node);
-static void _synctex_log_hbox(synctex_node_t node);
-
-
-static _synctex_class_t 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_implementation_0, /* parent */
- &_synctex_implementation_1, /* child */
- &_synctex_implementation_2, /* sibling */
- &_synctex_implementation_3, /* friend */
- &_synctex_implementation_4, /* next hbox */
- (_synctex_info_getter_t)&_synctex_implementation_5
+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_t class;
- synctex_info_t implementation[3+SYNCTEX_DEPTH_IDX+1]; /* parent,sibling,friend,
- * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
- * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH*/
-} synctex_node_void_vbox_t;
+ 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_NODE(void_vbox)
-
-static void _synctex_log_void_box(synctex_node_t node);
-static void _synctex_display_void_vbox(synctex_node_t node);
-
-static _synctex_class_t synctex_class_void_vbox = {
- NULL, /* No scanner yet */
- synctex_node_type_void_vbox,/* Node type */
- &_synctex_new_void_vbox, /* creator */
- &_synctex_free_node, /* destructor */
- &_synctex_log_void_box, /* log */
- &_synctex_display_void_vbox,/* display */
- &_synctex_implementation_0, /* parent */
- NULL, /* No child */
- &_synctex_implementation_1, /* sibling */
- &_synctex_implementation_2, /* friend */
- NULL, /* No next hbox */
- (_synctex_info_getter_t)&_synctex_implementation_3
+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 */
};
-typedef synctex_node_void_vbox_t synctex_node_void_hbox_t;
+# 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_NODE(void_hbox)
-
-static void _synctex_display_void_hbox(synctex_node_t node);
-
-static _synctex_class_t synctex_class_void_hbox = {
- NULL, /* No scanner yet */
- synctex_node_type_void_hbox,/* Node type */
- &_synctex_new_void_hbox, /* creator */
- &_synctex_free_node, /* destructor */
- &_synctex_log_void_box, /* log */
- &_synctex_display_void_hbox,/* display */
- &_synctex_implementation_0, /* parent */
- NULL, /* No child */
- &_synctex_implementation_1, /* sibling */
- &_synctex_implementation_2, /* friend */
- NULL, /* No next hbox */
- (_synctex_info_getter_t)&_synctex_implementation_3
+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 */
};
-/* The medium nodes correspond to kern, glue, penalty and math nodes.
- * In LuaTeX, the size of the nodes may have changed. */
+# ifdef SYNCTEX_NOTHING
+# pragma mark form ref.
+# endif
+
+/* The form ref node. */
typedef struct {
SYNCTEX_DECLARE_CHARINDEX
- synctex_class_t class;
- synctex_info_t implementation[3+SYNCTEX_WIDTH_IDX+1]; /* parent,sibling,friend,
- * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
- * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH */
-} synctex_node_medium_t;
+ 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 */
+ -1, /* name */
+ -1, /* page */
+ synctex_data_ref_thv_max /* size */
+};
+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
-#define SYNCTEX_IS_BOX(NODE)\
- ((NODE->class->type == synctex_node_type_vbox)\
- || (NODE->class->type == synctex_node_type_void_vbox)\
- || (NODE->class->type == synctex_node_type_hbox)\
- || (NODE->class->type == synctex_node_type_void_hbox))
+/* 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;
-#define SYNCTEX_HAS_CHILDREN(NODE) (NODE && SYNCTEX_CHILD(NODE))
+static void _synctex_log_tlchv_node(synctex_node_p node);
-static void _synctex_log_medium_node(synctex_node_t node);
+# ifdef SYNCTEX_NOTHING
+# pragma mark math.
+# endif
-typedef synctex_node_medium_t synctex_node_math_t;
+typedef synctex_node_tlchv_s synctex_node_math_s;
/* math node creator */
-DEFINE_synctex_new_NODE(math)
-
-static void _synctex_display_math(synctex_node_t node);
-
-static _synctex_class_t synctex_class_math = {
- NULL, /* No scanner yet */
- synctex_node_type_math, /* Node type */
- &_synctex_new_math, /* creator */
- &_synctex_free_leaf, /* destructor */
- &_synctex_log_medium_node, /* log */
- &_synctex_display_math, /* display */
- &_synctex_implementation_0, /* parent */
- NULL, /* No child */
- &_synctex_implementation_1, /* sibling */
- &_synctex_implementation_2, /* friend */
- NULL, /* No next hbox */
- (_synctex_info_getter_t)&_synctex_implementation_3
+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,
};
-typedef synctex_node_medium_t synctex_node_kern_t;
+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_NODE(kern)
-
-static void _synctex_display_kern(synctex_node_t node);
-
-static _synctex_class_t synctex_class_kern = {
- NULL, /* No scanner yet */
- synctex_node_type_kern, /* Node type */
- &_synctex_new_kern, /* creator */
- &_synctex_free_leaf, /* destructor */
- &_synctex_log_medium_node, /* log */
- &_synctex_display_kern, /* display */
- &_synctex_implementation_0, /* parent */
- NULL, /* No child */
- &_synctex_implementation_1, /* sibling */
- &_synctex_implementation_2, /* friend */
- NULL, /* No next hbox */
- (_synctex_info_getter_t)&_synctex_implementation_3
+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_t class;
- synctex_info_t implementation[3+SYNCTEX_VERT_IDX+1]; /* parent,sibling,friend,
- * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
- * SYNCTEX_HORIZ,SYNCTEX_VERT */
-} synctex_node_small_t;
-
-static void _synctex_log_small_node(synctex_node_t node);
+ 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,
+};
-/* glue node creator */
-typedef synctex_node_small_t synctex_node_glue_t;
-DEFINE_synctex_new_NODE(glue)
-static void _synctex_display_glue(synctex_node_t node);
-
-static _synctex_class_t synctex_class_glue = {
- NULL, /* No scanner yet */
- synctex_node_type_glue, /* Node type */
- &_synctex_new_glue, /* creator */
- &_synctex_free_leaf, /* destructor */
- &_synctex_log_medium_node, /* log */
- &_synctex_display_glue, /* display */
- &_synctex_implementation_0, /* parent */
- NULL, /* No child */
- &_synctex_implementation_1, /* sibling */
- &_synctex_implementation_2, /* friend */
- NULL, /* No next hbox */
- (_synctex_info_getter_t)&_synctex_implementation_3
+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_small_t synctex_node_boundary_t;
-DEFINE_synctex_new_NODE(boundary)
-
-static void _synctex_display_boundary(synctex_node_t node);
-
-static _synctex_class_t synctex_class_boundary = {
- NULL, /* No scanner yet */
- synctex_node_type_boundary, /* Node type */
- &_synctex_new_boundary, /* creator */
- &_synctex_free_leaf, /* destructor */
- &_synctex_log_small_node, /* log */
- &_synctex_display_boundary, /* display */
- &_synctex_implementation_0, /* parent */
- NULL, /* No child */
- &_synctex_implementation_1, /* sibling */
- &_synctex_implementation_2, /* friend */
- NULL, /* No next hbox */
- (_synctex_info_getter_t)&_synctex_implementation_3
+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 */
};
-# define SYNCTEX_NAME_IDX (SYNCTEX_TAG_IDX+1)
-# define SYNCTEX_NAME(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_NAME_IDX].PTR
+# ifdef SYNCTEX_NOTHING
+# pragma mark box boundary.
+# endif
-/* Input nodes only know about their sibling, which is another input node.
- * The synctex information is the SYNCTEX_TAG and SYNCTEX_NAME*/
typedef struct {
SYNCTEX_DECLARE_CHARINDEX
- synctex_class_t class;
- synctex_info_t implementation[1+SYNCTEX_NAME_IDX+1]; /* sibling,
- * SYNCTEX_TAG,SYNCTEX_NAME */
-} synctex_input_t;
+ 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 */
+};
-# define SYNCTEX_INPUT_MARK "Input:"
-static synctex_node_t _synctex_new_input(synctex_scanner_t scanner) {
- if (scanner) {
- synctex_node_t node = _synctex_malloc(sizeof(synctex_input_t));
- if (node) {
- SYNCTEX_IMPLEMENT_CHARINDEX(node,strlen(SYNCTEX_INPUT_MARK));
- node->class = scanner->class+synctex_node_type_input;
- }
- return node;
- }
- return NULL;
-}
-
-static void _synctex_free_input(synctex_node_t node){
- if (node) {
- SYNCTEX_FREE(SYNCTEX_SIBLING(node));
- free(SYNCTEX_NAME(node));
- free(node);
- }
-}
-
-static void _synctex_display_input(synctex_node_t node);
-static void _synctex_log_input(synctex_node_t node);
-
-static _synctex_class_t 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 */
- NULL, /* No parent */
- NULL, /* No child */
- &_synctex_implementation_0, /* sibling */
- NULL, /* No friend */
- NULL, /* No next hbox */
- (_synctex_info_getter_t)&_synctex_implementation_1
+# 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 handle node.
+ * A handle is never the target of a proxy
+ * or another handle.
+ * The child of a handle is always a handle if any.
+ * The sibling of a handle is always a handle if any.
+ * The parent of a handle is always a handle if any.
+ */
+
+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
+};
+
+static const synctex_data_model_s synctex_data_model_handle = {
+ -1, /* tag */
+ -1, /* line */
+ -1, /* column */
+ -1, /* h */
+ -1, /* v */
+ -1, /* width */
+ -1, /* height */
+ -1, /* depth */
+ -1, /* mean_line */
+ synctex_data_handle_w_idx, /* weight */
+ -1, /* h_V */
+ -1, /* v_V */
+ -1, /* width_V */
+ -1, /* height_V */
+ -1, /* depth_V */
+ -1, /* name */
+ -1, /* page */
+ synctex_data_handle_w_max
+};
+
+typedef struct {
+ SYNCTEX_DECLARE_CHARINDEX
+ synctex_class_p class_;
+ synctex_data_u data[synctex_tree_spct_handle_max+synctex_data_handle_w_max];
+} synctex_node_handle_s;
+
+/* handle 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_handle, /* destructor */
+ &_synctex_log_handle, /* log */
+ &_synctex_display_handle, /* display */
+ &_synctex_abstract_handle, /* abstract */
+ &synctex_tree_model_handle, /* tree model */
+ &synctex_data_model_handle, /* 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;
+}
+SYNCTEX_INLINE static synctex_node_p _synctex_new_handle_with_child(synctex_node_p child) {
+ if (child) {
+ synctex_node_p result = _synctex_new_handle(child->class_->scanner);
+ if (result) {
+ _synctex_tree_set_child(result,child);
+ return result;
+ }
+ }
+ return NULL;
+}
+
+# ifdef SYNCTEX_NOTHING
# pragma mark -
# pragma mark Navigation
# endif
-synctex_node_t synctex_node_parent(synctex_node_t node)
+synctex_node_p synctex_node_parent(synctex_node_p node)
{
- return SYNCTEX_PARENT(node);
+ return _synctex_tree_parent(node);
}
-synctex_node_t synctex_node_sheet(synctex_node_t node)
+synctex_node_p synctex_node_parent_sheet(synctex_node_p node)
{
- while(node && node->class->type != synctex_node_type_sheet) {
- node = SYNCTEX_PARENT(node);
- }
- /* exit the while loop either when node is NULL or node is a sheet */
- return 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_t synctex_node_child(synctex_node_t node)
+synctex_node_p synctex_node_parent_form(synctex_node_p node)
{
- return SYNCTEX_CHILD(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;
}
-synctex_node_t synctex_node_sibling(synctex_node_t node)
-{
- return SYNCTEX_SIBLING(node);
-}
-synctex_node_t synctex_node_next(synctex_node_t node) {
- if (SYNCTEX_CHILD(node)) {
- return SYNCTEX_CHILD(node);
- }
-sibling:
- if (SYNCTEX_SIBLING(node)) {
- return SYNCTEX_SIBLING(node);
- }
- if ((node = SYNCTEX_PARENT(node))) {
- if (node->class->type == synctex_node_type_sheet) {/* EXC_BAD_ACCESS? */
- return NULL;
- }
- goto sibling;
- }
- return NULL;
+
+/**
+ * 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_data_height(to_node));
+ _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 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 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 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 -
@@ -770,430 +2870,1013 @@ sibling:
# endif
/* Public node accessor: the type */
-synctex_node_type_t synctex_node_type(synctex_node_t node) {
- if (node) {
- return (((node)->class))->type;
- }
- return synctex_node_type_error;
+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_t node) {
-static const char * isa[synctex_node_number_of_types] =
- {"Not a node","input","sheet","vbox","void vbox","hbox","void hbox","kern","glue","math","boundary"};
- return isa[synctex_node_type(node)];
+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 SYNCTEX_LOG
+# pragma mark LOG
# endif
-# define SYNCTEX_LOG(NODE) SYNCTEX_MSG_SEND(NODE,log)
-
/* Public node logger */
-void synctex_node_log(synctex_node_t node) {
- SYNCTEX_LOG(node);
+void synctex_node_log(synctex_node_p node) {
+ SYNCTEX_MSG_SEND(node,log);
}
-static void _synctex_log_input(synctex_node_t node) {
- if (node) {
- printf("%s:%i,%s",synctex_node_isa(node),SYNCTEX_TAG(node),SYNCTEX_NAME(node));
- printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
+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_t node) {
- if (node) {
- printf("%s:%i",synctex_node_isa(node),SYNCTEX_PAGE(node));
- SYNCTEX_PRINT_CHARINDEX;
- printf("SELF:%p",(void *)node);
- printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
- printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
- printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
- printf(" SYNCTEX_FRIEND:%p",(void *)SYNCTEX_FRIEND(node));
- printf(" SYNCTEX_NEXT_hbox:%p\n",(void *)SYNCTEX_NEXT_hbox(node));
- }
-}
-
-static void _synctex_log_small_node(synctex_node_t node) {
- if (node) {
- printf("%s:%i,%i:%i,%i",
- synctex_node_isa(node),
- SYNCTEX_TAG(node),
- SYNCTEX_LINE(node),
- SYNCTEX_HORIZ(node),
- SYNCTEX_VERT(node));
- SYNCTEX_PRINT_CHARINDEX;
- printf("SELF:%p",(void *)node);
- printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
- printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
- printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
- printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node));
- }
-}
-
-static void _synctex_log_medium_node(synctex_node_t node) {
- if (node) {
- printf("%s:%i,%i:%i,%i:%i",
- synctex_node_isa(node),
- SYNCTEX_TAG(node),
- SYNCTEX_LINE(node),
- SYNCTEX_HORIZ(node),
- SYNCTEX_VERT(node),
- SYNCTEX_WIDTH(node));
- SYNCTEX_PRINT_CHARINDEX;
- printf("SELF:%p",(void *)node);
- printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
- printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
- printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
- printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node));
- }
-}
-
-static void _synctex_log_void_box(synctex_node_t node) {
- if (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,%i",
+ synctex_node_isa(node),
+ _synctex_data_tag(node),
+ _synctex_data_line(node),
+ _synctex_data_column(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:%i",
+ synctex_node_isa(node),
+ _synctex_data_tag(node),
+ _synctex_data_line(node),
+ _synctex_data_column(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,%i",
+ synctex_node_isa(node),
+ _synctex_data_tag(node),
+ _synctex_data_line(node),
+ _synctex_data_column(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_TAG(node));
- printf(",%i",SYNCTEX_LINE(node));
- printf(",%i",0);
- printf(":%i",SYNCTEX_HORIZ(node));
- printf(",%i",SYNCTEX_VERT(node));
- printf(":%i",SYNCTEX_WIDTH(node));
- printf(",%i",SYNCTEX_HEIGHT(node));
- printf(",%i",SYNCTEX_DEPTH(node));
- SYNCTEX_PRINT_CHARINDEX;
- printf("SELF:%p",(void *)node);
- printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
- printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
- printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
- printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node));
+ printf(":%i",_synctex_data_tag(node));
+ printf(",%i",_synctex_data_line(node));
+ printf(",%i",_synctex_data_column(node));
+ 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_t node) {
- if (node) {
+static void _synctex_log_vbox(synctex_node_p node) {
+ if (node) {
printf("%s",synctex_node_isa(node));
- printf(":%i",SYNCTEX_TAG(node));
- printf(",%i",SYNCTEX_LINE(node));
- printf(",%i",0);
- printf(":%i",SYNCTEX_HORIZ(node));
- printf(",%i",SYNCTEX_VERT(node));
- printf(":%i",SYNCTEX_WIDTH(node));
- printf(",%i",SYNCTEX_HEIGHT(node));
- printf(",%i",SYNCTEX_DEPTH(node));
- SYNCTEX_PRINT_CHARINDEX;
- printf("SELF:%p",(void *)node);
- printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
- printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
- printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
- printf(" SYNCTEX_FRIEND:%p",(void *)SYNCTEX_FRIEND(node));
- printf(" SYNCTEX_NEXT_hbox:%p\n",(void *)SYNCTEX_NEXT_hbox(node));
+ printf(":%i",_synctex_data_tag(node));
+ printf(",%i",_synctex_data_line(node));
+ printf(",%i",_synctex_data_column(node));
+ 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_t node) {
- if (node) {
+static void _synctex_log_hbox(synctex_node_p node) {
+ if (node) {
printf("%s",synctex_node_isa(node));
- printf(":%i",SYNCTEX_TAG(node));
- printf(",%i~%i*%i",SYNCTEX_LINE(node),SYNCTEX_MEAN_LINE(node),SYNCTEX_NODE_WEIGHT(node));
- printf(",%i",0);
- printf(":%i",SYNCTEX_HORIZ(node));
- printf(",%i",SYNCTEX_VERT(node));
- printf(":%i",SYNCTEX_WIDTH(node));
- printf(",%i",SYNCTEX_HEIGHT(node));
- printf(",%i",SYNCTEX_DEPTH(node));
- printf("/%i",SYNCTEX_HORIZ_V(node));
- printf(",%i",SYNCTEX_VERT_V(node));
- printf(":%i",SYNCTEX_WIDTH_V(node));
- printf(",%i",SYNCTEX_HEIGHT_V(node));
- printf(",%i",SYNCTEX_DEPTH_V(node));
- SYNCTEX_PRINT_CHARINDEX;
- printf("SELF:%p",(void *)node);
- printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
- printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
- printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
- printf(" SYNCTEX_FRIEND:%p",(void *)SYNCTEX_FRIEND(node));
- printf(" SYNCTEX_NEXT_hbox:%p\n",(void *)SYNCTEX_NEXT_hbox(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",_synctex_data_column(node));
+ 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 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;
}
-# define SYNCTEX_DISPLAY(NODE) SYNCTEX_MSG_SEND(NODE,display)
+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));
+ }
+}
-void synctex_node_display(synctex_node_t node) {
- SYNCTEX_DISPLAY(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_input(synctex_node_t node) {
+static void _synctex_display_sheet(synctex_node_p node) {
if (node) {
- printf("....Input:%i:%s",
- SYNCTEX_TAG(node),
- SYNCTEX_NAME(node));
- SYNCTEX_PRINT_CHARINDEX;
- SYNCTEX_DISPLAY(SYNCTEX_SIBLING(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 void _synctex_display_sheet(synctex_node_t node) {
- if (node) {
- printf("....{%i",SYNCTEX_PAGE(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;
- SYNCTEX_DISPLAY(SYNCTEX_CHILD(node));
- printf("....}\n");
- SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
- }
+ }
+ return abstract;
}
-static void _synctex_display_vbox(synctex_node_t node) {
+static void _synctex_display_form(synctex_node_p node) {
if (node) {
- printf("....[%i,%i:%i,%i:%i,%i,%i",
- SYNCTEX_TAG(node),
- SYNCTEX_LINE(node),
- SYNCTEX_HORIZ(node),
- SYNCTEX_VERT(node),
- SYNCTEX_WIDTH(node),
- SYNCTEX_HEIGHT(node),
- SYNCTEX_DEPTH(node));
- SYNCTEX_PRINT_CHARINDEX;
- SYNCTEX_DISPLAY(SYNCTEX_CHILD(node));
- printf("....]\n");
- SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
- }
-}
-
-static void _synctex_display_hbox(synctex_node_t 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) {
- printf("....(%i,%i~%i*%i:%i,%i:%i,%i,%i",
- SYNCTEX_TAG(node),
- SYNCTEX_LINE(node),
- SYNCTEX_MEAN_LINE(node),
- SYNCTEX_NODE_WEIGHT(node),
- SYNCTEX_HORIZ(node),
- SYNCTEX_VERT(node),
- SYNCTEX_WIDTH(node),
- SYNCTEX_HEIGHT(node),
- SYNCTEX_DEPTH(node));
- SYNCTEX_PRINT_CHARINDEX;
- SYNCTEX_DISPLAY(SYNCTEX_CHILD(node));
- printf("....)\n");
- SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
- }
-}
-
-static void _synctex_display_void_vbox(synctex_node_t 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("....v%i,%i;%i,%i:%i,%i,%i",
- SYNCTEX_TAG(node),
- SYNCTEX_LINE(node),
- SYNCTEX_HORIZ(node),
- SYNCTEX_VERT(node),
- SYNCTEX_WIDTH(node),
- SYNCTEX_HEIGHT(node),
- SYNCTEX_DEPTH(node));
- SYNCTEX_PRINT_CHARINDEX;
- SYNCTEX_DISPLAY(SYNCTEX_SIBLING(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 void _synctex_display_void_hbox(synctex_node_t node) {
+static char * _synctex_abstract_hbox(synctex_node_p node) {
+ static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
if (node) {
- printf("....h%i,%i:%i,%i:%i,%i,%i",
- SYNCTEX_TAG(node),
- SYNCTEX_LINE(node),
- SYNCTEX_HORIZ(node),
- SYNCTEX_VERT(node),
- SYNCTEX_WIDTH(node),
- SYNCTEX_HEIGHT(node),
- SYNCTEX_DEPTH(node));
- SYNCTEX_PRINT_CHARINDEX;
- SYNCTEX_DISPLAY(SYNCTEX_SIBLING(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_glue(synctex_node_t node) {
+static void _synctex_display_hbox(synctex_node_p node) {
if (node) {
- printf("....glue:%i,%i:%i,%i",
- SYNCTEX_TAG(node),
- SYNCTEX_LINE(node),
- SYNCTEX_HORIZ(node),
- SYNCTEX_VERT(node));
- SYNCTEX_PRINT_CHARINDEX;
- SYNCTEX_DISPLAY(SYNCTEX_SIBLING(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 void _synctex_display_math(synctex_node_t node) {
+static char * _synctex_abstract_void_vbox(synctex_node_p node) {
+ static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
if (node) {
- printf("....math:%i,%i:%i,%i",
- SYNCTEX_TAG(node),
- SYNCTEX_LINE(node),
- SYNCTEX_HORIZ(node),
- SYNCTEX_VERT(node));
- SYNCTEX_PRINT_CHARINDEX;
- SYNCTEX_DISPLAY(SYNCTEX_SIBLING(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_kern(synctex_node_t node) {
+static void _synctex_display_void_vbox(synctex_node_p node) {
if (node) {
- printf("....kern:%i,%i:%i,%i:%i",
- SYNCTEX_TAG(node),
- SYNCTEX_LINE(node),
- SYNCTEX_HORIZ(node),
- SYNCTEX_VERT(node),
- SYNCTEX_WIDTH(node));
- SYNCTEX_PRINT_CHARINDEX;
- SYNCTEX_DISPLAY(SYNCTEX_SIBLING(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 void _synctex_display_boundary(synctex_node_t node) {
+static char * _synctex_abstract_void_hbox(synctex_node_p node) {
+ static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
if (node) {
- printf("....boundary:%i,%i:%i,%i",
- SYNCTEX_TAG(node),
- SYNCTEX_LINE(node),
- SYNCTEX_HORIZ(node),
- SYNCTEX_VERT(node));
- SYNCTEX_PRINT_CHARINDEX;
- SYNCTEX_DISPLAY(SYNCTEX_SIBLING(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;
}
-# ifdef SYNCTEX_NOTHING
-# pragma mark -
-# pragma mark SCANNER
-# endif
+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);
+ }
+}
-/* 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
- */
+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;
+}
-/* 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: */
-# define SYNCTEX_STATUS_OK (SYNCTEX_STATUS_NOT_OK+1)
-/* Generic error: */
-# define SYNCTEX_STATUS_ERROR -1
-/* Parameter error: */
-# define SYNCTEX_STATUS_BAD_ARGUMENT -2
+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);
+ }
+}
-# define SYNCTEX_FILE (scanner->file)
+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;
+}
-/* Actually, the minimum buffer size is driven by integer and float parsing.
- * �0.123456789e123
- */
-# define SYNCTEX_BUFFER_MIN_SIZE 16
-# define SYNCTEX_BUFFER_SIZE 32768
+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(%i):->%s\n",
+ node->class_->scanner->display_prompt,
+ synctex_node_isa(node),
+ _synctex_data_weight(N),
+ _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
-synctex_status_t _synctex_buffer_get_available_size(synctex_scanner_t scanner, size_t * size_ptr);
-synctex_status_t _synctex_next_line(synctex_scanner_t scanner);
-synctex_status_t _synctex_match_string(synctex_scanner_t scanner, const char * the_string);
-synctex_status_t _synctex_decode_int(synctex_scanner_t scanner, int* value_ref);
-synctex_status_t _synctex_decode_string(synctex_scanner_t scanner, char ** value_ref);
-synctex_status_t _synctex_scan_input(synctex_scanner_t scanner);
-synctex_status_t _synctex_scan_preamble(synctex_scanner_t scanner);
-synctex_status_t _synctex_scan_float_and_dimension(synctex_scanner_t scanner, float * value_ref);
-synctex_status_t _synctex_scan_post_scriptum(synctex_scanner_t scanner);
-synctex_status_t _synctex_scan_postamble(synctex_scanner_t scanner);
-synctex_status_t _synctex_setup_visible_box(synctex_node_t box);
-synctex_status_t _synctex_hbox_setup_visible(synctex_node_t node,int h, int v);
-synctex_status_t _synctex_scan_sheet(synctex_scanner_t scanner, synctex_node_t parent);
-synctex_status_t _synctex_scan_nested_sheet(synctex_scanner_t scanner);
-synctex_status_t _synctex_scan_content(synctex_scanner_t scanner);
-int synctex_scanner_pre_x_offset(synctex_scanner_t scanner);
-int synctex_scanner_pre_y_offset(synctex_scanner_t scanner);
-const char * synctex_scanner_get_output_fmt(synctex_scanner_t scanner);
-int _synctex_node_is_box(synctex_node_t node);
-
-/* Try to ensure that the buffer contains at least size bytes.
+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 null 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,
- * in which case, SYNCTEX_STATUS_BAD_ARGUMENT is returned.
- * The value returned in size_ptr is the number of bytes now available in the buffer.
- * This is a nonnegative integer, it may take the value 0.
+ * 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. */
-synctex_status_t _synctex_buffer_get_available_size(synctex_scanner_t scanner, size_t * size_ptr) {
- size_t available = 0;
- if (NULL == scanner || NULL == size_ptr) {
- return SYNCTEX_STATUS_BAD_ARGUMENT;
- }
-# define size (* size_ptr)
- if (size>SYNCTEX_BUFFER_SIZE){
- size = SYNCTEX_BUFFER_SIZE;
- }
- available = SYNCTEX_END - SYNCTEX_CUR; /* available is the number of unparsed chars in the buffer */
- if (size<=available) {
- /* There are already sufficiently many characters in the buffer */
- size = available;
- return 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;
+ * 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->charindex_offset += SYNCTEX_CUR - SYNCTEX_START;
+ scanner->reader->charindex_offset += SYNCTEX_CUR - SYNCTEX_START;
# endif
- if (available) {
- memmove(SYNCTEX_START, SYNCTEX_CUR, available);
- }
- SYNCTEX_CUR = SYNCTEX_START + available; /* 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 - available));
- if (already_read>0) {
- /* We assume that 0<already_read<=SYNCTEX_BUFFER_SIZE - available, such that
- * SYNCTEX_CUR + already_read = SYNCTEX_START + available + 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';
- SYNCTEX_CUR = SYNCTEX_START;
- size = SYNCTEX_END - SYNCTEX_CUR; /* == old available + already_read*/
- return SYNCTEX_STATUS_OK; /* May be available is less than size, the caller will have to test. */
- } 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_STATUS_ERROR;
- } else if (errnum) {
- _synctex_error("gzread error (%i:%i,%s)",already_read,errnum,error_string);
- return SYNCTEX_STATUS_ERROR;
- }
- }
+ 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.*/
- size = SYNCTEX_END - SYNCTEX_CUR;
- return SYNCTEX_STATUS_EOF; /* there might be a bit of text left */
+ /* 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. */
- size = available;
- return SYNCTEX_STATUS_EOF;
-# undef size
+ /* 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.
@@ -1205,29 +3888,27 @@ synctex_status_t _synctex_buffer_get_available_size(synctex_scanner_t scanner, s
* 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
*/
-synctex_status_t _synctex_next_line(synctex_scanner_t scanner) {
- synctex_status_t status = SYNCTEX_STATUS_OK;
- size_t available = 0;
- if (NULL == scanner) {
- return SYNCTEX_STATUS_BAD_ARGUMENT;
- }
+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;
- available = 1;
- return _synctex_buffer_get_available_size(scanner, &available);
- }
- ++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. */
- available = 1;
- status = _synctex_buffer_get_available_size(scanner, &available);
- if (status<=0) {
- return status;
- }
- goto 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.
@@ -1240,116 +3921,109 @@ infinite_loop:
* 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.
*/
-synctex_status_t _synctex_match_string(synctex_scanner_t 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_status_t status = 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? */
- available = remaining_len;
- status = _synctex_buffer_get_available_size(scanner,&available);
- if (status<SYNCTEX_STATUS_EOF) {
- return status;
- }
- /* Maybe we have less characters than expected because the buffer is too small. */
- if (available>=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,available)) {
- /* 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 += available;
- /* update the remaining length and the parsed length. */
- remaining_len -= available;
- tested_len += available;
- SYNCTEX_CUR += available; /* We validate the tested characters. */
- if (0 == remaining_len) {
- /* Nothing left to test, we have found the given string, we return the length. */
- return tested_len;
- }
- /* 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. */
- available = SYNCTEX_CUR - SYNCTEX_START; /* available can be used as temporary placeholder. */
- /* available now corresponds to 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 buffer contents is completely replaced by _synctex_buffer_get_available_size.
- * They were buffered from offset-len location in the file. */
- offset -= available;
-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. */
- available = remaining_len;
- status = _synctex_buffer_get_available_size(scanner,&available);
- if (status<SYNCTEX_STATUS_EOF) {
- return status; /* This is an error, no need to go further. */
- }
- if (available==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 (available<remaining_len) {
- /* We'll have to loop one more time. */
- if (strncmp((char *)SYNCTEX_CUR,the_string,available)) {
- /* 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 -= available;
- tested_len += available;
- SYNCTEX_CUR += available; /* We validate the tested characters. */
- if (0 == remaining_len) {
- /* Nothing left to test, we have found the given string. */
- return SYNCTEX_STATUS_OK;
- }
- 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;
- }
+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.
@@ -1362,40 +4036,88 @@ return_NOT_OK:
* 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.
*/
-synctex_status_t _synctex_decode_int(synctex_scanner_t scanner, int* value_ref) {
- char * ptr = NULL;
- char * end = NULL;
- int result = 0;
- size_t available = 0;
- synctex_status_t status = 0;
- if (NULL == scanner) {
- return SYNCTEX_STATUS_BAD_ARGUMENT;
- }
- available = SYNCTEX_BUFFER_MIN_SIZE;
- status = _synctex_buffer_get_available_size(scanner, &available);
- if (status<SYNCTEX_STATUS_EOF) {
- return status;/* Forward error. */
- }
- if (available==0) {
- return SYNCTEX_STATUS_EOF;/* it is the end of file. */
- }
- ptr = SYNCTEX_CUR;
- if (*ptr==':' || *ptr==',') {
- ++ptr;
- --available;
- if (available==0) {
- return SYNCTEX_STATUS_NOT_OK;/* It is not possible to scan an int */
- }
- }
- result = (int)strtol(ptr, &end, 10);
- if (end>ptr) {
- SYNCTEX_CUR = end;
- if (value_ref) {
- * value_ref = result;
- }
- return SYNCTEX_STATUS_OK;/* Successfully scanned an int */
- }
- return SYNCTEX_STATUS_NOT_OK;/* Could not scan an int */
+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.
@@ -1404,7 +4126,8 @@ synctex_status_t _synctex_decode_int(synctex_scanner_t scanner, int* value_ref)
* 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.
+ * 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,
@@ -1415,149 +4138,120 @@ synctex_status_t _synctex_decode_int(synctex_scanner_t scanner, int* value_ref)
* If either scanner or value_ref is NULL, it is considered as an error and
* SYNCTEX_STATUS_BAD_ARGUMENT is returned.
*/
-synctex_status_t _synctex_decode_string(synctex_scanner_t scanner, char ** value_ref) {
- char * end = NULL;
- size_t current_size = 0;
- size_t new_size = 0;
- size_t len = 0;/* The number of bytes to copy */
- size_t available = 0;
- synctex_status_t status = 0;
- if (NULL == scanner || NULL == value_ref) {
- return SYNCTEX_STATUS_BAD_ARGUMENT;
- }
- /* The buffer must at least contain one character: the '\n' end of line marker */
- if (SYNCTEX_CUR>=SYNCTEX_END) {
- available = 1;
- status = _synctex_buffer_get_available_size(scanner,&available);
- if (status < 0) {
- return status;
- }
- if (0 == available) {
- return 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;
- * value_ref = NULL;/* Initialize, it will be realloc'ed */
- /* We scan all the characters up to the next '\n' */
-next_character:
- if (end<SYNCTEX_END) {
- if (*end == '\n') {
- /* OK, we found where to stop */
- len = end - SYNCTEX_CUR;
- if (current_size>UINT_MAX-len-1) {
- /* But we have reached the limit: we do not have current_size+len+1>UINT_MAX.
- * We return the missing amount of memory.
- * This will never occur in practice. */
- return UINT_MAX-len-1 - current_size;
- }
- new_size = current_size+len;
- /* We have current_size+len+1<=UINT_MAX
- * or equivalently new_size<UINT_MAX,
- * where we have assumed that len<UINT_MAX */
- if ((* value_ref = realloc(* value_ref,new_size+1)) != NULL) {
- if (memcpy((*value_ref)+current_size,SYNCTEX_CUR,len)) {
- (* value_ref)[new_size]='\0'; /* Terminate the string */
- SYNCTEX_CUR += len;/* Advance to the terminating '\n' */
- return SYNCTEX_STATUS_OK;
- }
- free(* value_ref);
- * value_ref = NULL;
- _synctex_error("could not copy memory (1).");
- return SYNCTEX_STATUS_ERROR;
- }
- _synctex_error("could not allocate memory (1).");
- return SYNCTEX_STATUS_ERROR;
- } else {
- ++end;
- goto next_character;
- }
- } else {
- /* end == SYNCTEX_END */
- len = SYNCTEX_END - SYNCTEX_CUR;
- if (current_size>UINT_MAX-len-1) {
- /* We have reached the limit. */
- _synctex_error("limit reached (missing %i).",current_size-(UINT_MAX-len-1));
- return SYNCTEX_STATUS_ERROR;
- }
- new_size = current_size+len;
- if ((* value_ref = realloc(* value_ref,new_size+1)) != NULL) {
- if (memcpy((*value_ref)+current_size,SYNCTEX_CUR,len)) {
- (* value_ref)[new_size]='\0'; /* Terminate the string */
- SYNCTEX_CUR = SYNCTEX_END;/* Advance the cursor to the end of the bufer */
- return SYNCTEX_STATUS_OK;
- }
- free(* value_ref);
- * value_ref = NULL;
- _synctex_error("could not copy memory (2).");
- return SYNCTEX_STATUS_ERROR;
- }
- /* Huge memory problem */
- _synctex_error("could not allocate memory (2).");
- return SYNCTEX_STATUS_ERROR;
- }
+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;
+ 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) {
+ return (synctex_ss_s){NULL,zs.status};
+ } else if (0 == zs.size) {
+ 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 ((string = realloc(string,len+already_len+1)) != 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};
+ }
+ }
+ _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.
*/
-synctex_status_t _synctex_scan_input(synctex_scanner_t scanner) {
- synctex_status_t status = 0;
- size_t available = 0;
- synctex_node_t input = NULL;
- if (NULL == scanner) {
- return SYNCTEX_STATUS_BAD_ARGUMENT;
- }
- status = _synctex_match_string(scanner,SYNCTEX_INPUT_MARK);
- if (status<SYNCTEX_STATUS_OK) {
- return status;
- }
- /* Create a node */
- input = _synctex_new_input(scanner);
- if (NULL == input) {
- _synctex_error("could not create an input node.");
- return SYNCTEX_STATUS_ERROR;
- }
- /* Decode the synctag */
- status = _synctex_decode_int(scanner,&(SYNCTEX_TAG(input)));
- if (status<SYNCTEX_STATUS_OK) {
- _synctex_error("bad format of input node.");
- SYNCTEX_FREE(input);
- return status;
- }
- /* The next character is a field separator, we expect one character in the buffer. */
- available = 1;
- status = _synctex_buffer_get_available_size(scanner, &available);
- if (status<=SYNCTEX_STATUS_ERROR) {
- return status;
- }
- if (0 == available) {
- return SYNCTEX_STATUS_EOF;
- }
- /* We can now safely advance to the next character, stepping over the field separator. */
- ++SYNCTEX_CUR;
- --available;
- /* Then we scan the file name */
- status = _synctex_decode_string(scanner,&(SYNCTEX_NAME(input)));
- if (status<SYNCTEX_STATUS_OK) {
- SYNCTEX_FREE(input);
- return status;
- }
- /* Prepend this input node to the input linked list of the scanner */
- SYNCTEX_SET_SIBLING(input,scanner->input);
- scanner->input = input;
+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;
# if SYNCTEX_VERBOSE
- synctex_node_log(input);
+ synctex_node_log(input);
# endif
- return _synctex_next_line(scanner);/* read the line termination character, if any */
- /* Now, set up the path */
+ return (synctex_ns_s){input,_synctex_next_line(scanner)};/* read the line termination character, if any */
}
-typedef synctex_status_t (*synctex_decoder_t)(synctex_scanner_t,void *);
-
-synctex_status_t _synctex_scan_named(synctex_scanner_t scanner,const char * name,void * value_ref,synctex_decoder_t decoder);
+typedef synctex_is_s (*synctex_decoder_t)(synctex_scanner_p);
/* Used when parsing the synctex file.
* Read one of the settings.
@@ -1567,255 +4261,275 @@ synctex_status_t _synctex_scan_named(synctex_scanner_t scanner,const char * name
* 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.
*/
-synctex_status_t _synctex_scan_named(synctex_scanner_t scanner,const char * name,void * value_ref,synctex_decoder_t decoder) {
- synctex_status_t status = 0;
- if (NULL == scanner || NULL == name || NULL == value_ref || NULL == decoder) {
- return SYNCTEX_STATUS_BAD_ARGUMENT;
- }
+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;
- }
- /* A line is found, scan the value */
- return (*decoder)(scanner,value_ref);
+ 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.
*/
-synctex_status_t _synctex_scan_preamble(synctex_scanner_t scanner) {
- synctex_status_t status = 0;
- if (NULL == scanner) {
- return SYNCTEX_STATUS_BAD_ARGUMENT;
- }
- status = _synctex_scan_named(scanner,"SyncTeX Version:",&(scanner->version),(synctex_decoder_t)&_synctex_decode_int);
- if (status<SYNCTEX_STATUS_OK) {
- return status;
- }
- status = _synctex_next_line(scanner);
- if (status<SYNCTEX_STATUS_OK) {
- return status;
- }
- /* Read all the input records */
- do {
- status = _synctex_scan_input(scanner);
- 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. */
- status = _synctex_scan_named(scanner,"Output:",&(scanner->output_fmt),(synctex_decoder_t)&_synctex_decode_string);
- if (status<SYNCTEX_STATUS_NOT_OK) {
- return status;
- }
- status = _synctex_next_line(scanner);
- if (status<SYNCTEX_STATUS_OK) {
- return status;
- }
- status = _synctex_scan_named(scanner,"Magnification:",&(scanner->pre_magnification),(synctex_decoder_t)&_synctex_decode_int);
- if (status<SYNCTEX_STATUS_OK) {
- return status;
- }
- status = _synctex_next_line(scanner);
- if (status<SYNCTEX_STATUS_OK) {
- return status;
- }
- status = _synctex_scan_named(scanner,"Unit:",&(scanner->pre_unit),(synctex_decoder_t)&_synctex_decode_int);
- if (status<SYNCTEX_STATUS_OK) {
- return status;
- }
- status = _synctex_next_line(scanner);
- if (status<SYNCTEX_STATUS_OK) {
- return status;
- }
- status = _synctex_scan_named(scanner,"X Offset:",&(scanner->pre_x_offset),(synctex_decoder_t)&_synctex_decode_int);
- if (status<SYNCTEX_STATUS_OK) {
- return status;
- }
- status = _synctex_next_line(scanner);
- if (status<SYNCTEX_STATUS_OK) {
- return status;
- }
- status = _synctex_scan_named(scanner,"Y Offset:",&(scanner->pre_y_offset),(synctex_decoder_t)&_synctex_decode_int);
- if (status<SYNCTEX_STATUS_OK) {
- return status;
- }
- return _synctex_next_line(scanner);
+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 */
-synctex_status_t _synctex_scan_float_and_dimension(synctex_scanner_t scanner, float * value_ref) {
- synctex_status_t status = 0;
- char * endptr = NULL;
- float f = 0;
+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);
+ char * loc = setlocale(LC_NUMERIC, NULL);
#endif
- size_t available = 0;
- if (NULL == scanner || NULL == value_ref) {
- return SYNCTEX_STATUS_BAD_ARGUMENT;
- }
- available = SYNCTEX_BUFFER_MIN_SIZE;
- status = _synctex_buffer_get_available_size(scanner, &available);
- if (status<SYNCTEX_STATUS_EOF) {
- _synctex_error("problem with float.");
- return status;
- }
+ 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");
+ setlocale(LC_NUMERIC, "C");
#endif
- f = strtod(SYNCTEX_CUR,&endptr);
+ fs.value = strtod(SYNCTEX_CUR,&endptr);
#ifdef HAVE_SETLOCALE
- setlocale(LC_NUMERIC, loc);
+ setlocale(LC_NUMERIC, loc);
#endif
- if (endptr == SYNCTEX_CUR) {
- _synctex_error("a float was expected.");
- return SYNCTEX_STATUS_ERROR;
- }
- SYNCTEX_CUR = endptr;
- if ((status = _synctex_match_string(scanner,"in")) >= SYNCTEX_STATUS_OK) {
- f *= 72.27f*65536;
- } else if (status<SYNCTEX_STATUS_EOF) {
-report_unit_error:
- _synctex_error("problem with unit.");
- return status;
- } else if ((status = _synctex_match_string(scanner,"cm")) >= SYNCTEX_STATUS_OK) {
- f *= 72.27f*65536/2.54f;
- } else if (status<0) {
- goto report_unit_error;
- } else if ((status = _synctex_match_string(scanner,"mm")) >= SYNCTEX_STATUS_OK) {
- f *= 72.27f*65536/25.4f;
- } else if (status<0) {
- goto report_unit_error;
- } else if ((status = _synctex_match_string(scanner,"pt")) >= SYNCTEX_STATUS_OK) {
- f *= 65536.0f;
- } else if (status<0) {
- goto report_unit_error;
- } else if ((status = _synctex_match_string(scanner,"bp")) >= SYNCTEX_STATUS_OK) {
- f *= 72.27f/72*65536.0f;
- } else if (status<0) {
- goto report_unit_error;
- } else if ((status = _synctex_match_string(scanner,"pc")) >= SYNCTEX_STATUS_OK) {
- f *= 12.0*65536.0f;
- } else if (status<0) {
- goto report_unit_error;
- } else if ((status = _synctex_match_string(scanner,"sp")) >= SYNCTEX_STATUS_OK) {
- f *= 1.0f;
- } else if (status<0) {
- goto report_unit_error;
- } else if ((status = _synctex_match_string(scanner,"dd")) >= SYNCTEX_STATUS_OK) {
- f *= 1238.0f/1157*65536.0f;
- } else if (status<0) {
- goto report_unit_error;
- } else if ((status = _synctex_match_string(scanner,"cc")) >= SYNCTEX_STATUS_OK) {
- f *= 14856.0f/1157*65536;
- } else if (status<0) {
- goto report_unit_error;
- } else if ((status = _synctex_match_string(scanner,"nd")) >= SYNCTEX_STATUS_OK) {
- f *= 685.0f/642*65536;
- } else if (status<0) {
- goto report_unit_error;
- } else if ((status = _synctex_match_string(scanner,"nc")) >= SYNCTEX_STATUS_OK) {
- f *= 1370.0f/107*65536;
- } else if (status<0) {
- goto report_unit_error;
- }
- *value_ref = f;
- return SYNCTEX_STATUS_OK;
+ 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 */
-synctex_status_t _synctex_scan_post_scriptum(synctex_scanner_t scanner) {
- synctex_status_t status = 0;
- char * endptr = NULL;
+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);
+ 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 */
+ 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. */
+ 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 ) {
+ 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");
+ setlocale(LC_NUMERIC, "C");
#endif
- scanner->unit = strtod(SYNCTEX_CUR,&endptr);
+ scanner->unit = strtod(SYNCTEX_CUR,&endptr);
#ifdef HAVE_SETLOCALE
- setlocale(LC_NUMERIC, loc);
+ 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) {
- status = _synctex_scan_float_and_dimension(scanner, &(scanner->x_offset));
- if (status<SYNCTEX_STATUS_OK) {
- _synctex_error("problem with X offset in the Post Scriptum.");
- return status;
- }
- 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) {
- status = _synctex_scan_float_and_dimension(scanner, &(scanner->y_offset));
- if (status<SYNCTEX_STATUS_OK) {
- _synctex_error("problem with Y offset in the Post Scriptum.");
- return status;
- }
- goto next_line;
- } else if (status<SYNCTEX_STATUS_EOF){
- goto report_record_problem;
- }
- goto next_line;
+ 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
@@ -1823,32 +4537,33 @@ report_record_problem:
* a negative error otherwise
* The postamble comprises the post scriptum section.
*/
-synctex_status_t _synctex_scan_postamble(synctex_scanner_t scanner) {
- synctex_status_t status = 0;
- if (NULL == scanner) {
- return SYNCTEX_STATUS_BAD_ARGUMENT;
- }
- status = _synctex_match_string(scanner,"Postamble:");
- if (status < SYNCTEX_STATUS_OK) {
- return status;
- }
+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:
- status = _synctex_next_line(scanner);
- if (status < SYNCTEX_STATUS_OK) {
- return status;
- }
- status = _synctex_scan_named(scanner,"Count:",&(scanner->count),(synctex_decoder_t)&_synctex_decode_int);
- if (status < SYNCTEX_STATUS_EOF) {
- return status; /* forward the error */
- } else if (status < SYNCTEX_STATUS_OK) { /* No Count record found */
- status = _synctex_next_line(scanner); /* Advance one more line */
- if (status<SYNCTEX_STATUS_OK) {
- return status;
- }
- goto count_again;
- }
- /* Now we scan the last part of the SyncTeX file: the Post Scriptum section. */
- return _synctex_scan_post_scriptum(scanner);
+ 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.
@@ -1856,63 +4571,108 @@ count_again:
* For example 0 width boxes may contain text.
* At creation time, the visible size is set to the values of the real size.
*/
-synctex_status_t _synctex_setup_visible_box(synctex_node_t box) {
- if (box) {
- switch(box->class->type) {
- case synctex_node_type_hbox:
- if (SYNCTEX_INFO(box) != NULL) {
- SYNCTEX_HORIZ_V(box) = SYNCTEX_HORIZ(box);
- SYNCTEX_VERT_V(box) = SYNCTEX_VERT(box);
- SYNCTEX_WIDTH_V(box) = SYNCTEX_WIDTH(box);
- SYNCTEX_HEIGHT_V(box) = SYNCTEX_HEIGHT(box);
- SYNCTEX_DEPTH_V(box) = SYNCTEX_DEPTH(box);
- return SYNCTEX_STATUS_OK;
- }
- return SYNCTEX_STATUS_ERROR;
- }
- }
- return SYNCTEX_STATUS_BAD_ARGUMENT;
+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).
*/
-synctex_status_t _synctex_hbox_setup_visible(synctex_node_t node,int h, int v) {
-# ifdef __DARWIN_UNIX03
-# pragma unused(v)
-# endif
- int itsBtm, itsTop;
- if (NULL == node || node->class->type != synctex_node_type_hbox) {
- return SYNCTEX_STATUS_BAD_ARGUMENT;
- }
- if (SYNCTEX_WIDTH_V(node)<0) {
- itsBtm = SYNCTEX_HORIZ_V(node);
- itsTop = SYNCTEX_HORIZ_V(node)-SYNCTEX_WIDTH_V(node);
- if (h<itsBtm) {
- SYNCTEX_HORIZ_V(node) = h;
- SYNCTEX_WIDTH_V(node) = SYNCTEX_HORIZ_V(node) - itsTop;
- } else if (h>itsTop) {
- SYNCTEX_WIDTH_V(node) = SYNCTEX_HORIZ_V(node) - h;
- }
- } else {
- itsBtm = SYNCTEX_HORIZ_V(node);
- itsTop = SYNCTEX_HORIZ_V(node)+SYNCTEX_WIDTH_V(node);
- if (h<itsBtm) {
- SYNCTEX_HORIZ_V(node) = h;
- SYNCTEX_WIDTH_V(node) = itsTop - SYNCTEX_HORIZ_V(node);
- } else if (h>itsTop) {
- SYNCTEX_WIDTH_V(node) = h - SYNCTEX_HORIZ_V(node);
- }
- }
- return SYNCTEX_STATUS_OK;
+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 '('
@@ -1922,2491 +4682,4243 @@ synctex_status_t _synctex_hbox_setup_visible(synctex_node_t node,int h, int 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
-/* Used when parsing the synctex file. A '{' character has just been parsed.
- * The purpose is to gobble everything until the closing '}'.
- * Actually only one nesting depth has been observed when using the clip option
- * of \includegraphics option. Here we use arbitrary level of depth.
+# 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;
+ }
+ /* sheets have no parent */
+ __synctex_tree_set_sibling(last_sheet,node);
+ } 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
*/
-synctex_status_t _synctex_scan_nested_sheet(synctex_scanner_t scanner) {
- unsigned int depth = 0;
-deeper:
- ++depth;
- if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Unexpected end of nested sheet (1).");
+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;
+}
+/**
+ * Free node and its siblings and return its detached child.
+ */
+SYNCTEX_INLINE static synctex_node_p _synctex_handle_pop_child(synctex_node_p handle) {
+ synctex_node_p child = _synctex_tree_reset_child(handle);
+ synctex_node_free(handle);
+ return child;
+}
+/**
+ * Set the tlc of all the x nodes that are targets of
+ * x_handle and its sibling.
+ * Reset the target of x_handle and deletes its siblings.
+ * child is a node that has just been parsed and is not a boundary node.
+ */
+SYNCTEX_INLINE static void _synctex_handle_set_tlc(synctex_node_p x_handle, synctex_node_p child, synctex_bool_t make_friend) {
+ if (x_handle) {
+ synctex_node_p sibling = x_handle;
+ if (child) {
+ synctex_node_p target;
+ while ((target = synctex_node_target(sibling))) {
+ _synctex_data_set_tlc(target,child);
+ if (make_friend) {
+ _synctex_node_make_friend_tlc(target);
+ }
+ if ((sibling = __synctex_tree_sibling(sibling))) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ }
+ _synctex_tree_reset_target(x_handle);
+ sibling = __synctex_tree_reset_sibling(x_handle);
+ synctex_node_free(sibling);
+ }
+}
+/**
+ * When we have parsed a box, we must register
+ * all the contained heading boundary nodes
+ * that have not yet been registered.
+ * Those handles will be deleted when poping.
+ */
+SYNCTEX_INLINE static void _synctex_handle_make_friend_tlc(synctex_node_p node) {
+ while (node) {
+ synctex_node_p target = _synctex_tree_reset_target(node);
+ _synctex_node_make_friend_tlc(target);
+ node = __synctex_tree_sibling(node);
+ }
+}
+/**
+ * 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;
+ /*
+ * Experimentations lead to the forthcoming conclusion:
+ * Sometimes, the first nodes of a box have the wrong line number.
+ * These are only boundary (x) nodes.
+ * We observed that boundary nodes do have the proper line number
+ * if they follow a node with a different type.
+ * We keep track of these leading x nodes in a handle tree.
+ */
+ synctex_node_p x_handle = NULL;
+# define SYNCTEX_RETURN(STATUS) \
+ synctex_node_free(x_handle);\
+ return STATUS
+ synctex_node_p last_k = NULL;
+ synctex_node_p last_g = NULL;
+ synctex_ns_s ns = SYNCTEX_NS_NULL;
+ int form_depth = 0;
+ int ignored_form_depth = 0;
+ synctex_bool_t try_input = synctex_YES;
+ if (!(x_handle = _synctex_new_handle(scanner))) {
SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
}
-scan_next_line:
+# 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_CUR == SYNCTEX_CHAR_END_SHEET) {
- ++SYNCTEX_CUR;
- if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Unexpected end of nested sheet (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- if (--depth>0) {
- goto scan_next_line;
- } else {
- SYNCTEX_RETURN(SYNCTEX_STATUS_OK);
+ 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;
+ last_k = last_g = NULL;
+ goto content_loop;
}
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_SHEET) {
- ++SYNCTEX_CUR;
- goto deeper;
-
- } else if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Unexpected end of nested sheet (3).");
+ if (form || sheet) {
+ last_k = last_g = NULL;
+ 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;
+ last_k = last_g = NULL;
+ 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) {
+ last_k = last_g = NULL;
+ 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;
+ SYNCTEX_RETURN(status);
+ }
+ status = _synctex_next_line(scanner);
+ if (status<SYNCTEX_STATUS_OK) {
+ SYNCTEX_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);
}
}
- _synctex_error("Unexpected end of nested sheet (4).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
-}
+ if (ignored_form_depth) {
+ goto ignore_loop;
+ } else {
+ last_k = last_g = NULL;
+ goto content_loop;
+ }
-/* Used when parsing the synctex file.
- * The sheet argument is a newly created sheet node that will hold the contents.
- * Something is returned in case of error.
- */
-synctex_status_t _synctex_scan_sheet(synctex_scanner_t scanner, synctex_node_t sheet) {
- synctex_node_t parent = sheet;
- synctex_node_t child = NULL;
- synctex_node_t sibling = NULL;
- synctex_node_t box = sheet;
- int friend_index = 0;
- synctex_info_t * info = NULL;
- synctex_status_t status = 0;
- size_t available = 0;
- if ((NULL == scanner) || (NULL == sheet)) {
- return SYNCTEX_STATUS_BAD_ARGUMENT;
- }
- /* We MUST start with a box, so at this level, the unique possibility is '[', '(' or "}". */
-prepare_loop:
- if (SYNCTEX_CUR<SYNCTEX_END) {
- if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_VBOX) {
-scan_vbox:
- if ((child = _synctex_new_vbox(scanner)) && (info = SYNCTEX_INFO(child))) {
-# define SYNCTEX_DECODE_FAILED(WHAT) \
- (_synctex_decode_int(scanner,&(info[WHAT].INT))<SYNCTEX_STATUS_OK)
- if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
- || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Bad vbox record.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- SYNCTEX_SET_CHILD(parent,child);
- parent = child;
- child = NULL;
- goto child_loop;/* next created node will be a child */
- } else {
- _synctex_error("Can't create vbox record.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_HBOX) {
-scan_hbox:
- if ((child = _synctex_new_hbox(scanner)) && (info = SYNCTEX_INFO(child))) {
- if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
- || _synctex_setup_visible_box(child)<SYNCTEX_STATUS_OK
- || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Bad hbox record.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child));
- SYNCTEX_SET_CHILD(parent,child);
- parent = child;
- child = NULL;
- goto child_loop;/* next created node will be a child */
- } else {
- _synctex_error("Can't create hbox record.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_SHEET) {
-scan_teehs:
- ++SYNCTEX_CUR;
- if (NULL == parent || parent->class->type != synctex_node_type_sheet
- || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Unexpected end of sheet.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
-# if SYNCTEX_VERBOSE
+# 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;
+#if SYNCTEX_VERBOSE
+ synctex_scanner_set_display_switcher(scanner,-1);
+ printf("NEW CONTENT LOOP\n");
+#if 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) {
+ x_handle = _synctex_new_handle_with_child(x_handle);
+ 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);
+# if SYNCTEX_VERBOSE
synctex_node_log(parent);
-# endif
- SYNCTEX_RETURN(SYNCTEX_STATUS_OK);
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_SHEET) {
- /* Addendum to version 1.10 to manage nested sheets */
- ++SYNCTEX_CUR;
- if (_synctex_scan_nested_sheet(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Unexpected nested sheet.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- goto prepare_loop;
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_ANCHOR) {
-scan_anchor:
- ++SYNCTEX_CUR;
- if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Missing anchor.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- goto prepare_loop;
- } else {
- /* _synctex_error("Ignored record %c\n",*SYNCTEX_CUR); */
- ++SYNCTEX_CUR;
- if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Unexpected end.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- goto prepare_loop;
- }
- } else {
- available = 1;
- status = _synctex_buffer_get_available_size(scanner,&available);
- if (status<SYNCTEX_STATUS_OK && available>0){
- _synctex_error("Uncomplete sheet(0)");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- goto prepare_loop;
- }
-/* The child loop means that we go down one level, when we just created a box node,
- * the next node created is a child of this box. */
-child_loop:
- if (SYNCTEX_CUR<SYNCTEX_END) {
- if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_VBOX) {
- goto scan_vbox;
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_VBOX) {
-scan_xobv:
- ++SYNCTEX_CUR;
- if (NULL != parent && parent->class->type == synctex_node_type_vbox) {
- #define SYNCTEX_UPDATE_BOX_FRIEND(NODE)\
- friend_index = ((SYNCTEX_INFO(NODE))[SYNCTEX_TAG_IDX].INT+(SYNCTEX_INFO(NODE))[SYNCTEX_LINE_IDX].INT)%(scanner->number_of_lists);\
- SYNCTEX_SET_FRIEND(NODE,(scanner->lists_of_friends)[friend_index]);\
- (scanner->lists_of_friends)[friend_index] = NODE;
- if (NULL == SYNCTEX_CHILD(parent)) {
- /* only void boxes are friends */
- SYNCTEX_UPDATE_BOX_FRIEND(parent);
- }
- child = parent;
- parent = SYNCTEX_PARENT(child);
- } else {
- _synctex_error("Unexpected end of vbox, ignored.");
- }
- if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Uncomplete sheet.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
-# if SYNCTEX_VERBOSE
+# endif
+ input.node = _synctex_input_register_line(input.node,parent);
+ last_k = last_g = NULL;
+ 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);
+ if (!form) {
+ _synctex_handle_make_friend_tlc(x_handle);
+ }
+ x_handle = _synctex_handle_pop_child(x_handle);
+ _synctex_handle_set_tlc(x_handle,child,!form);
+# if SYNCTEX_VERBOSE
synctex_node_log(child);
-# endif
- goto sibling_loop;
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_HBOX) {
- goto scan_hbox;
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_HBOX) {
-scan_xobh:
- ++SYNCTEX_CUR;
- if ((parent) && parent->class->type == synctex_node_type_hbox) {
- /* Update the mean line number */
- synctex_node_t node = SYNCTEX_CHILD(parent);
- if (node) {
- unsigned int node_weight = 0;
- unsigned int cumulated_line_numbers = 0;
- do {
- if (synctex_node_type(node)==synctex_node_type_hbox) {
- if (SYNCTEX_NODE_WEIGHT(node)) {
- node_weight += SYNCTEX_NODE_WEIGHT(node);
- cumulated_line_numbers += SYNCTEX_MEAN_LINE(node)*SYNCTEX_NODE_WEIGHT(node);
+# endif
+ if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
+ _synctex_error("Uncomplete container.");
+ SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
+ }
+ last_k = last_g = NULL;
+ 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) {
+ x_handle = _synctex_new_handle_with_child(x_handle);
+ 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_tlchv(child,parent);
+ if (!form) {
+ __synctex_node_make_friend_tlc(child);
+ }
+ } else {
+ _synctex_error("Can't create box bdry record.");
+ }
+# if SYNCTEX_VERBOSE
+ synctex_node_log(parent);
+# endif
+ input.node = _synctex_input_register_line(input.node,parent);
+ last_k = last_g = NULL;
+ 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 && (sibling = __synctex_tree_sibling(node))) {
+ unsigned int node_weight = 0;
+ unsigned int cumulated_line_numbers = 0;
+ _synctex_data_set_line(node, _synctex_data_line(sibling));
+ node = sibling;
+ 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_MEAN_LINE(node);
+ cumulated_line_numbers += synctex_node_line(node);
}
- } else {
- ++node_weight;
- cumulated_line_numbers += SYNCTEX_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_tlc(sibling,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));
+ if (last_k && last_g && (child = synctex_node_child(parent))) {
+ /* Find the node preceeding last_k */
+ synctex_node_p next;
+ while ((next = __synctex_tree_sibling(child))) {
+ if (next == last_k) {
+ _synctex_data_set_tlc(last_k,child);
+ _synctex_data_set_tlc(last_g,child);
+ break;
+ }
+ child = next;
}
- } while ((node = SYNCTEX_SIBLING(node)));
- SYNCTEX_MEAN_LINE(parent)=(cumulated_line_numbers + node_weight/2)/node_weight;
- SYNCTEX_NODE_WEIGHT(parent)=node_weight;
+ }
+ child = parent;
+ parent = _synctex_tree_parent(child);
+ if (!form) {
+ _synctex_handle_make_friend_tlc(x_handle);
+ }
+ x_handle = _synctex_handle_pop_child(x_handle);
+ _synctex_handle_set_tlc(x_handle,child,!form);
+ _synctex_make_hbox_contain_box(parent, _synctex_data_box_V(child));
+# if SYNCTEX_VERBOSE
+ synctex_node_log(child);
+# endif
+ }
+ if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
+ _synctex_error("Uncomplete container.");
+ SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
+ }
+ last_k = last_g = NULL;
+ 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_MEAN_LINE(parent)=SYNCTEX_LINE(parent);
- SYNCTEX_NODE_WEIGHT(parent)=1;
+ _synctex_node_set_child(parent,ns.node);
}
- if (NULL == child) {
- /* Only boxes with no children are friends,
- * boxes with children are indirectly friends through one of their contained nodes. */
- SYNCTEX_UPDATE_BOX_FRIEND(parent);
- }
- /* setting the next horizontal box at the end ensures that a child is recorded before any of its ancestors. */
- SYNCTEX_SET_NEXT_hbox(box,parent);
- box = parent;
- child = parent;
- parent = SYNCTEX_PARENT(child);
- } else {
- _synctex_error("Unexpected end of hbox, ignored.");
- }
- if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Uncomplete sheet.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
-# if SYNCTEX_VERBOSE
+ child = ns.node;
+ _synctex_handle_set_tlc(x_handle, child,!form);
+# if SYNCTEX_VERBOSE
synctex_node_log(child);
-# endif
- goto sibling_loop;
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_VOID_VBOX) {
- if (NULL != (child = _synctex_new_void_vbox(scanner))
- && NULL != (info = SYNCTEX_INFO(child))) {
- if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
- || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Bad void vbox record.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- SYNCTEX_SET_CHILD(parent,child);
- #define SYNCTEX_UPDATE_FRIEND(NODE)\
- friend_index = (info[SYNCTEX_TAG_IDX].INT+info[SYNCTEX_LINE_IDX].INT)%(scanner->number_of_lists);\
- SYNCTEX_SET_FRIEND(NODE,(scanner->lists_of_friends)[friend_index]);\
- (scanner->lists_of_friends)[friend_index] = NODE;
- SYNCTEX_UPDATE_FRIEND(child);
-# if SYNCTEX_VERBOSE
- synctex_node_log(child);
-# endif
- goto sibling_loop;
- } else {
- _synctex_error("Can't create vbox record.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_VOID_HBOX) {
- if (NULL != (child = _synctex_new_void_hbox(scanner))
- && NULL != (info = SYNCTEX_INFO(child))) {
- if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
- || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Bad void hbox record.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- SYNCTEX_SET_CHILD(parent,child);
- SYNCTEX_UPDATE_FRIEND(child);
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child));
-# if SYNCTEX_VERBOSE
- synctex_node_log(child);
-# endif
- goto sibling_loop;
- } else {
- _synctex_error("Can't create void hbox record.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_KERN) {
- if (NULL != (child = _synctex_new_kern(scanner))
- && NULL != (info = SYNCTEX_INFO(child))) {
- if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
- || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Bad kern record.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- SYNCTEX_SET_CHILD(parent,child);
- SYNCTEX_UPDATE_FRIEND(child);
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child)-SYNCTEX_WIDTH(child),SYNCTEX_VERT(child));
-# if SYNCTEX_VERBOSE
- synctex_node_log(child);
-# endif
- goto sibling_loop;
- } else {
- _synctex_error("Can't create kern record.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_GLUE) {
- if (NULL != (child = _synctex_new_glue(scanner))
- && NULL != (info = SYNCTEX_INFO(child))) {
- if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
- || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Bad glue record.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- SYNCTEX_SET_CHILD(parent,child);
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
- SYNCTEX_UPDATE_FRIEND(child);
-# if SYNCTEX_VERBOSE
- synctex_node_log(child);
-# endif
- goto sibling_loop;
- } else {
- _synctex_error("Can't create glue record.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_MATH) {
- if (NULL != (child = _synctex_new_math(scanner))
- && NULL != (info = SYNCTEX_INFO(child))) {
- if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
- || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Bad math record.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- SYNCTEX_SET_CHILD(parent,child);
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
- SYNCTEX_UPDATE_FRIEND(child);
-# if SYNCTEX_VERBOSE
- synctex_node_log(child);
-# endif
- goto sibling_loop;
- } else {
- _synctex_error("Can't create math record.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BOUNDARY) {
- if (NULL != (child = _synctex_new_boundary(scanner))
- && NULL != (info = SYNCTEX_INFO(child))) {
- if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
- || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Bad boundary record.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- SYNCTEX_SET_CHILD(parent,child);
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
- SYNCTEX_UPDATE_FRIEND(child);
-# if SYNCTEX_VERBOSE
- synctex_node_log(child);
-# endif
- goto sibling_loop;
- } else {
- _synctex_error("Can't create math record.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_SHEET) {
- goto scan_teehs;
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_SHEET) {
- /* Addendum to version 1.10 to manage nested sheets */
- ++SYNCTEX_CUR;
- if (_synctex_scan_nested_sheet(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Unexpected nested sheet.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- goto child_loop;
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_ANCHOR) {
- goto scan_anchor;
- } else {
- /* _synctex_error("Ignored record %c\n",*SYNCTEX_CUR); */
- ++SYNCTEX_CUR;
- if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Unexpected end.");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- goto child_loop;
- }
- } else {
- available = 1;
- status = _synctex_buffer_get_available_size(scanner,&available);
- if (status<SYNCTEX_STATUS_OK && available>0){
- _synctex_error("Uncomplete sheet(0)");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- } else {
- goto child_loop;
- }
- }
-/* The vertical loop means that we are on the same level, for example when we just ended a box.
- * If a node is created now, it will be a sibling of the current node, sharing the same parent. */
-sibling_loop:
- if (SYNCTEX_CUR<SYNCTEX_END) {
- if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_VBOX) {
- if (NULL != (sibling = _synctex_new_vbox(scanner))
- && NULL != (info = SYNCTEX_INFO(sibling))) {
- if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
- || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Bad vbox record (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- SYNCTEX_SET_SIBLING(child,sibling);
- parent = sibling;
- child = NULL;
- goto child_loop;
- } else {
- _synctex_error("Can't create vbox record (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_VBOX) {
- goto scan_xobv;
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_HBOX) {
- if (NULL != (sibling = _synctex_new_hbox(scanner)) &&
- NULL != (info = SYNCTEX_INFO(sibling))) {
- if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
- || _synctex_setup_visible_box(sibling)<SYNCTEX_STATUS_OK
- || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Bad hbox record (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- SYNCTEX_SET_SIBLING(child,sibling);
- child = sibling;
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child));
-# if SYNCTEX_VERBOSE
- synctex_node_log(child);
-# endif
- parent = child;
- child = NULL;
- goto child_loop;
- } else {
- _synctex_error("Can't create hbox record (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_HBOX) {
- goto scan_xobh;
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_VOID_VBOX) {
- if (NULL != (sibling = _synctex_new_void_vbox(scanner)) &&
- NULL != (info = SYNCTEX_INFO(sibling))) {
- if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
- || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Bad void vbox record (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- SYNCTEX_SET_SIBLING(child,sibling);
- child = sibling;
-# if SYNCTEX_VERBOSE
- synctex_node_log(child);
-# endif
- SYNCTEX_UPDATE_FRIEND(child);
- goto sibling_loop;
- } else {
- _synctex_error("can't create void vbox record (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_VOID_HBOX) {
- if (NULL != (sibling = _synctex_new_void_hbox(scanner)) &&
- NULL != (info = SYNCTEX_INFO(sibling))) {
- if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
- || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Bad void hbox record (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- SYNCTEX_SET_SIBLING(child,sibling);
- child = sibling;
-# if SYNCTEX_VERBOSE
- synctex_node_log(child);
-# endif
- SYNCTEX_UPDATE_FRIEND(child);
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child));
- goto sibling_loop;
- } else {
- _synctex_error("can't create void hbox record (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_KERN) {
- if (NULL != (sibling = _synctex_new_kern(scanner))
- && NULL != (info = SYNCTEX_INFO(sibling))) {
- if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
- || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Bad kern record (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- SYNCTEX_SET_SIBLING(child,sibling);
- child = sibling;
-# if SYNCTEX_VERBOSE
- synctex_node_log(child);
-# endif
- SYNCTEX_UPDATE_FRIEND(child);
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child)-SYNCTEX_WIDTH(child),SYNCTEX_VERT(child));
- goto sibling_loop;
- } else {
- _synctex_error("Can't create kern record (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_GLUE) {
- if (NULL != (sibling = _synctex_new_glue(scanner))
- && NULL != (info = SYNCTEX_INFO(sibling))) {
- if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
- || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Bad glue record (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- SYNCTEX_SET_SIBLING(child,sibling);
- child = sibling;
-# if SYNCTEX_VERBOSE
- synctex_node_log(child);
-# endif
- SYNCTEX_UPDATE_FRIEND(child);
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
- goto sibling_loop;
- } else {
- _synctex_error("Can't create glue record (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_MATH) {
- if (NULL != (sibling = _synctex_new_math(scanner))
- && NULL != (info = SYNCTEX_INFO(sibling))) {
- if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
- || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Bad math record (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- SYNCTEX_SET_SIBLING(child,sibling);
- child = sibling;
-# if SYNCTEX_VERBOSE
- synctex_node_log(child);
-# endif
- SYNCTEX_UPDATE_FRIEND(child);
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
- goto sibling_loop;
- } else {
- _synctex_error("Can't create math record (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BOUNDARY) {
- if (NULL != (sibling = _synctex_new_boundary(scanner))
- && NULL != (info = SYNCTEX_INFO(sibling))) {
- if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
- || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
- || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Bad boundary record (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- SYNCTEX_SET_SIBLING(child,sibling);
- child = sibling;
-# if SYNCTEX_VERBOSE
- synctex_node_log(child);
-# endif
- SYNCTEX_UPDATE_FRIEND(child);
- _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
- goto sibling_loop;
- } else {
- _synctex_error("Can't create boundary record (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_SHEET) {
- goto scan_teehs;
- } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_ANCHOR) {
- ++SYNCTEX_CUR;
- if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- _synctex_error("Missing anchor (2).");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- goto sibling_loop;
- } else {
- ++SYNCTEX_CUR;
- /* _synctex_error("Ignored record %c(2)\n",*SYNCTEX_CUR); */
- if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- goto sibling_loop;
- }
- } else {
- available = 1;
- status = _synctex_buffer_get_available_size(scanner,&available);
- if (status<SYNCTEX_STATUS_OK && available>0){
- goto sibling_loop;
- } else {
- _synctex_error("Uncomplete sheet(2)");
- SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
- }
- }
-# undef SYNCTEX_DECODE_FAILED
+# endif
+ input.node = _synctex_input_register_line(input.node,child);
+ last_k = last_g = NULL;
+ 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_handle_set_tlc(x_handle, child,!form);
+ _synctex_make_hbox_contain_box(parent,_synctex_data_box(child));
+# if SYNCTEX_VERBOSE
+ synctex_node_log(child);
+# endif
+ input.node = _synctex_input_register_line(input.node,child);
+ last_k = last_g = NULL;
+ 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_handle_set_tlc(x_handle, child,!form);
+ _synctex_make_hbox_contain_box(parent,_synctex_data_xob(child));
+# if SYNCTEX_VERBOSE
+ synctex_node_log(child);
+# endif
+ input.node = _synctex_input_register_line(input.node,child);
+ last_k = child;
+ last_g = NULL;
+ 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_handle_set_tlc(x_handle, child,!form);
+ _synctex_make_hbox_contain_point(parent,_synctex_data_point(child));
+# if SYNCTEX_VERBOSE
+ synctex_node_log(child);
+# endif
+ input.node = _synctex_input_register_line(input.node,child);
+ if (last_k) {
+ last_g = child;
+ } else {
+ last_k = last_g = NULL;
+ }
+ 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);
+ }
+ _synctex_handle_set_tlc(x_handle, child,!form);
+ /* Rules are sometimes far too big
+_synctex_make_hbox_contain_box(parent,_synctex_data_box(child));
+ */
+# if SYNCTEX_VERBOSE
+ synctex_node_log(child);
+# endif
+ input.node = _synctex_input_register_line(input.node,child);
+ last_k = last_g = NULL;
+ 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_handle_set_tlc(x_handle, child,!form);
+ _synctex_make_hbox_contain_point(parent,_synctex_data_point(child));
+# if SYNCTEX_VERBOSE
+ synctex_node_log(child);
+# endif
+ input.node = _synctex_input_register_line(input.node,child);
+ last_k = last_g = NULL;
+ goto content_loop;
+ }
+ } else if (SYNCTEX_START_SCAN(FORM_REF)) {
+# ifdef SYNCTEX_NOTHING
+# pragma mark + SCAN FORM REF
+# endif
+#if 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;
+ }
+# if SYNCTEX_VERBOSE
+ synctex_node_log(child);
+# endif
+ last_k = last_g = NULL;
+ 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);
+ }
+ if (synctex_node_type(child)==synctex_node_type_box_bdry
+ || _synctex_tree_target(x_handle)) {
+ child = _synctex_tree_reset_child(x_handle);
+ child = _synctex_new_handle_with_child(child);
+ __synctex_tree_set_sibling(child, x_handle);
+ x_handle = child;
+ _synctex_tree_set_target(x_handle,ns.node);
+ } else if (!form) {
+ __synctex_node_make_friend_tlc(ns.node);
+ }
+ child = ns.node;
+ _synctex_make_hbox_contain_point(parent,_synctex_data_point(child));
+# if SYNCTEX_VERBOSE
+ synctex_node_log(child);
+# endif
+ input.node = _synctex_input_register_line(input.node,child);
+ last_k = last_g = NULL;
+ 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);
+ }
+ last_k = last_g = NULL;
+ 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.");
+ SYNCTEX_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);
+ }
+ last_k = last_g = NULL;
+ 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);
+ }
+ last_k = last_g = NULL;
+ goto content_loop;
}
-
-# define SYNCTEX_APPEND_SHEET(SCANNER,SHEET) if (SCANNER->sheet) {\
- synctex_node_t last_sheet = SCANNER->sheet;\
- synctex_node_t next_sheet = NULL;\
- while ((next_sheet = SYNCTEX_SIBLING(last_sheet))) {\
- last_sheet = next_sheet;\
- }\
- SYNCTEX_SET_SIBLING(last_sheet,SHEET);\
- } else {\
- SCANNER->sheet = SHEET;\
+#undef SYNCTEX_RETURN
+/**
+ * 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 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 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 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 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 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 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 SYNCTEX_DEBUG>500
+ printf("! ref replaced in sheet _synctex_post_process.\n");
+ synctex_node_display(scanner->sheet);
+#endif
+#if 0
+ {
+ int i;
+ for (i=0;i<scanner->number_of_lists;++i) {
+ synctex_node_p P = ns.node;
+ do {
+ synctex_node_p N = scanner->lists_of_friends[i];
+ do {
+ if (P == N) {
+ printf("Already registered.\n");
+ synctex_node_display(N);
+ break;
+ }
+ } while ((N = _synctex_tree_friend(N)));
+ } while((P = _synctex_tree_friend(P)));
+ }
+ }
+#endif
+#if 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 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
*/
-synctex_status_t _synctex_scan_content(synctex_scanner_t scanner) {
- synctex_node_t sheet = NULL;
- synctex_status_t status = 0;
- if (NULL == scanner) {
- return SYNCTEX_STATUS_BAD_ARGUMENT;
- }
- /* set up the lists of friends */
- if (NULL == scanner->lists_of_friends) {
- scanner->number_of_lists = 1024;
- scanner->lists_of_friends = (synctex_node_t *)_synctex_malloc(scanner->number_of_lists*sizeof(synctex_node_t));
- if (NULL == scanner->lists_of_friends) {
- _synctex_error("malloc:2");
- return SYNCTEX_STATUS_ERROR;
- }
- }
- /* Find where this section starts */
+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;
- }
-next_sheet:
- if (*SYNCTEX_CUR != SYNCTEX_CHAR_BEGIN_SHEET) {
- status = _synctex_scan_postamble(scanner);
- if (status < SYNCTEX_STATUS_EOF) {
- _synctex_error("Bad content.");
- return status;
- }
- if (status<SYNCTEX_STATUS_OK) {
- status = _synctex_next_line(scanner);
- if (status < SYNCTEX_STATUS_OK) {
- _synctex_error("Bad content.");
- return status;
- }
- goto next_sheet;
- }
- return SYNCTEX_STATUS_OK;
- }
- /* Create a new sheet node */
- sheet = _synctex_new_sheet(scanner);
- status = _synctex_decode_int(scanner,&(SYNCTEX_PAGE(sheet)));
- if (status<SYNCTEX_STATUS_OK) {
- _synctex_error("Missing sheet number.");
-bail:
- SYNCTEX_FREE(sheet);
- return SYNCTEX_STATUS_ERROR;
- }
- status = _synctex_next_line(scanner);
- if (status<SYNCTEX_STATUS_OK) {
- _synctex_error("Uncomplete file.");
- goto bail;
- }
- status = _synctex_scan_sheet(scanner,sheet);
- if (status<SYNCTEX_STATUS_OK) {
- _synctex_error("Bad sheet content.");
- goto bail;
- }
- SYNCTEX_APPEND_SHEET(scanner,sheet);
- sheet = NULL;
- /* Now read the list of Inputs between 2 sheets. */
- do {
- status = _synctex_scan_input(scanner);
- if (status<SYNCTEX_STATUS_EOF) {
- _synctex_error("Bad input section.");
- goto bail;
- }
- }
- while(status >= SYNCTEX_STATUS_OK);
- goto next_sheet;
-}
-
-int _synctex_open(const char * output, const char * build_directory, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_modeRef);
-
-/* Where the synctex scanner is created. */
-synctex_scanner_t synctex_scanner_new_with_output_file(const char * output, const char * build_directory, int parse) {
- gzFile file = NULL;
- char * synctex = NULL;
- synctex_scanner_t scanner = NULL;
- synctex_io_mode_t io_mode = 0;
- /* Here we assume that int are smaller than void * */
- if (sizeof(int)>sizeof(void*)) {
- _synctex_error("INTERNAL INCONSISTENCY: int's are unexpectedly bigger than pointers, bailing out.");
- return NULL;
- }
- /* We ensure that SYNCTEX_BUFFER_SIZE < UINT_MAX, I don't know if it makes sense... */
- if (SYNCTEX_BUFFER_SIZE >= UINT_MAX) {
- _synctex_error("Internal inconsistency, bad SYNCTEX_BUFFER_SIZE (1)");
- return NULL;
- }
- /* for integers: */
- if (SYNCTEX_BUFFER_SIZE < SYNCTEX_BUFFER_MIN_SIZE) {
- _synctex_error("Internal inconsistency, bad SYNCTEX_BUFFER_SIZE (2)");
- return NULL;
- }
- /* now open the synctex file */
- if (_synctex_open(output,build_directory,&synctex,&file,synctex_ADD_QUOTES,&io_mode) || !file) {
- if (_synctex_open(output,build_directory,&synctex,&file,synctex_DONT_ADD_QUOTES,&io_mode) || !file) {
- return NULL;
- }
- }
- scanner = (synctex_scanner_t)_synctex_malloc(sizeof(_synctex_scanner_t));
- if (NULL == scanner) {
- _synctex_error("malloc problem");
- free(synctex);
- gzclose(file);
- return NULL;
- }
- /* make a private copy of output for the scanner */
- if (NULL == (scanner->output = (char *)malloc(strlen(output)+1))){
- _synctex_error("! synctex_scanner_new_with_output_file: Memory problem (2), scanner's output is not reliable.");
- } else if (scanner->output != strcpy(scanner->output,output)) {
- _synctex_error("! synctex_scanner_new_with_output_file: Copy problem, scanner's output is not reliable.");
- }
- scanner->synctex = synctex;/* Now the scanner owns synctex */
- SYNCTEX_FILE = file;
- return parse? synctex_scanner_parse(scanner):scanner;
+ 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;
}
-
-/* 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.
- * 0 on success, non 0 on error. */
-static int __synctex_open(const char * output, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_mode_ref) {
- if (synctex_name_ref && file_ref && io_mode_ref) {
- /* 1 local variables that uses dynamic memory */
- char * synctex_name = NULL;
- gzFile the_file = NULL;
- char * quoteless_synctex_name = NULL;
- size_t size = 0;
- synctex_io_mode_t io_mode = *io_mode_ref;
- const char * mode = _synctex_get_io_mode_name(io_mode);
- /* now create the synctex file name */
- size = strlen(output)+strlen(synctex_suffix)+strlen(synctex_suffix_gz)+1;
- synctex_name = (char *)malloc(size);
- if (NULL == synctex_name) {
- _synctex_error("! __synctex_open: Memory problem (1)\n");
- return 1;
- }
- /* 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 (synctex_name != strcpy(synctex_name,output)) {
- _synctex_error("! __synctex_open: Copy problem\n");
-return_on_error:
- free(synctex_name);
- free(quoteless_synctex_name);
- return 2;
- }
- /* remove the last path extension if any */
- _synctex_strip_last_path_extension(synctex_name);
- if (!strlen(synctex_name)) {
- goto return_on_error;
- }
- /* now insert quotes. */
- if (add_quotes) {
- char * quoted = NULL;
- if (_synctex_copy_with_quoting_last_path_component(synctex_name,&quoted,size) || (NULL == quoted)) {
- /* There was an error or quoting does not make sense: */
- goto return_on_error;
- }
- quoteless_synctex_name = synctex_name;
- synctex_name = quoted;
- }
- /* Now add to synctex_name the first path extension. */
- if (synctex_name != strcat(synctex_name,synctex_suffix)){
- _synctex_error("! __synctex_open: 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 == (the_file = gzopen(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 %s, error %i\n",synctex_name,errno);
- goto return_on_error;
- }
- /* Apparently, there is no uncompressed synctex file. Try the compressed version */
- if (synctex_name != strcat(synctex_name,synctex_suffix_gz)){
- _synctex_error("! __synctex_open: Concatenation problem (can't add suffix '%s')\n",synctex_suffix_gz);
- goto return_on_error;
- }
- io_mode |= synctex_io_gz_mask;
- mode = _synctex_get_io_mode_name(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 == (the_file = gzopen(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 %s, error %i\n",synctex_name,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(the_file);
- if (rename(synctex_name,quoteless_synctex_name)) {
- _synctex_error("Could not rename %s to %s, error %i\n",synctex_name,quoteless_synctex_name,errno);
- /* We could not rename, reopen the file with the quoted name. */
- if (NULL == (the_file = gzopen(synctex_name,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",synctex_name,errno);
- }
- goto return_on_error;
- }
- } else {
- /* The file has been successfully renamed */
- if (NULL == (the_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(synctex_name);
- synctex_name = quoteless_synctex_name;
- quoteless_synctex_name = NULL;
- }
- }
- /* The operation is successfull, return the arguments by value. */
- * file_ref = the_file;
- * io_mode_ref = io_mode;
- * synctex_name_ref = synctex_name;
- return 0;
- }
- return 3; /* Bad parameter. */
+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;
}
-
-/* Opens the ouput file, taking into account the eventual build_directory.
- * 0 on success, non 0 on error. */
-int _synctex_open(const char * output, const char * build_directory, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_mode_ref) {
-# define synctex_name (*synctex_name_ref)
-# define the_file (*file_ref)
- int result = __synctex_open(output,synctex_name_ref,file_ref,add_quotes,io_mode_ref);
- if ((result || !*file_ref) && 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 *)malloc(size))) {
- if (is_absolute) {
- build_output[0] = '\0';
- } else {
- if (build_output != strcpy(build_output,output)) {
- free(build_output);
- return -4;
- }
- 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,"/")) {
- free(build_output);
- return -2;
- }
- }
- /* Append the last path component of the output. */
- if (build_output != strcat(build_output,lpc)) {
- free(build_output);
- return -3;
- }
- result = __synctex_open(build_output,synctex_name_ref,file_ref,add_quotes,io_mode_ref);
- free(build_output);
- return result;
- }
- free(build_output);
- }
- return -1;
- }
- return result;
-# undef synctex_name
-# undef the_file
+/* 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;
+ }
+ _synctex_error("No file?");
+ return NULL;
}
/* The scanner destructor
*/
-void synctex_scanner_free(synctex_scanner_t scanner) {
- if (NULL == scanner) {
- return;
- }
- if (SYNCTEX_FILE) {
- gzclose(SYNCTEX_FILE);
- SYNCTEX_FILE = NULL;
- }
- SYNCTEX_FREE(scanner->sheet);
- SYNCTEX_FREE(scanner->input);
- free(SYNCTEX_START);
- free(scanner->output_fmt);
- free(scanner->output);
- free(scanner->synctex);
- free(scanner->lists_of_friends);
- free(scanner);
+int synctex_scanner_free(synctex_scanner_p scanner) {
+ int node_count = 0;
+ if (scanner) {
+ if (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 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_t synctex_scanner_parse(synctex_scanner_t 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 overriden by the real life value */
- scanner->x_offset = scanner->y_offset = 6.027e23f;
-# 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(sheet);
- DEFINE_synctex_scanner_class(input);
- 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(math);
- DEFINE_synctex_scanner_class(boundary);
- SYNCTEX_START = (char *)malloc(SYNCTEX_BUFFER_SIZE+1); /* one more character for null termination */
- if (NULL == SYNCTEX_START) {
- _synctex_error("malloc error");
- synctex_scanner_free(scanner);
- return NULL;
- }
- 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;
+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 overriden by the real life value */
+ scanner->x_offset = scanner->y_offset = 6.027e23f;
+ scanner->reader->line_number = 1;
+
+ 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->charindex_offset = -SYNCTEX_BUFFER_SIZE;
+ scanner->reader->charindex_offset = -SYNCTEX_BUFFER_SIZE;
# endif
- status = _synctex_scan_preamble(scanner);
- if (status<SYNCTEX_STATUS_OK) {
- _synctex_error("SyncTeX Error: Bad preamble\n");
-bailey:
- synctex_scanner_free(scanner);
- return NULL;
- }
- status = _synctex_scan_content(scanner);
- if (status<SYNCTEX_STATUS_OK) {
- _synctex_error("SyncTeX Error: Bad content\n");
- goto bailey;
- }
- /* 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
+ 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 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_t scanner){
- return scanner?scanner->pre_x_offset:0;
-}
-int synctex_scanner_pre_y_offset(synctex_scanner_t scanner){
- return scanner?scanner->pre_y_offset:0;
-}
-int synctex_scanner_x_offset(synctex_scanner_t scanner){
- return scanner?scanner->x_offset:0;
-}
-int synctex_scanner_y_offset(synctex_scanner_t scanner){
- return scanner?scanner->y_offset:0;
-}
-float synctex_scanner_magnification(synctex_scanner_t scanner){
- return scanner?scanner->unit:1;
-}
-void synctex_scanner_display(synctex_scanner_t scanner) {
- if (NULL == scanner) {
- return;
- }
- printf("The scanner:\noutput:%s\noutput_fmt:%s\nversion:%i\n",scanner->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_DISPLAY(scanner->input);
- if (scanner->count<1000) {
- printf("The sheets:\n");
- SYNCTEX_DISPLAY(scanner->sheet);
- printf("The friends:\n");
- if (scanner->lists_of_friends) {
- int i = scanner->number_of_lists;
- synctex_node_t 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_TAG(node),
- SYNCTEX_LINE(node)
- );
- node = SYNCTEX_FRIEND(node);
- }
- }
- }
- } else {
- printf("SyncTeX Warning: Too many objects\n");
- }
-}
-/* Public*/
-const char * synctex_scanner_get_name(synctex_scanner_t scanner,int tag) {
- synctex_node_t input = NULL;
- if (NULL == scanner) {
- return NULL;
- }
- input = scanner->input;
- do {
- if (tag == SYNCTEX_TAG(input)) {
- return (SYNCTEX_NAME(input));
- }
- } while((input = SYNCTEX_SIBLING(input)) != NULL);
- return NULL;
-}
-
-int _synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name);
-int _synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name) {
- synctex_node_t input = NULL;
- if (NULL == scanner) {
- return 0;
- }
- input = scanner->input;
- do {
- if (_synctex_is_equivalent_file_name(name,(SYNCTEX_NAME(input)))) {
- return SYNCTEX_TAG(input);
- }
- } while((input = SYNCTEX_SIBLING(input)) != NULL);
+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);
- input = scanner->input;
- do {
- if (_synctex_is_equivalent_file_name(name,_synctex_base_name(SYNCTEX_NAME(input)))) {
- synctex_node_t other_input = input;
- while((other_input = SYNCTEX_SIBLING(other_input)) != NULL) {
- if (_synctex_is_equivalent_file_name(name,_synctex_base_name(SYNCTEX_NAME(other_input)))
- && (strlen(SYNCTEX_NAME(input))!=strlen(SYNCTEX_NAME(other_input))
- || strncmp(SYNCTEX_NAME(other_input),SYNCTEX_NAME(input),strlen(SYNCTEX_NAME(input))))) {
- // There is a second possible candidate
- return 0;
+ 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);
}
- return SYNCTEX_TAG(input);
- }
- } while((input = SYNCTEX_SIBLING(input)) != NULL);
- return 0;
-}
-
-int synctex_scanner_get_tag(synctex_scanner_t 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->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_t synctex_scanner_input(synctex_scanner_t scanner) {
- return scanner?scanner->input:NULL;
-}
-const char * synctex_scanner_get_output_fmt(synctex_scanner_t scanner) {
- return NULL != scanner && scanner->output_fmt?scanner->output_fmt:"";
-}
-const char * synctex_scanner_get_output(synctex_scanner_t scanner) {
- return NULL != scanner && scanner->output?scanner->output:"";
-}
-const char * synctex_scanner_get_synctex(synctex_scanner_t scanner) {
- return NULL != scanner && scanner->synctex?scanner->synctex:"";
+ } 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
-int synctex_node_h(synctex_node_t node){
- if (!node) {
- return 0;
- }
- return SYNCTEX_HORIZ(node);
-}
-int synctex_node_v(synctex_node_t node){
- if (!node) {
- return 0;
- }
- return SYNCTEX_VERT(node);
-}
-int synctex_node_width(synctex_node_t node){
- if (!node) {
- return 0;
- }
- return SYNCTEX_WIDTH(node);
-}
-int synctex_node_box_h(synctex_node_t node){
- if (!node) {
- return 0;
- }
- if (SYNCTEX_IS_BOX(node)) {
-result:
- return SYNCTEX_HORIZ(node);
- }
- if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
- goto result;
- }
- return 0;
-}
-int synctex_node_box_v(synctex_node_t node){
- if (!node) {
- return 0;
- }
- if (SYNCTEX_IS_BOX(node)) {
-result:
- return SYNCTEX_VERT(node);
- }
- if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
- goto result;
- }
- return 0;
-}
-int synctex_node_box_width(synctex_node_t node){
- if (!node) {
- return 0;
- }
- if (SYNCTEX_IS_BOX(node)) {
-result:
- return SYNCTEX_WIDTH(node);
- }
- if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
- goto result;
- }
- return 0;
-}
-int synctex_node_box_height(synctex_node_t node){
- if (!node) {
- return 0;
- }
- if (SYNCTEX_IS_BOX(node)) {
-result:
- return SYNCTEX_HEIGHT(node);
- }
- if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
- goto result;
- }
- return 0;
-}
-int synctex_node_box_depth(synctex_node_t node){
- if (!node) {
- return 0;
- }
- if (SYNCTEX_IS_BOX(node)) {
-result:
- return SYNCTEX_DEPTH(node);
- }
- if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
- goto result;
- }
- return 0;
+
+# 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
-float synctex_node_visible_h(synctex_node_t node){
- if (!node) {
- return 0;
- }
- return SYNCTEX_HORIZ(node)*node->class->scanner->unit+node->class->scanner->x_offset;
-}
-float synctex_node_visible_v(synctex_node_t node){
- if (!node) {
- return 0;
- }
- return SYNCTEX_VERT(node)*node->class->scanner->unit+node->class->scanner->y_offset;
-}
-float synctex_node_visible_width(synctex_node_t node){
- if (!node) {
- return 0;
- }
- return SYNCTEX_WIDTH(node)*node->class->scanner->unit;
-}
-float synctex_node_box_visible_h(synctex_node_t node){
- if (!node) {
- return 0;
- }
- switch(node->class->type) {
- case synctex_node_type_vbox:
- case synctex_node_type_void_vbox:
- case synctex_node_type_void_hbox:
- return SYNCTEX_HORIZ(node)*node->class->scanner->unit+node->class->scanner->x_offset;
- case synctex_node_type_hbox:
-result:
- return SYNCTEX_HORIZ_V(node)*node->class->scanner->unit+node->class->scanner->x_offset;
- }
- if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
- goto result;
- }
- return 0;
-}
-float synctex_node_box_visible_v(synctex_node_t node){
- if (!node) {
- return 0;
- }
- switch(node->class->type) {
- case synctex_node_type_vbox:
- case synctex_node_type_void_vbox:
- case synctex_node_type_void_hbox:
- return SYNCTEX_VERT(node)*node->class->scanner->unit+node->class->scanner->y_offset;
- case synctex_node_type_hbox:
-result:
- return SYNCTEX_VERT_V(node)*node->class->scanner->unit+node->class->scanner->y_offset;
- }
- if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
- goto result;
- }
- return 0;
-}
-float synctex_node_box_visible_width(synctex_node_t node){
- if (!node) {
- return 0;
- }
- switch(node->class->type) {
- case synctex_node_type_vbox:
- case synctex_node_type_void_vbox:
- case synctex_node_type_void_hbox:
- return SYNCTEX_WIDTH(node)*node->class->scanner->unit;
- case synctex_node_type_hbox:
-result:
- return SYNCTEX_WIDTH_V(node)*node->class->scanner->unit;
- }
- if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
- goto result;
- }
- return 0;
-}
-float synctex_node_box_visible_height(synctex_node_t node){
- if (!node) {
- return 0;
- }
- switch(node->class->type) {
- case synctex_node_type_vbox:
- case synctex_node_type_void_vbox:
- case synctex_node_type_void_hbox:
- return SYNCTEX_HEIGHT(node)*node->class->scanner->unit;
- case synctex_node_type_hbox:
-result:
- return SYNCTEX_HEIGHT_V(node)*node->class->scanner->unit;
- }
- if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
- goto result;
- }
- return 0;
-}
-float synctex_node_box_visible_depth(synctex_node_t node){
- if (!node) {
- return 0;
- }
- switch(node->class->type) {
- case synctex_node_type_vbox:
- case synctex_node_type_void_vbox:
- case synctex_node_type_void_hbox:
- return SYNCTEX_DEPTH(node)*node->class->scanner->unit;
- case synctex_node_type_hbox:
-result:
- return SYNCTEX_DEPTH_V(node)*node->class->scanner->unit;
- }
- if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
- goto result;
- }
- return 0;
+
+#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);
}
-# ifdef SYNCTEX_NOTHING
-# pragma mark -
-# pragma mark Other public node attributes
-# endif
-int synctex_node_page(synctex_node_t node){
- synctex_node_t parent = NULL;
- if (!node) {
- return -1;
- }
- parent = SYNCTEX_PARENT(node);
- while(parent) {
- node = parent;
- parent = SYNCTEX_PARENT(node);
- }
- if (node->class->type == synctex_node_type_sheet) {
- return SYNCTEX_PAGE(node);
- }
- return -1;
-}
-synctex_charindex_t synctex_node_charindex(synctex_node_t node) {
- return node?SYNCTEX_CHARINDEX(node):0;
-}
-int synctex_node_tag(synctex_node_t node) {
- return node?SYNCTEX_TAG(node):-1;
-}
-int synctex_node_line(synctex_node_t node) {
- return node?SYNCTEX_LINE(node):-1;
-}
-int synctex_node_mean_line(synctex_node_t node) {
- return node?(node->class->type==synctex_node_type_hbox?SYNCTEX_MEAN_LINE(node):SYNCTEX_LINE(node)):-1;
-}
-int synctex_node_child_count(synctex_node_t node) {
- return node?(node->class->type==synctex_node_type_hbox?SYNCTEX_NODE_WEIGHT(node):0):-1;
-}
-int synctex_node_column(synctex_node_t node) {
-# ifdef __DARWIN_UNIX03
-# pragma unused(node)
-# endif
- return -1;
+/**
+ * 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.0);
+ 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 Sheet
+# pragma mark Other public node attributes
# endif
-synctex_node_t synctex_sheet(synctex_scanner_t scanner,int page) {
- if (scanner) {
- synctex_node_t sheet = scanner->sheet;
- while(sheet) {
- if (page == SYNCTEX_PAGE(sheet)) {
- return sheet;
- }
- sheet = SYNCTEX_SIBLING(sheet);
- }
- }
- return NULL;
+/**
+ * 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));
}
-synctex_node_t synctex_sheet_content(synctex_scanner_t scanner,int page) {
- if (scanner) {
- return SYNCTEX_CHILD(synctex_sheet(scanner,page));
- }
- return NULL;
+#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 other = _synctex_tree_target(node);
+ if (other) {
+ node = other;
+ }
+ if (_synctex_data_has_mean_line(node)) {
+ return _synctex_data_mean_line(node);
+ }
+ if ((other = synctex_node_parent(node))) {
+ if (_synctex_data_has_mean_line(other)) {
+ return _synctex_data_mean_line(other);
+ }
+ }
+ return synctex_node_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 Query
+# pragma mark Sheet & Form
# endif
-synctex_status_t synctex_display_query(synctex_scanner_t scanner,const char * name,int line,int column) {
-# ifdef __DARWIN_UNIX03
-# pragma unused(column)
-# endif
- int tag = synctex_scanner_get_tag(scanner,name);
- size_t size = 0;
- int friend_index = 0;
- int max_line = 0;
- synctex_node_t node = NULL;
- if (tag == 0) {
- printf("SyncTeX Warning: No tag for %s\n",name);
- return -1;
- }
- free(SYNCTEX_START);
- SYNCTEX_CUR = SYNCTEX_END = SYNCTEX_START = NULL;
- max_line = line < INT_MAX-scanner->number_of_lists ? line+scanner->number_of_lists:INT_MAX;
- while(line<max_line) {
- /* This loop will only be performed once for advanced viewers */
- friend_index = (tag+line)%(scanner->number_of_lists);
- if ((node = (scanner->lists_of_friends)[friend_index])) {
- do {
- if ((synctex_node_type(node)>=synctex_node_type_boundary)
- && (tag == SYNCTEX_TAG(node))
- && (line == SYNCTEX_LINE(node))) {
- if (SYNCTEX_CUR == SYNCTEX_END) {
- size += 16;
- SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *));
- SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START;
- SYNCTEX_START = SYNCTEX_END;
- SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *);
- }
- *(synctex_node_t *)SYNCTEX_CUR = node;
- SYNCTEX_CUR += sizeof(synctex_node_t);
- }
- } while ((node = SYNCTEX_FRIEND(node)));
- if (SYNCTEX_START == NULL) {
- /* We did not find any matching boundary, retry with glue or kern */
- node = (scanner->lists_of_friends)[friend_index];/* no need to test it again, already done */
- do {
- if ((synctex_node_type(node)>=synctex_node_type_kern)
- && (tag == SYNCTEX_TAG(node))
- && (line == SYNCTEX_LINE(node))) {
- if (SYNCTEX_CUR == SYNCTEX_END) {
- size += 16;
- SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *));
- SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START;
- SYNCTEX_START = SYNCTEX_END;
- SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *);
- }
- *(synctex_node_t *)SYNCTEX_CUR = node;
- SYNCTEX_CUR += sizeof(synctex_node_t);
- }
- } while ((node = SYNCTEX_FRIEND(node)));
- if (SYNCTEX_START == NULL) {
- /* We did not find any matching glue or kern, retry with boxes */
- node = (scanner->lists_of_friends)[friend_index];/* no need to test it again, already done */
- do {
- if ((tag == SYNCTEX_TAG(node))
- && (line == SYNCTEX_LINE(node))) {
- if (SYNCTEX_CUR == SYNCTEX_END) {
- size += 16;
- SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *));
- SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START;
- SYNCTEX_START = SYNCTEX_END;
- SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *);
- }
- *(synctex_node_t *)SYNCTEX_CUR = node;
- SYNCTEX_CUR += sizeof(synctex_node_t);
- }
- } while((node = SYNCTEX_FRIEND(node)));
- }
- }
- SYNCTEX_END = SYNCTEX_CUR;
- /* Now reverse the order to have nodes in display order, and then keep just a few nodes.
- * Order first the best node. */
- if ((SYNCTEX_START) && (SYNCTEX_END)) {
- unsigned int best_match = -1;
- unsigned int next_match = -1;
- unsigned int best_weight = 0;
- synctex_node_t * best_ref = NULL;
- synctex_node_t * start_ref = (synctex_node_t *)SYNCTEX_START;
- synctex_node_t * end_ref = (synctex_node_t *)SYNCTEX_END;
- --end_ref;
- while (start_ref < end_ref) {
- node = *start_ref;
- *start_ref = *end_ref;
- *end_ref = node;
- ++start_ref;
- --end_ref;
- }
- /* Now reorder the nodes to put first the one which fits best.
- * The idea is to walk along the list of nodes and pick up the first one
- * which line info is exactly the mean line of its parent, or at least very close.
- * Then we choose among all such node the one with the maximum number of child nodes.
- * Then we switch with the first node.
- */
- best_ref = start_ref = (synctex_node_t *)SYNCTEX_START;
- node = *start_ref;
- best_match = abs(SYNCTEX_LINE(node)-SYNCTEX_MEAN_LINE(SYNCTEX_PARENT(node)));
- end_ref = (synctex_node_t *)SYNCTEX_END;
- while (++start_ref<end_ref) {
- synctex_node_t parent = NULL;
- node = *start_ref;
- parent = SYNCTEX_PARENT(node);
- next_match = abs(SYNCTEX_LINE(node)-SYNCTEX_MEAN_LINE(parent));
- if (next_match < best_match
- || (next_match == best_match && SYNCTEX_NODE_WEIGHT(parent)>best_weight)) {
- best_match = next_match;
- best_ref = start_ref;
- best_weight = SYNCTEX_NODE_WEIGHT(parent);
- }
- }
- node = *best_ref;
- *best_ref = *(synctex_node_t *)SYNCTEX_START;
- *(synctex_node_t *)SYNCTEX_START = node;
- /* Basically, we keep the first node for each parent.
- * More precisely, we keep only nodes that are not children of
- * their predecessor's parent. */
- start_ref = (synctex_node_t *)SYNCTEX_START;
- end_ref = (synctex_node_t *)SYNCTEX_START;
-next_end:
- end_ref += 1; /* we allways have start_ref<= end_ref*/
- if (end_ref < (synctex_node_t *)SYNCTEX_END) {
- node = *end_ref;
- while ((node = SYNCTEX_PARENT(node))) {
- if (SYNCTEX_PARENT(*start_ref) == node) {
- goto next_end;
- }
- }
- start_ref += 1;
- *start_ref = *end_ref;
- goto next_end;
- }
- start_ref += 1;
- SYNCTEX_END = (char *)start_ref;
- SYNCTEX_CUR = NULL;// added on behalf of Jose Alliste
- return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t);// added on behalf Jan Sundermeyer
+/**
+ * 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;
}
- SYNCTEX_CUR = NULL;
- // return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t); removed on behalf Jan Sundermeyer
- }
-# if defined(__SYNCTEX_STRONG_DISPLAY_QUERY__)
- break;
-# else
- ++line;
-# endif
- }
- return 0;
+ 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;
}
-synctex_node_t synctex_next_result(synctex_scanner_t scanner) {
- if (NULL == SYNCTEX_CUR) {
- SYNCTEX_CUR = SYNCTEX_START;
- } else {
- SYNCTEX_CUR+=sizeof(synctex_node_t);
- }
- if (SYNCTEX_CUR<SYNCTEX_END) {
- return *(synctex_node_t*)SYNCTEX_CUR;
- } else {
- 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;
}
-/* This struct records a point in TeX coordinates.*/
+/**
+ * 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);
+}
+/**
+ * The sibling argument is a parent/child list of nodes of the same page.
+ */
typedef struct {
- int h;
- int v;
-} synctex_point_t;
+ int count;
+ synctex_node_p node;
+} synctex_counted_node_s;
+
+SYNCTEX_INLINE static synctex_counted_node_s _synctex_vertically_sorted_v2(synctex_node_p sibling) {
+ /* Clean the weights of the parents */
+ synctex_counted_node_s result = {0, NULL};
+ synctex_node_p h = NULL;
+ synctex_node_p next_h = NULL;
+ synctex_node_p parent = NULL;
+ int weight = 0;
+ synctex_node_p N = NULL;
+ h = sibling;
+ do {
+ N = _synctex_tree_target(h);
+ parent = _synctex_tree_parent(N);
+ _synctex_data_set_weight(parent, 0);
+ } while((h = _synctex_tree_child(h)));
+ /* Compute the weights of the nodes */
+ h = sibling;
+ do {
+ N = _synctex_tree_target(h);
+ parent = _synctex_tree_parent(N);
+ weight = _synctex_data_weight(parent);
+ if (weight==0) {
+ N = _synctex_tree_child(parent);
+ do {
+ if (_synctex_nodes_are_friend(N,sibling)) {
+ ++ weight;
+ }
+ } while ((N = __synctex_tree_sibling(N)));
+ _synctex_data_set_weight(h,weight);
+ _synctex_data_set_weight(parent,weight);
+ }
+ } while((h = _synctex_tree_child(h)));
+ /* Order handle nodes according to the weight */
+ h = _synctex_tree_reset_child(sibling);
+ result.node = sibling;
+ weight = 0;
+ while((h)) {
+ N = result.node;
+ if (_synctex_data_weight(h)>_synctex_data_weight(N)) {
+ next_h = _synctex_tree_set_child(h,N);
+ result.node = h;
+ } else if (_synctex_data_weight(h) == 0) {
+ ++ weight;
+ next_h = _synctex_tree_reset_child(h);
+ synctex_node_free(h);
+ } else {
+ synctex_node_p next_N = NULL;
+ while((next_N = _synctex_tree_child(N))) {
+ N = next_N;
+ if (_synctex_data_weight(h)<_synctex_data_weight(next_N)) {
+ continue;
+ }
+ break;
+ }
+ next_h = _synctex_tree_set_child(h,_synctex_tree_set_child(N,h));
+ }
+ h = next_h;
+ };
+ h = result.node;
+ weight = 0;
+ do {
+ ++weight;
+ } while((h = _synctex_tree_child(h)));
+ result.count = 1;
+ h = result.node;
+ while((next_h = _synctex_tree_child(h))) {
+ if (_synctex_data_weight(next_h)==0) {
+ _synctex_tree_reset_child(h);
+ weight = 1;
+ h = next_h;
+ while((h = _synctex_tree_child(h))) {
+ ++weight;
+ }
+ synctex_node_free(next_h);
+ break;
+ }
+ ++result.count;
+ h = next_h;
+ }
+ return result;
+}
+
+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 positive or 0 and the right one is negative or 0.
+/* 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 {
- int left;
- int right;
-} synctex_distances_t;
typedef struct {
- synctex_point_t left;
- synctex_point_t right;
-} synctex_offsets_t;
+ 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_node_t left;
- synctex_node_t right;
-} synctex_node_set_t;
+ 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_t _synctex_smallest_container(synctex_node_t node, synctex_node_t other_node);
-
-/* Returns the distance between the hit point hitPoint=(H,V) and the given node. */
-synctex_bool_t _synctex_point_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible);
-int _synctex_node_distance_to_point(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible);
+SYNCTEX_INLINE static synctex_node_p _synctex_smallest_container_v2(synctex_node_p node, synctex_node_p other_node);
-/* The best container is the deeper box that contains the hit point (H,V).
- * _synctex_eq_deepest_container 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_t _synctex_eq_deepest_container(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible);
+/* Returns the distance between the hit point hit point=(H,V) and the given node. */
-/* Once a best container is found, the closest children are the closest nodes to the left or right of the hit point.
- * Only horizontal and vertical offsets are used to compare the positions of the nodes. */
-SYNCTEX_INLINE static int _synctex_eq_get_closest_children_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef, synctex_bool_t visible);
+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. */
-SYNCTEX_INLINE static synctex_node_t _synctex_eq_closest_child(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible);
-
-#define SYNCTEX_MASK_LEFT 1
-#define SYNCTEX_MASK_RIGHT 2
-
-synctex_status_t synctex_edit_query(synctex_scanner_t scanner,int page,float h,float v) {
- synctex_node_t sheet = NULL;
- synctex_node_t node = NULL; /* placeholder */
- synctex_node_t other_node = NULL; /* placeholder */
- synctex_point_t hitPoint = {0,0}; /* placeholder */
- synctex_node_set_t bestNodes = {NULL,NULL}; /* holds the best node */
- synctex_distances_t bestDistances = {INT_MAX,INT_MAX}; /* holds the best distances for the best node */
- synctex_node_t bestContainer = NULL; /* placeholder */
- if (NULL == (scanner = synctex_scanner_parse(scanner)) || 0 >= scanner->unit) {/* scanner->unit must be >0 */
- return 0;
- }
- /* Convert the given point to scanner integer coordinates */
- hitPoint.h = (h-scanner->x_offset)/scanner->unit;
- hitPoint.v = (v-scanner->y_offset)/scanner->unit;
- /* We will store in the scanner's buffer the result of the query. */
- free(SYNCTEX_START);
- SYNCTEX_START = SYNCTEX_END = SYNCTEX_CUR = NULL;
- /* Find the proper sheet */
- sheet = scanner->sheet;
- while((sheet) && SYNCTEX_PAGE(sheet) != page) {
- sheet = SYNCTEX_SIBLING(sheet);
- }
- if (NULL == sheet) {
- return -1;
- }
- /* Now sheet points to the sheet node with proper page number */
- /* Here is how we work:
- * At first we do not consider the visible box dimensions. This will cover the most frequent cases.
- * Then we try with the visible box dimensions.
- * We try to find a non void box containing the hit point.
- * We browse all the horizontal boxes until we find one containing the hit point. */
- if ((node = SYNCTEX_NEXT_hbox(sheet))) {
- do {
- if (_synctex_point_in_box(hitPoint,node,synctex_YES)) {
- /* Maybe the hitPoint belongs to a contained vertical box. */
-end:
- /* This trick is for catching overlapping boxes */
- if ((other_node = SYNCTEX_NEXT_hbox(node))) {
- do {
- if (_synctex_point_in_box(hitPoint,other_node,synctex_YES)) {
- node = _synctex_smallest_container(other_node,node);
- }
- } while((other_node = SYNCTEX_NEXT_hbox(other_node)));
- }
- /* node is the smallest horizontal box that contains hitPoint. */
- if ((bestContainer = _synctex_eq_deepest_container(hitPoint,node,synctex_YES))) {
- node = bestContainer;
- }
- _synctex_eq_get_closest_children_in_box(hitPoint,node,&bestNodes,&bestDistances,synctex_YES);
- if (bestNodes.right && bestNodes.left) {
- if ((SYNCTEX_TAG(bestNodes.right)!=SYNCTEX_TAG(bestNodes.left))
- || (SYNCTEX_LINE(bestNodes.right)!=SYNCTEX_LINE(bestNodes.left))
- || (SYNCTEX_COLUMN(bestNodes.right)!=SYNCTEX_COLUMN(bestNodes.left))) {
- if ((SYNCTEX_START = malloc(2*sizeof(synctex_node_t)))) {
- if (bestDistances.left>bestDistances.right) {
- ((synctex_node_t *)SYNCTEX_START)[0] = bestNodes.right;
- ((synctex_node_t *)SYNCTEX_START)[1] = bestNodes.left;
- } else {
- ((synctex_node_t *)SYNCTEX_START)[0] = bestNodes.left;
- ((synctex_node_t *)SYNCTEX_START)[1] = bestNodes.right;
- }
- SYNCTEX_END = SYNCTEX_START + 2*sizeof(synctex_node_t);
- SYNCTEX_CUR = NULL;
- return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t);
- }
- return SYNCTEX_STATUS_ERROR;
- }
- /* both nodes have the same input coordinates
- * We choose the one closest to the hit point */
- if (bestDistances.left>bestDistances.right) {
- bestNodes.left = bestNodes.right;
- }
- bestNodes.right = NULL;
- } else if (bestNodes.right) {
- bestNodes.left = bestNodes.right;
- } else if (!bestNodes.left){
- bestNodes.left = node;
- }
- if ((SYNCTEX_START = malloc(sizeof(synctex_node_t)))) {
- * (synctex_node_t *)SYNCTEX_START = bestNodes.left;
- SYNCTEX_END = SYNCTEX_START + sizeof(synctex_node_t);
- SYNCTEX_CUR = NULL;
- return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t);
- }
- return SYNCTEX_STATUS_ERROR;
- }
- } while ((node = SYNCTEX_NEXT_hbox(node)));
- /* All the horizontal boxes have been tested,
- * None of them contains the hit point.
- */
- }
- /* We are not lucky */
- if ((node = SYNCTEX_CHILD(sheet))) {
- goto end;
- }
- return 0;
+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
+
+/**
+ * iterator for a deep first tree traversal.
+ */
+struct synctex_iterator_t {
+ synctex_node_p seed;
+ synctex_node_p top;
+ 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->top = 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;
+ if(!(iterator->next = _synctex_tree_child(N))) {
+ iterator->next = iterator->top = __synctex_tree_sibling(iterator->top);
+ }
+ --iterator->count;
+ return _synctex_tree_target(N);
+ }
+ return NULL;
+}
+int synctex_iterator_reset(synctex_iterator_p iterator) {
+ if (iterator) {
+ iterator->next = iterator->top = 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 (_synctex_data_line(nds.r.node)<_synctex_data_line(nds.l.node)) {
+ node = nds.r.node;
+ nds.r.node = nds.l.node;
+ nds.l.node = node;
+ } else if (_synctex_data_line(nds.r.node)==_synctex_data_line(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) {
+ /* Insert result between same_page_node and its child */
+ _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) {
+ SYNCTEX_UNUSED(column)
+ 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 ones with the biggest count.
+ */
+ if (result) {
+ /* navigate through siblings, then children */
+ 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;
+ synctex_counted_node_s cn = _synctex_vertically_sorted_v2(result);
+ int count = cn.count;
+ result = cn.node;
+ while((sibling = next_sibling)) {
+ /* What is next? Do not miss that step! */
+ next_sibling = __synctex_tree_reset_sibling(sibling);
+ cn = _synctex_vertically_sorted_v2(sibling);
+ count += cn.count;
+ sibling = cn.node;
+ 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);
+ }
+ }
+ 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 Utilities
+# pragma mark Geometric utilities
# endif
-/* Rougly speaking, this is:
- * node's h coordinate - hitPoint's h coordinate.
+/** 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.*/
-int _synctex_point_h_distance(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible);
-int _synctex_point_h_distance(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) {
- if (node) {
- int min,med,max;
- switch(node->class->type) {
- /* 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_hbox:
- /* getting the box bounds, taking into account negative width, height and depth. */
- min = visible?SYNCTEX_HORIZ_V(node):SYNCTEX_HORIZ(node);
- max = min + (visible?SYNCTEX_ABS_WIDTH_V(node):SYNCTEX_ABS_WIDTH(node));
- /* We allways have min <= max */
- if (hitPoint.h<min) {
- return min - hitPoint.h; /* regions 1+4+7, result is > 0 */
- } else if (hitPoint.h>max) {
- return max - hitPoint.h; /* regions 3+6+9, result is < 0 */
- } else {
- return 0; /* regions 2+5+8, inside the box, except for vertical coordinates */
- }
- break;
- 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.
- * For these boxes, no visible dimension available */
- min = SYNCTEX_HORIZ(node);
- max = min + SYNCTEX_ABS_WIDTH(node);
- /* We allways have min <= max */
- if (hitPoint.h<min) {
- return min - hitPoint.h; /* regions 1+4+7, result is > 0 */
- } else if (hitPoint.h>max) {
- return max - hitPoint.h; /* regions 3+6+9, result is < 0 */
- } else {
- return 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_WIDTH(node);
- if (max<0) {
- min = SYNCTEX_HORIZ(node);
- max = min - max;
- } else {
- min = -max;
- max = SYNCTEX_HORIZ(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 efectively overlapping text.
- * But this should be extremely rare. I guess that in that case, many different choices
- * could be made, one being in contradiction of the other.
- * It means that the best choice should be made according to the situation that occurs
- * most frequently.
- */
- if (hitPoint.h<min) {
- return min - hitPoint.h + 1; /* penalty to ensure other nodes are chosen first in case of overlapping ones */
- } else if (hitPoint.h>max) {
- return max - hitPoint.h - 1; /* same kind of penalty */
- } else if (hitPoint.h>med) {
- /* do things like if the node had 0 width and was placed at the max edge + 1*/
- return max - hitPoint.h + 1; /* positive, the kern is to the right of the hitPoint */
- } else {
- return min - hitPoint.h - 1; /* negative, the kern is to the left of the hitPoint */
- }
- case synctex_node_type_glue:
- case synctex_node_type_math:
- return SYNCTEX_HORIZ(node) - hitPoint.h;
- }
- }
- return INT_MAX;/* We always assume that the node is faraway to the right*/
-}
-/* Rougly speaking, this is:
- * node's v coordinate - hitPoint's v coordinate.
+ * 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 allways 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 allways 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 allways 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.*/
-int _synctex_point_v_distance(synctex_point_t hitPoint, synctex_node_t node,synctex_bool_t visible);
-int _synctex_point_v_distance(synctex_point_t hitPoint, synctex_node_t node,synctex_bool_t visible) {
-# ifdef __DARWIN_UNIX03
-# pragma unused(visible)
-# endif
- if (node) {
- int min,max;
- switch(node->class->type) {
- /* 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_hbox:
- /* getting the box bounds, taking into account negative width, height and depth. */
- min = SYNCTEX_VERT_V(node);
- max = min + SYNCTEX_ABS_DEPTH_V(node);
- min -= SYNCTEX_ABS_HEIGHT_V(node);
- /* We allways have min <= max */
- if (hitPoint.v<min) {
- return min - hitPoint.v; /* regions 1+2+3, result is > 0 */
- } else if (hitPoint.v>max) {
- return max - hitPoint.v; /* regions 7+8+9, result is < 0 */
- } else {
- return 0; /* regions 4.5.6, inside the box, except for horizontal coordinates */
- }
- break;
- 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_VERT(node);
- max = min + SYNCTEX_ABS_DEPTH(node);
- min -= SYNCTEX_ABS_HEIGHT(node);
- /* We allways have min <= max */
- if (hitPoint.v<min) {
- return min - hitPoint.v; /* regions 1+2+3, result is > 0 */
- } else if (hitPoint.v>max) {
- return max - hitPoint.v; /* regions 7+8+9, result is < 0 */
- } else {
- return 0; /* regions 4.5.6, inside the box, except for horizontal coordinates */
- }
- break;
- case synctex_node_type_kern:
- case synctex_node_type_glue:
- case synctex_node_type_math:
- return SYNCTEX_VERT(node) - hitPoint.v;
- }
- }
- return INT_MAX;/* We always assume that the node is faraway to the top*/
-}
-
-SYNCTEX_INLINE static synctex_node_t _synctex_smallest_container(synctex_node_t node, synctex_node_t other_node) {
- float height, other_height;
- if (SYNCTEX_ABS_WIDTH(node)<SYNCTEX_ABS_WIDTH(other_node)) {
- return node;
- }
- if (SYNCTEX_ABS_WIDTH(node)>SYNCTEX_ABS_WIDTH(other_node)) {
- return other_node;
- }
- height = SYNCTEX_ABS_DEPTH(node) + SYNCTEX_ABS_HEIGHT(node);
- other_height = SYNCTEX_ABS_DEPTH(other_node) + SYNCTEX_ABS_HEIGHT(other_node);
- if (height<other_height) {
- return node;
- }
- if (height>other_height) {
- return other_node;
+ * 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 allways 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 allways 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 allways 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 allways 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_bool_t _synctex_point_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) {
- if (node) {
- if (0 == _synctex_point_h_distance(hitPoint,node,visible)
- && 0 == _synctex_point_v_distance(hitPoint,node,visible)) {
- return synctex_YES;
- }
- }
- return synctex_NO;
+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;
}
-int _synctex_node_distance_to_point(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) {
-# ifdef __DARWIN_UNIX03
-# pragma unused(visible)
-# endif
- int result = INT_MAX; /* when the distance is meaning less (sheet, input...) */
- if (node) {
- int minH,maxH,minV,maxV;
- switch(node->class->type) {
- /* 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. */
- case synctex_node_type_vbox:
- case synctex_node_type_void_vbox:
- case synctex_node_type_hbox:
- case synctex_node_type_void_hbox:
- /* getting the box bounds, taking into account negative widths. */
- minH = SYNCTEX_HORIZ(node);
- maxH = minH + SYNCTEX_ABS_WIDTH(node);
- minV = SYNCTEX_VERT(node);
- maxV = minV + SYNCTEX_ABS_DEPTH(node);
- minV -= SYNCTEX_ABS_HEIGHT(node);
- /* In what region is the point hitPoint=(H,V) ? */
- if (hitPoint.v<minV) {
- if (hitPoint.h<minH) {
- /* This is region 1. The distance to the box is the L1 distance PA. */
- result = minV - hitPoint.v + minH - hitPoint.h;/* Integer overflow? probability epsilon */
- } else if (hitPoint.h<=maxH) {
- /* This is region 2. The distance to the box is the geometrical distance to the top edge. */
- result = minV - hitPoint.v;
- } else {
- /* This is region 3. The distance to the box is the L1 distance PB. */
- result = minV - hitPoint.v + hitPoint.h - maxH;
- }
- } else if (hitPoint.v<=maxV) {
- if (hitPoint.h<minH) {
- /* This is region 4. The distance to the box is the geometrical distance to the left edge. */
- result = minH - hitPoint.h;
- } else if (hitPoint.h<=maxH) {
- /* This is region 4. We are inside the box. */
- result = 0;
- } else {
- /* This is region 6. The distance to the box is the geometrical distance to the right edge. */
- result = hitPoint.h - maxH;
- }
- } else {
- if (hitPoint.h<minH) {
- /* This is region 7. The distance to the box is the L1 distance PC. */
- result = hitPoint.v - maxV + minH - hitPoint.h;
- } else if (hitPoint.h<=maxH) {
- /* This is region 8. The distance to the box is the geometrical distance to the top edge. */
- result = hitPoint.v - maxV;
- } else {
- /* This is region 9. The distance to the box is the L1 distance PD. */
- result = hitPoint.v - maxV + hitPoint.h - maxH;
- }
- }
- break;
- case synctex_node_type_kern:
- maxH = SYNCTEX_WIDTH(node);
- if (maxH<0) {
- minH = SYNCTEX_HORIZ(node);
- maxH = minH - maxH;
- } else {
- minH = -maxH;
- maxH = SYNCTEX_HORIZ(node);
- minH += maxH;
- }
- minV = SYNCTEX_VERT(node);
- if (hitPoint.h<minH) {
- if (hitPoint.v>minV) {
- result = hitPoint.v - minV + minH - hitPoint.h;
- } else {
- result = minV - hitPoint.v + minH - hitPoint.h;
- }
- } else if (hitPoint.h>maxH) {
- if (hitPoint.v>minV) {
- result = hitPoint.v - minV + hitPoint.h - maxH;
- } else {
- result = minV - hitPoint.v + hitPoint.h - maxH;
- }
- } else if (hitPoint.v>minV) {
- result = hitPoint.v - minV;
- } else {
- result = minV - hitPoint.v;
- }
- break;
- case synctex_node_type_glue:
- case synctex_node_type_math:
- minH = SYNCTEX_HORIZ(node);
- minV = SYNCTEX_VERT(node);
- if (hitPoint.h<minH) {
- if (hitPoint.v>minV) {
- result = hitPoint.v - minV + minH - hitPoint.h;
- } else {
- result = minV - hitPoint.v + minH - hitPoint.h;
- }
- } else if (hitPoint.v>minV) {
- result = hitPoint.v - minV + hitPoint.h - minH;
- } else {
- result = minV - hitPoint.v + hitPoint.h - minH;
- }
- break;
- }
- }
- return result;
-}
-
-static synctex_node_t _synctex_eq_deepest_container(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible) {
- if (node) {
- synctex_node_t result = NULL;
- synctex_node_t child = NULL;
- switch(node->class->type) {
- case synctex_node_type_vbox:
- case synctex_node_type_hbox:
- /* test the deep nodes first */
- if ((child = SYNCTEX_CHILD(node))) {
- do {
- if ((result = _synctex_eq_deepest_container(hitPoint,child,visible))) {
- return result;
- }
- } while((child = SYNCTEX_SIBLING(child)));
- }
- /* is the hit point inside the box? */
- if (_synctex_point_in_box(hitPoint,node,visible)) {
- /* 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. */
- if ((node->class->type == synctex_node_type_vbox) && (child = SYNCTEX_CHILD(node))) {
- int bestDistance = INT_MAX;
- do {
- if (SYNCTEX_CHILD(child)) {
- int distance = _synctex_node_distance_to_point(hitPoint,child,visible);
- if (distance < bestDistance) {
- bestDistance = distance;
- node = child;
- }
- }
- } while((child = SYNCTEX_SIBLING(child)));
- }
- return node;
- }
- }
- }
- return NULL;
-}
-
-/* Compares the locations of the hitPoint 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 int __synctex_eq_get_closest_children_in_hbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef, synctex_bool_t visible);
-SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_hbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef, synctex_bool_t visible) {
- int result = 0;
- if ((node = SYNCTEX_CHILD(node))) {
- do {
- int off7 = _synctex_point_h_distance(hitPoint,node,visible);
- if (off7 > 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 (bestDistancesRef->right > off7) {
- bestDistancesRef->right = off7;
- bestNodesRef->right = node;
- result |= SYNCTEX_MASK_RIGHT;
- } else if (bestDistancesRef->right == off7 && bestNodesRef->right) {
- if (SYNCTEX_TAG(bestNodesRef->right) == SYNCTEX_TAG(node)
- && (SYNCTEX_LINE(bestNodesRef->right) > SYNCTEX_LINE(node)
- || (SYNCTEX_LINE(bestNodesRef->right) == SYNCTEX_LINE(node)
- && SYNCTEX_COLUMN(bestNodesRef->right) > SYNCTEX_COLUMN(node)))) {
- bestNodesRef->right = node;
- result |= SYNCTEX_MASK_RIGHT;
- }
- }
- } else if (off7 == 0) {
- /* hitPoint is inside node. */
- bestDistancesRef->left = bestDistancesRef->right = 0;
- bestNodesRef->left = node;
- bestNodesRef->right = NULL;
- result |= SYNCTEX_MASK_LEFT;
- } else { /* here off7 < 0, hitPoint is to the right of node */
- off7 = -off7;
- if (bestDistancesRef->left > off7) {
- bestDistancesRef->left = off7;
- bestNodesRef->left = node;
- result |= SYNCTEX_MASK_LEFT;
- } else if (bestDistancesRef->left == off7 && bestNodesRef->left) {
- if (SYNCTEX_TAG(bestNodesRef->left) == SYNCTEX_TAG(node)
- && (SYNCTEX_LINE(bestNodesRef->left) > SYNCTEX_LINE(node)
- || (SYNCTEX_LINE(bestNodesRef->left) == SYNCTEX_LINE(node)
- && SYNCTEX_COLUMN(bestNodesRef->left) > SYNCTEX_COLUMN(node)))) {
- bestNodesRef->left = node;
- result |= SYNCTEX_MASK_LEFT;
- }
- }
- }
- } while((node = SYNCTEX_SIBLING(node)));
- if (result & SYNCTEX_MASK_LEFT) {
- /* the left node is new, try to narrow the result */
- if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->left,visible))) {
- bestNodesRef->left = node;
- }
- if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->left,visible))) {
- bestNodesRef->left = node;
- }
- }
- if (result & SYNCTEX_MASK_RIGHT) {
- /* the right node is new, try to narrow the result */
- if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->right,visible))) {
- bestNodesRef->right = node;
- }
- if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->right,visible))) {
- bestNodesRef->right = node;
- }
- }
- }
- return result;
-}
-SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_vbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef,synctex_bool_t visible);
-SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_vbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef,synctex_bool_t visible) {
- int result = 0;
- if ((node = SYNCTEX_CHILD(node))) {
- do {
- int off7 = _synctex_point_v_distance(hitPoint,node,visible);/* this is what makes the difference with the h version above */
- if (off7 > 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 (bestDistancesRef->right > off7) {
- bestDistancesRef->right = off7;
- bestNodesRef->right = node;
- result |= SYNCTEX_MASK_RIGHT;
- } else if (bestDistancesRef->right == off7 && bestNodesRef->right) {
- if (SYNCTEX_TAG(bestNodesRef->right) == SYNCTEX_TAG(node)
- && (SYNCTEX_LINE(bestNodesRef->right) > SYNCTEX_LINE(node)
- || (SYNCTEX_LINE(bestNodesRef->right) == SYNCTEX_LINE(node)
- && SYNCTEX_COLUMN(bestNodesRef->right) > SYNCTEX_COLUMN(node)))) {
- bestNodesRef->right = node;
- result |= SYNCTEX_MASK_RIGHT;
- }
- }
- } else if (off7 == 0) {
- bestDistancesRef->left = bestDistancesRef->right = 0;
- bestNodesRef->left = node;
- bestNodesRef->right = NULL;
- result |= SYNCTEX_MASK_LEFT;
- } else { /* here off7 < 0 */
- off7 = -off7;
- if (bestDistancesRef->left > off7) {
- bestDistancesRef->left = off7;
- bestNodesRef->left = node;
- result |= SYNCTEX_MASK_LEFT;
- } else if (bestDistancesRef->left == off7 && bestNodesRef->left) {
- if (SYNCTEX_TAG(bestNodesRef->left) == SYNCTEX_TAG(node)
- && (SYNCTEX_LINE(bestNodesRef->left) > SYNCTEX_LINE(node)
- || (SYNCTEX_LINE(bestNodesRef->left) == SYNCTEX_LINE(node)
- && SYNCTEX_COLUMN(bestNodesRef->left) > SYNCTEX_COLUMN(node)))) {
- bestNodesRef->left = node;
- result |= SYNCTEX_MASK_LEFT;
- }
- }
- }
- } while((node = SYNCTEX_SIBLING(node)));
- if (result & SYNCTEX_MASK_LEFT) {
- /* the left node is new, try to narrow the result */
- if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->left,visible))) {
- bestNodesRef->left = node;
- }
- if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->left,visible))) {
- bestNodesRef->left = node;
- }
- }
- if (result & SYNCTEX_MASK_RIGHT) {
- /* the right node is new, try to narrow the result */
- if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->right,visible))) {
- bestNodesRef->right = node;
- }
- if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->right,visible))) {
- bestNodesRef->right = node;
- }
- }
- }
- return result;
-}
-SYNCTEX_INLINE static int _synctex_eq_get_closest_children_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef,synctex_bool_t visible) {
- if (node) {
- switch(node->class->type) {
- case synctex_node_type_hbox:
- return __synctex_eq_get_closest_children_in_hbox(hitPoint, node, bestNodesRef, bestDistancesRef,visible);
- case synctex_node_type_vbox:
- return __synctex_eq_get_closest_children_in_vbox(hitPoint, node, bestNodesRef, bestDistancesRef,visible);
- }
- }
- return 0;
-}
-
-SYNCTEX_INLINE static synctex_node_t __synctex_eq_closest_child(synctex_point_t hitPoint, synctex_node_t node,int* distanceRef, synctex_bool_t visible);
-SYNCTEX_INLINE static synctex_node_t __synctex_eq_closest_child(synctex_point_t hitPoint, synctex_node_t node,int* distanceRef, synctex_bool_t visible) {
- synctex_node_t best_node = NULL;
- if ((node = SYNCTEX_CHILD(node))) {
- do {
- int distance = _synctex_node_distance_to_point(hitPoint,node,visible);
- synctex_node_t candidate = NULL;
- if (distance<=*distanceRef) {
- *distanceRef = distance;
- best_node = node;
- }
- switch(node->class->type) {
- case synctex_node_type_vbox:
- case synctex_node_type_hbox:
- if ((candidate = __synctex_eq_closest_child(hitPoint,node,distanceRef,visible))) {
- best_node = candidate;
- }
- }
- } while((node = SYNCTEX_SIBLING(node)));
- }
- return best_node;
-}
-SYNCTEX_INLINE static synctex_node_t _synctex_eq_closest_child(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible) {
- if (node) {
- switch(node->class->type) {
- case synctex_node_type_hbox:
- case synctex_node_type_vbox:
- {
- int best_distance = INT_MAX;
- synctex_node_t best_node = __synctex_eq_closest_child(hitPoint,node,&best_distance,visible);
- if ((best_node)) {
- synctex_node_t child = NULL;
- switch(best_node->class->type) {
- case synctex_node_type_vbox:
- case synctex_node_type_hbox:
- if ((child = SYNCTEX_CHILD(best_node))) {
- best_distance = _synctex_node_distance_to_point(hitPoint,child,visible);
- while((child = SYNCTEX_SIBLING(child))) {
- int distance = _synctex_node_distance_to_point(hitPoint,child,visible);
- if (distance<=best_distance) {
- best_distance = distance;
- best_node = child;
- }
- }
- }
- }
- }
- return best_node;
- }
- }
- }
- return NULL;
+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. */
+ if (_synctex_tree_child(childd.node)) {
+ return _synctex_eq_get_closest_children_in_box_v2(hitP, childd.node);
+ }
+ nds.l = childd;
+ } 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;
+}
+
+#if 0
+SYNCTEX_INLINE static synctex_nd_lr_s __synctex_eq_get_closest_children_in_hbox_v3(synctex_point_p hitP, synctex_node_p nodeP) {
+ synctex_nd_s nd = SYNCTEX_ND_0;
+ synctex_nd_lr_s nds = {SYNCTEX_ND_0,SYNCTEX_ND_0};
+ if ((nd.node = _synctex_tree_child(nodeP))) {
+ do {
+ nd = _synctex_point_h_ordered_distance_v2(hitP,nd.node);
+ if (nd.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 > 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) {
+ /* hit point is inside node. */
+ nds.l = nd;
+ } else { /* here nd.d < 0, the hit point is to the right of node */
+ 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_tree_sibling(nd.node)));
+ if (nds.l.node) {
+ /* the left node is new, try to narrow the result */
+ 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) {
+ /* the right node is new, try to narrow the result */
+ 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;
+}
+#endif
+SYNCTEX_INLINE static synctex_nd_lr_s __synctex_eq_get_closest_children_in_vbox_v2(synctex_point_p hitP, synctex_node_p nodeP) {
+ SYNCTEX_UNUSED(nodeP)
+ 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 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_fprintf_t)(void *, const char * , ...); /* print formatted to either FILE * or gzFile */
+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
-struct __synctex_updater_t {
- gzFile file; /* the foo.synctex or foo.synctex.gz I/O identifier */
- synctex_fprintf_t fprintf; /* either fprintf or gzprintf */
- int length; /* the number of chars appended */
- struct _flags {
- unsigned int no_gz:1; /* Whether zlib is used or not */
- unsigned int reserved:SYNCTEX_BITS_PER_BYTE*sizeof(int)-1; /* Align */
- } flags;
+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 */
};
-# define SYNCTEX_FILE updater->file
-# define SYNCTEX_NO_GZ ((updater->flags).no_gz)
-# define SYNCTEX_fprintf (*(updater->fprintf))
-
-synctex_updater_t synctex_updater_new_with_output_file(const char * output, const char * build_directory) {
- synctex_updater_t updater = NULL;
- char * synctex = NULL;
- synctex_io_mode_t io_mode = 0;
- const char * mode = NULL;
- /* prepare the updater, the memory is the only one dynamically allocated */
- updater = (synctex_updater_t)_synctex_malloc(sizeof(synctex_updater_t));
- if (NULL == updater) {
- _synctex_error("! synctex_updater_new_with_file: malloc problem");
- return NULL;
- }
- if (_synctex_open(output,build_directory,&synctex,&SYNCTEX_FILE,synctex_ADD_QUOTES,&io_mode)
- && _synctex_open(output,build_directory,&synctex,&SYNCTEX_FILE,synctex_DONT_ADD_QUOTES,&io_mode)) {
-return_on_error:
- free(updater);
- updater = NULL;
- return NULL;
- }
- /* OK, the file exists, we close it and reopen it with the correct mode.
+
+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)
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.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, ...) {
+ 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(SYNCTEX_FILE);
- SYNCTEX_FILE = NULL;
- SYNCTEX_NO_GZ = (io_mode&synctex_io_gz_mask)?synctex_NO:synctex_YES;
- mode = _synctex_get_io_mode_name(io_mode|synctex_io_append_mask);/* either "a" or "ab", depending on the file extension */
- if (SYNCTEX_NO_GZ) {
- if (NULL == (SYNCTEX_FILE = (void *)fopen(synctex,mode))) {
-no_write_error:
- _synctex_error("! synctex_updater_new_with_file: Can't append to %s",synctex);
- free(synctex);
- goto return_on_error;
- }
- updater->fprintf = (synctex_fprintf_t)(&fprintf);
- } else {
- if (NULL == (SYNCTEX_FILE = (void *)gzopen(synctex,mode))) {
- goto no_write_error;
- }
- updater->fprintf = (synctex_fprintf_t)(&gzprintf);
- }
- printf("SyncTeX: updating %s...",synctex);
- free(synctex);
- return updater;
-}
-
-
-void synctex_updater_append_magnification(synctex_updater_t updater, char * magnification){
- if (NULL==updater) {
- return;
- }
- if (magnification && strlen(magnification)) {
- updater->length += SYNCTEX_fprintf(SYNCTEX_FILE,"Magnification:%s\n",magnification);
- }
-}
-
-void synctex_updater_append_x_offset(synctex_updater_t updater, char * x_offset){
- if (NULL==updater) {
- return;
- }
- if (x_offset && strlen(x_offset)) {
- updater->length += SYNCTEX_fprintf(SYNCTEX_FILE,"X Offset:%s\n",x_offset);
- }
-}
-
-void synctex_updater_append_y_offset(synctex_updater_t updater, char * y_offset){
- if (NULL==updater) {
- return;
- }
- if (y_offset && strlen(y_offset)) {
- updater->length += SYNCTEX_fprintf(SYNCTEX_FILE,"Y Offset:%s\n",y_offset);
- }
-}
-
-void synctex_updater_free(synctex_updater_t updater){
- if (NULL==updater) {
- return;
- }
- if (updater->length>0) {
- SYNCTEX_fprintf(SYNCTEX_FILE,"!%i\n",updater->length);
- }
- if (SYNCTEX_NO_GZ) {
- fclose((FILE *)SYNCTEX_FILE);
- } else {
- gzclose((gzFile)SYNCTEX_FILE);
- }
- free(updater);
- printf("... done.\n");
- return;
+ 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