diff options
author | rbuj <[email protected]> | 2019-08-21 23:07:52 +0200 |
---|---|---|
committer | raveit65 <[email protected]> | 2019-08-29 12:00:35 +0200 |
commit | 6061cf30d7a351d7214ee074e4530fb8b9d4e94c (patch) | |
tree | 017eb17cf1f61084b9162a52834ac06a83dcc088 | |
parent | 7dc6ac4dde817633a82f35cfb4f19102ea94b272 (diff) | |
download | atril-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
-rw-r--r-- | cut-n-paste/synctex/Makefile.am | 13 | ||||
-rw-r--r-- | cut-n-paste/synctex/synctex_parser.c | 12284 | ||||
-rw-r--r-- | cut-n-paste/synctex/synctex_parser.h | 762 | ||||
-rw-r--r-- | cut-n-paste/synctex/synctex_parser_advanced.h | 554 | ||||
-rw-r--r-- | cut-n-paste/synctex/synctex_parser_local.h | 80 | ||||
-rw-r--r-- | cut-n-paste/synctex/synctex_parser_readme.md | 259 | ||||
-rw-r--r-- | cut-n-paste/synctex/synctex_parser_utils.c | 174 | ||||
-rw-r--r-- | cut-n-paste/synctex/synctex_parser_utils.h | 57 | ||||
-rw-r--r-- | cut-n-paste/synctex/synctex_parser_version.txt | 2 | ||||
-rw-r--r-- | cut-n-paste/synctex/synctex_version.h | 59 | ||||
-rwxr-xr-x | cut-n-paste/synctex/update-synctex-from-TL.sh | 4 | ||||
-rw-r--r-- | libdocument/ev-document.c | 16 |
12 files changed, 9894 insertions, 4370 deletions
diff --git a/cut-n-paste/synctex/Makefile.am b/cut-n-paste/synctex/Makefile.am index 5d7b24c2..415cc0ff 100644 --- a/cut-n-paste/synctex/Makefile.am +++ b/cut-n-paste/synctex/Makefile.am @@ -1,10 +1,15 @@ +NULL = + noinst_LTLIBRARIES = libsynctex.la -libsynctex_la_SOURCES = \ +libsynctex_la_SOURCES = \ synctex_parser.c \ - synctex_parser.h \ - synctex_parser_utils.h \ - synctex_parser_utils.c + synctex_parser.h \ + synctex_parser_advanced.h \ + synctex_parser_utils.c \ + synctex_parser_utils.h \ + synctex_version.h \ + $(NULL) libsynctex_la_CPPFLAGS = \ -DSYNCTEX_VERBOSE=0 \ 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,"ed,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,"ed,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 diff --git a/cut-n-paste/synctex/synctex_parser.h b/cut-n-paste/synctex/synctex_parser.h index fd74bd3d..e54a0176 100644 --- a/cut-n-paste/synctex/synctex_parser.h +++ b/cut-n-paste/synctex/synctex_parser.h @@ -1,360 +1,426 @@ /* -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: Fri Jul 14 16:20:41 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. */ #ifndef __SYNCTEX_PARSER__ # define __SYNCTEX_PARSER__ +#include "synctex_version.h" + #ifdef __cplusplus extern "C" { #endif - -# define SYNCTEX_VERSION_STRING "1.18" - -/* synctex_node_t is the type for all synctex nodes. - * The synctex file is parsed into a tree of nodes, either sheet, boxes, math nodes... */ -typedef struct _synctex_node * synctex_node_t; - -/* The main synctex object is a scanner - * Its implementation is considered private. - * The basic workflow is - * - create a "synctex scanner" with the contents of a file - * - perform actions on that scanner like display or edit queries - * - free the scanner when the work is done - */ -typedef struct __synctex_scanner_t _synctex_scanner_t; -typedef _synctex_scanner_t * synctex_scanner_t; - -/* This is the designated method to create a new synctex scanner object. - * output is the pdf/dvi/xdv file associated to the synctex file. - * If necessary, it can be the tex file that originated the synctex file - * but this might cause problems if the \jobname has a custom value. - * Despite this method can accept a relative path in practice, - * you should only pass a full path name. - * The path should be encoded by the underlying file system, - * assuming that it is based on 8 bits characters, including UTF8, - * not 16 bits nor 32 bits. - * The last file extension is removed and replaced by the proper extension. - * Then the private method _synctex_scanner_new_with_contents_of_file is called. - * NULL is returned in case of an error or non existent file. - * Once you have a scanner, use the synctex_display_query and synctex_edit_query below. - * The new "build_directory" argument is available since version 1.5. - * It is the directory where all the auxiliary stuff is created. - * Sometimes, the synctex output file and the pdf, dvi or xdv files are not created in the same directory. - * This is the case in MikTeX (I will include this into TeX Live). - * This directory path can be nil, it will be ignored then. - * It can be either absolute or relative to the directory of the output pdf (dvi or xdv) file. - * If no synctex file is found in the same directory as the output file, then we try to find one in the build directory. - * Please note that this new "build_directory" is provided as a convenient argument but should not be used. - * In fact, this is implempented as a work around of a bug in MikTeX where the synctex file does not follow the pdf file. - * The new "parse" argument is available since version 1.5. In general, use 1. - * Use 0 only if you do not want to parse the content but just check the existence. - */ -synctex_scanner_t synctex_scanner_new_with_output_file(const char * output, const char * build_directory, int parse); - -/* This is the designated method to delete a synctex scanner object. - * Frees all the memory, you must call it when you are finished with the scanner. - */ -void synctex_scanner_free(synctex_scanner_t scanner); - -/* Send this message to force the scanner to parse the contents of the synctex output file. - * Nothing is performed if the file was already parsed. - * In each query below, this message is sent, but if you need to access information more directly, - * you must be sure that the parsing did occur. - * Usage: - * if((my_scanner = synctex_scanner_parse(my_scanner))) { - * continue with my_scanner... - * } else { - * there was a problem - * } - */ -synctex_scanner_t synctex_scanner_parse(synctex_scanner_t scanner); - -/* The main entry points. - * Given the file name, a line and a column number, synctex_display_query returns the number of nodes - * satisfying the contrain. Use code like - * - * if(synctex_display_query(scanner,name,line,column)>0) { - * synctex_node_t node; - * while((node = synctex_next_result(scanner))) { - * // do something with node - * ... - * } - * } - * - * For example, one can - * - highlight each resulting node in the output, using synctex_node_h and synctex_node_v - * - highlight all the rectangles enclosing those nodes, using synctex_box_... functions - * - highlight just the character using that information - * - * Given the page and the position in the page, synctex_edit_query returns the number of nodes - * satisfying the contrain. Use code like - * - * if(synctex_edit_query(scanner,page,h,v)>0) { - * synctex_node_t node; - * while(node = synctex_next_result(scanner)) { - * // do something with node - * ... - * } - * } - * - * For example, one can - * - highlight each resulting line in the input, - * - highlight just the character using that information - * - * page is 1 based - * h and v are coordinates in 72 dpi unit, relative to the top left corner of the page. - * If you make a new query, the result of the previous one is discarded. - * If one of this function returns a non positive integer, - * it means that an error occurred. - * - * Both methods are conservative, in the sense that matching is weak. - * If the exact column number is not found, there will be an answer with the whole line. - * - * Sumatra-PDF, Skim, iTeXMac2 and Texworks are examples of open source software that use this library. - * You can browse their code for a concrete implementation. - */ -typedef long synctex_status_t; -synctex_status_t synctex_display_query(synctex_scanner_t scanner,const char * name,int line,int column); -synctex_status_t synctex_edit_query(synctex_scanner_t scanner,int page,float h,float v); -synctex_node_t synctex_next_result(synctex_scanner_t scanner); - -/* Display all the information contained in the scanner object. - * If the records are too numerous, only the first ones are displayed. - * This is mainly for informatinal purpose to help developers. - */ -void synctex_scanner_display(synctex_scanner_t scanner); - -/* The x and y offset of the origin in TeX coordinates. The magnification - These are used by pdf viewers that want to display the real box size. - For example, getting the horizontal coordinates of a node would require - synctex_node_box_h(node)*synctex_scanner_magnification(scanner)+synctex_scanner_x_offset(scanner) - Getting its TeX width would simply require - synctex_node_box_width(node)*synctex_scanner_magnification(scanner) - but direct methods are available for that below. - */ -int synctex_scanner_x_offset(synctex_scanner_t scanner); -int synctex_scanner_y_offset(synctex_scanner_t scanner); -float synctex_scanner_magnification(synctex_scanner_t scanner); - -/* Managing the input file names. - * Given a tag, synctex_scanner_get_name will return the corresponding file name. - * Conversely, given a file name, synctex_scanner_get_tag will retur, the corresponding tag. - * The file name must be the very same as understood by TeX. - * For example, if you \input myDir/foo.tex, the file name is myDir/foo.tex. - * No automatic path expansion is performed. - * Finally, synctex_scanner_input is the first input node of the scanner. - * To browse all the input node, use a loop like - * - * if((input_node = synctex_scanner_input(scanner))){ - * do { - * blah - * } while((input_node=synctex_node_sibling(input_node))); - * } - * - * The output is the name that was used to create the scanner. - * The synctex is the real name of the synctex file, - * it was obtained from output by setting the proper file extension. - */ -const char * synctex_scanner_get_name(synctex_scanner_t scanner,int tag); -int synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name); -synctex_node_t synctex_scanner_input(synctex_scanner_t scanner); -const char * synctex_scanner_get_output(synctex_scanner_t scanner); -const char * synctex_scanner_get_synctex(synctex_scanner_t scanner); - -/* Browsing the nodes - * parent, child and sibling are standard names for tree nodes. - * The parent is one level higher, the child is one level deeper, - * and the sibling is at the same level. - * The sheet of a node is the first ancestor, it is of type sheet. - * A node and its sibling have the same parent. - * A node is the parent of its child. - * A node is either the child of its parent, - * or belongs to the sibling chain of its parent's child. - * The next node is either the child, the sibling or the parent's sibling, - * unless the parent is a sheet. - * This allows to navigate through all the nodes of a given sheet node: - * - * synctex_node_t node = sheet; - * while((node = synctex_node_next(node))) { - * // do something with node - * } - * - * With synctex_sheet_content, you can retrieve the sheet node given the page. - * The page is 1 based, according to TeX standards. - * Conversely synctex_node_sheet allows to retrieve the sheet containing a given node. - */ -synctex_node_t synctex_node_parent(synctex_node_t node); -synctex_node_t synctex_node_sheet(synctex_node_t node); -synctex_node_t synctex_node_child(synctex_node_t node); -synctex_node_t synctex_node_sibling(synctex_node_t node); -synctex_node_t synctex_node_next(synctex_node_t node); -synctex_node_t synctex_sheet(synctex_scanner_t scanner,int page); -synctex_node_t synctex_sheet_content(synctex_scanner_t scanner,int page); - -/* These are the types of the synctex nodes */ -typedef enum { - synctex_node_type_error = 0, - synctex_node_type_input, - synctex_node_type_sheet, - synctex_node_type_vbox, - synctex_node_type_void_vbox, - synctex_node_type_hbox, - synctex_node_type_void_hbox, - synctex_node_type_kern, - synctex_node_type_glue, - synctex_node_type_math, - synctex_node_type_boundary, - synctex_node_number_of_types -} synctex_node_type_t; - -/* synctex_node_type gives the type of a given node, - * synctex_node_isa gives the same information as a human readable text. */ -synctex_node_type_t synctex_node_type(synctex_node_t node); -const char * synctex_node_isa(synctex_node_t node); - -/* This is primarily used for debugging purpose. - * The second one logs information for the node and recursively displays information for its next node */ -void synctex_node_log(synctex_node_t node); -void synctex_node_display(synctex_node_t node); - -/* Given a node, access to the location in the synctex file where it is defined. - */ -typedef unsigned int synctex_charindex_t; -synctex_charindex_t synctex_node_charindex(synctex_node_t node); - -/* Given a node, access to its tag, line and column. - * The line and column numbers are 1 based. - * The latter is not yet fully supported in TeX, the default implementation returns 0 which means the whole line. - * When the tag is known, the scanner of the node will give the corresponding file name. - * When the tag is known, the scanner of the node will give the name. - */ -int synctex_node_tag(synctex_node_t node); -int synctex_node_line(synctex_node_t node); -int synctex_node_column(synctex_node_t node); - -/* In order to enhance forward synchronization, - * non void horizontal boxes have supplemental cached information. - * The mean line is the average of the line numbers of the included nodes. - * The child count is the number of chidren. - */ -int synctex_node_mean_line(synctex_node_t node); -int synctex_node_child_count(synctex_node_t node); - -/* This is the page where the node appears. - * This is a 1 based index as given by TeX. - */ -int synctex_node_page(synctex_node_t node); - -/* For quite all nodes, horizontal, vertical coordinates, and width. - * These are expressed in TeX small points coordinates, with origin at the top left corner. - */ -int synctex_node_h(synctex_node_t node); -int synctex_node_v(synctex_node_t node); -int synctex_node_width(synctex_node_t node); - -/* For all nodes, dimensions of the enclosing box. - * These are expressed in TeX small points coordinates, with origin at the top left corner. - * A box is enclosing itself. - */ -int synctex_node_box_h(synctex_node_t node); -int synctex_node_box_v(synctex_node_t node); -int synctex_node_box_width(synctex_node_t node); -int synctex_node_box_height(synctex_node_t node); -int synctex_node_box_depth(synctex_node_t node); - -/* For quite all nodes, horizontal, vertical coordinates, and width. - * The visible dimensions are bigger than real ones to compensate 0 width boxes - * that do contain nodes. - * These are expressed in page coordinates, with origin at the top left corner. - * A box is enclosing itself. - */ -float synctex_node_visible_h(synctex_node_t node); -float synctex_node_visible_v(synctex_node_t node); -float synctex_node_visible_width(synctex_node_t node); -/* For all nodes, visible dimensions of the enclosing box. - * A box is enclosing itself. - * The visible dimensions are bigger than real ones to compensate 0 width boxes - * that do contain nodes. - */ -float synctex_node_box_visible_h(synctex_node_t node); -float synctex_node_box_visible_v(synctex_node_t node); -float synctex_node_box_visible_width(synctex_node_t node); -float synctex_node_box_visible_height(synctex_node_t node); -float synctex_node_box_visible_depth(synctex_node_t node); - -/* The main synctex updater object. - * This object is used to append information to the synctex file. - * Its implementation is considered private. - * It is used by the synctex command line tool to take into account modifications - * that could occur while postprocessing files by dvipdf like filters. - */ -typedef struct __synctex_updater_t _synctex_updater_t; -typedef _synctex_updater_t * synctex_updater_t; - -/* Designated initializer. - * Once you are done with your whole job, - * free the updater */ -synctex_updater_t synctex_updater_new_with_output_file(const char * output, const char * directory); - -/* Use the next functions to append records to the synctex file, - * no consistency tests made on the arguments */ -void synctex_updater_append_magnification(synctex_updater_t updater, char * magnification); -void synctex_updater_append_x_offset(synctex_updater_t updater, char * x_offset); -void synctex_updater_append_y_offset(synctex_updater_t updater, char * y_offset); - -/* You MUST free the updater, once everything is properly appended */ -void synctex_updater_free(synctex_updater_t updater); + + /* The main synctex object is a scanner. + * Its implementation is considered private. + * The basic workflow is + * - create a "synctex scanner" with the contents of a file + * - perform actions on that scanner like + synctex_display_query or synctex_edit_query below. + * - perform actions on nodes returned by the scanner + * - free the scanner when the work is done + */ + typedef struct synctex_scanner_t synctex_scanner_s; + typedef synctex_scanner_s * synctex_scanner_p; + + /** + * This is the designated method to create + * a new synctex scanner object. + * - argument output: the pdf/dvi/xdv file associated + * to the synctex file. + * If necessary, it can be the tex file that + * originated the synctex file but this might cause + * problems if the \jobname has a custom value. + * Despite this method can accept a relative path + * in practice, you should only pass full paths. + * The path should be encoded by the underlying + * file system, assuming that it is based on + * 8 bits characters, including UTF8, + * not 16 bits nor 32 bits. + * The last file extension is removed and + * replaced by the proper extension, + * either synctex or synctex.gz. + * - argument build_directory: It is the directory where + * all the auxiliary stuff is created. + * If no synctex file is found in the same directory + * as the output file, then we try to find one in + * this build directory. + * It is the directory where all the auxiliary + * stuff is created. Sometimes, the synctex output + * file and the pdf, dvi or xdv files are not + * created in the same location. See MikTeX. + * This directory path can be NULL, + * it will be ignored then. + * It can be either absolute or relative to the + * directory of the output pdf (dvi or xdv) file. + * Please note that this new argument is provided + * as a convenience but should not be used. + * Available since version 1.5. + * - argument parse: In general, use 1. + * Use 0 only if you do not want to parse the + * content but just check for existence. + * Available since version 1.5 + * - resturn: a scanner. NULL is returned in case + * of an error or non existent file. + */ + synctex_scanner_p synctex_scanner_new_with_output_file(const char * output, const char * build_directory, int parse); + + /** + * Designated method to delete a synctex scanner object, + * including all its internal resources. + * Frees all the memory, you must call it when you are finished with the scanner. + * - argument scanner: a scanner. + * - returns: an integer used for testing purposes. + */ + int synctex_scanner_free(synctex_scanner_p scanner); + + /** + * Send this message to force the scanner to + * parse the contents of the synctex output file. + * Nothing is performed if the file was already parsed. + * In each query below, this message is sent, + * but if you need to access information more directly, + * you must ensure that the parsing did occur. + * Usage: + * if((my_scanner = synctex_scanner_parse(my_scanner))) { + * continue with my_scanner... + * } else { + * there was a problem + * } + * - returns: the argument on success. + * On failure, frees scanner and returns NULL. + */ + synctex_scanner_p synctex_scanner_parse(synctex_scanner_p scanner); + + /* synctex_node_p is the type for all synctex nodes. + * Its implementation is considered private. + * The synctex file is parsed into a tree of nodes, either sheet, form, boxes, math nodes... */ + + typedef struct synctex_node_t synctex_node_s; + typedef synctex_node_s * synctex_node_p; + + /* The main entry points. + * Given the file name, a line and a column number, synctex_display_query returns the number of nodes + * satisfying the contrain. Use code like + * + * if(synctex_display_query(scanner,name,line,column,page_hint)>0) { + * synctex_node_p node; + * while((node = synctex_scanner_next_result(scanner))) { + * // do something with node + * ... + * } + * } + * + * Please notice that since version 1.19, + * there is a new argument page_hint. + * The results in pages closer to page_hint are given first. + * For example, one can + * - highlight each resulting node in the output, using synctex_node_visible_h and synctex_node_visible_v + * - highlight all the rectangles enclosing those nodes, using synctex_node_box_visible_... functions + * - highlight just the character using that information + * + * Given the page and the position in the page, synctex_edit_query returns the number of nodes + * satisfying the contrain. Use code like + * + * if(synctex_edit_query(scanner,page,h,v)>0) { + * synctex_node_p node; + * while(node = synctex_scanner_next_result(scanner)) { + * // do something with node + * ... + * } + * } + * + * For example, one can + * - highlight each resulting line in the input, + * - highlight just the character using that information + * + * page is 1 based + * h and v are coordinates in 72 dpi unit, relative to the top left corner of the page. + * If you make a new query, the result of the previous one is discarded. If you need to make more than one query + * in parallel, use the iterator API exposed in + * the synctex_parser_private.h header. + * If one of this function returns a negative integer, + * it means that an error occurred. + * + * Both methods are conservative, in the sense that matching is weak. + * If the exact column number is not found, there will be an answer with the whole line. + * + * Sumatra-PDF, Skim, iTeXMac2, TeXShop and Texworks are examples of open source software that use this library. + * You can browse their code for a concrete implementation. + */ + typedef long synctex_status_t; + /* The page_hint argument is used to resolve ambiguities. + * Whenever, different matches occur, the ones closest + * to the page will be given first. Pass a negative number + * when in doubt. Using pdf forms may lead to ambiguities. + */ + synctex_status_t synctex_display_query(synctex_scanner_p scanner,const char * name,int line,int column, int page_hint); + synctex_status_t synctex_edit_query(synctex_scanner_p scanner,int page,float h,float v); + synctex_node_p synctex_scanner_next_result(synctex_scanner_p scanner); + synctex_status_t synctex_scanner_reset_result(synctex_scanner_p scanner); + + /** + * The horizontal and vertical location, + * the width, height and depth of a box enclosing node. + * All dimensions are given in page coordinates + * as opposite to TeX coordinates. + * The origin is at the top left corner of the page. + * Code example for Qt5: + * (from TeXworks source TWSynchronize.cpp) + * QRectF nodeRect(synctex_node_box_visible_h(node), + * synctex_node_box_visible_v(node) - + * synctex_node_box_visible_height(node), + * synctex_node_box_visible_width(node), + * synctex_node_box_visible_height(node) + + * synctex_node_box_visible_depth(node)); + * Code example for Cocoa: + * NSRect bounds = [pdfPage + * boundsForBox:kPDFDisplayBoxMediaBox]; + * NSRect nodeRect = NSMakeRect( + * synctex_node_box_visible_h(node), + * NSMaxY(bounds)-synctex_node_box_visible_v(node) + + * synctex_node_box_visible_height(node), + * synctex_node_box_visible_width(node), + * synctex_node_box_visible_height(node) + + * synctex_node_box_visible_depth(node) + * ); + * The visible dimensions are bigger than real ones + * to compensate 0 width boxes or nodes intentionnaly + * put outside the box (using \kern for example). + * - parameter node: a node. + * - returns: a float. + * - author: JL + */ + float synctex_node_box_visible_h(synctex_node_p node); + float synctex_node_box_visible_v(synctex_node_p node); + float synctex_node_box_visible_width(synctex_node_p node); + float synctex_node_box_visible_height(synctex_node_p node); + float synctex_node_box_visible_depth(synctex_node_p node); + + /** + * For quite all nodes, horizontal and vertical coordinates, and width. + * All dimensions are given in page coordinates + * as opposite to TeX coordinates. + * The origin is at the top left corner of the page. + * The visible dimensions are bigger than real ones + * to compensate 0 width boxes or nodes intentionnaly + * put outside the box (using \kern for example). + * All nodes have coordinates, but all nodes don't + * have non null size. For example, math nodes + * have no width according to TeX, and in that case + * synctex_node_visible_width simply returns 0. + * The same holds for kern nodes that do not have + * height nor depth, etc... + */ + float synctex_node_visible_h(synctex_node_p node); + float synctex_node_visible_v(synctex_node_p node); + float synctex_node_visible_width(synctex_node_p node); + float synctex_node_visible_height(synctex_node_p node); + float synctex_node_visible_depth(synctex_node_p node); + + /** + * Given a node, access to its tag, line and column. + * The line and column numbers are 1 based. + * The latter is not yet fully supported in TeX, + * the default implementation returns 0 + * which means the whole line. + * synctex_node_get_name returns the path of the + * TeX source file that was used to create the node. + * When the tag is known, the scanner of the node + * will also give that same file name, see + * synctex_scanner_get_name below. + * For an hbox node, the mean line is the mean + * of all the lines of the child nodes. + * Sometimes, when synchronization form pdf to source + * fails with the line, one should try with the + * mean line. + */ + int synctex_node_tag(synctex_node_p node); + int synctex_node_line(synctex_node_p node); + int synctex_node_mean_line(synctex_node_p node); + int synctex_node_column(synctex_node_p node); + const char * synctex_node_get_name(synctex_node_p node); + + /** + This is the page where the node appears. + * This is a 1 based index as given by TeX. + */ + int synctex_node_page(synctex_node_p node); + + /** + * Display all the information contained in the scanner. + * If the records are too numerous, only the first ones are displayed. + * This is mainly for informational purpose to help developers. + */ + void synctex_scanner_display(synctex_scanner_p scanner); + + /* Managing the input file names. + * Given a tag, synctex_scanner_get_name will return the corresponding file name. + * Conversely, given a file name, synctex_scanner_get_tag will return, the corresponding tag. + * The file name must be the very same as understood by TeX. + * For example, if you \input myDir/foo.tex, the file name is myDir/foo.tex. + * No automatic path expansion is performed. + * Finally, synctex_scanner_input is the first input node of the scanner. + * To browse all the input node, use a loop like + * ... + * synctex_node_p = input_node; + * ... + * if((input_node = synctex_scanner_input(scanner))) { + * do { + * blah + * } while((input_node=synctex_node_sibling(input_node))); + * } + * + * The output is the name that was used to create the scanner. + * The synctex is the real name of the synctex file, + * it was obtained from output by setting the proper file extension. + */ + const char * synctex_scanner_get_name(synctex_scanner_p scanner,int tag); + + int synctex_scanner_get_tag(synctex_scanner_p scanner,const char * name); + + synctex_node_p synctex_scanner_input(synctex_scanner_p scanner); + synctex_node_p synctex_scanner_input_with_tag(synctex_scanner_p scanner,int tag); + const char * synctex_scanner_get_output(synctex_scanner_p scanner); + const char * synctex_scanner_get_synctex(synctex_scanner_p scanner); + + /* The x and y offset of the origin in TeX coordinates. The magnification + These are used by pdf viewers that want to display the real box size. + For example, getting the horizontal coordinates of a node would require + synctex_node_box_h(node)*synctex_scanner_magnification(scanner)+synctex_scanner_x_offset(scanner) + Getting its TeX width would simply require + synctex_node_box_width(node)*synctex_scanner_magnification(scanner) + but direct methods are available for that below. + */ + int synctex_scanner_x_offset(synctex_scanner_p scanner); + int synctex_scanner_y_offset(synctex_scanner_p scanner); + float synctex_scanner_magnification(synctex_scanner_p scanner); + + /** + * ## Browsing the nodes + * parent, child and sibling are standard names for tree nodes. + * The parent is one level higher, + * the child is one level deeper, + * and the sibling is at the same level. + * A node and its sibling have the same parent. + * A node is the parent of its children. + * A node is either the child of its parent, + * or belongs to the sibling chain of its parent's child. + * The sheet or form of a node is the topmost ancestor, + * it is of type sheet or form. + * The next node is either the child, the sibling or the parent's sibling, + * unless the parent is a sheet, a form or NULL. + * This allows to navigate through all the nodes of a given sheet node: + * + * synctex_node_p node = sheet; + * while((node = synctex_node_next(node))) { + * // do something with node + * } + * + * With synctex_sheet_content and synctex_form_content, + * you can retrieve the sheet node given the page + * or form tag. + * The page is 1 based, according to TeX standards. + * Conversely synctex_node_parent_sheet or + * synctex_node_parent_form allows to retrieve + * the sheet or the form containing a given node. + * Notice that a node is not contained in a sheet + * and a form at the same time. + * Some nodes are not contained in either (handles). + */ + + synctex_node_p synctex_node_parent(synctex_node_p node); + synctex_node_p synctex_node_parent_sheet(synctex_node_p node); + synctex_node_p synctex_node_parent_form(synctex_node_p node); + synctex_node_p synctex_node_child(synctex_node_p node); + synctex_node_p synctex_node_last_child(synctex_node_p node); + synctex_node_p synctex_node_sibling(synctex_node_p node); + synctex_node_p synctex_node_last_sibling(synctex_node_p node); + synctex_node_p synctex_node_arg_sibling(synctex_node_p node); + synctex_node_p synctex_node_next(synctex_node_p node); + + /** + * Top level entry points. + * The scanner owns a list of sheet siblings and + * a list of form siblings. + * Sheets or forms have one child which is a box: + * theie contents. + * - argument page: 1 based sheet page number. + * - argument tag: 1 based form tag number. + */ + synctex_node_p synctex_sheet(synctex_scanner_p scanner,int page); + synctex_node_p synctex_sheet_content(synctex_scanner_p scanner,int page); + synctex_node_p synctex_form(synctex_scanner_p scanner,int tag); + synctex_node_p synctex_form_content(synctex_scanner_p scanner,int tag); + + /* This is primarily used for debugging purpose. + * The second one logs information for the node and recursively displays information for its next node */ + void synctex_node_log(synctex_node_p node); + void synctex_node_display(synctex_node_p node); + + /* For quite all nodes, horizontal, vertical coordinates, and width. + * These are expressed in TeX small points coordinates, with origin at the top left corner. + */ + int synctex_node_h(synctex_node_p node); + int synctex_node_v(synctex_node_p node); + int synctex_node_width(synctex_node_p node); + int synctex_node_height(synctex_node_p node); + int synctex_node_depth(synctex_node_p node); + + /* For all nodes, dimensions of the enclosing box. + * These are expressed in TeX small points coordinates, with origin at the top left corner. + * A box is enclosing itself. + */ + int synctex_node_box_h(synctex_node_p node); + int synctex_node_box_v(synctex_node_p node); + int synctex_node_box_width(synctex_node_p node); + int synctex_node_box_height(synctex_node_p node); + int synctex_node_box_depth(synctex_node_p node); #ifdef __cplusplus } diff --git a/cut-n-paste/synctex/synctex_parser_advanced.h b/cut-n-paste/synctex/synctex_parser_advanced.h new file mode 100644 index 00000000..867fbf7e --- /dev/null +++ b/cut-n-paste/synctex/synctex_parser_advanced.h @@ -0,0 +1,554 @@ +/* + 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. + */ + +#include "synctex_parser.h" +#include "synctex_parser_utils.h" + +#ifndef __SYNCTEX_PARSER_PRIVATE__ +# define __SYNCTEX_PARSER_PRIVATE__ + +#ifdef __cplusplus +extern "C" { +#endif + /* Reminder that the argument must not be NULL */ + typedef synctex_node_p synctex_non_null_node_p; + + /* 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. + */ + + /** + * These are the masks for the synctex node types. + * int's are 32 bits at leats. + */ + enum { + synctex_shift_root, + synctex_shift_no_root, + synctex_shift_void, + synctex_shift_no_void, + synctex_shift_box, + synctex_shift_no_box, + synctex_shift_proxy, + synctex_shift_no_proxy, + synctex_shift_h, + synctex_shift_v + }; + enum { + synctex_mask_root = 1, + synctex_mask_no_root = synctex_mask_root<<1, + synctex_mask_void = synctex_mask_no_root<<1, + synctex_mask_no_void = synctex_mask_void<<1, + synctex_mask_box = synctex_mask_no_void<<1, + synctex_mask_no_box = synctex_mask_box<<1, + synctex_mask_proxy = synctex_mask_no_box<<1, + synctex_mask_no_proxy = synctex_mask_proxy<<1, + synctex_mask_h = synctex_mask_no_proxy<<1, + synctex_mask_v = synctex_mask_h<<1, + }; + enum { + synctex_mask_non_void_hbox = synctex_mask_no_void + | synctex_mask_box + | synctex_mask_h, + synctex_mask_non_void_vbox = synctex_mask_no_void + | synctex_mask_box + | synctex_mask_v + }; + typedef enum { + synctex_node_mask_sf = + synctex_mask_root + |synctex_mask_no_void + |synctex_mask_no_box + |synctex_mask_no_proxy, + synctex_node_mask_vbox = + synctex_mask_no_root + |synctex_mask_no_void + |synctex_mask_box + |synctex_mask_no_proxy + |synctex_mask_v, + synctex_node_mask_hbox = + synctex_mask_no_root + |synctex_mask_no_void + |synctex_mask_box + |synctex_mask_no_proxy + |synctex_mask_h, + synctex_node_mask_void_vbox = + synctex_mask_no_root + |synctex_mask_void + |synctex_mask_box + |synctex_mask_no_proxy + |synctex_mask_v, + synctex_node_mask_void_hbox = + synctex_mask_no_root + |synctex_mask_void + |synctex_mask_box + |synctex_mask_no_proxy + |synctex_mask_h, + synctex_node_mask_vbox_proxy = + synctex_mask_no_root + |synctex_mask_no_void + |synctex_mask_box + |synctex_mask_proxy + |synctex_mask_v, + synctex_node_mask_hbox_proxy = + synctex_mask_no_root + |synctex_mask_no_void + |synctex_mask_box + |synctex_mask_proxy + |synctex_mask_h, + synctex_node_mask_nvnn = + synctex_mask_no_root + |synctex_mask_void + |synctex_mask_no_box + |synctex_mask_no_proxy, + synctex_node_mask_input = + synctex_mask_root + |synctex_mask_void + |synctex_mask_no_box + |synctex_mask_no_proxy, + synctex_node_mask_proxy = + synctex_mask_no_root + |synctex_mask_void + |synctex_mask_no_box + |synctex_mask_proxy + } synctex_node_mask_t; + + enum { + /* input */ + synctex_tree_sibling_idx = 0, + synctex_tree_s_input_max = 1, + /* All */ + synctex_tree_s_parent_idx = 1, + synctex_tree_sp_child_idx = 2, + synctex_tree_spc_friend_idx = 3, + synctex_tree_spcf_last_idx = 4, + synctex_tree_spcfl_vbox_max = 5, + /* hbox supplement */ + synctex_tree_spcfl_next_hbox_idx = 5, + synctex_tree_spcfln_hbox_max = 6, + /* hbox proxy supplement */ + synctex_tree_spcfln_target_idx = 6, + synctex_tree_spcflnt_proxy_hbox_max = 7, + /* vbox proxy supplement */ + synctex_tree_spcfl_target_idx = 5, + synctex_tree_spcflt_proxy_vbox_max = 6, + /* spf supplement*/ + synctex_tree_sp_friend_idx = 2, + synctex_tree_spf_max = 3, + /* box boundary supplement */ + synctex_tree_spf_arg_sibling_idx = 3, + synctex_tree_spfa_max = 4, + /* proxy supplement */ + synctex_tree_spf_target_idx = 3, + synctex_tree_spft_proxy_max = 4, + /* last proxy supplement */ + synctex_tree_spfa_target_idx = 4, + synctex_tree_spfat_proxy_last_max = 5, + /* sheet supplement */ + synctex_tree_s_child_idx = 1, + synctex_tree_sc_next_hbox_idx = 2, + synctex_tree_scn_sheet_max = 3, + /* form supplement */ + synctex_tree_sc_target_idx = 2, + synctex_tree_sct_form_max = 3, + /* spct */ + synctex_tree_spc_target_idx = 3, + synctex_tree_spct_handle_max = 4, + }; + + enum { + /* input */ + synctex_data_input_tag_idx = 0, + synctex_data_input_line_idx = 1, + synctex_data_input_name_idx = 2, + synctex_data_input_tln_max = 3, + /* sheet */ + synctex_data_sheet_page_idx = 0, + synctex_data_p_sheet_max = 1, + /* form */ + synctex_data_form_tag_idx = 0, + synctex_data_t_form_max = 1, + /* tlchv */ + synctex_data_tag_idx = 0, + synctex_data_line_idx = 1, + synctex_data_column_idx = 2, + synctex_data_h_idx = 3, + synctex_data_v_idx = 4, + synctex_data_tlchv_max = 5, + /* tlchvw */ + synctex_data_width_idx = 5, + synctex_data_tlchvw_max = 6, + /* box */ + synctex_data_height_idx = 6, + synctex_data_depth_idx = 7, + synctex_data_box_max = 8, + /* hbox supplement */ + synctex_data_mean_line_idx = 8, + synctex_data_weight_idx = 9, + synctex_data_h_V_idx = 10, + synctex_data_v_V_idx = 11, + synctex_data_width_V_idx = 12, + synctex_data_height_V_idx = 13, + synctex_data_depth_V_idx = 14, + synctex_data_hbox_max = 15, + /* ref */ + synctex_data_ref_tag_idx = 0, + synctex_data_ref_h_idx = 1, + synctex_data_ref_v_idx = 2, + synctex_data_ref_thv_max = 3, + /* proxy */ + synctex_data_proxy_h_idx = 0, + synctex_data_proxy_v_idx = 1, + synctex_data_proxy_hv_max = 2, + /* handle */ + synctex_data_handle_w_idx = 0, + synctex_data_handle_w_max = 1, + }; + + /* each synctex node has a class */ + typedef struct synctex_class_t synctex_class_s; + typedef synctex_class_s * synctex_class_p; + + + /* synctex_node_p is a pointer to a node + * synctex_node_s is the target of the synctex_node_p 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. + */ + typedef union { + synctex_node_p as_node; + int as_integer; + char * as_string; + void * as_pointer; + } synctex_data_u; + typedef synctex_data_u * synctex_data_p; + +# if defined(SYNCTEX_USE_CHARINDEX) + typedef unsigned int synctex_charindex_t; + synctex_charindex_t synctex_node_charindex(synctex_node_p node); + typedef synctex_charindex_t synctex_lineindex_t; + synctex_lineindex_t synctex_node_lineindex(synctex_node_p node); + synctex_node_p synctex_scanner_handle(synctex_scanner_p scanner); +# define SYNCTEX_DECLARE_CHARINDEX \ + synctex_charindex_t char_index;\ + synctex_lineindex_t line_index; +# define SYNCTEX_DECLARE_CHAR_OFFSET \ + synctex_charindex_t charindex_offset; +# else +# define SYNCTEX_DECLARE_CHARINDEX +# define SYNCTEX_DECLARE_CHAR_OFFSET +# endif + struct synctex_node_t { + SYNCTEX_DECLARE_CHARINDEX + synctex_class_p class_; +#ifdef DEBUG + synctex_data_u data[22]; +#else + synctex_data_u data[1]; +#endif + }; + + typedef synctex_node_p * synctex_node_r; + + typedef struct { + int h; + int v; + } synctex_point_s; + + typedef synctex_point_s * synctex_point_p; + + typedef struct { + synctex_point_s min; /* top left */ + synctex_point_s max; /* bottom right */ + } synctex_box_s; + + typedef synctex_box_s * synctex_box_p; + /** + * These are the types of the synctex nodes. + * No need to use them but the compiler needs them here. + * There are 3 kinds of nodes. + * - primary nodes + * - proxies + * - handles + * Primary nodes are created at parse time + * of the synctex file. + * Proxies are used to support pdf forms. + * The ref primary nodes are replaced by a tree + * of proxy nodes which duplicate the tree of primary + * nodes available in the refered form. + * Roughly speaking, the primary nodes of the form + * know what to display, the proxy nodes know where. + * Handles are used in queries. They point to either + * primary nodes or proxies. + */ + typedef enum { + synctex_node_type_none = 0, + synctex_node_type_input, + synctex_node_type_sheet, + synctex_node_type_form, + synctex_node_type_ref, + synctex_node_type_vbox, + synctex_node_type_void_vbox, + synctex_node_type_hbox, + synctex_node_type_void_hbox, + synctex_node_type_kern, + synctex_node_type_glue, + synctex_node_type_rule, + synctex_node_type_math, + synctex_node_type_boundary, + synctex_node_type_box_bdry, + synctex_node_type_proxy, + synctex_node_type_proxy_last, + synctex_node_type_proxy_vbox, + synctex_node_type_proxy_hbox, + synctex_node_type_handle, + synctex_node_number_of_types + } synctex_node_type_t; + /* synctex_node_type gives the type of a given node, + * synctex_node_isa gives the same information as a human readable text. */ + synctex_node_type_t synctex_node_type(synctex_node_p node); + const char * synctex_node_isa(synctex_node_p node); + + synctex_node_type_t synctex_node_target_type(synctex_node_p node); + + synctex_node_type_t synctex_node_type(synctex_node_p node); + const char * synctex_node_isa(synctex_node_p node); + + void synctex_node_log(synctex_node_p node); + void synctex_node_display(synctex_node_p node); + + /* Given a node, access to the location in the synctex file where it is defined. + */ + + int synctex_node_form_tag(synctex_node_p node); + + int synctex_node_weight(synctex_node_p node); + int synctex_node_child_count(synctex_node_p node); + + int synctex_node_h(synctex_node_p node); + int synctex_node_v(synctex_node_p node); + int synctex_node_width(synctex_node_p node); + + int synctex_node_box_h(synctex_node_p node); + int synctex_node_box_v(synctex_node_p node); + int synctex_node_box_width(synctex_node_p node); + int synctex_node_box_height(synctex_node_p node); + int synctex_node_box_depth(synctex_node_p node); + + int synctex_node_hbox_h(synctex_node_p node); + int synctex_node_hbox_v(synctex_node_p node); + int synctex_node_hbox_width(synctex_node_p node); + int synctex_node_hbox_height(synctex_node_p node); + int synctex_node_hbox_depth(synctex_node_p node); + + synctex_scanner_p synctex_scanner_new(void); + synctex_node_p synctex_node_new(synctex_scanner_p scanner,synctex_node_type_t type); + + /** + * Scanner display switcher getter. + * If the switcher is 0, synctex_node_display is disabled. + * If the switcher is <0, synctex_node_display has no limit. + * If the switcher is >0, only the first switcher (as number) nodes are displayed. + * - parameter: a scanner + * - returns: an integer + */ + int synctex_scanner_display_switcher(synctex_scanner_p scanR); + void synctex_scanner_set_display_switcher(synctex_scanner_p scanR, int switcher); + + /** + * Iterator is the structure used to traverse + * the answer to client queries. + * First answers are the best matches, according + * to criteria explained below. + * Next answers are not ordered. + * Objects are handles to nodes in the synctex node tree starting at scanner. + */ + typedef struct synctex_iterator_t synctex_iterator_s; + typedef synctex_iterator_s * synctex_iterator_p; + + /** + * Designated creator for a display query, id est, + * forward navigation from source to output. + * Returns NULL if the query has no answer. + * Code example: + * synctex_iterator_p iterator = NULL; + * if ((iterator = synctex_iterator_new_display(...)) { + * synctex_node_p node = NULL; + * while((node = synctex_iterator_next_result(iterator))) { + * do something with node... + * } + */ + synctex_iterator_p synctex_iterator_new_display(synctex_scanner_p scanner,const char * name,int line,int column, int page_hint); + /** + * Designated creator for an edit query, id est, + * backward navigation from output to source. + * Code example: + * synctex_iterator_p iterator = NULL; + * if ((iterator = synctex_iterator_new_edit(...)) { + * synctex_node_p node = NULL; + * while((node = synctex_iterator_next_result(iterator))) { + * do something with node... + * } + */ + synctex_iterator_p synctex_iterator_new_edit(synctex_scanner_p scanner,int page,float h,float v); + /** + * Free all the resources. + * - argument iterator: the object to free... + * You should free the iterator before the scanner + * owning the nodes it iterates with. + */ + void synctex_iterator_free(synctex_iterator_p iterator); + /** + * Wether the iterator actually points to an object. + * - argument iterator: the object to iterate on... + */ + synctex_bool_t synctex_iterator_has_next(synctex_iterator_p iterator); + /** + * Returns the pointed object and advance the cursor + * to the next object. Returns NULL and does nothing + * if the end has already been reached. + * - argument iterator: the object to iterate on... + */ + synctex_node_p synctex_iterator_next_result(synctex_iterator_p iterator); + /** + * Reset the cursor position to the first result. + * - argument iterator: the object to iterate on... + */ + int synctex_iterator_reset(synctex_iterator_p iterator); + /** + * The number of objects left for traversal. + * - argument iterator: the object to iterate on... + */ + int synctex_iterator_count(synctex_iterator_p iterator); + + /** + * The target of the node, either a handle or a proxy. + */ + synctex_node_p synctex_node_target(synctex_node_p node); + +#ifndef SYNCTEX_NO_UPDATER + /* The main synctex updater object. + * This object is used to append information to the synctex file. + * Its implementation is considered private. + * It is used by the synctex command line tool to take into account modifications + * that could occur while postprocessing files by dvipdf like filters. + */ + typedef struct synctex_updater_t synctex_updater_s; + typedef synctex_updater_s * synctex_updater_p; + + /* Designated initializer. + * Once you are done with your whole job, + * free the updater */ + synctex_updater_p synctex_updater_new_with_output_file(const char * output, const char * directory); + + /* Use the next functions to append records to the synctex file, + * no consistency tests made on the arguments */ + void synctex_updater_append_magnification(synctex_updater_p updater, char * magnification); + void synctex_updater_append_x_offset(synctex_updater_p updater, char * x_offset); + void synctex_updater_append_y_offset(synctex_updater_p updater, char * y_offset); + + /* You MUST free the updater, once everything is properly appended */ + void synctex_updater_free(synctex_updater_p updater); +#endif + +#if defined(SYNCTEX_DEBUG) +# include "assert.h" +# define SYNCTEX_ASSERT assert +#else +# define SYNCTEX_ASSERT(UNUSED) +#endif + +#if defined(SYNCTEX_TESTING) +#warning TESTING IS PROHIBITED +#if __clang__ +#define __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \ +_Pragma("clang diagnostic push") \ +_Pragma("clang diagnostic ignored \"-Wformat-extra-args\"") + +#define __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS _Pragma("clang diagnostic pop") +#else +#define __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS +#define __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS +#endif + +# define SYNCTEX_TEST_BODY(counter, condition, desc, ...) \ + do { \ + __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \ + if (!(condition)) { \ + ++counter; \ + printf("**** Test failed: %s\nfile %s\nfunction %s\nline %i\n",#condition,__FILE__,__FUNCTION__,__LINE__); \ + printf((desc), ##__VA_ARGS__); \ + } \ + __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \ + } while(0) + +# define SYNCTEX_TEST_PARAMETER(counter, condition) SYNCTEX_TEST_BODY(counter, (condition), "Invalid parameter not satisfying: %s", #condition) + + int synctex_test_input(synctex_scanner_p scanner); + int synctex_test_proxy(synctex_scanner_p scanner); + int synctex_test_tree(synctex_scanner_p scanner); + int synctex_test_page(synctex_scanner_p scanner); + int synctex_test_handle(synctex_scanner_p scanner); + int synctex_test_display_query(synctex_scanner_p scanner); + int synctex_test_charindex(); + int synctex_test_sheet_1(); + int synctex_test_sheet_2(); + int synctex_test_sheet_3(); + int synctex_test_form(); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cut-n-paste/synctex/synctex_parser_local.h b/cut-n-paste/synctex/synctex_parser_local.h index 76848181..032b2568 100644 --- a/cut-n-paste/synctex/synctex_parser_local.h +++ b/cut-n-paste/synctex/synctex_parser_local.h @@ -1,43 +1,43 @@ -/* -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. - -*/ +/* + Copyright (c) 2008, 2009, 2010 , 2011 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.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. + + */ /* This local header file is for TEXLIVE, use your own header to fit your system */ # include <w2c/c-auto.h> /* for inline && HAVE_xxx */ diff --git a/cut-n-paste/synctex/synctex_parser_readme.md b/cut-n-paste/synctex/synctex_parser_readme.md new file mode 100644 index 00000000..d47a89f5 --- /dev/null +++ b/cut-n-paste/synctex/synctex_parser_readme.md @@ -0,0 +1,259 @@ +# __SyncTeX__ + +This file is part of the __SyncTeX__ package. + +[//]: # (Version: 1.21) +[//]: # (Date: Sun Oct 15 15:09:55 UTC 2017) + +## Important + +* Changes in version `1.21` + + * Display query returns more results (as much as `1.18`) + * Remove a `\` character from the name of 2 test files. + * Change variable name `class` to `class_` because the former is a reserved keyword in C++. + * Adding a more portable unused variable management. + * Various cosmetic changes in the source code, including explicit declaration of `void` in forward function declaration. + + +* Changes in version `1.20` + + One bug fixed in some initialization and different syntax to make some compilers happy. + +* Changes in version `1.19` + + A long standing bug affecting only pdftex has been fixed by adding support to pdf forms. As a side effect, the synchronization algorithm gains in accuracy for all the engines, especially from pdf to source. Of course, there is a small cost in both memory footprint and computational time, but none is noticeable. + + Some technical changes in the API. + * more consistent type naming convention + * `_s` suffix for struct's + * `_p` suffix for pointers + * `_t` suffix for standard types + * `_f` suffix for functions... + + thus `synctex_node_t` has become `synctex_node_p`. + + * supplemental argument in `synctex_display_query`. Set `page_hint` to the currently displayed pdf page number (0 based). If this info is not available, set `page_hint` to 0, it corresponds to the old behaviour. + * rename `synctex_next_result` to `synctex_scanner_next_result` + * additional `synctex_parser_private.h` header where + more API are exposed. For an advanced usage only (eg parallel synchronizations). + * `SYNCTEX_NO_UPDATER` preprocessor macro to deactivate some code useless to frontends. + +## What is it ? + +The *Synchronization TeXnology* named __SyncTeX__ is a new feature +of recent __TeX__ engines designed by Jérôme Laurens. +It allows to synchronize between input and output, which means to +navigate from the source document to the typeset material and vice versa. +Browse the source code for more information. + +## Contents +This package is mainly for developers, it contains the following files: + +* `synctex_parser_readme.md` (this file) +* `synctex_parser_version.txt` +* `synctex_parser_utils.c` +* `synctex_parser_utils.h` +* `synctex_parser_local.h` +* `synctex_parser.h` +* `synctex_parser_advanced.h` +* `synctex_parser.c` + +The file you are reading contains more informations about the __SyncTeX__ parser history. + +## Source + +All stable sources are available from [TeXLive repository](http://www.tug.org/svn/texlive/trunk/Build/source/texk/web2c/synctexdir/). + +Latest development sources are available from GitHub. + +Please notice that due to the complexity of the TeXLive TeX distribution, there might be some delay before synchronization occurs between various repositories. + +## Usage + +In order to support __SyncTeX__ in a viewer, it is sufficient to include +in the source the files `synctex_parser.c` and `synctex_parser_utils.c`. +The synctex parser usage is described in `synctex_parser.h` header file. + +More advanced usage is found in `synctex_parser_advanced.h` + +The other files are used by tex engines or by the synctex command line utility: + +``` +ChangeLog +README.txt +am +man1 +man5 +synctex-common.h +synctex-convert.sh +synctex-e-mem.ch0 +synctex-e-mem.ch1 +synctex-e-rec.ch0 +synctex-e-rec.ch1 +synctex-etex.h +synctex-mem.ch0 +synctex-mem.ch1 +synctex-mem.ch2 +synctex-pdf-rec.ch2 +synctex-pdftex.h +synctex-rec.ch0 +synctex-rec.ch1 +synctex-rec.ch2 +synctex-tex.h +synctex-xe-mem.ch2 +synctex-xe-rec.ch2 +synctex-xe-rec.ch3 +synctex-xetex.h +synctex.c +synctex.defines +synctex.h +synctex_main.c +tests +... +``` + +## Version: + +This is version 1, which refers to the synctex output file format. + +The files are identified by a build number. +In order to help developers to automatically manage the version and build numbers +and download the parser only when necessary, the `synctex_parser_version.txt` +is an ASCII text file just containing the current version and build numbers eg `1.19`. + +## History: + +* 1.1: Thu Jul 17 09:28:13 UTC 2008 + - First official version available in TeXLive 2008 DVD. + Unfortunately, the backwards synchronization is not working properly mainly for ConTeXt users, see below. +* 1.2: Tue Sep 2 10:28:32 UTC 2008 + - Correction for ConTeXt support in the edit query. + The previous method was assuming that TeX boxes do not overlap, + which is reasonable for LaTeX but not for ConTeXt. + This assumption is no longer considered. +* 1.3: Fri Sep 5 09:39:57 UTC 2008 + - Local variable "read" renamed to "already_read" to avoid conflicts. + - "inline" compiler directive renamed to "SYNCTEX_INLINE" for code support and maintenance + - _synctex_error cannot be inlined due to variable arguments (thanks Christiaan Hofman) + - Correction in the display query, extra boundary nodes are used for a more precise forwards synchronization +* 1.4: Fri Sep 12 08:12:34 UTC 2008 + - For an unknown reason, the previous version was not the real 1.3 (as used in iTeXMac2 build 747). + As a consequence, a crash was observed. + - Some typos are fixed. +* 1.6: Mon Nov 3 20:20:02 UTC 2008 + - The bug that prevented synchronization with compressed files on windows has been fixed. + - New interface to allow system specific customization. + - Note that some APIs have changed. +* 1.8: Mer 8 jul 2009 11:32:38 UTC +Note that version 1.7 was delivered privately. + - bug fix: synctex was causing a memory leak in pdftex and xetex, thus some processing speed degradation + - bug fix: the synctex command line tool was broken when updating a .synctex file + - enhancement: better accuracy of the synchronization process + - enhancement: the pdf output file and the associated .synctex file no longer need to live in the same directory. + The new -d option of the synctex command line tool manages this situation. + This is handy when using something like tex -output-directory=DIR ... +* 1.9: Wed Nov 4 11:52:35 UTC 2009 + - Various typo fixed + - OutputDebugString replaced by OutputDebugStringA to deliberately disable unicode preprocessing + - New conditional created because OutputDebugStringA is only available since Windows 2K professional +* 1.10: Sun Jan 10 10:12:32 UTC 2010 + - Bug fix in synctex_parser.c to solve a synchronization problem with amsmath's gather environment. + Concerns the synctex tool. +* 1.11: Sun Jan 17 09:12:31 UTC 2010 + - Bug fix in synctex_parser.c, function synctex_node_box_visible_v: 'x' replaced by 'y'. + Only 3rd party tools are concerned. +* 1.12: Mon Jul 19 21:52:10 UTC 2010 + - Bug fix in synctex_parser.c, function __synctex_open: the io_mode was modified even in case of a non zero return, +causing a void .synctex.gz file to be created even if it was not expected. Reported by Marek Kasik concerning a bug on evince. +* 1.13: Fri Mar 11 07:39:12 UTC 2011 + - Bug fix in synctex_parser.c, better synchronization as suggested by Jan Sundermeyer (near line 3388). + - Stronger code design in synctex_parser_utils.c, function _synctex_get_name (really neutral behavior). + Only 3rd party tools are concerned. +* 1.14: Fri Apr 15 19:10:57 UTC 2011 + - taking output_directory into account + - Replaced FOPEN_WBIN_MODE by FOPEN_W_MODE when opening the text version of the .synctex file. + - Merging with LuaTeX's version of synctex.c +* 1.15: Fri Jun 10 14:10:17 UTC 2011 +This concerns the synctex command line tool and 3rd party developers. +TeX and friends are not concerned by these changes. + - Bug fixed in _synctex_get_io_mode_name, sometimes the wrong mode was returned + - Support for LuaTeX convention of './' file prefixing +* 1.16: Tue Jun 14 08:23:30 UTC 2011 +This concerns the synctex command line tool and 3rd party developers. +TeX and friends are not concerned by these changes. + - Better forward search (thanks Jose Alliste) + - Support for LuaTeX convention of './' file prefixing now for everyone, not only for Windows +* 1.17: Fri Oct 14 08:15:16 UTC 2011 +This concerns the synctex command line tool and 3rd party developers. +TeX and friends are not concerned by these changes. + - synctex_parser.c: cosmetic changes to enhance code readability + - Better forward synchronization. + The problem occurs for example with LaTeX \item command. + The fact is that this command creates nodes at parse time but these nodes are used only + after the text material of the \item is displayed on the page. The consequence is that sometimes, + forward synchronization spots an irrelevant point from the point of view of the editing process. + This was due to some very basic filtering policy, where a somehow arbitrary choice was made when + many different possibilities where offered for synchronisation. + Now, forward synchronization prefers nodes inside an hbox with as many acceptable spots as possible. + This is achieved with the notion of mean line and node weight. + - Adding support for the new file naming convention with './' + - function `synctex_ignore_leading_dot_slash_in_path replaces` `synctex_ignore_leading_dot_slash` + - function `_synctex_is_equivalent_file_name` is more permissive + Previously, the function synctex_scanner_get_tag would give an answer only when + the given file name was EXACTLY one of the file names listed in the synctex file. + The we added some changes accepting for example 'foo.tex' instead of './foo.tex'. + Now we have an even looser policy for dealing with file names. + If the given file name does not match exactly one the file names of the synctex file, + then we try to match the base names. If there is only one match of the base names, + then it is taken as a match for the whole names. + The base name is defined as following: + + `./foo => foo + /my///.////foo => foo + /foo => /foo + /my//.foo => /my//.foo` + +* 1.17: Tue Mar 13 10:10:03 UTC 2012 + - minor changes, no version changes + - syntax man pages are fixed as suggested by M. Shimata + see mail to [email protected] titled "syntax.5 has many warnings from groff" and "syntax.1 use invalid macro for mdoc" + - 1.17: Tue Jan 14 09:55:00 UTC 2014, fixed a segfault, patch from Sebastian Ramacher + - 1.17: Mon Aug 04, fixed a memory leak +* 1.18: Thu Jun 25 11:36:05 UTC 2015 + - nested sheets now fully supported (does it make sense in TeX) + - cosmetic changes: uniform indentation + - suppression of warnings, mainly long/int ones. In short, zlib likes ints when size_t likes longs. + - CLI synctex tool can build out of TeXLive (modulo appropriate options passed to the compiler) +* 1.19: Mon Jul 3 20:03:56 UTC 2017 + - the nested sheets patch was not a good solution. + It has been moved from the parser to the engine. + See the `synctex.c` source file for detailed explanations. + - there is a new synctex format specification. + We can see that a `.synctex` file can contain many times + the same vertical position because many objects belong + to the same line. When the options read `-synctex=±2` or more, + a very basic compression algorithm is used: + if synctex is about to write the same number then it writes + an `=` sign instead. This saves approximately 10% of the + synctex output file, either compressed or not. + The new synctex parser has been updated accordingly. + Actual tex frontend won't see any difference with the + TeX engines that include this new feature. + Frontends with the new parser won't see any difference + with the older TeX engines. + Frontends with the new parser will only see a difference + with new TeX engines if `-synctex=±2` or more is used. + +## 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. + +Copyright (c) 2008-2017 jerome DOT laurens AT u-bourgogne DOT fr + diff --git a/cut-n-paste/synctex/synctex_parser_utils.c b/cut-n-paste/synctex/synctex_parser_utils.c index 62ac0ad2..c4f200d8 100644 --- a/cut-n-paste/synctex/synctex_parser_utils.c +++ b/cut-n-paste/synctex/synctex_parser_utils.c @@ -1,41 +1,40 @@ -/* -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. +/* + Copyright (c) 2008-2017 jerome DOT laurens AT u-bourgogne DOT fr + + This file is part of the __SyncTeX__ package. + + [//]: # (Latest Revision: Fri Jul 14 16:20:41 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. */ @@ -61,7 +60,7 @@ authorization from the copyright holder. #define SYNCTEX_OS2 1 #endif -#ifdef _WIN32_WINNT_WINXP +#if defined(_WIN32) #define SYNCTEX_RECENT_WINDOWS 1 #endif @@ -71,18 +70,25 @@ authorization from the copyright holder. #endif void *_synctex_malloc(size_t size) { - void * ptr = malloc(size); - if(ptr) { -/* There used to be a switch to use bzero because it is more secure. JL */ - memset(ptr,0, size); - } - return (void *)ptr; + void * ptr = malloc(size); + if(ptr) { + memset(ptr,0, size);/* ensures null termination of strings */ + } + return (void *)ptr; } -int _synctex_error(const char * reason,...) { - va_list arg; +void _synctex_free(void * ptr) { + if (ptr) { + free(ptr); + } +} + +#if !defined(_WIN32) +# include <syslog.h> +#endif + +int _synctex_log(int level, const char * prompt, const char * reason,va_list arg) { int result; - va_start (arg, reason); # ifdef SYNCTEX_RECENT_WINDOWS {/* This code is contributed by William Blum. As it does not work on some older computers, @@ -94,23 +100,65 @@ int _synctex_error(const char * reason,...) { JL.*/ char *buff; size_t len; - OutputDebugStringA("SyncTeX ERROR: "); + OutputDebugStringA(prompt); len = _vscprintf(reason, arg) + 1; buff = (char*)malloc( len * sizeof(char) ); - result = vsprintf(buff, reason, arg) +strlen("SyncTeX ERROR: "); + result = vsprintf(buff, reason, arg) +strlen(prompt); OutputDebugStringA(buff); OutputDebugStringA("\n"); free(buff); } +# elif SYNCTEX_USE_SYSLOG + char * buffer1 = NULL; + char * buffer2 = NULL; + openlog ("SyncTeX", LOG_CONS | LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_LOCAL0); + if (vasprintf(&buffer1,reason,arg)>=0 + && asprintf(&buffer2,"%s%s",prompt, buffer1)>=0) { + syslog (level, "%s", buffer2); + result = (int)strlen(buffer2); + } else { + syslog (level, "%s",prompt); + vsyslog(level,reason,arg); + result = (int)strlen(prompt); + } + free(buffer1); + free(buffer2); + closelog(); # else - result = fprintf(stderr,"SyncTeX ERROR: "); - result += vfprintf(stderr, reason, arg); - result += fprintf(stderr,"\n"); + FILE * where = level == LOG_ERR? stderr: stdout; + result = fputs(prompt,where); + result += vfprintf(where, reason, arg); + result += fprintf(where,"\n"); # endif - va_end (arg); return result; } +int _synctex_error(const char * reason,...) { + va_list arg; + int result; + va_start (arg, reason); +#if defined(SYNCTEX_RECENT_WINDOWS) /* LOG_ERR is not used */ + result = _synctex_log(0, "! SyncTeX Error : ", reason, arg); +#else + result = _synctex_log(LOG_ERR, "! SyncTeX Error : ", reason, arg); +#endif + va_end (arg); + return result; +} + +int _synctex_debug(const char * reason,...) { + va_list arg; + int result; + va_start (arg, reason); +#if defined(SYNCTEX_RECENT_WINDOWS) /* LOG_DEBUG is not used */ + result = _synctex_log(0, "! SyncTeX Error : ", reason, arg); +#else + result = _synctex_log(LOG_DEBUG, "! SyncTeX Error : ", reason, arg); +#endif + va_end (arg); + return result; +} + /* strip the last extension of the given string, this string is modified! */ void _synctex_strip_last_path_extension(char * string) { if(NULL != string){ @@ -250,8 +298,8 @@ const char * _synctex_last_path_component(const char * name) { } int _synctex_copy_with_quoting_last_path_component(const char * src, char ** dest_ref, size_t size) { - const char * lpc; if(src && dest_ref) { + const char * lpc; # define dest (*dest_ref) dest = NULL; /* Default behavior: no change and sucess. */ lpc = _synctex_last_path_component(src); @@ -335,7 +383,7 @@ char * _synctex_merge_strings(const char * first,...) { _synctex_error("! _synctex_merge_strings: Memory problem"); return NULL; } - return NULL; + return NULL; } /* The purpose of _synctex_get_name is to find the name of the synctex file. @@ -396,7 +444,6 @@ int _synctex_get_name(const char * output, const char * build_directory, char ** if(NULL == (dir_name = (char *)malloc(size+1))) { _synctex_error("! _synctex_get_name: Memory problem"); free(core_name); - dir_name = NULL; return -1; } if(dir_name != strncpy(dir_name,output,size)) { @@ -497,6 +544,17 @@ int _synctex_get_name(const char * output, const char * build_directory, char ** # undef CLEAN_AND_REMOVE /* set up the returned values */ * synctex_name_ref = synctex_name; + /* synctex_name won't always end in .gz, even when compressed. */ + FILE * F = fopen(synctex_name, "r"); + if (F != NULL) { + if (!feof(F) + && 31 == fgetc(F) + && !feof(F) + && 139 == fgetc(F)) { + io_mode = synctex_compress_mode_gz; + } + fclose(F); + } * io_mode_ref = io_mode; return 0; } @@ -506,7 +564,7 @@ int _synctex_get_name(const char * output, const char * build_directory, char ** } const char * _synctex_get_io_mode_name(synctex_io_mode_t io_mode) { - static const char * synctex_io_modes[4] = {"r","rb","a","ab"}; + static const char * synctex_io_modes[4] = {"r","rb","a","ab"}; unsigned index = ((io_mode & synctex_io_gz_mask)?1:0) + ((io_mode & synctex_io_append_mask)?2:0);// bug pointed out by Jose Alliste return synctex_io_modes[index]; } diff --git a/cut-n-paste/synctex/synctex_parser_utils.h b/cut-n-paste/synctex/synctex_parser_utils.h index 86387f19..4dd4e17e 100644 --- a/cut-n-paste/synctex/synctex_parser_utils.h +++ b/cut-n-paste/synctex/synctex_parser_utils.h @@ -1,16 +1,15 @@ -/* -Copyright (c) 2008, 2009, 2010, 2011 jerome DOT laurens AT u-bourgogne DOT fr +/* + Copyright (c) 2008-2017 jerome DOT laurens AT u-bourgogne DOT fr + + This file is part of the __SyncTeX__ package. + + [//]: # (Latest Revision: Fri Jul 14 16:20:41 UTC 2017) + [//]: # (Version: 1.21) + + See `synctex_parser_readme.md` for more details + + ## License -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 @@ -32,23 +31,29 @@ 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 +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. */ +#ifndef SYNCTEX_PARSER_UTILS_H +#define SYNCTEX_PARSER_UTILS_H + /* The utilities declared here are subject to conditional implementation. * All the operating system special stuff goes here. * The problem mainly comes from file name management: path separator, encoding... */ -# define synctex_bool_t int -# define synctex_YES -1 +#include "synctex_version.h" + +typedef int synctex_bool_t; +# define synctex_YES (0==0) +# define synctex_NO (0==1) + # define synctex_ADD_QUOTES -1 # define synctex_COMPRESS -1 -# define synctex_NO 0 # define synctex_DONT_ADD_QUOTES 0 # define synctex_DONT_COMPRESS 0 @@ -68,27 +73,32 @@ extern "C" { # define SYNCTEX_CASE_SENSITIVE_PATH 1 # define SYNCTEX_IS_PATH_SEPARATOR(c) ('/' == c) # endif - + # if defined(_WIN32) || defined(__OS2__) # define SYNCTEX_IS_DOT(c) ('.' == c) # else # define SYNCTEX_IS_DOT(c) ('.' == c) # endif - + # if SYNCTEX_CASE_SENSITIVE_PATH # define SYNCTEX_ARE_PATH_CHARACTERS_EQUAL(left,right) (left != right) # else # define SYNCTEX_ARE_PATH_CHARACTERS_EQUAL(left,right) (toupper(left) != toupper(right)) # endif - + /* This custom malloc functions initializes to 0 the newly allocated memory. * There is no bzero function on windows. */ void *_synctex_malloc(size_t size); +/* To balance _synctex_malloc. + * ptr might be NULL. */ +void _synctex_free(void * ptr); + /* This is used to log some informational message to the standard error stream. * On Windows, the stderr stream is not exposed and another method is used. * The return value is the number of characters printed. */ -int _synctex_error(const char * reason,...); + int _synctex_error(const char * reason,...); + int _synctex_debug(const char * reason,...); /* strip the last extension of the given string, this string is modified! * This function depends on the OS because the path separator may differ. @@ -144,9 +154,10 @@ int _synctex_get_name(const char * output, const char * build_directory, char ** const char * _synctex_get_io_mode_name(synctex_io_mode_t io_mode); synctex_bool_t synctex_ignore_leading_dot_slash_in_path(const char ** name); - + #ifdef __cplusplus } #endif #endif +#endif /* SYNCTEX_PARSER_UTILS_H */ diff --git a/cut-n-paste/synctex/synctex_parser_version.txt b/cut-n-paste/synctex/synctex_parser_version.txt index d907c153..d2ab029d 100644 --- a/cut-n-paste/synctex/synctex_parser_version.txt +++ b/cut-n-paste/synctex/synctex_parser_version.txt @@ -1 +1 @@ -1.18
\ No newline at end of file +1.21 diff --git a/cut-n-paste/synctex/synctex_version.h b/cut-n-paste/synctex/synctex_version.h new file mode 100644 index 00000000..5665ccb9 --- /dev/null +++ b/cut-n-paste/synctex/synctex_version.h @@ -0,0 +1,59 @@ +/* +Copyright (c) 2008-2017 jerome DOT laurens AT u-bourgogne DOT fr + +This file is part of the __SyncTeX__ package. + +[//]: # (Latest Revision: Fri Jul 14 16:20:41 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. +*/ + +#ifndef __SYNCTEX_VERSION__ +# define __SYNCTEX_VERSION__ + +# define SYNCTEX_VERSION_MAJOR 1 + +# define SYNCTEX_VERSION_STRING "1.21" + +# define SYNCTEX_CLI_VERSION_STRING "1.5" + +#endif diff --git a/cut-n-paste/synctex/update-synctex-from-TL.sh b/cut-n-paste/synctex/update-synctex-from-TL.sh index ca0e10bf..4d8af0e3 100755 --- a/cut-n-paste/synctex/update-synctex-from-TL.sh +++ b/cut-n-paste/synctex/update-synctex-from-TL.sh @@ -4,10 +4,10 @@ # Get latest synctex parser from TexLive SVN repository. SVN_URI=svn://tug.org/texlive/trunk/Build/source/texk/web2c/synctexdir SCRIPT_NAME=update-synctex-from-TL.sh -FILES="synctex_parser_version.txt synctex_parser.c synctex_parser.h synctex_parser_local.h synctex_parser_utils.c synctex_parser_utils.h" +FILES="synctex_parser.c synctex_parser.h synctex_parser_advanced.h synctex_parser_local.h synctex_parser_readme.md synctex_parser_readme.txt synctex_parser_utils.c synctex_parser_utils.h synctex_parser_version.txt synctex_version.h" echo "Obtaining latest version of the sources" - for FILE in $FILES + for FILE in $FILES do svn export $SVN_URI/$FILE done diff --git a/libdocument/ev-document.c b/libdocument/ev-document.c index 639335e7..fcebc6e7 100644 --- a/libdocument/ev-document.c +++ b/libdocument/ev-document.c @@ -54,7 +54,7 @@ struct _EvDocumentPrivate EvPageSize *page_sizes; EvDocumentInfo *info; - synctex_scanner_t synctex_scanner; + synctex_scanner_p synctex_scanner; }; static gint _ev_document_get_n_pages (EvDocument *document); @@ -417,7 +417,7 @@ ev_document_synctex_backward_search (EvDocument *document, gfloat y) { EvSourceLink *result = NULL; - synctex_scanner_t scanner; + synctex_scanner_p scanner; g_return_val_if_fail (EV_IS_DOCUMENT (document), NULL); @@ -426,10 +426,10 @@ ev_document_synctex_backward_search (EvDocument *document, return NULL; if (synctex_edit_query (scanner, page_index + 1, x, y) > 0) { - synctex_node_t node; + synctex_node_p node; /* We assume that a backward search returns either zero or one result_node */ - node = synctex_next_result (scanner); + node = synctex_scanner_next_result (scanner); if (node != NULL) { const gchar *filename; @@ -462,7 +462,7 @@ ev_document_synctex_forward_search (EvDocument *document, EvSourceLink *link) { EvMapping *result = NULL; - synctex_scanner_t scanner; + synctex_scanner_p scanner; g_return_val_if_fail (EV_IS_DOCUMENT (document), NULL); @@ -470,11 +470,11 @@ ev_document_synctex_forward_search (EvDocument *document, if (!scanner) return NULL; - if (synctex_display_query (scanner, link->filename, link->line, link->col) > 0) { - synctex_node_t node; + if (synctex_display_query (scanner, link->filename, link->line, link->col, 0) > 0) { + synctex_node_p node; gint page; - if ((node = synctex_next_result (scanner))) { + if ((node = synctex_scanner_next_result (scanner))) { result = g_new (EvMapping, 1); page = synctex_node_page (node) - 1; |