1 /*
2  Copyright (c) 2008-2017 jerome DOT laurens AT u-bourgogne DOT fr
3 
4  This file is part of the __SyncTeX__ package.
5 
6  [//]: # (Latest Revision: Sun Oct 15 15:09:55 UTC 2017)
7  [//]: # (Version: 1.21)
8 
9  See `synctex_parser_readme.md` for more details
10 
11  ## License
12 
13  Permission is hereby granted, free of charge, to any person
14  obtaining a copy of this software and associated documentation
15  files (the "Software"), to deal in the Software without
16  restriction, including without limitation the rights to use,
17  copy, modify, merge, publish, distribute, sublicense, and/or sell
18  copies of the Software, and to permit persons to whom the
19  Software is furnished to do so, subject to the following
20  conditions:
21 
22  The above copyright notice and this permission notice shall be
23  included in all copies or substantial portions of the Software.
24 
25  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
27  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
29  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
30  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
32  OTHER DEALINGS IN THE SOFTWARE
33 
34  Except as contained in this notice, the name of the copyright holder
35  shall not be used in advertising or otherwise to promote the sale,
36  use or other dealings in this Software without prior written
37  authorization from the copyright holder.
38 
39  Acknowledgments:
40  ----------------
41  The author received useful remarks from the pdfTeX developers, especially Hahn The Thanh,
42  and significant help from XeTeX developer Jonathan Kew
43 
44  Nota Bene:
45  ----------
46  If you include or use a significant part of the synctex package into a software,
47  I would appreciate to be listed as contributor and see "SyncTeX" highlighted.
48 
49  */
50 
51 /*  We assume that high level application like pdf viewers will want
52  *  to embed this code as is. We assume that they also have locale.h and setlocale.
53  *  For other tools such as TeXLive tools, you must define SYNCTEX_USE_LOCAL_HEADER,
54  *  when building. You also have to create and customize synctex_parser_local.h to fit your system.
55  *  In particular, the HAVE_LOCALE_H and HAVE_SETLOCALE macros should be properly defined.
56  *  With this design, you should not need to edit this file. */
57 
58 /**
59  *  \file synctex_parser.c
60  *  \brief SyncTeX file parser and controller.
61  *  - author: Jérôme LAURENS
62  *  \version 1.21
63  *  \date Sun Oct 15 15:09:55 UTC 2017
64  *
65  *  Reads and parse *.synctex[.gz] files,
66  *  performs edit and display queries.
67  *
68  *  See
69  *  - synctex_scanner_new_with_output_file
70  *  - synctex_scanner_parse
71  *  - synctex_scanner_free
72  *  - synctex_display_query
73  *  - synctex_edit_query
74  *  - synctex_scanner_next_result
75  *  - synctex_scanner_reset_result
76  *
77  *  The data is organized in a graph with multiple entries.
78  *  The root object is a scanner, it is created with the contents on a synctex file.
79  *  Each node of the tree is a synctex_node_t object.
80  *  There are 3 subtrees, two of them sharing the same leaves.
81  *  The first tree is the list of input records, where input file names are associated with tags.
82  *  The second tree is the box tree as given by TeX when shipping pages out.
83  *  First level objects are sheets and forms, containing boxes, glues, kerns...
84  *  The third tree allows to browse leaves according to tag and line.
85  */
86 #   if defined(SYNCTEX_USE_LOCAL_HEADER)
87 #       include "synctex_parser_local.h"
88 #   else
89 #       define HAVE_LOCALE_H 1
90 #       define HAVE_SETLOCALE 1
91 #       if defined(_MSC_VER)
92 #          define SYNCTEX_INLINE __inline
93 #       else
94 #          define SYNCTEX_INLINE inline
95 #       endif
96 #   endif
97 
98 #define _GNU_SOURCE
99 #include <stdlib.h>
100 #include <stdarg.h>
101 #include <stdio.h>
102 #include <string.h>
103 #include <errno.h>
104 #include <limits.h>
105 
106 #if defined(HAVE_LOCALE_H)
107 #include <locale.h>
108 #endif
109 
110 /* Mark unused paramters, so that there will be no compile warnings. */
111 #ifdef __DARWIN_UNIX03
112 #   define SYNCTEX_UNUSED(x) SYNCTEX_PRAGMA(unused(x))
113 #   define SYNCTEX_PRAGMA(x) _Pragma ( #x )
114 #else
115 #   define SYNCTEX_UNUSED(x) (void)(x);
116 #endif
117 
118 #include "synctex_parser_advanced.h"
119 
_synctex_abs(int x)120 SYNCTEX_INLINE static int _synctex_abs(int x) {
121     return x>0? x: -x;
122 }
123 /*  These are the possible extensions of the synctex file */
124 const char * synctex_suffix = ".synctex";
125 const char * synctex_suffix_gz = ".gz";
126 
127 typedef synctex_node_p(*synctex_node_new_f)(synctex_scanner_p);
128 typedef void(*synctex_node_fld_f)(synctex_node_p);
129 typedef char *(*synctex_node_str_f)(synctex_node_p);
130 
131 /**
132  *  Pseudo class.
133  *  - author: J. Laurens
134  *
135  *  Each nodes has a class, it is therefore called an object.
136  *  Each class has a unique scanner.
137  *  Each class has a type which is a unique identifier.
138  *  The class points to various methods,
139  *  each of them vary amongst objects.
140  *  Each class has a data model which stores node's attributes.
141  *  Each class has an tree model which stores children and parent.
142  *  Inspectors give access to data and tree elements.
143  */
144 
145 /*  8 fields + size: spcflnat */
146 typedef struct synctex_tree_model_t {
147     int sibling;
148     int parent;
149     int child;
150     int friend;
151     int last;
152     int next_hbox;
153     int arg_sibling;
154     int target;
155     int size;
156 } synctex_tree_model_s;
157 typedef const synctex_tree_model_s * synctex_tree_model_p;
158 
159 typedef struct synctex_data_model_t {
160     int tag;
161     int line;
162     int column;
163     int h;
164     int v;
165     int width;
166     int height;
167     int depth;
168     int mean_line;
169     int weight;
170     int h_V;
171     int v_V;
172     int width_V;
173     int height_V;
174     int depth_V;
175     int name;
176     int page;
177     int size;
178 } synctex_data_model_s;
179 
180 typedef const synctex_data_model_s * synctex_data_model_p;
181 
182 typedef int (*synctex_int_getter_f)(synctex_node_p);
183 typedef struct synctex_tlcpector_t {
184     synctex_int_getter_f tag;
185     synctex_int_getter_f line;
186     synctex_int_getter_f column;
187 } synctex_tlcpector_s;
188 typedef const synctex_tlcpector_s * synctex_tlcpector_p;
_synctex_int_none(synctex_node_p node)189 static int _synctex_int_none(synctex_node_p node) {
190     SYNCTEX_UNUSED(node)
191     return 0;
192 }
193 static const synctex_tlcpector_s synctex_tlcpector_none = {
194     &_synctex_int_none, /* tag */
195     &_synctex_int_none, /* line */
196     &_synctex_int_none, /* column */
197 };
198 
199 typedef struct synctex_inspector_t {
200     synctex_int_getter_f h;
201     synctex_int_getter_f v;
202     synctex_int_getter_f width;
203     synctex_int_getter_f height;
204     synctex_int_getter_f depth;
205 } synctex_inspector_s;
206 typedef const synctex_inspector_s * synctex_inspector_p;
207 static const synctex_inspector_s synctex_inspector_none = {
208     &_synctex_int_none, /* h */
209     &_synctex_int_none, /* v */
210     &_synctex_int_none, /* width */
211     &_synctex_int_none, /* height */
212     &_synctex_int_none, /* depth */
213 };
214 
215 typedef float (*synctex_float_getter_f)(synctex_node_p);
216 typedef struct synctex_vispector_t {
217     synctex_float_getter_f h;
218     synctex_float_getter_f v;
219     synctex_float_getter_f width;
220     synctex_float_getter_f height;
221     synctex_float_getter_f depth;
222 } synctex_vispector_s;
_synctex_float_none(synctex_node_p node)223 static float _synctex_float_none(synctex_node_p node) {
224     SYNCTEX_UNUSED(node)
225     return 0;
226 }
227 static const synctex_vispector_s synctex_vispector_none = {
228     &_synctex_float_none, /* h */
229     &_synctex_float_none, /* v */
230     &_synctex_float_none, /* width */
231     &_synctex_float_none, /* height */
232     &_synctex_float_none, /* depth */
233 };
234 typedef const synctex_vispector_s * synctex_vispector_p;
235 
236 struct synctex_class_t {
237     synctex_scanner_p scanner;
238     synctex_node_type_t type;
239     synctex_node_new_f new;
240     synctex_node_fld_f free;
241     synctex_node_fld_f log;
242     synctex_node_fld_f display;
243     synctex_node_str_f abstract;
244     synctex_tree_model_p navigator;
245     synctex_data_model_p modelator;
246     synctex_tlcpector_p tlcpector;
247     synctex_inspector_p inspector;
248     synctex_vispector_p vispector;
249 };
250 
251 /**
252  *  Nota bene: naming convention.
253  *  For static API, when the name contains "proxy", it applies to proxies.
254  *  When the name contains "noxy", it applies to non proxies only.
255  *  When the name contains "node", well it depends...
256  */
257 
258 typedef synctex_node_p synctex_proxy_p;
259 typedef synctex_node_p synctex_noxy_p;
260 
261 #	ifdef SYNCTEX_NOTHING
262 #       pragma mark -
263 #       pragma mark Abstract OBJECTS and METHODS
264 #   endif
265 
266 /**
267  *  \def SYNCTEX_MSG_SEND
268  *  \brief Takes care of sending the given message if possible.
269  *  - parameter NODE: of type synctex_node_p
270  *  - parameter SELECTOR: one of the class_ pointer properties
271  */
272 #   define SYNCTEX_MSG_SEND(NODE,SELECTOR) do {\
273     synctex_node_p N__ = NODE;\
274     if (N__ && N__->class_->SELECTOR) {\
275         (*(N__->class_->SELECTOR))(N__);\
276     }\
277 } while (synctex_NO)
278 
279 /**
280  *  Free the given node by sending the free message.
281  *  - parameter NODE: of type synctex_node_p
282  */
synctex_node_free(synctex_node_p node)283 void synctex_node_free(synctex_node_p node) {
284     SYNCTEX_MSG_SEND(node,free);
285 }
286 #   if defined(SYNCTEX_TESTING)
287 #       if !defined(SYNCTEX_USE_HANDLE)
288 #           define SYNCTEX_USE_HANDLE 1
289 #       endif
290 #       if !defined(SYNCTEX_USE_CHARINDEX)
291 #           define SYNCTEX_USE_CHARINDEX 1
292 #       endif
293 #   endif
294 SYNCTEX_INLINE static synctex_node_p _synctex_new_handle_with_target(synctex_node_p target);
295 #   if defined(SYNCTEX_USE_HANDLE)
296 #       define SYNCTEX_SCANNER_FREE_HANDLE(SCANR) \
297 __synctex_scanner_free_handle(SCANR)
298 #       define SYNCTEX_SCANNER_REMOVE_HANDLE_TO(WHAT) \
299 __synctex_scanner_remove_handle_to(WHAT)
300 #       define SYNCTEX_REGISTER_HANDLE_TO(NODE) \
301 __synctex_scanner_register_handle_to(NODE)
302 #   else
303 #       define SYNCTEX_SCANNER_FREE_HANDLE(SCANR)
304 #       define SYNCTEX_SCANNER_REMOVE_HANDLE_TO(WHAT)
305 #       define SYNCTEX_REGISTER_HANDLE_TO(NODE)
306 #   endif
307 
308 #   if defined(SYNCTEX_USE_CHARINDEX)
309 #       define SYNCTEX_CHARINDEX(NODE) (NODE->char_index)
310 #       define SYNCTEX_LINEINDEX(NODE) (NODE->line_index)
311 #       define SYNCTEX_PRINT_CHARINDEX_FMT "#%i"
312 #       define SYNCTEX_PRINT_CHARINDEX_WHAT ,SYNCTEX_CHARINDEX(node)
313 #       define SYNCTEX_PRINT_CHARINDEX \
314             printf(SYNCTEX_PRINT_CHARINDEX_FMT SYNCTEX_PRINT_CHARINDEX_WHAT)
315 #       define SYNCTEX_PRINT_LINEINDEX_FMT "L#%i"
316 #       define SYNCTEX_PRINT_LINEINDEX_WHAT ,SYNCTEX_LINEINDEX(node)
317 #       define SYNCTEX_PRINT_LINEINDEX \
318             printf(SYNCTEX_PRINT_LINEINDEX_FMT SYNCTEX_PRINT_LINEINDEX_WHAT)
319 #       define SYNCTEX_PRINT_CHARINDEX_NL \
320             printf(SYNCTEX_PRINT_CHARINDEX_FMT "\n" SYNCTEX_PRINT_CHARINDEX_WHAT)
321 #       define SYNCTEX_PRINT_LINEINDEX_NL \
322             printf(SYNCTEX_PRINT_CHARINDEX_FMT "\n"SYNCTEX_PRINT_LINEINDEX_WHAT)
323 #       define SYNCTEX_IMPLEMENT_CHARINDEX(NODE,CORRECTION)\
324             NODE->char_index = (synctex_charindex_t)(scanner->reader->charindex_offset+SYNCTEX_CUR-SYNCTEX_START+(CORRECTION)); \
325             NODE->line_index = scanner->reader->line_number;
326 #   else
327 #       define SYNCTEX_CHARINDEX(NODE) 0
328 #       define SYNCTEX_LINEINDEX(NODE) 0
329 #       define SYNCTEX_PRINT_CHARINDEX_FMT
330 #       define SYNCTEX_PRINT_CHARINDEX_WHAT
331 #       define SYNCTEX_PRINT_CHARINDEX
332 #       define SYNCTEX_PRINT_CHARINDEX
333 #       define SYNCTEX_PRINT_LINEINDEX_FMT
334 #       define SYNCTEX_PRINT_LINEINDEX_WHAT
335 #       define SYNCTEX_PRINT_LINEINDEX
336 #       define SYNCTEX_PRINT_CHARINDEX_NL printf("\n")
337 #       define SYNCTEX_PRINT_LINEINDEX_NL printf("\n")
338 #       define SYNCTEX_IMPLEMENT_CHARINDEX(NODE,CORRECTION)
339 #   endif
340 
341 /**
342  *  The next macros are used to access the node tree info
343  *  SYNCTEX_DATA(node) points to the first synctex integer or pointer data of node
344  *  SYNCTEX_DATA(node)[index] is the information at index
345  *  for example, the page of a sheet is stored in SYNCTEX_DATA(sheet)[_synctex_data_page_idx]
346  *  - parameter NODE: of type synctex_node_p
347  *  If the name starts with "__", the argument is nonullable
348  */
349 #	ifdef SYNCTEX_NOTHING
350 #       pragma mark -
351 #       pragma mark Tree SETGET
352 #   endif
353 
354 #if SYNCTEX_DEBUG > 1000
355 #define SYNCTEX_PARAMETER_ASSERT(WHAT) \
356     do { \
357         if (!(WHAT)) { \
358             printf("! Parameter failure: %s\n",#WHAT); \
359         } \
360     } while (synctex_NO)
361 #define DEFINE_SYNCTEX_TREE_HAS(WHAT)\
362 static synctex_bool_t _synctex_tree_has_##WHAT(synctex_node_p node) {\
363     if (node) {\
364         if (node->class_->navigator->WHAT>=0) {\
365             return  synctex_YES; \
366         } else {\
367             printf("WARNING: NO tree %s for %s\n", #WHAT, synctex_node_isa(node));\
368         }\
369     }\
370     return synctex_NO;\
371 }
372 #else
373 #define SYNCTEX_PARAMETER_ASSERT(WHAT)
374 #define DEFINE_SYNCTEX_TREE_HAS(WHAT) \
375 static synctex_bool_t _synctex_tree_has_##WHAT(synctex_node_p node) {\
376     return (node && (node->class_->navigator->WHAT>=0));\
377 }
378 #endif
379 
380 #   define DEFINE_SYNCTEX_TREE__GET(WHAT) \
381 SYNCTEX_INLINE static synctex_node_p __synctex_tree_##WHAT(synctex_non_null_node_p node) {\
382     return node->data[node->class_->navigator->WHAT].as_node;\
383 }
384 #   define DEFINE_SYNCTEX_TREE_GET(WHAT) \
385 DEFINE_SYNCTEX_TREE__GET(WHAT) \
386 static synctex_node_p _synctex_tree_##WHAT(synctex_node_p node) {\
387     if (_synctex_tree_has_##WHAT(node)) {\
388         return __synctex_tree_##WHAT(node);\
389     }\
390     return 0;\
391 }
392 #   define DEFINE_SYNCTEX_TREE__RESET(WHAT) \
393 SYNCTEX_INLINE static synctex_node_p __synctex_tree_reset_##WHAT(synctex_non_null_node_p node) {\
394     synctex_node_p old = node->data[node->class_->navigator->WHAT].as_node;\
395     node->data[node->class_->navigator->WHAT].as_node=NULL;\
396     return old;\
397 }
398 #   define DEFINE_SYNCTEX_TREE_RESET(WHAT) \
399 DEFINE_SYNCTEX_TREE__RESET(WHAT) \
400 SYNCTEX_INLINE static synctex_node_p _synctex_tree_reset_##WHAT(synctex_node_p node) {\
401         return _synctex_tree_has_##WHAT(node)? \
402             __synctex_tree_reset_##WHAT(node): NULL; \
403 }
404 #   define DEFINE_SYNCTEX_TREE__SET(WHAT) \
405 SYNCTEX_INLINE static synctex_node_p __synctex_tree_set_##WHAT(synctex_non_null_node_p node, synctex_node_p new_value) {\
406     synctex_node_p old = __synctex_tree_##WHAT(node);\
407     node->data[node->class_->navigator->WHAT].as_node=new_value;\
408     return old;\
409 }
410 #   define DEFINE_SYNCTEX_TREE_SET(WHAT) \
411 DEFINE_SYNCTEX_TREE__SET(WHAT) \
412 SYNCTEX_INLINE static synctex_node_p _synctex_tree_set_##WHAT(synctex_node_p node, synctex_node_p new_value) {\
413     return _synctex_tree_has_##WHAT(node)?\
414         __synctex_tree_set_##WHAT(node,new_value):NULL;\
415 }
416 #   define DEFINE_SYNCTEX_TREE__GETSETRESET(WHAT) \
417 DEFINE_SYNCTEX_TREE__GET(WHAT) \
418 DEFINE_SYNCTEX_TREE__SET(WHAT) \
419 DEFINE_SYNCTEX_TREE__RESET(WHAT)
420 
421 #   define DEFINE_SYNCTEX_TREE_GETSET(WHAT) \
422 DEFINE_SYNCTEX_TREE_HAS(WHAT) \
423 DEFINE_SYNCTEX_TREE_GET(WHAT) \
424 DEFINE_SYNCTEX_TREE_SET(WHAT)
425 
426 #   define DEFINE_SYNCTEX_TREE_GETRESET(WHAT) \
427 DEFINE_SYNCTEX_TREE_HAS(WHAT) \
428 DEFINE_SYNCTEX_TREE_GET(WHAT) \
429 DEFINE_SYNCTEX_TREE_RESET(WHAT)
430 
431 #   define DEFINE_SYNCTEX_TREE_GETSETRESET(WHAT) \
432 DEFINE_SYNCTEX_TREE_HAS(WHAT) \
433 DEFINE_SYNCTEX_TREE_GET(WHAT) \
434 DEFINE_SYNCTEX_TREE_SET(WHAT) \
435 DEFINE_SYNCTEX_TREE_RESET(WHAT)
436 
437 /*
438  *  _synctex_tree_set_... methods return the old value.
439  *  The return value of _synctex_tree_set_child and
440  *  _synctex_tree_set_sibling must be released somehown.
441  */
442 DEFINE_SYNCTEX_TREE__GETSETRESET(sibling)
443 DEFINE_SYNCTEX_TREE_GETSETRESET(parent)
444 DEFINE_SYNCTEX_TREE_GETSETRESET(child)
445 DEFINE_SYNCTEX_TREE_GETSETRESET(friend)
446 DEFINE_SYNCTEX_TREE_GETSET(last)
447 DEFINE_SYNCTEX_TREE_GETSET(next_hbox)
448 DEFINE_SYNCTEX_TREE_GETSET(arg_sibling)
449 DEFINE_SYNCTEX_TREE_GETSETRESET(target)
450 
451 #if SYNCTEX_DEBUG>1000
452 #   undef SYNCTEX_USE_NODE_COUNT
453 #   define SYNCTEX_USE_NODE_COUNT 1
454 #endif
455 #if SYNCTEX_USE_NODE_COUNT>0
456 #   define SYNCTEX_DECLARE_NODE_COUNT int node_count;
457 #   define SYNCTEX_INIT_NODE_COUNT \
458         do { node_count = 0; } while(synctex_NO)
459 #else
460 #   define SYNCTEX_DECLARE_NODE_COUNT
461 #   define SYNCTEX_INIT_NODE_COUNT
462 #endif
463 
464 #if SYNCTEX_USE_NODE_COUNT>10
465 #   define SYNCTEX_DID_NEW(N)   _synctex_did_new(N)
466 #   define SYNCTEX_WILL_FREE(N) _synctex_will_free(N)
467 #else
468 #   define SYNCTEX_DID_NEW(N)
469 #   define SYNCTEX_WILL_FREE(N)
470 #endif
471 
472 #define SYNCTEX_HAS_CHILDREN(NODE) (NODE && _synctex_tree_child(NODE))
473 #	ifdef	_X_SYNCTEX_WORK__
474 #		include "/usr/include/zlib.h"
475 #	else
476 #		include <zlib.h>
477 #	endif
478 
479 #	ifdef SYNCTEX_NOTHING
480 #       pragma mark -
481 #       pragma mark STATUS
482 #   endif
483 /*  When the end of the synctex file has been reached: */
484 #   define SYNCTEX_STATUS_EOF 0
485 /*  When the function could not return the value it was asked for: */
486 #   define SYNCTEX_STATUS_NOT_OK (SYNCTEX_STATUS_EOF+1)
487 /*  When the function returns the value it was asked for:
488  It must be the biggest one */
489 #   define SYNCTEX_STATUS_OK (SYNCTEX_STATUS_NOT_OK+1)
490 /*  Generic error: */
491 #   define SYNCTEX_STATUS_ERROR (SYNCTEX_STATUS_EOF-1)
492 /*  Parameter error: */
493 #   define SYNCTEX_STATUS_BAD_ARGUMENT (SYNCTEX_STATUS_ERROR-1)
494 
495 #	ifdef SYNCTEX_NOTHING
496 #       pragma mark -
497 #       pragma mark File reader
498 #   endif
499 
500 /*  We ensure that SYNCTEX_BUFFER_SIZE < UINT_MAX, I don't know if it makes sense... */
501 /*  Actually, the minimum buffer size is driven by integer and float parsing, including the unit.
502  *  ±0.123456789e123??
503  */
504 #   define SYNCTEX_BUFFER_MIN_SIZE 32
505 #   define SYNCTEX_BUFFER_SIZE 32768
506 
507 #if SYNCTEX_BUFFER_SIZE >= UINT_MAX
508 #   error BAD BUFFER SIZE(1)
509 #endif
510 #if SYNCTEX_BUFFER_SIZE < SYNCTEX_BUFFER_MIN_SIZE
511 #   error BAD BUFFER SIZE(2)
512 #endif
513 
514 typedef struct synctex_reader_t {
515     gzFile file;    /*  The (possibly compressed) file */
516     char * output;
517     char * synctex;
518     char * current; /*  current location in the buffer */
519     char * start;   /*  start of the buffer */
520     char * end;     /*  end of the buffer */
521     size_t min_size;
522     size_t size;
523     int lastv;
524     int line_number;
525     SYNCTEX_DECLARE_CHAR_OFFSET
526 } synctex_reader_s;
527 
528 typedef synctex_reader_s * synctex_reader_p;
529 
530 typedef struct {
531     synctex_status_t status;
532     char * synctex;
533     gzFile file;
534     synctex_io_mode_t io_mode;
535 } synctex_open_s;
536 
537 /*	This functions opens the file at the "output" given location.
538  *  It manages the problem of quoted filenames that appear with pdftex and filenames containing the space character.
539  *  In TeXLive 2008, the synctex file created with pdftex did contain unexpected quotes.
540  *	This function will remove them if possible.
541  *  All the reference arguments will take a value on return. They must be non NULL.
542  *	- returns: an open structure which status is
543  *      SYNCTEX_STATUS_OK on success,
544  *      SYNCTEX_STATUS_ERROR on failure.
545  *  - note: on success, the caller is the owner
546  *      of the fields of the returned open structure.
547  */
__synctex_open_v2(const char * output,synctex_io_mode_t io_mode,synctex_bool_t add_quotes)548 static synctex_open_s __synctex_open_v2(const char * output, synctex_io_mode_t io_mode, synctex_bool_t add_quotes) {
549     synctex_open_s open = {SYNCTEX_STATUS_ERROR, NULL, NULL, io_mode};
550     char * quoteless_synctex_name = NULL;
551     const char * mode = _synctex_get_io_mode_name(open.io_mode);
552     size_t size = strlen(output)+strlen(synctex_suffix)+strlen(synctex_suffix_gz)+1;
553     if (NULL == (open.synctex = (char *)malloc(size))) {
554         _synctex_error("!  __synctex_open_v2: Memory problem (1)\n");
555         return open;
556     }
557     /*  we have reserved for synctex enough memory to copy output (including its 2 eventual quotes), both suffices,
558      *  including the terminating character. size is free now. */
559     if (open.synctex != strcpy(open.synctex,output)) {
560         _synctex_error("!  __synctex_open_v2: Copy problem\n");
561     return_on_error:
562         free(open.synctex);
563         open.synctex = NULL;
564         free(quoteless_synctex_name);/* We MUST have quoteless_synctex_name<>synctex_name */
565         return open;
566     }
567     /*  remove the last path extension if any */
568     _synctex_strip_last_path_extension(open.synctex);
569     if (!strlen(open.synctex)) {
570         goto return_on_error;
571     }
572     /*  now insert quotes. */
573     if (add_quotes) {
574         char * quoted = NULL;
575         if (_synctex_copy_with_quoting_last_path_component(open.synctex,&quoted,size) || quoted == NULL) {
576             /*	There was an error or quoting does not make sense: */
577             goto return_on_error;
578         }
579         quoteless_synctex_name = open.synctex;
580         open.synctex = quoted;
581     }
582     /*	Now add to open.synctex the first path extension. */
583     if (open.synctex != strcat(open.synctex,synctex_suffix)){
584         _synctex_error("!  __synctex_open_v2: Concatenation problem (can't add suffix '%s')\n",synctex_suffix);
585         goto return_on_error;
586     }
587     /*	Add to quoteless_synctex_name as well, if relevant. */
588     if (quoteless_synctex_name && (quoteless_synctex_name != strcat(quoteless_synctex_name,synctex_suffix))){
589         free(quoteless_synctex_name);
590         quoteless_synctex_name = NULL;
591     }
592     if (NULL == (open.file = gzopen(open.synctex,mode))) {
593         /*  Could not open this file */
594         if (errno != ENOENT) {
595             /*  The file does exist, this is a lower level error, I can't do anything. */
596             _synctex_error("could not open %s, error %i\n",open.synctex,errno);
597             goto return_on_error;
598         }
599         /*  Apparently, there is no uncompressed synctex file. Try the compressed version */
600         if (open.synctex != strcat(open.synctex,synctex_suffix_gz)){
601             _synctex_error("!  __synctex_open_v2: Concatenation problem (can't add suffix '%s')\n",synctex_suffix_gz);
602             goto return_on_error;
603         }
604         open.io_mode |= synctex_io_gz_mask;
605         mode = _synctex_get_io_mode_name(open.io_mode); /* the file is a compressed and is a binary file, this caused errors on Windows */
606         /*	Add the suffix to the quoteless_synctex_name as well. */
607         if (quoteless_synctex_name && (quoteless_synctex_name != strcat(quoteless_synctex_name,synctex_suffix_gz))){
608             free(quoteless_synctex_name);
609             quoteless_synctex_name = NULL;
610         }
611         if (NULL == (open.file = gzopen(open.synctex,mode))) {
612             /*  Could not open this file */
613             if (errno != ENOENT) {
614                 /*  The file does exist, this is a lower level error, I can't do anything. */
615                 _synctex_error("Could not open %s, error %i\n",open.synctex,errno);
616             }
617             goto return_on_error;
618         }
619     }
620     /*	At this point, the file is properly open.
621      *  If we are in the add_quotes mode, we change the file name by removing the quotes. */
622     if (quoteless_synctex_name) {
623         gzclose(open.file);
624         if (rename(open.synctex,quoteless_synctex_name)) {
625             _synctex_error("Could not rename %s to %s, error %i\n",open.synctex,quoteless_synctex_name,errno);
626             /*	We could not rename, reopen the file with the quoted name. */
627             if (NULL == (open.file = gzopen(open.synctex,mode))) {
628                 /*  No luck, could not re open this file, something has happened meanwhile */
629                 if (errno != ENOENT) {
630                     /*  The file does not exist any more, it has certainly be removed somehow
631                      *  this is a lower level error, I can't do anything. */
632                     _synctex_error("Could not open again %s, error %i\n",open.synctex,errno);
633                 }
634                 goto return_on_error;
635             }
636         } else {
637             /*  The file has been successfully renamed */
638             if (NULL == (open.file = gzopen(quoteless_synctex_name,mode))) {
639                 /*  Could not open this file */
640                 if (errno != ENOENT) {
641                     /*  The file does exist, this is a lower level error, I can't do anything. */
642                     _synctex_error("Could not open renamed %s, error %i\n",quoteless_synctex_name,errno);
643                 }
644                 goto return_on_error;
645             }
646             /*  The quote free file name should replace the old one:*/
647             free(open.synctex);
648             open.synctex = quoteless_synctex_name;
649             quoteless_synctex_name = NULL;
650         }
651     }
652     /*  The operation is successfull, return the arguments by value.    */
653     open.status = SYNCTEX_STATUS_OK;
654     return open;
655 }
656 
657 /*	Opens the ouput file, taking into account the eventual build_directory.
658  *	- returns: an open structure which status is
659  *      SYNCTEX_STATUS_OK on success,
660  *      SYNCTEX_STATUS_ERROR on failure.
661  *  - note: on success, the caller is the owner
662  *      of the fields of the returned open structure.
663  */
_synctex_open_v2(const char * output,const char * build_directory,synctex_io_mode_t io_mode,synctex_bool_t add_quotes)664 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) {
665     synctex_open_s open = __synctex_open_v2(output,io_mode,add_quotes);
666     if (open.status == SYNCTEX_STATUS_OK) {
667         return open;
668     }
669     if (build_directory && strlen(build_directory)) {
670         char * build_output;
671         const char *lpc;
672         size_t size;
673         synctex_bool_t is_absolute;
674         build_output = NULL;
675         lpc = _synctex_last_path_component(output);
676         size = strlen(build_directory)+strlen(lpc)+2;   /*  One for the '/' and one for the '\0'.   */
677         is_absolute = _synctex_path_is_absolute(build_directory);
678         if (!is_absolute) {
679             size += strlen(output);
680         }
681         if ((build_output = (char *)_synctex_malloc(size))) {
682             if (is_absolute) {
683                 build_output[0] = '\0';
684             } else {
685                 if (build_output != strcpy(build_output,output)) {
686                     _synctex_free(build_output);
687                     return open;
688                 }
689                 build_output[lpc-output]='\0';
690             }
691             if (build_output == strcat(build_output,build_directory)) {
692                 /*	Append a path separator if necessary. */
693                 if (!SYNCTEX_IS_PATH_SEPARATOR(build_output[strlen(build_directory)-1])) {
694                     if (build_output != strcat(build_output,"/")) {
695                         _synctex_free(build_output);
696                         return open;
697                     }
698                 }
699                 /*	Append the last path component of the output. */
700                 if (build_output != strcat(build_output,lpc)) {
701                     _synctex_free(build_output);
702                     return open;
703                 }
704                 open = __synctex_open_v2(build_output,io_mode,add_quotes);
705             }
706             _synctex_free(build_output);
707         } /* if ((build_output... */
708     } /* if (build_directory...) */
709     return open;
710 }
synctex_reader_free(synctex_reader_p reader)711 void synctex_reader_free(synctex_reader_p reader) {
712     if (reader) {
713         _synctex_free(reader->output);
714         _synctex_free(reader->synctex);
715         _synctex_free(reader->start);
716         gzclose(reader->file);
717         _synctex_free(reader);
718     }
719 }
720 /*
721  *  Return reader on success.
722  *  Deallocate reader and return NULL on failure.
723  */
synctex_reader_init_with_output_file(synctex_reader_p reader,const char * output,const char * build_directory)724 synctex_reader_p synctex_reader_init_with_output_file(synctex_reader_p reader, const char * output, const char * build_directory) {
725     if (reader) {
726         /*  now open the synctex file */
727         synctex_open_s open = _synctex_open_v2(output,build_directory,0,synctex_ADD_QUOTES);
728         if (open.status<SYNCTEX_STATUS_OK) {
729             open = _synctex_open_v2(output,build_directory,0,synctex_DONT_ADD_QUOTES);
730             if (open.status<SYNCTEX_STATUS_OK) {
731                 return NULL;
732             }
733         }
734         reader->synctex = open.synctex;
735         reader->file = open.file;
736         /*  make a private copy of output */
737         if (NULL == (reader->output = (char *)_synctex_malloc(strlen(output)+1))){
738             _synctex_error("!  synctex_scanner_new_with_output_file: Memory problem (2), reader's output is not reliable.");
739         } else if (reader->output != strcpy(reader->output,output)) {
740             _synctex_free(reader->output);
741             reader->output = NULL;
742             _synctex_error("!  synctex_scanner_new_with_output_file: Copy problem, reader's output is not reliable.");
743         }
744         reader->start = reader->end = reader->current = NULL;
745         reader->min_size = SYNCTEX_BUFFER_MIN_SIZE;
746         reader->size = SYNCTEX_BUFFER_SIZE;
747         reader->start = reader->current =
748             (char *)_synctex_malloc(reader->size+1); /*  one more character for null termination */
749         if (NULL == reader->start) {
750             _synctex_error("!  malloc error in synctex_reader_init_with_output_file.");
751 #ifdef SYNCTEX_DEBUG
752             return reader;
753 #else
754             synctex_reader_free(reader);
755             return NULL;
756 #endif
757         }
758         reader->end = reader->start+reader->size;
759         /*  reader->end always points to a null terminating character.
760          *  Maybe there is another null terminating character between reader->current and reader->end-1.
761          *  At least, we are sure that reader->current points to a string covering a valid part of the memory. */
762 #   if defined(SYNCTEX_USE_CHARINDEX)
763         reader->charindex_offset = -reader->size;
764 #   endif
765     }
766     return reader;
767 }
768 
769 #   if defined(SYNCTEX_USE_HANDLE)
770 #       define SYNCTEX_DECLARE_HANDLE synctex_node_p handle;
771 #   else
772 #       define SYNCTEX_DECLARE_HANDLE
773 #   endif
774 
775 #   ifdef SYNCTEX_NOTHING
776 #       pragma mark -
777 #       pragma mark SCANNER
778 #   endif
779 /**
780  *  The synctex scanner is the root object.
781  *  Is is initialized with the contents of a text file or a gzipped file.
782  *  The buffer_.* are first used to parse the text.
783  */
784 struct synctex_scanner_t {
785     synctex_reader_p reader;
786     SYNCTEX_DECLARE_NODE_COUNT
787     SYNCTEX_DECLARE_HANDLE
788     char * output_fmt;          /*  dvi or pdf, not yet used */
789     synctex_iterator_p iterator;/*  result iterator */
790     int version;                /*  1, not yet used */
791     struct {
792         unsigned has_parsed:1;		/*  Whether the scanner has parsed its underlying synctex file. */
793         unsigned postamble:1;		/*  Whether the scanner has parsed its underlying synctex file. */
794         unsigned reserved:sizeof(unsigned)-2;	/*  alignment */
795     } flags;
796     int pre_magnification;  /*  magnification from the synctex preamble */
797     int pre_unit;           /*  unit from the synctex preamble */
798     int pre_x_offset;       /*  X offset from the synctex preamble */
799     int pre_y_offset;       /*  Y offset from the synctex preamble */
800     int count;              /*  Number of records, from the synctex postamble */
801     float unit;             /*  real unit, from synctex preamble or post scriptum */
802     float x_offset;         /*  X offset, from synctex preamble or post scriptum */
803     float y_offset;         /*  Y Offset, from synctex preamble or post scriptum */
804     synctex_node_p input;   /*  The first input node, its siblings are the other input nodes */
805     synctex_node_p sheet;   /*  The first sheet node, its siblings are the other sheet nodes */
806     synctex_node_p form;    /*  The first form, its siblings are the other forms */
807     synctex_node_p ref_in_sheet; /*  The first form ref node in sheet, its friends are the other form ref nodes */
808     synctex_node_p ref_in_form;  /*  The first form ref node, its friends are the other form ref nodes in sheet */
809     int number_of_lists;    /*  The number of friend lists */
810     synctex_node_r lists_of_friends;/*  The friend lists */
811     synctex_class_s class_[synctex_node_number_of_types]; /*  The classes of the nodes of the scanner */
812     int display_switcher;
813     char * display_prompt;
814 };
815 
816 /**
817  *  Create a new node of the given type.
818  *  - parameter scanner: of type synctex_node_p
819  *  - parameter type: a type, the client is responsible
820  *  to ask for an acceptable type.
821  */
synctex_node_new(synctex_scanner_p scanner,synctex_node_type_t type)822 synctex_node_p synctex_node_new(synctex_scanner_p scanner, synctex_node_type_t type) {
823     return scanner? scanner->class_[type].new(scanner):NULL;
824 }
825 #   if defined(SYNCTEX_USE_HANDLE)
__synctex_scanner_free_handle(synctex_scanner_p scanner)826 SYNCTEX_INLINE static void __synctex_scanner_free_handle(synctex_scanner_p scanner) {
827     synctex_node_free(scanner->handle);
828 }
__synctex_scanner_remove_handle_to(synctex_node_p node)829 SYNCTEX_INLINE static void __synctex_scanner_remove_handle_to(synctex_node_p node) {
830     synctex_node_p arg_sibling = NULL;
831     synctex_node_p handle = node->class_->scanner->handle;
832     while (handle) {
833         synctex_node_p sibling;
834         if (node == _synctex_tree_target(handle)) {
835             sibling = __synctex_tree_reset_sibling(handle);
836             if (arg_sibling) {
837                 __synctex_tree_set_sibling(arg_sibling, sibling);
838             } else {
839                 node->class_->scanner->handle = sibling;
840             }
841             synctex_node_free(handle);
842             break;
843         } else {
844             sibling = __synctex_tree_sibling(handle);
845         }
846         arg_sibling = handle;
847         handle = sibling;
848     }
849 }
__synctex_scanner_register_handle_to(synctex_node_p node)850 SYNCTEX_INLINE static void __synctex_scanner_register_handle_to(synctex_node_p  node) {
851     synctex_node_p NNN = _synctex_new_handle_with_target(node);
852     __synctex_tree_set_sibling(NNN,node->class_->scanner->handle);
853     node->class_->scanner->handle = NNN;
854 }
855 #endif
856 #if SYNCTEX_USE_NODE_COUNT>10
_synctex_did_new(synctex_node_p node)857 SYNCTEX_INLINE static void _synctex_did_new(synctex_node_p node) {
858     printf("NODE CREATED # %i, %s, %p\n",
859            (node->class_->scanner->node_count)++,
860            synctex_node_isa(node),
861            node);
862 }
_synctex_will_free(synctex_node_p node)863 SYNCTEX_INLINE static void _synctex_will_free(synctex_node_p node) {
864     printf("NODE DELETED # %i, %s, %p\n",
865            --(node->class_->scanner->node_count),
866            synctex_node_isa(node),
867            node);
868 }
869 #endif
870 
871 /**
872  *  Free the given node.
873  *  - parameter node: of type synctex_node_p
874  *  - note: a node is meant to own its child and sibling.
875  *  It is not owned by its parent, unless it is its first child.
876  *  This destructor is for all nodes with children.
877  */
_synctex_free_node(synctex_node_p node)878 static void _synctex_free_node(synctex_node_p node) {
879     if (node) {
880         SYNCTEX_SCANNER_REMOVE_HANDLE_TO(node);
881         SYNCTEX_WILL_FREE(node);
882         synctex_node_free(__synctex_tree_sibling(node));
883         synctex_node_free(_synctex_tree_child(node));
884         _synctex_free(node);
885     }
886     return;
887 }
888 /**
889  *  Free the given handle.
890  *  - parameter node: of type synctex_node_p
891  *  - note: a node is meant to own its child and sibling.
892  *  It is not owned by its parent, unless it is its first child.
893  *  This destructor is for all handles.
894  */
_synctex_free_handle(synctex_node_p handle)895 static void _synctex_free_handle(synctex_node_p handle) {
896     if (handle) {
897         synctex_node_p n = handle;
898         synctex_node_p nn;
899         __synctex_tree_set_parent(n, NULL);
900     down:
901         while ((nn = _synctex_tree_child(n))) {
902             n = nn;
903         };
904     right:
905         nn = __synctex_tree_sibling(n);
906         if (nn) {
907             _synctex_free(n);
908             n = nn;
909             goto down;
910         }
911         nn = __synctex_tree_parent(n);
912         _synctex_free(n);
913         if (nn) {
914             n = nn;
915             goto right;
916         }
917     }
918     return;
919 }
920 /**
921  *  Free the given leaf node.
922  *  - parameter node: of type synctex_node_p, with no child nor sibling.
923  *  - note: a node is meant to own its child and sibling.
924  *  It is not owned by its parent, unless it is its first child.
925  *  This destructor is for all nodes with no children.
926  */
_synctex_free_leaf(synctex_node_p node)927 static void _synctex_free_leaf(synctex_node_p node) {
928     if (node) {
929         SYNCTEX_SCANNER_REMOVE_HANDLE_TO(node);
930         SYNCTEX_WILL_FREE(node);
931         synctex_node_free(__synctex_tree_sibling(node));
932         _synctex_free(node);
933     }
934     return;
935 }
936 
937 /**
938  SYNCTEX_CUR, SYNCTEX_START and SYNCTEX_END are convenient shortcuts
939  */
940 #   define SYNCTEX_CUR (scanner->reader->current)
941 #   define SYNCTEX_START (scanner->reader->start)
942 #   define SYNCTEX_END (scanner->reader->end)
943 
944 /*  Here are gathered all the possible status that the next scanning functions will return.
945  *  All these functions return a status, and pass their result through pointers.
946  *  Negative values correspond to errors.
947  *  The management of the buffer is causing some significant overhead.
948  *  Every function that may access the buffer returns a status related to the buffer and file state.
949  *  status >= SYNCTEX_STATUS_OK means the function worked as expected
950  *  status < SYNCTEX_STATUS_OK means the function did not work as expected
951  *  status == SYNCTEX_STATUS_NOT_OK means the function did not work as expected but there is still some material to parse.
952  *  status == SYNCTEX_STATUS_EOF means the function did not work as expected and there is no more material.
953  *  status<SYNCTEX_STATUS_EOF means an error
954  */
955 #if defined(SYNCTEX_USE_CHARINDEX)
synctex_scanner_handle(synctex_scanner_p scanner)956 synctex_node_p synctex_scanner_handle(synctex_scanner_p scanner) {
957     return scanner? scanner->handle:NULL;
958 }
959 #endif
960 
961 #	ifdef SYNCTEX_NOTHING
962 #       pragma mark -
963 #       pragma mark Decoding prototypes
964 #   endif
965 
966 typedef struct {
967     int integer;
968     synctex_status_t status;
969 } synctex_is_s;
970 
971 static synctex_is_s _synctex_decode_int(synctex_scanner_p scanner);
972 static synctex_is_s _synctex_decode_int_opt(synctex_scanner_p scanner, int default_value);
973 static synctex_is_s _synctex_decode_int_v(synctex_scanner_p scanner);
974 
975 typedef struct {
976     char * string;
977     synctex_status_t status;
978 } synctex_ss_s;
979 
980 static synctex_ss_s _synctex_decode_string(synctex_scanner_p scanner);
981 
982 #	ifdef SYNCTEX_NOTHING
983 #       pragma mark -
984 #       pragma mark Data SETGET
985 #   endif
986 
987 /**
988  *  The next macros are used to access the node data info
989  *  through the class modelator integer fields.
990   *  - parameter NODE: of type synctex_node_p
991  */
992 #   define SYNCTEX_DATA(NODE) ((*((((NODE)->class_))->info))(NODE))
993 #if defined SYNCTEX_DEBUG > 1000
994 #   define DEFINE_SYNCTEX_DATA_HAS(WHAT) \
995 SYNCTEX_INLINE static synctex_bool_t __synctex_data_has_##WHAT(synctex_node_p node) {\
996     return (node && (node->class_->modelator->WHAT>=0));\
997 }\
998 SYNCTEX_INLINE static synctex_bool_t _synctex_data_has_##WHAT(synctex_node_p node) {\
999     if (node && (node->class_->modelator->WHAT<0)) {\
1000         printf("WARNING: NO %s for %s\n", #WHAT, synctex_node_isa(node));\
1001     }\
1002     return __synctex_data_has_##WHAT(node);\
1003 }
1004 #else
1005 #   define DEFINE_SYNCTEX_DATA_HAS(WHAT) \
1006 SYNCTEX_INLINE static synctex_bool_t __synctex_data_has_##WHAT(synctex_node_p node) {\
1007     return (node && (node->class_->modelator->WHAT>=0));\
1008 }\
1009 SYNCTEX_INLINE static synctex_bool_t _synctex_data_has_##WHAT(synctex_node_p node) {\
1010     return __synctex_data_has_##WHAT(node);\
1011 }
1012 #endif
1013 
__synctex_data(synctex_node_p node)1014 SYNCTEX_INLINE static synctex_data_p __synctex_data(synctex_node_p node) {
1015     return node->data+node->class_->navigator->size;
1016 }
1017 #   define DEFINE_SYNCTEX_DATA_INT_GETSET(WHAT) \
1018 DEFINE_SYNCTEX_DATA_HAS(WHAT)\
1019 static int _synctex_data_##WHAT(synctex_node_p node) {\
1020     if (_synctex_data_has_##WHAT(node)) {\
1021         return __synctex_data(node)[node->class_->modelator->WHAT].as_integer;\
1022     }\
1023     return 0;\
1024 }\
1025 static int _synctex_data_set_##WHAT(synctex_node_p node, int new_value) {\
1026     int old = 0;\
1027     if (_synctex_data_has_##WHAT(node)) {\
1028         old = __synctex_data(node)[node->class_->modelator->WHAT].as_integer;\
1029         __synctex_data(node)[node->class_->modelator->WHAT].as_integer=new_value;\
1030     }\
1031     return old;\
1032 }
1033 #define DEFINE_SYNCTEX_DATA_INT_DECODE(WHAT) \
1034 static synctex_status_t _synctex_data_decode_##WHAT(synctex_node_p node) {\
1035     if (_synctex_data_has_##WHAT(node)) {\
1036         synctex_is_s is = _synctex_decode_int(node->class_->scanner);\
1037         if (is.status == SYNCTEX_STATUS_OK) {\
1038             _synctex_data_set_##WHAT(node,is.integer);\
1039         } \
1040         return is.status;\
1041     }\
1042     return SYNCTEX_STATUS_BAD_ARGUMENT;\
1043 }
1044 #   define DEFINE_SYNCTEX_DATA_INT_DECODE_v(WHAT) \
1045 static synctex_status_t _synctex_data_decode_##WHAT##_v(synctex_node_p node) {\
1046     if (_synctex_data_has_##WHAT(node)) {\
1047         synctex_is_s is = _synctex_decode_int_v(node->class_->scanner);\
1048         if (is.status == SYNCTEX_STATUS_OK) {\
1049             _synctex_data_set_##WHAT(node,is.integer);\
1050         } \
1051         return is.status;\
1052     }\
1053     return SYNCTEX_STATUS_BAD_ARGUMENT;\
1054 }
1055 #define DEFINE_SYNCTEX_DATA_STR_GETSET(WHAT) \
1056 DEFINE_SYNCTEX_DATA_HAS(WHAT)\
1057 static char * _synctex_data_##WHAT(synctex_node_p node) {\
1058     if (_synctex_data_has_##WHAT(node)) {\
1059         return node->data[node->class_->navigator->size+node->class_->modelator->WHAT].as_string;\
1060     }\
1061     return NULL;\
1062 }\
1063 static char * _synctex_data_set_##WHAT(synctex_node_p node, char * new_value) {\
1064     char * old = "";\
1065     if (_synctex_data_has_##WHAT(node)) {\
1066         old = node->data[node->class_->navigator->size+node->class_->modelator->WHAT].as_string;\
1067         node->data[node->class_->navigator->size+node->class_->modelator->WHAT].as_string =new_value;\
1068     }\
1069     return old;\
1070 }
1071 #define DEFINE_SYNCTEX_DATA_STR_DECODE(WHAT) \
1072 static synctex_status_t _synctex_data_decode_##WHAT(synctex_node_p node) {\
1073     if (_synctex_data_has_##WHAT(node)) {\
1074         synctex_ss_s ss = _synctex_decode_string(node->class_->scanner);\
1075         if (ss.status == SYNCTEX_STATUS_OK) {\
1076             _synctex_data_set_##WHAT(node,ss.string);\
1077         } \
1078         return ss.status;\
1079     }\
1080     return SYNCTEX_STATUS_BAD_ARGUMENT;\
1081 }
1082 #define DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(WHAT) \
1083 DEFINE_SYNCTEX_DATA_INT_GETSET(WHAT) \
1084 DEFINE_SYNCTEX_DATA_INT_DECODE(WHAT)
1085 #define DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE_v(WHAT) \
1086 DEFINE_SYNCTEX_DATA_INT_GETSET(WHAT) \
1087 DEFINE_SYNCTEX_DATA_INT_DECODE_v(WHAT)
1088 #define DEFINE_SYNCTEX_DATA_STR_GETSET_DECODE(WHAT) \
1089 DEFINE_SYNCTEX_DATA_STR_GETSET(WHAT) \
1090 DEFINE_SYNCTEX_DATA_STR_DECODE(WHAT)
1091 
1092 #	ifdef SYNCTEX_NOTHING
1093 #       pragma mark -
1094 #       pragma mark OBJECTS, their creators and destructors.
1095 #   endif
1096 
1097 #	ifdef SYNCTEX_NOTHING
1098 #       pragma mark input.
1099 #   endif
1100 
1101 DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(tag)
1102 DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(line)
1103 DEFINE_SYNCTEX_DATA_STR_GETSET_DECODE(name)
1104 
1105 /*  Input nodes only know about their sibling, which is another input node.
1106  *  The synctex information is the _synctex_data_tag and _synctex_data_name
1107  *  note: the input owns its name. */
1108 
1109 #   define SYNCTEX_INPUT_MARK "Input:"
1110 
1111 static const synctex_tree_model_s synctex_tree_model_input = {
1112     synctex_tree_sibling_idx, /* sibling */
1113     -1, /* parent */
1114     -1, /* child */
1115     -1, /* friend */
1116     -1, /* last */
1117     -1, /* next_hbox */
1118     -1, /* arg_sibling */
1119     -1, /* target */
1120     synctex_tree_s_input_max
1121 };
1122 static const synctex_data_model_s synctex_data_model_input = {
1123     synctex_data_input_tag_idx, /* tag */
1124     synctex_data_input_line_idx,/* line */
1125     -1, /* column */
1126     -1, /* h */
1127     -1, /* v */
1128     -1, /* width */
1129     -1, /* height */
1130     -1, /* depth */
1131     -1, /* mean_line */
1132     -1, /* weight */
1133     -1, /* h_V */
1134     -1, /* v_V */
1135     -1, /* width_V */
1136     -1, /* height_V */
1137     -1, /* depth_V */
1138     synctex_data_input_name_idx, /* name */
1139     -1, /* page */
1140     synctex_data_input_tln_max
1141 };
1142 
1143 #define SYNCTEX_INSPECTOR_GETTER_F(WHAT)\
1144 &_synctex_data_##WHAT, &_synctex_data_set_##WHAT
1145 
1146 static synctex_node_p _synctex_new_input(synctex_scanner_p scanner);
1147 static void _synctex_free_input(synctex_node_p node);
1148 static void _synctex_log_input(synctex_node_p node);
1149 static char * _synctex_abstract_input(synctex_node_p node);
1150 static void _synctex_display_input(synctex_node_p node);
1151 
1152 static const synctex_tlcpector_s synctex_tlcpector_input = {
1153     &_synctex_data_tag, /* tag */
1154     &_synctex_int_none, /* line */
1155     &_synctex_int_none, /* column */
1156 };
1157 
1158 static synctex_class_s synctex_class_input = {
1159     NULL,                       /*  No scanner yet */
1160     synctex_node_type_input,    /*  Node type */
1161     &_synctex_new_input,        /*  creator */
1162     &_synctex_free_input,       /*  destructor */
1163     &_synctex_log_input,        /*  log */
1164     &_synctex_display_input,    /*  display */
1165     &_synctex_abstract_input,   /*  abstract */
1166     &synctex_tree_model_input,  /*  tree model */
1167     &synctex_data_model_input,  /*  data model */
1168     &synctex_tlcpector_input,   /*  inspector */
1169     &synctex_inspector_none,    /*  inspector */
1170     &synctex_vispector_none,    /*  vispector */
1171 };
1172 
1173 typedef struct {
1174     SYNCTEX_DECLARE_CHARINDEX
1175     synctex_class_p class_;
1176     synctex_data_u data[synctex_tree_s_input_max+synctex_data_input_tln_max];
1177 } synctex_input_s;
1178 
_synctex_new_input(synctex_scanner_p scanner)1179 static synctex_node_p _synctex_new_input(synctex_scanner_p scanner) {
1180     if (scanner) {
1181         synctex_node_p node = _synctex_malloc(sizeof(synctex_input_s));
1182         if (node) {
1183             node->class_ = scanner->class_+synctex_node_type_input;
1184             SYNCTEX_DID_NEW(node);
1185             SYNCTEX_IMPLEMENT_CHARINDEX(node,0);
1186             SYNCTEX_REGISTER_HANDLE_TO(node);
1187         }
1188         return node;
1189     }
1190     return NULL;
1191 }
1192 
_synctex_free_input(synctex_node_p node)1193 static void _synctex_free_input(synctex_node_p node){
1194     if (node) {
1195         SYNCTEX_SCANNER_REMOVE_HANDLE_TO(node);
1196         SYNCTEX_WILL_FREE(node);
1197         synctex_node_free(__synctex_tree_sibling(node));
1198         _synctex_free(_synctex_data_name(node));
1199         _synctex_free(node);
1200     }
1201 }
1202 
1203 /*  The sheet is a first level node.
1204  *  It has no parent (the owner is the scanner itself)
1205  *  Its sibling points to another sheet.
1206  *  Its child points to its first child, in general a box.
1207  *  A sheet node contains only one synctex information: the page.
1208  *  This is the 1 based page index as given by TeX.
1209  */
1210 
1211 #	ifdef SYNCTEX_NOTHING
1212 #       pragma mark sheet.
1213 #   endif
1214 /**
1215  *  Every node has the same structure, but not the same size.
1216  */
1217 
1218 DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(page)
1219 
1220 typedef struct {
1221     SYNCTEX_DECLARE_CHARINDEX
1222     synctex_class_p class_;
1223     synctex_data_u data[synctex_tree_scn_sheet_max+synctex_data_p_sheet_max];
1224 } synctex_node_sheet_s;
1225 
1226 /*  sheet node creator */
1227 
1228 #define DEFINE_synctex_new_scanned_NODE(NAME)\
1229 static synctex_node_p _synctex_new_##NAME(synctex_scanner_p scanner) {\
1230     if (scanner) {\
1231         ++SYNCTEX_CUR;\
1232         synctex_node_p node = _synctex_malloc(sizeof(synctex_node_##NAME##_s));\
1233         if (node) {\
1234             node->class_ = scanner->class_+synctex_node_type_##NAME;\
1235             SYNCTEX_DID_NEW(node); \
1236             SYNCTEX_IMPLEMENT_CHARINDEX(node,-1);\
1237             SYNCTEX_REGISTER_HANDLE_TO(node); \
1238         }\
1239         return node;\
1240     }\
1241     return NULL;\
1242 }
1243 /*  NB: -1 in SYNCTEX_IMPLEMENT_CHARINDEX above because
1244  *  the first char of the line has been scanned
1245  */
1246 DEFINE_synctex_new_scanned_NODE(sheet)
1247 static void _synctex_log_sheet(synctex_node_p node);
1248 static char * _synctex_abstract_sheet(synctex_node_p node);
1249 static void _synctex_display_sheet(synctex_node_p node);
1250 
1251 static const synctex_tree_model_s synctex_tree_model_sheet = {
1252     synctex_tree_sibling_idx, /* sibling */
1253     -1, /* parent */
1254     synctex_tree_s_child_idx, /* child */
1255     -1, /* friend */
1256     -1, /* last */
1257     synctex_tree_sc_next_hbox_idx, /* next_hbox */
1258     -1, /* arg_sibling */
1259     -1, /* target */
1260     synctex_tree_scn_sheet_max
1261 };
1262 static const synctex_data_model_s synctex_data_model_sheet = {
1263     -1, /* tag */
1264     -1, /* line */
1265     -1, /* column */
1266     -1, /* h */
1267     -1, /* v */
1268     -1, /* width */
1269     -1, /* height */
1270     -1, /* depth */
1271     -1, /* mean_line */
1272     -1, /* weight */
1273     -1, /* h_V */
1274     -1, /* v_V */
1275     -1, /* width_V */
1276     -1, /* height_V */
1277     -1, /* depth_V */
1278     -1, /* name */
1279     synctex_data_sheet_page_idx, /* page */
1280     synctex_data_p_sheet_max
1281 };
1282 static synctex_class_s synctex_class_sheet = {
1283     NULL,                       /*  No scanner yet */
1284     synctex_node_type_sheet,    /*  Node type */
1285     &_synctex_new_sheet,        /*  creator */
1286     &_synctex_free_node,        /*  destructor */
1287     &_synctex_log_sheet,        /*  log */
1288     &_synctex_display_sheet,    /*  display */
1289     &_synctex_abstract_sheet,   /*  abstract */
1290     &synctex_tree_model_sheet,  /*  tree model */
1291     &synctex_data_model_sheet,  /*  data model */
1292     &synctex_tlcpector_none,    /*  tlcpector */
1293     &synctex_inspector_none,    /*  inspector */
1294     &synctex_vispector_none,    /*  vispector */
1295 };
1296 
1297 #	ifdef SYNCTEX_NOTHING
1298 #       pragma mark form.
1299 #   endif
1300 /**
1301  *  Every node has the same structure, but not the same size.
1302  */
1303 typedef struct {
1304     SYNCTEX_DECLARE_CHARINDEX
1305     synctex_class_p class_;
1306     synctex_data_u data[synctex_tree_sct_form_max+synctex_data_t_form_max];
1307 } synctex_node_form_s;
1308 
1309 DEFINE_synctex_new_scanned_NODE(form)
1310 
1311 static char * _synctex_abstract_form(synctex_node_p node);
1312 static void _synctex_display_form(synctex_node_p node);
1313 static void _synctex_log_form(synctex_node_p node);
1314 
1315 static const synctex_tree_model_s synctex_tree_model_form = {
1316     synctex_tree_sibling_idx, /* sibling */
1317     -1, /* parent */
1318     synctex_tree_s_child_idx, /* child */
1319     -1, /* friend */
1320     -1, /* last */
1321     -1, /* next_hbox */
1322     -1, /* arg_sibling */
1323     synctex_tree_sc_target_idx, /* target */
1324     synctex_tree_sct_form_max
1325 };
1326 static const synctex_data_model_s synctex_data_model_form = {
1327     synctex_data_form_tag_idx, /* tag */
1328     -1, /* line */
1329     -1, /* column */
1330     -1, /* h */
1331     -1, /* v */
1332     -1, /* width */
1333     -1, /* height */
1334     -1, /* depth */
1335     -1, /* mean_line */
1336     -1, /* weight */
1337     -1, /* h_V */
1338     -1, /* v_V */
1339     -1, /* width_V */
1340     -1, /* height_V */
1341     -1, /* depth_V */
1342     -1, /* name */
1343     -1, /* page */
1344     synctex_data_t_form_max
1345 };
1346 static synctex_class_s synctex_class_form = {
1347     NULL,                       /*  No scanner yet */
1348     synctex_node_type_form,     /*  Node type */
1349     &_synctex_new_form,         /*  creator */
1350     &_synctex_free_node,        /*  destructor */
1351     &_synctex_log_form,         /*  log */
1352     &_synctex_display_form,     /*  display */
1353     &_synctex_abstract_form,    /*  abstract */
1354     &synctex_tree_model_form,   /*  tree model */
1355     &synctex_data_model_form,   /*  data model */
1356     &synctex_tlcpector_none,    /*  tlcpector */
1357     &synctex_inspector_none,    /*  inspector */
1358     &synctex_vispector_none,    /*  vispector */
1359 };
1360 
1361 #	ifdef SYNCTEX_NOTHING
1362 #       pragma mark vbox.
1363 #   endif
1364 
1365 /*  A box node contains navigation and synctex information
1366  *  There are different kinds of boxes.
1367  *  Only horizontal boxes are treated differently because of their visible size.
1368  */
1369 typedef struct {
1370     SYNCTEX_DECLARE_CHARINDEX
1371     synctex_class_p class_;
1372     synctex_data_u data[synctex_tree_spcfl_vbox_max+synctex_data_box_max];
1373 } synctex_node_vbox_s;
1374 
1375 /*  vertical box node creator */
1376 DEFINE_synctex_new_scanned_NODE(vbox)
1377 
1378 static char * _synctex_abstract_vbox(synctex_node_p node);
1379 static void _synctex_display_vbox(synctex_node_p node);
1380 static void _synctex_log_vbox(synctex_node_p node);
1381 
1382 static const synctex_tree_model_s synctex_tree_model_vbox = {
1383     synctex_tree_sibling_idx,       /* sibling */
1384     synctex_tree_s_parent_idx,      /* parent */
1385     synctex_tree_sp_child_idx,      /* child */
1386     synctex_tree_spc_friend_idx,    /* friend */
1387     synctex_tree_spcf_last_idx,     /* last */
1388     -1, /* next_hbox */
1389     -1, /* arg_sibling */
1390     -1, /* target */
1391     synctex_tree_spcfl_vbox_max
1392 };
1393 
1394 #define SYNCTEX_DFLT_COLUMN -1
1395 
DEFINE_SYNCTEX_DATA_INT_GETSET(column)1396 DEFINE_SYNCTEX_DATA_INT_GETSET(column)
1397 static synctex_status_t _synctex_data_decode_column(synctex_node_p node) {
1398     if (_synctex_data_has_column(node)) {
1399         synctex_is_s is = _synctex_decode_int_opt(node->class_->scanner,
1400             SYNCTEX_DFLT_COLUMN);
1401         if (is.status == SYNCTEX_STATUS_OK) {
1402             _synctex_data_set_column(node,is.integer);
1403         }
1404         return is.status;
1405     }
1406     return SYNCTEX_STATUS_BAD_ARGUMENT;
1407 }
1408 DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(h)
DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE_v(v)1409 DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE_v(v)
1410 DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(width)
1411 DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(height)
1412 DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(depth)
1413 
1414 SYNCTEX_INLINE static void _synctex_data_set_tlc(synctex_node_p node, synctex_node_p model) {
1415     _synctex_data_set_tag(node, _synctex_data_tag(model));
1416     _synctex_data_set_line(node, _synctex_data_line(model));
1417     _synctex_data_set_column(node, _synctex_data_column(model));
1418 }
_synctex_data_set_tlchv(synctex_node_p node,synctex_node_p model)1419 SYNCTEX_INLINE static void _synctex_data_set_tlchv(synctex_node_p node, synctex_node_p model) {
1420     _synctex_data_set_tlc(node,model);
1421     _synctex_data_set_h(node, _synctex_data_h(model));
1422     _synctex_data_set_v(node, _synctex_data_v(model));
1423 }
1424 
1425 static const synctex_data_model_s synctex_data_model_box = {
1426     synctex_data_tag_idx, /* tag */
1427     synctex_data_line_idx,  /* line */
1428     synctex_data_column_idx,/* column */
1429     synctex_data_h_idx,     /* h */
1430     synctex_data_v_idx,     /* v */
1431     synctex_data_width_idx, /* width */
1432     synctex_data_height_idx,/* height */
1433     synctex_data_depth_idx, /* depth */
1434     -1, /* mean_line */
1435     -1, /* weight */
1436     -1, /* h_V */
1437     -1, /* v_V */
1438     -1, /* width_V */
1439     -1, /* height_V */
1440     -1, /* depth_V */
1441     -1, /* name */
1442     -1, /* page */
1443     synctex_data_box_max
1444 };
1445 static const synctex_tlcpector_s synctex_tlcpector_default = {
1446     &_synctex_data_tag, /* tag */
1447     &_synctex_data_line, /* line */
1448     &_synctex_data_column, /* column */
1449 };
1450 static const synctex_inspector_s synctex_inspector_box = {
1451     &_synctex_data_h,
1452     &_synctex_data_v,
1453     &_synctex_data_width,
1454     &_synctex_data_height,
1455     &_synctex_data_depth,
1456 };
1457 static float __synctex_node_visible_h(synctex_node_p node);
1458 static float __synctex_node_visible_v(synctex_node_p node);
1459 static float __synctex_node_visible_width(synctex_node_p node);
1460 static float __synctex_node_visible_height(synctex_node_p node);
1461 static float __synctex_node_visible_depth(synctex_node_p node);
1462 static synctex_vispector_s synctex_vispector_box = {
1463     &__synctex_node_visible_h,
1464     &__synctex_node_visible_v,
1465     &__synctex_node_visible_width,
1466     &__synctex_node_visible_height,
1467     &__synctex_node_visible_depth,
1468 };
1469 /*  These are static class objects, each scanner will make a copy of them and setup the scanner field.
1470  */
1471 static synctex_class_s synctex_class_vbox = {
1472     NULL,                       /*  No scanner yet */
1473     synctex_node_type_vbox,     /*  Node type */
1474     &_synctex_new_vbox,         /*  creator */
1475     &_synctex_free_node,        /*  destructor */
1476     &_synctex_log_vbox,         /*  log */
1477     &_synctex_display_vbox,     /*  display */
1478     &_synctex_abstract_vbox,    /*  abstract */
1479     &synctex_tree_model_vbox,   /*  tree model */
1480     &synctex_data_model_box,    /*  data model */
1481     &synctex_tlcpector_default, /*  tlcpector */
1482     &synctex_inspector_box,     /*  inspector */
1483     &synctex_vispector_box,     /*  vispector */
1484 };
1485 
1486 #	ifdef SYNCTEX_NOTHING
1487 #       pragma mark hbox.
1488 #   endif
1489 
1490 /*  Horizontal boxes must contain visible size, because 0 width does not mean emptiness.
1491  *  They also contain an average of the line numbers of the containing nodes. */
1492 
1493 static const synctex_tree_model_s synctex_tree_model_hbox = {
1494     synctex_tree_sibling_idx,       /* sibling */
1495     synctex_tree_s_parent_idx,      /* parent */
1496     synctex_tree_sp_child_idx,      /* child */
1497     synctex_tree_spc_friend_idx,    /* friend */
1498     synctex_tree_spcf_last_idx,     /* last */
1499     synctex_tree_spcfl_next_hbox_idx, /* next_hbox */
1500     -1, /* arg_sibling */
1501     -1, /* target */
1502     synctex_tree_spcfln_hbox_max
1503 };
1504 
1505 DEFINE_SYNCTEX_DATA_INT_GETSET(mean_line)
1506 DEFINE_SYNCTEX_DATA_INT_GETSET(weight)
1507 DEFINE_SYNCTEX_DATA_INT_GETSET(h_V)
1508 DEFINE_SYNCTEX_DATA_INT_GETSET(v_V)
1509 DEFINE_SYNCTEX_DATA_INT_GETSET(width_V)
1510 DEFINE_SYNCTEX_DATA_INT_GETSET(height_V)
1511 DEFINE_SYNCTEX_DATA_INT_GETSET(depth_V)
1512 
1513 /**
1514  *  The hbox model.
1515  *  It contains V variants of geometrical information.
1516  *  It happens that hboxes contain material that is not used to compute
1517  *  the bounding box. Some letters may appear out of the box given by TeX.
1518  *  In such a situation, the visible bouding box is bigger ence the V variant.
1519  *  Only hboxes have such variant. It does not make sense for void boxes
1520  *  and it is not used here for vboxes.
1521  *  - author: JL
1522  */
1523 
1524 static const synctex_data_model_s synctex_data_model_hbox = {
1525     synctex_data_tag_idx, /* tag */
1526     synctex_data_line_idx,  /* line */
1527     synctex_data_column_idx,/* column */
1528     synctex_data_h_idx,     /* h */
1529     synctex_data_v_idx,     /* v */
1530     synctex_data_width_idx, /* width */
1531     synctex_data_height_idx,/* height */
1532     synctex_data_depth_idx, /* depth */
1533     synctex_data_mean_line_idx, /* mean_line */
1534     synctex_data_weight_idx, /* weight */
1535     synctex_data_h_V_idx, /* h_V */
1536     synctex_data_v_V_idx, /* v_V */
1537     synctex_data_width_V_idx, /* width_V */
1538     synctex_data_height_V_idx, /* height_V */
1539     synctex_data_depth_V_idx, /* depth_V */
1540     -1, /* name */
1541     -1, /* page */
1542     synctex_data_hbox_max
1543 };
1544 
1545 typedef struct {
1546     SYNCTEX_DECLARE_CHARINDEX
1547     synctex_class_p class_;
1548     synctex_data_u data[synctex_tree_spcfln_hbox_max+synctex_data_hbox_max];
1549 } synctex_node_hbox_s;
1550 
1551 /*  horizontal box node creator */
1552 DEFINE_synctex_new_scanned_NODE(hbox)
1553 
1554 static void _synctex_log_hbox(synctex_node_p node);
1555 static char * _synctex_abstract_hbox(synctex_node_p node);
1556 static void _synctex_display_hbox(synctex_node_p node);
1557 
1558 static synctex_class_s synctex_class_hbox = {
1559     NULL,                       /*  No scanner yet */
1560     synctex_node_type_hbox,     /*  Node type */
1561     &_synctex_new_hbox,         /*  creator */
1562     &_synctex_free_node,        /*  destructor */
1563     &_synctex_log_hbox,         /*  log */
1564     &_synctex_display_hbox,     /*  display */
1565     &_synctex_abstract_hbox,    /*  abstract */
1566     &synctex_tree_model_hbox,   /*  tree model */
1567     &synctex_data_model_hbox,   /*  data model */
1568     &synctex_tlcpector_default, /*  tlcpector */
1569     &synctex_inspector_box,     /*  inspector */
1570     &synctex_vispector_box,     /*  vispector */
1571 };
1572 
1573 #	ifdef SYNCTEX_NOTHING
1574 #       pragma mark void vbox.
1575 #   endif
1576 
1577 /*  This void box node implementation is either horizontal or vertical
1578  *  It does not contain a child field.
1579  */
1580 static const synctex_tree_model_s synctex_tree_model_spf = {
1581     synctex_tree_sibling_idx,   /* sibling */
1582     synctex_tree_s_parent_idx,  /* parent */
1583     -1, /* child */
1584     synctex_tree_sp_friend_idx, /* friend */
1585     -1, /* last */
1586     -1, /* next_hbox */
1587     -1, /* arg_sibling */
1588     -1, /* target */
1589     synctex_tree_spf_max
1590 };
1591 typedef struct {
1592     SYNCTEX_DECLARE_CHARINDEX
1593     synctex_class_p class_;
1594     synctex_data_u data[synctex_tree_spf_max+synctex_data_box_max];
1595 } synctex_node_void_vbox_s;
1596 
1597 /*  vertical void box node creator */
1598 DEFINE_synctex_new_scanned_NODE(void_vbox)
1599 
1600 static void _synctex_log_void_box(synctex_node_p node);
1601 static char * _synctex_abstract_void_vbox(synctex_node_p node);
1602 static void _synctex_display_void_vbox(synctex_node_p node);
1603 
1604 static synctex_class_s synctex_class_void_vbox = {
1605     NULL,                       /*  No scanner yet */
1606     synctex_node_type_void_vbox,/*  Node type */
1607     &_synctex_new_void_vbox,    /*  creator */
1608     &_synctex_free_leaf,        /*  destructor */
1609     &_synctex_log_void_box,     /*  log */
1610     &_synctex_display_void_vbox,/*  display */
1611     &_synctex_abstract_void_vbox,/*  abstract */
1612     &synctex_tree_model_spf,    /*  tree model */
1613     &synctex_data_model_box,    /*  data model */
1614     &synctex_tlcpector_default, /*  tlcpector */
1615     &synctex_inspector_box,     /*  inspector */
1616     &synctex_vispector_box,     /*  vispector */
1617 };
1618 
1619 #	ifdef SYNCTEX_NOTHING
1620 #       pragma mark void hbox.
1621 #   endif
1622 
1623 typedef synctex_node_void_vbox_s synctex_node_void_hbox_s;
1624 
1625 /*  horizontal void box node creator */
1626 DEFINE_synctex_new_scanned_NODE(void_hbox)
1627 
1628 static char * _synctex_abstract_void_hbox(synctex_node_p node);
1629 static void _synctex_display_void_hbox(synctex_node_p node);
1630 
1631 static synctex_class_s synctex_class_void_hbox = {
1632     NULL,                       /*  No scanner yet */
1633     synctex_node_type_void_hbox,/*  Node type */
1634     &_synctex_new_void_hbox,    /*  creator */
1635     &_synctex_free_leaf,        /*  destructor */
1636     &_synctex_log_void_box,     /*  log */
1637     &_synctex_display_void_hbox,/*  display */
1638     &_synctex_abstract_void_hbox,/*  abstract */
1639     &synctex_tree_model_spf,    /*  tree model */
1640     &synctex_data_model_box,    /*  data model */
1641     &synctex_tlcpector_default, /*  tlcpector */
1642     &synctex_inspector_box,     /*  inspector */
1643     &synctex_vispector_box,     /*  vispector */
1644 };
1645 
1646 #	ifdef SYNCTEX_NOTHING
1647 #       pragma mark form ref.
1648 #   endif
1649 
1650 /*  The form ref node.  */
1651 typedef struct {
1652     SYNCTEX_DECLARE_CHARINDEX
1653     synctex_class_p class_;
1654     synctex_data_u data[synctex_tree_spfa_max+synctex_data_ref_thv_max];
1655 } synctex_node_ref_s;
1656 
1657 /*  form ref node creator */
1658 DEFINE_synctex_new_scanned_NODE(ref)
1659 
1660 static void _synctex_log_ref(synctex_node_p node);
1661 static char * _synctex_abstract_ref(synctex_node_p node);
1662 static void _synctex_display_ref(synctex_node_p node);
1663 
1664 static const synctex_tree_model_s synctex_tree_model_spfa = {
1665     synctex_tree_sibling_idx,   /* sibling */
1666     synctex_tree_s_parent_idx,  /* parent */
1667     -1, /* child */
1668     synctex_tree_sp_friend_idx, /* friend */
1669     -1, /* last */
1670     -1, /* next_hbox */
1671     synctex_tree_spf_arg_sibling_idx, /* arg_sibling */
1672     -1, /* target */
1673     synctex_tree_spfa_max
1674 };
1675 static const synctex_data_model_s synctex_data_model_ref = {
1676     synctex_data_tag_idx, /* tag */
1677     -1, /* line */
1678     -1, /* column */
1679     synctex_data_ref_h_idx, /* h */
1680     synctex_data_ref_v_idx, /* v */
1681     -1, /* width */
1682     -1, /* height */
1683     -1, /* depth */
1684     -1, /* mean_line */
1685     -1, /* weight */
1686     -1, /* h_V */
1687     -1, /* v_V */
1688     -1, /* width_V */
1689     -1, /* height_V */
1690     -1, /* depth_V */
1691     -1, /* name */
1692     -1, /* page */
1693     synctex_data_ref_thv_max /* size */
1694 };
1695 static synctex_class_s synctex_class_ref = {
1696     NULL,                       /*  No scanner yet */
1697     synctex_node_type_ref,      /*  Node type */
1698     &_synctex_new_ref,          /*  creator */
1699     &_synctex_free_leaf,        /*  destructor */
1700     &_synctex_log_ref,          /*  log */
1701     &_synctex_display_ref,      /*  display */
1702     &_synctex_abstract_ref,     /*  abstract */
1703     &synctex_tree_model_spfa,   /*  navigator */
1704     &synctex_data_model_ref,    /*  data model */
1705     &synctex_tlcpector_none,    /*  tlcpector */
1706     &synctex_inspector_none,    /*  inspector */
1707     &synctex_vispector_none,    /*  vispector */
1708 };
1709 #	ifdef SYNCTEX_NOTHING
1710 #       pragma mark small node.
1711 #   endif
1712 
1713 /*  The small nodes correspond to glue, penalty, math and boundary nodes. */
1714 static const synctex_data_model_s synctex_data_model_tlchv = {
1715     synctex_data_tag_idx, /* tag */
1716     synctex_data_line_idx, /* line */
1717     synctex_data_column_idx, /* column */
1718     synctex_data_h_idx, /* h */
1719     synctex_data_v_idx, /* v */
1720     -1, /* width */
1721     -1, /* height */
1722     -1, /* depth */
1723     -1, /* mean_line */
1724     -1, /* weight */
1725     -1, /* h_V */
1726     -1, /* v_V */
1727     -1, /* width_V */
1728     -1, /* height_V */
1729     -1, /* depth_V */
1730     -1, /* name */
1731     -1, /* page */
1732     synctex_data_tlchv_max
1733 };
1734 
1735 typedef struct {
1736     SYNCTEX_DECLARE_CHARINDEX
1737     synctex_class_p class_;
1738     synctex_data_u data[synctex_tree_spf_max+synctex_data_tlchv_max];
1739 } synctex_node_tlchv_s;
1740 
1741 static void _synctex_log_tlchv_node(synctex_node_p node);
1742 
1743 #	ifdef SYNCTEX_NOTHING
1744 #       pragma mark math.
1745 #   endif
1746 
1747 typedef synctex_node_tlchv_s synctex_node_math_s;
1748 
1749 /*  math node creator */
1750 DEFINE_synctex_new_scanned_NODE(math)
1751 
1752 static char * _synctex_abstract_math(synctex_node_p node);
1753 static void _synctex_display_math(synctex_node_p node);
1754 static synctex_inspector_s synctex_inspector_hv = {
1755     &_synctex_data_h,
1756     &_synctex_data_v,
1757     &_synctex_int_none,
1758     &_synctex_int_none,
1759     &_synctex_int_none,
1760 };
1761 static synctex_vispector_s synctex_vispector_hv = {
1762     &__synctex_node_visible_h,
1763     &__synctex_node_visible_v,
1764     &_synctex_float_none,
1765     &_synctex_float_none,
1766     &_synctex_float_none,
1767 };
1768 
1769 static synctex_class_s synctex_class_math = {
1770     NULL,                       /*  No scanner yet */
1771     synctex_node_type_math,     /*  Node type */
1772     &_synctex_new_math,         /*  creator */
1773     &_synctex_free_leaf,        /*  destructor */
1774     &_synctex_log_tlchv_node,   /*  log */
1775     &_synctex_display_math,     /*  display */
1776     &_synctex_abstract_math,    /*  abstract */
1777     &synctex_tree_model_spf,    /*  tree model */
1778     &synctex_data_model_tlchv,  /*  data model */
1779     &synctex_tlcpector_default, /*  tlcpector */
1780     &synctex_inspector_hv,      /*  inspector */
1781     &synctex_vispector_hv,      /*  vispector */
1782 };
1783 
1784 #	ifdef SYNCTEX_NOTHING
1785 #       pragma mark kern node.
1786 #   endif
1787 
1788 static const synctex_data_model_s synctex_data_model_tlchvw = {
1789     synctex_data_tag_idx,   /* tag */
1790     synctex_data_line_idx,  /* line */
1791     synctex_data_column_idx,/* column */
1792     synctex_data_h_idx,     /* h */
1793     synctex_data_v_idx,     /* v */
1794     synctex_data_width_idx, /* width */
1795     -1, /* height */
1796     -1, /* depth */
1797     -1, /* mean_line */
1798     -1, /* weight */
1799     -1, /* h_V */
1800     -1, /* v_V */
1801     -1, /* width_V */
1802     -1, /* height_V */
1803     -1, /* depth_V */
1804     -1, /* name */
1805     -1, /* page */
1806     synctex_data_tlchvw_max
1807 };
1808 typedef struct {
1809     SYNCTEX_DECLARE_CHARINDEX
1810     synctex_class_p class_;
1811     synctex_data_u data[synctex_tree_spf_max+synctex_data_tlchvw_max];
1812 } synctex_node_kern_s;
1813 
1814 /*  kern node creator */
1815 DEFINE_synctex_new_scanned_NODE(kern)
1816 
1817 static void _synctex_log_kern_node(synctex_node_p node);
1818 static char * _synctex_abstract_kern(synctex_node_p node);
1819 static void _synctex_display_kern(synctex_node_p node);
1820 
1821 static synctex_inspector_s synctex_inspector_kern = {
1822     &_synctex_data_h,
1823     &_synctex_data_v,
1824     &_synctex_data_width,
1825     &_synctex_int_none,
1826     &_synctex_int_none,
1827 };
1828 static float __synctex_kern_visible_h(synctex_node_p node);
1829 static float __synctex_kern_visible_width(synctex_node_p node);
1830 static synctex_vispector_s synctex_vispector_kern = {
1831     &__synctex_kern_visible_h,
1832     &__synctex_node_visible_v,
1833     &__synctex_kern_visible_width,
1834     &_synctex_float_none,
1835     &_synctex_float_none,
1836 };
1837 
1838 static synctex_class_s synctex_class_kern = {
1839     NULL,                       /*  No scanner yet */
1840     synctex_node_type_kern,     /*  Node type */
1841     &_synctex_new_kern,         /*  creator */
1842     &_synctex_free_leaf,        /*  destructor */
1843     &_synctex_log_kern_node,    /*  log */
1844     &_synctex_display_kern,     /*  display */
1845     &_synctex_abstract_kern,    /*  abstract */
1846     &synctex_tree_model_spf,    /*  tree model */
1847     &synctex_data_model_tlchvw, /*  data model */
1848     &synctex_tlcpector_default, /*  tlcpector */
1849     &synctex_inspector_kern,    /*  inspector */
1850     &synctex_vispector_kern,    /*  vispector */
1851 };
1852 
1853 #	ifdef SYNCTEX_NOTHING
1854 #       pragma mark glue.
1855 #   endif
1856 
1857 /*  glue node creator */
1858 typedef synctex_node_tlchv_s synctex_node_glue_s;
1859 DEFINE_synctex_new_scanned_NODE(glue)
1860 
1861 static char * _synctex_abstract_glue(synctex_node_p node);
1862 static void _synctex_display_glue(synctex_node_p node);
1863 
1864 static synctex_class_s synctex_class_glue = {
1865     NULL,                       /*  No scanner yet */
1866     synctex_node_type_glue,     /*  Node type */
1867     &_synctex_new_glue,         /*  creator */
1868     &_synctex_free_leaf,        /*  destructor */
1869     &_synctex_log_tlchv_node,   /*  log */
1870     &_synctex_display_glue,     /*  display */
1871     &_synctex_abstract_glue,    /*  abstract */
1872     &synctex_tree_model_spf,    /*  tree model */
1873     &synctex_data_model_tlchv,  /*  data model */
1874     &synctex_tlcpector_default, /*  tlcpector */
1875     &synctex_inspector_hv,      /*  inspector */
1876     &synctex_vispector_hv,      /*  vispector */
1877 };
1878 
1879 /*  The small nodes correspond to glue and boundary nodes.  */
1880 
1881 #	ifdef SYNCTEX_NOTHING
1882 #       pragma mark rule.
1883 #   endif
1884 
1885 typedef struct {
1886     SYNCTEX_DECLARE_CHARINDEX
1887     synctex_class_p class_;
1888     synctex_data_u data[synctex_tree_spf_max+synctex_data_box_max];
1889 } synctex_node_rule_s;
1890 
1891 DEFINE_synctex_new_scanned_NODE(rule)
1892 
1893 static void _synctex_log_rule(synctex_node_p node);
1894 static char * _synctex_abstract_rule(synctex_node_p node);
1895 static void _synctex_display_rule(synctex_node_p node);
1896 
1897 static float __synctex_rule_visible_h(synctex_node_p node);
1898 static float __synctex_rule_visible_v(synctex_node_p node);
1899 static float __synctex_rule_visible_width(synctex_node_p node);
1900 static float __synctex_rule_visible_height(synctex_node_p node);
1901 static float __synctex_rule_visible_depth(synctex_node_p node);
1902 static synctex_vispector_s synctex_vispector_rule = {
1903     &__synctex_rule_visible_h,
1904     &__synctex_rule_visible_v,
1905     &__synctex_rule_visible_width,
1906     &__synctex_rule_visible_height,
1907     &__synctex_rule_visible_depth,
1908 };
1909 
1910 static synctex_class_s synctex_class_rule = {
1911     NULL,                       /*  No scanner yet */
1912     synctex_node_type_rule,     /*  Node type */
1913     &_synctex_new_rule,         /*  creator */
1914     &_synctex_free_leaf,        /*  destructor */
1915     &_synctex_log_rule,         /*  log */
1916     &_synctex_display_rule,     /*  display */
1917     &_synctex_abstract_rule,    /*  abstract */
1918     &synctex_tree_model_spf,    /*  tree model */
1919     &synctex_data_model_box,    /*  data model */
1920     &synctex_tlcpector_default, /*  tlcpector */
1921     &synctex_inspector_box,     /*  inspector */
1922     &synctex_vispector_rule,    /*  vispector */
1923 };
1924 
1925 #	ifdef SYNCTEX_NOTHING
1926 #       pragma mark boundary.
1927 #   endif
1928 
1929 /*  boundary node creator */
1930 typedef synctex_node_tlchv_s synctex_node_boundary_s;
1931 DEFINE_synctex_new_scanned_NODE(boundary)
1932 
1933 static char * _synctex_abstract_boundary(synctex_node_p node);
1934 static void _synctex_display_boundary(synctex_node_p node);
1935 
1936 static synctex_class_s synctex_class_boundary = {
1937     NULL,                       /*  No scanner yet */
1938     synctex_node_type_boundary, /*  Node type */
1939     &_synctex_new_boundary,     /*  creator */
1940     &_synctex_free_leaf,        /*  destructor */
1941     &_synctex_log_tlchv_node,   /*  log */
1942     &_synctex_display_boundary, /*  display */
1943     &_synctex_abstract_boundary,/*  abstract */
1944     &synctex_tree_model_spf,    /*  tree model */
1945     &synctex_data_model_tlchv,  /*  data model */
1946     &synctex_tlcpector_default, /*  tlcpector */
1947     &synctex_inspector_hv,      /*  inspector */
1948     &synctex_vispector_hv,      /*  vispector */
1949 };
1950 
1951 #	ifdef SYNCTEX_NOTHING
1952 #       pragma mark box boundary.
1953 #   endif
1954 
1955 typedef struct {
1956     SYNCTEX_DECLARE_CHARINDEX
1957     synctex_class_p class_;
1958     synctex_data_u data[synctex_tree_spfa_max+synctex_data_tlchv_max];
1959 } synctex_node_box_bdry_s;
1960 
1961 #define DEFINE_synctex_new_unscanned_NODE(NAME)\
1962 SYNCTEX_INLINE static synctex_node_p _synctex_new_##NAME(synctex_scanner_p scanner) {\
1963     if (scanner) {\
1964         synctex_node_p node = _synctex_malloc(sizeof(synctex_node_##NAME##_s));\
1965         if (node) {\
1966             node->class_ = scanner->class_+synctex_node_type_##NAME;\
1967             SYNCTEX_DID_NEW(node); \
1968         }\
1969         return node;\
1970     }\
1971     return NULL;\
1972 }
1973 DEFINE_synctex_new_unscanned_NODE(box_bdry)
1974 
1975 static char * _synctex_abstract_box_bdry(synctex_node_p node);
1976 static void _synctex_display_box_bdry(synctex_node_p node);
1977 
1978 static synctex_class_s synctex_class_box_bdry = {
1979     NULL,                       /*  No scanner yet */
1980     synctex_node_type_box_bdry, /*  Node type */
1981     &_synctex_new_box_bdry,     /*  creator */
1982     &_synctex_free_leaf,        /*  destructor */
1983     &_synctex_log_tlchv_node,   /*  log */
1984     &_synctex_display_box_bdry, /*  display */
1985     &_synctex_abstract_box_bdry,/*  display */
1986     &synctex_tree_model_spfa,   /*  tree model */
1987     &synctex_data_model_tlchv,  /*  data model */
1988     &synctex_tlcpector_default, /*  tlcpector */
1989     &synctex_inspector_hv,      /*  inspector */
1990     &synctex_vispector_hv,      /*  vispector */
1991 };
1992 
1993 #	ifdef SYNCTEX_NOTHING
1994 #       pragma mark hbox proxy.
1995 #   endif
1996 
1997 /**
1998  *  Standard nodes refer to TeX nodes: math, kern, boxes...
1999  *  Proxy nodes are used to support forms.
2000  *  A form is parsed as a tree of standard nodes starting
2001  *  at the top left position.
2002  *  When a reference is used, the form is duplicated
2003  *  to the location specified by the reference.
2004  *  As the same form can be duplicated at different locations,
2005  *  the geometrical information is relative to its own top left point.
2006  *  As we need absolute locations, we use proxy nodes.
2007  *  A proxy node records an offset and the target node.
2008  *  The target partly acts as a delegate.
2009  *  The h and v position of the proxy node is the h and v
2010  *  position of the target shifted by the proxy's offset.
2011  *  The width, height and depth are not sensitive to offsets.
2012  *  When are proxies created ?
2013  *  1)  when the synctex file has been parsed, all the form refs
2014  *  are replaced by proxies to the content of a form.
2015  *  This content is a node with siblings (actually none).
2016  *  Those root proxies have the parent of the ref they replace,
2017  *  so their parents exist and are no proxy.
2018  *  Moreover, if they have no sibling, it means that their target have no
2019  *  sibling as well.
2020  *  Such nodes are called root proxies.
2021  *  2)  On the fly, when a proxy is asked for its child
2022  *  (or sibling) and has none, a proxy to its target's child
2023  *  (or sibling) is created if any. There are only 2 possible situations:
2024  *  either the newly created proxy is the child of a proxy,
2025  *  or it is the sibling of a proxy created on the fly.
2026  *  In both cases, the parent is a proxy with children.
2027  *  Such nodes are called child proxies.
2028  *  How to compute the offset of a proxy ?
2029  *  The offset of root proxy objects is exactly
2030  *  the offset of the ref they replace.
2031  *  The offset of other proxies is their owner's,
2032  *  except when pointing to a root proxy.
2033  *  What happens for cascading forms ?
2034  *  Here is an example diagram
2035  *
2036  *  At parse time, the arrow means "owns":
2037  *  sheet0 -> ref_to1
2038  *
2039  *            target1 -> ref_to2
2040  *
2041  *                       target2 -> child22
2042  *
2043  *  After replacing the refs:
2044  *  sheet0 -> proxy00 -> proxy01 -> proxy02
2045  *               |          |          |
2046  *            target1 -> proxy11 -> proxy12
2047  *                          |          |
2048  *                       target2 -> proxy22
2049  *
2050  *  proxy00, proxy11 and proxy22 are root proxies.
2051  *  Their offset is the one of the ref they replace
2052  *  proxy01, proxy02 and proxy12 are child proxies.
2053  *  Their proxy is the one of their parent.
2054  *  Optimization.
2055  *  After all the refs are replaced, there are only root nodes
2056  *  targeting standard node. We make sure that each child proxy
2057  *  also targets a standard node.
2058  *  It is possible for a proxy to have a standard sibling
2059  *  whereas its target has no sibling at all. Root proxies
2060  *  are such nodes, and are the only ones.
2061  *  The consequence is that proxies created on the fly
2062  *  must take into account this situation.
2063  */
2064 
2065 /*  A proxy to a hbox.
2066  *  A proxy do have a target, which can be a proxy
2067  */
2068 
2069 static const synctex_tree_model_s synctex_tree_model_proxy_hbox = {
2070     synctex_tree_sibling_idx,       /* sibling */
2071     synctex_tree_s_parent_idx,      /* parent */
2072     synctex_tree_sp_child_idx,      /* child */
2073     synctex_tree_spc_friend_idx,    /* friend */
2074     synctex_tree_spcf_last_idx,     /* last */
2075     synctex_tree_spcfl_next_hbox_idx,   /* next_hbox */
2076     -1, /* arg_sibling */
2077     synctex_tree_spcfln_target_idx, /* target */
2078     synctex_tree_spcflnt_proxy_hbox_max
2079 };
2080 static const synctex_data_model_s synctex_data_model_proxy = {
2081     -1, /* tag */
2082     -1, /* line */
2083     -1, /* column */
2084     synctex_data_proxy_h_idx, /* h */
2085     synctex_data_proxy_v_idx, /* v */
2086     -1, /* width */
2087     -1, /* height */
2088     -1, /* depth */
2089     -1, /* mean_line */
2090     -1, /* weight */
2091     -1, /* h_V */
2092     -1, /* v_V */
2093     -1, /* width_V */
2094     -1, /* height_V */
2095     -1, /* depth_V */
2096     -1, /* name */
2097     -1, /* page */
2098     synctex_data_proxy_hv_max
2099 };
2100 typedef struct {
2101     SYNCTEX_DECLARE_CHARINDEX
2102     synctex_class_p class_;
2103     synctex_data_u data[synctex_tree_spcflnt_proxy_hbox_max+synctex_data_proxy_hv_max];
2104 } synctex_node_proxy_hbox_s;
2105 
2106 /*  box proxy node creator */
2107 DEFINE_synctex_new_unscanned_NODE(proxy_hbox)
2108 
2109 static void _synctex_log_proxy(synctex_node_p node);
2110 static char * _synctex_abstract_proxy_hbox(synctex_node_p node);
2111 static void _synctex_display_proxy_hbox(synctex_node_p node);
2112 
2113 static int _synctex_proxy_tag(synctex_node_p);
2114 static int _synctex_proxy_line(synctex_node_p);
2115 static int _synctex_proxy_column(synctex_node_p);
2116 
2117 static synctex_tlcpector_s synctex_tlcpector_proxy = {
2118     &_synctex_proxy_tag,
2119     &_synctex_proxy_line,
2120     &_synctex_proxy_column,
2121 };
2122 static int _synctex_proxy_h(synctex_node_p);
2123 static int _synctex_proxy_v(synctex_node_p);
2124 static int _synctex_proxy_width(synctex_node_p);
2125 static int _synctex_proxy_height(synctex_node_p);
2126 static int _synctex_proxy_depth(synctex_node_p);
2127 static synctex_inspector_s synctex_inspector_proxy_box = {
2128     &_synctex_proxy_h,
2129     &_synctex_proxy_v,
2130     &_synctex_proxy_width,
2131     &_synctex_proxy_height,
2132     &_synctex_proxy_depth,
2133 };
2134 
2135 static float __synctex_proxy_visible_h(synctex_node_p);
2136 static float __synctex_proxy_visible_v(synctex_node_p);
2137 static float __synctex_proxy_visible_width(synctex_node_p);
2138 static float __synctex_proxy_visible_height(synctex_node_p);
2139 static float __synctex_proxy_visible_depth(synctex_node_p);
2140 
2141 static synctex_vispector_s synctex_vispector_proxy_box = {
2142     &__synctex_proxy_visible_h,
2143     &__synctex_proxy_visible_v,
2144     &__synctex_proxy_visible_width,
2145     &__synctex_proxy_visible_height,
2146     &__synctex_proxy_visible_depth,
2147 };
2148 
2149 static synctex_class_s synctex_class_proxy_hbox = {
2150     NULL,                           /*  No scanner yet */
2151     synctex_node_type_proxy_hbox,   /*  Node type */
2152     &_synctex_new_proxy_hbox,       /*  creator */
2153     &_synctex_free_node,            /*  destructor */
2154     &_synctex_log_proxy,            /*  log */
2155     &_synctex_display_proxy_hbox,   /*  display */
2156     &_synctex_abstract_proxy_hbox,  /*  abstract */
2157     &synctex_tree_model_proxy_hbox, /*  tree model */
2158     &synctex_data_model_proxy,      /*  data model */
2159     &synctex_tlcpector_proxy,       /*  tlcpector */
2160     &synctex_inspector_proxy_box,   /*  inspector */
2161     &synctex_vispector_proxy_box,   /*  vispector */
2162 };
2163 
2164 #	ifdef SYNCTEX_NOTHING
2165 #       pragma mark vbox proxy.
2166 #   endif
2167 
2168 /*  A proxy to a vbox. */
2169 
2170 static const synctex_tree_model_s synctex_tree_model_proxy_vbox = {
2171     synctex_tree_sibling_idx,       /* sibling */
2172     synctex_tree_s_parent_idx,      /* parent */
2173     synctex_tree_sp_child_idx,      /* child */
2174     synctex_tree_spc_friend_idx,    /* friend */
2175     synctex_tree_spcf_last_idx, /* last */
2176     -1, /* next_hbox */
2177     -1, /* arg_sibling */
2178     synctex_tree_spcfl_target_idx,    /* target */
2179     synctex_tree_spcflt_proxy_vbox_max
2180 };
2181 
2182 typedef struct {
2183     SYNCTEX_DECLARE_CHARINDEX
2184     synctex_class_p class_;
2185     synctex_data_u data[synctex_tree_spcflt_proxy_vbox_max+synctex_data_proxy_hv_max];
2186 } synctex_node_proxy_vbox_s;
2187 
2188 /*  box proxy node creator */
2189 DEFINE_synctex_new_unscanned_NODE(proxy_vbox)
2190 
2191 static void _synctex_log_proxy(synctex_node_p node);
2192 static char * _synctex_abstract_proxy_vbox(synctex_node_p node);
2193 static void _synctex_display_proxy_vbox(synctex_node_p node);
2194 
2195 static synctex_class_s synctex_class_proxy_vbox = {
2196     NULL,                           /*  No scanner yet */
2197     synctex_node_type_proxy_vbox,   /*  Node type */
2198     &_synctex_new_proxy_vbox,       /*  creator */
2199     &_synctex_free_node,            /*  destructor */
2200     &_synctex_log_proxy,            /*  log */
2201     &_synctex_display_proxy_vbox,   /*  display */
2202     &_synctex_abstract_proxy_vbox,  /*  abstract */
2203     &synctex_tree_model_proxy_vbox, /*  tree model */
2204     &synctex_data_model_proxy,      /*  data model */
2205     &synctex_tlcpector_proxy,       /*  tlcpector */
2206     &synctex_inspector_proxy_box,   /*  inspector */
2207     &synctex_vispector_proxy_box,   /*  vispector */
2208 };
2209 
2210 #	ifdef SYNCTEX_NOTHING
2211 #       pragma mark proxy.
2212 #   endif
2213 
2214 /**
2215  *  A proxy to a node but a box.
2216  */
2217 
2218 static const synctex_tree_model_s synctex_tree_model_proxy = {
2219     synctex_tree_sibling_idx,   /* sibling */
2220     synctex_tree_s_parent_idx,  /* parent */
2221     -1, /* child */
2222     synctex_tree_sp_friend_idx, /* friend */
2223     -1, /* last */
2224     -1, /* next_hbox */
2225     -1, /* arg_sibling */
2226     synctex_tree_spf_target_idx,/* target */
2227     synctex_tree_spft_proxy_max
2228 };
2229 
2230 typedef struct {
2231     SYNCTEX_DECLARE_CHARINDEX
2232     synctex_class_p class_;
2233     synctex_data_u data[synctex_tree_spft_proxy_max+synctex_data_proxy_hv_max];
2234 } synctex_node_proxy_s;
2235 
2236 /*  proxy node creator */
2237 DEFINE_synctex_new_unscanned_NODE(proxy)
2238 
2239 static void _synctex_log_proxy(synctex_node_p node);
2240 static char * _synctex_abstract_proxy(synctex_node_p node);
2241 static void _synctex_display_proxy(synctex_node_p node);
2242 
2243 static synctex_vispector_s synctex_vispector_proxy = {
2244     &__synctex_proxy_visible_h,
2245     &__synctex_proxy_visible_v,
2246     &__synctex_proxy_visible_width,
2247     &_synctex_float_none,
2248     &_synctex_float_none,
2249 };
2250 
2251 static synctex_class_s synctex_class_proxy = {
2252     NULL,                       /*  No scanner yet */
2253     synctex_node_type_proxy,    /*  Node type */
2254     &_synctex_new_proxy,        /*  creator */
2255     &_synctex_free_leaf,        /*  destructor */
2256     &_synctex_log_proxy,        /*  log */
2257     &_synctex_display_proxy,    /*  display */
2258     &_synctex_abstract_proxy,   /*  abstract */
2259     &synctex_tree_model_proxy,  /*  tree model */
2260     &synctex_data_model_proxy,  /*  data model */
2261     &synctex_tlcpector_proxy,   /*  tlcpector */
2262     &synctex_inspector_proxy_box,   /*  inspector */
2263     &synctex_vispector_proxy,   /*  vispector */
2264 };
2265 
2266 #	ifdef SYNCTEX_NOTHING
2267 #       pragma mark last proxy.
2268 #   endif
2269 
2270 /**
2271  *  A proxy to the last proxy/box boundary.
2272  */
2273 
2274 static const synctex_tree_model_s synctex_tree_model_proxy_last = {
2275     synctex_tree_sibling_idx,   /* sibling */
2276     synctex_tree_s_parent_idx,  /* parent */
2277     -1, /* child */
2278     synctex_tree_sp_friend_idx, /* friend */
2279     -1, /* last */
2280     -1, /* next_hbox */
2281     synctex_tree_spf_arg_sibling_idx, /* arg_sibling */
2282     synctex_tree_spfa_target_idx,     /* target */
2283     synctex_tree_spfat_proxy_last_max
2284 };
2285 
2286 typedef struct {
2287     SYNCTEX_DECLARE_CHARINDEX
2288     synctex_class_p class_;
2289     synctex_data_u data[synctex_tree_spfat_proxy_last_max+synctex_data_proxy_hv_max];
2290 } synctex_node_proxy_last_s;
2291 
2292 /*  proxy node creator */
2293 DEFINE_synctex_new_unscanned_NODE(proxy_last)
2294 
2295 static void _synctex_log_proxy(synctex_node_p node);
2296 static char * _synctex_abstract_proxy(synctex_node_p node);
2297 static void _synctex_display_proxy(synctex_node_p node);
2298 
2299 static synctex_class_s synctex_class_proxy_last = {
2300     NULL,                           /*  No scanner yet */
2301     synctex_node_type_proxy_last,   /*  Node type */
2302     &_synctex_new_proxy,            /*  creator */
2303     &_synctex_free_leaf,            /*  destructor */
2304     &_synctex_log_proxy,            /*  log */
2305     &_synctex_display_proxy,        /*  display */
2306     &_synctex_abstract_proxy,       /*  abstract */
2307     &synctex_tree_model_proxy_last, /*  tree model */
2308     &synctex_data_model_proxy,      /*  data model */
2309     &synctex_tlcpector_proxy,       /*  tlcpector */
2310     &synctex_inspector_proxy_box,       /*  inspector */
2311     &synctex_vispector_proxy,       /*  vispector */
2312 };
2313 
2314 #	ifdef SYNCTEX_NOTHING
2315 #       pragma mark handle.
2316 #   endif
2317 
2318 /**
2319  *  A handle node.
2320  *  A handle is never the target of a proxy
2321  *  or another handle.
2322  *  The child of a handle is always a handle if any.
2323  *  The sibling of a handle is always a handle if any.
2324  *  The parent of a handle is always a handle if any.
2325  */
2326 
2327 static const synctex_tree_model_s synctex_tree_model_handle = {
2328     synctex_tree_sibling_idx,   /* sibling */
2329     synctex_tree_s_parent_idx,  /* parent */
2330     synctex_tree_sp_child_idx,  /* child */
2331     -1, /* friend */
2332     -1, /* last */
2333     -1, /* next_hbox */
2334     -1, /* arg_sibling */
2335     synctex_tree_spc_target_idx,/* target */
2336     synctex_tree_spct_handle_max
2337 };
2338 
2339 static const synctex_data_model_s synctex_data_model_handle = {
2340     -1, /* tag */
2341     -1, /* line */
2342     -1, /* column */
2343     -1, /* h */
2344     -1, /* v */
2345     -1, /* width */
2346     -1, /* height */
2347     -1, /* depth */
2348     -1, /* mean_line */
2349     synctex_data_handle_w_idx, /* weight */
2350     -1, /* h_V */
2351     -1, /* v_V */
2352     -1, /* width_V */
2353     -1, /* height_V */
2354     -1, /* depth_V */
2355     -1, /* name */
2356     -1, /* page */
2357     synctex_data_handle_w_max
2358 };
2359 
2360 typedef struct {
2361     SYNCTEX_DECLARE_CHARINDEX
2362     synctex_class_p class_;
2363     synctex_data_u data[synctex_tree_spct_handle_max+synctex_data_handle_w_max];
2364 } synctex_node_handle_s;
2365 
2366 /*  handle node creator */
2367 DEFINE_synctex_new_unscanned_NODE(handle)
2368 
2369 static void _synctex_log_handle(synctex_node_p node);
2370 static char * _synctex_abstract_handle(synctex_node_p node);
2371 static void _synctex_display_handle(synctex_node_p node);
2372 
2373 static synctex_class_s synctex_class_handle = {
2374     NULL,                       /*  No scanner yet */
2375     synctex_node_type_handle,   /*  Node type */
2376     &_synctex_new_handle,       /*  creator */
2377     &_synctex_free_handle,      /*  destructor */
2378     &_synctex_log_handle,       /*  log */
2379     &_synctex_display_handle,   /*  display */
2380     &_synctex_abstract_handle,  /*  abstract */
2381     &synctex_tree_model_handle, /*  tree model */
2382     &synctex_data_model_handle, /*  data model */
2383     &synctex_tlcpector_proxy,   /*  tlcpector */
2384     &synctex_inspector_proxy_box,   /*  inspector */
2385     &synctex_vispector_proxy_box,   /*  vispector */
2386 };
2387 
_synctex_new_handle_with_target(synctex_node_p target)2388 SYNCTEX_INLINE static synctex_node_p _synctex_new_handle_with_target(synctex_node_p target) {
2389     if (target) {
2390         synctex_node_p result = _synctex_new_handle(target->class_->scanner);
2391         if (result) {
2392             _synctex_tree_set_target(result,target);
2393             return result;
2394         }
2395     }
2396     return NULL;
2397 }
_synctex_new_handle_with_child(synctex_node_p child)2398 SYNCTEX_INLINE static synctex_node_p _synctex_new_handle_with_child(synctex_node_p child) {
2399     if (child) {
2400         synctex_node_p result = _synctex_new_handle(child->class_->scanner);
2401         if (result) {
2402             _synctex_tree_set_child(result,child);
2403             return result;
2404         }
2405     }
2406     return NULL;
2407 }
2408 
2409 #	ifdef SYNCTEX_NOTHING
2410 #       pragma mark -
2411 #       pragma mark Navigation
2412 #   endif
synctex_node_parent(synctex_node_p node)2413 synctex_node_p synctex_node_parent(synctex_node_p node)
2414 {
2415     return _synctex_tree_parent(node);
2416 }
synctex_node_parent_sheet(synctex_node_p node)2417 synctex_node_p synctex_node_parent_sheet(synctex_node_p node)
2418 {
2419     while(node && synctex_node_type(node) != synctex_node_type_sheet) {
2420         node = _synctex_tree_parent(node);
2421     }
2422     /*  exit the while loop either when node is NULL or node is a sheet */
2423     return node;
2424 }
synctex_node_parent_form(synctex_node_p node)2425 synctex_node_p synctex_node_parent_form(synctex_node_p node)
2426 {
2427     while(node && synctex_node_type(node) != synctex_node_type_form) {
2428         node = _synctex_tree_parent(node);
2429     }
2430     /*  exit the while loop either when node is NULL or node is a form */
2431     return node;
2432 }
2433 
2434 /**
2435  *  The returned proxy will be the child or a sibling of source.
2436  *  The returned proxy has no parent, child nor sibling.
2437  *  Used only by __synctex_replace_ref.
2438  *  argument to_node: a box, not a proxy nor anything else.
2439  */
__synctex_new_proxy_from_ref_to(synctex_node_p ref,synctex_node_p to_node)2440 SYNCTEX_INLINE static synctex_node_p __synctex_new_proxy_from_ref_to(synctex_node_p ref, synctex_node_p to_node) {
2441     synctex_node_p proxy = NULL;
2442     if (!ref || !to_node) {
2443         return NULL;
2444     }
2445     switch(synctex_node_type(to_node)) {
2446         case synctex_node_type_vbox:
2447             proxy = _synctex_new_proxy_vbox(ref->class_->scanner);
2448             break;
2449         case synctex_node_type_hbox:
2450             proxy = _synctex_new_proxy_hbox(ref->class_->scanner);
2451             break;
2452         default:
2453             _synctex_error("!  __synctex_new_proxy_from_ref_to. Unexpected form child (%s). Please report.", synctex_node_isa(to_node));
2454             return NULL;
2455     }
2456     if (!proxy) {
2457         _synctex_error("!  __synctex_new_proxy_from_ref_to. Internal error. Please report.");
2458         return NULL;
2459     }
2460     _synctex_data_set_h(proxy, _synctex_data_h(ref));
2461     _synctex_data_set_v(proxy, _synctex_data_v(ref)-_synctex_data_height(to_node));
2462     _synctex_tree_set_target(proxy,to_node);
2463 #   if defined(SYNCTEX_USE_CHARINDEX)
2464     proxy->line_index=to_node?to_node->line_index:0;
2465     proxy->char_index=to_node?to_node->char_index:0;
2466 #   endif
2467     return proxy;
2468 }
2469 /**
2470  *  The returned proxy will be the child or a sibling of owning_proxy.
2471  *  The returned proxy has no parent, nor child.
2472  *  Used only by synctex_node_child and synctex_node_sibling
2473  *  to create proxies on the fly.
2474  *  If the to_node has an already computed sibling,
2475  *  then the returned proxy has itself a sibling
2476  *  pointing to that already computed sibling.
2477  */
__synctex_new_child_proxy_to(synctex_node_p owner,synctex_node_p to_node)2478 SYNCTEX_INLINE static synctex_node_p __synctex_new_child_proxy_to(synctex_node_p owner, synctex_node_p to_node) {
2479     synctex_node_p proxy = NULL;
2480     synctex_node_p target = to_node;
2481     if (!owner) {
2482         return NULL;
2483     }
2484     switch(synctex_node_type(target)) {
2485         case synctex_node_type_vbox:
2486             if ((proxy = _synctex_new_proxy_vbox(owner->class_->scanner))) {
2487             exit_standard:
2488                 _synctex_data_set_h(proxy, _synctex_data_h(owner));
2489                 _synctex_data_set_v(proxy, _synctex_data_v(owner));
2490             exit0:
2491                 _synctex_tree_set_target(proxy,target);
2492 #   if defined(SYNCTEX_USE_CHARINDEX)
2493                 proxy->line_index=to_node?to_node->line_index:0;
2494                 proxy->char_index=to_node?to_node->char_index:0;
2495 #   endif
2496                 return proxy;
2497             };
2498             break;
2499         case synctex_node_type_proxy_vbox:
2500             if ((proxy = _synctex_new_proxy_vbox(owner->class_->scanner))) {
2501             exit_proxy:
2502                 target = _synctex_tree_target(to_node);
2503                 _synctex_data_set_h(proxy, _synctex_data_h(owner)+_synctex_data_h(to_node));
2504                 _synctex_data_set_v(proxy, _synctex_data_v(owner)+_synctex_data_v(to_node));
2505                 goto exit0;
2506             };
2507             break;
2508         case synctex_node_type_hbox:
2509             if ((proxy = _synctex_new_proxy_hbox(owner->class_->scanner))) {
2510                 goto exit_standard;
2511             };
2512             break;
2513         case synctex_node_type_proxy_hbox:
2514             if ((proxy = _synctex_new_proxy_hbox(owner->class_->scanner))) {
2515                 goto exit_proxy;
2516             };
2517             break;
2518         case synctex_node_type_proxy:
2519         case synctex_node_type_proxy_last:
2520             if ((proxy = _synctex_new_proxy(owner->class_->scanner))) {
2521                 goto exit_proxy;
2522             };
2523             break;
2524         default:
2525             if ((proxy = _synctex_new_proxy(owner->class_->scanner))) {
2526                 goto exit_standard;
2527             };
2528             break;
2529     }
2530     _synctex_error("!  __synctex_new_child_proxy_to. "
2531                    "Internal error. "
2532                    "Please report.");
2533     return NULL;
2534 }
2535 SYNCTEX_INLINE static synctex_node_p _synctex_tree_set_sibling(synctex_node_p node, synctex_node_p new_sibling);
2536 typedef struct synctex_nns_t {
2537     synctex_node_p first;
2538     synctex_node_p last;
2539     synctex_status_t status;
2540 } synctex_nns_s;
2541 /**
2542  *  Given a target node, create a list of proxies.
2543  *  The first proxy points to the target node,
2544  *  its sibling points to the target's sibling and so on.
2545  *  Returns the first created proxy, the last one and
2546  *  an error status.
2547  */
_synctex_new_child_proxies_to(synctex_node_p owner,synctex_node_p to_node)2548 SYNCTEX_INLINE static synctex_nns_s _synctex_new_child_proxies_to(synctex_node_p owner, synctex_node_p to_node) {
2549     synctex_nns_s nns = {NULL,NULL,SYNCTEX_STATUS_OK};
2550     if ((nns.first = nns.last = __synctex_new_child_proxy_to(owner,to_node))) {
2551         synctex_node_p to_next_sibling = __synctex_tree_sibling(to_node);
2552         synctex_node_p to_sibling;
2553         while ((to_sibling = to_next_sibling)) {
2554             synctex_node_p sibling;
2555             if ((to_next_sibling = __synctex_tree_sibling(to_sibling))) {
2556                 /*  This is not the last sibling */
2557                 if((sibling = __synctex_new_child_proxy_to(owner,to_sibling))) {
2558                     _synctex_tree_set_sibling(nns.last,sibling);
2559                     nns.last = sibling;
2560                     continue;
2561                 } else {
2562                     _synctex_error("!  _synctex_new_child_proxy_to. "
2563                                    "Internal error (1). "
2564                                    "Please report.");
2565                     nns.status = SYNCTEX_STATUS_ERROR;
2566                 }
2567             } else if((sibling = _synctex_new_proxy_last(owner->class_->scanner))) {
2568                 _synctex_tree_set_sibling(nns.last,sibling);
2569                 nns.last = sibling;
2570                 _synctex_data_set_h(nns.last, _synctex_data_h(nns.first));
2571                 _synctex_data_set_v(nns.last, _synctex_data_v(nns.first));
2572                 _synctex_tree_set_target(nns.last,to_sibling);
2573 #   if defined(SYNCTEX_USE_CHARINDEX)
2574                 nns.last->line_index=to_sibling->line_index;
2575                 nns.last->char_index=to_sibling->char_index;
2576 #   endif
2577             } else {
2578                 _synctex_error("!  _synctex_new_child_proxy_to. "
2579                                "Internal error (2). "
2580                                "Please report.");
2581                 nns.status = SYNCTEX_STATUS_ERROR;
2582             }
2583             break;
2584         }
2585     }
2586     return nns;
2587 }
2588 static char * _synctex_node_abstract(synctex_node_p node);
synctex_tree_set_friend(synctex_node_p node,synctex_node_p new_friend)2589 SYNCTEX_INLINE static synctex_node_p synctex_tree_set_friend(synctex_node_p node,synctex_node_p new_friend) {
2590 #if SYNCTEX_DEBUG
2591     synctex_node_p F = new_friend;
2592     while (F) {
2593         if (node == F) {
2594             printf("THIS IS AN ERROR\n");
2595             F = new_friend;
2596             while (F) {
2597                 printf("%s\n",_synctex_node_abstract(F));
2598                 if (node == F) {
2599                     return NULL;
2600                 }
2601                 F = _synctex_tree_friend(F);
2602             }
2603             return NULL;
2604         }
2605         F = _synctex_tree_friend(F);
2606     }
2607 #endif
2608     return new_friend?_synctex_tree_set_friend(node,new_friend):_synctex_tree_reset_friend(node);
2609 }
2610 /**
2611  *
2612  */
__synctex_node_make_friend(synctex_node_p node,int i)2613 SYNCTEX_INLINE static synctex_node_p __synctex_node_make_friend(synctex_node_p node, int i) {
2614     synctex_node_p old = NULL;
2615     if (i>=0) {
2616         i = i%(node->class_->scanner->number_of_lists);
2617         old = synctex_tree_set_friend(node,(node->class_->scanner->lists_of_friends)[i]);
2618         (node->class_->scanner->lists_of_friends)[i] = node;
2619 #if SYNCTEX_DEBUG>500
2620         printf("tl(%i)=>",i);
2621         synctex_node_log(node);
2622         if (synctex_node_parent_form(node)) {
2623             printf("!  ERROR. No registration expected!\n");
2624         }
2625 #endif
2626     }
2627     return old;
2628 }
2629 /**
2630  *  All proxies have tlc attributes, on behalf of their target.
2631  *  The purpose is to register all af them.
2632  *  - argument node: is the proxy, must not be NULL
2633  */
__synctex_proxy_make_friend_and_next_hbox(synctex_node_p node)2634 SYNCTEX_INLINE static synctex_node_p __synctex_proxy_make_friend_and_next_hbox(synctex_node_p node) {
2635     synctex_node_p old = NULL;
2636     synctex_node_p target = _synctex_tree_target(node);
2637     if (target) {
2638         int i = _synctex_data_tag(target)+_synctex_data_line(target);
2639         old = __synctex_node_make_friend(node,i);
2640     } else {
2641         old = __synctex_tree_reset_friend(node);
2642     }
2643     if (synctex_node_type(node) == synctex_node_type_proxy_hbox) {
2644         synctex_node_p sheet = synctex_node_parent_sheet(node);
2645         if (sheet) {
2646             _synctex_tree_set_next_hbox(node,_synctex_tree_next_hbox(sheet));
2647             _synctex_tree_set_next_hbox(sheet,node);
2648         }
2649     }
2650     return old;
2651 }
2652 /**
2653  *  Register a node which have tag, line and column.
2654  *  - argument node: the node
2655  */
__synctex_node_make_friend_tlc(synctex_node_p node)2656 SYNCTEX_INLINE static synctex_node_p __synctex_node_make_friend_tlc(synctex_node_p node) {
2657     int i = synctex_node_tag(node)+synctex_node_line(node);
2658     return __synctex_node_make_friend(node,i);
2659 }
2660 /**
2661  *  Register a node which have tag, line and column.
2662  *  Does nothing if the argument is NULL.
2663  *  Calls __synctex_node_make_friend_tlc.
2664  *  - argument node: the node
2665  */
_synctex_node_make_friend_tlc(synctex_node_p node)2666 SYNCTEX_INLINE static void _synctex_node_make_friend_tlc(synctex_node_p node) {
2667     if (node) {
2668         __synctex_node_make_friend_tlc(node);
2669     }
2670 }
2671 static synctex_node_p _synctex_node_set_child(synctex_node_p node, synctex_node_p new_child);
2672 /**
2673  *  The (first) child of the node, if any, NULL otherwise.
2674  *  At parse time, non void box nodes have children.
2675  *  All other nodes have no children.
2676  *  In order to support pdf forms, proxies are created
2677  *  to place form nodes at real locations.
2678  *  Ref nodes are replaced by root proxies targeting
2679  *  form contents. If root proxies have no children,
2680  *  they are created on the fly as proxies to the
2681  *  children of the targeted box.
2682  *  As such, proxies created here are targeting a
2683  *  node that belongs to a form.
2684  *  This is the only place where child proxies are created.
2685  */
synctex_node_child(synctex_node_p node)2686 synctex_node_p synctex_node_child(synctex_node_p node) {
2687     synctex_node_p child = NULL;
2688     synctex_node_p target = NULL;
2689     if ((child = _synctex_tree_child(node))) {
2690         return child;
2691     } else if ((target = _synctex_tree_target(node))) {
2692         if ((child = synctex_node_child(target))) {
2693             /*  This is a proxy with no child
2694              *  which target does have a child. */
2695             synctex_nns_s nns = _synctex_new_child_proxies_to(node, child);
2696             if (nns.first) {
2697                 _synctex_node_set_child(node,nns.first);
2698                 return nns.first;
2699             } else {
2700                 _synctex_error("!  synctex_node_child. Internal inconsistency. Please report.");
2701             }
2702         }
2703     }
2704     return NULL;
2705 }
2706 /*
2707  *  Set the parent/child bound.
2708  *  Things get complicated when new_child has siblings.
2709  *  The caller is responsible for releasing the returned value.
2710  */
_synctex_node_set_child(synctex_node_p parent,synctex_node_p new_child)2711 static synctex_node_p _synctex_node_set_child(synctex_node_p parent, synctex_node_p new_child) {
2712     if (parent) {
2713         synctex_node_p old = _synctex_tree_set_child(parent,new_child);
2714         synctex_node_p last_child = NULL;
2715         synctex_node_p child;
2716         if ((child = old)) {
2717             do {
2718                 _synctex_tree_reset_parent(child);
2719             } while ((child = __synctex_tree_sibling(child)));
2720         }
2721         if ((child = new_child)) {
2722             do {
2723                 _synctex_tree_set_parent(child,parent);
2724                 last_child = child;
2725             } while ((child = __synctex_tree_sibling(child)));
2726         }
2727         _synctex_tree_set_last(parent,last_child);
2728         return old;
2729     }
2730     return NULL;
2731 }
2732 
2733 /*  The last child of the given node, or NULL.
2734  */
synctex_node_last_child(synctex_node_p node)2735 synctex_node_p synctex_node_last_child(synctex_node_p node) {
2736     return _synctex_tree_last(node);
2737 }
2738 /**
2739  *  All nodes siblings are properly set up at parse time
2740  *  except for non root proxies.
2741  */
synctex_node_sibling(synctex_node_p node)2742 synctex_node_p synctex_node_sibling(synctex_node_p node) {
2743     return node? __synctex_tree_sibling(node): NULL;
2744 }
2745 /**
2746  *  All the _synctex_tree_... methods refer to the tree model.
2747  *  __synctex_tree_... methods are low level.
2748  */
2749 /**
2750  *  Replace the sibling.
2751  *  Connect to the arg_sibling of the new_sibling if relevant.
2752  *  - returns the old sibling.
2753  *  The caller is responsible for releasing the old sibling.
2754  *  The bound to the parent is managed below.
2755  */
_synctex_tree_set_sibling(synctex_node_p node,synctex_node_p new_sibling)2756 SYNCTEX_INLINE static synctex_node_p _synctex_tree_set_sibling(synctex_node_p node, synctex_node_p new_sibling) {
2757     if (node == new_sibling) {
2758         printf("BOF\n");
2759     }
2760     synctex_node_p old = node? __synctex_tree_set_sibling(node,new_sibling): NULL;
2761     _synctex_tree_set_arg_sibling(new_sibling,node);
2762     return old;
2763 }
2764 /**
2765  *  Replace the sibling.
2766  *  Set the parent of the new sibling (and further siblings)
2767  *  to the parent of the receiver.
2768  *  Also set the last sibling of parent.
2769  *  - argument new_sibling: must not be NULL.
2770  *  - returns the old sibling.
2771  *  The caller is responsible for releasing the old sibling.
2772  */
_synctex_node_set_sibling(synctex_node_p node,synctex_node_p new_sibling)2773 static synctex_node_p _synctex_node_set_sibling(synctex_node_p node, synctex_node_p new_sibling) {
2774     if (node && new_sibling) {
2775         synctex_node_p old = _synctex_tree_set_sibling(node,new_sibling);
2776         if (_synctex_tree_has_parent(node)) {
2777             synctex_node_p parent = __synctex_tree_parent(node);
2778             if (parent) {
2779                 synctex_node_p N = new_sibling;
2780                 while (synctex_YES) {
2781                     if (_synctex_tree_has_parent(N)) {
2782                         __synctex_tree_set_parent(N,parent);
2783                         _synctex_tree_set_last(parent,N);
2784                         N = __synctex_tree_sibling(N);
2785                         continue;
2786                     } else if (N) {
2787                         _synctex_error("!  synctex_node_sibling. "
2788                                        "Internal inconsistency. "
2789                                        "Please report.");
2790                     }
2791                     break;
2792                 }
2793             }
2794         }
2795         return old;
2796     }
2797     return NULL;
2798 }
2799 /**
2800  *  The last sibling of the given node, or NULL with node.
2801  */
synctex_node_last_sibling(synctex_node_p node)2802 synctex_node_p synctex_node_last_sibling(synctex_node_p node) {
2803     synctex_node_p sibling;
2804     do {
2805         sibling = node;
2806     } while((node = synctex_node_sibling(node)));
2807     return sibling;
2808 }
2809 /**
2810  *  The next nodes corresponds to a deep first tree traversal.
2811  *  Does not create child proxies as side effect contrary to
2812  *  the synctex_node_next method above.
2813  *  May loop infinitely many times if the tree
2814  *  is not properly built (contains loops).
2815  */
_synctex_node_sibling_or_parents(synctex_node_p node)2816 SYNCTEX_INLINE static synctex_node_p _synctex_node_sibling_or_parents(synctex_node_p node) {
2817     while (node) {
2818         synctex_node_p N;
2819         if ((N = __synctex_tree_sibling(node))) {
2820             return N;
2821         } else if ((node = _synctex_tree_parent(node))) {
2822             if (synctex_node_type(node) == synctex_node_type_sheet) {/*  EXC_BAD_ACCESS? */
2823                 return NULL;
2824             } else if (synctex_node_type(node) == synctex_node_type_form) {
2825                 return NULL;
2826             }
2827         } else {
2828             return NULL;
2829         }
2830     }
2831     return NULL;
2832 }
2833 /**
2834  *  The next nodes corresponds to a deep first tree traversal.
2835  *  Creates child proxies as side effect.
2836  *  May loop infinitely many times if the tree
2837  *  is not properly built (contains loops).
2838  */
synctex_node_next(synctex_node_p node)2839 synctex_node_p synctex_node_next(synctex_node_p node) {
2840     synctex_node_p N = synctex_node_child(node);
2841     if (N) {
2842         return N;
2843     }
2844     return _synctex_node_sibling_or_parents(node);
2845 }
2846 /**
2847  *  The next nodes corresponds to a deep first tree traversal.
2848  *  Does not create child proxies as side effect contrary to
2849  *  the synctex_node_next method above.
2850  *  May loop infinitely many times if the tree
2851  *  is not properly built (contains loops).
2852  */
_synctex_node_next(synctex_node_p node)2853 synctex_node_p _synctex_node_next(synctex_node_p node) {
2854     synctex_node_p N = _synctex_tree_child(node);
2855     if (N) {
2856         return N;
2857     }
2858     return _synctex_node_sibling_or_parents(node);
2859 }
2860 /**
2861  *  The node which argument is the sibling.
2862  *  - return: NULL if the argument has no parent or
2863  *      is the first child of its parent.
2864  *  - Input nodes have no arg siblings
2865  */
synctex_node_arg_sibling(synctex_node_p node)2866 synctex_node_p synctex_node_arg_sibling(synctex_node_p node) {
2867 #if 1
2868     return _synctex_tree_arg_sibling(node);
2869 #else
2870     synctex_node_p N = _synctex_tree_parent(node);
2871     if ((N = _synctex_tree_child(N))) {
2872         do {
2873             synctex_node_p NN = __synctex_tree_sibling(N);
2874             if (NN == node) {
2875                 return N;
2876             }
2877             N = NN;
2878         } while (N);
2879     }
2880     return N;
2881 #endif
2882 }
2883 #	ifdef SYNCTEX_NOTHING
2884 #       pragma mark -
2885 #       pragma mark CLASS
2886 #   endif
2887 
2888 /*  Public node accessor: the type  */
synctex_node_type(synctex_node_p node)2889 synctex_node_type_t synctex_node_type(synctex_node_p node) {
2890     return node? node->class_->type: synctex_node_type_none;
2891 }
2892 
2893 /*  Public node accessor: the type  */
synctex_node_target_type(synctex_node_p node)2894 synctex_node_type_t synctex_node_target_type(synctex_node_p node) {
2895     synctex_node_p target = _synctex_tree_target(node);
2896     if (target) {
2897         return (((target)->class_))->type;
2898     } else if (node) {
2899         return (((node)->class_))->type;
2900     }
2901     return synctex_node_type_none;
2902 }
2903 
2904 /*  Public node accessor: the human readable type  */
synctex_node_isa(synctex_node_p node)2905 const char * synctex_node_isa(synctex_node_p node) {
2906     static const char * isa[synctex_node_number_of_types] =
2907     {"Not a node",
2908         "input",
2909         "sheet",
2910         "form",
2911         "ref",
2912         "vbox",
2913         "void vbox",
2914         "hbox",
2915         "void hbox",
2916         "kern",
2917         "glue",
2918         "rule",
2919         "math",
2920         "boundary",
2921         "box_bdry",
2922         "proxy",
2923         "last proxy",
2924         "vbox proxy",
2925         "hbox proxy",
2926         "handle"};
2927     return isa[synctex_node_type(node)];
2928 }
2929 
2930 #	ifdef SYNCTEX_NOTHING
2931 #       pragma mark -
2932 #       pragma mark LOG
2933 #   endif
2934 
2935 /*  Public node logger  */
synctex_node_log(synctex_node_p node)2936 void synctex_node_log(synctex_node_p node) {
2937     SYNCTEX_MSG_SEND(node,log);
2938 }
2939 
_synctex_log_input(synctex_node_p node)2940 static void _synctex_log_input(synctex_node_p node) {
2941     if (node) {
2942         printf("%s:%i,%s(%i)\n",synctex_node_isa(node),
2943                _synctex_data_tag(node),
2944                _synctex_data_name(node),
2945                _synctex_data_line(node));
2946         printf("SELF:%p\n",(void *)node);
2947         printf("    SIBLING:%p\n",
2948                (void *)__synctex_tree_sibling(node));
2949     }
2950 }
2951 
_synctex_log_sheet(synctex_node_p node)2952 static void _synctex_log_sheet(synctex_node_p node) {
2953     if (node) {
2954         printf("%s:%i",synctex_node_isa(node),_synctex_data_page(node));
2955         SYNCTEX_PRINT_CHARINDEX_NL;
2956         printf("SELF:%p\n",(void *)node);
2957         printf("    SIBLING:%p\n",(void *)__synctex_tree_sibling(node));
2958         printf("    PARENT:%p\n",(void *)_synctex_tree_parent(node));
2959         printf("    CHILD:%p\n",(void *)_synctex_tree_child(node));
2960         printf("    LEFT:%p\n",(void *)_synctex_tree_friend(node));
2961         printf("    NEXT_hbox:%p\n",(void *)_synctex_tree_next_hbox(node));
2962     }
2963 }
2964 
_synctex_log_form(synctex_node_p node)2965 static void _synctex_log_form(synctex_node_p node) {
2966     if (node) {
2967         printf("%s:%i",synctex_node_isa(node),_synctex_data_tag(node));
2968         SYNCTEX_PRINT_CHARINDEX_NL;
2969         printf("SELF:%p\n",(void *)node);
2970         printf("    SIBLING:%p\n",(void *)__synctex_tree_sibling(node));
2971         printf("    PARENT:%p\n",(void *)_synctex_tree_parent(node));
2972         printf("    CHILD:%p\n",(void *)_synctex_tree_child(node));
2973         printf("    LEFT:%p\n",(void *)_synctex_tree_friend(node));
2974     }
2975 }
2976 
_synctex_log_ref(synctex_node_p node)2977 static void _synctex_log_ref(synctex_node_p node) {
2978     if (node) {
2979         printf("%s:%i:%i,%i",
2980                synctex_node_isa(node),
2981                _synctex_data_tag(node),
2982                _synctex_data_h(node),
2983                _synctex_data_v(node));
2984         SYNCTEX_PRINT_CHARINDEX_NL;
2985         printf("SELF:%p\n",(void *)node);
2986         printf("    SIBLING:%p\n",(void *)__synctex_tree_sibling(node));
2987         printf("    PARENT:%p\n",(void *)_synctex_tree_parent(node));
2988     }
2989 }
2990 
_synctex_log_tlchv_node(synctex_node_p node)2991 static void _synctex_log_tlchv_node(synctex_node_p node) {
2992     if (node) {
2993         printf("%s:%i,%i,%i:%i,%i",
2994                synctex_node_isa(node),
2995                _synctex_data_tag(node),
2996                _synctex_data_line(node),
2997                _synctex_data_column(node),
2998                _synctex_data_h(node),
2999                _synctex_data_v(node));
3000         SYNCTEX_PRINT_CHARINDEX_NL;
3001         printf("SELF:%p\n",(void *)node);
3002         printf("    SIBLING:%p\n",(void *)__synctex_tree_sibling(node));
3003         printf("    PARENT:%p\n",(void *)_synctex_tree_parent(node));
3004         printf("    CHILD:%p\n",(void *)_synctex_tree_child(node));
3005         printf("    LEFT:%p\n",(void *)_synctex_tree_friend(node));
3006     }
3007 }
3008 
_synctex_log_kern_node(synctex_node_p node)3009 static void _synctex_log_kern_node(synctex_node_p node) {
3010     if (node) {
3011         printf("%s:%i,%i,%i:%i,%i:%i",
3012                synctex_node_isa(node),
3013                _synctex_data_tag(node),
3014                _synctex_data_line(node),
3015                _synctex_data_column(node),
3016                _synctex_data_h(node),
3017                _synctex_data_v(node),
3018                _synctex_data_width(node));
3019         SYNCTEX_PRINT_CHARINDEX_NL;
3020         printf("SELF:%p\n",(void *)node);
3021         printf("    SIBLING:%p\n",(void *)__synctex_tree_sibling(node));
3022         printf("    PARENT:%p\n",(void *)_synctex_tree_parent(node));
3023         printf("    CHILD:%p\n",(void *)_synctex_tree_child(node));
3024         printf("    LEFT:%p\n",(void *)_synctex_tree_friend(node));
3025     }
3026 }
3027 
_synctex_log_rule(synctex_node_p node)3028 static void _synctex_log_rule(synctex_node_p node) {
3029     if (node) {
3030         printf("%s:%i,%i,%i:%i,%i",
3031                synctex_node_isa(node),
3032                _synctex_data_tag(node),
3033                _synctex_data_line(node),
3034                _synctex_data_column(node),
3035                _synctex_data_h(node),
3036                _synctex_data_v(node));
3037         printf(":%i",_synctex_data_width(node));
3038         printf(",%i",_synctex_data_height(node));
3039         printf(",%i",_synctex_data_depth(node));
3040         SYNCTEX_PRINT_CHARINDEX_NL;
3041         printf("SELF:%p\n",(void *)node);
3042         printf("    SIBLING:%p\n",(void *)__synctex_tree_sibling(node));
3043         printf("    PARENT:%p\n",(void *)_synctex_tree_parent(node));
3044         printf("    LEFT:%p\n",(void *)_synctex_tree_friend(node));
3045     }
3046 }
3047 
_synctex_log_void_box(synctex_node_p node)3048 static void _synctex_log_void_box(synctex_node_p node) {
3049     if (node) {
3050         printf("%s",synctex_node_isa(node));
3051         printf(":%i",_synctex_data_tag(node));
3052         printf(",%i",_synctex_data_line(node));
3053         printf(",%i",_synctex_data_column(node));
3054         printf(":%i",_synctex_data_h(node));
3055         printf(",%i",_synctex_data_v(node));
3056         printf(":%i",_synctex_data_width(node));
3057         printf(",%i",_synctex_data_height(node));
3058         printf(",%i",_synctex_data_depth(node));
3059         SYNCTEX_PRINT_CHARINDEX_NL;
3060         printf("SELF:%p\n",(void *)node);
3061         printf("    SIBLING:%p\n",(void *)__synctex_tree_sibling(node));
3062         printf("    PARENT:%p\n",(void *)_synctex_tree_parent(node));
3063         printf("    CHILD:%p\n",(void *)_synctex_tree_child(node));
3064         printf("    LEFT:%p\n",(void *)_synctex_tree_friend(node));
3065     }
3066 }
3067 
_synctex_log_vbox(synctex_node_p node)3068 static void _synctex_log_vbox(synctex_node_p node) {
3069     if (node) {
3070         printf("%s",synctex_node_isa(node));
3071         printf(":%i",_synctex_data_tag(node));
3072         printf(",%i",_synctex_data_line(node));
3073         printf(",%i",_synctex_data_column(node));
3074         printf(":%i",_synctex_data_h(node));
3075         printf(",%i",_synctex_data_v(node));
3076         printf(":%i",_synctex_data_width(node));
3077         printf(",%i",_synctex_data_height(node));
3078         printf(",%i",_synctex_data_depth(node));
3079         SYNCTEX_PRINT_CHARINDEX_NL;
3080         printf("SELF:%p\n",(void *)node);
3081         printf("    SIBLING:%p\n",(void *)__synctex_tree_sibling(node));
3082         printf("    PARENT:%p\n",(void *)_synctex_tree_parent(node));
3083         printf("    CHILD:%p\n",(void *)_synctex_tree_child(node));
3084         printf("    LEFT:%p\n",(void *)_synctex_tree_friend(node));
3085         printf("    NEXT_hbox:%p\n",(void *)_synctex_tree_next_hbox(node));
3086     }
3087 }
3088 
_synctex_log_hbox(synctex_node_p node)3089 static void _synctex_log_hbox(synctex_node_p node) {
3090     if (node) {
3091         printf("%s",synctex_node_isa(node));
3092         printf(":%i",_synctex_data_tag(node));
3093         printf(",%i~%i*%i",_synctex_data_line(node),_synctex_data_mean_line(node),_synctex_data_weight(node));
3094         printf(",%i",_synctex_data_column(node));
3095         printf(":%i",_synctex_data_h(node));
3096         printf(",%i",_synctex_data_v(node));
3097         printf(":%i",_synctex_data_width(node));
3098         printf(",%i",_synctex_data_height(node));
3099         printf(",%i",_synctex_data_depth(node));
3100         printf("/%i",_synctex_data_h_V(node));
3101         printf(",%i",_synctex_data_v_V(node));
3102         printf(":%i",_synctex_data_width_V(node));
3103         printf(",%i",_synctex_data_height_V(node));
3104         printf(",%i",_synctex_data_depth_V(node));
3105         SYNCTEX_PRINT_CHARINDEX_NL;
3106         printf("SELF:%p\n",(void *)node);
3107         printf("    SIBLING:%p\n",(void *)__synctex_tree_sibling(node));
3108         printf("    PARENT:%p\n",(void *)_synctex_tree_parent(node));
3109         printf("    CHILD:%p\n",(void *)_synctex_tree_child(node));
3110         printf("    LEFT:%p\n",(void *)_synctex_tree_friend(node));
3111         printf("    NEXT_hbox:%p\n",(void *)_synctex_tree_next_hbox(node));
3112     }
3113 }
_synctex_log_proxy(synctex_node_p node)3114 static void _synctex_log_proxy(synctex_node_p node) {
3115     if (node) {
3116         synctex_node_p N = _synctex_tree_target(node);
3117         printf("%s",synctex_node_isa(node));
3118         printf(":%i",_synctex_data_h(node));
3119         printf(",%i",_synctex_data_v(node));
3120         SYNCTEX_PRINT_CHARINDEX_NL;
3121         printf("SELF:%p\n",(void *)node);
3122         printf("    SIBLING:%p\n",(void *)__synctex_tree_sibling(node));
3123         printf("    LEFT:%p\n",(void *)_synctex_tree_friend(node));
3124         printf("    ->%s\n",_synctex_node_abstract(N));
3125     }
3126 }
_synctex_log_handle(synctex_node_p node)3127 static void _synctex_log_handle(synctex_node_p node) {
3128     if (node) {
3129         synctex_node_p N = _synctex_tree_target(node);
3130         printf("%s",synctex_node_isa(node));
3131         SYNCTEX_PRINT_CHARINDEX_NL;
3132         printf("SELF:%p\n",(void *)node);
3133         printf("    SIBLING:%p\n",(void *)__synctex_tree_sibling(node));
3134         printf("    ->%s\n",_synctex_node_abstract(N));
3135     }
3136 }
3137 
3138 #	ifdef SYNCTEX_NOTHING
3139 #       pragma mark -
3140 #       pragma mark SYNCTEX_DISPLAY
3141 #   endif
3142 
synctex_scanner_display_switcher(synctex_scanner_p scanR)3143 int synctex_scanner_display_switcher(synctex_scanner_p scanR) {
3144     return scanR->display_switcher;
3145 }
synctex_scanner_set_display_switcher(synctex_scanner_p scanR,int switcher)3146 void synctex_scanner_set_display_switcher(synctex_scanner_p scanR, int switcher) {
3147     scanR->display_switcher = switcher;
3148 }
3149 static const char * const _synctex_display_prompt = "................................";
3150 
_synctex_scanner_display_prompt_down(synctex_scanner_p scanR)3151 static char * _synctex_scanner_display_prompt_down(synctex_scanner_p scanR) {
3152     if (scanR->display_prompt>_synctex_display_prompt) {
3153         --scanR->display_prompt;
3154     }
3155     return scanR->display_prompt;
3156 }
_synctex_scanner_display_prompt_up(synctex_scanner_p scanR)3157 static char * _synctex_scanner_display_prompt_up(synctex_scanner_p scanR) {
3158     if (scanR->display_prompt+1<_synctex_display_prompt+strlen(_synctex_display_prompt)) {
3159         ++scanR->display_prompt;
3160     }
3161     return scanR->display_prompt;
3162 }
3163 
synctex_node_display(synctex_node_p node)3164 void synctex_node_display(synctex_node_p node) {
3165     if (node) {
3166         synctex_scanner_p scanR = node->class_->scanner;
3167         if (scanR) {
3168             if (scanR->display_switcher<0) {
3169                 SYNCTEX_MSG_SEND(node, display);
3170             } else if (scanR->display_switcher>0 && --scanR->display_switcher>0) {
3171                 SYNCTEX_MSG_SEND(node, display);
3172             } else if (scanR->display_switcher-->=0) {
3173                 printf("%s Next display skipped. Reset display switcher.\n",node->class_->scanner->display_prompt);
3174             }
3175         } else {
3176             SYNCTEX_MSG_SEND(node, display);
3177         }
3178     }
3179 }
_synctex_node_abstract(synctex_node_p node)3180 static char * _synctex_node_abstract(synctex_node_p node) {
3181     SYNCTEX_PARAMETER_ASSERT(node || node->class_);
3182     return (node && node->class_->abstract)? node->class_->abstract(node):"none";
3183 }
3184 
_synctex_display_child(synctex_node_p node)3185 SYNCTEX_INLINE static void _synctex_display_child(synctex_node_p node) {
3186     synctex_node_p N = _synctex_tree_child(node);
3187     if (N) {
3188         _synctex_scanner_display_prompt_down(N->class_->scanner);
3189         synctex_node_display(N);
3190         _synctex_scanner_display_prompt_up(N->class_->scanner);
3191     }
3192 }
3193 
_synctex_display_sibling(synctex_node_p node)3194 SYNCTEX_INLINE static void _synctex_display_sibling(synctex_node_p node) {
3195     synctex_node_display(__synctex_tree_sibling(node));
3196 }
3197 #define SYNCTEX_ABSTRACT_MAX 128
_synctex_abstract_input(synctex_node_p node)3198 static char * _synctex_abstract_input(synctex_node_p node) {
3199     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3200     if (node) {
3201         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,"Input:%i:%s(%i)" SYNCTEX_PRINT_CHARINDEX_FMT,
3202                _synctex_data_tag(node),
3203                _synctex_data_name(node),
3204                _synctex_data_line(node)
3205                SYNCTEX_PRINT_CHARINDEX_WHAT);
3206     }
3207     return abstract;
3208 }
3209 
_synctex_display_input(synctex_node_p node)3210 static void _synctex_display_input(synctex_node_p node) {
3211     if (node) {
3212         printf("Input:%i:%s(%i)"
3213                SYNCTEX_PRINT_CHARINDEX_FMT
3214                "\n",
3215                _synctex_data_tag(node),
3216                _synctex_data_name(node),
3217                _synctex_data_line(node)
3218                 SYNCTEX_PRINT_CHARINDEX_WHAT);
3219         synctex_node_display(__synctex_tree_sibling(node));
3220     }
3221 }
3222 
_synctex_abstract_sheet(synctex_node_p node)3223 static char * _synctex_abstract_sheet(synctex_node_p node) {
3224     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3225     if (node) {
3226         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,"{%i...}" SYNCTEX_PRINT_CHARINDEX_FMT,
3227                _synctex_data_page(node)
3228                SYNCTEX_PRINT_CHARINDEX_WHAT);
3229     }
3230     return abstract;
3231 }
3232 
_synctex_display_sheet(synctex_node_p node)3233 static void _synctex_display_sheet(synctex_node_p node) {
3234     if (node) {
3235         printf("%s{%i"
3236                SYNCTEX_PRINT_CHARINDEX_FMT
3237                "\n",
3238                node->class_->scanner->display_prompt,
3239                _synctex_data_page(node)
3240                SYNCTEX_PRINT_CHARINDEX_WHAT);
3241         _synctex_display_child(node);
3242         printf("%s}\n",node->class_->scanner->display_prompt);
3243         _synctex_display_sibling(node);
3244     }
3245 }
3246 
_synctex_abstract_form(synctex_node_p node)3247 static char * _synctex_abstract_form(synctex_node_p node) {
3248     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3249     if (node) {
3250         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,"<%i...>" SYNCTEX_PRINT_CHARINDEX_FMT,
3251                _synctex_data_tag(node)
3252                SYNCTEX_PRINT_CHARINDEX_WHAT);
3253         SYNCTEX_PRINT_CHARINDEX;
3254     }
3255     return abstract;
3256 }
3257 
_synctex_display_form(synctex_node_p node)3258 static void _synctex_display_form(synctex_node_p node) {
3259     if (node) {
3260         printf("%s<%i"
3261                SYNCTEX_PRINT_CHARINDEX_FMT
3262                "\n",
3263                node->class_->scanner->display_prompt,
3264                _synctex_data_tag(node)
3265                SYNCTEX_PRINT_CHARINDEX_WHAT);
3266         _synctex_display_child(node);
3267         printf("%s>\n",node->class_->scanner->display_prompt);
3268         _synctex_display_sibling(node);
3269     }
3270 }
3271 
_synctex_abstract_vbox(synctex_node_p node)3272 static char * _synctex_abstract_vbox(synctex_node_p node) {
3273     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3274     if (node) {
3275         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,"[%i,%i:%i,%i:%i,%i,%i...]"
3276                SYNCTEX_PRINT_CHARINDEX_FMT,
3277                _synctex_data_tag(node),
3278                _synctex_data_line(node),
3279                _synctex_data_h(node),
3280                _synctex_data_v(node),
3281                _synctex_data_width(node),
3282                _synctex_data_height(node),
3283                _synctex_data_depth(node)
3284                SYNCTEX_PRINT_CHARINDEX_WHAT);
3285     }
3286     return abstract;
3287 }
3288 
_synctex_display_vbox(synctex_node_p node)3289 static void _synctex_display_vbox(synctex_node_p node) {
3290     if (node) {
3291         printf("%s[%i,%i:%i,%i:%i,%i,%i"
3292                SYNCTEX_PRINT_CHARINDEX_FMT
3293                "\n",
3294                node->class_->scanner->display_prompt,
3295                _synctex_data_tag(node),
3296                _synctex_data_line(node),
3297                _synctex_data_h(node),
3298                _synctex_data_v(node),
3299                _synctex_data_width(node),
3300                _synctex_data_height(node),
3301                _synctex_data_depth(node)
3302                SYNCTEX_PRINT_CHARINDEX_WHAT);
3303         _synctex_display_child(node);
3304         printf("%s]\n%slast:%s\n",
3305                node->class_->scanner->display_prompt,
3306                node->class_->scanner->display_prompt,
3307                _synctex_node_abstract(_synctex_tree_last(node)));
3308         _synctex_display_sibling(node);
3309     }
3310 }
3311 
_synctex_abstract_hbox(synctex_node_p node)3312 static char * _synctex_abstract_hbox(synctex_node_p node) {
3313     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3314     if (node) {
3315         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,"(%i,%i~%i*%i:%i,%i:%i,%i,%i...)"
3316                SYNCTEX_PRINT_CHARINDEX_FMT,
3317                _synctex_data_tag(node),
3318                _synctex_data_line(node),
3319                _synctex_data_mean_line(node),
3320                _synctex_data_weight(node),
3321                _synctex_data_h(node),
3322                _synctex_data_v(node),
3323                _synctex_data_width(node),
3324                _synctex_data_height(node),
3325                _synctex_data_depth(node)
3326                SYNCTEX_PRINT_CHARINDEX_WHAT);
3327     }
3328     return abstract;
3329 }
3330 
_synctex_display_hbox(synctex_node_p node)3331 static void _synctex_display_hbox(synctex_node_p node) {
3332     if (node) {
3333         printf("%s(%i,%i~%i*%i:%i,%i:%i,%i,%i"
3334                SYNCTEX_PRINT_CHARINDEX_FMT
3335                "\n",
3336                node->class_->scanner->display_prompt,
3337                _synctex_data_tag(node),
3338                _synctex_data_line(node),
3339                _synctex_data_mean_line(node),
3340                _synctex_data_weight(node),
3341                _synctex_data_h(node),
3342                _synctex_data_v(node),
3343                _synctex_data_width(node),
3344                _synctex_data_height(node),
3345                _synctex_data_depth(node)
3346                SYNCTEX_PRINT_CHARINDEX_WHAT);
3347         _synctex_display_child(node);
3348         printf("%s)\n%slast:%s\n",
3349                node->class_->scanner->display_prompt,
3350                node->class_->scanner->display_prompt,
3351                _synctex_node_abstract(_synctex_tree_last(node)));
3352         _synctex_display_sibling(node);
3353     }
3354 }
3355 
_synctex_abstract_void_vbox(synctex_node_p node)3356 static char * _synctex_abstract_void_vbox(synctex_node_p node) {
3357     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3358     if (node) {
3359         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,"v%i,%i;%i,%i:%i,%i,%i"
3360                        SYNCTEX_PRINT_CHARINDEX_FMT
3361                        "\n",
3362                _synctex_data_tag(node),
3363                _synctex_data_line(node),
3364                _synctex_data_h(node),
3365                _synctex_data_v(node),
3366                _synctex_data_width(node),
3367                _synctex_data_height(node),
3368                _synctex_data_depth(node)
3369                        SYNCTEX_PRINT_CHARINDEX_WHAT);
3370     }
3371     return abstract;
3372 }
3373 
_synctex_display_void_vbox(synctex_node_p node)3374 static void _synctex_display_void_vbox(synctex_node_p node) {
3375     if (node) {
3376         printf("%sv%i,%i;%i,%i:%i,%i,%i"
3377                SYNCTEX_PRINT_CHARINDEX_FMT
3378                "\n",
3379                node->class_->scanner->display_prompt,
3380                _synctex_data_tag(node),
3381                _synctex_data_line(node),
3382                _synctex_data_h(node),
3383                _synctex_data_v(node),
3384                _synctex_data_width(node),
3385                _synctex_data_height(node),
3386                _synctex_data_depth(node)
3387                SYNCTEX_PRINT_CHARINDEX_WHAT);
3388         _synctex_display_sibling(node);
3389     }
3390 }
3391 
_synctex_abstract_void_hbox(synctex_node_p node)3392 static char * _synctex_abstract_void_hbox(synctex_node_p node) {
3393     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3394     if (node) {
3395         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,"h%i,%i:%i,%i:%i,%i,%i"
3396                        SYNCTEX_PRINT_CHARINDEX_FMT,
3397                _synctex_data_tag(node),
3398                _synctex_data_line(node),
3399                _synctex_data_h(node),
3400                _synctex_data_v(node),
3401                _synctex_data_width(node),
3402                _synctex_data_height(node),
3403                _synctex_data_depth(node)
3404                        SYNCTEX_PRINT_CHARINDEX_WHAT);
3405     }
3406     return abstract;
3407 }
3408 
_synctex_display_void_hbox(synctex_node_p node)3409 static void _synctex_display_void_hbox(synctex_node_p node) {
3410     if (node) {
3411         printf("%sh%i,%i:%i,%i:%i,%i,%i"
3412                SYNCTEX_PRINT_CHARINDEX_FMT
3413                "\n",
3414                node->class_->scanner->display_prompt,
3415                _synctex_data_tag(node),
3416                _synctex_data_line(node),
3417                _synctex_data_h(node),
3418                _synctex_data_v(node),
3419                _synctex_data_width(node),
3420                _synctex_data_height(node),
3421                _synctex_data_depth(node)
3422                SYNCTEX_PRINT_CHARINDEX_WHAT);
3423         _synctex_display_sibling(node);
3424     }
3425 }
3426 
_synctex_abstract_glue(synctex_node_p node)3427 static char * _synctex_abstract_glue(synctex_node_p node) {
3428     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3429     if (node) {
3430         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,"glue:%i,%i:%i,%i"
3431                        SYNCTEX_PRINT_CHARINDEX_FMT,
3432                _synctex_data_tag(node),
3433                _synctex_data_line(node),
3434                _synctex_data_h(node),
3435                _synctex_data_v(node)
3436                        SYNCTEX_PRINT_CHARINDEX_WHAT);
3437     }
3438     return abstract;
3439 }
3440 
_synctex_display_glue(synctex_node_p node)3441 static void _synctex_display_glue(synctex_node_p node) {
3442     if (node) {
3443         printf("%sglue:%i,%i:%i,%i"
3444                SYNCTEX_PRINT_CHARINDEX_FMT
3445                "\n",
3446                node->class_->scanner->display_prompt,
3447                _synctex_data_tag(node),
3448                _synctex_data_line(node),
3449                _synctex_data_h(node),
3450                _synctex_data_v(node)
3451                SYNCTEX_PRINT_CHARINDEX_WHAT);
3452         _synctex_display_sibling(node);
3453     }
3454 }
3455 
_synctex_abstract_rule(synctex_node_p node)3456 static char * _synctex_abstract_rule(synctex_node_p node) {
3457     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3458     if (node) {
3459         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,"rule:%i,%i:%i,%i:%i,%i,%i"
3460                SYNCTEX_PRINT_CHARINDEX_FMT,
3461                _synctex_data_tag(node),
3462                _synctex_data_line(node),
3463                _synctex_data_h(node),
3464                _synctex_data_v(node),
3465                _synctex_data_width(node),
3466                _synctex_data_height(node),
3467                _synctex_data_depth(node)
3468                SYNCTEX_PRINT_CHARINDEX_WHAT);
3469     }
3470     return abstract;
3471 }
3472 
_synctex_display_rule(synctex_node_p node)3473 static void _synctex_display_rule(synctex_node_p node) {
3474     if (node) {
3475         printf("%srule:%i,%i:%i,%i:%i,%i,%i"
3476                SYNCTEX_PRINT_CHARINDEX_FMT
3477                "\n",
3478                node->class_->scanner->display_prompt,
3479                _synctex_data_tag(node),
3480                _synctex_data_line(node),
3481                _synctex_data_h(node),
3482                _synctex_data_v(node),
3483                _synctex_data_width(node),
3484                _synctex_data_height(node),
3485                _synctex_data_depth(node)
3486                SYNCTEX_PRINT_CHARINDEX_WHAT);
3487         _synctex_display_sibling(node);
3488     }
3489 }
3490 
_synctex_abstract_math(synctex_node_p node)3491 static char * _synctex_abstract_math(synctex_node_p node) {
3492     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3493     if (node) {
3494         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,"math:%i,%i:%i,%i"
3495                        SYNCTEX_PRINT_CHARINDEX_FMT,
3496                _synctex_data_tag(node),
3497                _synctex_data_line(node),
3498                _synctex_data_h(node),
3499                _synctex_data_v(node)
3500                        SYNCTEX_PRINT_CHARINDEX_WHAT);
3501     }
3502     return abstract;
3503 }
3504 
_synctex_display_math(synctex_node_p node)3505 static void _synctex_display_math(synctex_node_p node) {
3506     if (node) {
3507         printf("%smath:%i,%i:%i,%i"
3508                SYNCTEX_PRINT_CHARINDEX_FMT
3509                "\n",
3510                node->class_->scanner->display_prompt,
3511                _synctex_data_tag(node),
3512                _synctex_data_line(node),
3513                _synctex_data_h(node),
3514                _synctex_data_v(node)
3515                SYNCTEX_PRINT_CHARINDEX_WHAT);
3516         _synctex_display_sibling(node);
3517     }
3518 }
3519 
_synctex_abstract_kern(synctex_node_p node)3520 static char * _synctex_abstract_kern(synctex_node_p node) {
3521     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3522     if (node) {
3523         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,"kern:%i,%i:%i,%i:%i"
3524                        SYNCTEX_PRINT_CHARINDEX_FMT,
3525                _synctex_data_tag(node),
3526                _synctex_data_line(node),
3527                _synctex_data_h(node),
3528                _synctex_data_v(node),
3529                _synctex_data_width(node)
3530                        SYNCTEX_PRINT_CHARINDEX_WHAT);
3531     }
3532     return abstract;
3533 }
3534 
_synctex_display_kern(synctex_node_p node)3535 static void _synctex_display_kern(synctex_node_p node) {
3536     if (node) {
3537         printf("%skern:%i,%i:%i,%i:%i"
3538                SYNCTEX_PRINT_CHARINDEX_FMT
3539                "\n",
3540                node->class_->scanner->display_prompt,
3541                _synctex_data_tag(node),
3542                _synctex_data_line(node),
3543                _synctex_data_h(node),
3544                _synctex_data_v(node),
3545                _synctex_data_width(node)
3546                SYNCTEX_PRINT_CHARINDEX_WHAT);
3547         _synctex_display_sibling(node);
3548     }
3549 }
3550 
_synctex_abstract_boundary(synctex_node_p node)3551 static char * _synctex_abstract_boundary(synctex_node_p node) {
3552     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3553     if (node) {
3554         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,"boundary:%i,%i:%i,%i"
3555                        SYNCTEX_PRINT_CHARINDEX_FMT,
3556                _synctex_data_tag(node),
3557                _synctex_data_line(node),
3558                _synctex_data_h(node),
3559                _synctex_data_v(node)
3560                        SYNCTEX_PRINT_CHARINDEX_WHAT);
3561     }
3562     return abstract;
3563 }
3564 
_synctex_display_boundary(synctex_node_p node)3565 static void _synctex_display_boundary(synctex_node_p node) {
3566     if (node) {
3567         printf("%sboundary:%i,%i:%i,%i"
3568                SYNCTEX_PRINT_CHARINDEX_FMT
3569                "\n",
3570                node->class_->scanner->display_prompt,
3571                _synctex_data_tag(node),
3572                _synctex_data_line(node),
3573                _synctex_data_h(node),
3574                _synctex_data_v(node)
3575                SYNCTEX_PRINT_CHARINDEX_WHAT);
3576         _synctex_display_sibling(node);
3577     }
3578 }
3579 
_synctex_abstract_box_bdry(synctex_node_p node)3580 static char * _synctex_abstract_box_bdry(synctex_node_p node) {
3581     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3582     if (node) {
3583         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,"box bdry:%i,%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT,
3584                _synctex_data_tag(node),
3585                _synctex_data_line(node),
3586                _synctex_data_h(node),
3587                _synctex_data_v(node)
3588                SYNCTEX_PRINT_CHARINDEX_WHAT);
3589     }
3590     return abstract;
3591 }
3592 
_synctex_display_box_bdry(synctex_node_p node)3593 static void _synctex_display_box_bdry(synctex_node_p node) {
3594     if (node) {
3595         printf("%sbox bdry:%i,%i:%i,%i",
3596                node->class_->scanner->display_prompt,
3597                _synctex_data_tag(node),
3598                _synctex_data_line(node),
3599                _synctex_data_h(node),
3600                _synctex_data_v(node));
3601         SYNCTEX_PRINT_CHARINDEX_NL;
3602         _synctex_display_sibling(node);
3603     }
3604 }
3605 
_synctex_abstract_ref(synctex_node_p node)3606 static char * _synctex_abstract_ref(synctex_node_p node) {
3607     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3608     if (node) {
3609         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,"form ref:%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT,
3610                _synctex_data_tag(node),
3611                _synctex_data_h(node),
3612                _synctex_data_v(node)
3613                        SYNCTEX_PRINT_CHARINDEX_WHAT);
3614     }
3615     return abstract;
3616 }
3617 
_synctex_display_ref(synctex_node_p node)3618 static void _synctex_display_ref(synctex_node_p node) {
3619     if (node) {
3620         printf("%sform ref:%i:%i,%i",
3621                node->class_->scanner->display_prompt,
3622                _synctex_data_tag(node),
3623                _synctex_data_h(node),
3624                _synctex_data_v(node));
3625         SYNCTEX_PRINT_CHARINDEX_NL;
3626         _synctex_display_sibling(node);
3627     }
3628 }
_synctex_abstract_proxy(synctex_node_p node)3629 static char * _synctex_abstract_proxy(synctex_node_p node) {
3630     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3631     if (node) {
3632         synctex_node_p N = _synctex_tree_target(node);
3633         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,"%s:%i,%i:%i,%i/%p%s",
3634                synctex_node_isa(node),
3635                synctex_node_tag(node),
3636                synctex_node_line(node),
3637                _synctex_data_h(node),
3638                _synctex_data_v(node),
3639                node,
3640                _synctex_node_abstract(N));
3641     }
3642     return abstract;
3643 }
_synctex_display_proxy(synctex_node_p node)3644 static void _synctex_display_proxy(synctex_node_p node) {
3645     if (node) {
3646         synctex_node_p N = _synctex_tree_target(node);
3647         printf("%s%s:%i,%i:%i,%i",
3648                node->class_->scanner->display_prompt,
3649                synctex_node_isa(node),
3650                synctex_node_tag(node),
3651                synctex_node_line(node),
3652                _synctex_data_h(node),
3653                _synctex_data_v(node));
3654         if (N) {
3655             printf("=%i,%i:%i,%i,%i->%s",
3656                    synctex_node_h(node),
3657                    synctex_node_v(node),
3658                    synctex_node_width(node),
3659                    synctex_node_height(node),
3660                    synctex_node_depth(node),
3661                    _synctex_node_abstract(N));
3662         }
3663         printf("\n");
3664         _synctex_display_child(node);
3665         _synctex_display_sibling(node);
3666     }
3667 }
_synctex_abstract_proxy_vbox(synctex_node_p node)3668 static char * _synctex_abstract_proxy_vbox(synctex_node_p node) {
3669     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3670     if (node) {
3671         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,
3672                  "[*%i,%i:%i,%i:%i,%i,%i...*]"
3673                SYNCTEX_PRINT_CHARINDEX_FMT,
3674                synctex_node_tag(node),
3675                synctex_node_line(node),
3676                synctex_node_h(node),
3677                synctex_node_v(node),
3678                synctex_node_width(node),
3679                synctex_node_height(node),
3680                synctex_node_depth(node)
3681                SYNCTEX_PRINT_CHARINDEX_WHAT);
3682     }
3683     return abstract;
3684 }
3685 
_synctex_display_proxy_vbox(synctex_node_p node)3686 static void _synctex_display_proxy_vbox(synctex_node_p node) {
3687     if (node) {
3688         printf("%s[*%i,%i:%i,%i:%i,%i,%i"
3689                SYNCTEX_PRINT_CHARINDEX_FMT
3690                "\n",
3691                node->class_->scanner->display_prompt,
3692                synctex_node_tag(node),
3693                synctex_node_line(node),
3694                synctex_node_h(node),
3695                synctex_node_v(node),
3696                synctex_node_width(node),
3697                synctex_node_height(node),
3698                synctex_node_depth(node)
3699                SYNCTEX_PRINT_CHARINDEX_WHAT);
3700         _synctex_display_child(node);
3701         printf("%s*]\n%slast:%s\n",
3702                node->class_->scanner->display_prompt,
3703                node->class_->scanner->display_prompt,
3704                _synctex_node_abstract(_synctex_tree_last(node)));
3705         _synctex_display_sibling(node);
3706     }
3707 }
3708 
_synctex_abstract_proxy_hbox(synctex_node_p node)3709 static char * _synctex_abstract_proxy_hbox(synctex_node_p node) {
3710     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3711     if (node) {
3712         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,"(*%i,%i~%i*%i:%i,%i:%i,%i,%i...*)/%p"
3713                SYNCTEX_PRINT_CHARINDEX_FMT,
3714                synctex_node_tag(node),
3715                synctex_node_line(node),
3716                synctex_node_mean_line(node),
3717                synctex_node_weight(node),
3718                synctex_node_h(node),
3719                synctex_node_v(node),
3720                synctex_node_width(node),
3721                synctex_node_height(node),
3722                synctex_node_depth(node),
3723                node
3724                SYNCTEX_PRINT_CHARINDEX_WHAT);
3725     }
3726     return abstract;
3727 }
3728 
_synctex_display_proxy_hbox(synctex_node_p node)3729 static void _synctex_display_proxy_hbox(synctex_node_p node) {
3730     if (node) {
3731         printf("%s(*%i,%i~%i*%i:%i,%i:%i,%i,%i"
3732                SYNCTEX_PRINT_CHARINDEX_FMT
3733                "\n",
3734                node->class_->scanner->display_prompt,
3735                synctex_node_tag(node),
3736                synctex_node_line(node),
3737                synctex_node_mean_line(node),
3738                synctex_node_weight(node),
3739                synctex_node_h(node),
3740                synctex_node_v(node),
3741                synctex_node_width(node),
3742                synctex_node_height(node),
3743                synctex_node_depth(node)
3744                SYNCTEX_PRINT_CHARINDEX_WHAT);
3745         _synctex_display_child(node);
3746         printf("%s*)\n%slast:%s\n",
3747                node->class_->scanner->display_prompt,
3748                node->class_->scanner->display_prompt,
3749                _synctex_node_abstract(_synctex_tree_last(node)));
3750         _synctex_display_sibling(node);
3751     }
3752 }
3753 
_synctex_abstract_handle(synctex_node_p node)3754 static char * _synctex_abstract_handle(synctex_node_p node) {
3755     static char abstract[SYNCTEX_ABSTRACT_MAX] = "none";
3756     if (node) {
3757         synctex_node_p N = _synctex_tree_target(node);
3758         if (N && !N->class_) {
3759             exit(1);
3760         }
3761         snprintf(abstract,SYNCTEX_ABSTRACT_MAX,"%s:%s",
3762                synctex_node_isa(node),
3763                (N?_synctex_node_abstract(N):""));
3764     }
3765     return abstract;
3766 }
_synctex_display_handle(synctex_node_p node)3767 static void _synctex_display_handle(synctex_node_p node) {
3768     if (node) {
3769         synctex_node_p N = _synctex_tree_target(node);
3770         printf("%s%s(%i):->%s\n",
3771                node->class_->scanner->display_prompt,
3772                synctex_node_isa(node),
3773                _synctex_data_weight(N),
3774                _synctex_node_abstract(N));
3775         _synctex_display_child(node);
3776         _synctex_display_sibling(node);
3777     }
3778 }
3779 #	ifdef SYNCTEX_NOTHING
3780 #       pragma mark -
3781 #       pragma mark STATUS
3782 #   endif
3783 
3784 #	ifdef SYNCTEX_NOTHING
3785 #       pragma mark -
3786 #       pragma mark Prototypes
3787 #   endif
3788 typedef struct {
3789     size_t size;
3790     synctex_status_t status;
3791 } synctex_zs_s;
3792 static synctex_zs_s _synctex_buffer_get_available_size(synctex_scanner_p scanner, size_t size);
3793 static synctex_status_t _synctex_next_line(synctex_scanner_p scanner);
3794 static synctex_status_t _synctex_match_string(synctex_scanner_p scanner, const char * the_string);
3795 
3796 typedef struct synctex_ns_t {
3797     synctex_node_p node;
3798     synctex_status_t status;
3799 } synctex_ns_s;
3800 static synctex_ns_s __synctex_parse_new_input(synctex_scanner_p scanner);
3801 static synctex_status_t _synctex_scan_preamble(synctex_scanner_p scanner);
3802 typedef struct {
3803     float value;
3804     synctex_status_t status;
3805 } synctex_fs_s;
3806 static synctex_fs_s _synctex_scan_float_and_dimension(synctex_scanner_p scanner);
3807 static synctex_status_t _synctex_scan_post_scriptum(synctex_scanner_p scanner);
3808 static synctex_status_t _synctex_scan_postamble(synctex_scanner_p scanner);
3809 static synctex_status_t _synctex_setup_visible_hbox(synctex_node_p box);
3810 static synctex_status_t _synctex_scan_content(synctex_scanner_p scanner);
3811 int synctex_scanner_pre_x_offset(synctex_scanner_p scanner);
3812 int synctex_scanner_pre_y_offset(synctex_scanner_p scanner);
3813 const char * synctex_scanner_get_output_fmt(synctex_scanner_p scanner);
3814 
3815 #	ifdef SYNCTEX_NOTHING
3816 #       pragma mark -
3817 #       pragma mark SCANNER UTILITIES
3818 #   endif
3819 
3820 #   define SYNCTEX_FILE (scanner->reader->file)
3821 
3822 /**
3823  *  Try to ensure that the buffer contains at least size bytes.
3824  *  Passing a huge size argument means the whole buffer length.
3825  *  Passing a 0 size argument means return the available buffer length, without reading the file.
3826  *  In that case, the return status is always SYNCTEX_STATUS_OK unless the given scanner is NULL.
3827  *  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.
3828  *  It is the responsibility of the caller to test whether this size is conforming to its needs.
3829  *  Negative values may return in case of error, actually
3830  *  when there was an error reading the synctex file.
3831  *  - parameter scanner: The owning scanner. When NULL, returns SYNCTEX_STATUS_BAD_ARGUMENT.
3832  *  - parameter expected: expected number of bytes.
3833  *  - returns: a size and a status.
3834  */
_synctex_buffer_get_available_size(synctex_scanner_p scanner,size_t expected)3835 static synctex_zs_s _synctex_buffer_get_available_size(synctex_scanner_p scanner, size_t expected) {
3836     size_t size = 0;
3837     if (NULL == scanner) {
3838         return (synctex_zs_s){0,SYNCTEX_STATUS_BAD_ARGUMENT};
3839     }
3840     if (expected>scanner->reader->size){
3841         expected = scanner->reader->size;
3842     }
3843     size = SYNCTEX_END - SYNCTEX_CUR; /*  available is the number of unparsed chars in the buffer */
3844     if (expected<=size) {
3845         /*  There are already sufficiently many characters in the buffer */
3846         return (synctex_zs_s){size,SYNCTEX_STATUS_OK};
3847     }
3848     if (SYNCTEX_FILE) {
3849         /*  Copy the remaining part of the buffer to the beginning,
3850          *  then read the next part of the file */
3851         int already_read = 0;
3852 #   if defined(SYNCTEX_USE_CHARINDEX)
3853         scanner->reader->charindex_offset += SYNCTEX_CUR - SYNCTEX_START;
3854 #   endif
3855         if (size) {
3856             memmove(SYNCTEX_START, SYNCTEX_CUR, size);
3857         }
3858         SYNCTEX_CUR = SYNCTEX_START + size; /*  the next character after the move, will change. */
3859         /*  Fill the buffer up to its end */
3860         already_read = gzread(SYNCTEX_FILE,(void *)SYNCTEX_CUR,(int)(SYNCTEX_BUFFER_SIZE - size));
3861         if (already_read>0) {
3862             /*  We assume that 0<already_read<=SYNCTEX_BUFFER_SIZE - size, such that
3863              *  SYNCTEX_CUR + already_read = SYNCTEX_START + size  + already_read <= SYNCTEX_START + SYNCTEX_BUFFER_SIZE */
3864             SYNCTEX_END = SYNCTEX_CUR + already_read;
3865             /*  If the end of the file was reached, all the required SYNCTEX_BUFFER_SIZE - available
3866              *  may not be filled with values from the file.
3867              *  In that case, the buffer should stop properly after already_read characters. */
3868             * SYNCTEX_END = '\0'; /* there is enough room */
3869             SYNCTEX_CUR = SYNCTEX_START;
3870             /*  May be available is less than size, the caller will have to test. */
3871             return (synctex_zs_s){SYNCTEX_END - SYNCTEX_CUR,SYNCTEX_STATUS_OK};
3872         } else if (0>already_read) {
3873             /*  There is a possible error in reading the file */
3874             int errnum = 0;
3875             const char * error_string = gzerror(SYNCTEX_FILE, &errnum);
3876             if (Z_ERRNO == errnum) {
3877                 /*  There is an error in zlib caused by the file system */
3878                 _synctex_error("gzread error from the file system (%i)",errno);
3879                 return (synctex_zs_s){0,SYNCTEX_STATUS_ERROR};
3880             } else if (errnum) {
3881                 _synctex_error("gzread error (%i:%i,%s)",already_read,errnum,error_string);
3882                 return (synctex_zs_s){0,SYNCTEX_STATUS_ERROR};
3883             }
3884         }
3885         /*  Nothing was read, we are at the end of the file. */
3886         gzclose(SYNCTEX_FILE);
3887         SYNCTEX_FILE = NULL;
3888         SYNCTEX_END = SYNCTEX_CUR;
3889         SYNCTEX_CUR = SYNCTEX_START;
3890         * SYNCTEX_END = '\0';/*  Terminate the string properly.*/
3891         /*  there might be a bit of text left */
3892         return (synctex_zs_s){SYNCTEX_END - SYNCTEX_CUR,SYNCTEX_STATUS_EOF};
3893     }
3894     /*  We cannot enlarge the buffer because the end of the file was reached. */
3895     return (synctex_zs_s){size,SYNCTEX_STATUS_EOF};
3896 }
3897 
3898 /*  Used when parsing the synctex file.
3899  *  Advance to the next character starting a line.
3900  *  Actually, only '\n' is recognized as end of line marker.
3901  *  On normal completion, the returned value is the number of unparsed characters available in the buffer.
3902  *  In general, it is a positive value, 0 meaning that the end of file was reached.
3903  *  -1 is returned in case of error, actually because there was an error while feeding the buffer.
3904  *  When the function returns with no error, SYNCTEX_CUR points to the first character of the next line, if any.
3905  *  J. Laurens: Sat May 10 07:52:31 UTC 2008
3906  */
_synctex_next_line(synctex_scanner_p scanner)3907 static synctex_status_t _synctex_next_line(synctex_scanner_p scanner) {
3908     synctex_status_t status = SYNCTEX_STATUS_OK;
3909     if (NULL == scanner) {
3910         return SYNCTEX_STATUS_BAD_ARGUMENT;
3911     }
3912 infinite_loop:
3913     while(SYNCTEX_CUR<SYNCTEX_END) {
3914         if (*SYNCTEX_CUR == '\n') {
3915             ++SYNCTEX_CUR;
3916             ++scanner->reader->line_number;
3917             return _synctex_buffer_get_available_size(scanner, 1).status;
3918         }
3919         ++SYNCTEX_CUR;
3920     }
3921     /*  Here, we have SYNCTEX_CUR == SYNCTEX_END, such that the next call to _synctex_buffer_get_available_size
3922      *  will read another bunch of synctex file. Little by little, we advance to the end of the file. */
3923     status = _synctex_buffer_get_available_size(scanner, 1).status;
3924     if (status<=SYNCTEX_STATUS_EOF) {
3925         return status;
3926     }
3927     goto infinite_loop;
3928 }
3929 
3930 /*  Scan the given string.
3931  *  Both scanner and the_string must not be NULL, and the_string must not be 0 length.
3932  *  SYNCTEX_STATUS_OK is returned if the string is found,
3933  *  SYNCTEX_STATUS_EOF is returned when the EOF is reached,
3934  *  SYNCTEX_STATUS_NOT_OK is returned is the string is not found,
3935  *  an error status is returned otherwise.
3936  *  This is a critical method because buffering renders things more difficult.
3937  *  The given string might be as long as the maximum size_t value.
3938  *  As side effect, the buffer state may have changed if the given argument string can't fit into the buffer.
3939  */
_synctex_match_string(synctex_scanner_p scanner,const char * the_string)3940 static synctex_status_t _synctex_match_string(synctex_scanner_p scanner, const char * the_string) {
3941     size_t tested_len = 0; /*  the number of characters at the beginning of the_string that match */
3942     size_t remaining_len = 0; /*  the number of remaining characters of the_string that should match */
3943     size_t available = 0;
3944     synctex_zs_s zs = {0,0};
3945     if (NULL == scanner || NULL == the_string) {
3946         return SYNCTEX_STATUS_BAD_ARGUMENT;
3947     }
3948     remaining_len = strlen(the_string); /*  All the_string should match */
3949     if (0 == remaining_len) {
3950         return SYNCTEX_STATUS_BAD_ARGUMENT;
3951     }
3952     /*  How many characters available in the buffer? */
3953     zs = _synctex_buffer_get_available_size(scanner,remaining_len);
3954     if (zs.status<SYNCTEX_STATUS_EOF) {
3955         return zs.status;
3956     }
3957     /*  Maybe we have less characters than expected because the buffer is too small. */
3958     if (zs.size>=remaining_len) {
3959         /*  The buffer is sufficiently big to hold the expected number of characters. */
3960         if (strncmp((char *)SYNCTEX_CUR,the_string,remaining_len)) {
3961             return SYNCTEX_STATUS_NOT_OK;
3962         }
3963     return_OK:
3964         /*  Advance SYNCTEX_CUR to the next character after the_string. */
3965         SYNCTEX_CUR += remaining_len;
3966         return SYNCTEX_STATUS_OK;
3967     } else if (strncmp((char *)SYNCTEX_CUR,the_string,zs.size)) {
3968         /*  No need to go further, this is not the expected string in the buffer. */
3969         return SYNCTEX_STATUS_NOT_OK;
3970     } else if (SYNCTEX_FILE) {
3971         /*  The buffer was too small to contain remaining_len characters.
3972          *  We have to cut the string into pieces. */
3973         z_off_t offset = 0L;
3974         /*  the first part of the string is found, advance the_string to the next untested character. */
3975         the_string += zs.size;
3976         /*  update the remaining length and the parsed length. */
3977         remaining_len -= zs.size;
3978         tested_len += zs.size;
3979         SYNCTEX_CUR += zs.size; /*  We validate the tested characters. */
3980         if (0 == remaining_len) {
3981             /*  Nothing left to test, we have found the given string. */
3982             return SYNCTEX_STATUS_OK;
3983         }
3984         /*  We also have to record the current state of the file cursor because
3985          *  if the_string does not match, all this should be a totally blank operation,
3986          *  for which the file and buffer states should not be modified at all.
3987          *  In fact, the states of the buffer before and after this function are in general different
3988          *  but they are totally equivalent as long as the values of the buffer before SYNCTEX_CUR
3989          *  can be safely discarded.  */
3990         offset = gztell(SYNCTEX_FILE);
3991         /*  offset now corresponds to the first character of the file that was not buffered. */
3992         /*  SYNCTEX_CUR - SYNCTEX_START is the number of chars that where already buffered and
3993          *  that match the head of the_string. If in fine the_string does not match, all these chars must be recovered
3994          *  because the whole buffer contents is replaced in _synctex_buffer_get_available_size.
3995          *  They were buffered from offset-len location in the file. */
3996         offset -= SYNCTEX_CUR - SYNCTEX_START;
3997     more_characters:
3998         /*  There is still some work to be done, so read another bunch of file.
3999          *  This is the second call to _synctex_buffer_get_available_size,
4000          *  which means that the actual contents of the buffer will be discarded.
4001          *  We will definitely have to recover the previous state in case we do not find the expected string. */
4002         zs = _synctex_buffer_get_available_size(scanner,remaining_len);
4003         if (zs.status<SYNCTEX_STATUS_EOF) {
4004             return zs.status; /*  This is an error, no need to go further. */
4005         }
4006         if (zs.size==0) {
4007             /*  Missing characters: recover the initial state of the file and return. */
4008         return_NOT_OK:
4009             if (offset != gzseek(SYNCTEX_FILE,offset,SEEK_SET)) {
4010                 /*  This is a critical error, we could not recover the previous state. */
4011                 _synctex_error("Can't seek file");
4012                 return SYNCTEX_STATUS_ERROR;
4013             }
4014             /*  Next time we are asked to fill the buffer,
4015              *  we will read a complete bunch of text from the file. */
4016             SYNCTEX_CUR = SYNCTEX_END;
4017             return SYNCTEX_STATUS_NOT_OK;
4018         }
4019         if (zs.size<remaining_len) {
4020             /*  We'll have to loop one more time. */
4021             if (strncmp((char *)SYNCTEX_CUR,the_string,zs.size)) {
4022                 /*  This is not the expected string, recover the previous state and return. */
4023                 goto return_NOT_OK;
4024             }
4025             /*  Advance the_string to the first untested character. */
4026             the_string += available;
4027             /*  update the remaining length and the parsed length. */
4028             remaining_len -= zs.size;
4029             tested_len += zs.size;
4030             SYNCTEX_CUR += zs.size; /*  We validate the tested characters. */
4031             goto more_characters;
4032         }
4033         /*  This is the last step. */
4034         if (strncmp((char *)SYNCTEX_CUR,the_string,remaining_len)) {
4035             /*  This is not the expected string, recover the previous state and return. */
4036             goto return_NOT_OK;
4037         }
4038         goto return_OK;
4039     } else {
4040         /*  The buffer can't contain the given string argument, and the EOF was reached */
4041         return SYNCTEX_STATUS_EOF;
4042     }
4043 }
4044 
4045 /*  Used when parsing the synctex file.
4046  *  Decode an integer.
4047  *  First, field separators, namely ':' and ',' characters are skipped
4048  *  The returned value is negative if there is an unrecoverable error.
4049  *  It is SYNCTEX_STATUS_NOT_OK if an integer could not be parsed, for example
4050  *  if the characters at the current cursor position are not digits or
4051  *  if the end of the file has been reached.
4052  *  It is SYNCTEX_STATUS_OK if an int has been successfully parsed.
4053  *  The given scanner argument must not be NULL, on the contrary, value_ref may be NULL.
4054  */
_synctex_decode_int(synctex_scanner_p scanner)4055 static synctex_is_s _synctex_decode_int(synctex_scanner_p scanner) {
4056     char * ptr = NULL;
4057     char * end = NULL;
4058     synctex_zs_s zs = {0,0};
4059     int result;
4060     if (NULL == scanner) {
4061         return (synctex_is_s){0, SYNCTEX_STATUS_BAD_ARGUMENT};
4062     }
4063     zs = _synctex_buffer_get_available_size(scanner, SYNCTEX_BUFFER_MIN_SIZE);
4064     if (zs.status<SYNCTEX_STATUS_EOF) {
4065         return (synctex_is_s){0,zs.status};
4066     }
4067     if (zs.size==0) {
4068         return (synctex_is_s){0,SYNCTEX_STATUS_NOT_OK};
4069     }
4070     ptr = SYNCTEX_CUR;
4071     /*  Optionally parse the separator */
4072     if (*ptr==':' || *ptr==',') {
4073         ++ptr;
4074         --zs.size;
4075         if (zs.size==0) {
4076             return (synctex_is_s){0,SYNCTEX_STATUS_NOT_OK};
4077         }
4078     }
4079     result = (int)strtol(ptr, &end, 10);
4080     if (end>ptr) {
4081         SYNCTEX_CUR = end;
4082         return (synctex_is_s){result,SYNCTEX_STATUS_OK};
4083     }
4084     return (synctex_is_s){result,SYNCTEX_STATUS_NOT_OK};
4085 }
_synctex_decode_int_opt(synctex_scanner_p scanner,int default_value)4086 static synctex_is_s _synctex_decode_int_opt(synctex_scanner_p scanner, int default_value) {
4087     char * ptr = NULL;
4088     char * end = NULL;
4089     synctex_zs_s zs = {0, 0};
4090     if (NULL == scanner) {
4091         return (synctex_is_s){default_value, SYNCTEX_STATUS_BAD_ARGUMENT};
4092     }
4093     zs = _synctex_buffer_get_available_size(scanner, SYNCTEX_BUFFER_MIN_SIZE);
4094     if (zs.status<SYNCTEX_STATUS_EOF) {
4095         return (synctex_is_s){default_value,zs.status};
4096     }
4097     if (zs.size==0) {
4098         return (synctex_is_s){default_value,SYNCTEX_STATUS_OK};
4099     }
4100     ptr = SYNCTEX_CUR;
4101     /*  Comma separator required */
4102     if (*ptr==',') {
4103         int result;
4104         ++ptr;
4105         --zs.size;
4106         if (zs.size==0) {
4107             return (synctex_is_s){default_value,SYNCTEX_STATUS_NOT_OK};
4108         }
4109         result = (int)strtol(ptr, &end, 10);
4110         if (end>ptr) {
4111             SYNCTEX_CUR = end;
4112             return (synctex_is_s){result,SYNCTEX_STATUS_OK};
4113         }
4114         return (synctex_is_s){default_value,SYNCTEX_STATUS_NOT_OK};
4115     }
4116     return (synctex_is_s){default_value,SYNCTEX_STATUS_OK};
4117 }
4118 /*  Used when parsing the synctex file.
4119  *  Decode an integer for a v field.
4120  *  Try the _synctex_decode_int version and set the last v field scanned.
4121  *  If it does not succeed, tries to match an '=' sign,
4122  *  which is a shortcut for the last v field scanned.
4123  */
4124 #   define SYNCTEX_INPUT_COMEQUALS ",="
_synctex_decode_int_v(synctex_scanner_p scanner)4125 static synctex_is_s _synctex_decode_int_v(synctex_scanner_p scanner) {
4126     synctex_is_s is = _synctex_decode_int(scanner);
4127     if (SYNCTEX_STATUS_OK == is.status) {
4128         scanner->reader->lastv = is.integer;
4129         return is;
4130     }
4131     is.status = _synctex_match_string(scanner,SYNCTEX_INPUT_COMEQUALS);
4132     if (is.status<SYNCTEX_STATUS_OK) {
4133         return is;
4134     }
4135     is.integer = scanner->reader->lastv;
4136     return is;
4137 }
4138 
4139 /*  The purpose of this function is to read a string.
4140  *  A string is an array of characters from the current parser location
4141  *  and before the next '\n' character.
4142  *  If a string was properly decoded, it is returned in value_ref and
4143  *  the cursor points to the new line marker.
4144  *  The returned string was alloced on the heap, the caller is the owner and
4145  *  is responsible to free it in due time,
4146  *  unless it transfers the ownership to another object.
4147  *  If no string is parsed, * value_ref is undefined.
4148  *  The maximum length of a string that a scanner can decode is platform dependent, namely UINT_MAX.
4149  *  If you just want to blindly parse the file up to the end of the current line,
4150  *  use _synctex_next_line instead.
4151  *  On return, the scanner cursor is unchanged if a string could not be scanned or
4152  *  points to the terminating '\n' character otherwise. As a consequence,
4153  *  _synctex_next_line is necessary after.
4154  *  If either scanner or value_ref is NULL, it is considered as an error and
4155  *  SYNCTEX_STATUS_BAD_ARGUMENT is returned.
4156  */
_synctex_decode_string(synctex_scanner_p scanner)4157 static synctex_ss_s _synctex_decode_string(synctex_scanner_p scanner) {
4158     char * end = NULL;
4159     size_t len = 0;/*  The number of bytes to copy */
4160     size_t already_len = 0;
4161     synctex_zs_s zs = {0,0};
4162     char * string = NULL;
4163     if (NULL == scanner) {
4164         return (synctex_ss_s){NULL,SYNCTEX_STATUS_BAD_ARGUMENT};
4165     }
4166     /*  The buffer must at least contain one character: the '\n' end of line marker */
4167     if (SYNCTEX_CUR>=SYNCTEX_END) {
4168 more_characters:
4169         zs = _synctex_buffer_get_available_size(scanner,1);
4170         if (zs.status < SYNCTEX_STATUS_EOF) {
4171             return (synctex_ss_s){NULL,zs.status};
4172         } else if (0 == zs.size) {
4173             return (synctex_ss_s){NULL,SYNCTEX_STATUS_EOF};
4174         }
4175     }
4176     /*  Now we are sure that there is at least one available character, either because
4177      *  SYNCTEX_CUR was already < SYNCTEX_END, or because the buffer has been properly filled. */
4178     /*  end will point to the next unparsed '\n' character in the file, when mapped to the buffer. */
4179     end = SYNCTEX_CUR;
4180     /*  We scan all the characters up to the next '\n' */
4181     while (end<SYNCTEX_END && *end != '\n') {
4182         ++end;
4183     }
4184     /*  OK, we found where to stop:
4185      *      either end == SYNCTEX_END
4186      *      or *end == '\n' */
4187     len = end - SYNCTEX_CUR;
4188     if (len<UINT_MAX-already_len) {
4189         if ((string = realloc(string,len+already_len+1)) != NULL) {
4190             if (memcpy(string+already_len,SYNCTEX_CUR,len)) {
4191                 already_len += len;
4192                 string[already_len]='\0'; /*  Terminate the string */
4193                 SYNCTEX_CUR += len;/*  Eventually advance to the terminating '\n' */
4194                 if (SYNCTEX_CUR==SYNCTEX_END) {
4195                     /* No \n found*/
4196                     goto more_characters;
4197                 }
4198                 /* trim the trailing whites */
4199                 len = already_len;
4200                 while (len>0) {
4201                     already_len = len--;
4202                     if (string[len]!=' ') {
4203                         break;
4204                     }
4205                 }
4206                 string[already_len] = '\0';
4207                 return (synctex_ss_s){string,SYNCTEX_STATUS_OK};
4208             }
4209             free(string);
4210             _synctex_error("could not copy memory (1).");
4211             return (synctex_ss_s){NULL,SYNCTEX_STATUS_ERROR};
4212         }
4213     }
4214     _synctex_error("could not (re)allocate memory (1).");
4215     return (synctex_ss_s){NULL,SYNCTEX_STATUS_ERROR};
4216 }
4217 
4218 /*  Used when parsing the synctex file.
4219  *  Read an Input record.
4220  *  - parameter scanner: non NULL scanner
4221  *  - returns SYNCTEX_STATUS_OK on successful completions, others values otherwise.
4222  */
__synctex_parse_new_input(synctex_scanner_p scanner)4223 static synctex_ns_s __synctex_parse_new_input(synctex_scanner_p scanner) {
4224     synctex_node_p input = NULL;
4225     synctex_status_t status = SYNCTEX_STATUS_BAD_ARGUMENT;
4226     synctex_zs_s zs = {0,0};
4227     if (NULL == scanner) {
4228         return (synctex_ns_s){NULL,status};
4229     }
4230     if ((status=_synctex_match_string(scanner,SYNCTEX_INPUT_MARK))<SYNCTEX_STATUS_OK) {
4231         return (synctex_ns_s){NULL,status};
4232     }
4233     /*  Create a node */
4234     if (NULL == (input = _synctex_new_input(scanner))) {
4235         _synctex_error("Could not create an input node.");
4236         return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4237     }
4238     /*  Decode the tag  */
4239     if ((status=_synctex_data_decode_tag(input))<SYNCTEX_STATUS_OK) {
4240         _synctex_error("Bad format of input node.");
4241         synctex_node_free(input);
4242         return (synctex_ns_s){NULL,status};
4243     }
4244     /*  The next character is a field separator, we expect one character in the buffer. */
4245     zs = _synctex_buffer_get_available_size(scanner, 1);
4246     if (zs.status<=SYNCTEX_STATUS_ERROR) {
4247         return (synctex_ns_s){NULL,status};
4248     }
4249     if (0 == zs.size) {
4250         return (synctex_ns_s){NULL,SYNCTEX_STATUS_EOF};
4251     }
4252     /*  We can now safely advance to the next character, stepping over the field separator. */
4253     ++SYNCTEX_CUR;
4254     --zs.size;
4255     /*  Then we scan the file name */
4256     if ((status=_synctex_data_decode_name(input))<SYNCTEX_STATUS_OK) {
4257         synctex_node_free(input);
4258         _synctex_next_line(scanner);/* Ignore this whole line */
4259         return (synctex_ns_s){NULL,status};
4260     }
4261     /*  Prepend this input node to the input linked list of the scanner */
4262     __synctex_tree_set_sibling(input,scanner->input);/* input has no parent */
4263     scanner->input = input;
4264 #   if SYNCTEX_VERBOSE
4265     synctex_node_log(input);
4266 #   endif
4267     return (synctex_ns_s){input,_synctex_next_line(scanner)};/*  read the line termination character, if any */
4268 }
4269 
4270 typedef synctex_is_s (*synctex_decoder_t)(synctex_scanner_p);
4271 
4272 /*  Used when parsing the synctex file.
4273  *  Read one of the settings.
4274  *  On normal completion, returns SYNCTEX_STATUS_OK.
4275  *  On error, returns SYNCTEX_STATUS_ERROR.
4276  *  Both arguments must not be NULL.
4277  *  On return, the scanner points to the next character after the decoded object whatever it is.
4278  *  It is the responsibility of the caller to prepare the scanner for the next line.
4279  */
_synctex_scan_named(synctex_scanner_p scanner,const char * name)4280 static synctex_status_t _synctex_scan_named(synctex_scanner_p scanner,const char * name) {
4281     synctex_status_t status = 0;
4282     if (NULL == scanner || NULL == name) {
4283         return SYNCTEX_STATUS_BAD_ARGUMENT;
4284     }
4285 not_found:
4286     status = _synctex_match_string(scanner,name);
4287     if (status<SYNCTEX_STATUS_NOT_OK) {
4288         return status;
4289     } else if (status == SYNCTEX_STATUS_NOT_OK) {
4290         status = _synctex_next_line(scanner);
4291         if (status<SYNCTEX_STATUS_OK) {
4292             return status;
4293         }
4294         goto not_found;
4295     }
4296     return SYNCTEX_STATUS_OK;
4297 }
4298 
4299 /*  Used when parsing the synctex file.
4300  *  Read the preamble.
4301  */
_synctex_scan_preamble(synctex_scanner_p scanner)4302 static synctex_status_t _synctex_scan_preamble(synctex_scanner_p scanner) {
4303     synctex_status_t status = 0;
4304     synctex_is_s is = {0,0};
4305     synctex_ss_s ss = {NULL,0};
4306     if (NULL == scanner) {
4307         return SYNCTEX_STATUS_BAD_ARGUMENT;
4308     }
4309     status = _synctex_scan_named(scanner,"SyncTeX Version:");
4310     if (status<SYNCTEX_STATUS_OK) {
4311         return status;
4312     }
4313     is = _synctex_decode_int(scanner);
4314     if (is.status<SYNCTEX_STATUS_OK) {
4315         return is.status;
4316     }
4317     status = _synctex_next_line(scanner);
4318     if (status<SYNCTEX_STATUS_OK) {
4319         return status;
4320     }
4321     scanner->version = is.integer;
4322     /*  Read all the input records */
4323     do {
4324         status = __synctex_parse_new_input(scanner).status;
4325         if (status<SYNCTEX_STATUS_NOT_OK) {
4326             return status;
4327         }
4328     } while(status == SYNCTEX_STATUS_OK);
4329     /*  the loop exits when status == SYNCTEX_STATUS_NOT_OK */
4330     /*  Now read all the required settings. */
4331     if ((status=_synctex_scan_named(scanner,"Output:"))<SYNCTEX_STATUS_OK) {
4332         return status;
4333     }
4334     if ((ss=_synctex_decode_string(scanner)).status<SYNCTEX_STATUS_OK) {
4335         return is.status;
4336     }
4337     if ((status=_synctex_next_line(scanner))<SYNCTEX_STATUS_OK) {
4338         return status;
4339     }
4340     scanner->output_fmt = ss.string;
4341     if ((status=_synctex_scan_named(scanner,"Magnification:"))<SYNCTEX_STATUS_OK) {
4342         return status;
4343     }
4344     if ((is=_synctex_decode_int(scanner)).status<SYNCTEX_STATUS_OK) {
4345         return is.status;
4346     }
4347     if ((status=_synctex_next_line(scanner))<SYNCTEX_STATUS_OK) {
4348         return status;
4349     }
4350     scanner->pre_magnification = is.integer;
4351     if ((status=_synctex_scan_named(scanner,"Unit:"))<SYNCTEX_STATUS_OK) {
4352         return status;
4353     }
4354     if ((is=_synctex_decode_int(scanner)).status<SYNCTEX_STATUS_OK) {
4355         return is.status;
4356     }
4357     if ((status=_synctex_next_line(scanner))<SYNCTEX_STATUS_OK) {
4358         return status;
4359     }
4360     scanner->pre_unit = is.integer;
4361     if ((status=_synctex_scan_named(scanner,"X Offset:"))<SYNCTEX_STATUS_OK) {
4362         return status;
4363     }
4364     if ((is=_synctex_decode_int(scanner)).status<SYNCTEX_STATUS_OK) {
4365         return is.status;
4366     }
4367     if ((status=_synctex_next_line(scanner))<SYNCTEX_STATUS_OK) {
4368         return status;
4369     }
4370     scanner->pre_x_offset = is.integer;
4371     if ((status=_synctex_scan_named(scanner,"Y Offset:"))<SYNCTEX_STATUS_OK) {
4372         return status;
4373     }
4374     if ((is=_synctex_decode_int(scanner)).status<SYNCTEX_STATUS_OK) {
4375         return is.status;
4376     }
4377     if ((status=_synctex_next_line(scanner))<SYNCTEX_STATUS_OK) {
4378         return status;
4379     }
4380     scanner->pre_y_offset = is.integer;
4381     return SYNCTEX_STATUS_OK;
4382 }
4383 
4384 /*  parse a float with a dimension */
_synctex_scan_float_and_dimension(synctex_scanner_p scanner)4385 static synctex_fs_s _synctex_scan_float_and_dimension(synctex_scanner_p scanner) {
4386     synctex_fs_s fs = {0,0};
4387     synctex_zs_s zs = {0,0};
4388     char * endptr = NULL;
4389 #ifdef HAVE_SETLOCALE
4390     char * loc = setlocale(LC_NUMERIC, NULL);
4391 #endif
4392     if (NULL == scanner) {
4393         return (synctex_fs_s){0,SYNCTEX_STATUS_BAD_ARGUMENT};
4394     }
4395     zs = _synctex_buffer_get_available_size(scanner, SYNCTEX_BUFFER_MIN_SIZE);
4396     if (zs.status<SYNCTEX_STATUS_EOF) {
4397         _synctex_error("Problem with float.");
4398         return (synctex_fs_s){0,zs.status};
4399     }
4400 #ifdef HAVE_SETLOCALE
4401     setlocale(LC_NUMERIC, "C");
4402 #endif
4403     fs.value = strtod(SYNCTEX_CUR,&endptr);
4404 #ifdef HAVE_SETLOCALE
4405     setlocale(LC_NUMERIC, loc);
4406 #endif
4407     if (endptr == SYNCTEX_CUR) {
4408         _synctex_error("A float was expected.");
4409         return (synctex_fs_s){0,SYNCTEX_STATUS_ERROR};
4410     }
4411     SYNCTEX_CUR = endptr;
4412     if ((fs.status = _synctex_match_string(scanner,"in")) >= SYNCTEX_STATUS_OK) {
4413         fs.value *= 72.27f*65536;
4414     } else if (fs.status<SYNCTEX_STATUS_EOF) {
4415     report_unit_error:
4416         _synctex_error("problem with unit.");
4417         return fs;
4418     } else if ((fs.status = _synctex_match_string(scanner,"cm")) >= SYNCTEX_STATUS_OK) {
4419         fs.value *= 72.27f*65536/2.54f;
4420     } else if (fs.status<SYNCTEX_STATUS_EOF) {
4421         goto report_unit_error;
4422     } else if ((fs.status = _synctex_match_string(scanner,"mm")) >= SYNCTEX_STATUS_OK) {
4423         fs.value *= 72.27f*65536/25.4f;
4424     } else if (fs.status<SYNCTEX_STATUS_EOF) {
4425         goto report_unit_error;
4426     } else if ((fs.status = _synctex_match_string(scanner,"pt")) >= SYNCTEX_STATUS_OK) {
4427         fs.value *= 65536.0f;
4428     } else if (fs.status<SYNCTEX_STATUS_EOF) {
4429         goto report_unit_error;
4430     } else if ((fs.status = _synctex_match_string(scanner,"bp")) >= SYNCTEX_STATUS_OK) {
4431         fs.value *= 72.27f/72*65536.0f;
4432     }  else if (fs.status<SYNCTEX_STATUS_EOF) {
4433         goto report_unit_error;
4434     } else if ((fs.status = _synctex_match_string(scanner,"pc")) >= SYNCTEX_STATUS_OK) {
4435         fs.value *= 12.0*65536.0f;
4436     }  else if (fs.status<SYNCTEX_STATUS_EOF) {
4437         goto report_unit_error;
4438     } else if ((fs.status = _synctex_match_string(scanner,"sp")) >= SYNCTEX_STATUS_OK) {
4439         fs.value *= 1.0f;
4440     }  else if (fs.status<SYNCTEX_STATUS_EOF) {
4441         goto report_unit_error;
4442     } else if ((fs.status = _synctex_match_string(scanner,"dd")) >= SYNCTEX_STATUS_OK) {
4443         fs.value *= 1238.0f/1157*65536.0f;
4444     }  else if (fs.status<SYNCTEX_STATUS_EOF) {
4445         goto report_unit_error;
4446     } else if ((fs.status = _synctex_match_string(scanner,"cc")) >= SYNCTEX_STATUS_OK) {
4447         fs.value *= 14856.0f/1157*65536;
4448     } else if (fs.status<SYNCTEX_STATUS_EOF) {
4449         goto report_unit_error;
4450     } else if ((fs.status = _synctex_match_string(scanner,"nd")) >= SYNCTEX_STATUS_OK) {
4451         fs.value *= 685.0f/642*65536;
4452     }  else if (fs.status<SYNCTEX_STATUS_EOF) {
4453         goto report_unit_error;
4454     } else if ((fs.status = _synctex_match_string(scanner,"nc")) >= SYNCTEX_STATUS_OK) {
4455         fs.value *= 1370.0f/107*65536;
4456     } else if (fs.status<SYNCTEX_STATUS_EOF) {
4457         goto report_unit_error;
4458     }
4459     return fs;
4460 }
4461 
4462 /*  parse the post scriptum
4463  *  SYNCTEX_STATUS_OK is returned on completion
4464  *  a negative error is returned otherwise */
_synctex_scan_post_scriptum(synctex_scanner_p scanner)4465 static synctex_status_t _synctex_scan_post_scriptum(synctex_scanner_p scanner) {
4466     synctex_status_t status = 0;
4467     synctex_fs_s fs = {0,0};
4468     char * endptr = NULL;
4469 #ifdef HAVE_SETLOCALE
4470     char * loc = setlocale(LC_NUMERIC, NULL);
4471 #endif
4472     if (NULL == scanner) {
4473         return SYNCTEX_STATUS_BAD_ARGUMENT;
4474     }
4475     /*  Scan the file until a post scriptum line is found */
4476 post_scriptum_not_found:
4477     status = _synctex_match_string(scanner,"Post scriptum:");
4478     if (status<SYNCTEX_STATUS_NOT_OK) {
4479         return status;
4480     }
4481     if (status == SYNCTEX_STATUS_NOT_OK) {
4482         status = _synctex_next_line(scanner);
4483         if (status<SYNCTEX_STATUS_EOF) {
4484             return status;
4485         } else if (status<SYNCTEX_STATUS_OK) {
4486             return SYNCTEX_STATUS_OK;/*  The EOF is found, we have properly scanned the file */
4487         }
4488         goto post_scriptum_not_found;
4489     }
4490     /*  We found the name, advance to the next line. */
4491 next_line:
4492     status = _synctex_next_line(scanner);
4493     if (status<SYNCTEX_STATUS_EOF) {
4494         return status;
4495     } else if (status<SYNCTEX_STATUS_OK) {
4496         return SYNCTEX_STATUS_OK;/*  The EOF is found, we have properly scanned the file */
4497     }
4498     /*  Scanning the information */
4499     status = _synctex_match_string(scanner,"Magnification:");
4500     if (status == SYNCTEX_STATUS_OK ) {
4501 #ifdef HAVE_SETLOCALE
4502         setlocale(LC_NUMERIC, "C");
4503 #endif
4504         scanner->unit = strtod(SYNCTEX_CUR,&endptr);
4505 #ifdef HAVE_SETLOCALE
4506         setlocale(LC_NUMERIC, loc);
4507 #endif
4508         if (endptr == SYNCTEX_CUR) {
4509             _synctex_error("bad magnification in the post scriptum, a float was expected.");
4510             return SYNCTEX_STATUS_ERROR;
4511         }
4512         if (scanner->unit<=0) {
4513             _synctex_error("bad magnification in the post scriptum, a positive float was expected.");
4514             return SYNCTEX_STATUS_ERROR;
4515         }
4516         SYNCTEX_CUR = endptr;
4517         goto next_line;
4518     }
4519     if (status<SYNCTEX_STATUS_EOF){
4520     report_record_problem:
4521         _synctex_error("Problem reading the Post Scriptum records");
4522         return status; /*  echo the error. */
4523     }
4524     status = _synctex_match_string(scanner,"X Offset:");
4525     if (status == SYNCTEX_STATUS_OK) {
4526         fs = _synctex_scan_float_and_dimension(scanner);
4527         if (fs.status<SYNCTEX_STATUS_OK) {
4528             _synctex_error("Problem with X offset in the Post Scriptum.");
4529             return fs.status;
4530         }
4531         scanner->x_offset = fs.value;
4532         goto next_line;
4533     } else if (status<SYNCTEX_STATUS_EOF){
4534         goto report_record_problem;
4535     }
4536     status = _synctex_match_string(scanner,"Y Offset:");
4537     if (status==SYNCTEX_STATUS_OK) {
4538         fs = _synctex_scan_float_and_dimension(scanner);
4539         if (fs.status<SYNCTEX_STATUS_OK) {
4540             _synctex_error("Problem with Y offset in the Post Scriptum.");
4541             return fs.status;
4542         }
4543         scanner->x_offset = fs.value;
4544         goto next_line;
4545     } else if (status<SYNCTEX_STATUS_EOF){
4546         goto report_record_problem;
4547     }
4548     goto next_line;
4549 }
4550 
4551 /*  SYNCTEX_STATUS_OK is returned if the postamble is read
4552  *  SYNCTEX_STATUS_NOT_OK is returned if the postamble is not at the current location
4553  *  a negative error otherwise
4554  *  The postamble comprises the post scriptum section.
4555  */
_synctex_scan_postamble(synctex_scanner_p scanner)4556 static synctex_status_t _synctex_scan_postamble(synctex_scanner_p scanner) {
4557     synctex_status_t status = 0;
4558     synctex_is_s is = {0,0};
4559     if (NULL == scanner) {
4560         return SYNCTEX_STATUS_BAD_ARGUMENT;
4561     }
4562     if (!scanner->flags.postamble && (status=_synctex_match_string(scanner,"Postamble:"))<SYNCTEX_STATUS_OK) {
4563         return status;
4564     }
4565 count_again:
4566     if ((status=_synctex_next_line(scanner))<SYNCTEX_STATUS_OK) {
4567         return status;
4568     }
4569     if ((status=_synctex_scan_named(scanner,"Count:"))< SYNCTEX_STATUS_EOF) {
4570         return status; /*  forward the error */
4571     } else if (status < SYNCTEX_STATUS_OK) { /*  No Count record found */
4572         goto count_again;
4573     }
4574     if ((is=_synctex_decode_int(scanner)).status<SYNCTEX_STATUS_OK) {
4575         return is.status;
4576     }
4577     if ((status=_synctex_next_line(scanner))<SYNCTEX_STATUS_OK) {
4578         return status;
4579     }
4580     scanner->count = is.integer;
4581     /*  Now we scan the last part of the SyncTeX file: the Post Scriptum section. */
4582     return _synctex_scan_post_scriptum(scanner);
4583 }
4584 
4585 /*  Horizontal boxes also have visible size.
4586  *  Visible size are bigger than real size.
4587  *  For example 0 width boxes may contain text.
4588  *  At creation time, the visible size is set to the values of the real size.
4589  */
_synctex_setup_visible_hbox(synctex_node_p box)4590 static synctex_status_t _synctex_setup_visible_hbox(synctex_node_p box) {
4591     if (box) {
4592         switch(synctex_node_type(box)) {
4593             case synctex_node_type_hbox:
4594                 _synctex_data_set_h_V(box,_synctex_data_h(box));
4595                 _synctex_data_set_v_V(box,_synctex_data_v(box));
4596                 _synctex_data_set_width_V(box,_synctex_data_width(box));
4597                 _synctex_data_set_height_V(box,_synctex_data_height(box));
4598                 _synctex_data_set_depth_V(box,_synctex_data_depth(box));
4599                 return SYNCTEX_STATUS_OK;
4600             default:
4601                 break;
4602         }
4603     }
4604     return SYNCTEX_STATUS_BAD_ARGUMENT;
4605 }
4606 
4607 /*  This method is sent to an horizontal box to setup the visible size
4608  *  Some box have 0 width but do contain text material.
4609  *  With this method, one can enlarge the box to contain the given point (h,v).
4610  */
_synctex_make_hbox_contain_point(synctex_node_p node,synctex_point_s point)4611 static synctex_status_t _synctex_make_hbox_contain_point(synctex_node_p node,synctex_point_s point) {
4612     int min, max, n;
4613     if (NULL == node || synctex_node_type(node) != synctex_node_type_hbox) {
4614         return SYNCTEX_STATUS_BAD_ARGUMENT;
4615     }
4616     if ((n = _synctex_data_width_V(node))<0) {
4617         max = _synctex_data_h_V(node);
4618         min = max+n;
4619         if (point.h<min) {
4620             _synctex_data_set_width_V(node,point.h-max);
4621         } else if (point.h>max) {
4622             _synctex_data_set_h_V(node,point.h);
4623             _synctex_data_set_width_V(node,min-point.h);
4624         }
4625     } else {
4626         min = _synctex_data_h_V(node);
4627         max = min+n;
4628         if (point.h<min) {
4629             _synctex_data_set_h_V(node,point.h);
4630             _synctex_data_set_width_V(node,max - point.h);
4631         } else if (point.h>max) {
4632             _synctex_data_set_width_V(node,point.h - min);
4633         }
4634     }
4635     n = _synctex_data_v_V(node);
4636     min = n - _synctex_data_height_V(node);
4637     max = n + _synctex_data_depth_V(node);
4638     if (point.v<min) {
4639         _synctex_data_set_height_V(node,n-point.v);
4640     } else if (point.v>max) {
4641         _synctex_data_set_depth_V(node,point.v-n);
4642     }
4643     return SYNCTEX_STATUS_OK;
4644 }
_synctex_make_hbox_contain_box(synctex_node_p node,synctex_box_s box)4645 static synctex_status_t _synctex_make_hbox_contain_box(synctex_node_p node,synctex_box_s box) {
4646     int min, max, n;
4647     if (NULL == node || synctex_node_type(node) != synctex_node_type_hbox) {
4648         return SYNCTEX_STATUS_BAD_ARGUMENT;
4649     }
4650     if ((n = _synctex_data_width_V(node))<0) {
4651         max = _synctex_data_h_V(node);
4652         min = max+n;
4653         if (box.min.h <min) {
4654             _synctex_data_set_width_V(node,box.min.h-max);
4655         } else if (box.max.h>max) {
4656             _synctex_data_set_h_V(node,box.max.h);
4657             _synctex_data_set_width_V(node,min-box.max.h);
4658         }
4659     } else {
4660         min = _synctex_data_h_V(node);
4661         max = min+n;
4662         if (box.min.h<min) {
4663             _synctex_data_set_h_V(node,box.min.h);
4664             _synctex_data_set_width_V(node,max - box.min.h);
4665         } else if (box.max.h>max) {
4666             _synctex_data_set_width_V(node,box.max.h - min);
4667         }
4668     }
4669     n = _synctex_data_v_V(node);
4670     min = n - _synctex_data_height_V(node);
4671     max = n + _synctex_data_depth_V(node);
4672     if (box.min.v<min) {
4673         _synctex_data_set_height_V(node,n-box.min.v);
4674     } else if (box.max.v>max) {
4675         _synctex_data_set_depth_V(node,box.max.v-n);
4676     }
4677     return SYNCTEX_STATUS_OK;
4678 }
4679 #	ifdef SYNCTEX_NOTHING
4680 #       pragma mark -
4681 #       pragma mark SPECIAL CHARACTERS
4682 #   endif
4683 
4684 
4685 /*  Here are the control characters that strat each line of the synctex output file.
4686  *  Their values define the meaning of the line.
4687  */
4688 #   define SYNCTEX_CHAR_BEGIN_SHEET '{'
4689 #   define SYNCTEX_CHAR_END_SHEET   '}'
4690 #   define SYNCTEX_CHAR_BEGIN_FORM  '<'
4691 #   define SYNCTEX_CHAR_END_FORM    '>'
4692 #   define SYNCTEX_CHAR_BEGIN_VBOX  '['
4693 #   define SYNCTEX_CHAR_END_VBOX    ']'
4694 #   define SYNCTEX_CHAR_BEGIN_HBOX  '('
4695 #   define SYNCTEX_CHAR_END_HBOX    ')'
4696 #   define SYNCTEX_CHAR_ANCHOR      '!'
4697 #   define SYNCTEX_CHAR_VOID_VBOX   'v'
4698 #   define SYNCTEX_CHAR_VOID_HBOX   'h'
4699 #   define SYNCTEX_CHAR_KERN        'k'
4700 #   define SYNCTEX_CHAR_GLUE        'g'
4701 #   define SYNCTEX_CHAR_RULE        'r'
4702 #   define SYNCTEX_CHAR_MATH        '$'
4703 #   define SYNCTEX_CHAR_FORM_REF    'f'
4704 #   define SYNCTEX_CHAR_BOUNDARY    'x'
4705 #   define SYNCTEX_CHAR_CHARACTER   'c'
4706 #   define SYNCTEX_CHAR_COMMENT     '%'
4707 
4708 #	ifdef SYNCTEX_NOTHING
4709 #       pragma mark -
4710 #       pragma mark SCANNERS & PARSERS
4711 #   endif
4712 
4713 #   define SYNCTEX_DECODE_FAILED(NODE,WHAT) \
4714 (_synctex_data_decode_##WHAT(NODE)<SYNCTEX_STATUS_OK)
4715 #   define SYNCTEX_DECODE_FAILED_V(NODE,WHAT) \
4716 (_synctex_data_decode_##WHAT##_v(NODE)<SYNCTEX_STATUS_OK)
4717 
4718 #define SYNCTEX_NS_NULL (synctex_ns_s){NULL,SYNCTEX_STATUS_NOT_OK}
_synctex_parse_new_sheet(synctex_scanner_p scanner)4719 static synctex_ns_s _synctex_parse_new_sheet(synctex_scanner_p scanner) {
4720     synctex_node_p node;
4721     if ((node = _synctex_new_sheet(scanner))) {
4722         if (
4723             SYNCTEX_DECODE_FAILED(node,page)) {
4724             _synctex_error("Bad sheet record.");
4725         } else if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
4726             _synctex_error("Missing end of sheet.");
4727         } else {
4728             /* Now set the owner */
4729             if (scanner->sheet) {
4730                 synctex_node_p last_sheet = scanner->sheet;
4731                 synctex_node_p next_sheet = NULL;
4732                 while ((next_sheet = __synctex_tree_sibling(last_sheet))) {
4733                     last_sheet = next_sheet;
4734                 }
4735                 /* sheets have no parent */
4736                 __synctex_tree_set_sibling(last_sheet,node);
4737             } else {
4738                 scanner->sheet = node;
4739             }
4740             return (synctex_ns_s){node,SYNCTEX_STATUS_OK};
4741         }
4742         _synctex_free_node(node);
4743     }
4744     return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4745 }
4746 /**
4747  *  - requirement: scanner != NULL
4748  */
_synctex_parse_new_form(synctex_scanner_p scanner)4749 static synctex_ns_s _synctex_parse_new_form(synctex_scanner_p scanner) {
4750     synctex_node_p node;
4751     if ((node = _synctex_new_form(scanner))) {
4752         if (
4753             SYNCTEX_DECODE_FAILED(node,tag)) {
4754             _synctex_error("Bad sheet record.");
4755         } else if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
4756             _synctex_error("Missing end of form.");
4757         } else {
4758             /* Now set the owner */
4759             if (scanner->form) {
4760                 synctex_node_p last_form = scanner->form;
4761                 synctex_node_p next_form = NULL;
4762                 while ((next_form = __synctex_tree_sibling(last_form))) {
4763                     last_form = next_form;
4764                 }
4765                 __synctex_tree_set_sibling(last_form,node);
4766             } else {
4767                 scanner->form = node;
4768             }
4769             return (synctex_ns_s){node,SYNCTEX_STATUS_OK};
4770         }
4771         _synctex_free_node(node);
4772     }
4773     return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4774 }
4775 #   define SYNCTEX_SHOULD_DECODE_FAILED(NODE,WHAT) \
4776 (_synctex_data_has_##WHAT(NODE) &&(_synctex_data_decode_##WHAT(NODE)<SYNCTEX_STATUS_OK))
4777 #   define SYNCTEX_SHOULD_DECODE_FAILED_V(NODE,WHAT) \
4778 (_synctex_data_has_##WHAT(NODE) &&(_synctex_data_decode_##WHAT##_v(NODE)<SYNCTEX_STATUS_OK))
4779 
_synctex_data_decode_tlchvwhd(synctex_node_p node)4780 static synctex_status_t _synctex_data_decode_tlchvwhd(synctex_node_p node) {
4781     return SYNCTEX_SHOULD_DECODE_FAILED(node,tag)
4782     || SYNCTEX_SHOULD_DECODE_FAILED(node,line)
4783     || SYNCTEX_SHOULD_DECODE_FAILED(node,column)
4784     || SYNCTEX_SHOULD_DECODE_FAILED(node,h)
4785     || SYNCTEX_SHOULD_DECODE_FAILED_V(node,v)
4786     || SYNCTEX_SHOULD_DECODE_FAILED(node,width)
4787     || SYNCTEX_SHOULD_DECODE_FAILED(node,height)
4788     || SYNCTEX_SHOULD_DECODE_FAILED(node,depth);
4789 }
_synctex_parse_new_vbox(synctex_scanner_p scanner)4790 static synctex_ns_s _synctex_parse_new_vbox(synctex_scanner_p scanner) {
4791     synctex_node_p node;
4792     if ((node = _synctex_new_vbox(scanner))) {
4793         if (_synctex_data_decode_tlchvwhd(node)) {
4794             _synctex_error("Bad vbox record.");
4795             _synctex_next_line(scanner);
4796         out:
4797             _synctex_free_node(node);
4798             return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4799         }
4800         if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
4801             _synctex_error("Missing end of vbox.");
4802             goto out;
4803         }
4804         return (synctex_ns_s){node,SYNCTEX_STATUS_OK};
4805     }
4806     _synctex_next_line(scanner);
4807     return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4808 }
4809 SYNCTEX_INLINE static synctex_node_p __synctex_node_make_friend_tlc(synctex_node_p node);
_synctex_parse_new_hbox(synctex_scanner_p scanner)4810 static synctex_ns_s _synctex_parse_new_hbox(synctex_scanner_p scanner) {
4811     synctex_node_p node;
4812     if ((node = _synctex_new_hbox(scanner))) {
4813         if (_synctex_data_decode_tlchvwhd(node)) {
4814             _synctex_error("Bad hbox record.");
4815             _synctex_next_line(scanner);
4816         out:
4817             _synctex_free_node(node);
4818             return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4819         }
4820         if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
4821             _synctex_error("Missing end of hbox.");
4822             goto out;
4823         }
4824         if (_synctex_setup_visible_hbox(node)<SYNCTEX_STATUS_OK) {
4825             _synctex_error("Unexpected error (_synctex_parse_new_hbox).");
4826             goto out;
4827         }
4828         return (synctex_ns_s){node,SYNCTEX_STATUS_OK};
4829     }
4830     _synctex_next_line(scanner);
4831     return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4832 }
_synctex_parse_new_void_vbox(synctex_scanner_p scanner)4833 static synctex_ns_s _synctex_parse_new_void_vbox(synctex_scanner_p scanner) {
4834     synctex_node_p node;
4835     if ((node = _synctex_new_void_vbox(scanner))) {
4836         if (_synctex_data_decode_tlchvwhd(node)) {
4837             _synctex_error("Bad void vbox record.");
4838             _synctex_next_line(scanner);
4839         out:
4840             _synctex_free_node(node);
4841             return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4842         }
4843         if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
4844             _synctex_error("Missing end of container.");
4845             goto out;
4846         }
4847         return (synctex_ns_s){node,SYNCTEX_STATUS_OK};
4848     }
4849     _synctex_next_line(scanner);
4850     return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4851 }
_synctex_parse_new_void_hbox(synctex_scanner_p scanner)4852 static synctex_ns_s _synctex_parse_new_void_hbox(synctex_scanner_p scanner) {
4853     synctex_node_p node;
4854     if ((node = _synctex_new_void_hbox(scanner))) {
4855         if (_synctex_data_decode_tlchvwhd(node)) {
4856             _synctex_error("Bad void hbox record.");
4857             _synctex_next_line(scanner);
4858         out:
4859             _synctex_free_node(node);
4860             return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4861         }
4862         if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
4863             _synctex_error("Missing end of container.");
4864             goto out;
4865         }
4866         return (synctex_ns_s){node,SYNCTEX_STATUS_OK};
4867     }
4868     _synctex_next_line(scanner);
4869     return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4870 }
_synctex_parse_new_kern(synctex_scanner_p scanner)4871 static synctex_ns_s _synctex_parse_new_kern(synctex_scanner_p scanner) {
4872     synctex_node_p node;
4873     if ((node = _synctex_new_kern(scanner))) {
4874         if (_synctex_data_decode_tlchvwhd(node)) {
4875             _synctex_error("Bad kern record.");
4876             _synctex_next_line(scanner);
4877         out:
4878             _synctex_free_node(node);
4879             return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4880         }
4881         if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
4882             _synctex_error("Missing end of container.");
4883             goto out;
4884         }
4885         return (synctex_ns_s){node,SYNCTEX_STATUS_OK};
4886     }
4887     _synctex_next_line(scanner);
4888     return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4889 }
_synctex_parse_new_glue(synctex_scanner_p scanner)4890 static synctex_ns_s _synctex_parse_new_glue(synctex_scanner_p scanner) {
4891     synctex_node_p node;
4892     if ((node = _synctex_new_glue(scanner))) {
4893         if (_synctex_data_decode_tlchvwhd(node)) {
4894             _synctex_error("Bad glue record.");
4895             _synctex_next_line(scanner);
4896         out:
4897             _synctex_free_node(node);
4898             return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4899         }
4900         if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
4901             _synctex_error("Missing end of container.");
4902             goto out;
4903         }
4904         return (synctex_ns_s){node,SYNCTEX_STATUS_OK};
4905     }
4906     _synctex_next_line(scanner);
4907     return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4908 }
_synctex_parse_new_rule(synctex_scanner_p scanner)4909 static synctex_ns_s _synctex_parse_new_rule(synctex_scanner_p scanner) {
4910     synctex_node_p node;
4911     if ((node = _synctex_new_rule(scanner))) {
4912         if (_synctex_data_decode_tlchvwhd(node)) {
4913             _synctex_error("Bad rule record.");
4914             _synctex_next_line(scanner);
4915         out:
4916             _synctex_free_node(node);
4917             return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4918         }
4919         if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
4920             _synctex_error("Missing end of container.");
4921             goto out;
4922         }
4923         return (synctex_ns_s){node,SYNCTEX_STATUS_OK};
4924     }
4925     _synctex_next_line(scanner);
4926     return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4927 }
_synctex_parse_new_math(synctex_scanner_p scanner)4928 static synctex_ns_s _synctex_parse_new_math(synctex_scanner_p scanner) {
4929     synctex_node_p node;
4930     if ((node = _synctex_new_math(scanner))) {
4931         if (_synctex_data_decode_tlchvwhd(node)) {
4932             _synctex_error("Bad math record.");
4933             _synctex_next_line(scanner);
4934         out:
4935             _synctex_free_node(node);
4936             return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4937         }
4938         if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
4939             _synctex_error("Missing end of container.");
4940             goto out;
4941         }
4942         return (synctex_ns_s){node,SYNCTEX_STATUS_OK};
4943     }
4944     _synctex_next_line(scanner);
4945     return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4946 }
_synctex_parse_new_boundary(synctex_scanner_p scanner)4947 static synctex_ns_s _synctex_parse_new_boundary(synctex_scanner_p scanner) {
4948     synctex_node_p node;
4949     if ((node = _synctex_new_boundary(scanner))) {
4950         if (_synctex_data_decode_tlchvwhd(node)) {
4951             _synctex_error("Bad boundary record.");
4952             _synctex_next_line(scanner);
4953         out:
4954             _synctex_free_node(node);
4955             return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4956         }
4957         if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
4958             _synctex_error("Missing end of container.");
4959             goto out;
4960         }
4961         return (synctex_ns_s){node,SYNCTEX_STATUS_OK};
4962     }
4963     _synctex_next_line(scanner);
4964     return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4965 }
_synctex_parse_new_ref(synctex_scanner_p scanner)4966 SYNCTEX_INLINE static synctex_ns_s _synctex_parse_new_ref(synctex_scanner_p scanner) {
4967     synctex_node_p node;
4968     if ((node = _synctex_new_ref(scanner))) {
4969         if (SYNCTEX_DECODE_FAILED(node,tag)
4970             || SYNCTEX_DECODE_FAILED(node,h)
4971             || SYNCTEX_DECODE_FAILED_V(node,v)) {
4972             _synctex_error("Bad form ref record.");
4973             _synctex_next_line(scanner);
4974         out:
4975             _synctex_free_node(node);
4976             return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4977         }
4978         if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
4979             _synctex_error("Missing end of container.");
4980             goto out;
4981         }
4982         return (synctex_ns_s){node,SYNCTEX_STATUS_OK};
4983     }
4984     _synctex_next_line(scanner);
4985     return (synctex_ns_s){NULL,SYNCTEX_STATUS_ERROR};
4986 }
4987 #   undef SYNCTEX_DECODE_FAILED
4988 #   undef SYNCTEX_DECODE_FAILED_V
4989 
4990 SYNCTEX_INLINE static synctex_point_s _synctex_data_point(synctex_node_p node);
4991 SYNCTEX_INLINE static synctex_point_s _synctex_data_point_V(synctex_node_p node);
4992 SYNCTEX_INLINE static synctex_point_s _synctex_data_set_point(synctex_node_p node, synctex_point_s point);
4993 SYNCTEX_INLINE static synctex_box_s _synctex_data_box(synctex_node_p node);
4994 SYNCTEX_INLINE static synctex_box_s _synctex_data_xob(synctex_node_p node);
4995 SYNCTEX_INLINE static synctex_box_s _synctex_data_box_V(synctex_node_p node);
4996 
_synctex_input_register_line(synctex_node_p input,synctex_node_p node)4997 SYNCTEX_INLINE static synctex_node_p _synctex_input_register_line(synctex_node_p input,synctex_node_p node) {
4998     if (node && _synctex_data_tag(input) != _synctex_data_tag(node)) {
4999         input = synctex_scanner_input_with_tag(node->class_->scanner,_synctex_data_tag(node));
5000     }
5001     if (_synctex_data_line(node)>_synctex_data_line(input)) {
5002         _synctex_data_set_line(input,_synctex_data_line(node));
5003     }
5004     return input;
5005 }
5006 /**
5007  *  Free node and its siblings and return its detached child.
5008  */
_synctex_handle_pop_child(synctex_node_p handle)5009 SYNCTEX_INLINE static synctex_node_p _synctex_handle_pop_child(synctex_node_p handle) {
5010     synctex_node_p child = _synctex_tree_reset_child(handle);
5011     synctex_node_free(handle);
5012     return child;
5013 }
5014 /**
5015  *  Set the tlc of all the x nodes that are targets of
5016  *  x_handle and its sibling.
5017  *  Reset the target of x_handle and deletes its siblings.
5018  *  child is a node that has just been parsed and is not a boundary node.
5019  */
_synctex_handle_set_tlc(synctex_node_p x_handle,synctex_node_p child,synctex_bool_t make_friend)5020 SYNCTEX_INLINE static void _synctex_handle_set_tlc(synctex_node_p x_handle, synctex_node_p child, synctex_bool_t make_friend) {
5021     if (x_handle) {
5022         synctex_node_p sibling = x_handle;
5023         if (child) {
5024             synctex_node_p target;
5025             while ((target = synctex_node_target(sibling))) {
5026                 _synctex_data_set_tlc(target,child);
5027                 if (make_friend) {
5028                     _synctex_node_make_friend_tlc(target);
5029                 }
5030                 if ((sibling = __synctex_tree_sibling(sibling))) {
5031                     continue;
5032                 } else {
5033                     break;
5034                 }
5035             }
5036         }
5037         _synctex_tree_reset_target(x_handle);
5038         sibling = __synctex_tree_reset_sibling(x_handle);
5039         synctex_node_free(sibling);
5040     }
5041 }
5042 /**
5043  *  When we have parsed a box, we must register
5044  *  all the contained heading boundary nodes
5045  *  that have not yet been registered.
5046  *  Those handles will be deleted when poping.
5047  */
_synctex_handle_make_friend_tlc(synctex_node_p node)5048 SYNCTEX_INLINE static void _synctex_handle_make_friend_tlc(synctex_node_p node) {
5049     while (node) {
5050         synctex_node_p target = _synctex_tree_reset_target(node);
5051         _synctex_node_make_friend_tlc(target);
5052         node = __synctex_tree_sibling(node);
5053     }
5054 }
5055 /**
5056  *  Scan sheets, forms and input records.
5057  *  - parameter scanner: owning scanner
5058  *  - returns: status
5059  */
__synctex_parse_sfi(synctex_scanner_p scanner)5060 static synctex_status_t __synctex_parse_sfi(synctex_scanner_p scanner) {
5061     synctex_status_t status = SYNCTEX_STATUS_OK;
5062     synctex_zs_s zs = {0,0};
5063     synctex_ns_s input = SYNCTEX_NS_NULL;
5064     synctex_node_p sheet = NULL;
5065     synctex_node_p form = NULL;
5066     synctex_node_p parent = NULL;
5067     synctex_node_p child = NULL;
5068     /*
5069      *  Experimentations lead to the forthcoming conclusion:
5070      *  Sometimes, the first nodes of a box have the wrong line number.
5071      *  These are only boundary (x) nodes.
5072      *  We observed that boundary nodes do have the proper line number
5073      *  if they follow a node with a different type.
5074      *  We keep track of these leading x nodes in a handle tree.
5075      */
5076     synctex_node_p x_handle = NULL;
5077 #   define SYNCTEX_RETURN(STATUS) \
5078         synctex_node_free(x_handle);\
5079         return STATUS
5080     synctex_node_p last_k = NULL;
5081     synctex_node_p last_g = NULL;
5082     synctex_ns_s ns = SYNCTEX_NS_NULL;
5083     int form_depth = 0;
5084     int ignored_form_depth = 0;
5085     synctex_bool_t try_input = synctex_YES;
5086     if (!(x_handle = _synctex_new_handle(scanner))) {
5087         SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
5088     }
5089 #	ifdef SYNCTEX_NOTHING
5090 #       pragma mark MAIN LOOP
5091 #   endif
5092 main_loop:
5093     status = SYNCTEX_STATUS_OK;
5094     sheet = form = parent = child = NULL;
5095 #   define SYNCTEX_START_SCAN(WHAT)\
5096 (*SYNCTEX_CUR == SYNCTEX_CHAR_##WHAT)
5097     if (SYNCTEX_CUR<SYNCTEX_END) {
5098         if (SYNCTEX_START_SCAN(BEGIN_FORM)) {
5099 #	ifdef SYNCTEX_NOTHING
5100 #       pragma mark + SCAN FORM
5101 #   endif
5102         scan_form:
5103             ns = _synctex_parse_new_form(scanner);
5104             if (ns.status == SYNCTEX_STATUS_OK) {
5105                 ++form_depth;
5106                 if (_synctex_tree_parent(form)) {
5107                     /* This form is already being parsed */
5108                     ++ignored_form_depth;
5109                     goto ignore_loop;
5110                 }
5111                 _synctex_tree_set_parent(ns.node,form);
5112                 form = ns.node;
5113                 parent = form;
5114                 child = NULL;
5115                 last_k = last_g = NULL;
5116                 goto content_loop;
5117             }
5118             if (form || sheet) {
5119                 last_k = last_g = NULL;
5120                 goto content_loop;
5121             }
5122             try_input = synctex_YES;
5123             goto main_loop;
5124         } else if (SYNCTEX_START_SCAN(BEGIN_SHEET)) {
5125 #	ifdef SYNCTEX_NOTHING
5126 #       pragma mark + SCAN SHEET
5127 #   endif
5128             try_input = synctex_YES;
5129             ns = _synctex_parse_new_sheet(scanner);
5130             if (ns.status == SYNCTEX_STATUS_OK) {
5131                 sheet = ns.node;
5132                 parent = sheet;
5133                 last_k = last_g = NULL;
5134                 goto content_loop;
5135             }
5136             goto main_loop;
5137         } else if (SYNCTEX_START_SCAN(ANCHOR)) {
5138 #	ifdef SYNCTEX_NOTHING
5139 #       pragma mark + SCAN ANCHOR
5140 #   endif
5141         scan_anchor:
5142             ++SYNCTEX_CUR;
5143             if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
5144                 _synctex_error("Missing anchor.");
5145                 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
5146             }
5147             if (form || sheet) {
5148                 last_k = last_g = NULL;
5149                 goto content_loop;
5150             }
5151             try_input = synctex_YES;
5152             goto main_loop;
5153         } else if (SYNCTEX_START_SCAN(ANCHOR)) {
5154 #	ifdef SYNCTEX_NOTHING
5155 #       pragma mark + SCAN COMMENT
5156 #   endif
5157             ++SYNCTEX_CUR;
5158             _synctex_next_line(scanner);
5159             try_input = synctex_YES;
5160             goto main_loop;
5161         } else if (try_input) {
5162 #	ifdef SYNCTEX_NOTHING
5163 #       pragma mark + SCAN INPUT
5164 #   endif
5165             try_input = synctex_NO;
5166             do {
5167                 input = __synctex_parse_new_input(scanner);
5168             } while (input.status == SYNCTEX_STATUS_OK);
5169             goto main_loop;
5170         }
5171         status = _synctex_match_string(scanner,"Postamble:");
5172         if (status==SYNCTEX_STATUS_OK) {
5173             scanner->flags.postamble = 1;
5174             SYNCTEX_RETURN(status);
5175         }
5176         status = _synctex_next_line(scanner);
5177         if (status<SYNCTEX_STATUS_OK) {
5178             SYNCTEX_RETURN(status);
5179         }
5180    }
5181     /* At least 1 more character */
5182     zs = _synctex_buffer_get_available_size(scanner,1);
5183     if (zs.size == 0){
5184         _synctex_error("Uncomplete synctex file, postamble missing.");
5185         SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
5186     }
5187     goto main_loop;
5188     /*  Unreachable. */
5189 #	ifdef SYNCTEX_NOTHING
5190 #       pragma mark IGNORE LOOP
5191 #   endif
5192 ignore_loop:
5193     ns = SYNCTEX_NS_NULL;
5194     if (SYNCTEX_CUR<SYNCTEX_END) {
5195         if (SYNCTEX_START_SCAN(BEGIN_FORM)) {
5196             ++ignored_form_depth;
5197         } else if (SYNCTEX_START_SCAN(END_FORM)) {
5198             --ignored_form_depth;
5199         }
5200         if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
5201             _synctex_error("Uncomplete container.");
5202             SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
5203         }
5204     } else {
5205         zs = _synctex_buffer_get_available_size(scanner,1);
5206         if (zs.size == 0){
5207             _synctex_error("Uncomplete synctex file, postamble missing.");
5208             SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
5209         }
5210     }
5211     if (ignored_form_depth) {
5212         goto ignore_loop;
5213     } else {
5214         last_k = last_g = NULL;
5215         goto content_loop;
5216     }
5217 
5218 #	ifdef SYNCTEX_NOTHING
5219 #       pragma mark CONTENT LOOP
5220 #   endif
5221 content_loop:
5222     /*  Either in a form, a sheet or a box.
5223      *  - in a sheet, "{" is not possible, only boxes and "}" at top level.
5224      *  - in a form, "{" is not possible, only boxes, "<" and ">" at top level.
5225      *  - in a box, the unique possibility is '<', '[', '(' or ">".
5226      *  We still keep the '(' for a sheet, because that dos not cost too much.
5227      *  We must also consider void boxes as children.
5228      */
5229     /* forms are everywhere */
5230     ns = SYNCTEX_NS_NULL;
5231 #if SYNCTEX_VERBOSE
5232     synctex_scanner_set_display_switcher(scanner,-1);
5233     printf("NEW CONTENT LOOP\n");
5234 #if SYNCTEX_DEBUG>500
5235     synctex_node_display(sheet);
5236 #endif
5237 #endif
5238     if (SYNCTEX_CUR<SYNCTEX_END) {
5239         if (SYNCTEX_START_SCAN(BEGIN_FORM)) {
5240             goto scan_form;
5241         } else if (SYNCTEX_START_SCAN(BEGIN_VBOX)) {
5242 #	ifdef SYNCTEX_NOTHING
5243 #       pragma mark + SCAN VBOX
5244 #   endif
5245             ns = _synctex_parse_new_vbox(scanner);
5246             if (ns.status == SYNCTEX_STATUS_OK) {
5247                 x_handle = _synctex_new_handle_with_child(x_handle);
5248                 if (child) {
5249                     _synctex_node_set_sibling(child,ns.node);
5250                 } else {
5251                     _synctex_node_set_child(parent,ns.node);
5252                 }
5253                 parent = ns.node;
5254                 child = _synctex_tree_last(parent);
5255 #   if SYNCTEX_VERBOSE
5256                 synctex_node_log(parent);
5257 #   endif
5258                 input.node = _synctex_input_register_line(input.node,parent);
5259                 last_k = last_g = NULL;
5260                 goto content_loop;
5261             }
5262         } else if (SYNCTEX_START_SCAN(END_VBOX)) {
5263             if (synctex_node_type(parent) == synctex_node_type_vbox) {
5264 #	ifdef SYNCTEX_NOTHING
5265 #       pragma mark + SCAN XOBV
5266 #   endif
5267                 ++SYNCTEX_CUR;
5268                 if (NULL == _synctex_tree_child(parent) && !form) {
5269                     /*  only void v boxes are friends */
5270                     _synctex_node_make_friend_tlc(parent);
5271                 }
5272                 child = parent;
5273                 parent = _synctex_tree_parent(child);
5274                 if (!form) {
5275                     _synctex_handle_make_friend_tlc(x_handle);
5276                 }
5277                 x_handle = _synctex_handle_pop_child(x_handle);
5278                 _synctex_handle_set_tlc(x_handle,child,!form);
5279 #   if SYNCTEX_VERBOSE
5280                 synctex_node_log(child);
5281 #   endif
5282                 if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
5283                     _synctex_error("Uncomplete container.");
5284                     SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
5285                 }
5286                 last_k = last_g = NULL;
5287                 goto content_loop;
5288             }
5289         } else if (SYNCTEX_START_SCAN(BEGIN_HBOX)) {
5290 #	ifdef SYNCTEX_NOTHING
5291 #       pragma mark + SCAN HBOX
5292 #   endif
5293 #   if defined(SYNCTEX_USE_CHARINDEX)
5294             synctex_charindex_t char_index = (synctex_charindex_t)(scanner->reader->charindex_offset+SYNCTEX_CUR-SYNCTEX_START);
5295             synctex_lineindex_t line_index = scanner->reader->line_number;
5296 #   endif
5297             ns = _synctex_parse_new_hbox(scanner);
5298             if (ns.status == SYNCTEX_STATUS_OK) {
5299                 x_handle = _synctex_new_handle_with_child(x_handle);
5300                 if (child) {
5301                     _synctex_node_set_sibling(child,ns.node);
5302                 } else {
5303                     _synctex_node_set_child(parent,ns.node);
5304                 }
5305                 parent = ns.node;
5306                 /*  add a box boundary node at the start */
5307                 if ((child = _synctex_new_box_bdry(scanner))) {
5308 #   if defined(SYNCTEX_USE_CHARINDEX)
5309                     child->line_index=line_index;
5310                     child->char_index=char_index;
5311 #   endif
5312                     _synctex_node_set_child(parent,child);
5313                     _synctex_data_set_tlchv(child,parent);
5314                     if (!form) {
5315                         __synctex_node_make_friend_tlc(child);
5316                     }
5317                 } else {
5318                     _synctex_error("Can't create box bdry record.");
5319                 }
5320 #   if SYNCTEX_VERBOSE
5321                 synctex_node_log(parent);
5322 #   endif
5323                 input.node = _synctex_input_register_line(input.node,parent);
5324                 last_k = last_g = NULL;
5325                 goto content_loop;
5326             }
5327         } else if (SYNCTEX_START_SCAN(END_HBOX)) {
5328             if (synctex_node_type(parent) == synctex_node_type_hbox) {
5329 #	ifdef SYNCTEX_NOTHING
5330 #       pragma mark + SCAN XOBH
5331 #   endif
5332                 ++SYNCTEX_CUR;
5333                 /*  setting the next horizontal box at the end ensures
5334                  * that a child is recorded before any of its ancestors.
5335                  */
5336                 if (form == NULL /* && sheet != NULL*/ ) {
5337                     _synctex_tree_set_next_hbox(parent,_synctex_tree_next_hbox(sheet));
5338                     _synctex_tree_set_next_hbox(sheet,parent);
5339                 }
5340                 {
5341                     /*  Update the mean line number */
5342                     synctex_node_p node = _synctex_tree_child(parent);
5343                     synctex_node_p sibling = NULL;
5344                     /*  Ignore the first node (a box_bdry) */
5345                     if (node && (sibling = __synctex_tree_sibling(node))) {
5346                         unsigned int node_weight = 0;
5347                         unsigned int cumulated_line_numbers = 0;
5348                         _synctex_data_set_line(node, _synctex_data_line(sibling));
5349                         node = sibling;
5350                         do {
5351                             if (synctex_node_type(node)==synctex_node_type_hbox) {
5352                                 if (_synctex_data_weight(node)) {
5353                                     node_weight += _synctex_data_weight(node);
5354                                     cumulated_line_numbers += _synctex_data_mean_line(node)*_synctex_data_weight(node);
5355                                 } else {
5356                                     ++node_weight;
5357                                     cumulated_line_numbers += _synctex_data_mean_line(node);
5358                                 }
5359                             } else {
5360                                 ++node_weight;
5361                                 cumulated_line_numbers += synctex_node_line(node);
5362                             }
5363                         } while ((node = __synctex_tree_sibling(node)));
5364                         _synctex_data_set_mean_line(parent,(cumulated_line_numbers + node_weight/2)/node_weight);
5365                         _synctex_data_set_weight(parent,node_weight);
5366                     } else {
5367                         _synctex_data_set_mean_line(parent,_synctex_data_line(parent));
5368                         _synctex_data_set_weight(parent,1);
5369                     }
5370                     if ((sibling = _synctex_new_box_bdry(scanner))) {
5371 #   if defined(SYNCTEX_USE_CHARINDEX)
5372                         sibling->line_index=child->line_index;
5373                         sibling->char_index=child->char_index;
5374 #   endif
5375                         _synctex_node_set_sibling(child,sibling);
5376                         {
5377                             synctex_node_p N = child;
5378                             while (synctex_node_type(N) == synctex_node_type_ref) {
5379                                 N = _synctex_tree_arg_sibling(N);
5380                             }
5381                             _synctex_data_set_tlc(sibling,N);
5382                         }
5383                         _synctex_data_set_h(sibling,_synctex_data_h_V(parent)+_synctex_data_width_V(parent));
5384                         _synctex_data_set_v(sibling,_synctex_data_v_V(parent));
5385                         child = sibling;
5386                     } else {
5387                         _synctex_error("Can't create box bdry record.");
5388                     }
5389                     sibling = _synctex_tree_child(parent);
5390                     _synctex_data_set_point(sibling,_synctex_data_point_V(parent));
5391                     if (last_k && last_g && (child = synctex_node_child(parent))) {
5392                         /* Find the node preceeding last_k */
5393                         synctex_node_p next;
5394                         while ((next = __synctex_tree_sibling(child))) {
5395                             if (next == last_k) {
5396                                 _synctex_data_set_tlc(last_k,child);
5397                                 _synctex_data_set_tlc(last_g,child);
5398                                 break;
5399                             }
5400                             child = next;
5401                         }
5402                     }
5403                     child = parent;
5404                     parent = _synctex_tree_parent(child);
5405                     if (!form) {
5406                         _synctex_handle_make_friend_tlc(x_handle);
5407                     }
5408                     x_handle = _synctex_handle_pop_child(x_handle);
5409                     _synctex_handle_set_tlc(x_handle,child,!form);
5410                     _synctex_make_hbox_contain_box(parent,                                    _synctex_data_box_V(child));
5411 #   if SYNCTEX_VERBOSE
5412                     synctex_node_log(child);
5413 #   endif
5414                 }
5415                 if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
5416                     _synctex_error("Uncomplete container.");
5417                     SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
5418                 }
5419                 last_k = last_g = NULL;
5420                 goto content_loop;
5421             }
5422         } else if (SYNCTEX_START_SCAN(VOID_VBOX)) {
5423 #	ifdef SYNCTEX_NOTHING
5424 #       pragma mark + SCAN VOID VBOX
5425 #   endif
5426             ns = _synctex_parse_new_void_vbox(scanner);
5427             if (ns.status == SYNCTEX_STATUS_OK) {
5428                 if (child) {
5429                     _synctex_node_set_sibling(child,ns.node);
5430                 } else {
5431                     _synctex_node_set_child(parent,ns.node);
5432                 }
5433                 child = ns.node;
5434                 _synctex_handle_set_tlc(x_handle, child,!form);
5435 #   if SYNCTEX_VERBOSE
5436                 synctex_node_log(child);
5437 #   endif
5438                 input.node = _synctex_input_register_line(input.node,child);
5439                 last_k = last_g = NULL;
5440                 goto content_loop;
5441             }
5442         } else if (SYNCTEX_START_SCAN(VOID_HBOX)) {
5443 #	ifdef SYNCTEX_NOTHING
5444 #       pragma mark + SCAN VOID HBOX
5445 #   endif
5446             ns = _synctex_parse_new_void_hbox(scanner);
5447             if (ns.status == SYNCTEX_STATUS_OK) {
5448                 if (_synctex_data_width(ns.node)<0) {
5449                     printf("Negative width\n");
5450                 }
5451                 if (child) {
5452                     _synctex_node_set_sibling(child,ns.node);
5453                 } else {
5454                     _synctex_node_set_child(parent,ns.node);
5455                 }
5456                 child = ns.node;
5457                 _synctex_handle_set_tlc(x_handle, child,!form);
5458                 _synctex_make_hbox_contain_box(parent,_synctex_data_box(child));
5459 #   if SYNCTEX_VERBOSE
5460                 synctex_node_log(child);
5461 #   endif
5462                 input.node = _synctex_input_register_line(input.node,child);
5463                 last_k = last_g = NULL;
5464                 goto content_loop;
5465             }
5466         } else if (SYNCTEX_START_SCAN(KERN)) {
5467 #	ifdef SYNCTEX_NOTHING
5468 #       pragma mark + SCAN KERN
5469 #   endif
5470             ns = _synctex_parse_new_kern(scanner);
5471             if (ns.status == SYNCTEX_STATUS_OK) {
5472                 if (child) {
5473                     _synctex_node_set_sibling(child,ns.node);
5474                 } else {
5475                     _synctex_node_set_child(parent,ns.node);
5476                 }
5477                 child = ns.node;
5478                 if (!form) {
5479                     __synctex_node_make_friend_tlc(child);
5480                 }
5481                 _synctex_handle_set_tlc(x_handle, child,!form);
5482                 _synctex_make_hbox_contain_box(parent,_synctex_data_xob(child));
5483 #   if SYNCTEX_VERBOSE
5484                 synctex_node_log(child);
5485 #   endif
5486                 input.node = _synctex_input_register_line(input.node,child);
5487                 last_k = child;
5488                 last_g = NULL;
5489                 goto content_loop;
5490             }
5491         } else if (SYNCTEX_START_SCAN(GLUE)) {
5492 #	ifdef SYNCTEX_NOTHING
5493 #       pragma mark + SCAN GLUE
5494 #   endif
5495             ns = _synctex_parse_new_glue(scanner);
5496             if (ns.status == SYNCTEX_STATUS_OK) {
5497                 if (child) {
5498                     _synctex_node_set_sibling(child,ns.node);
5499                 } else {
5500                     _synctex_node_set_child(parent,ns.node);
5501                 }
5502                 child = ns.node;
5503                 if (!form) {
5504                     __synctex_node_make_friend_tlc(child);
5505                 }
5506                 _synctex_handle_set_tlc(x_handle, child,!form);
5507                 _synctex_make_hbox_contain_point(parent,_synctex_data_point(child));
5508 #   if SYNCTEX_VERBOSE
5509                 synctex_node_log(child);
5510 #   endif
5511                 input.node = _synctex_input_register_line(input.node,child);
5512                 if (last_k) {
5513                     last_g = child;
5514                 } else {
5515                     last_k = last_g = NULL;
5516                 }
5517                 goto content_loop;
5518             }
5519         } else if (SYNCTEX_START_SCAN(RULE)) {
5520 #	ifdef SYNCTEX_NOTHING
5521 #       pragma mark + SCAN RULE
5522 #   endif
5523             ns = _synctex_parse_new_rule(scanner);
5524             if (ns.status == SYNCTEX_STATUS_OK) {
5525                 if (child) {
5526                     _synctex_node_set_sibling(child,ns.node);
5527                 } else {
5528                     _synctex_node_set_child(parent,ns.node);
5529                 }
5530                 child = ns.node;
5531                 if (!form) {
5532                     __synctex_node_make_friend_tlc(child);
5533                 }
5534                 _synctex_handle_set_tlc(x_handle, child,!form);
5535                 /* Rules are sometimes far too big
5536 _synctex_make_hbox_contain_box(parent,_synctex_data_box(child));
5537                  */
5538 #   if SYNCTEX_VERBOSE
5539                 synctex_node_log(child);
5540 #   endif
5541                 input.node = _synctex_input_register_line(input.node,child);
5542                 last_k = last_g = NULL;
5543                 goto content_loop;
5544             }
5545         } else if (SYNCTEX_START_SCAN(MATH)) {
5546 #	ifdef SYNCTEX_NOTHING
5547 #       pragma mark + SCAN MATH
5548 #   endif
5549             ns = _synctex_parse_new_math(scanner);
5550             if (ns.status == SYNCTEX_STATUS_OK) {
5551                 if (child) {
5552                     _synctex_node_set_sibling(child,ns.node);
5553                 } else {
5554                     _synctex_node_set_child(parent,ns.node);
5555                 }
5556                 child = ns.node;
5557                 if (!form) {
5558                     __synctex_node_make_friend_tlc(child);
5559                 }
5560                 _synctex_handle_set_tlc(x_handle, child,!form);
5561                 _synctex_make_hbox_contain_point(parent,_synctex_data_point(child));
5562 #   if SYNCTEX_VERBOSE
5563                 synctex_node_log(child);
5564 #   endif
5565                 input.node = _synctex_input_register_line(input.node,child);
5566                 last_k = last_g = NULL;
5567                 goto content_loop;
5568             }
5569         } else if (SYNCTEX_START_SCAN(FORM_REF)) {
5570 #	ifdef SYNCTEX_NOTHING
5571 #       pragma mark + SCAN FORM REF
5572 #   endif
5573 #if SYNCTEX_DEBUG>500
5574             synctex_node_display(parent);
5575             synctex_node_display(child);
5576 #endif
5577             ns = _synctex_parse_new_ref(scanner);
5578             if (ns.status == SYNCTEX_STATUS_OK) {
5579                 if (child) {
5580                     _synctex_node_set_sibling(child,ns.node);
5581                 } else {
5582                     _synctex_node_set_child(parent,ns.node);
5583                 }
5584                 child = ns.node;
5585                 if (form) {
5586                     if (scanner->ref_in_form) {
5587                         synctex_tree_set_friend(child,scanner->ref_in_form);
5588                     }
5589                     scanner->ref_in_form = child;
5590                 } else {
5591                     if (scanner->ref_in_sheet) {
5592                         synctex_tree_set_friend(child,scanner->ref_in_sheet);
5593                     }
5594                     scanner->ref_in_sheet = child;
5595                 }
5596 #   if SYNCTEX_VERBOSE
5597                 synctex_node_log(child);
5598 #   endif
5599                 last_k = last_g = NULL;
5600                 goto content_loop;
5601             }
5602         } else if (SYNCTEX_START_SCAN(BOUNDARY)) {
5603 #	ifdef SYNCTEX_NOTHING
5604 #       pragma mark + SCAN BOUNDARY
5605 #   endif
5606             ns = _synctex_parse_new_boundary(scanner);
5607             if (ns.status == SYNCTEX_STATUS_OK) {
5608                 if (child) {
5609                     _synctex_node_set_sibling(child,ns.node);
5610                 } else {
5611                     _synctex_node_set_child(parent,ns.node);
5612                 }
5613                 if (synctex_node_type(child)==synctex_node_type_box_bdry
5614                     || _synctex_tree_target(x_handle)) {
5615                     child = _synctex_tree_reset_child(x_handle);
5616                     child = _synctex_new_handle_with_child(child);
5617                     __synctex_tree_set_sibling(child, x_handle);
5618                     x_handle = child;
5619                     _synctex_tree_set_target(x_handle,ns.node);
5620                 } else if (!form) {
5621                     __synctex_node_make_friend_tlc(ns.node);
5622                 }
5623                 child = ns.node;
5624                 _synctex_make_hbox_contain_point(parent,_synctex_data_point(child));
5625 #   if SYNCTEX_VERBOSE
5626                 synctex_node_log(child);
5627 #   endif
5628                 input.node = _synctex_input_register_line(input.node,child);
5629                 last_k = last_g = NULL;
5630                 goto content_loop;
5631             }
5632         } else if (SYNCTEX_START_SCAN(CHARACTER)) {
5633 #	ifdef SYNCTEX_NOTHING
5634 #       pragma mark + SCAN CHARACTER
5635 #   endif
5636             ++SYNCTEX_CUR;
5637             if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
5638                 _synctex_error("Missing end of container.");
5639                 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
5640             }
5641             last_k = last_g = NULL;
5642             goto content_loop;
5643         } else if (SYNCTEX_START_SCAN(ANCHOR)) {
5644 #	ifdef SYNCTEX_NOTHING
5645 #       pragma mark + SCAN ANCHOR
5646 #   endif
5647             goto scan_anchor;
5648         } else if (SYNCTEX_START_SCAN(END_SHEET)) {
5649             if (sheet && parent == sheet) {
5650 #	ifdef SYNCTEX_NOTHING
5651 #       pragma mark + SCAN TEEHS
5652 #   endif
5653                 ++SYNCTEX_CUR;
5654                 if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
5655                     _synctex_error("Missing anchor.");
5656                 }
5657                 parent = sheet = NULL;
5658                 goto main_loop;
5659             }
5660         } else if (SYNCTEX_START_SCAN(END_FORM)) {
5661             if (parent == form && form_depth > 0) {
5662 #	ifdef SYNCTEX_NOTHING
5663 #       pragma mark + SCAN MROF
5664 #   endif
5665                 ++SYNCTEX_CUR;
5666                 --form_depth;
5667                 if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK
5668                     && (form_depth || sheet)) {
5669                     _synctex_error("Missing end of container.");
5670                     SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
5671                 }
5672                 if ((parent = _synctex_tree_parent(form))) {
5673                     _synctex_tree_reset_parent(form);
5674                     child = form;
5675                     form = parent;
5676                     goto content_loop;
5677                 } else if (sheet) {
5678                     form = NULL;
5679                     parent = sheet;
5680                     child = synctex_node_last_sibling(child);
5681                     goto content_loop;
5682                 }
5683                 goto main_loop;
5684             }
5685         }
5686         _synctex_error("Ignored record <%.20s...>(line %i)\n",SYNCTEX_CUR, scanner->reader->line_number+1);
5687         if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
5688             _synctex_error("Missing end of sheet/form.");
5689             SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
5690         }
5691         last_k = last_g = NULL;
5692         goto content_loop;
5693     }
5694     zs = _synctex_buffer_get_available_size(scanner,1);
5695     if (zs.size == 0){
5696         _synctex_error("Uncomplete synctex file, postamble missing.");
5697         SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
5698     }
5699     last_k = last_g = NULL;
5700     goto content_loop;
5701 }
5702 #undef SYNCTEX_RETURN
5703 /**
5704  *  Replace ref in its tree hierarchy by a single box
5705  *  proxy to the contents of the associated form.
5706  *  - argument ref: a ref node with no friend
5707  *  - return the proxy created.
5708  *  - note: Does nothing if ref is not owned.
5709  *  - note: On return, ref will have no parent nor sibling.
5710  *      The caller is responsible for releasing ref.
5711  *  - note: this is where root proxies are created.
5712  *  - note: the target of the root proxy is the content
5713  *      of a form.
5714  */
__synctex_replace_ref(synctex_node_p ref)5715 SYNCTEX_INLINE static synctex_ns_s __synctex_replace_ref(synctex_node_p ref) {
5716     synctex_ns_s ns = {NULL,SYNCTEX_STATUS_OK};
5717     synctex_node_p parent;
5718     if ((parent = _synctex_tree_parent(ref))) {
5719         synctex_node_p sibling = __synctex_tree_reset_sibling(ref);
5720         synctex_node_p arg_sibling = synctex_node_arg_sibling(ref);
5721         /*  arg_sibling != NULL because the child of a box
5722          *  is always a box boundary, not a ref. */
5723         synctex_node_p target = synctex_form_content(ref->class_->scanner, _synctex_data_tag(ref));
5724         /*  The target is a single node (box)
5725          *  with children and no siblings. */
5726         if ((ns.node = __synctex_new_proxy_from_ref_to(ref, target))) {
5727             /*  Insert this proxy instead of ref. */
5728             _synctex_node_set_sibling(arg_sibling,ns.node);
5729             /*  Then append the original sibling of ref. */
5730             _synctex_node_set_sibling(ns.node,sibling);
5731 #   if defined(SYNCTEX_USE_CHARINDEX)
5732             if (synctex_node_type(sibling) == synctex_node_type_box_bdry) {
5733                 /*  The sibling is the last box boundary
5734                  *  which may have a less accurate information */
5735                 sibling->char_index = arg_sibling->char_index;
5736                 sibling->line_index = arg_sibling->line_index;
5737             }
5738 #endif
5739 #if SYNCTEX_DEBUG>500
5740             printf("!  Ref replacement:\n");
5741             synctex_node_log(ref);
5742             synctex_node_display(synctex_node_sibling(ref));
5743 #endif
5744         } else /*  simply remove ref */ {
5745             _synctex_tree_set_sibling(arg_sibling,sibling);
5746         }
5747         __synctex_tree_reset_parent(ref);
5748     } else {
5749         _synctex_error("!  Missing parent in __synctex_replace_ref. "
5750                        "Please report.");
5751         ns.status = SYNCTEX_STATUS_BAD_ARGUMENT;
5752     }
5753     return ns;
5754 }
5755 /**
5756  *  - argument ref: is the starting point of a linked list
5757  *      of refs. The link is made through the friend field.
5758  *  - returns: the status and the list of all the proxies
5759  *      created. The link is made through the friend field.
5760  *  - note: All refs are freed
5761  */
_synctex_post_process_ref(synctex_node_p ref)5762 SYNCTEX_INLINE static synctex_ns_s _synctex_post_process_ref(synctex_node_p ref) {
5763     synctex_ns_s ns = {NULL, SYNCTEX_STATUS_OK};
5764     while (ref) {
5765         synctex_node_p next_ref = _synctex_tree_reset_friend(ref);
5766         synctex_ns_s sub_ns = __synctex_replace_ref(ref);
5767         if (sub_ns.status < ns.status) {
5768             ns.status = sub_ns.status;
5769         } else {
5770             /*  Insert all the created proxies in the list
5771              *  sub_ns.node is the last friend,
5772              */
5773             synctex_tree_set_friend(sub_ns.node,ns.node);
5774             ns.node = sub_ns.node;
5775         }
5776         synctex_node_free(ref);
5777         ref = next_ref;
5778     }
5779     return ns;
5780 }
5781 typedef synctex_node_p (* synctex_processor_f)(synctex_node_p node);
5782 /**
5783  *  Apply the processor f to the tree hierarchy rooted at proxy.
5784  *  proxy has replaced a form ref, no children yet.
5785  *  As a side effect all the hierarchy of nodes will be created.
5786  */
_synctex_post_process_proxy(synctex_node_p proxy,synctex_processor_f f)5787 SYNCTEX_INLINE static synctex_status_t _synctex_post_process_proxy(synctex_node_p proxy, synctex_processor_f f) {
5788     while(proxy) {
5789         synctex_node_p next_proxy = _synctex_tree_friend(proxy);
5790         synctex_node_p halt = __synctex_tree_sibling(proxy);
5791         /*  if proxy is the last sibling, halt is NULL.
5792          *  Find what should be a next node,
5793          *  without creating new nodes. */
5794         if (!halt) {
5795             synctex_node_p parent = _synctex_tree_parent(proxy);
5796             halt = __synctex_tree_sibling(parent);
5797             while (!halt && parent) {
5798                 parent = _synctex_tree_parent(parent);
5799                 halt = __synctex_tree_sibling(parent);
5800             }
5801         }
5802         do {
5803 #if SYNCTEX_DEBUG>500
5804             printf("POST PROCESSING %s\n",_synctex_node_abstract(proxy));
5805             {
5806                 int i,j = 0;
5807                 for (i=0;i<proxy->class_->scanner->number_of_lists;++i) {
5808                     synctex_node_p N = proxy->class_->scanner->lists_of_friends[i];
5809                     do {
5810                         if (N==proxy) {
5811                             ++j;
5812                             printf("%s",_synctex_node_abstract(N));
5813                         }
5814                     } while ((N = _synctex_tree_friend(N)));
5815                 }
5816                 if (j) {
5817                     printf("\nBeforehand %i match\n",j);
5818                 }
5819             }
5820 #endif
5821             f(proxy);
5822 #if SYNCTEX_DEBUG>500
5823             {
5824                 int i,j = 0;
5825                 for (i=0;i<proxy->class_->scanner->number_of_lists;++i) {
5826                     synctex_node_p N = proxy->class_->scanner->lists_of_friends[i];
5827                     do {
5828                         if (N==proxy) {
5829                             ++j;
5830                             printf("%s",_synctex_node_abstract(N));
5831                         }
5832                     } while ((N = _synctex_tree_friend(N)));
5833                 }
5834                 if (j) {
5835                     printf("\n%i match\n",j);
5836                 }
5837             }
5838 #endif
5839             /*  Side effect: create the hierarchy on the fly */
5840             proxy = synctex_node_next(proxy); /*  Change is here */
5841 #if SYNCTEX_DEBUG>500
5842             if (proxy) {
5843                 int i,j = 0;
5844                 for (i=0;i<proxy->class_->scanner->number_of_lists;++i) {
5845                     synctex_node_p N = proxy->class_->scanner->lists_of_friends[i];
5846                     do {
5847                         if (N==proxy) {
5848                             ++j;
5849                             printf("%s",_synctex_node_abstract(N));
5850                         }
5851                     } while ((N = _synctex_tree_friend(N)));
5852                 }
5853                 if (j) {
5854                     printf("\nnext %i match\n",j);
5855                 }
5856             }
5857 #endif
5858         } while (proxy && proxy != halt);
5859         proxy = next_proxy;
5860     }
5861     return SYNCTEX_STATUS_OK;
5862 }
5863 /**
5864  *  Replace all the form refs by root box proxies.
5865  *  Create the node hierarchy and update the friends.
5866  *  On entry, the refs are collected as a friend list
5867  *  in either a form or a sheet
5868  *  - parameter: the owning scanner
5869  */
_synctex_post_process(synctex_scanner_p scanner)5870 SYNCTEX_INLINE static synctex_status_t _synctex_post_process(synctex_scanner_p scanner) {
5871     synctex_status_t status = SYNCTEX_STATUS_OK;
5872     synctex_ns_s ns = {NULL,SYNCTEX_STATUS_NOT_OK};
5873 #if SYNCTEX_DEBUG>500
5874     printf("!  entering _synctex_post_process.\n");
5875     synctex_node_display(scanner->sheet);
5876     synctex_node_display(scanner->form);
5877 #endif
5878     /*  replace form refs inside forms by box proxies */
5879     ns = _synctex_post_process_ref(scanner->ref_in_form);
5880     scanner->ref_in_form = NULL;/*  it was just released */
5881     if (ns.status<status) {
5882         status = ns.status;
5883     }
5884 #if SYNCTEX_DEBUG>500
5885     printf("!  ref replaced in form _synctex_post_process.\n");
5886     synctex_node_display(scanner->form);
5887 #endif
5888     /*  Create all the form proxy nodes on the fly.
5889      *  ns.node is the root of the list of
5890      *  newly created proxies.
5891      *  There might be a problem with cascading proxies.
5892      *  In order to be properly managed, the data must
5893      *  be organized in the right way.
5894      *  The inserted form must be defined before
5895      *  the inserting one. *TeX will take care of that.   */
5896     ns.status = _synctex_post_process_proxy(ns.node,&_synctex_tree_reset_friend);
5897     if (ns.status<status) {
5898         status = ns.status;
5899     }
5900     /*  replace form refs inside sheets by box proxies */
5901     ns = _synctex_post_process_ref(scanner->ref_in_sheet);
5902     if (ns.status<status) {
5903         status = ns.status;
5904     }
5905     scanner->ref_in_sheet = NULL;
5906 #if SYNCTEX_DEBUG>500
5907     printf("!  ref replaced in sheet _synctex_post_process.\n");
5908     synctex_node_display(scanner->sheet);
5909 #endif
5910 #if 0
5911     {
5912         int i;
5913         for (i=0;i<scanner->number_of_lists;++i) {
5914             synctex_node_p P = ns.node;
5915             do {
5916                 synctex_node_p N = scanner->lists_of_friends[i];
5917                 do {
5918                     if (P == N) {
5919                         printf("Already registered.\n");
5920                         synctex_node_display(N);
5921                         break;
5922                     }
5923                 } while ((N = _synctex_tree_friend(N)));
5924             } while((P = _synctex_tree_friend(P)));
5925         }
5926     }
5927 #endif
5928 #if SYNCTEX_DEBUG>10000
5929     {
5930         int i;
5931         for (i=0;i<scanner->number_of_lists;++i) {
5932             synctex_node_p P = scanner->lists_of_friends[i];
5933             int j = 0;
5934             while (P) {
5935                 ++j;
5936                 synctex_node_log(P);
5937                 P = _synctex_tree_friend(P);
5938             }
5939             if (j) {
5940                 printf("friends %i -> # %i\n",i,j);
5941             }
5942         }
5943     }
5944 #endif
5945     ns.status = _synctex_post_process_proxy(ns.node,&__synctex_proxy_make_friend_and_next_hbox);
5946     if (ns.status<status) {
5947         status = ns.status;
5948     }
5949 #if SYNCTEX_DEBUG>500
5950     printf("!  exiting _synctex_post_process.\n");
5951     synctex_node_display(scanner->sheet);
5952     synctex_node_display(scanner->form);
5953     printf("!  display all.\n");
5954     synctex_node_display(scanner->sheet);
5955     synctex_node_display(scanner->form);
5956 #endif
5957     return status;
5958 }
5959 /*  Used when parsing the synctex file
5960  */
_synctex_scan_content(synctex_scanner_p scanner)5961 static synctex_status_t _synctex_scan_content(synctex_scanner_p scanner) {
5962     if (NULL == scanner) {
5963         return SYNCTEX_STATUS_BAD_ARGUMENT;
5964     }
5965     scanner->reader->lastv = -1;
5966     synctex_status_t status = 0;
5967     /*  Find where this section starts */
5968 content_not_found:
5969     status = _synctex_match_string(scanner,"Content:");
5970     if (status<SYNCTEX_STATUS_EOF) {
5971         return status;
5972     }
5973     if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
5974         _synctex_error("Uncomplete Content.");
5975         return SYNCTEX_STATUS_ERROR;
5976     }
5977     if (status == SYNCTEX_STATUS_NOT_OK) {
5978         goto content_not_found;
5979     }
5980     status = __synctex_parse_sfi(scanner);
5981     if (status == SYNCTEX_STATUS_OK) {
5982         status = _synctex_post_process(scanner);
5983     }
5984     return status;
5985 }
synctex_scanner_new()5986 synctex_scanner_p synctex_scanner_new() {
5987     synctex_scanner_p scanner =(synctex_scanner_p)_synctex_malloc(sizeof(synctex_scanner_s));
5988     if (scanner) {
5989         if (!(scanner->reader = _synctex_malloc(sizeof(synctex_reader_s)))) {
5990             _synctex_free(scanner);
5991             return NULL;
5992         }
5993 #	ifdef SYNCTEX_NOTHING
5994 #       pragma mark -
5995 #   endif
5996 #   define DEFINE_synctex_scanner_class(NAME)\
5997     scanner->class_[synctex_node_type_##NAME] = synctex_class_##NAME;\
5998 (scanner->class_[synctex_node_type_##NAME]).scanner = scanner
5999         DEFINE_synctex_scanner_class(input);
6000         DEFINE_synctex_scanner_class(sheet);
6001         DEFINE_synctex_scanner_class(form);
6002         DEFINE_synctex_scanner_class(hbox);
6003         DEFINE_synctex_scanner_class(void_hbox);
6004         DEFINE_synctex_scanner_class(vbox);
6005         DEFINE_synctex_scanner_class(void_vbox);
6006         DEFINE_synctex_scanner_class(kern);
6007         DEFINE_synctex_scanner_class(glue);
6008         DEFINE_synctex_scanner_class(rule);
6009         DEFINE_synctex_scanner_class(math);
6010         DEFINE_synctex_scanner_class(boundary);
6011         DEFINE_synctex_scanner_class(box_bdry);
6012         DEFINE_synctex_scanner_class(ref);
6013         DEFINE_synctex_scanner_class(proxy_hbox);
6014         DEFINE_synctex_scanner_class(proxy_vbox);
6015         DEFINE_synctex_scanner_class(proxy);
6016         DEFINE_synctex_scanner_class(proxy_last);
6017         DEFINE_synctex_scanner_class(handle);
6018         /*  set up the lists of friends */
6019         scanner->number_of_lists = 1024;
6020         scanner->lists_of_friends = (synctex_node_r)_synctex_malloc(scanner->number_of_lists*sizeof(synctex_node_p));
6021         if (NULL == scanner->lists_of_friends) {
6022             synctex_scanner_free(scanner);
6023             _synctex_error("malloc:2");
6024             return NULL;
6025         }
6026         scanner->display_switcher = 100;
6027         scanner->display_prompt = (char *)_synctex_display_prompt+strlen(_synctex_display_prompt)-1;
6028     }
6029     return scanner;
6030 }
6031 /*  Where the synctex scanner is created. */
synctex_scanner_new_with_output_file(const char * output,const char * build_directory,int parse)6032 synctex_scanner_p synctex_scanner_new_with_output_file(const char * output, const char * build_directory, int parse) {
6033     synctex_scanner_p scanner = synctex_scanner_new();
6034     if (NULL == scanner) {
6035         _synctex_error("malloc problem");
6036         return NULL;
6037     }
6038     if ((scanner->reader = synctex_reader_init_with_output_file(scanner->reader, output, build_directory))) {
6039         return parse? synctex_scanner_parse(scanner):scanner;
6040     }
6041     _synctex_error("No file?");
6042     return NULL;
6043 }
6044 
6045 /*  The scanner destructor
6046  */
synctex_scanner_free(synctex_scanner_p scanner)6047 int synctex_scanner_free(synctex_scanner_p scanner) {
6048     int node_count = 0;
6049     if (scanner) {
6050         if (SYNCTEX_FILE) {
6051             gzclose(SYNCTEX_FILE);
6052             SYNCTEX_FILE = NULL;
6053         }
6054         synctex_node_free(scanner->sheet);
6055         synctex_node_free(scanner->form);
6056         synctex_node_free(scanner->input);
6057         synctex_reader_free(scanner->reader);
6058         SYNCTEX_SCANNER_FREE_HANDLE(scanner);
6059         synctex_iterator_free(scanner->iterator);
6060         free(scanner->output_fmt);
6061         free(scanner->lists_of_friends);
6062 #if SYNCTEX_USE_NODE_COUNT>0
6063         node_count = scanner->node_count;
6064 #endif
6065         free(scanner);
6066     }
6067     return node_count;
6068 }
6069 
6070 /*  Where the synctex scanner parses the contents of the file. */
synctex_scanner_parse(synctex_scanner_p scanner)6071 synctex_scanner_p synctex_scanner_parse(synctex_scanner_p scanner) {
6072     synctex_status_t status = 0;
6073     if (!scanner || scanner->flags.has_parsed) {
6074         return scanner;
6075     }
6076     scanner->flags.has_parsed=1;
6077     scanner->pre_magnification = 1000;
6078     scanner->pre_unit = 8192;
6079     scanner->pre_x_offset = scanner->pre_y_offset = 578;
6080     /*  initialize the offset with a fake unprobable value,
6081      *  If there is a post scriptum section, this value will be overriden by the real life value */
6082     scanner->x_offset = scanner->y_offset = 6.027e23f;
6083     scanner->reader->line_number = 1;
6084 
6085     SYNCTEX_START = (char *)malloc(SYNCTEX_BUFFER_SIZE+1); /*  one more character for null termination */
6086     if (NULL == SYNCTEX_START) {
6087         _synctex_error("!  malloc error in synctex_scanner_parse.");
6088     bailey:
6089 #ifdef SYNCTEX_DEBUG
6090         return scanner;
6091 #else
6092         synctex_scanner_free(scanner);
6093         return NULL;
6094 #endif
6095     }
6096     synctex_scanner_set_display_switcher(scanner, 1000);
6097     SYNCTEX_END = SYNCTEX_START+SYNCTEX_BUFFER_SIZE;
6098     /*  SYNCTEX_END always points to a null terminating character.
6099      *  Maybe there is another null terminating character between SYNCTEX_CUR and SYNCTEX_END-1.
6100      *  At least, we are sure that SYNCTEX_CUR points to a string covering a valid part of the memory. */
6101     *SYNCTEX_END = '\0';
6102     SYNCTEX_CUR = SYNCTEX_END;
6103 #   if defined(SYNCTEX_USE_CHARINDEX)
6104     scanner->reader->charindex_offset = -SYNCTEX_BUFFER_SIZE;
6105 #   endif
6106     status = _synctex_scan_preamble(scanner);
6107     if (status<SYNCTEX_STATUS_OK) {
6108         _synctex_error("Bad preamble\n");
6109         goto bailey;
6110     }
6111     status = _synctex_scan_content(scanner);
6112     if (status<SYNCTEX_STATUS_OK) {
6113         _synctex_error("Bad content\n");
6114         goto bailey;
6115     }
6116     status = _synctex_scan_postamble(scanner);
6117     if (status<SYNCTEX_STATUS_OK) {
6118         _synctex_error("Bad postamble. Ignored\n");
6119     }
6120 #if SYNCTEX_DEBUG>500
6121     synctex_scanner_set_display_switcher(scanner, 100);
6122     synctex_node_display(scanner->sheet);
6123     synctex_node_display(scanner->form);
6124 #endif
6125     synctex_scanner_set_display_switcher(scanner, 1000);
6126     /*  Everything is finished, free the buffer, close the file */
6127     free((void *)SYNCTEX_START);
6128     SYNCTEX_START = SYNCTEX_CUR = SYNCTEX_END = NULL;
6129     gzclose(SYNCTEX_FILE);
6130     SYNCTEX_FILE = NULL;
6131     /*  Final tuning: set the default values for various parameters */
6132     /*  1 pre_unit = (scanner->pre_unit)/65536 pt = (scanner->pre_unit)/65781.76 bp
6133      * 1 pt = 65536 sp */
6134     if (scanner->pre_unit<=0) {
6135         scanner->pre_unit = 8192;
6136     }
6137     if (scanner->pre_magnification<=0) {
6138         scanner->pre_magnification = 1000;
6139     }
6140     if (scanner->unit <= 0) {
6141         /*  no post magnification */
6142         scanner->unit = scanner->pre_unit / 65781.76;/*  65781.76 or 65536.0*/
6143     } else {
6144         /*  post magnification */
6145         scanner->unit *= scanner->pre_unit / 65781.76;
6146     }
6147     scanner->unit *= scanner->pre_magnification / 1000.0;
6148     if (scanner->x_offset > 6e23) {
6149         /*  no post offset */
6150         scanner->x_offset = scanner->pre_x_offset * (scanner->pre_unit / 65781.76);
6151         scanner->y_offset = scanner->pre_y_offset * (scanner->pre_unit / 65781.76);
6152     } else {
6153         /*  post offset */
6154         scanner->x_offset /= 65781.76f;
6155         scanner->y_offset /= 65781.76f;
6156     }
6157     return scanner;
6158 #undef SYNCTEX_FILE
6159 }
6160 
6161 /*  Scanner accessors.
6162  */
synctex_scanner_pre_x_offset(synctex_scanner_p scanner)6163 int synctex_scanner_pre_x_offset(synctex_scanner_p scanner){
6164     return scanner?scanner->pre_x_offset:0;
6165 }
synctex_scanner_pre_y_offset(synctex_scanner_p scanner)6166 int synctex_scanner_pre_y_offset(synctex_scanner_p scanner){
6167     return scanner?scanner->pre_y_offset:0;
6168 }
synctex_scanner_x_offset(synctex_scanner_p scanner)6169 int synctex_scanner_x_offset(synctex_scanner_p scanner){
6170     return scanner?scanner->x_offset:0;
6171 }
synctex_scanner_y_offset(synctex_scanner_p scanner)6172 int synctex_scanner_y_offset(synctex_scanner_p scanner){
6173     return scanner?scanner->y_offset:0;
6174 }
synctex_scanner_magnification(synctex_scanner_p scanner)6175 float synctex_scanner_magnification(synctex_scanner_p scanner){
6176     return scanner?scanner->unit:1;
6177 }
synctex_scanner_display(synctex_scanner_p scanner)6178 void synctex_scanner_display(synctex_scanner_p scanner) {
6179     if (NULL == scanner) {
6180         return;
6181     }
6182     printf("The scanner:\noutput:%s\noutput_fmt:%s\nversion:%i\n",scanner->reader->output,scanner->output_fmt,scanner->version);
6183     printf("pre_unit:%i\nx_offset:%i\ny_offset:%i\n",scanner->pre_unit,scanner->pre_x_offset,scanner->pre_y_offset);
6184     printf("count:%i\npost_magnification:%f\npost_x_offset:%f\npost_y_offset:%f\n",
6185            scanner->count,scanner->unit,scanner->x_offset,scanner->y_offset);
6186     printf("The input:\n");
6187     synctex_node_display(scanner->input);
6188     if (scanner->count<1000) {
6189         printf("The sheets:\n");
6190         synctex_node_display(scanner->sheet);
6191         printf("The friends:\n");
6192         if (scanner->lists_of_friends) {
6193             int i = scanner->number_of_lists;
6194             synctex_node_p node;
6195             while(i--) {
6196                 printf("Friend index:%i\n",i);
6197                 node = (scanner->lists_of_friends)[i];
6198                 while(node) {
6199                     printf("%s:%i,%i\n",
6200                            synctex_node_isa(node),
6201                            _synctex_data_tag(node),
6202                            _synctex_data_line(node)
6203                            );
6204                     node = _synctex_tree_friend(node);
6205                 }
6206             }
6207         }
6208     } else {
6209         printf("SyncTeX Warning: Too many objects\n");
6210     }
6211 }
6212 /*  Public */
synctex_scanner_get_name(synctex_scanner_p scanner,int tag)6213 const char * synctex_scanner_get_name(synctex_scanner_p scanner,int tag) {
6214     synctex_node_p input = NULL;
6215     if (NULL == scanner) {
6216         return NULL;
6217     }
6218     if ((input = scanner->input)) {;
6219         do {
6220             if (tag == _synctex_data_tag(input)) {
6221                 return (_synctex_data_name(input));
6222             }
6223         } while((input = __synctex_tree_sibling(input)));
6224     }
6225     return NULL;
6226 }
synctex_node_get_name(synctex_node_p node)6227 const char * synctex_node_get_name(synctex_node_p node) {
6228     if (node) {
6229         return synctex_scanner_get_name(node->class_->scanner,_synctex_data_tag(node));
6230     }
6231     return NULL;
6232 }
6233 
6234 static int _synctex_scanner_get_tag(synctex_scanner_p scanner,const char * name);
_synctex_scanner_get_tag(synctex_scanner_p scanner,const char * name)6235 static int _synctex_scanner_get_tag(synctex_scanner_p scanner,const char * name) {
6236     synctex_node_p input = NULL;
6237     if (NULL == scanner) {
6238         return 0;
6239     }
6240     if ((input = scanner->input)) {
6241         do {
6242             if (_synctex_is_equivalent_file_name(name,(_synctex_data_name(input)))) {
6243                 return _synctex_data_tag(input);
6244             }
6245         } while((input = __synctex_tree_sibling(input)));
6246     }
6247     //  2011 version
6248     name = _synctex_base_name(name);
6249     if ((input = scanner->input)) {
6250         do {
6251             if (_synctex_is_equivalent_file_name(name,_synctex_base_name(_synctex_data_name(input)))) {
6252                 synctex_node_p other_input = input;
6253                 while((other_input = __synctex_tree_sibling(other_input))) {
6254                     if (_synctex_is_equivalent_file_name(name,_synctex_base_name(_synctex_data_name(other_input)))
6255                         && (strlen(_synctex_data_name(input))!=strlen(_synctex_data_name(other_input))
6256                             || strncmp(_synctex_data_name(other_input),_synctex_data_name(input),strlen(_synctex_data_name(input))))) {
6257                             // There is a second possible candidate
6258                             return 0;
6259                         }
6260                 }
6261                 return _synctex_data_tag(input);
6262             }
6263         } while((input = __synctex_tree_sibling(input)));
6264     }
6265     return 0;
6266 }
6267 
synctex_scanner_get_tag(synctex_scanner_p scanner,const char * name)6268 int synctex_scanner_get_tag(synctex_scanner_p scanner,const char * name) {
6269     size_t char_index = strlen(name);
6270     if ((scanner = synctex_scanner_parse(scanner)) && (0 < char_index)) {
6271         /*  the name is not void */
6272         char_index -= 1;
6273         if (!SYNCTEX_IS_PATH_SEPARATOR(name[char_index])) {
6274             /*  the last character of name is not a path separator */
6275             int result = _synctex_scanner_get_tag(scanner,name);
6276             if (result) {
6277                 return result;
6278             } else {
6279                 /*  the given name was not the one known by TeX
6280                  *  try a name relative to the enclosing directory of the scanner->output file */
6281                 const char * relative = name;
6282                 const char * ptr = scanner->reader->output;
6283                 while((strlen(relative) > 0) && (strlen(ptr) > 0) && (*relative == *ptr))
6284                 {
6285                     relative += 1;
6286                     ptr += 1;
6287                 }
6288                 /*  Find the last path separator before relative */
6289                 while(relative > name) {
6290                     if (SYNCTEX_IS_PATH_SEPARATOR(*(relative-1))) {
6291                         break;
6292                     }
6293                     relative -= 1;
6294                 }
6295                 if ((relative > name) && (result = _synctex_scanner_get_tag(scanner,relative))) {
6296                     return result;
6297                 }
6298                 if (SYNCTEX_IS_PATH_SEPARATOR(name[0])) {
6299                     /*  No tag found for the given absolute name,
6300                      *  Try each relative path starting from the shortest one */
6301                     while(0<char_index) {
6302                         char_index -= 1;
6303                         if (SYNCTEX_IS_PATH_SEPARATOR(name[char_index])
6304                             && (result = _synctex_scanner_get_tag(scanner,name+char_index+1))) {
6305                             return result;
6306                         }
6307                     }
6308                 }
6309             }
6310             return result;
6311         }
6312     }
6313     return 0;
6314 }
synctex_scanner_input(synctex_scanner_p scanner)6315 synctex_node_p synctex_scanner_input(synctex_scanner_p scanner) {
6316     return scanner?scanner->input:NULL;
6317 }
synctex_scanner_input_with_tag(synctex_scanner_p scanner,int tag)6318 synctex_node_p synctex_scanner_input_with_tag(synctex_scanner_p scanner, int tag) {
6319     synctex_node_p input = scanner?scanner->input:NULL;
6320     while (_synctex_data_tag(input)!=tag) {
6321         if ((input = __synctex_tree_sibling(input))) {
6322             continue;
6323         }
6324         break;
6325     }
6326     return input;
6327 }
synctex_scanner_get_output_fmt(synctex_scanner_p scanner)6328 const char * synctex_scanner_get_output_fmt(synctex_scanner_p scanner) {
6329     return NULL != scanner && scanner->output_fmt?scanner->output_fmt:"";
6330 }
synctex_scanner_get_output(synctex_scanner_p scanner)6331 const char * synctex_scanner_get_output(synctex_scanner_p scanner) {
6332     return NULL != scanner && scanner->reader->output?scanner->reader->output:"";
6333 }
synctex_scanner_get_synctex(synctex_scanner_p scanner)6334 const char * synctex_scanner_get_synctex(synctex_scanner_p scanner) {
6335     return NULL != scanner && scanner->reader->synctex?scanner->reader->synctex:"";
6336 }
6337 #	ifdef SYNCTEX_NOTHING
6338 #       pragma mark -
6339 #       pragma mark Public node attributes
6340 #   endif
6341 
6342 #   define SYNCTEX_DEFINE_NODE_HVWHD(WHAT) \
6343 int synctex_node_##WHAT(synctex_node_p node) { \
6344     return (node && node->class_->inspector->WHAT)? \
6345         node->class_->inspector->WHAT(node): 0; \
6346 }
6347 #   define SYNCTEX_DEFINE_PROXY_HV(WHAT) \
6348 static int _synctex_proxy_##WHAT(synctex_proxy_p proxy) { \
6349     synctex_node_p target = _synctex_tree_target(proxy); \
6350     if (target) { \
6351         return _synctex_data_##WHAT(proxy)+synctex_node_##WHAT(target); \
6352     } else { \
6353         return proxy? _synctex_data_##WHAT(proxy): 0; \
6354     } \
6355 }
6356 #define SYNCTEX_DEFINE_PROXY_TLCWVD(WHAT) \
6357 static int _synctex_proxy_##WHAT(synctex_proxy_p proxy) { \
6358     synctex_node_p target = _synctex_tree_target(proxy); \
6359     return target? synctex_node_##WHAT(target): 0; \
6360 }
6361 
6362 /**
6363  *  The horizontal location of the node.
6364  *  Idem for v, width, height and depth.
6365  *  - parameter node: a node with geometrical information.
6366  *  - returns: an integer.
6367  *  - requires: every proxy node has a target.
6368  *  - note: recursive call if the parameter has a proxy.
6369  *  - author: JL
6370  */
6371 SYNCTEX_DEFINE_NODE_HVWHD(h)
SYNCTEX_DEFINE_NODE_HVWHD(v)6372 SYNCTEX_DEFINE_NODE_HVWHD(v)
6373 SYNCTEX_DEFINE_NODE_HVWHD(width)
6374 SYNCTEX_DEFINE_NODE_HVWHD(height)
6375 SYNCTEX_DEFINE_NODE_HVWHD(depth)
6376 SYNCTEX_DEFINE_PROXY_TLCWVD(tag)
6377 SYNCTEX_DEFINE_PROXY_TLCWVD(line)
6378 SYNCTEX_DEFINE_PROXY_TLCWVD(column)
6379 SYNCTEX_DEFINE_PROXY_HV(h)
6380 SYNCTEX_DEFINE_PROXY_HV(v)
6381 SYNCTEX_DEFINE_PROXY_TLCWVD(width)
6382 SYNCTEX_DEFINE_PROXY_TLCWVD(height)
6383 SYNCTEX_DEFINE_PROXY_TLCWVD(depth)
6384 
6385 /**
6386  *  Whether the argument is a box,
6387  *  either vertical or horizontal,
6388  *  either void or not,
6389  *  or a proxy to such a box.
6390  *  - parameter NODE: of type synctex_node_p
6391  *  - returns: yorn
6392  */
6393 
6394 SYNCTEX_INLINE static synctex_bool_t _synctex_node_is_box(synctex_node_p node) {
6395     return node &&
6396     (node->class_->type == synctex_node_type_hbox
6397      || node->class_->type == synctex_node_type_void_hbox
6398      || node->class_->type == synctex_node_type_vbox
6399      || node->class_->type == synctex_node_type_void_vbox
6400      || _synctex_node_is_box(_synctex_tree_target(node)));
6401 }
6402 
6403 /**
6404  *  Whether the argument is a handle.
6405  *  Handles are similar to proxies because they have a target.
6406  *  They are used for query results.
6407  *  - parameter NODE: of type synctex_node_p
6408  *  - returns: yorn
6409  */
6410 
_synctex_node_is_handle(synctex_node_p node)6411 SYNCTEX_INLINE static synctex_bool_t _synctex_node_is_handle(synctex_node_p node) {
6412     return node &&
6413     (node->class_->type == synctex_node_type_handle);
6414 }
6415 
6416 /**
6417  *  Resolves handle indirection.
6418  *  - parameter node: of type synctex_node_p
6419  *  - returns: node if it is not a handle,
6420  *  its target otherwise.
6421  */
6422 
_synctex_node_or_handle_target(synctex_node_p node)6423 SYNCTEX_INLINE static synctex_node_p _synctex_node_or_handle_target(synctex_node_p node) {
6424     return _synctex_node_is_handle(node)?
6425     _synctex_tree_target(node):node;
6426 }
6427 
6428 /**
6429  *  Whether the argument is an hbox.
6430  *  - parameter NODE: of type synctex_node_p
6431  *  - returns: yorn
6432  */
6433 
_synctex_node_is_hbox(synctex_node_p node)6434 SYNCTEX_INLINE static synctex_bool_t _synctex_node_is_hbox(synctex_node_p node) {
6435     return node &&
6436     (node->class_->type == synctex_node_type_hbox
6437      || node->class_->type == synctex_node_type_void_hbox
6438      || _synctex_node_is_hbox(_synctex_tree_target(node)));
6439 }
6440 
6441 /**
6442  *  The horizontal location of the first box enclosing node.
6443  *  - parameter node: a node with geometrical information.
6444  *  - returns: an integer.
6445  *  - author: JL
6446  */
synctex_node_box_h(synctex_node_p node)6447 int synctex_node_box_h(synctex_node_p node) {
6448     if (_synctex_node_is_box(node) || (node = _synctex_tree_parent(node))) {
6449         return synctex_node_h(node);
6450     }
6451     return 0;
6452 }
6453 /**
6454  *  The vertical location of the first box enclosing node.
6455  *  - parameter node: a node with geometrical information.
6456  *  - returns: an integer.
6457  *  - author: JL
6458  */
synctex_node_box_v(synctex_node_p node)6459 int synctex_node_box_v(synctex_node_p node) {
6460     if (_synctex_node_is_box(node) || (node = _synctex_tree_parent(node))) {
6461         return synctex_node_v(node);
6462     }
6463     return 0;
6464 }
6465 /**
6466  *  The width of the first box enclosing node.
6467  *  - parameter node: a node with geometrical information.
6468  *  - returns: an integer.
6469  *  - author: JL
6470  */
synctex_node_box_width(synctex_node_p node)6471 int synctex_node_box_width(synctex_node_p node) {
6472     if (_synctex_node_is_box(node) || (node = _synctex_tree_parent(node))) {
6473         return synctex_node_width(node);
6474     }
6475     return 0;
6476 }
6477 /**
6478  *  The height of the first box enclosing node.
6479  *  - parameter node: a node with geometrical information.
6480  *  - returns: an integer.
6481  *  - author: JL
6482  */
synctex_node_box_height(synctex_node_p node)6483 int synctex_node_box_height(synctex_node_p node) {
6484     if (_synctex_node_is_box(node) || (node = _synctex_tree_parent(node))) {
6485         return synctex_node_height(node);
6486     }
6487     return 0;
6488 }
6489 /**
6490  *  The depth of the first box enclosing node.
6491  *  - parameter node: a node with geometrical information.
6492  *  - returns: an integer.
6493  *  - author: JL
6494  */
synctex_node_box_depth(synctex_node_p node)6495 int synctex_node_box_depth(synctex_node_p node) {
6496     if (_synctex_node_is_box(node) || (node = _synctex_tree_parent(node))) {
6497         return synctex_node_depth(node);
6498     }
6499     return 0;
6500 }
6501 /**
6502  *  The horizontal location of an hbox, corrected with contents.
6503  *  - parameter node: an hbox node.
6504  *  - returns: an integer, 0 if node is not an hbox or an hbox proxy.
6505  *  - note: recursive call when node is an hbox proxy.
6506  *  - author: JL
6507  */
synctex_node_hbox_h(synctex_node_p node)6508 int synctex_node_hbox_h(synctex_node_p node) {
6509     switch(synctex_node_type(node)) {
6510         case synctex_node_type_hbox:
6511             return _synctex_data_h_V(node);
6512         case synctex_node_type_proxy_hbox:
6513             return _synctex_data_h(node)+synctex_node_hbox_h(_synctex_tree_target(node));
6514         default:
6515             return 0;
6516     }
6517 }
6518 /**
6519  *  The vertical location of an hbox, corrected with contents.
6520  *  - parameter node: an hbox node.
6521  *  - returns: an integer, 0 if node is not an hbox or an hbox proxy.
6522  *  - note: recursive call when node is an hbox proxy.
6523  *  - author: JL
6524  */
synctex_node_hbox_v(synctex_node_p node)6525 int synctex_node_hbox_v(synctex_node_p node) {
6526     switch(synctex_node_type(node)) {
6527         case synctex_node_type_hbox:
6528             return _synctex_data_v_V(node);
6529         case synctex_node_type_proxy_hbox:
6530             return _synctex_data_v(node)+synctex_node_hbox_v(_synctex_tree_target(node));
6531         default:
6532             return 0;
6533     }
6534 }
6535 /**
6536  *  The width of an hbox, corrected with contents.
6537  *  - parameter node: an hbox node, 0 if node is not an hbox or an hbox proxy.
6538  *  - returns: an integer.
6539  *  - author: JL
6540  */
synctex_node_hbox_width(synctex_node_p node)6541 int synctex_node_hbox_width(synctex_node_p node) {
6542     synctex_node_p target = _synctex_tree_target(node);
6543     if (target) {
6544         node = target;
6545     }
6546     return synctex_node_type(node) == synctex_node_type_hbox?
6547     _synctex_data_width_V(node): 0;
6548 }
6549 /**
6550  *  The height of an hbox, corrected with contents.
6551  *  - parameter node: an hbox node.
6552  *  - returns: an integer, 0 if node is not an hbox or an hbox proxy.
6553  *  - author: JL
6554  */
synctex_node_hbox_height(synctex_node_p node)6555 int synctex_node_hbox_height(synctex_node_p node) {
6556     synctex_node_p target = _synctex_tree_target(node);
6557     if (target) {
6558         node = target;
6559     }
6560     return synctex_node_type(node) == synctex_node_type_hbox?
6561     _synctex_data_height_V(node): 0;
6562 }
6563 /**
6564  *  The depth of an hbox, corrected with contents.
6565  *  - parameter node: an hbox node.
6566  *  - returns: an integer, 0 if node is not an hbox or an hbox proxy.
6567  *  - note: recursive call when node is an hbox proxy.
6568  *  - author: JL
6569  */
synctex_node_hbox_depth(synctex_node_p node)6570 int synctex_node_hbox_depth(synctex_node_p node) {
6571     synctex_node_p target = _synctex_tree_target(node);
6572     if (target) {
6573         node = target;
6574     }
6575     return synctex_node_type(node) == synctex_node_type_hbox?
6576     _synctex_data_depth_V(node): 0;
6577 }
6578 #	ifdef SYNCTEX_NOTHING
6579 #       pragma mark -
6580 #       pragma mark Public node visible attributes
6581 #   endif
6582 
6583 #define SYNCTEX_VISIBLE_SIZE(node,s) \
6584 (s)*node->class_->scanner->unit
6585 #define SYNCTEX_VISIBLE_DISTANCE_h(node,d) \
6586 ((d)*node->class_->scanner->unit+node->class_->scanner->x_offset)
6587 #define SYNCTEX_VISIBLE_DISTANCE_v(node,d) \
6588 ((d)*node->class_->scanner->unit+node->class_->scanner->y_offset)
__synctex_node_visible_h(synctex_node_p node)6589 static float __synctex_node_visible_h(synctex_node_p node) {
6590     return SYNCTEX_VISIBLE_DISTANCE_h(node,synctex_node_h(node));
6591 }
__synctex_node_visible_v(synctex_node_p node)6592 static float __synctex_node_visible_v(synctex_node_p node) {
6593     return SYNCTEX_VISIBLE_DISTANCE_v(node,synctex_node_v(node));
6594 }
__synctex_node_visible_width(synctex_node_p node)6595 static float __synctex_node_visible_width(synctex_node_p node) {
6596     return SYNCTEX_VISIBLE_SIZE(node,synctex_node_width(node));
6597 }
__synctex_node_visible_height(synctex_node_p node)6598 static float __synctex_node_visible_height(synctex_node_p node) {
6599     return SYNCTEX_VISIBLE_SIZE(node,synctex_node_height(node));
6600 }
__synctex_node_visible_depth(synctex_node_p node)6601 static float __synctex_node_visible_depth(synctex_node_p node) {
6602     return SYNCTEX_VISIBLE_SIZE(node,synctex_node_depth(node));
6603 }
__synctex_proxy_visible_h(synctex_node_p node)6604 static float __synctex_proxy_visible_h(synctex_node_p node) {
6605     return SYNCTEX_VISIBLE_DISTANCE_h(node,synctex_node_h(node));
6606 }
__synctex_proxy_visible_v(synctex_node_p node)6607 static float __synctex_proxy_visible_v(synctex_node_p node) {
6608     return SYNCTEX_VISIBLE_DISTANCE_v(node,synctex_node_v(node));
6609 }
__synctex_proxy_visible_width(synctex_node_p node)6610 static float __synctex_proxy_visible_width(synctex_node_p node) {
6611     synctex_node_p target = _synctex_tree_target(node);
6612     return __synctex_node_visible_width(target);
6613 }
__synctex_proxy_visible_height(synctex_node_p node)6614 static float __synctex_proxy_visible_height(synctex_node_p node) {
6615     synctex_node_p target = _synctex_tree_target(node);
6616     return __synctex_node_visible_height(target);
6617 }
__synctex_proxy_visible_depth(synctex_node_p node)6618 static float __synctex_proxy_visible_depth(synctex_node_p node) {
6619     synctex_node_p target = _synctex_tree_target(node);
6620     return __synctex_node_visible_depth(target);
6621 }
__synctex_kern_visible_h(synctex_noxy_p noxy)6622 static float __synctex_kern_visible_h(synctex_noxy_p noxy) {
6623     int h = _synctex_data_h(noxy);
6624     int width = _synctex_data_width(noxy);
6625     return SYNCTEX_VISIBLE_DISTANCE_h(noxy, width>0?h-width:h);
6626 }
__synctex_kern_visible_width(synctex_noxy_p noxy)6627 static float __synctex_kern_visible_width(synctex_noxy_p noxy) {
6628     int width = _synctex_data_width(noxy);
6629     return SYNCTEX_VISIBLE_SIZE(noxy, width>0?width:-width);
6630 }
__synctex_rule_visible_h(synctex_noxy_p noxy)6631 static float __synctex_rule_visible_h(synctex_noxy_p noxy) {
6632     int h = _synctex_data_h(noxy);
6633     int width = _synctex_data_width(noxy);
6634     return SYNCTEX_VISIBLE_DISTANCE_h(noxy, width>0?h:h-width);
6635 }
__synctex_rule_visible_width(synctex_noxy_p noxy)6636 static float __synctex_rule_visible_width(synctex_noxy_p noxy) {
6637     int width = _synctex_data_width(noxy);
6638     return SYNCTEX_VISIBLE_SIZE(noxy, width>0?width:-width);
6639 }
__synctex_rule_visible_v(synctex_noxy_p noxy)6640 static float __synctex_rule_visible_v(synctex_noxy_p noxy) {
6641     return __synctex_node_visible_v(noxy);
6642 }
__synctex_rule_visible_height(synctex_noxy_p noxy)6643 static float __synctex_rule_visible_height(synctex_noxy_p noxy) {
6644     return __synctex_node_visible_height(noxy);
6645 }
__synctex_rule_visible_depth(synctex_noxy_p noxy)6646 static float __synctex_rule_visible_depth(synctex_noxy_p noxy) {
6647     return __synctex_node_visible_depth(noxy);
6648 }
6649 
6650 /**
6651  *  The horizontal location of node, in page coordinates.
6652  *  - parameter node: a node.
6653  *  - returns: a float.
6654  *  - author: JL
6655  */
synctex_node_visible_h(synctex_node_p node)6656 float synctex_node_visible_h(synctex_node_p node){
6657     return node? node->class_->vispector->h(node): 0;
6658 }
6659 /**
6660  *  The vertical location of node, in page coordinates.
6661  *  - parameter node: a node.
6662  *  - returns: a float.
6663  *  - author: JL
6664  */
synctex_node_visible_v(synctex_node_p node)6665 float synctex_node_visible_v(synctex_node_p node){
6666     return node? node->class_->vispector->v(node): 0;
6667 }
6668 /**
6669  *  The width of node, in page coordinates.
6670  *  - parameter node: a node.
6671  *  - returns: a float.
6672  *  - author: JL
6673  */
synctex_node_visible_width(synctex_node_p node)6674 float synctex_node_visible_width(synctex_node_p node){
6675     return node? node->class_->vispector->width(node): 0;
6676 }
6677 /**
6678  *  The height of node, in page coordinates.
6679  *  - parameter node: a node.
6680  *  - returns: a float.
6681  *  - author: JL
6682  */
synctex_node_visible_height(synctex_node_p node)6683 float synctex_node_visible_height(synctex_node_p node){
6684     return node? node->class_->vispector->height(node): 0;
6685 }
6686 /**
6687  *  The depth of node, in page coordinates.
6688  *  - parameter node: a node.
6689  *  - returns: a float.
6690  *  - author: JL
6691  */
synctex_node_visible_depth(synctex_node_p node)6692 float synctex_node_visible_depth(synctex_node_p node){
6693     return node? node->class_->vispector->depth(node): 0;
6694 }
6695 
6696 /**
6697  *  The V variant of geometrical information.
6698  *  - parameter node: a node.
6699  *  - returns: an integer.
6700  *  - author: JL
6701  */
6702 #define SYNCTEX_DEFINE_V(WHAT)\
6703 SYNCTEX_INLINE static int _synctex_node_##WHAT##_V(synctex_node_p node) { \
6704     synctex_node_p target = _synctex_tree_target(node); \
6705     if (target) { \
6706         return _synctex_data_##WHAT(node)+_synctex_node_##WHAT##_V(target); \
6707     } else if (_synctex_data_has_##WHAT##_V(node)) { \
6708         return _synctex_data_##WHAT##_V(node); \
6709     } else { \
6710         return _synctex_data_##WHAT(node); \
6711     } \
6712 }
6713 SYNCTEX_DEFINE_V(h)
SYNCTEX_DEFINE_V(v)6714 SYNCTEX_DEFINE_V(v)
6715 SYNCTEX_DEFINE_V(width)
6716 SYNCTEX_DEFINE_V(height)
6717 SYNCTEX_DEFINE_V(depth)
6718 
6719 SYNCTEX_INLINE static synctex_point_s _synctex_data_point(synctex_node_p node) {
6720     return (synctex_point_s){synctex_node_h(node),synctex_node_v(node)};
6721 }
_synctex_data_point_V(synctex_node_p node)6722 SYNCTEX_INLINE static synctex_point_s _synctex_data_point_V(synctex_node_p node) {
6723     return (synctex_point_s){_synctex_node_h_V(node),_synctex_node_v_V(node)};
6724 }
_synctex_data_set_point(synctex_node_p node,synctex_point_s point)6725 SYNCTEX_INLINE static synctex_point_s _synctex_data_set_point(synctex_node_p node, synctex_point_s point) {
6726     synctex_point_s old = _synctex_data_point(node);
6727     _synctex_data_set_h(node,point.h);
6728     _synctex_data_set_v(node,point.v);
6729     return old;
6730 }
_synctex_data_box(synctex_node_p node)6731 SYNCTEX_INLINE static synctex_box_s _synctex_data_box(synctex_node_p node) {
6732     synctex_box_s box = {{0,0},{0,0}};
6733     int n;
6734     n = synctex_node_width(node);
6735     if (n<0) {
6736         box.max.h = synctex_node_h(node);
6737         box.min.h = box.max.h + n;
6738     } else {
6739         box.min.h = synctex_node_h(node);
6740         box.max.h = box.min.h + n;
6741     }
6742     n = synctex_node_v(node);
6743     box.min.v = n - synctex_node_height(node);
6744     box.max.v = n + synctex_node_depth(node);
6745     return box;
6746 }
_synctex_data_xob(synctex_node_p node)6747 SYNCTEX_INLINE static synctex_box_s _synctex_data_xob(synctex_node_p node) {
6748     synctex_box_s box = {{0,0},{0,0}};
6749     int n;
6750     n = synctex_node_width(node);
6751     if (n>0) {
6752         box.max.h = synctex_node_h(node);
6753         box.min.h = box.max.h - n;
6754     } else {
6755         box.min.h = synctex_node_h(node);
6756         box.max.h = box.min.h - n;
6757     }
6758     n = synctex_node_v(node);
6759     box.min.v = n - synctex_node_height(node);
6760     box.max.v = n + synctex_node_depth(node);
6761     return box;
6762 }
_synctex_data_box_V(synctex_node_p node)6763 SYNCTEX_INLINE static synctex_box_s _synctex_data_box_V(synctex_node_p node) {
6764     synctex_box_s box = {{0,0},{0,0}};
6765     int n;
6766     n = _synctex_node_width_V(node);
6767     if (n<0) {
6768         box.max.h = _synctex_node_h_V(node);
6769         box.min.h = box.max.h + n;
6770     } else {
6771         box.min.h = _synctex_node_h_V(node);
6772         box.max.h = box.min.h + n;
6773     }
6774     n = _synctex_node_v_V(node);
6775     box.min.v = n - _synctex_node_height_V(node);
6776     box.max.v = n + _synctex_node_depth_V(node);
6777     return box;
6778 }
6779 
6780 /**
6781  *  The higher box node in the parent hierarchy which
6782  *  mean line number is the one of node ±1.
6783  *  This enclosing box is computed as follows
6784  *  1) get the first hbox in the parent linked list
6785  *  starting at node.
6786  *  If there is none, simply return the parent of node.
6787  *  2) compute the mean line number
6788  *  3) scans up the tree for the higher hbox with
6789  *  the same mean line number, ±1 eventually
6790 *  - parameter node: a node.
6791  *  - returns: a (proxy to a) box node.
6792  *  - author: JL
6793  */
_synctex_node_box_visible(synctex_node_p node)6794 static synctex_node_p _synctex_node_box_visible(synctex_node_p node) {
6795     if ((node = _synctex_node_or_handle_target(node))) {
6796         int mean = 0;
6797         int bound = 1500000/(node->class_->scanner->pre_magnification/1000.0);
6798         synctex_node_p parent = NULL;
6799         /*  get the first enclosing parent
6800          *  then get the highest enclosing parent with the same mean line ±1 */
6801         node = _synctex_node_or_handle_target(node);
6802         if (!_synctex_node_is_box(node)) {
6803             if ((parent = _synctex_tree_parent(node))) {
6804                 node = parent;
6805             } else if ((node = _synctex_tree_target(node))) {
6806                 if (!_synctex_node_is_box(node)) {
6807                     if ((parent = _synctex_tree_parent(node))) {
6808                         node = parent;
6809                     } else {
6810                         return NULL;
6811                     }
6812                 }
6813             }
6814         }
6815         parent = node;
6816         mean = synctex_node_mean_line(node);
6817         while ((parent = _synctex_tree_parent(parent))) {
6818             if (_synctex_node_is_hbox(parent)) {
6819                 if (_synctex_abs(mean-synctex_node_mean_line(parent))>1) {
6820                     return node;
6821                 } else if (synctex_node_width(parent)>bound) {
6822                     return parent;
6823                 } else if (synctex_node_height(parent)+synctex_node_depth(parent)>bound) {
6824                     return parent;
6825                 }
6826                 node = parent;
6827             }
6828         }
6829     }
6830     return node;
6831 }
6832 /**
6833  *  The horizontal location of the first box enclosing node, in page coordinates.
6834  *  - parameter node: a node.
6835  *  - returns: a float.
6836  *  - author: JL
6837  */
synctex_node_box_visible_h(synctex_node_p node)6838 float synctex_node_box_visible_h(synctex_node_p node) {
6839     return SYNCTEX_VISIBLE_DISTANCE_h(node,_synctex_node_h_V(_synctex_node_box_visible(node)));
6840 }
6841 /**
6842  *  The vertical location of the first box enclosing node, in page coordinates.
6843  *  - parameter node: a node.
6844  *  - returns: a float.
6845  *  - author: JL
6846  */
synctex_node_box_visible_v(synctex_node_p node)6847 float synctex_node_box_visible_v(synctex_node_p node) {
6848     return SYNCTEX_VISIBLE_DISTANCE_v(node,_synctex_node_v_V(_synctex_node_box_visible(node)));
6849 }
6850 /**
6851  *  The width of the first box enclosing node, in page coordinates.
6852  *  - parameter node: a node.
6853  *  - returns: a float.
6854  *  - author: JL
6855  */
synctex_node_box_visible_width(synctex_node_p node)6856 float synctex_node_box_visible_width(synctex_node_p node) {
6857     return SYNCTEX_VISIBLE_SIZE(node,_synctex_node_width_V(_synctex_node_box_visible(node)));
6858 }
6859 /**
6860  *  The height of the first box enclosing node, in page coordinates.
6861  *  - parameter node: a node.
6862  *  - returns: a float.
6863  *  - author: JL
6864  */
synctex_node_box_visible_height(synctex_node_p node)6865 float synctex_node_box_visible_height(synctex_node_p node) {
6866     return SYNCTEX_VISIBLE_SIZE(node,_synctex_node_height_V(_synctex_node_box_visible(node)));
6867 }
6868 /**
6869  *  The depth of the first box enclosing node, in page coordinates.
6870  *  - parameter node: a node.
6871  *  - returns: a float.
6872  *  - author: JL
6873  */
synctex_node_box_visible_depth(synctex_node_p node)6874 float synctex_node_box_visible_depth(synctex_node_p node) {
6875     return SYNCTEX_VISIBLE_SIZE(node,_synctex_node_depth_V(_synctex_node_box_visible(node)));
6876 }
6877 #	ifdef SYNCTEX_NOTHING
6878 #       pragma mark -
6879 #       pragma mark Other public node attributes
6880 #   endif
6881 
6882 /**
6883  *  The page number of the sheet enclosing node.
6884  *  - parameter node: a node.
6885  *  - returns: the page number or -1 if node does not belong to a sheet tree.
6886  *  - note: a proxy target does not belong to a sheet
6887  *      but a form, its page number is always -1.
6888  *  - note: a handles does not belong to a sheet not a form.
6889  *      its page number is -1.
6890  *  - author: JL
6891  */
synctex_node_page(synctex_node_p node)6892 int synctex_node_page(synctex_node_p node){
6893     synctex_node_p parent = NULL;
6894     while((parent = _synctex_tree_parent(node))) {
6895         node = parent;
6896     }
6897     if (synctex_node_type(node) == synctex_node_type_sheet) {
6898         return _synctex_data_page(node);
6899     }
6900     return -1;
6901 }
6902 /**
6903  *  The page number of the target.
6904  *  - author: JL
6905  */
_synctex_node_target_page(synctex_node_p node)6906 SYNCTEX_INLINE static int _synctex_node_target_page(synctex_node_p node){
6907     return synctex_node_page(_synctex_tree_target(node));
6908 }
6909 
6910 #if defined (SYNCTEX_USE_CHARINDEX)
synctex_node_charindex(synctex_node_p node)6911 synctex_charindex_t synctex_node_charindex(synctex_node_p node) {
6912     synctex_node_p target = _synctex_tree_target(node);
6913     return target? SYNCTEX_CHARINDEX(target):(node?SYNCTEX_CHARINDEX(node):0);
6914 }
6915 #endif
6916 
6917 /**
6918  *  The tag of the node.
6919  *  - parameter node: a node.
6920  *  - returns: the tag or -1 if node is NULL.
6921  *  - author: JL
6922  */
synctex_node_tag(synctex_node_p node)6923 int synctex_node_tag(synctex_node_p node) {
6924     return node? node->class_->tlcpector->tag(node): -1;
6925 }
6926 /**
6927  *  The line of the node.
6928  *  - parameter node: a node.
6929  *  - returns: the line or -1 if node is NULL.
6930  *  - author: JL
6931  */
synctex_node_line(synctex_node_p node)6932 int synctex_node_line(synctex_node_p node) {
6933     return node? node->class_->tlcpector->line(node): -1;
6934 }
6935 /**
6936  *  The column of the node.
6937  *  - parameter node: a node.
6938  *  - returns: the column or -1 if node is NULL.
6939  *  - author: JL
6940  */
synctex_node_column(synctex_node_p node)6941 int synctex_node_column(synctex_node_p node) {
6942     return node? node->class_->tlcpector->column(node): -1;
6943 }
6944 /**
6945  *  The mean line number of the node.
6946  *  - parameter node: a node.
6947  *  - returns: the mean line or -1 if node is NULL.
6948  *  - author: JL
6949  */
synctex_node_mean_line(synctex_node_p node)6950 int synctex_node_mean_line(synctex_node_p node) {
6951     synctex_node_p other = _synctex_tree_target(node);
6952     if (other) {
6953         node = other;
6954     }
6955     if (_synctex_data_has_mean_line(node)) {
6956         return _synctex_data_mean_line(node);
6957     }
6958     if ((other = synctex_node_parent(node))) {
6959         if (_synctex_data_has_mean_line(other)) {
6960             return _synctex_data_mean_line(other);
6961         }
6962     }
6963     return synctex_node_line(node);
6964 }
6965 /**
6966  *  The weight of the node.
6967  *  - parameter node: a node.
6968  *  - returns: the weight or -1 if node is NULL.
6969  *  - author: JL
6970  */
synctex_node_weight(synctex_node_p node)6971 int synctex_node_weight(synctex_node_p node) {
6972     synctex_node_p target = _synctex_tree_target(node);
6973     if (target) {
6974         node = target;
6975     }
6976     return node?(synctex_node_type(node)==synctex_node_type_hbox?_synctex_data_weight(node):0):-1;
6977 }
6978 /**
6979  *  The number of children of the node.
6980  *  - parameter node: a node.
6981  *  - returns: the count or -1 if node is NULL.
6982  *  - author: JL
6983  */
synctex_node_child_count(synctex_node_p node)6984 int synctex_node_child_count(synctex_node_p node) {
6985     synctex_node_p target = _synctex_tree_target(node);
6986     if (target) {
6987         node = target;
6988     }
6989     return node?(synctex_node_type(node)==synctex_node_type_hbox?_synctex_data_weight(node):0):-1;
6990 }
6991 #	ifdef SYNCTEX_NOTHING
6992 #       pragma mark -
6993 #       pragma mark Sheet & Form
6994 #   endif
6995 
6996 /**
6997  *  The sheet of the scanner with a given page number.
6998  *  - parameter scanner: a scanner.
6999  *  - parameter page: a 1 based page number.
7000  *      If page == 0, returns the first sheet.
7001  *  - returns: a sheet or NULL.
7002  *  - author: JL
7003  */
synctex_sheet(synctex_scanner_p scanner,int page)7004 synctex_node_p synctex_sheet(synctex_scanner_p scanner,int page) {
7005     if (scanner) {
7006         synctex_node_p sheet = scanner->sheet;
7007         while(sheet) {
7008             if (page == _synctex_data_page(sheet)) {
7009                 return sheet;
7010             }
7011             sheet = __synctex_tree_sibling(sheet);
7012         }
7013         if (page == 0) {
7014             return scanner->sheet;
7015         }
7016     }
7017     return NULL;
7018 }
7019 /**
7020  *  The form of the scanner with a given tag.
7021  *  - parameter scanner: a scanner.
7022  *  - parameter tag: an integer identifier.
7023  *      If tag == 0, returns the first form.
7024  *  - returns: a form.
7025  *  - author: JL
7026  */
synctex_form(synctex_scanner_p scanner,int tag)7027 synctex_node_p synctex_form(synctex_scanner_p scanner,int tag) {
7028     if (scanner) {
7029         synctex_node_p form = scanner->form;
7030         while(form) {
7031             if (tag == _synctex_data_tag(form)) {
7032                 return form;
7033             }
7034             form = __synctex_tree_sibling(form);
7035         }
7036         if (tag == 0) {
7037             return scanner->form;
7038         }
7039     }
7040     return NULL;
7041 }
7042 
7043 /**
7044  *  The content of the sheet with given page number.
7045  *  - parameter scanner: a scanner.
7046  *  - parameter page: a 1 based page number.
7047  *  - returns: a (vertical) box node.
7048  *  - author: JL
7049  */
synctex_sheet_content(synctex_scanner_p scanner,int page)7050 synctex_node_p synctex_sheet_content(synctex_scanner_p scanner,int page) {
7051     if (scanner) {
7052         return _synctex_tree_child(synctex_sheet(scanner,page));
7053     }
7054     return NULL;
7055 }
7056 
7057 /**
7058  *  The content of the sheet with given page number.
7059  *  - parameter scanner: a scanner.
7060  *  - parameter tag: an integer identifier.
7061  *  - returns: a box node.
7062  *  - author: JL
7063  */
synctex_form_content(synctex_scanner_p scanner,int tag)7064 synctex_node_p synctex_form_content(synctex_scanner_p scanner,int tag) {
7065     if (scanner) {
7066         return _synctex_tree_child(synctex_form(scanner,tag));
7067     }
7068     return NULL;
7069 }
7070 
_synctex_scanner_friend(synctex_scanner_p scanner,int i)7071 SYNCTEX_INLINE static synctex_node_p _synctex_scanner_friend(synctex_scanner_p scanner,int i) {
7072     if (i>=0) {
7073         i = _synctex_abs(i)%(scanner->number_of_lists);
7074         return (scanner->lists_of_friends)[i];
7075     }
7076     return NULL;
7077 }
_synctex_nodes_are_friend(synctex_node_p left,synctex_node_p right)7078 SYNCTEX_INLINE static synctex_bool_t _synctex_nodes_are_friend(synctex_node_p left, synctex_node_p right) {
7079     return synctex_node_tag(left) == synctex_node_tag(right) && synctex_node_line(left) == synctex_node_line(right);
7080 }
7081 /**
7082  *  The sibling argument is a parent/child list of nodes of the same page.
7083  */
7084 typedef struct {
7085     int count;
7086     synctex_node_p node;
7087 } synctex_counted_node_s;
7088 
_synctex_vertically_sorted_v2(synctex_node_p sibling)7089 SYNCTEX_INLINE static synctex_counted_node_s _synctex_vertically_sorted_v2(synctex_node_p sibling) {
7090     /* Clean the weights of the parents */
7091     synctex_counted_node_s result = {0, NULL};
7092     synctex_node_p h = NULL;
7093     synctex_node_p next_h = NULL;
7094     synctex_node_p parent = NULL;
7095     int weight = 0;
7096     synctex_node_p N = NULL;
7097     h = sibling;
7098     do {
7099         N = _synctex_tree_target(h);
7100         parent = _synctex_tree_parent(N);
7101         _synctex_data_set_weight(parent, 0);
7102     } while((h = _synctex_tree_child(h)));
7103     /* Compute the weights of the nodes */
7104     h = sibling;
7105     do {
7106         N = _synctex_tree_target(h);
7107         parent = _synctex_tree_parent(N);
7108         weight = _synctex_data_weight(parent);
7109         if (weight==0) {
7110             N = _synctex_tree_child(parent);
7111             do {
7112                 if (_synctex_nodes_are_friend(N,sibling)) {
7113                     ++ weight;
7114                 }
7115             } while ((N = __synctex_tree_sibling(N)));
7116             _synctex_data_set_weight(h,weight);
7117             _synctex_data_set_weight(parent,weight);
7118         }
7119     } while((h = _synctex_tree_child(h)));
7120     /* Order handle nodes according to the weight */
7121     h = _synctex_tree_reset_child(sibling);
7122     result.node = sibling;
7123     weight = 0;
7124     while((h)) {
7125         N = result.node;
7126         if (_synctex_data_weight(h)>_synctex_data_weight(N)) {
7127             next_h = _synctex_tree_set_child(h,N);
7128             result.node = h;
7129         } else if (_synctex_data_weight(h) == 0) {
7130             ++ weight;
7131             next_h = _synctex_tree_reset_child(h);
7132             synctex_node_free(h);
7133         } else {
7134             synctex_node_p next_N = NULL;
7135             while((next_N = _synctex_tree_child(N))) {
7136                 N = next_N;
7137                 if (_synctex_data_weight(h)<_synctex_data_weight(next_N)) {
7138                     continue;
7139                 }
7140                 break;
7141             }
7142             next_h = _synctex_tree_set_child(h,_synctex_tree_set_child(N,h));
7143         }
7144         h = next_h;
7145     };
7146     h = result.node;
7147     weight = 0;
7148     do {
7149         ++weight;
7150     } while((h = _synctex_tree_child(h)));
7151     result.count = 1;
7152     h = result.node;
7153     while((next_h = _synctex_tree_child(h))) {
7154         if (_synctex_data_weight(next_h)==0) {
7155             _synctex_tree_reset_child(h);
7156             weight = 1;
7157             h = next_h;
7158             while((h = _synctex_tree_child(h))) {
7159                 ++weight;
7160             }
7161             synctex_node_free(next_h);
7162             break;
7163         }
7164         ++result.count;
7165         h = next_h;
7166     }
7167     return result;
7168 }
7169 
7170 SYNCTEX_INLINE static synctex_bool_t _synctex_point_in_box_v2(synctex_point_p hitP, synctex_node_p node);
7171 
7172 /*  This struct records distances, the left one is non negative and the right one is non positive.
7173  *  When comparing the locations of 2 different graphical objects on the page, we will have to also record the
7174  *  horizontal distance as signed to keep track of the typesetting order.*/
7175 
7176 typedef struct {
7177     synctex_node_p node;
7178     int distance;
7179 } synctex_nd_s;
7180 
7181 #define SYNCTEX_ND_0 (synctex_nd_s){NULL,INT_MAX}
7182 
7183 typedef synctex_nd_s * synctex_nd_p;
7184 
7185 typedef struct {
7186     synctex_nd_s l;
7187     synctex_nd_s r;
7188 } synctex_nd_lr_s;
7189 
7190 /*  The best container is the deeper box that contains the hit point (H,V).
7191  *  _synctex_eq_deepest_container_v2 starts with node whereas
7192  *  _synctex_box_child_deepest starts with node's children, if any
7193  *  if node is not a box, or a void box, NULL is returned.
7194  *  We traverse the node tree in a deep first manner and stop as soon as a result is found. */
7195 static synctex_node_p _synctex_eq_deepest_container_v2(synctex_point_p hitP, synctex_node_p node);
7196 
7197 SYNCTEX_INLINE static synctex_nd_lr_s _synctex_eq_get_closest_children_in_box_v2(synctex_point_p hitP, synctex_node_p node);
7198 
7199 /*  Closest child, recursive.  */
7200 static synctex_nd_s __synctex_closest_deep_child_v2(synctex_point_p hitP, synctex_node_p node);
7201 
7202 /*  The smallest container between two has the smallest width or height.
7203  *  This comparison is used when there are 2 overlapping boxes that contain the hit point.
7204  *  For ConTeXt, the problem appears at each page.
7205  *  The chosen box is the one with the smallest height, then the smallest width. */
7206 SYNCTEX_INLINE static synctex_node_p _synctex_smallest_container_v2(synctex_node_p node, synctex_node_p other_node);
7207 
7208 /*  Returns the distance between the hit point hit point=(H,V) and the given node. */
7209 
7210 static int _synctex_point_node_distance_v2(synctex_point_p hitP, synctex_node_p node);
7211 
7212 /*  The closest container is the box that is the one closest to the given point.
7213  *  The "visible" version takes into account the visible dimensions instead of the real ones given by TeX. */
7214 static synctex_nd_s _synctex_eq_closest_child_v2(synctex_point_p hitP, synctex_node_p node);
7215 
7216 #	ifdef SYNCTEX_NOTHING
7217 #       pragma mark -
7218 #       pragma mark Queries
7219 #   endif
7220 
7221 /**
7222  *  iterator for a deep first tree traversal.
7223  */
7224 struct synctex_iterator_t {
7225     synctex_node_p seed;
7226     synctex_node_p top;
7227     synctex_node_p next;
7228     int count0;
7229     int count;
7230 };
7231 
_synctex_iterator_new(synctex_node_p result,int count)7232 SYNCTEX_INLINE static synctex_iterator_p _synctex_iterator_new(synctex_node_p result, int count) {
7233     synctex_iterator_p iterator;
7234     if ((iterator = _synctex_malloc(sizeof(synctex_iterator_s)))) {
7235         iterator->seed = iterator->top = iterator->next = result;
7236         iterator->count0 = iterator->count = count;
7237     }
7238     return iterator;
7239 };
7240 
synctex_iterator_free(synctex_iterator_p iterator)7241 void synctex_iterator_free(synctex_iterator_p iterator) {
7242     if (iterator) {
7243         synctex_node_free(iterator->seed);
7244         _synctex_free(iterator);
7245     }
7246 }
synctex_iterator_has_next(synctex_iterator_p iterator)7247 synctex_bool_t synctex_iterator_has_next(synctex_iterator_p iterator) {
7248     return iterator?iterator->count>0:0;
7249 }
synctex_iterator_count(synctex_iterator_p iterator)7250 int synctex_iterator_count(synctex_iterator_p iterator) {
7251     return iterator? iterator->count: 0;
7252 }
7253 
7254 /**
7255  *  The next result of the iterator.
7256  *  Internally, the iterator stores handles to nodes.
7257  *  Externally, it returns the targets,
7258  *  such that the caller only sees nodes.
7259  */
synctex_iterator_next_result(synctex_iterator_p iterator)7260 synctex_node_p synctex_iterator_next_result(synctex_iterator_p iterator) {
7261     if (iterator && iterator->count>0) {
7262         synctex_node_p N = iterator->next;
7263         if(!(iterator->next = _synctex_tree_child(N))) {
7264             iterator->next = iterator->top = __synctex_tree_sibling(iterator->top);
7265         }
7266         --iterator->count;
7267         return _synctex_tree_target(N);
7268     }
7269     return NULL;
7270 }
synctex_iterator_reset(synctex_iterator_p iterator)7271 int synctex_iterator_reset(synctex_iterator_p iterator) {
7272     if (iterator) {
7273         iterator->next = iterator->top = iterator->seed;
7274         return iterator->count = iterator->count0;
7275     }
7276     return 0;
7277 }
7278 
synctex_iterator_new_edit(synctex_scanner_p scanner,int page,float h,float v)7279 synctex_iterator_p synctex_iterator_new_edit(synctex_scanner_p scanner,int page,float h,float v){
7280     if (scanner) {
7281         synctex_node_p sheet = NULL;
7282         synctex_point_s hit;
7283         synctex_node_p node = NULL;
7284         synctex_nd_lr_s nds = {{NULL,0},{NULL,0}};
7285         if (NULL == (scanner = synctex_scanner_parse(scanner)) || 0 >= scanner->unit) {/*  scanner->unit must be >0 */
7286             return NULL;
7287         }
7288         /*  Find the proper sheet */
7289         sheet = synctex_sheet(scanner,page);
7290         if (NULL == sheet) {
7291             return NULL;
7292         }
7293         /*  Now sheet points to the sheet node with proper page number. */
7294         /*  Now that scanner has been initialized, we can convert
7295          *  the given point to scanner integer coordinates */
7296         hit = (synctex_point_s)
7297         {(h-scanner->x_offset)/scanner->unit,
7298             (v-scanner->y_offset)/scanner->unit};
7299         /*  At first, we browse all the horizontal boxes of the sheet
7300          *  until we find one containing the hit point. */
7301         if ((node = _synctex_tree_next_hbox(sheet))) {
7302             do {
7303                 if (_synctex_point_in_box_v2(&hit,node)) {
7304                     /*  Maybe the hit point belongs to a contained vertical box.
7305                      *  This is the most likely situation.
7306                      */
7307                     synctex_node_p next = node;
7308 #if defined(SYNCTEX_DEBUG)
7309                     printf("--- We are lucky\n");
7310 #endif
7311                     /*  This trick is for catching overlapping boxes */
7312                     while ((next = _synctex_tree_next_hbox(next))) {
7313                         if (_synctex_point_in_box_v2(&hit,next)) {
7314                             node = _synctex_smallest_container_v2(next,node);
7315                         }
7316                     }
7317                     /*  node is the smallest horizontal box that contains hit,
7318                      *  unless there is no hbox at all.
7319                      */
7320                     node = _synctex_eq_deepest_container_v2(&hit, node);
7321                     nds = _synctex_eq_get_closest_children_in_box_v2(&hit, node);
7322                 end:
7323                     if (nds.r.node && nds.l.node) {
7324                         if ((_synctex_data_tag(nds.r.node)!=_synctex_data_tag(nds.l.node))
7325                             || (_synctex_data_line(nds.r.node)!=_synctex_data_line(nds.l.node))
7326                             || (_synctex_data_column(nds.r.node)!=_synctex_data_column(nds.l.node))) {
7327                             if (_synctex_data_line(nds.r.node)<_synctex_data_line(nds.l.node)) {
7328                                 node = nds.r.node;
7329                                 nds.r.node = nds.l.node;
7330                                 nds.l.node = node;
7331                             } else if (_synctex_data_line(nds.r.node)==_synctex_data_line(nds.l.node)) {
7332                                 if (nds.l.distance>nds.r.distance) {
7333                                     node = nds.r.node;
7334                                     nds.r.node = nds.l.node;
7335                                     nds.l.node = node;
7336                                 }
7337                             }
7338                             if((node = _synctex_new_handle_with_target(nds.l.node))) {
7339                                 synctex_node_p other_handle;
7340                                 if((other_handle = _synctex_new_handle_with_target(nds.r.node))) {
7341                                     _synctex_tree_set_sibling(node,other_handle);
7342                                     return _synctex_iterator_new(node,2);
7343                                 }
7344                                 return _synctex_iterator_new(node,1);
7345                             }
7346                             return NULL;
7347                         }
7348                         /*  both nodes have the same input coordinates
7349                          *  We choose the one closest to the hit point  */
7350                         if (nds.l.distance>nds.r.distance) {
7351                             nds.l.node = nds.r.node;
7352                         }
7353                         nds.r.node = NULL;
7354                     } else if (nds.r.node) {
7355                         nds.l = nds.r;
7356                     } else if (!nds.l.node) {
7357                         nds.l.node = node;
7358                     }
7359                     if((node = _synctex_new_handle_with_target(nds.l.node))) {
7360                         return _synctex_iterator_new(node,1);
7361                     }
7362                     return 0;
7363                 }
7364             } while ((node = _synctex_tree_next_hbox(node)));
7365             /*  All the horizontal boxes have been tested,
7366              *  None of them contains the hit point.
7367              */
7368         }
7369         /*  We are not lucky,
7370          *  we test absolutely all the node
7371          *  to find the closest... */
7372         if ((node = _synctex_tree_child(sheet))) {
7373 #if defined(SYNCTEX_DEBUG)
7374             printf("--- We are not lucky\n");
7375 #endif
7376             nds.l = __synctex_closest_deep_child_v2(&hit, node);
7377 #if defined(SYNCTEX_DEBUG)
7378             printf("Edit query best: %i\n", nds.l.distance);
7379 #endif
7380             goto end;
7381         }
7382     }
7383     return NULL;
7384 }
7385 
7386 /**
7387  *  Loop the candidate friendly list to find the ones with the proper
7388  *  tag and line.
7389  *  Returns a tree of results targeting the found candidates.
7390  *  At the top level each sibling has its own page number.
7391  *  All the results with the same page number are linked by child/parent entry.
7392  *  - parameter candidate: a friendly list of candidates
7393  */
_synctex_display_query_v2(synctex_node_p target,int tag,int line,synctex_bool_t exclude_box)7394 static synctex_node_p _synctex_display_query_v2(synctex_node_p target, int tag, int line, synctex_bool_t exclude_box) {
7395     synctex_node_p first_handle = NULL;
7396     /*  Search the first match */
7397     if (target == NULL) {
7398         return first_handle;
7399     }
7400     do {
7401         int page;
7402         if ((exclude_box
7403              && _synctex_node_is_box(target))
7404             || (tag != synctex_node_tag(target))
7405             || (line != synctex_node_line(target))) {
7406             continue;
7407         }
7408         /*  We found a first match, create
7409          *  a result handle targeting that candidate. */
7410         first_handle = _synctex_new_handle_with_target(target);
7411         if (first_handle == NULL) {
7412             return first_handle;
7413         }
7414         /*  target is either a node,
7415          *  or a proxy to some node, in which case,
7416          *  the target's target belongs to a form,
7417          *  not a sheet. */
7418         page = synctex_node_page(target);
7419         /*  Now create all the other results  */
7420         while ((target = _synctex_tree_friend(target))) {
7421             synctex_node_p result = NULL;
7422             if ((exclude_box
7423                  && _synctex_node_is_box(target))
7424                 || (tag != synctex_node_tag(target))
7425                 || (line != synctex_node_line(target))) {
7426                 continue;
7427             }
7428             /*  Another match, same page number ? */
7429             result = _synctex_new_handle_with_target(target);
7430             if (NULL == result ) {
7431                 return first_handle;
7432             }
7433             /*  is it the same page number ? */
7434             if (synctex_node_page(target) == page) {
7435                 __synctex_tree_set_child(result, first_handle);
7436                 first_handle = result;
7437             } else {
7438                 /*  We have 2 page numbers involved */
7439                 __synctex_tree_set_sibling(first_handle, result);
7440                 while ((target = _synctex_tree_friend(target))) {
7441                     synctex_node_p same_page_node;
7442                     if ((exclude_box
7443                          && _synctex_node_is_box(target))
7444                         || (tag != synctex_node_tag(target))
7445                         || (line != synctex_node_line(target))) {
7446                         continue;
7447                     }
7448                     /*  New match found, which page? */
7449                     result = _synctex_new_handle_with_target(target);
7450                     if (NULL == result) {
7451                         return first_handle;
7452                     }
7453                     same_page_node = first_handle;
7454                     page = synctex_node_page(target);
7455                     /*  Find a result with the same page number */;
7456                     do {
7457                         if (_synctex_node_target_page(same_page_node) == page) {
7458                             /* Insert result between same_page_node and its child */
7459                             _synctex_tree_set_child(result,_synctex_tree_set_child(same_page_node,result));
7460                         } else if ((same_page_node = __synctex_tree_sibling(same_page_node))) {
7461                             continue;
7462                         } else {
7463                             /*  This is a new page number */
7464                             __synctex_tree_set_sibling(result,first_handle);
7465                             first_handle = result;
7466                         }
7467                         break;
7468                     } while (synctex_YES);
7469                 }
7470                 return first_handle;
7471             }
7472         }
7473     } while ((target = _synctex_tree_friend(target)));
7474     return first_handle;
7475 }
synctex_iterator_new_display(synctex_scanner_p scanner,const char * name,int line,int column,int page_hint)7476 synctex_iterator_p synctex_iterator_new_display(synctex_scanner_p scanner,const char * name,int line,int column, int page_hint) {
7477     SYNCTEX_UNUSED(column)
7478     if (scanner) {
7479         int tag = synctex_scanner_get_tag(scanner,name);/* parse if necessary */
7480         int max_line = 0;
7481         int line_offset = 1;
7482         int try_count = 100;
7483         synctex_node_p node = NULL;
7484         synctex_node_p result = NULL;
7485         if (tag == 0) {
7486             printf("SyncTeX Warning: No tag for %s\n",name);
7487             return NULL;
7488         }
7489         node = synctex_scanner_input_with_tag(scanner, tag);
7490         max_line = _synctex_data_line(node);
7491         /*  node = NULL; */
7492         if (line>max_line) {
7493             line = max_line;
7494         }
7495         while(try_count--) {
7496             if (line<=max_line) {
7497                 /*  This loop will only be performed once for advanced viewers */
7498                 synctex_node_p friend = _synctex_scanner_friend(scanner,tag+line);
7499                 if ((node = friend)) {
7500                     result = _synctex_display_query_v2(node,tag,line,synctex_YES);
7501                     if (!result) {
7502                         /*  We did not find any matching boundary, retry including boxes */
7503                         node = friend;/*  no need to test it again, already done */
7504                         result = _synctex_display_query_v2(node,tag,line,synctex_NO);
7505                     }
7506                     /*  Now reverse the order to have nodes in display order, and then keep just a few nodes.
7507                      *  Order first the best node. */
7508                     /*  The result is a tree. At the root level, all nodes
7509                      *  correspond to different page numbers.
7510                      *  Each node has a child which corresponds to the same
7511                      *  page number if relevant.
7512                      *  Then reorder the nodes to put first the one which fits best.
7513                      *  The idea is to count the number of nodes
7514                      *  with the same tag and line number in the parents
7515                      *  and choose the ones with the biggest count.
7516                      */
7517                     if (result) {
7518                         /*  navigate through siblings, then children   */
7519                         synctex_node_p next_sibling = __synctex_tree_reset_sibling(result);
7520                         int best_match = abs(page_hint-_synctex_node_target_page(result));
7521                         synctex_node_p sibling;
7522                         int match;
7523                         synctex_counted_node_s cn = _synctex_vertically_sorted_v2(result);
7524                         int count = cn.count;
7525                         result = cn.node;
7526                         while((sibling = next_sibling)) {
7527                             /* What is next? Do not miss that step! */
7528                             next_sibling = __synctex_tree_reset_sibling(sibling);
7529                             cn = _synctex_vertically_sorted_v2(sibling);
7530                             count += cn.count;
7531                             sibling = cn.node;
7532                             match = abs(page_hint-_synctex_node_target_page(sibling));
7533                             if (match<best_match) {
7534                                 /*  Order this node first */
7535                                 __synctex_tree_set_sibling(sibling,result);
7536                                 result = sibling;
7537                                 best_match = match;
7538                             } else /*if (match>=best_match)*/ {
7539                                 __synctex_tree_set_sibling(sibling,__synctex_tree_sibling(result));
7540                                 __synctex_tree_set_sibling(result,sibling);
7541                             }
7542                         }
7543                         return _synctex_iterator_new(result,count);
7544                     }
7545                 }
7546 #       if defined(__SYNCTEX_STRONG_DISPLAY_QUERY__)
7547                 break;
7548 #       else
7549                 line += line_offset;
7550                 line_offset=line_offset<0?-(line_offset-1):-(line_offset+1);
7551                 if (line <= 0) {
7552                     line += line_offset;
7553                     line_offset=line_offset<0?-(line_offset-1):-(line_offset+1);
7554                 }
7555 #       endif
7556             }
7557         }
7558     }
7559     return NULL;
7560 }
synctex_display_query(synctex_scanner_p scanner,const char * name,int line,int column,int page_hint)7561 synctex_status_t synctex_display_query(synctex_scanner_p scanner,const char *  name,int line,int column, int page_hint) {
7562     if (scanner) {
7563         synctex_iterator_free(scanner->iterator);
7564         scanner->iterator = synctex_iterator_new_display(scanner, name,line,column, page_hint);
7565         return synctex_iterator_count(scanner->iterator);
7566     }
7567     return SYNCTEX_STATUS_ERROR;
7568 }
synctex_edit_query(synctex_scanner_p scanner,int page,float h,float v)7569 synctex_status_t synctex_edit_query(synctex_scanner_p scanner,int page,float h,float v) {
7570     if (scanner) {
7571         synctex_iterator_free(scanner->iterator);
7572         scanner->iterator = synctex_iterator_new_edit(scanner, page, h, v);
7573         return synctex_iterator_count(scanner->iterator);
7574     }
7575     return SYNCTEX_STATUS_ERROR;
7576 }
7577 /**
7578  *  The next result of a query.
7579  */
synctex_scanner_next_result(synctex_scanner_p scanner)7580 synctex_node_p synctex_scanner_next_result(synctex_scanner_p scanner) {
7581     return scanner? synctex_iterator_next_result(scanner->iterator): NULL;
7582 }
synctex_scanner_reset_result(synctex_scanner_p scanner)7583 synctex_status_t synctex_scanner_reset_result(synctex_scanner_p scanner) {
7584     return scanner? synctex_iterator_reset(scanner->iterator): SYNCTEX_STATUS_ERROR;
7585 }
7586 
synctex_node_target(synctex_node_p node)7587 synctex_node_p synctex_node_target(synctex_node_p node) {
7588     return _synctex_tree_target(node);
7589 }
7590 
7591 #	ifdef SYNCTEX_NOTHING
7592 #       pragma mark -
7593 #       pragma mark Geometric utilities
7594 #   endif
7595 
7596 /** Rougly speaking, this is:
7597  *  node's h coordinate - hit point's h coordinate.
7598  *  If node is to the right of the hit point, then this distance is positive,
7599  *  if node is to the left of the hit point, this distance is negative.
7600  *  If the argument is a pdf form reference, then the child is used and returned instead.
7601  *  Last Revision: Mon Apr 24 07:05:27 UTC 2017
7602  */
_synctex_point_h_ordered_distance_v2(synctex_point_p hit,synctex_node_p node)7603 static synctex_nd_s _synctex_point_h_ordered_distance_v2
7604 (synctex_point_p hit, synctex_node_p node) {
7605     synctex_nd_s nd = {node,INT_MAX};
7606     if (node) {
7607         int min,med,max,width;
7608         switch(synctex_node_type(node)) {
7609                 /*  The distance between a point and a box is special.
7610                  *  It is not the euclidian distance, nor something similar.
7611                  *  We have to take into account the particular layout,
7612                  *  and the box hierarchy.
7613                  *  Given a box, there are 9 regions delimited by the lines of the edges of the box.
7614                  *  The origin being at the top left corner of the page,
7615                  *  we also give names to the vertices of the box.
7616                  *
7617                  *   1 | 2 | 3
7618                  *  ---A---B--->
7619                  *   4 | 5 | 6
7620                  *  ---C---D--->
7621                  *   7 | 8 | 9
7622                  *     v   v
7623                  */
7624             case synctex_node_type_vbox:
7625             case synctex_node_type_void_vbox:
7626             case synctex_node_type_void_hbox:
7627                 /*  getting the box bounds, taking into account negative width, height and depth. */
7628                 width = _synctex_data_width(node);
7629                 min = _synctex_data_h(node);
7630                 max = min + (width>0?width:-width);
7631                 /*  We allways have min <= max */
7632                 if (hit->h<min) {
7633                     nd.distance = min - hit->h; /*  regions 1+4+7, result is > 0 */
7634                 } else if (hit->h>max) {
7635                     nd.distance = max - hit->h; /*  regions 3+6+9, result is < 0 */
7636                 } else {
7637                     nd.distance = 0; /*  regions 2+5+8, inside the box, except for vertical coordinates */
7638                 }
7639                 break;
7640             case synctex_node_type_proxy_vbox:
7641                 /*  getting the box bounds, taking into account negative width, height and depth. */
7642                 width = synctex_node_width(node);
7643                 min = synctex_node_h(node);
7644                 max = min + (width>0?width:-width);
7645                 /*  We allways have min <= max */
7646                 if (hit->h<min) {
7647                     nd.distance = min - hit->h; /*  regions 1+4+7, result is > 0 */
7648                 } else if (hit->h>max) {
7649                     nd.distance = max - hit->h; /*  regions 3+6+9, result is < 0 */
7650                 } else {
7651                     nd.distance = 0; /*  regions 2+5+8, inside the box, except for vertical coordinates */
7652                 }
7653                 break;
7654             case synctex_node_type_hbox:
7655             case synctex_node_type_proxy_hbox:
7656                 /*  getting the box bounds, taking into account negative width, height and depth. */
7657                 width = synctex_node_hbox_width(node);
7658                 min = synctex_node_hbox_h(node);
7659                 max = min + (width>0?width:-width);
7660                 /*  We allways have min <= max */
7661                 if (hit->h<min) {
7662                     nd.distance = min - hit->h; /*  regions 1+4+7, result is > 0 */
7663                 } else if (hit->h>max) {
7664                     nd.distance = max - hit->h; /*  regions 3+6+9, result is < 0 */
7665                 } else {
7666                     nd.distance = 0; /*  regions 2+5+8, inside the box, except for vertical coordinates */
7667                 }
7668                 break;
7669             case synctex_node_type_kern:
7670                 /*  IMPORTANT NOTICE: the location of the kern is recorded AFTER the move.
7671                  *  The distance to the kern is very special,
7672                  *  in general, there is no text material in the kern,
7673                  *  this is why we compute the offset relative to the closest edge of the kern.*/
7674                 max = _synctex_data_width(node);
7675                 if (max<0) {
7676                     min = _synctex_data_h(node);
7677                     max = min - max;
7678                 } else {
7679                     min = -max;
7680                     max = _synctex_data_h(node);
7681                     min += max;
7682                 }
7683                 med = (min+max)/2;
7684                 /*  positive kern: '.' means text, '>' means kern offset
7685                  *      .............
7686                  *                   min>>>>med>>>>max
7687                  *                                    ...............
7688                  *  negative kern: '.' means text, '<' means kern offset
7689                  *      ............................
7690                  *                 min<<<<med<<<<max
7691                  *                 .................................
7692                  *  Actually, we do not take into account negative widths.
7693                  *  There is a problem for such situation when there is effectively overlapping text.
7694                  *  But this should be extremely rare. I guess that in that case, many different choices
7695                  *  could be made, one being in contradiction with the other.
7696                  *  It means that the best choice should be made according to the situation that occurs
7697                  *  most frequently.
7698                  */
7699                 if (hit->h<min) {
7700                     nd.distance = min - hit->h + 1; /*  penalty to ensure other nodes are chosen first in case of overlapping ones */
7701                 } else if (hit->h>max) {
7702                     nd.distance = max - hit->h - 1; /*  same kind of penalty */
7703                 } else if (hit->h>med) {
7704                     /*  do things like if the node had 0 width and was placed at the max edge + 1*/
7705                     nd.distance = max - hit->h + 1; /*  positive, the kern is to the right of the hit point */
7706                 } else {
7707                     nd.distance = min - hit->h - 1; /*  negative, the kern is to the left of the hit point */
7708                 }
7709                 break;
7710             case synctex_node_type_rule:/* to do: special management */
7711             case synctex_node_type_glue:
7712             case synctex_node_type_math:
7713             case synctex_node_type_boundary:
7714             case synctex_node_type_box_bdry:
7715                 nd.distance = _synctex_data_h(node) - hit->h;
7716                 break;
7717             case synctex_node_type_ref:
7718                 nd.node = synctex_node_child(node);
7719                 nd = _synctex_point_h_ordered_distance_v2(hit,nd.node);
7720                 break;
7721             case synctex_node_type_proxy:
7722             case synctex_node_type_proxy_last:
7723             {
7724                 /* shift the hit point to be relative to the proxy origin,
7725                  *  then compute the distance to the target
7726                  */
7727                 synctex_point_s otherHit = *hit;
7728                 otherHit.h -= _synctex_data_h(node);
7729                 otherHit.v -= _synctex_data_v(node);
7730                 nd.node = _synctex_tree_target(node);
7731                 nd = _synctex_point_h_ordered_distance_v2(&otherHit,nd.node);
7732                 nd.node = node;
7733             }
7734             default:
7735                 break;
7736         }
7737     }
7738     return nd;
7739 }
7740 /** Rougly speaking, this is:
7741  *  node's v coordinate - hit point's v coordinate.
7742  *  If node is at the top of the hit point, then this distance is positive,
7743  *  if node is at the bottom of the hit point, this distance is negative.
7744  */
_synctex_point_v_ordered_distance_v2(synctex_point_p hit,synctex_node_p node)7745 static synctex_nd_s _synctex_point_v_ordered_distance_v2
7746 (synctex_point_p hit, synctex_node_p node) {
7747     synctex_nd_s nd = {node, INT_MAX};
7748     int min,max,depth,height;
7749     switch(synctex_node_type(node)) {
7750             /*  The distance between a point and a box is special.
7751              *  It is not the euclidian distance, nor something similar.
7752              *  We have to take into account the particular layout,
7753              *  and the box hierarchy.
7754              *  Given a box, there are 9 regions delimited by the lines of the edges of the box.
7755              *  The origin being at the top left corner of the page,
7756              *  we also give names to the vertices of the box.
7757              *
7758              *   1 | 2 | 3
7759              *  ---A---B--->
7760              *   4 | 5 | 6
7761              *  ---C---D--->
7762              *   7 | 8 | 9
7763              *     v   v
7764              */
7765         case synctex_node_type_vbox:
7766         case synctex_node_type_void_vbox:
7767         case synctex_node_type_void_hbox:
7768             /*  getting the box bounds, taking into account negative width, height and depth. */
7769             min = synctex_node_v(node);
7770             max = min + _synctex_abs(_synctex_data_depth(node));
7771             min -= _synctex_abs(_synctex_data_height(node));
7772             /*  We allways have min <= max */
7773             if (hit->v<min) {
7774                 nd.distance = min - hit->v; /*  regions 1+2+3, result is > 0 */
7775             } else if (hit->v>max) {
7776                 nd.distance = max - hit->v; /*  regions 7+8+9, result is < 0 */
7777             } else {
7778                 nd.distance = 0; /*  regions 4.5.6, inside the box, except for horizontal coordinates */
7779             }
7780             break;
7781         case synctex_node_type_proxy_vbox:
7782             /*  getting the box bounds, taking into account negative width, height and depth. */
7783             min = synctex_node_v(node);
7784             max = min + _synctex_abs(synctex_node_depth(node));
7785             min -= _synctex_abs(synctex_node_height(node));
7786             /*  We allways have min <= max */
7787             if (hit->v<min) {
7788                 nd.distance = min - hit->v; /*  regions 1+2+3, result is > 0 */
7789             } else if (hit->v>max) {
7790                 nd.distance = max - hit->v; /*  regions 7+8+9, result is < 0 */
7791             } else {
7792                 nd.distance = 0; /*  regions 4.5.6, inside the box, except for horizontal coordinates */
7793             }
7794             break;
7795         case synctex_node_type_hbox:
7796         case synctex_node_type_proxy_hbox:
7797             /*  getting the box bounds, taking into account negative height and depth. */
7798             min = synctex_node_hbox_v(node);
7799             depth = synctex_node_hbox_depth(node);
7800             max = min + (depth>0?depth:-depth);
7801             height = synctex_node_hbox_height(node);
7802             min -= (height>0?height:-height);
7803             /*  We allways have min <= max */
7804             if (hit->v<min) {
7805                 nd.distance = min - hit->v; /*  regions 1+2+3, result is > 0 */
7806             } else if (hit->v>max) {
7807                 nd.distance = max - hit->v; /*  regions 7+8+9, result is < 0 */
7808             } else {
7809                 nd.distance = 0; /*  regions 4.5.6, inside the box, except for horizontal coordinates */
7810             }
7811             break;
7812         case synctex_node_type_rule:/* to do: special management */
7813         case synctex_node_type_kern:
7814         case synctex_node_type_glue:
7815         case synctex_node_type_math:
7816             min = _synctex_data_v(node);
7817             max = min + _synctex_abs(_synctex_data_depth(_synctex_tree_parent(node)));
7818             min -= _synctex_abs(_synctex_data_height(_synctex_tree_parent(node)));
7819             /*  We allways have min <= max */
7820             if (hit->v<min) {
7821                 nd.distance = min - hit->v; /*  regions 1+2+3, result is > 0 */
7822             } else if (hit->v>max) {
7823                 nd.distance = max - hit->v; /*  regions 7+8+9, result is < 0 */
7824             } else {
7825                 nd.distance = 0; /*  regions 4.5.6, inside the box, except for horizontal coordinates */
7826             }
7827             break;
7828         case synctex_node_type_ref:
7829             nd.node = synctex_node_child(node);
7830             nd = _synctex_point_v_ordered_distance_v2(hit,nd.node);
7831             break;
7832         case synctex_node_type_proxy:
7833         case synctex_node_type_proxy_last:
7834         {
7835             synctex_point_s otherHit = *hit;
7836             otherHit.h -= _synctex_data_h(node);
7837             otherHit.v -= _synctex_data_v(node);
7838             nd.node = _synctex_tree_target(node);
7839             nd = _synctex_point_v_ordered_distance_v2(&otherHit,nd.node);
7840             nd.node = node;
7841         }
7842         default: break;
7843     }
7844     return nd;
7845 }
7846 /**
7847  *  The best is the one with the smallest area.
7848  *  The area is width*height where width and height may be big.
7849  *  So there is a real risk of overflow if we stick with ints.
7850  */
_synctex_smallest_container_v2(synctex_node_p node,synctex_node_p other_node)7851 SYNCTEX_INLINE static synctex_node_p _synctex_smallest_container_v2(synctex_node_p node, synctex_node_p other_node) {
7852     long total_height, other_total_height;
7853     unsigned long area, other_area;
7854     long width = synctex_node_hbox_width(node);
7855     long other_width = synctex_node_hbox_width(other_node);
7856     if (width<0) {
7857         width = -width;
7858     }
7859     if (other_width<0) {
7860         other_width = -other_width;
7861     }
7862     total_height = _synctex_abs(synctex_node_hbox_depth(node)) + _synctex_abs(synctex_node_hbox_height(node));
7863     other_total_height = _synctex_abs(synctex_node_hbox_depth(other_node)) + _synctex_abs(synctex_node_hbox_height(other_node));
7864     area = total_height*width;
7865     other_area = other_total_height*other_width;
7866     if (area<other_area) {
7867         return node;
7868     }
7869     if (area>other_area) {
7870         return other_node;
7871     }
7872     if (_synctex_abs(_synctex_data_width(node))>_synctex_abs(_synctex_data_width(other_node))) {
7873         return node;
7874     }
7875     if (_synctex_abs(_synctex_data_width(node))<_synctex_abs(_synctex_data_width(other_node))) {
7876         return other_node;
7877     }
7878     if (total_height<other_total_height) {
7879         return node;
7880     }
7881     if (total_height>other_total_height) {
7882         return other_node;
7883     }
7884     return node;
7885 }
7886 
_synctex_point_in_box_v2(synctex_point_p hit,synctex_node_p node)7887 SYNCTEX_INLINE static synctex_bool_t _synctex_point_in_box_v2(synctex_point_p hit, synctex_node_p node) {
7888     if (node) {
7889         if (0 == _synctex_point_h_ordered_distance_v2(hit,node).distance
7890             && 0 == _synctex_point_v_ordered_distance_v2(hit,node).distance) {
7891             return synctex_YES;
7892         }
7893     }
7894     return synctex_NO;
7895 }
7896 
_synctex_distance_to_box_v2(synctex_point_p hit,synctex_box_p box)7897 static int _synctex_distance_to_box_v2(synctex_point_p hit,synctex_box_p box) {
7898     /*  The distance between a point and a box is special.
7899      *  It is not the euclidian distance, nor something similar.
7900      *  We have to take into account the particular layout,
7901      *  and the box hierarchy.
7902      *  Given a box, there are 9 regions delimited by the lines of the edges of the box.
7903      *  The origin being at the top left corner of the page,
7904      *  we also give names to the vertices of the box.
7905      *
7906      *   1 | 2 | 3
7907      *  ---A---B--->
7908      *   4 | 5 | 6
7909      *  ---C---D--->
7910      *   7 | 8 | 9
7911      *     v   v
7912      *  In each region, there is a different formula.
7913      *  In the end we have a continuous distance which may not be a mathematical distance but who cares. */
7914     if (hit->v<box->min.v) {
7915         /*  Regions 1, 2 or 3 */
7916         if (hit->h<box->min.h) {
7917             /*  This is region 1. The distance to the box is the L1 distance PA. */
7918             return box->min.v - hit->v + box->min.h - hit->h;/*  Integer overflow? probability epsilon */
7919         } else if (hit->h<=box->max.h) {
7920             /*  This is region 2. The distance to the box is the geometrical distance to the top edge.  */
7921             return box->min.v - hit->v;
7922         } else {
7923             /*  This is region 3. The distance to the box is the L1 distance PB. */
7924             return box->min.v - hit->v + hit->h - box->max.h;
7925         }
7926     } else if (hit->v<=box->max.v) {
7927         /*  Regions 4, 5 or 6 */
7928         if (hit->h<box->min.h) {
7929             /*  This is region 4. The distance to the box is the geometrical distance to the left edge.  */
7930             return box->min.h - hit->h;
7931         } else if (hit->h<=box->max.h) {
7932             /*  This is region 5. We are inside the box.  */
7933             return 0;
7934         } else {
7935             /*  This is region 6. The distance to the box is the geometrical distance to the right edge.  */
7936             return hit->h - box->max.h;
7937         }
7938     } else {
7939         /*  Regions 7, 8 or 9 */
7940         if (hit->h<box->min.h) {
7941             /*  This is region 7. The distance to the box is the L1 distance PC. */
7942             return hit->v - box->max.v + box->min.h - hit->h;
7943         } else if (hit->h<=box->max.h) {
7944             /*  This is region 8. The distance to the box is the geometrical distance to the top edge.  */
7945             return hit->v - box->max.v;
7946         } else {
7947             /*  This is region 9. The distance to the box is the L1 distance PD. */
7948             return hit->v - box->max.v + hit->h - box->max.h;
7949         }
7950     }
7951 }
7952 
7953 /**
7954  *  The distance from the hit point to the node.
7955  */
_synctex_point_node_distance_v2(synctex_point_p hit,synctex_node_p node)7956 static int _synctex_point_node_distance_v2(synctex_point_p hit, synctex_node_p node) {
7957     int d = INT_MAX;
7958     if (node) {
7959         synctex_box_s box = {{0,0},{0,0}};
7960         int dd = INT_MAX;
7961         switch(synctex_node_type(node)) {
7962             case synctex_node_type_vbox:
7963                 box.min.h = _synctex_data_h(node);
7964                 box.max.h = box.min.h + _synctex_abs(_synctex_data_width(node));
7965                 box.min.v = synctex_node_v(node);
7966                 box.max.v = box.min.v + _synctex_abs(_synctex_data_depth(node));
7967                 box.min.v -= _synctex_abs(_synctex_data_height(node));
7968                 return _synctex_distance_to_box_v2(hit,&box);
7969             case synctex_node_type_proxy_vbox:
7970                 box.min.h = synctex_node_h(node);
7971                 box.max.h = box.min.h + _synctex_abs(synctex_node_width(node));
7972                 box.min.v = synctex_node_v(node);
7973                 box.max.v = box.min.v + _synctex_abs(synctex_node_depth(node));
7974                 box.min.v -= _synctex_abs(synctex_node_height(node));
7975                 return _synctex_distance_to_box_v2(hit,&box);
7976             case synctex_node_type_hbox:
7977             case synctex_node_type_proxy_hbox:
7978                 box.min.h = synctex_node_hbox_h(node);
7979                 box.max.h = box.min.h + _synctex_abs(synctex_node_hbox_width(node));
7980                 box.min.v = synctex_node_hbox_v(node);
7981                 box.max.v = box.min.v + _synctex_abs(synctex_node_hbox_depth(node));
7982                 box.min.v -= _synctex_abs(synctex_node_hbox_height(node));
7983                 return _synctex_distance_to_box_v2(hit,&box);
7984             case synctex_node_type_void_vbox:
7985             case synctex_node_type_void_hbox:
7986                 /*  best of distances from the left edge and right edge*/
7987                 box.min.h = _synctex_data_h(node);
7988                 box.max.h = box.min.h;
7989                 box.min.v = _synctex_data_v(node);
7990                 box.max.v = box.min.v + _synctex_abs(_synctex_data_depth(node));
7991                 box.min.v -= _synctex_abs(_synctex_data_height(node));
7992                 d = _synctex_distance_to_box_v2(hit,&box);
7993                 box.min.h = box.min.h + _synctex_abs(_synctex_data_width(node));
7994                 box.max.h = box.min.h;
7995                 dd = _synctex_distance_to_box_v2(hit,&box);
7996                 return d<dd ? d:dd;
7997             case synctex_node_type_kern:
7998                 box.min.h = _synctex_data_h(node);
7999                 box.max.h = box.min.h;
8000                 box.max.v = _synctex_data_v(node);
8001                 box.min.v = box.max.v - _synctex_abs(_synctex_data_height(_synctex_tree_parent(node)));
8002                 d = _synctex_distance_to_box_v2(hit,&box);
8003                 box.min.h -= _synctex_data_width(node);
8004                 box.max.h = box.min.h;
8005                 dd = _synctex_distance_to_box_v2(hit,&box);
8006                 return d<dd ? d:dd;
8007             case synctex_node_type_glue:
8008             case synctex_node_type_math:
8009             case synctex_node_type_boundary:
8010             case synctex_node_type_box_bdry:
8011                 box.min.h = _synctex_data_h(node);
8012                 box.max.h = box.min.h;
8013                 box.max.v = _synctex_data_v(node);
8014                 box.min.v = box.max.v - _synctex_abs(_synctex_data_height(_synctex_tree_parent(node)));
8015                 return _synctex_distance_to_box_v2(hit,&box);
8016             case synctex_node_type_proxy:
8017             case synctex_node_type_proxy_last:
8018             {
8019                 synctex_point_s otherHit = *hit;
8020                 otherHit.h -= _synctex_data_h(node);
8021                 otherHit.v -= _synctex_data_v(node);
8022                 return _synctex_point_node_distance_v2(&otherHit, _synctex_tree_target(node));
8023             }
8024             default: break;
8025         }
8026     }
8027     return d;
8028 }
_synctex_eq_deepest_container_v2(synctex_point_p hit,synctex_node_p node)8029 static synctex_node_p _synctex_eq_deepest_container_v2(synctex_point_p hit, synctex_node_p node) {
8030     if (node) {
8031         /**/
8032         synctex_node_p child;
8033         if ((child = synctex_node_child(node))) {
8034             /*  Non void hbox or vbox, form ref or proxy */
8035             /*  We go deep first because some boxes have 0 dimensions
8036              *  despite they do contain some black material.
8037              */
8038             do {
8039                 if ((_synctex_point_in_box_v2(hit,child))) {
8040                     synctex_node_p deep = _synctex_eq_deepest_container_v2(hit,child);
8041                     if (deep) {
8042                         /*  One of the children contains the hit. */
8043                         return deep;
8044                     }
8045                 }
8046             } while((child = synctex_node_sibling(child)));
8047             /*  is the hit point inside the box? */
8048             if (synctex_node_type(node) == synctex_node_type_vbox
8049                 || synctex_node_type(node) == synctex_node_type_proxy_vbox) {
8050                 /*  For vboxes we try to use some node inside.
8051                  *  Walk through the list of siblings until we find the closest one.
8052                  *  Only consider siblings with children inside. */
8053                 if ((child = _synctex_tree_child(node))) {
8054                     synctex_nd_s best = SYNCTEX_ND_0;
8055                     do {
8056                         if (_synctex_tree_child(child)) {
8057                             int d = _synctex_point_node_distance_v2(hit,child);
8058                             if (d <= best.distance) {
8059                                 best = (synctex_nd_s){child, d};
8060                             }
8061                         }
8062                     } while((child = __synctex_tree_sibling(child)));
8063                     if (best.node) {
8064                         return best.node;
8065                     }
8066                 }
8067             }
8068             if (_synctex_point_in_box_v2(hit,node)) {
8069                 return node;
8070             }
8071         }
8072     }
8073     return NULL;
8074 }
_synctex_eq_deepest_container_v3(synctex_point_p hit,synctex_node_p node)8075 static synctex_nd_s _synctex_eq_deepest_container_v3(synctex_point_p hit, synctex_node_p node) {
8076     if (node) {
8077         synctex_node_p child = NULL;
8078         if ((child = synctex_node_child(node))) {
8079             /*  Non void hbox, vbox, box proxy or form ref */
8080             /*  We go deep first because some boxes have 0 dimensions
8081              *  despite they do contain some black material.
8082              */
8083             do {
8084                 synctex_nd_s deep = _synctex_eq_deepest_container_v3(hit, child);
8085                 if (deep.node) {
8086                     /*  One of the children contains the hit-> */
8087                     return deep;
8088                 }
8089             } while((child = synctex_node_sibling(child)));
8090             /*  For vboxes we try to use some node inside.
8091              *  Walk through the list of siblings until we find the closest one.
8092              *  Only consider siblings with children inside. */
8093             if (synctex_node_type(node) == synctex_node_type_vbox
8094                 || synctex_node_type(node) == synctex_node_type_proxy_vbox) {
8095                 if ((child = synctex_node_child(node))) {
8096                     synctex_nd_s best = SYNCTEX_ND_0;
8097                     do {
8098                         if (synctex_node_child(child)) {
8099                             int d = _synctex_point_node_distance_v2(hit,child);
8100                             if (d < best.distance) {
8101                                 best = (synctex_nd_s){child,d};
8102                             }
8103                         }
8104                     } while((child = synctex_node_sibling(child)));
8105                     if (best.node) {
8106                         return best;
8107                     }
8108                 }
8109             }
8110             /*  is the hit point inside the box? */
8111             if (_synctex_point_in_box_v2(hit,node)) {
8112                 return (synctex_nd_s){node, 0};
8113             }
8114         }
8115     }
8116     return SYNCTEX_ND_0;
8117 }
8118 
8119 /*  Compares the locations of the hit point with the locations of
8120  *  the various nodes contained in the box.
8121  *  As it is an horizontal box, we only compare horizontal coordinates.
8122  */
__synctex_eq_get_closest_children_in_hbox_v2(synctex_point_p hitP,synctex_node_p node)8123 SYNCTEX_INLINE static synctex_nd_lr_s __synctex_eq_get_closest_children_in_hbox_v2(synctex_point_p hitP, synctex_node_p node) {
8124     synctex_nd_s childd = SYNCTEX_ND_0;
8125     synctex_nd_lr_s nds = {SYNCTEX_ND_0,SYNCTEX_ND_0};
8126     if ((childd.node = synctex_node_child(node))) {
8127         synctex_nd_s nd = SYNCTEX_ND_0;
8128         do {
8129             childd = _synctex_point_h_ordered_distance_v2(hitP,childd.node);
8130             if (childd.distance > 0) {
8131                 /*  node is to the right of the hit point.
8132                  *  We compare node and the previously recorded one, through the recorded distance.
8133                  *  If the nodes have the same tag, prefer the one with the smallest line number,
8134                  *  if the nodes also have the same line number, prefer the one with the smallest column. */
8135                 if (nds.r.distance > childd.distance) {
8136                     nds.r = childd;
8137                 } else if (nds.r.distance == childd.distance && nds.r.node) {
8138                     if (_synctex_data_tag(nds.r.node) == _synctex_data_tag(childd.node)
8139                         && (_synctex_data_line(nds.r.node) > _synctex_data_line(childd.node)
8140                             || (_synctex_data_line(nds.r.node) == _synctex_data_line(childd.node)
8141                                 && _synctex_data_column(nds.r.node) > _synctex_data_column(childd.node)))) {
8142                                 nds.r = childd;
8143                             }
8144                 }
8145             } else if (childd.distance == 0) {
8146                 /*  hit point is inside node. */
8147                 if (_synctex_tree_child(childd.node)) {
8148                     return _synctex_eq_get_closest_children_in_box_v2(hitP, childd.node);
8149                 }
8150                 nds.l = childd;
8151             } else { /*  here childd.distance < 0, the hit point is to the right of node */
8152                 childd.distance = -childd.distance;
8153                 if (nds.l.distance > childd.distance) {
8154                     nds.l = childd;
8155                 } else if (nds.l.distance == childd.distance && nds.l.node) {
8156                     if (_synctex_data_tag(nds.l.node) == _synctex_data_tag(childd.node)
8157                         && (_synctex_data_line(nds.l.node) > _synctex_data_line(childd.node)
8158                             || (_synctex_data_line(nds.l.node) == _synctex_data_line(childd.node)
8159                                 && _synctex_data_column(nds.l.node) > _synctex_data_column(childd.node)))) {
8160                                 nds.l = childd;
8161                             }
8162                 }
8163             }
8164         } while((childd.node = synctex_node_sibling(childd.node)));
8165         if (nds.l.node) {
8166             /*  the left node is new, try to narrow the result */
8167             if ((nd = _synctex_eq_deepest_container_v3(hitP,nds.l.node)).node) {
8168                 nds.l = nd;
8169             }
8170             if((nd = __synctex_closest_deep_child_v2(hitP,nds.l.node)).node) {
8171                 nds.l.node = nd.node;
8172             }
8173         }
8174         if (nds.r.node) {
8175             /*  the right node is new, try to narrow the result */
8176             if ((nd = _synctex_eq_deepest_container_v3(hitP,nds.r.node)).node) {
8177                 nds.r = nd;
8178             }
8179             if((nd = __synctex_closest_deep_child_v2(hitP,nds.r.node)).node) {
8180                 nds.r.node = nd.node;
8181             }
8182         }
8183     }
8184     return nds;
8185 }
8186 
8187 #if 0
8188 SYNCTEX_INLINE static synctex_nd_lr_s __synctex_eq_get_closest_children_in_hbox_v3(synctex_point_p hitP, synctex_node_p nodeP) {
8189     synctex_nd_s nd = SYNCTEX_ND_0;
8190     synctex_nd_lr_s nds = {SYNCTEX_ND_0,SYNCTEX_ND_0};
8191     if ((nd.node = _synctex_tree_child(nodeP))) {
8192         do {
8193             nd = _synctex_point_h_ordered_distance_v2(hitP,nd.node);
8194             if (nd.distance > 0) {
8195                 /*  node is to the right of the hit point.
8196                  *  We compare node and the previously recorded one, through the recorded distance.
8197                  *  If the nodes have the same tag, prefer the one with the smallest line number,
8198                  *  if the nodes also have the same line number, prefer the one with the smallest column. */
8199                 if (nds.r.distance > nd.distance) {
8200                     nds.r = nd;
8201                 } else if (nds.r.distance == nd.distance && nds.r.node) {
8202                     if (_synctex_data_tag(nds.r.node) == _synctex_data_tag(nd.node)
8203                         && (_synctex_data_line(nds.r.node) > _synctex_data_line(nd.node)
8204                             || (_synctex_data_line(nds.r.node) == _synctex_data_line(nd.node)
8205                                 && _synctex_data_column(nds.r.node) > _synctex_data_column(nd.node)))) {
8206                                 nds.r = nd;
8207                             }
8208                 }
8209             } else if (nd.distance == 0) {
8210                 /*  hit point is inside node. */
8211                 nds.l = nd;
8212             } else { /*  here nd.d < 0, the hit point is to the right of node */
8213                 nd.distance = -nd.distance;
8214                 if (nds.l.distance > nd.distance) {
8215                     nds.l = nd;
8216                 } else if (nds.l.distance == nd.distance && nds.l.node) {
8217                     if (_synctex_data_tag(nds.l.node) == _synctex_data_tag(nd.node)
8218                         && (_synctex_data_line(nds.l.node) > _synctex_data_line(nd.node)
8219                             || (_synctex_data_line(nds.l.node) == _synctex_data_line(nd.node)
8220                                 && _synctex_data_column(nds.l.node) > _synctex_data_column(nd.node)))) {
8221                                 nds.l = nd;
8222                             }
8223                 }
8224             }
8225         } while((nd.node = __synctex_tree_sibling(nd.node)));
8226         if (nds.l.node) {
8227             /*  the left node is new, try to narrow the result */
8228             if ((nd.node = _synctex_eq_deepest_container_v2(hitP,nds.l.node))) {
8229                 nds.l.node = nd.node;
8230             }
8231             if((nd = _synctex_eq_closest_child_v2(hitP,nds.l.node)).node) {
8232                 nds.l.node = nd.node;
8233             }
8234         }
8235         if (nds.r.node) {
8236             /*  the right node is new, try to narrow the result */
8237             if ((nd.node = _synctex_eq_deepest_container_v2(hitP,nds.r.node))) {
8238                 nds.r.node = nd.node;
8239             }
8240             if((nd = _synctex_eq_closest_child_v2(hitP,nds.r.node)).node) {
8241                 nds.r.node = nd.node;
8242             }
8243         }
8244     }
8245     return nds;
8246 }
8247 #endif
__synctex_eq_get_closest_children_in_vbox_v2(synctex_point_p hitP,synctex_node_p nodeP)8248 SYNCTEX_INLINE static synctex_nd_lr_s __synctex_eq_get_closest_children_in_vbox_v2(synctex_point_p hitP, synctex_node_p nodeP) {
8249     SYNCTEX_UNUSED(nodeP)
8250     synctex_nd_lr_s nds = {SYNCTEX_ND_0,SYNCTEX_ND_0};
8251     synctex_nd_s nd = SYNCTEX_ND_0;
8252     if ((nd.node = synctex_node_child(nd.node))) {
8253         do {
8254             nd = _synctex_point_v_ordered_distance_v2(hitP,nd.node);
8255             /*  this is what makes the difference with the h version above */
8256             if (nd.distance > 0) {
8257                 /*  node is to the top of the hit point (below because TeX is oriented from top to bottom.
8258                  *  We compare node and the previously recorded one, through the recorded distance.
8259                  *  If the nodes have the same tag, prefer the one with the smallest line number,
8260                  *  if the nodes also have the same line number, prefer the one with the smallest column. */
8261                 if (nds.r.distance > nd.distance) {
8262                     nds.r = nd;
8263                 } else if (nds.r.distance == nd.distance && nds.r.node) {
8264                     if (_synctex_data_tag(nds.r.node) == _synctex_data_tag(nd.node)
8265                         && (_synctex_data_line(nds.r.node) > _synctex_data_line(nd.node)
8266                             || (_synctex_data_line(nds.r.node) == _synctex_data_line(nd.node)
8267                                 && _synctex_data_column(nds.r.node) > _synctex_data_column(nd.node)))) {
8268                                 nds.r = nd;
8269                             }
8270                 }
8271             } else if (nd.distance == 0) {
8272                 nds.l = nd;
8273             } else { /*  here nd < 0 */
8274                 nd.distance = -nd.distance;
8275                 if (nds.l.distance > nd.distance) {
8276                     nds.l = nd;
8277                 } else if (nds.l.distance == nd.distance && nds.l.node) {
8278                     if (_synctex_data_tag(nds.l.node) == _synctex_data_tag(nd.node)
8279                         && (_synctex_data_line(nds.l.node) > _synctex_data_line(nd.node)
8280                             || (_synctex_data_line(nds.l.node) == _synctex_data_line(nd.node)
8281                                 && _synctex_data_column(nds.l.node) > _synctex_data_column(nd.node)))) {
8282                                 nds.l = nd;
8283                             }
8284                 }
8285             }
8286         } while((nd.node = synctex_node_sibling(nd.node)));
8287         if (nds.l.node) {
8288             if ((nd.node = _synctex_eq_deepest_container_v2(hitP,nds.l.node))) {
8289                 nds.l.node = nd.node;
8290             }
8291             if((nd = _synctex_eq_closest_child_v2(hitP,nds.l.node)).node) {
8292                 nds.l.node = nd.node;
8293             }
8294         }
8295         if (nds.r.node) {
8296             if ((nd.node = _synctex_eq_deepest_container_v2(hitP,nds.r.node))) {
8297                 nds.r.node = nd.node;
8298             }
8299             if((nd = _synctex_eq_closest_child_v2(hitP,nds.r.node)).node) {
8300                 nds.r.node = nd.node;
8301             }
8302         }
8303     }
8304     return nds;
8305 }
8306 
8307 /**
8308  *  Get the child closest to the hit point.
8309  *  - parameter: hit point
8310  *  - parameter: containing node
8311  *  - returns: the child and the distance to the hit point.
8312  *      SYNCTEX_ND_0 if the parameter node has no children.
8313  *  - note: recursive call.
8314  */
__synctex_closest_deep_child_v2(synctex_point_p hitP,synctex_node_p node)8315 static synctex_nd_s __synctex_closest_deep_child_v2(synctex_point_p hitP, synctex_node_p node) {
8316     synctex_nd_s best = SYNCTEX_ND_0;
8317     synctex_node_p child = NULL;
8318     if ((child = synctex_node_child(node))) {
8319 #if defined(SYNCTEX_DEBUG)
8320         printf("Closest deep child on box at line %i\n",
8321                SYNCTEX_LINEINDEX(node));
8322 #endif
8323         do {
8324 #if SYNCTEX_DEBUG>500
8325             synctex_node_display(child);
8326 #endif
8327             synctex_nd_s nd = SYNCTEX_ND_0;
8328             if (_synctex_node_is_box(child)) {
8329                 nd = __synctex_closest_deep_child_v2(hitP,child);
8330             } else {
8331                 nd = (synctex_nd_s) {child, _synctex_point_node_distance_v2(hitP,child)};
8332             }
8333             if (nd.distance < best.distance ||(nd.distance == best.distance
8334                                                && synctex_node_type(nd.node) != synctex_node_type_kern)) {
8335 #if defined(SYNCTEX_DEBUG)
8336                 if(nd.node) {
8337                     printf("New best %i<=%i line %i\n",nd.distance,
8338                            best.distance,SYNCTEX_LINEINDEX(nd.node));
8339                 }
8340 #endif
8341                 best = nd;
8342             }
8343         } while((child = synctex_node_sibling(child)));
8344 #if defined(SYNCTEX_DEBUG)
8345         if(best.node) {
8346             printf("Found new best %i line %i\n",best.distance,SYNCTEX_LINEINDEX(best.node));
8347         }
8348 #endif
8349     }
8350     return best;
8351 }
8352 
8353 /**
8354  *  Return the closest child.
8355  *  - parameter: a pointer to the hit point,
8356  *  - parameter: the container
8357  *  - return: SYNCTEX_ND_0 if node has no child,
8358  *      the __synctex_closest_deep_child_v2 otherwise.
8359  */
_synctex_eq_closest_child_v2(synctex_point_p hitP,synctex_node_p node)8360 static synctex_nd_s _synctex_eq_closest_child_v2(synctex_point_p hitP, synctex_node_p node) {
8361     synctex_nd_s nd = SYNCTEX_ND_0;
8362     if (_synctex_node_is_box(node)) {
8363         nd = __synctex_closest_deep_child_v2(hitP, node);
8364         if (_synctex_node_is_box(nd.node)) {
8365             synctex_node_p child = NULL;
8366             if ((child = synctex_node_child(nd.node))) {
8367                 synctex_nd_s best = {child,_synctex_point_node_distance_v2(hitP,child)};
8368                 while((child = synctex_node_sibling(child))) {
8369                     int d = _synctex_point_node_distance_v2(hitP,child);
8370                     if (d < best.distance) {
8371                         best = (synctex_nd_s){child,d};
8372                     } else if (d == best.distance && synctex_node_type(child) != synctex_node_type_kern) {
8373                         best.node = child;
8374                     }
8375                 }
8376                 return best;
8377             }
8378         }
8379         return nd;
8380     }
8381     return SYNCTEX_ND_0;
8382 }
_synctex_eq_get_closest_children_in_box_v2(synctex_point_p hitP,synctex_node_p node)8383 SYNCTEX_INLINE static synctex_nd_lr_s _synctex_eq_get_closest_children_in_box_v2(synctex_point_p hitP, synctex_node_p node) {
8384     synctex_nd_lr_s nds = {SYNCTEX_ND_0,SYNCTEX_ND_0};
8385     if(_synctex_tree_has_child(node)) { /* node != NULL */
8386         if (node->class_->type==synctex_node_type_hbox ||
8387             node->class_->type==synctex_node_type_proxy_hbox) {
8388             return __synctex_eq_get_closest_children_in_hbox_v2(hitP,node);
8389         } else {
8390             return __synctex_eq_get_closest_children_in_vbox_v2(hitP,node);
8391         }
8392     }
8393     return nds;
8394 }
8395 
8396 #ifndef SYNCTEX_NO_UPDATER
8397 
8398 #	ifdef SYNCTEX_NOTHING
8399 #       pragma mark -
8400 #       pragma mark Updater
8401 #   endif
8402 
8403 typedef int (*synctex_print_f)(synctex_updater_p, const char * , ...); /*  print formatted to either FILE *  or gzFile */
8404 typedef void (*synctex_close_f)(synctex_updater_p); /*  close FILE *  or gzFile */
8405 
8406 #   define SYNCTEX_BITS_PER_BYTE 8
8407 
8408 typedef union {
8409     gzFile as_gzFile;
8410     FILE * as_FILE_p;
8411     void * as_ptr;
8412 } syncex_file_u;
8413 
8414 struct synctex_updater_t {
8415     syncex_file_u file;
8416     synctex_print_f print;
8417     synctex_close_f close;
8418     int length;             /*  the number of chars appended */
8419 };
8420 
_synctex_updater_print(synctex_updater_p updater,const char * format,...)8421 static int _synctex_updater_print(synctex_updater_p updater, const char * format, ...) {
8422     int result = 0;
8423     if (updater) {
8424         va_list va;
8425         va_start(va, format);
8426         result = vfprintf(updater->file.as_FILE_p,
8427                            format,
8428                            va);
8429         va_end(va);
8430     }
8431     return result;
8432 }
8433 #if defined(_MSC_VER)
8434 #include <stdio.h>
8435 #include <stdlib.h>
8436 #include <stdarg.h>
8437 
vasprintf(char ** ret,const char * format,va_list ap)8438 static int vasprintf(char **ret,
8439                      const char *format,
8440                      va_list ap)
8441 {
8442     int len;
8443     len = _vsnprintf(NULL, 0, format, ap);
8444     if (len < 0) return -1;
8445     *ret = malloc(len + 1);
8446     if (!*ret) return -1;
8447     _vsnprintf(*ret, len+1, format, ap);
8448     (*ret)[len] = '\0';
8449     return len;
8450 }
8451 
8452 #endif
8453 
8454 /**
8455  *  gzvprintf is not available until OSX 10.10
8456  */
_synctex_updater_print_gz(synctex_updater_p updater,const char * format,...)8457 static int _synctex_updater_print_gz(synctex_updater_p updater, const char * format, ...) {
8458     int result = 0;
8459     if (updater) {
8460         char * buffer;
8461         va_list va;
8462         va_start(va, format);
8463         if (vasprintf(&buffer, format, va) < 0) {
8464             _synctex_error("Out of memory...");
8465         } else if ((result = (int)strlen(buffer))) {
8466             result = gzwrite(updater->file.as_gzFile, buffer, (unsigned)result);
8467         }
8468         va_end(va);
8469         free(buffer);
8470     }
8471     return result;
8472 }
8473 
_synctex_updater_close(synctex_updater_p updater)8474 static void _synctex_updater_close(synctex_updater_p updater) {
8475     if (updater) {
8476         fclose(updater->file.as_FILE_p);
8477     }
8478 }
8479 
_synctex_updater_close_gz(synctex_updater_p updater)8480 static void _synctex_updater_close_gz(synctex_updater_p updater) {
8481     if (updater) {
8482         gzclose(updater->file.as_gzFile);
8483     }
8484 }
8485 
synctex_updater_new_with_output_file(const char * output,const char * build_directory)8486 synctex_updater_p synctex_updater_new_with_output_file(const char * output, const char * build_directory) {
8487     synctex_updater_p updater = NULL;
8488     const char * mode = NULL;
8489     synctex_open_s open;
8490     /*  prepare the updater, the memory is the only one dynamically allocated */
8491     updater = (synctex_updater_p)_synctex_malloc(sizeof(synctex_updater_s));
8492     if (NULL == updater) {
8493         _synctex_error("!  synctex_updater_new_with_file: malloc problem");
8494         return NULL;
8495     }
8496     open = _synctex_open_v2(output,build_directory,0,synctex_ADD_QUOTES);
8497     if (open.status < SYNCTEX_STATUS_OK) {
8498         open = _synctex_open_v2(output,build_directory,0,synctex_DONT_ADD_QUOTES);
8499         if (open.status < SYNCTEX_STATUS_OK) {
8500         return_on_error:
8501             _synctex_free(updater);
8502             return updater = NULL;
8503         }
8504     }
8505     /*  OK, the file exists, we close it and reopen it with the correct mode.
8506      *  The receiver is now the owner of the "synctex" variable. */
8507     gzclose(open.file);
8508     updater->file.as_ptr = NULL;
8509     mode = _synctex_get_io_mode_name(open.io_mode|synctex_io_append_mask);/* either "a" or "ab", depending on the file extension */
8510     if (open.io_mode&synctex_io_gz_mask) {
8511         if (NULL == (updater->file.as_FILE_p = fopen(open.synctex,mode))) {
8512         no_write_error:
8513             _synctex_error("!  synctex_updater_new_with_file: Can't append to %s",open.synctex);
8514             free(open.synctex);
8515             goto return_on_error;
8516         }
8517         updater->print = &_synctex_updater_print;
8518         updater->close = &_synctex_updater_close;
8519     } else {
8520         if (NULL == (updater->file.as_gzFile = gzopen(open.synctex,mode))) {
8521             goto no_write_error;
8522         }
8523         updater->print = &_synctex_updater_print_gz;
8524         updater->close = &_synctex_updater_close_gz;
8525     }
8526     printf("SyncTeX: updating %s...",open.synctex);
8527     _synctex_free(open.synctex);
8528     return updater;
8529 }
8530 
synctex_updater_append_magnification(synctex_updater_p updater,char * magnification)8531 void synctex_updater_append_magnification(synctex_updater_p updater, char * magnification){
8532     if (NULL==updater) {
8533         return;
8534     }
8535     if (magnification && strlen(magnification)) {
8536         updater->length +=
8537         updater->print(updater,"Magnification:%s\n",magnification);
8538     }
8539 }
8540 
synctex_updater_append_x_offset(synctex_updater_p updater,char * x_offset)8541 void synctex_updater_append_x_offset(synctex_updater_p updater, char * x_offset){
8542     if (NULL==updater) {
8543         return;
8544     }
8545     if (x_offset && strlen(x_offset)) {
8546         updater->length += updater->print(updater,"X Offset:%s\n",x_offset);
8547     }
8548 }
8549 
synctex_updater_append_y_offset(synctex_updater_p updater,char * y_offset)8550 void synctex_updater_append_y_offset(synctex_updater_p updater, char * y_offset){
8551     if (NULL==updater) {
8552         return;
8553     }
8554     if (y_offset && strlen(y_offset)) {
8555         updater->length += updater->print(updater,"Y Offset:%s\n",y_offset);
8556     }
8557 }
8558 
synctex_updater_free(synctex_updater_p updater)8559 void synctex_updater_free(synctex_updater_p updater){
8560     if (NULL==updater) {
8561         return;
8562     }
8563     if (updater->length>0) {
8564         updater->print(updater,"!%i\n",updater->length);
8565     }
8566     updater->close(updater);
8567     _synctex_free(updater);
8568     printf("... done.\n");
8569     return;
8570 }
8571 #endif
8572 
8573 #if defined(SYNCTEX_TESTING)
8574 #	ifdef SYNCTEX_NOTHING
8575 #       pragma mark -
8576 #       pragma mark Testers
8577 #   endif
_synctex_input_copy_name(synctex_node_p input,char * name)8578 static int _synctex_input_copy_name(synctex_node_p input, char * name) {
8579     char * copy = _synctex_malloc(strlen(name)+1);
8580     memcpy(copy,name,strlen(name)+1);
8581     _synctex_data_set_name(input,copy);
8582     return 0;
8583 }
synctex_test_setup_scanner_sheets_421(synctex_scanner_p scanner)8584 int synctex_test_setup_scanner_sheets_421(synctex_scanner_p scanner) {
8585     int TC = 0;
8586     synctex_node_p sheet = synctex_node_new(scanner,synctex_node_type_sheet);
8587     _synctex_data_set_page(sheet,4);
8588     SYNCTEX_TEST_BODY(TC, _synctex_data_page(sheet)==4,"");
8589     synctex_node_free(scanner->sheet);
8590     scanner->sheet = sheet;
8591     sheet = synctex_node_new(scanner,synctex_node_type_sheet);
8592     _synctex_data_set_page(sheet,2);
8593     SYNCTEX_TEST_BODY(TC, _synctex_data_page(sheet)==2,"");
8594     __synctex_tree_set_sibling(sheet, scanner->sheet);
8595     scanner->sheet = sheet;
8596     sheet = synctex_node_new(scanner,synctex_node_type_sheet);
8597     _synctex_data_set_page(sheet,1);
8598     SYNCTEX_TEST_BODY(TC, _synctex_data_page(sheet)==1,"");
8599     __synctex_tree_set_sibling(sheet, scanner->sheet);
8600     scanner->sheet = sheet;
8601     return TC;
8602 }
synctex_test_input(synctex_scanner_p scanner)8603 int synctex_test_input(synctex_scanner_p scanner) {
8604     int TC = 0;
8605     synctex_node_p input = synctex_node_new(scanner,synctex_node_type_input);
8606     _synctex_data_set_tag(input,421);
8607     SYNCTEX_TEST_BODY(TC, _synctex_data_tag(input)==421,"");
8608     _synctex_data_set_tag(input,124);
8609     SYNCTEX_TEST_BODY(TC, _synctex_data_tag(input)==124,"");
8610     _synctex_data_set_line(input,421);
8611     SYNCTEX_TEST_BODY(TC, _synctex_data_line(input)==421,"");
8612     _synctex_data_set_line(input,214);
8613     SYNCTEX_TEST_BODY(TC, _synctex_data_line(input)==214,"");
8614     _synctex_data_set_line(input,214);
8615     SYNCTEX_TEST_BODY(TC, _synctex_data_line(input)==214,"");
8616     _synctex_input_copy_name(input,"214");
8617     SYNCTEX_TEST_BODY(TC, 0==memcmp(_synctex_data_name(input),"214",4),"");
8618     _synctex_input_copy_name(input,"421421");
8619 
8620     SYNCTEX_TEST_BODY(TC,
8621                       0==memcmp(_synctex_data_name(input),
8622                                 "421421",
8623                                 4),
8624                       "");
8625     synctex_node_free(input);
8626     return TC;
8627 }
synctex_test_proxy(synctex_scanner_p scanner)8628 int synctex_test_proxy(synctex_scanner_p scanner) {
8629     int TC = 0;
8630     synctex_node_p proxy = synctex_node_new(scanner,synctex_node_type_proxy);
8631     synctex_node_p target = synctex_node_new(scanner,synctex_node_type_rule);
8632     _synctex_tree_set_target(proxy,target);
8633     _synctex_data_set_tag(target,421);
8634     SYNCTEX_TEST_BODY(TC, _synctex_data_tag(target)==421,"");
8635     SYNCTEX_TEST_BODY(TC, synctex_node_tag(target)==421,"");
8636     SYNCTEX_TEST_BODY(TC, synctex_node_tag(proxy)==421,"");
8637     synctex_node_free(proxy);
8638     synctex_node_free(target);
8639     return TC;
8640 }
synctex_test_handle(synctex_scanner_p scanner)8641 int synctex_test_handle(synctex_scanner_p scanner) {
8642     int TC = 0;
8643     synctex_node_p handle = synctex_node_new(scanner,synctex_node_type_handle);
8644     synctex_node_p proxy = synctex_node_new(scanner, synctex_node_type_proxy);
8645     synctex_node_p target = synctex_node_new(scanner,synctex_node_type_rule);
8646     _synctex_tree_set_target(handle,target);
8647     _synctex_data_set_tag(target,421);
8648     SYNCTEX_TEST_BODY(TC, _synctex_data_tag(target)==421,"");
8649     SYNCTEX_TEST_BODY(TC, synctex_node_tag(target)==421,"");
8650     SYNCTEX_TEST_BODY(TC, synctex_node_tag(handle)==421,"");
8651     _synctex_data_set_line(target,214);
8652     SYNCTEX_TEST_BODY(TC, _synctex_data_line(target)==214,"");
8653     SYNCTEX_TEST_BODY(TC, synctex_node_line(target)==214,"");
8654     SYNCTEX_TEST_BODY(TC, synctex_node_line(handle)==214,"");
8655     _synctex_data_set_column(target,142);
8656     SYNCTEX_TEST_BODY(TC, _synctex_data_column(target)==142,"");
8657     SYNCTEX_TEST_BODY(TC, synctex_node_column(target)==142,"");
8658     SYNCTEX_TEST_BODY(TC, synctex_node_column(handle)==142,"");
8659     _synctex_tree_set_target(proxy,target);
8660     _synctex_tree_set_target(handle,proxy);
8661     _synctex_data_set_tag(target,412);
8662     SYNCTEX_TEST_BODY(TC, _synctex_data_tag(target)==412,"");
8663     SYNCTEX_TEST_BODY(TC, synctex_node_tag(target)==412,"");
8664     SYNCTEX_TEST_BODY(TC, synctex_node_tag(handle)==412,"");
8665     _synctex_data_set_line(target,124);
8666     SYNCTEX_TEST_BODY(TC, _synctex_data_line(target)==124,"");
8667     SYNCTEX_TEST_BODY(TC, synctex_node_line(target)==124,"");
8668     SYNCTEX_TEST_BODY(TC, synctex_node_line(handle)==124,"");
8669     _synctex_data_set_column(target,241);
8670     SYNCTEX_TEST_BODY(TC, _synctex_data_column(target)==241,"");
8671     SYNCTEX_TEST_BODY(TC, synctex_node_column(target)==241,"");
8672     SYNCTEX_TEST_BODY(TC, synctex_node_column(handle)==241,"");
8673     synctex_node_free(handle);
8674     synctex_node_free(proxy);
8675     synctex_node_free(target);
8676     return TC;
8677 }
synctex_test_setup_scanner_input(synctex_scanner_p scanner)8678 int synctex_test_setup_scanner_input(synctex_scanner_p scanner) {
8679     int TC = 0;
8680     synctex_node_p input = synctex_node_new(scanner,synctex_node_type_input);
8681     _synctex_data_set_tag(input,4);
8682     _synctex_input_copy_name(input,"21");
8683     _synctex_data_set_line(input,421);
8684     synctex_node_free(scanner->input);
8685     scanner->input = input;
8686     SYNCTEX_TEST_BODY(TC, _synctex_data_tag(input)==4,"");
8687     SYNCTEX_TEST_BODY(TC, strcmp(_synctex_data_name(input),"21")==0,"");
8688     SYNCTEX_TEST_BODY(TC, _synctex_data_line(input)==421,"");
8689     return TC;
8690 }
synctex_test_setup_nodes(synctex_scanner_p scanner,synctex_node_r nodes)8691 int synctex_test_setup_nodes(synctex_scanner_p scanner, synctex_node_r nodes) {
8692     int TC = 0;
8693     int n;
8694     for (n=0;n<synctex_node_number_of_types;++n) {
8695         nodes[n] = synctex_node_new(scanner,n);
8696         SYNCTEX_TEST_BODY(TC, nodes[n]!=NULL,"");
8697     }
8698     return TC;
8699 }
synctex_test_teardown_nodes(synctex_scanner_p scanner,synctex_node_r nodes)8700 int synctex_test_teardown_nodes(synctex_scanner_p scanner, synctex_node_r nodes) {
8701     int n;
8702     for (n=0;n<synctex_node_number_of_types;++n) {
8703         synctex_node_free(nodes[n]);
8704         nodes[n]=NULL;
8705     }
8706     return 1;
8707 }
synctex_test_tree(synctex_scanner_p scanner)8708 int synctex_test_tree(synctex_scanner_p scanner) {
8709     int TC = 0;
8710     synctex_node_p nodes1[synctex_node_number_of_types];
8711     synctex_node_p nodes2[synctex_node_number_of_types];
8712     synctex_node_p nodes3[synctex_node_number_of_types];
8713     int i,j;
8714     TC += synctex_test_setup_nodes(scanner,nodes1);
8715     TC += synctex_test_setup_nodes(scanner,nodes2);
8716     TC += synctex_test_setup_nodes(scanner,nodes3);
8717     /*  Every node has a sibling */
8718     for (i=0;i<synctex_node_number_of_types;++i) {
8719         for (j=0;j<synctex_node_number_of_types;++j) {
8720             _synctex_tree_set_sibling(nodes1[i],nodes2[i]);
8721             SYNCTEX_TEST_BODY(TC, nodes2[i]==synctex_node_sibling(nodes1[i]),"");
8722         }
8723     }
8724     synctex_test_teardown_nodes(scanner,nodes3);
8725     synctex_test_teardown_nodes(scanner,nodes2);
8726     synctex_test_teardown_nodes(scanner,nodes1);
8727     return TC;
8728 }
synctex_test_page(synctex_scanner_p scanner)8729 int synctex_test_page(synctex_scanner_p scanner) {
8730     int TC = synctex_test_setup_scanner_sheets_421(scanner);
8731     synctex_node_p sheet = scanner->sheet;
8732     synctex_node_p node = synctex_node_new(scanner,synctex_node_type_rule);
8733     _synctex_data_set_tag(node,4);
8734     _synctex_data_set_line(node,21);
8735     synctex_node_free(_synctex_node_set_child(sheet,node));
8736     SYNCTEX_TEST_BODY(TC, synctex_node_page(node)==synctex_node_page(sheet),"");
8737     return TC;
8738 }
synctex_test_display_query(synctex_scanner_p scanner)8739 int synctex_test_display_query(synctex_scanner_p scanner) {
8740     int TC = synctex_test_setup_scanner_sheets_421(scanner);
8741     synctex_node_p sheet = scanner->sheet;
8742     synctex_node_p node = synctex_node_new(scanner,synctex_node_type_rule);
8743     _synctex_data_set_tag(node,4);
8744     _synctex_data_set_line(node,21);
8745     synctex_node_free(_synctex_node_set_child(sheet,node));
8746     SYNCTEX_TEST_BODY(TC, node==synctex_node_child(sheet),"");
8747     __synctex_node_make_friend_tlc(node);
8748     SYNCTEX_TEST_BODY(TC, _synctex_scanner_friend(scanner, 25)==node,"");
8749     sheet = __synctex_tree_sibling(sheet);
8750     node = synctex_node_new(scanner,synctex_node_type_rule);
8751     _synctex_data_set_tag(node,4);
8752     _synctex_data_set_line(node,21);
8753     synctex_node_free(_synctex_node_set_child(sheet,node));
8754     SYNCTEX_TEST_BODY(TC, node==synctex_node_child(sheet),"");
8755     __synctex_node_make_friend_tlc(node);
8756     SYNCTEX_TEST_BODY(TC, _synctex_scanner_friend(scanner, 25)==node,"");
8757     sheet = __synctex_tree_sibling(sheet);
8758     node = synctex_node_new(scanner,synctex_node_type_rule);
8759     _synctex_data_set_tag(node,4);
8760     _synctex_data_set_line(node,21);
8761     synctex_node_free(_synctex_node_set_child(sheet,node));
8762     SYNCTEX_TEST_BODY(TC, node==synctex_node_child(sheet),"");
8763     __synctex_node_make_friend_tlc(node);
8764     SYNCTEX_TEST_BODY(TC, (_synctex_scanner_friend(scanner, 25)==node),"");
8765     synctex_test_setup_scanner_input(scanner);
8766     scanner->flags.has_parsed = synctex_YES;
8767 #if 1
8768     SYNCTEX_TEST_BODY(TC, (synctex_display_query(scanner,"21",21,4,-1)==3),"");
8769 #endif
8770     return TC;
8771 }
8772 typedef struct {
8773     int s;      /* status */
8774     char n[25]; /* name */
8775 } synctex_test_sn_s;
8776 
synctex_test_tmp_sn(char * content)8777 synctex_test_sn_s synctex_test_tmp_sn(char * content) {
8778     synctex_test_sn_s sn = {0, "/tmp/test.XXXXXX.synctex"};
8779     FILE *sfp;
8780     int fd = mkstemps(sn.n,8);
8781     if (fd < 0) {
8782         fprintf(stderr, "%s: %s\n", sn.n, strerror(errno));
8783         sn.s = -1;
8784         return sn;
8785     }
8786     if ((sfp = fdopen(fd, "w+")) == NULL) {
8787         unlink(sn.n);
8788         close(fd);
8789         fprintf(stderr, "%s: %s\n", sn.n, strerror(errno));
8790         sn.s = -2;
8791         return sn;
8792     }
8793     sn.s = fputs(content,sfp);
8794     printf("temp:%s\n%i\n",sn.n,sn.s);
8795     fclose(sfp);
8796     if (sn.s==0) {
8797         sn.s = -2;
8798         unlink(sn.n);
8799     }
8800     return sn;
8801 }
synctex_test_sheet_1()8802 int synctex_test_sheet_1() {
8803     int TC = 0;
8804     char * content =
8805     "SyncTeX Version:1  \n" /*00-19*/
8806     "Input:1:./1.tex    \n" /*20-39*/
8807     "Output:pdf         \n" /*40-59*/
8808     "Magnification:100000000      \n" /*60-89*/
8809     "Unit:1   \n"           /*90-99*/
8810     "X Offset:0         \n" /*00-19*/
8811     "Y Offset:0         \n" /*20-39*/
8812     "Content: \n"           /*40-49*/
8813     "{1       \n"           /*50-59*/
8814     "[1,10:20,350:330,330,0       \n" /*60-89*/
8815     "]        \n"           /*90-99*/
8816     "}        \n"           /*00-09*/
8817     "Postamble:\n";
8818     synctex_test_sn_s sn = synctex_test_tmp_sn(content);
8819     if (sn.s>0) {
8820         synctex_scanner_p scanner = synctex_scanner_new_with_output_file(sn.n, NULL, synctex_YES);
8821         synctex_node_p node = synctex_scanner_handle(scanner);
8822         printf("Created nodes:\n");
8823         while (node) {
8824             printf("%s\n",_synctex_node_abstract(node));
8825             node = synctex_node_next(node);
8826         }
8827         synctex_scanner_free(scanner);
8828         unlink(sn.n);
8829     } else {
8830         ++TC;
8831     }
8832     return TC;
8833 }
synctex_test_sheet_2()8834 int synctex_test_sheet_2() {
8835     int TC = 0;
8836     char * content =
8837     "SyncTeX Version:1  \n" /*00-19*/
8838     "Input:1:./1.tex    \n" /*20-39*/
8839     "Output:pdf         \n" /*40-59*/
8840     "Magnification:100000000      \n" /*60-89*/
8841     "Unit:1   \n"           /*90-99*/
8842     "X Offset:0         \n" /*00-19*/
8843     "Y Offset:0         \n" /*20-39*/
8844     "Content: \n"           /*40-49*/
8845     "{1       \n"           /*50-59*/
8846     "(1,10:20,350:330,330,0       \n" /*60-89*/
8847     ")        \n"           /*90-99*/
8848     "}        \n"           /*00-09*/
8849     "Postamble:\n";
8850     synctex_test_sn_s sn = synctex_test_tmp_sn(content);
8851     if (sn.s>0) {
8852         synctex_scanner_p scanner = synctex_scanner_new_with_output_file(sn.n, NULL, synctex_YES);
8853         synctex_node_p node = synctex_scanner_handle(scanner);
8854         printf("Created nodes:\n");
8855         while (node) {
8856             printf("%s\n",_synctex_node_abstract(node));
8857             node = _synctex_node_next(node);
8858         }
8859         TC += synctex_scanner_free(scanner);
8860         unlink(sn.n);
8861     } else {
8862         ++TC;
8863     }
8864     return TC;
8865 }
synctex_test_charindex()8866 int synctex_test_charindex() {
8867     int TC = 0;
8868     char * content =
8869     "SyncTeX Version:1  \n" /*00-19*/
8870     "Input:1:./1.tex    \n" /*20-39*/
8871     "Output:pdf         \n" /*40-59*/
8872     "Magnification:100000000      \n" /*60-89*/
8873     "Unit:1   \n"           /*90-99*/
8874     "X Offset:0         \n" /*00-19*/
8875     "Y Offset:0         \n" /*20-39*/
8876     "Content: \n"           /*40-49*/
8877     "{1       \n"           /*50-59*/
8878     "[1,10:20,350:330,330,0       \n" /*60-89*/
8879     "(1,58:20,100:250,10,5        \n" /*90-119*/
8880     "f1000:50,100       \n" /*20-39*/
8881     ")        \n"           /*40-49*/
8882     "]        \n"           /*50-59*/
8883     "}        \n"           /*60-69*/
8884     "Postamble:\n";
8885     synctex_test_sn_s sn = synctex_test_tmp_sn(content);
8886     if (sn.s>0) {
8887         synctex_scanner_p scanner = synctex_scanner_new_with_output_file(sn.n, NULL, synctex_YES);
8888         synctex_node_p node = synctex_scanner_handle(scanner);
8889         printf("Created nodes:\n");
8890         while (node) {
8891             printf("%s\n",_synctex_node_abstract(node));
8892             node = synctex_node_next(node);
8893         }
8894         TC += synctex_scanner_free(scanner);
8895         unlink(sn.n);
8896     } else {
8897         ++TC;
8898     }
8899     return TC;
8900 }
synctex_test_form()8901 int synctex_test_form() {
8902     int TC = 0;
8903     char * content =
8904     "SyncTeX Version:1  \n" /*00-19*/
8905     "Input:1:./1.tex    \n" /*20-39*/
8906     "Output:pdf         \n" /*40-59*/
8907     "Magnification:100000000      \n" /*60-89*/
8908     "Unit:1   \n"           /*90-99*/
8909     "X Offset:0         \n" /*00-19*/
8910     "Y Offset:0         \n" /*20-39*/
8911     "Content: \n"           /*40-49*/
8912     "{1       \n"           /*50-59*/
8913     "[1,10:20,350:330,330,0       \n" /*60-89*/
8914     "(1,58:20,100:250,10,5        \n" /*90-119*/
8915     "f1000:50,100       \n" /*20-39*/
8916     ")        \n"           /*40-49*/
8917     "]        \n"           /*50-59*/
8918     "}        \n"           /*60-69*/
8919     "<1000    \n"           /*70-79*/
8920     "(1,63:0,0:100,8,3  \n" /*80-99*/
8921     ")        \n"           /*00-09*/
8922     ">        \n"           /*10-19*/
8923     "Postamble:\n";
8924     synctex_test_sn_s sn = synctex_test_tmp_sn(content);
8925     if (sn.s>0) {
8926         synctex_scanner_p scanner = synctex_scanner_new_with_output_file(sn.n, NULL, synctex_YES);
8927         synctex_node_p node = synctex_scanner_handle(scanner);
8928         while (node) {
8929             printf("%s\n",_synctex_node_abstract(node));
8930             node = _synctex_node_next(node);
8931         }
8932         TC += synctex_scanner_free(scanner);
8933         unlink(sn.n);
8934     } else {
8935         ++TC;
8936     }
8937     return TC;
8938 }
8939 #endif
8940