source: terepaima/terepaima-0.4.16/synctex/synctex_parser.c @ 67bb23d

desarrollostretch
Last change on this file since 67bb23d was 1f4adec, checked in by aosorio <aosorio@…>, 8 years ago

Agregado proyecto base, esto luego del dh_make -f

  • Property mode set to 100644
File size: 161.6 KB
Line 
1/*
2Copyright (c) 2008, 2009, 2010 , 2011 jerome DOT laurens AT u-bourgogne DOT fr
3
4This file is part of the SyncTeX package.
5
6Latest Revision: Tue Jun 14 08:23:30 UTC 2011
7
8Version: 1.18
9
10See synctex_parser_readme.txt for more details
11
12License:
13--------
14Permission is hereby granted, free of charge, to any person
15obtaining a copy of this software and associated documentation
16files (the "Software"), to deal in the Software without
17restriction, including without limitation the rights to use,
18copy, modify, merge, publish, distribute, sublicense, and/or sell
19copies of the Software, and to permit persons to whom the
20Software is furnished to do so, subject to the following
21conditions:
22
23The above copyright notice and this permission notice shall be
24included in all copies or substantial portions of the Software.
25
26THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
28OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
30HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
31WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33OTHER DEALINGS IN THE SOFTWARE
34
35Except as contained in this notice, the name of the copyright holder 
36shall not be used in advertising or otherwise to promote the sale, 
37use or other dealings in this Software without prior written 
38authorization from the copyright holder.
39
40Acknowledgments:
41----------------
42The author received useful remarks from the pdfTeX developers, especially Hahn The Thanh,
43and significant help from XeTeX developer Jonathan Kew
44
45Nota Bene:
46----------
47If you include or use a significant part of the synctex package into a software,
48I would appreciate to be listed as contributor and see "SyncTeX" highlighted.
49
50Version 1
51Thu Jun 19 09:39:21 UTC 2008
52
53*/
54
55/*  We assume that high level application like pdf viewers will want
56 *  to embed this code as is. We assume that they also have locale.h and setlocale.
57 *  For other tools such as TeXLive tools, you must define SYNCTEX_USE_LOCAL_HEADER,
58 *  when building. You also have to create and customize synctex_parser_local.h to fit your system.
59 *  In particular, the HAVE_LOCALE_H and HAVE_SETLOCALE macros should be properly defined.
60 *  With this design, you should not need to edit this file. */
61
62#   if defined(SYNCTEX_USE_LOCAL_HEADER)
63#       include "synctex_parser_local.h"
64#   else
65#       define HAVE_LOCALE_H 1
66#       define HAVE_SETLOCALE 1
67#       if defined(_MSC_VER)
68#          define SYNCTEX_INLINE __inline
69#       else
70#          define SYNCTEX_INLINE inline
71#       endif
72#   endif
73
74#include <stdlib.h>
75#include <stdio.h>
76#include <string.h>
77#include <errno.h>
78#include <limits.h>
79
80#if defined(HAVE_LOCALE_H)
81#include <locale.h>
82#endif
83
84/*  The data is organized in a graph with multiple entries.
85 *  The root object is a scanner, it is created with the contents on a synctex file.
86 *  Each leaf of the tree is a synctex_node_t object.
87 *  There are 3 subtrees, two of them sharing the same leaves.
88 *  The first tree is the list of input records, where input file names are associated with tags.
89 *  The second tree is the box tree as given by TeX when shipping pages out.
90 *  First level objects are sheets, containing boxes, glues, kerns...
91 *  The third tree allows to browse leaves according to tag and line.
92 */
93
94#include "synctex_parser.h"
95#include "synctex_parser_utils.h"
96
97/*  These are the possible extensions of the synctex file */
98const char * synctex_suffix = ".synctex";
99const char * synctex_suffix_gz = ".gz";
100
101/*  each synctex node has a class */
102typedef struct __synctex_class_t _synctex_class_t;
103typedef _synctex_class_t * synctex_class_t;
104
105
106/*  synctex_node_t is a pointer to a node
107 *  _synctex_node is the target of the synctex_node_t pointer
108 *  It is a pseudo object oriented program.
109 *  class is a pointer to the class object the node belongs to.
110 *  implementation is meant to contain the private data of the node
111 *  basically, there are 2 kinds of information: navigation information and
112 *  synctex information. Both will depend on the type of the node,
113 *  thus different nodes will have different private data.
114 *  There is no inheritancy overhead.
115 */
116typedef union _synctex_info_t {
117        int    INT;
118        char * PTR;
119} synctex_info_t;
120
121#   if defined(SYNCTEX_USE_CHARINDEX)
122#       define SYNCTEX_DECLARE_CHARINDEX synctex_charindex_t char_index;
123#       define SYNCTEX_CHARINDEX(NODE) (NODE->char_index)
124#       define SYNCTEX_PRINT_CHARINDEX printf("#%i\n",SYNCTEX_CHARINDEX(node))
125#       define SYNCTEX_DECLARE_CHAR_OFFSET synctex_charindex_t charindex_offset
126#       define SYNCTEX_IMPLEMENT_CHARINDEX(NODE,CORRECTION) NODE->char_index = (synctex_charindex_t)(scanner->charindex_offset+SYNCTEX_CUR-SYNCTEX_START+(CORRECTION));
127#   else
128#       define SYNCTEX_DECLARE_CHARINDEX
129#       define SYNCTEX_CHARINDEX(NODE) 0
130#       define SYNCTEX_PRINT_CHARINDEX printf("\n")
131#       define SYNCTEX_DECLARE_CHAR_OFFSET synctex_charindex_t charindex_offset
132#       define SYNCTEX_IMPLEMENT_CHARINDEX(NODE,CORRECTION)
133#   endif
134
135struct _synctex_node {
136    SYNCTEX_DECLARE_CHARINDEX
137        synctex_class_t class;
138        synctex_info_t * implementation;
139};
140
141/*  Each node of the tree, except the scanner itself belongs to a class.
142 *  The class object is just a struct declaring the owning scanner
143 *  This is a pointer to the scanner as root of the tree.
144 *  The type is used to identify the kind of node.
145 *  The class declares pointers to a creator and a destructor method.
146 *  The log and display fields are used to log and display the node.
147 *  display will also display the child, sibling and parent sibling.
148 *  parent, child and sibling are used to navigate the tree,
149 *  from TeX box hierarchy point of view.
150 *  The friend field points to a method which allows to navigate from friend to friend.
151 *  A friend is a node with very close tag and line numbers.
152 *  Finally, the info field point to a method giving the private node info offset.
153 */
154
155typedef synctex_node_t *(*_synctex_node_getter_t)(synctex_node_t);
156typedef synctex_info_t *(*_synctex_info_getter_t)(synctex_node_t);
157
158struct __synctex_class_t {
159        synctex_scanner_t scanner;
160        int type;
161        synctex_node_t (*new)(synctex_scanner_t scanner);
162        void (*free)(synctex_node_t);
163        void (*log)(synctex_node_t);
164        void (*display)(synctex_node_t);
165        _synctex_node_getter_t parent;
166        _synctex_node_getter_t child;
167        _synctex_node_getter_t sibling;
168        _synctex_node_getter_t friend;
169        _synctex_node_getter_t next_hbox;
170        _synctex_info_getter_t info;
171};
172
173#       ifdef SYNCTEX_NOTHING
174#       pragma mark -
175#       pragma mark Abstract OBJECTS and METHODS
176#   endif
177
178/*  These macros are shortcuts
179 *  This macro checks if a message can be sent.
180 */
181#   define SYNCTEX_CAN_PERFORM(NODE,SELECTOR)\
182                (NULL!=((((NODE)->class))->SELECTOR))
183
184/*  This macro is some kind of objc_msg_send.
185 *  It takes care of sending the proper message if possible.
186 */
187#   define SYNCTEX_MSG_SEND(NODE,SELECTOR) if (NODE && SYNCTEX_CAN_PERFORM(NODE,SELECTOR)) {\
188                (*((((NODE)->class))->SELECTOR))(NODE);\
189        }
190
191/*  read only safe getter
192 */
193#   define SYNCTEX_GET(NODE,SELECTOR)((NODE && SYNCTEX_CAN_PERFORM(NODE,SELECTOR))?SYNCTEX_GETTER(NODE,SELECTOR)[0]:(NULL))
194
195/*  read/write getter
196 */
197#   define SYNCTEX_GETTER(NODE,SELECTOR)\
198                ((synctex_node_t *)((*((((NODE)->class))->SELECTOR))(NODE)))
199
200#   define SYNCTEX_FREE(NODE) SYNCTEX_MSG_SEND(NODE,free);
201
202/*  Parent getter and setter
203 */
204#   define SYNCTEX_PARENT(NODE) SYNCTEX_GET(NODE,parent)
205#   define SYNCTEX_SET_PARENT(NODE,NEW_PARENT) if (NODE && NEW_PARENT && SYNCTEX_CAN_PERFORM(NODE,parent)){\
206                SYNCTEX_GETTER(NODE,parent)[0]=NEW_PARENT;\
207        }
208
209/*  Child getter and setter
210 */
211#   define SYNCTEX_CHILD(NODE) SYNCTEX_GET(NODE,child)
212#   define SYNCTEX_SET_CHILD(NODE,NEW_CHILD) if (NODE && NEW_CHILD){\
213                SYNCTEX_GETTER(NODE,child)[0]=NEW_CHILD;\
214                SYNCTEX_GETTER(NEW_CHILD,parent)[0]=NODE;\
215        }
216
217/*  Sibling getter and setter
218 */
219#   define SYNCTEX_SIBLING(NODE) SYNCTEX_GET(NODE,sibling)
220#   define SYNCTEX_SET_SIBLING(NODE,NEW_SIBLING) if (NODE && NEW_SIBLING) {\
221                SYNCTEX_GETTER(NODE,sibling)[0]=NEW_SIBLING;\
222                if (SYNCTEX_CAN_PERFORM(NEW_SIBLING,parent) && SYNCTEX_CAN_PERFORM(NODE,parent)) {\
223                        SYNCTEX_GETTER(NEW_SIBLING,parent)[0]=SYNCTEX_GETTER(NODE,parent)[0];\
224                }\
225        }
226/*  Friend getter and setter. A friend is a kern, math, glue or void box node which tag and line numbers are similar.
227 *  This is a first filter on the nodes that avoids testing all of them.
228 *  Friends are used mainly in forward synchronization aka from source to output.
229 */
230#   define SYNCTEX_FRIEND(NODE) SYNCTEX_GET(NODE,friend)
231#   define SYNCTEX_SET_FRIEND(NODE,NEW_FRIEND) if (NODE && NEW_FRIEND){\
232                SYNCTEX_GETTER(NODE,friend)[0]=NEW_FRIEND;\
233        }
234
235/*  Next box getter and setter. The box tree can be traversed from one horizontal box to the other.
236 *  Navigation starts with the deeper boxes.
237 */
238#   define SYNCTEX_NEXT_hbox(NODE) SYNCTEX_GET(NODE,next_hbox)
239#   define SYNCTEX_SET_NEXT_hbox(NODE,NEXT_HBOX) if (NODE && NEXT_HBOX){\
240                SYNCTEX_GETTER(NODE,next_hbox)[0]=NEXT_HBOX;\
241        }
242
243/*  A node is meant to own its child and sibling.
244 *  It is not owned by its parent, unless it is its first child.
245 *  This destructor is for all nodes with children.
246 */
247static void _synctex_free_node(synctex_node_t node) {
248        if (node) {
249                (*((node->class)->sibling))(node);
250                SYNCTEX_FREE(SYNCTEX_SIBLING(node));
251                SYNCTEX_FREE(SYNCTEX_CHILD(node));
252                free(node);
253        }
254        return;
255}
256
257/*  A node is meant to own its child and sibling.
258 *  It is not owned by its parent, unless it is its first child.
259 *  This destructor is for nodes with no child.
260 *  The first sheet is onwned by the scanner.
261 */
262static void _synctex_free_leaf(synctex_node_t node) {
263        if (node) {
264                SYNCTEX_FREE(SYNCTEX_SIBLING(node));
265                free(node);
266        }
267        return;
268}
269#       ifdef   __SYNCTEX_WORK__
270#               include "/usr/include/zlib.h"
271#       else
272#               include <zlib.h>
273#       endif
274
275/*  The synctex scanner is the root object.
276 *  Is is initialized with the contents of a text file or a gzipped file.
277 *  The buffer_? are first used to parse the text.
278 */
279struct __synctex_scanner_t {
280        gzFile file;                  /*  The (possibly compressed) file */
281    SYNCTEX_DECLARE_CHAR_OFFSET;
282        char * buffer_cur;            /*  current location in the buffer */
283        char * buffer_start;          /*  start of the buffer */
284        char * buffer_end;            /*  end of the buffer */
285        char * output_fmt;            /*  dvi or pdf, not yet used */
286        char * output;                /*  the output name used to create the scanner */
287        char * synctex;               /*  the .synctex or .synctex.gz name used to create the scanner */
288        int version;                  /*  1, not yet used */
289        struct {
290                unsigned has_parsed:1;          /*  Whether the scanner has parsed its underlying synctex file. */
291                unsigned reserved:sizeof(unsigned)-1;   /*  alignment */
292        } flags;
293        int pre_magnification;        /*  magnification from the synctex preamble */
294        int pre_unit;                 /*  unit from the synctex preamble */
295        int pre_x_offset;             /*  X offste from the synctex preamble */
296        int pre_y_offset;             /*  Y offset from the synctex preamble */
297        int count;                    /*  Number of records, from the synctex postamble */
298        float unit;                   /*  real unit, from synctex preamble or post scriptum */
299        float x_offset;               /*  X offset, from synctex preamble or post scriptum */
300        float y_offset;               /*  Y Offset, from synctex preamble or post scriptum */
301        synctex_node_t sheet;         /*  The first sheet node, its siblings are the other sheet nodes */
302        synctex_node_t input;         /*  The first input node, its siblings are the other input nodes */
303        int number_of_lists;          /*  The number of friend lists */
304        synctex_node_t * lists_of_friends;/*  The friend lists */
305        _synctex_class_t class[synctex_node_number_of_types]; /*  The classes of the nodes of the scanner */
306};
307
308/*  SYNCTEX_CUR, SYNCTEX_START and SYNCTEX_END are convenient shortcuts
309 */
310#   define SYNCTEX_CUR (scanner->buffer_cur)
311#   define SYNCTEX_START (scanner->buffer_start)
312#   define SYNCTEX_END (scanner->buffer_end)
313
314#       ifdef SYNCTEX_NOTHING
315#       pragma mark -
316#       pragma mark OBJECTS, their creators and destructors.
317#   endif
318
319/*  Here, we define the indices for the different informations.
320 *  They are used to declare the size of the implementation.
321 *  For example, if one object uses SYNCTEX_HORIZ_IDX is its size,
322 *  then its info will contain a tag, line, column, horiz but no width nor height nor depth
323 */
324
325/*  The sheet is a first level node.
326 *  It has no parent (the parent is the scanner itself)
327 *  Its sibling points to another sheet.
328 *  Its child points to its first child, in general a box.
329 *  A sheet node contains only one synctex information: the page.
330 *  This is the 1 based page index as given by TeX.
331 */
332/*  The next macros are used to access the node info
333 *  SYNCTEX_INFO(node) points to the first synctex integer or pointer data of node
334 *  SYNCTEX_INFO(node)[index] is the information at index
335 *  for example, the page of a sheet is stored in SYNCTEX_INFO(sheet)[SYNCTEX_PAGE_IDX]
336 */
337#   define SYNCTEX_INFO(NODE) ((*((((NODE)->class))->info))(NODE))
338#   define SYNCTEX_PAGE_IDX 0
339#   define SYNCTEX_PAGE(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_PAGE_IDX].INT
340
341/*  This macro defines implementation offsets
342 *  It is only used for pointer values
343 */
344#   define SYNCTEX_MAKE_GET(SYNCTEX_GETTER,OFFSET)\
345static synctex_node_t * SYNCTEX_GETTER (synctex_node_t node) {\
346        return node?(synctex_node_t *)((&((node)->implementation))+OFFSET):NULL;\
347}
348SYNCTEX_MAKE_GET(_synctex_implementation_0,0)
349SYNCTEX_MAKE_GET(_synctex_implementation_1,1)
350SYNCTEX_MAKE_GET(_synctex_implementation_2,2)
351SYNCTEX_MAKE_GET(_synctex_implementation_3,3)
352SYNCTEX_MAKE_GET(_synctex_implementation_4,4)
353SYNCTEX_MAKE_GET(_synctex_implementation_5,5)
354
355typedef struct {
356    SYNCTEX_DECLARE_CHARINDEX
357        synctex_class_t class;
358        synctex_info_t implementation[3+SYNCTEX_PAGE_IDX+1];/*  child, sibling, next box,
359                                 *  SYNCTEX_PAGE_IDX */
360} synctex_node_sheet_t;
361
362/*  sheet node creator */
363
364#define DEFINE_synctex_new_NODE(NAME)\
365static synctex_node_t _synctex_new_##NAME(synctex_scanner_t scanner) {\
366        if (scanner) {\
367                synctex_node_t node = _synctex_malloc(sizeof(synctex_node_##NAME##_t));\
368                if (node) {\
369                        SYNCTEX_IMPLEMENT_CHARINDEX(node,0);\
370                        ++SYNCTEX_CUR;\
371                        node->class = scanner->class+synctex_node_type_##NAME;\
372                }\
373                return node;\
374        }\
375        return NULL;\
376}
377DEFINE_synctex_new_NODE(sheet)
378
379static void _synctex_display_sheet(synctex_node_t node);
380static void _synctex_log_sheet(synctex_node_t node);
381
382static _synctex_class_t synctex_class_sheet = {
383        NULL,                       /*  No scanner yet */
384        synctex_node_type_sheet,    /*  Node type */
385        &_synctex_new_sheet,        /*  creator */
386        &_synctex_free_node,        /*  destructor */
387        &_synctex_log_sheet,        /*  log */
388        &_synctex_display_sheet,    /*  display */
389        NULL,                       /*  No parent */
390        &_synctex_implementation_0, /*  child */
391        &_synctex_implementation_1, /*  sibling */
392        NULL,                       /*  No friend */
393        &_synctex_implementation_2, /*  Next hbox */
394        (_synctex_info_getter_t)&_synctex_implementation_3  /*  info */
395};
396
397/*  A box node contains navigation and synctex information
398 *  There are different kind of boxes.
399 *  Only horizontal boxes are treated differently because of their visible size.
400 */
401#   define SYNCTEX_TAG_IDX 0
402#   define SYNCTEX_LINE_IDX (SYNCTEX_TAG_IDX+1)
403#   define SYNCTEX_COLUMN_IDX (SYNCTEX_LINE_IDX+1)
404#   define SYNCTEX_HORIZ_IDX (SYNCTEX_COLUMN_IDX+1)
405#   define SYNCTEX_VERT_IDX (SYNCTEX_HORIZ_IDX+1)
406#   define SYNCTEX_WIDTH_IDX (SYNCTEX_VERT_IDX+1)
407#   define SYNCTEX_HEIGHT_IDX (SYNCTEX_WIDTH_IDX+1)
408#   define SYNCTEX_DEPTH_IDX (SYNCTEX_HEIGHT_IDX+1)
409/*  the corresponding info accessors */
410#   define SYNCTEX_TAG(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_TAG_IDX].INT
411#   define SYNCTEX_LINE(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_LINE_IDX].INT
412#   define SYNCTEX_COLUMN(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_COLUMN_IDX].INT
413#   define SYNCTEX_HORIZ(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HORIZ_IDX].INT
414#   define SYNCTEX_VERT(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_VERT_IDX].INT
415#   define SYNCTEX_WIDTH(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_WIDTH_IDX].INT
416#   define SYNCTEX_HEIGHT(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HEIGHT_IDX].INT
417#   define SYNCTEX_DEPTH(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_DEPTH_IDX].INT
418#   define SYNCTEX_ABS_WIDTH(NODE) ((SYNCTEX_WIDTH(NODE)>0?SYNCTEX_WIDTH(NODE):-SYNCTEX_WIDTH(NODE)))
419#   define SYNCTEX_ABS_HEIGHT(NODE) ((SYNCTEX_HEIGHT(NODE)>0?SYNCTEX_HEIGHT(NODE):-SYNCTEX_HEIGHT(NODE)))
420#   define SYNCTEX_ABS_DEPTH(NODE) ((SYNCTEX_DEPTH(NODE)>0?SYNCTEX_DEPTH(NODE):-SYNCTEX_DEPTH(NODE)))
421
422typedef struct {
423    SYNCTEX_DECLARE_CHARINDEX
424        synctex_class_t class;
425        synctex_info_t implementation[5+SYNCTEX_DEPTH_IDX+1]; /*  parent,child,sibling,friend,next box,
426                                                        *  SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
427                                                                *  SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH */
428} synctex_node_vbox_t;
429
430/*  vertical box node creator */
431DEFINE_synctex_new_NODE(vbox)
432
433static void _synctex_log_vbox(synctex_node_t node);
434static void _synctex_display_vbox(synctex_node_t node);
435
436/*  These are static class objects, each scanner will make a copy of them and setup the scanner field.
437 */
438static _synctex_class_t synctex_class_vbox = {
439        NULL,                       /*  No scanner yet */
440        synctex_node_type_vbox,     /*  Node type */
441        &_synctex_new_vbox,         /*  creator */
442        &_synctex_free_node,        /*  destructor */
443        &_synctex_log_vbox,          /*  log */
444        &_synctex_display_vbox,     /*  display */
445        &_synctex_implementation_0, /*  parent */
446        &_synctex_implementation_1, /*  child */
447        &_synctex_implementation_2, /*  sibling */
448        &_synctex_implementation_3, /*  friend */
449        &_synctex_implementation_4, /*  next hbox */
450        (_synctex_info_getter_t)&_synctex_implementation_5
451};
452
453/*  Horizontal boxes must contain visible size, because 0 width does not mean emptiness.
454 *  They also contain an average of the line numbers of the containing nodes. */
455#   define SYNCTEX_MEAN_LINE_IDX (SYNCTEX_DEPTH_IDX+1)
456#   define SYNCTEX_NODE_WEIGHT_IDX (SYNCTEX_MEAN_LINE_IDX+1)
457#   define SYNCTEX_HORIZ_V_IDX (SYNCTEX_NODE_WEIGHT_IDX+1)
458#   define SYNCTEX_VERT_V_IDX (SYNCTEX_HORIZ_V_IDX+1)
459#   define SYNCTEX_WIDTH_V_IDX (SYNCTEX_VERT_V_IDX+1)
460#   define SYNCTEX_HEIGHT_V_IDX (SYNCTEX_WIDTH_V_IDX+1)
461#   define SYNCTEX_DEPTH_V_IDX (SYNCTEX_HEIGHT_V_IDX+1)
462/*  the corresponding info accessors */
463#   define SYNCTEX_MEAN_LINE(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_MEAN_LINE_IDX].INT
464#   define SYNCTEX_NODE_WEIGHT(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_NODE_WEIGHT_IDX].INT
465#   define SYNCTEX_HORIZ_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HORIZ_V_IDX].INT
466#   define SYNCTEX_VERT_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_VERT_V_IDX].INT
467#   define SYNCTEX_WIDTH_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_WIDTH_V_IDX].INT
468#   define SYNCTEX_HEIGHT_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HEIGHT_V_IDX].INT
469#   define SYNCTEX_DEPTH_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_DEPTH_V_IDX].INT
470#   define SYNCTEX_ABS_WIDTH_V(NODE) ((SYNCTEX_WIDTH_V(NODE)>0?SYNCTEX_WIDTH_V(NODE):-SYNCTEX_WIDTH_V(NODE)))
471#   define SYNCTEX_ABS_HEIGHT_V(NODE) ((SYNCTEX_HEIGHT_V(NODE)>0?SYNCTEX_HEIGHT_V(NODE):-SYNCTEX_HEIGHT_V(NODE)))
472#   define SYNCTEX_ABS_DEPTH_V(NODE) ((SYNCTEX_DEPTH_V(NODE)>0?SYNCTEX_DEPTH_V(NODE):-SYNCTEX_DEPTH_V(NODE)))
473
474typedef struct {
475    SYNCTEX_DECLARE_CHARINDEX
476        synctex_class_t class;
477        synctex_info_t implementation[5+SYNCTEX_DEPTH_V_IDX+1]; /*parent,child,sibling,friend,next box,
478                                                *  SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
479                                                *  SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH,
480                        *  SYNCTEX_MEAN_LINE,SYNCTEX_NODE_WEIGHT,
481                                                *  SYNCTEX_HORIZ_V,SYNCTEX_VERT_V,SYNCTEX_WIDTH_V,SYNCTEX_HEIGHT_V,SYNCTEX_DEPTH_V*/
482} synctex_node_hbox_t;
483
484/*  horizontal box node creator */
485DEFINE_synctex_new_NODE(hbox)
486
487static void _synctex_display_hbox(synctex_node_t node);
488static void _synctex_log_hbox(synctex_node_t node);
489
490
491static _synctex_class_t synctex_class_hbox = {
492        NULL,                       /*  No scanner yet */
493        synctex_node_type_hbox,     /*  Node type */
494        &_synctex_new_hbox,         /*  creator */
495        &_synctex_free_node,        /*  destructor */
496        &_synctex_log_hbox,    /*  log */
497        &_synctex_display_hbox,     /*  display */
498        &_synctex_implementation_0, /*  parent */
499        &_synctex_implementation_1, /*  child */
500        &_synctex_implementation_2, /*  sibling */
501        &_synctex_implementation_3, /*  friend */
502        &_synctex_implementation_4, /*  next hbox */
503        (_synctex_info_getter_t)&_synctex_implementation_5
504};
505
506/*  This void box node implementation is either horizontal or vertical
507 *  It does not contain a child field.
508 */
509typedef struct {
510    SYNCTEX_DECLARE_CHARINDEX
511        synctex_class_t class;
512        synctex_info_t implementation[3+SYNCTEX_DEPTH_IDX+1]; /*  parent,sibling,friend,
513                          *  SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
514                                          *  SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH*/
515} synctex_node_void_vbox_t;
516
517/*  vertical void box node creator */
518DEFINE_synctex_new_NODE(void_vbox)
519
520static void _synctex_log_void_box(synctex_node_t node);
521static void _synctex_display_void_vbox(synctex_node_t node);
522
523static _synctex_class_t synctex_class_void_vbox = {
524        NULL,                       /*  No scanner yet */
525        synctex_node_type_void_vbox,/*  Node type */
526        &_synctex_new_void_vbox,    /*  creator */
527        &_synctex_free_node,        /*  destructor */
528        &_synctex_log_void_box,     /*  log */
529        &_synctex_display_void_vbox,/*  display */
530        &_synctex_implementation_0, /*  parent */
531        NULL,                       /*  No child */
532        &_synctex_implementation_1, /*  sibling */
533        &_synctex_implementation_2, /*  friend */
534        NULL,                                           /*  No next hbox */
535        (_synctex_info_getter_t)&_synctex_implementation_3
536};
537
538typedef synctex_node_void_vbox_t synctex_node_void_hbox_t;
539
540/*  horizontal void box node creator */
541DEFINE_synctex_new_NODE(void_hbox)
542
543static void _synctex_display_void_hbox(synctex_node_t node);
544
545static _synctex_class_t synctex_class_void_hbox = {
546        NULL,                       /*  No scanner yet */
547        synctex_node_type_void_hbox,/*  Node type */
548        &_synctex_new_void_hbox,    /*  creator */
549        &_synctex_free_node,        /*  destructor */
550        &_synctex_log_void_box,     /*  log */
551        &_synctex_display_void_hbox,/*  display */
552        &_synctex_implementation_0, /*  parent */
553        NULL,                       /*  No child */
554        &_synctex_implementation_1, /*  sibling */
555        &_synctex_implementation_2, /*  friend */
556        NULL,                                           /*  No next hbox */
557        (_synctex_info_getter_t)&_synctex_implementation_3
558};
559
560/*  The medium nodes correspond to kern, glue, penalty and math nodes.
561 *  In LuaTeX, the size of the nodes may have changed.  */
562typedef struct {
563    SYNCTEX_DECLARE_CHARINDEX
564        synctex_class_t class;
565        synctex_info_t implementation[3+SYNCTEX_WIDTH_IDX+1]; /*  parent,sibling,friend,
566                          *  SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
567                                          *  SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH */
568} synctex_node_medium_t;
569
570#define SYNCTEX_IS_BOX(NODE)\
571        ((NODE->class->type == synctex_node_type_vbox)\
572        || (NODE->class->type == synctex_node_type_void_vbox)\
573        || (NODE->class->type == synctex_node_type_hbox)\
574        || (NODE->class->type == synctex_node_type_void_hbox))
575       
576#define SYNCTEX_HAS_CHILDREN(NODE) (NODE && SYNCTEX_CHILD(NODE))
577       
578static void _synctex_log_medium_node(synctex_node_t node);
579
580typedef synctex_node_medium_t synctex_node_math_t;
581
582/*  math node creator */
583DEFINE_synctex_new_NODE(math)
584
585static void _synctex_display_math(synctex_node_t node);
586
587static _synctex_class_t synctex_class_math = {
588        NULL,                       /*  No scanner yet */
589        synctex_node_type_math,     /*  Node type */
590        &_synctex_new_math,         /*  creator */
591        &_synctex_free_leaf,        /*  destructor */
592        &_synctex_log_medium_node,  /*  log */
593        &_synctex_display_math,     /*  display */
594        &_synctex_implementation_0, /*  parent */
595        NULL,                       /*  No child */
596        &_synctex_implementation_1, /*  sibling */
597        &_synctex_implementation_2, /*  friend */
598        NULL,                       /*  No next hbox */
599        (_synctex_info_getter_t)&_synctex_implementation_3
600};
601
602typedef synctex_node_medium_t synctex_node_kern_t;
603
604/*  kern node creator */
605DEFINE_synctex_new_NODE(kern)
606
607static void _synctex_display_kern(synctex_node_t node);
608
609static _synctex_class_t synctex_class_kern = {
610        NULL,                       /*  No scanner yet */
611        synctex_node_type_kern,     /*  Node type */
612        &_synctex_new_kern,         /*  creator */
613        &_synctex_free_leaf,        /*  destructor */
614        &_synctex_log_medium_node,  /*  log */
615        &_synctex_display_kern,     /*  display */
616        &_synctex_implementation_0, /*  parent */
617        NULL,                       /*  No child */
618        &_synctex_implementation_1, /*  sibling */
619        &_synctex_implementation_2, /*  friend */
620        NULL,                       /*  No next hbox */
621        (_synctex_info_getter_t)&_synctex_implementation_3
622};
623
624/*  The small nodes correspond to glue and boundary nodes.  */
625typedef struct {
626    SYNCTEX_DECLARE_CHARINDEX
627        synctex_class_t class;
628        synctex_info_t implementation[3+SYNCTEX_VERT_IDX+1]; /*  parent,sibling,friend,
629                          *  SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
630                                          *  SYNCTEX_HORIZ,SYNCTEX_VERT */
631} synctex_node_small_t;
632
633static void _synctex_log_small_node(synctex_node_t node);
634
635/*  glue node creator */
636typedef synctex_node_small_t synctex_node_glue_t;
637DEFINE_synctex_new_NODE(glue)
638static void _synctex_display_glue(synctex_node_t node);
639
640static _synctex_class_t synctex_class_glue = {
641        NULL,                       /*  No scanner yet */
642        synctex_node_type_glue,     /*  Node type */
643        &_synctex_new_glue,         /*  creator */
644        &_synctex_free_leaf,        /*  destructor */
645        &_synctex_log_medium_node,  /*  log */
646        &_synctex_display_glue,     /*  display */
647        &_synctex_implementation_0, /*  parent */
648        NULL,                       /*  No child */
649        &_synctex_implementation_1, /*  sibling */
650        &_synctex_implementation_2, /*  friend */
651        NULL,                       /*  No next hbox */
652        (_synctex_info_getter_t)&_synctex_implementation_3
653};
654
655/*  boundary node creator */
656typedef synctex_node_small_t synctex_node_boundary_t;
657DEFINE_synctex_new_NODE(boundary)
658
659static void _synctex_display_boundary(synctex_node_t node);
660
661static _synctex_class_t synctex_class_boundary = {
662        NULL,                       /*  No scanner yet */
663        synctex_node_type_boundary,     /*  Node type */
664        &_synctex_new_boundary, /*  creator */
665        &_synctex_free_leaf,        /*  destructor */
666        &_synctex_log_small_node,   /*  log */
667        &_synctex_display_boundary,     /*  display */
668        &_synctex_implementation_0, /*  parent */
669        NULL,                       /*  No child */
670        &_synctex_implementation_1, /*  sibling */
671        &_synctex_implementation_2, /*  friend */
672        NULL,                       /*  No next hbox */
673        (_synctex_info_getter_t)&_synctex_implementation_3
674};
675
676#   define SYNCTEX_NAME_IDX (SYNCTEX_TAG_IDX+1)
677#   define SYNCTEX_NAME(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_NAME_IDX].PTR
678
679/*  Input nodes only know about their sibling, which is another input node.
680 *  The synctex information is the SYNCTEX_TAG and SYNCTEX_NAME*/
681typedef struct {
682    SYNCTEX_DECLARE_CHARINDEX
683        synctex_class_t class;
684        synctex_info_t implementation[1+SYNCTEX_NAME_IDX+1]; /*  sibling,
685                                  *  SYNCTEX_TAG,SYNCTEX_NAME */
686} synctex_input_t;
687
688#   define SYNCTEX_INPUT_MARK "Input:"
689static synctex_node_t _synctex_new_input(synctex_scanner_t scanner) {
690        if (scanner) {
691                synctex_node_t node = _synctex_malloc(sizeof(synctex_input_t));
692                if (node) {
693            SYNCTEX_IMPLEMENT_CHARINDEX(node,strlen(SYNCTEX_INPUT_MARK));
694                        node->class = scanner->class+synctex_node_type_input;
695                }
696                return node;
697        }
698        return NULL;
699}
700
701static void _synctex_free_input(synctex_node_t node){
702        if (node) {
703                SYNCTEX_FREE(SYNCTEX_SIBLING(node));
704                free(SYNCTEX_NAME(node));
705                free(node);
706        }
707}
708
709static void _synctex_display_input(synctex_node_t node);
710static void _synctex_log_input(synctex_node_t node);
711
712static _synctex_class_t synctex_class_input = {
713        NULL,                       /*  No scanner yet */
714        synctex_node_type_input,    /*  Node type */
715        &_synctex_new_input,        /*  creator */
716        &_synctex_free_input,       /*  destructor */
717        &_synctex_log_input,        /*  log */
718        &_synctex_display_input,    /*  display */
719        NULL,                       /*  No parent */
720        NULL,                       /*  No child */
721        &_synctex_implementation_0, /*  sibling */
722        NULL,                       /*  No friend */
723        NULL,                       /*  No next hbox */
724        (_synctex_info_getter_t)&_synctex_implementation_1
725};
726
727#       ifdef SYNCTEX_NOTHING
728#       pragma mark -
729#       pragma mark Navigation
730#   endif
731synctex_node_t synctex_node_parent(synctex_node_t node)
732{
733        return SYNCTEX_PARENT(node);
734}
735synctex_node_t synctex_node_sheet(synctex_node_t node)
736{
737        while(node && node->class->type != synctex_node_type_sheet) {
738                node = SYNCTEX_PARENT(node);
739        }
740        /*  exit the while loop either when node is NULL or node is a sheet */
741        return node;
742}
743synctex_node_t synctex_node_child(synctex_node_t node)
744{
745        return SYNCTEX_CHILD(node);
746}
747synctex_node_t synctex_node_sibling(synctex_node_t node)
748{
749        return SYNCTEX_SIBLING(node);
750}
751synctex_node_t synctex_node_next(synctex_node_t node) {
752        if (SYNCTEX_CHILD(node)) {
753                return SYNCTEX_CHILD(node);
754        }
755sibling:
756        if (SYNCTEX_SIBLING(node)) {
757                return SYNCTEX_SIBLING(node);
758        }
759        if ((node = SYNCTEX_PARENT(node))) {
760                if (node->class->type == synctex_node_type_sheet) {/*  EXC_BAD_ACCESS? */
761                        return NULL;
762                }
763                goto sibling;
764        }
765        return NULL;
766}
767#       ifdef SYNCTEX_NOTHING
768#       pragma mark -
769#       pragma mark CLASS
770#   endif
771
772/*  Public node accessor: the type  */
773synctex_node_type_t synctex_node_type(synctex_node_t node) {
774        if (node) {
775                return (((node)->class))->type;
776        }
777        return synctex_node_type_error;
778}
779
780/*  Public node accessor: the human readable type  */
781const char * synctex_node_isa(synctex_node_t node) {
782static const char * isa[synctex_node_number_of_types] =
783                {"Not a node","input","sheet","vbox","void vbox","hbox","void hbox","kern","glue","math","boundary"};
784        return isa[synctex_node_type(node)];
785}
786
787#       ifdef SYNCTEX_NOTHING
788#       pragma mark -
789#       pragma mark SYNCTEX_LOG
790#   endif
791
792#   define SYNCTEX_LOG(NODE) SYNCTEX_MSG_SEND(NODE,log)
793
794/*  Public node logger  */
795void synctex_node_log(synctex_node_t node) {
796        SYNCTEX_LOG(node);
797}
798
799static void _synctex_log_input(synctex_node_t node) {
800        if (node) {
801        printf("%s:%i,%s",synctex_node_isa(node),SYNCTEX_TAG(node),SYNCTEX_NAME(node));
802        printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
803    }
804}
805
806static void _synctex_log_sheet(synctex_node_t node) {
807        if (node) {
808                printf("%s:%i",synctex_node_isa(node),SYNCTEX_PAGE(node));
809        SYNCTEX_PRINT_CHARINDEX;
810                printf("SELF:%p",(void *)node);
811                printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
812                printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
813                printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
814                printf(" SYNCTEX_FRIEND:%p",(void *)SYNCTEX_FRIEND(node));
815        printf(" SYNCTEX_NEXT_hbox:%p\n",(void *)SYNCTEX_NEXT_hbox(node));
816        }
817}
818
819static void _synctex_log_small_node(synctex_node_t node) {
820        if (node) {
821        printf("%s:%i,%i:%i,%i",
822            synctex_node_isa(node),
823            SYNCTEX_TAG(node),
824            SYNCTEX_LINE(node),
825            SYNCTEX_HORIZ(node),
826            SYNCTEX_VERT(node));
827            SYNCTEX_PRINT_CHARINDEX;
828        printf("SELF:%p",(void *)node);
829        printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
830        printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
831        printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
832        printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node));
833    }
834}
835
836static void _synctex_log_medium_node(synctex_node_t node) {
837        if (node) {
838        printf("%s:%i,%i:%i,%i:%i",
839            synctex_node_isa(node),
840            SYNCTEX_TAG(node),
841            SYNCTEX_LINE(node),
842            SYNCTEX_HORIZ(node),
843            SYNCTEX_VERT(node),
844            SYNCTEX_WIDTH(node));
845            SYNCTEX_PRINT_CHARINDEX;
846        printf("SELF:%p",(void *)node);
847        printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
848        printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
849        printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
850        printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node));
851    }
852}
853
854static void _synctex_log_void_box(synctex_node_t node) {
855        if (node) {
856        printf("%s",synctex_node_isa(node));
857        printf(":%i",SYNCTEX_TAG(node));
858        printf(",%i",SYNCTEX_LINE(node));
859        printf(",%i",0);
860        printf(":%i",SYNCTEX_HORIZ(node));
861        printf(",%i",SYNCTEX_VERT(node));
862        printf(":%i",SYNCTEX_WIDTH(node));
863        printf(",%i",SYNCTEX_HEIGHT(node));
864        printf(",%i",SYNCTEX_DEPTH(node));
865        SYNCTEX_PRINT_CHARINDEX;
866        printf("SELF:%p",(void *)node);
867        printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
868        printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
869        printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
870        printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node));
871    }
872}
873
874static void _synctex_log_vbox(synctex_node_t node) {
875        if (node) {
876        printf("%s",synctex_node_isa(node));
877        printf(":%i",SYNCTEX_TAG(node));
878        printf(",%i",SYNCTEX_LINE(node));
879        printf(",%i",0);
880        printf(":%i",SYNCTEX_HORIZ(node));
881        printf(",%i",SYNCTEX_VERT(node));
882        printf(":%i",SYNCTEX_WIDTH(node));
883        printf(",%i",SYNCTEX_HEIGHT(node));
884        printf(",%i",SYNCTEX_DEPTH(node));
885        SYNCTEX_PRINT_CHARINDEX;
886        printf("SELF:%p",(void *)node);
887        printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
888        printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
889        printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
890        printf(" SYNCTEX_FRIEND:%p",(void *)SYNCTEX_FRIEND(node));
891        printf(" SYNCTEX_NEXT_hbox:%p\n",(void *)SYNCTEX_NEXT_hbox(node));
892    }
893}
894
895static void _synctex_log_hbox(synctex_node_t node) {
896        if (node) {
897        printf("%s",synctex_node_isa(node));
898        printf(":%i",SYNCTEX_TAG(node));
899        printf(",%i~%i*%i",SYNCTEX_LINE(node),SYNCTEX_MEAN_LINE(node),SYNCTEX_NODE_WEIGHT(node));
900        printf(",%i",0);
901        printf(":%i",SYNCTEX_HORIZ(node));
902        printf(",%i",SYNCTEX_VERT(node));
903        printf(":%i",SYNCTEX_WIDTH(node));
904        printf(",%i",SYNCTEX_HEIGHT(node));
905        printf(",%i",SYNCTEX_DEPTH(node));
906        printf("/%i",SYNCTEX_HORIZ_V(node));
907        printf(",%i",SYNCTEX_VERT_V(node));
908        printf(":%i",SYNCTEX_WIDTH_V(node));
909        printf(",%i",SYNCTEX_HEIGHT_V(node));
910        printf(",%i",SYNCTEX_DEPTH_V(node));
911        SYNCTEX_PRINT_CHARINDEX;
912        printf("SELF:%p",(void *)node);
913        printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
914        printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
915        printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
916        printf(" SYNCTEX_FRIEND:%p",(void *)SYNCTEX_FRIEND(node));
917        printf(" SYNCTEX_NEXT_hbox:%p\n",(void *)SYNCTEX_NEXT_hbox(node));
918    }
919}
920
921#   define SYNCTEX_DISPLAY(NODE) SYNCTEX_MSG_SEND(NODE,display)
922
923void synctex_node_display(synctex_node_t node) {
924        SYNCTEX_DISPLAY(node);
925}
926
927static void _synctex_display_input(synctex_node_t node) {
928    if (node) {
929        printf("....Input:%i:%s",
930            SYNCTEX_TAG(node),
931            SYNCTEX_NAME(node));
932            SYNCTEX_PRINT_CHARINDEX;
933        SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
934    }
935}
936
937static void _synctex_display_sheet(synctex_node_t node) {
938        if (node) {
939                printf("....{%i",SYNCTEX_PAGE(node));
940        SYNCTEX_PRINT_CHARINDEX;
941                SYNCTEX_DISPLAY(SYNCTEX_CHILD(node));
942                printf("....}\n");
943                SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
944        }
945}
946
947static void _synctex_display_vbox(synctex_node_t node) {
948    if (node) {
949        printf("....[%i,%i:%i,%i:%i,%i,%i",
950            SYNCTEX_TAG(node),
951            SYNCTEX_LINE(node),
952            SYNCTEX_HORIZ(node),
953            SYNCTEX_VERT(node),
954            SYNCTEX_WIDTH(node),
955            SYNCTEX_HEIGHT(node),
956            SYNCTEX_DEPTH(node));
957            SYNCTEX_PRINT_CHARINDEX;
958        SYNCTEX_DISPLAY(SYNCTEX_CHILD(node));
959        printf("....]\n");
960        SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
961    }
962}
963
964static void _synctex_display_hbox(synctex_node_t node) {
965    if (node) {
966        printf("....(%i,%i~%i*%i:%i,%i:%i,%i,%i",
967            SYNCTEX_TAG(node),
968            SYNCTEX_LINE(node),
969            SYNCTEX_MEAN_LINE(node),
970            SYNCTEX_NODE_WEIGHT(node),
971            SYNCTEX_HORIZ(node),
972            SYNCTEX_VERT(node),
973            SYNCTEX_WIDTH(node),
974            SYNCTEX_HEIGHT(node),
975            SYNCTEX_DEPTH(node));
976            SYNCTEX_PRINT_CHARINDEX;
977        SYNCTEX_DISPLAY(SYNCTEX_CHILD(node));
978        printf("....)\n");
979        SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
980    }
981}
982
983static void _synctex_display_void_vbox(synctex_node_t node) {
984    if (node) {
985        printf("....v%i,%i;%i,%i:%i,%i,%i",
986            SYNCTEX_TAG(node),
987            SYNCTEX_LINE(node),
988            SYNCTEX_HORIZ(node),
989            SYNCTEX_VERT(node),
990            SYNCTEX_WIDTH(node),
991            SYNCTEX_HEIGHT(node),
992            SYNCTEX_DEPTH(node));
993            SYNCTEX_PRINT_CHARINDEX;
994        SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
995    }
996}
997
998static void _synctex_display_void_hbox(synctex_node_t node) {
999    if (node) {
1000        printf("....h%i,%i:%i,%i:%i,%i,%i",
1001            SYNCTEX_TAG(node),
1002            SYNCTEX_LINE(node),
1003            SYNCTEX_HORIZ(node),
1004            SYNCTEX_VERT(node),
1005            SYNCTEX_WIDTH(node),
1006            SYNCTEX_HEIGHT(node),
1007            SYNCTEX_DEPTH(node));
1008            SYNCTEX_PRINT_CHARINDEX;
1009        SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
1010    }
1011}
1012
1013static void _synctex_display_glue(synctex_node_t node) {
1014    if (node) {
1015        printf("....glue:%i,%i:%i,%i",
1016            SYNCTEX_TAG(node),
1017            SYNCTEX_LINE(node),
1018            SYNCTEX_HORIZ(node),
1019            SYNCTEX_VERT(node));
1020            SYNCTEX_PRINT_CHARINDEX;
1021        SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
1022    }
1023}
1024
1025static void _synctex_display_math(synctex_node_t node) {
1026    if (node) {
1027        printf("....math:%i,%i:%i,%i",
1028            SYNCTEX_TAG(node),
1029            SYNCTEX_LINE(node),
1030            SYNCTEX_HORIZ(node),
1031            SYNCTEX_VERT(node));
1032            SYNCTEX_PRINT_CHARINDEX;
1033        SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
1034    }
1035}
1036
1037static void _synctex_display_kern(synctex_node_t node) {
1038    if (node) {
1039        printf("....kern:%i,%i:%i,%i:%i",
1040            SYNCTEX_TAG(node),
1041            SYNCTEX_LINE(node),
1042            SYNCTEX_HORIZ(node),
1043            SYNCTEX_VERT(node),
1044            SYNCTEX_WIDTH(node));
1045            SYNCTEX_PRINT_CHARINDEX;
1046        SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
1047    }
1048}
1049
1050static void _synctex_display_boundary(synctex_node_t node) {
1051    if (node) {
1052        printf("....boundary:%i,%i:%i,%i",
1053            SYNCTEX_TAG(node),
1054            SYNCTEX_LINE(node),
1055            SYNCTEX_HORIZ(node),
1056            SYNCTEX_VERT(node));
1057            SYNCTEX_PRINT_CHARINDEX;
1058        SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
1059    }
1060}
1061
1062#       ifdef SYNCTEX_NOTHING
1063#       pragma mark -
1064#       pragma mark SCANNER
1065#   endif
1066
1067/*  Here are gathered all the possible status that the next scanning functions will return.
1068 *  All these functions return a status, and pass their result through pointers.
1069 *  Negative values correspond to errors.
1070 *  The management of the buffer is causing some significant overhead.
1071 *  Every function that may access the buffer returns a status related to the buffer and file state.
1072 *  status >= SYNCTEX_STATUS_OK means the function worked as expected
1073 *  status < SYNCTEX_STATUS_OK means the function did not work as expected
1074 *  status == SYNCTEX_STATUS_NOT_OK means the function did not work as expected but there is still some material to parse.
1075 *  status == SYNCTEX_STATUS_EOF means the function did not work as expected and there is no more material.
1076 *  status<SYNCTEX_STATUS_EOF means an error
1077 */
1078
1079/*  When the end of the synctex file has been reached: */
1080#   define SYNCTEX_STATUS_EOF 0
1081/*  When the function could not return the value it was asked for: */
1082#   define SYNCTEX_STATUS_NOT_OK (SYNCTEX_STATUS_EOF+1)
1083/*  When the function returns the value it was asked for: */
1084#   define SYNCTEX_STATUS_OK (SYNCTEX_STATUS_NOT_OK+1)
1085/*  Generic error: */
1086#   define SYNCTEX_STATUS_ERROR -1
1087/*  Parameter error: */
1088#   define SYNCTEX_STATUS_BAD_ARGUMENT -2
1089
1090#   define SYNCTEX_FILE (scanner->file)
1091
1092/*  Actually, the minimum buffer size is driven by integer and float parsing.
1093 *  ±0.123456789e123
1094 */
1095#   define SYNCTEX_BUFFER_MIN_SIZE 16
1096#   define SYNCTEX_BUFFER_SIZE 32768
1097
1098#       ifdef SYNCTEX_NOTHING
1099#       pragma mark -
1100#       pragma mark Prototypes
1101#   endif
1102synctex_status_t _synctex_buffer_get_available_size(synctex_scanner_t scanner, size_t * size_ptr);
1103synctex_status_t _synctex_next_line(synctex_scanner_t scanner);
1104synctex_status_t _synctex_match_string(synctex_scanner_t scanner, const char * the_string);
1105synctex_status_t _synctex_decode_int(synctex_scanner_t scanner, int* value_ref);
1106synctex_status_t _synctex_decode_string(synctex_scanner_t scanner, char ** value_ref);
1107synctex_status_t _synctex_scan_input(synctex_scanner_t scanner);
1108synctex_status_t _synctex_scan_preamble(synctex_scanner_t scanner);
1109synctex_status_t _synctex_scan_float_and_dimension(synctex_scanner_t scanner, float * value_ref);
1110synctex_status_t _synctex_scan_post_scriptum(synctex_scanner_t scanner);
1111synctex_status_t _synctex_scan_postamble(synctex_scanner_t scanner);
1112synctex_status_t _synctex_setup_visible_box(synctex_node_t box);
1113synctex_status_t _synctex_hbox_setup_visible(synctex_node_t node,int h, int v);
1114synctex_status_t _synctex_scan_sheet(synctex_scanner_t scanner, synctex_node_t parent);
1115synctex_status_t _synctex_scan_nested_sheet(synctex_scanner_t scanner);
1116synctex_status_t _synctex_scan_content(synctex_scanner_t scanner);
1117int synctex_scanner_pre_x_offset(synctex_scanner_t scanner);
1118int synctex_scanner_pre_y_offset(synctex_scanner_t scanner);
1119const char * synctex_scanner_get_output_fmt(synctex_scanner_t scanner);
1120int _synctex_node_is_box(synctex_node_t node);
1121
1122/*  Try to ensure that the buffer contains at least size bytes.
1123 *  Passing a huge size argument means the whole buffer length.
1124 *  Passing a null size argument means return the available buffer length, without reading the file.
1125 *  In that case, the return status is always SYNCTEX_STATUS_OK unless the given scanner is NULL,
1126 *  in which case, SYNCTEX_STATUS_BAD_ARGUMENT is returned.
1127 *  The value returned in size_ptr is the number of bytes now available in the buffer.
1128 *  This is a nonnegative integer, it may take the value 0.
1129 *  It is the responsibility of the caller to test whether this size is conforming to its needs.
1130 *  Negative values may return in case of error, actually
1131 *  when there was an error reading the synctex file. */
1132synctex_status_t _synctex_buffer_get_available_size(synctex_scanner_t scanner, size_t * size_ptr) {
1133        size_t available = 0;
1134        if (NULL == scanner || NULL == size_ptr) {
1135                return SYNCTEX_STATUS_BAD_ARGUMENT;
1136        }
1137#   define size (* size_ptr)
1138        if (size>SYNCTEX_BUFFER_SIZE){
1139                size = SYNCTEX_BUFFER_SIZE;
1140        }
1141        available = SYNCTEX_END - SYNCTEX_CUR; /*  available is the number of unparsed chars in the buffer */
1142        if (size<=available) {
1143                /*  There are already sufficiently many characters in the buffer */
1144                size = available;
1145                return SYNCTEX_STATUS_OK;
1146        }
1147        if (SYNCTEX_FILE) {
1148                /*  Copy the remaining part of the buffer to the beginning,
1149                 *  then read the next part of the file */
1150                int already_read = 0;
1151#   if defined(SYNCTEX_USE_CHARINDEX)
1152        scanner->charindex_offset += SYNCTEX_CUR - SYNCTEX_START;
1153#   endif
1154                if (available) {
1155                        memmove(SYNCTEX_START, SYNCTEX_CUR, available);
1156                }
1157                SYNCTEX_CUR = SYNCTEX_START + available; /*  the next character after the move, will change. */
1158                /*  Fill the buffer up to its end */
1159                already_read = gzread(SYNCTEX_FILE,(void *)SYNCTEX_CUR,(int)(SYNCTEX_BUFFER_SIZE - available));
1160                if (already_read>0) {
1161                        /*  We assume that 0<already_read<=SYNCTEX_BUFFER_SIZE - available, such that
1162                         *  SYNCTEX_CUR + already_read = SYNCTEX_START + available  + already_read <= SYNCTEX_START + SYNCTEX_BUFFER_SIZE */
1163                        SYNCTEX_END = SYNCTEX_CUR + already_read;
1164                        /*  If the end of the file was reached, all the required SYNCTEX_BUFFER_SIZE - available
1165                         *  may not be filled with values from the file.
1166                         *  In that case, the buffer should stop properly after already_read characters. */
1167                        * SYNCTEX_END = '\0';
1168                        SYNCTEX_CUR = SYNCTEX_START;
1169                        size = SYNCTEX_END - SYNCTEX_CUR; /* == old available + already_read*/
1170                        return SYNCTEX_STATUS_OK; /*  May be available is less than size, the caller will have to test. */
1171                } else if (0>already_read) {
1172                        /*  There is a possible error in reading the file */
1173                        int errnum = 0;
1174                        const char * error_string = gzerror(SYNCTEX_FILE, &errnum);
1175                        if (Z_ERRNO == errnum) {
1176                                /*  There is an error in zlib caused by the file system */
1177                                _synctex_error("gzread error from the file system (%i)",errno);
1178                return SYNCTEX_STATUS_ERROR;
1179                        } else if (errnum) {
1180                                _synctex_error("gzread error (%i:%i,%s)",already_read,errnum,error_string);
1181                return SYNCTEX_STATUS_ERROR;
1182                        }
1183                }
1184        /*  Nothing was read, we are at the end of the file. */
1185        gzclose(SYNCTEX_FILE);
1186        SYNCTEX_FILE = NULL;
1187        SYNCTEX_END = SYNCTEX_CUR;
1188        SYNCTEX_CUR = SYNCTEX_START;
1189        * SYNCTEX_END = '\0';/*  Terminate the string properly.*/
1190        size = SYNCTEX_END - SYNCTEX_CUR;
1191        return SYNCTEX_STATUS_EOF; /*  there might be a bit of text left */
1192    }
1193        /*  We cannot enlarge the buffer because the end of the file was reached. */
1194        size = available;
1195        return SYNCTEX_STATUS_EOF;
1196#   undef size
1197}
1198
1199/*  Used when parsing the synctex file.
1200 *  Advance to the next character starting a line.
1201 *  Actually, only '\n' is recognized as end of line marker.
1202 *  On normal completion, the returned value is the number of unparsed characters available in the buffer.
1203 *  In general, it is a positive value, 0 meaning that the end of file was reached.
1204 *  -1 is returned in case of error, actually because there was an error while feeding the buffer.
1205 *  When the function returns with no error, SYNCTEX_CUR points to the first character of the next line, if any.
1206 *  J. Laurens: Sat May 10 07:52:31 UTC 2008
1207 */
1208synctex_status_t _synctex_next_line(synctex_scanner_t scanner) {
1209        synctex_status_t status = SYNCTEX_STATUS_OK;
1210        size_t available = 0;
1211        if (NULL == scanner) {
1212                return SYNCTEX_STATUS_BAD_ARGUMENT;
1213        }
1214infinite_loop:
1215        while(SYNCTEX_CUR<SYNCTEX_END) {
1216                if (*SYNCTEX_CUR == '\n') {
1217                        ++SYNCTEX_CUR;
1218                        available = 1;
1219                        return _synctex_buffer_get_available_size(scanner, &available);
1220                }
1221                ++SYNCTEX_CUR;
1222        }
1223        /*  Here, we have SYNCTEX_CUR == SYNCTEX_END, such that the next call to _synctex_buffer_get_available_size
1224         *  will read another bunch of synctex file. Little by little, we advance to the end of the file. */
1225        available = 1;
1226        status = _synctex_buffer_get_available_size(scanner, &available);
1227        if (status<=0) {
1228                return status;
1229        }
1230        goto infinite_loop;
1231}
1232
1233/*  Scan the given string.
1234 *  Both scanner and the_string must not be NULL, and the_string must not be 0 length.
1235 *  SYNCTEX_STATUS_OK is returned if the string is found,
1236 *  SYNCTEX_STATUS_EOF is returned when the EOF is reached,
1237 *  SYNCTEX_STATUS_NOT_OK is returned is the string is not found,
1238 *  an error status is returned otherwise.
1239 *  This is a critical method because buffering renders things more difficult.
1240 *  The given string might be as long as the maximum size_t value.
1241 *  As side effect, the buffer state may have changed if the given argument string can't fit into the buffer.
1242 */
1243synctex_status_t _synctex_match_string(synctex_scanner_t scanner, const char * the_string) {
1244        size_t tested_len = 0; /*  the number of characters at the beginning of the_string that match */
1245        size_t remaining_len = 0; /*  the number of remaining characters of the_string that should match */
1246        size_t available = 0;
1247        synctex_status_t status = 0;
1248        if (NULL == scanner || NULL == the_string) {
1249                return SYNCTEX_STATUS_BAD_ARGUMENT;
1250        }
1251        remaining_len = strlen(the_string); /*  All the_string should match */
1252        if (0 == remaining_len) {
1253                return SYNCTEX_STATUS_BAD_ARGUMENT;
1254        }
1255        /*  How many characters available in the buffer? */
1256        available = remaining_len;
1257        status = _synctex_buffer_get_available_size(scanner,&available);
1258        if (status<SYNCTEX_STATUS_EOF) {
1259                return status;
1260        }
1261        /*  Maybe we have less characters than expected because the buffer is too small. */
1262        if (available>=remaining_len) {
1263                /*  The buffer is sufficiently big to hold the expected number of characters. */
1264                if (strncmp((char *)SYNCTEX_CUR,the_string,remaining_len)) {
1265                        return SYNCTEX_STATUS_NOT_OK;
1266                }
1267return_OK:
1268                /*  Advance SYNCTEX_CUR to the next character after the_string. */
1269                SYNCTEX_CUR += remaining_len;
1270                return SYNCTEX_STATUS_OK;
1271        } else if (strncmp((char *)SYNCTEX_CUR,the_string,available)) {
1272                        /*  No need to go further, this is not the expected string in the buffer. */
1273                        return SYNCTEX_STATUS_NOT_OK;
1274        } else if (SYNCTEX_FILE) {
1275                /*  The buffer was too small to contain remaining_len characters.
1276                 *  We have to cut the string into pieces. */
1277                z_off_t offset = 0L;
1278                /*  the first part of the string is found, advance the_string to the next untested character. */
1279                the_string += available;
1280                /*  update the remaining length and the parsed length. */
1281                remaining_len -= available;
1282                tested_len += available;
1283                SYNCTEX_CUR += available; /*  We validate the tested characters. */
1284                if (0 == remaining_len) {
1285                        /*  Nothing left to test, we have found the given string, we return the length. */
1286                        return tested_len;
1287                }
1288                /*  We also have to record the current state of the file cursor because
1289                 *  if the_string does not match, all this should be a totally blank operation,
1290                 *  for which the file and buffer states should not be modified at all.
1291                 *  In fact, the states of the buffer before and after this function are in general different
1292                 *  but they are totally equivalent as long as the values of the buffer before SYNCTEX_CUR
1293                 *  can be safely discarded.  */
1294                offset = gztell(SYNCTEX_FILE);
1295                /*  offset now corresponds to the first character of the file that was not buffered. */
1296                available = SYNCTEX_CUR - SYNCTEX_START; /*  available can be used as temporary placeholder. */
1297                /*  available now corresponds to the number of chars that where already buffered and
1298                 *  that match the head of the_string. If in fine the_string does not match, all these chars must be recovered
1299                 *  because the buffer contents is completely replaced by _synctex_buffer_get_available_size.
1300                 *  They were buffered from offset-len location in the file. */
1301                offset -= available;
1302more_characters:
1303                /*  There is still some work to be done, so read another bunch of file.
1304                 *  This is the second call to _synctex_buffer_get_available_size,
1305                 *  which means that the actual contents of the buffer will be discarded.
1306                 *  We will definitely have to recover the previous state in case we do not find the expected string. */
1307                available = remaining_len;
1308                status = _synctex_buffer_get_available_size(scanner,&available);
1309                if (status<SYNCTEX_STATUS_EOF) {
1310                        return status; /*  This is an error, no need to go further. */
1311                }
1312                if (available==0) {
1313                        /*  Missing characters: recover the initial state of the file and return. */
1314return_NOT_OK:
1315                        if (offset != gzseek(SYNCTEX_FILE,offset,SEEK_SET)) {
1316                                /*  This is a critical error, we could not recover the previous state. */
1317                                _synctex_error("can't seek file");
1318                                return SYNCTEX_STATUS_ERROR;
1319                        }
1320                        /*  Next time we are asked to fill the buffer,
1321                         *  we will read a complete bunch of text from the file. */
1322                        SYNCTEX_CUR = SYNCTEX_END;
1323                        return SYNCTEX_STATUS_NOT_OK;
1324                }
1325                if (available<remaining_len) {
1326                        /*  We'll have to loop one more time. */
1327                        if (strncmp((char *)SYNCTEX_CUR,the_string,available)) {
1328                                /*  This is not the expected string, recover the previous state and return. */
1329                                goto return_NOT_OK;
1330                        }
1331                        /*  Advance the_string to the first untested character. */
1332                        the_string += available;
1333                        /*  update the remaining length and the parsed length. */
1334                        remaining_len -= available;
1335                        tested_len += available;
1336                        SYNCTEX_CUR += available; /*  We validate the tested characters. */
1337                        if (0 == remaining_len) {
1338                                /*  Nothing left to test, we have found the given string. */
1339                                return SYNCTEX_STATUS_OK;
1340                        }
1341                        goto more_characters;
1342                }
1343                /*  This is the last step. */
1344                if (strncmp((char *)SYNCTEX_CUR,the_string,remaining_len)) {
1345                        /*  This is not the expected string, recover the previous state and return. */
1346                        goto return_NOT_OK;
1347                }
1348                goto return_OK;
1349        } else {
1350                /*  The buffer can't contain the given string argument, and the EOF was reached */
1351                return SYNCTEX_STATUS_EOF;
1352        }
1353}
1354
1355/*  Used when parsing the synctex file.
1356 *  Decode an integer.
1357 *  First, field separators, namely ':' and ',' characters are skipped
1358 *  The returned value is negative if there is an unrecoverable error.
1359 *  It is SYNCTEX_STATUS_NOT_OK if an integer could not be parsed, for example
1360 *  if the characters at the current cursor position are not digits or
1361 *  if the end of the file has been reached.
1362 *  It is SYNCTEX_STATUS_OK if an int has been successfully parsed.
1363 *  The given scanner argument must not be NULL, on the contrary, value_ref may be NULL.
1364 */
1365synctex_status_t _synctex_decode_int(synctex_scanner_t scanner, int* value_ref) {
1366        char * ptr = NULL;
1367        char * end = NULL;
1368        int result = 0;
1369        size_t available = 0;
1370        synctex_status_t status = 0;
1371        if (NULL == scanner) {
1372                 return SYNCTEX_STATUS_BAD_ARGUMENT;
1373        }
1374        available = SYNCTEX_BUFFER_MIN_SIZE;
1375        status = _synctex_buffer_get_available_size(scanner, &available);
1376        if (status<SYNCTEX_STATUS_EOF) {
1377                return status;/*  Forward error. */
1378        }
1379        if (available==0) {
1380                return SYNCTEX_STATUS_EOF;/*  it is the end of file. */
1381        }
1382        ptr = SYNCTEX_CUR;
1383        if (*ptr==':' || *ptr==',') {
1384                ++ptr;
1385                --available;
1386                if (available==0) {
1387                        return SYNCTEX_STATUS_NOT_OK;/*  It is not possible to scan an int */
1388                }
1389        }
1390        result = (int)strtol(ptr, &end, 10);
1391        if (end>ptr) {
1392                SYNCTEX_CUR = end;
1393                if (value_ref) {
1394                        * value_ref = result;
1395                }
1396                return SYNCTEX_STATUS_OK;/*  Successfully scanned an int */
1397        }       
1398        return SYNCTEX_STATUS_NOT_OK;/*  Could not scan an int */
1399}
1400
1401/*  The purpose of this function is to read a string.
1402 *  A string is an array of characters from the current parser location
1403 *  and before the next '\n' character.
1404 *  If a string was properly decoded, it is returned in value_ref and
1405 *  the cursor points to the new line marker.
1406 *  The returned string was alloced on the heap, the caller is the owner and
1407 *  is responsible to free it in due time.
1408 *  If no string is parsed, * value_ref is undefined.
1409 *  The maximum length of a string that a scanner can decode is platform dependent, namely UINT_MAX.
1410 *  If you just want to blindly parse the file up to the end of the current line,
1411 *  use _synctex_next_line instead.
1412 *  On return, the scanner cursor is unchanged if a string could not be scanned or
1413 *  points to the terminating '\n' character otherwise. As a consequence,
1414 *  _synctex_next_line is necessary after.
1415 *  If either scanner or value_ref is NULL, it is considered as an error and
1416 *  SYNCTEX_STATUS_BAD_ARGUMENT is returned.
1417 */
1418synctex_status_t _synctex_decode_string(synctex_scanner_t scanner, char ** value_ref) {
1419        char * end = NULL;
1420        size_t current_size = 0;
1421        size_t new_size = 0;
1422        size_t len = 0;/*  The number of bytes to copy */
1423        size_t available = 0;
1424        synctex_status_t status = 0;
1425        if (NULL == scanner || NULL == value_ref) {
1426                return SYNCTEX_STATUS_BAD_ARGUMENT;
1427        }
1428        /*  The buffer must at least contain one character: the '\n' end of line marker */
1429        if (SYNCTEX_CUR>=SYNCTEX_END) {
1430                available = 1;
1431                status = _synctex_buffer_get_available_size(scanner,&available);
1432                if (status < 0) {
1433                        return status;
1434                }
1435                if (0 == available) {
1436                        return SYNCTEX_STATUS_EOF;
1437                }
1438        }
1439        /*  Now we are sure that there is at least one available character, either because
1440         *  SYNCTEX_CUR was already < SYNCTEX_END, or because the buffer has been properly filled. */
1441        /*  end will point to the next unparsed '\n' character in the file, when mapped to the buffer. */
1442        end = SYNCTEX_CUR;
1443        * value_ref = NULL;/*  Initialize, it will be realloc'ed */
1444        /*  We scan all the characters up to the next '\n' */
1445next_character:
1446        if (end<SYNCTEX_END) {
1447                if (*end == '\n') {
1448                        /*  OK, we found where to stop */
1449                        len = end - SYNCTEX_CUR;
1450                        if (current_size>UINT_MAX-len-1) {
1451                                /*  But we have reached the limit: we do not have current_size+len+1>UINT_MAX.
1452                                 *  We return the missing amount of memory.
1453                                 *  This will never occur in practice. */
1454                                return UINT_MAX-len-1 - current_size;
1455                        }
1456                        new_size = current_size+len;
1457                        /*  We have current_size+len+1<=UINT_MAX
1458                         *  or equivalently new_size<UINT_MAX,
1459                         *  where we have assumed that len<UINT_MAX */
1460                        if ((* value_ref = realloc(* value_ref,new_size+1)) != NULL) {
1461                                if (memcpy((*value_ref)+current_size,SYNCTEX_CUR,len)) {
1462                                        (* value_ref)[new_size]='\0'; /*  Terminate the string */
1463                                        SYNCTEX_CUR += len;/*  Advance to the terminating '\n' */
1464                                        return SYNCTEX_STATUS_OK;
1465                                }
1466                                free(* value_ref);
1467                                * value_ref = NULL;
1468                                _synctex_error("could not copy memory (1).");
1469                                return SYNCTEX_STATUS_ERROR;
1470                        }
1471                        _synctex_error("could not allocate memory (1).");
1472                        return SYNCTEX_STATUS_ERROR;
1473                } else {
1474                        ++end;
1475                        goto next_character;
1476                }
1477        } else {
1478                /*  end == SYNCTEX_END */
1479                len = SYNCTEX_END - SYNCTEX_CUR;
1480                if (current_size>UINT_MAX-len-1) {
1481                        /*  We have reached the limit. */
1482                        _synctex_error("limit reached (missing %i).",current_size-(UINT_MAX-len-1));
1483                        return SYNCTEX_STATUS_ERROR;
1484                }
1485                new_size = current_size+len;
1486                if ((* value_ref = realloc(* value_ref,new_size+1)) != NULL) {
1487                        if (memcpy((*value_ref)+current_size,SYNCTEX_CUR,len)) {
1488                                (* value_ref)[new_size]='\0'; /*  Terminate the string */
1489                                SYNCTEX_CUR = SYNCTEX_END;/*  Advance the cursor to the end of the bufer */
1490                                return SYNCTEX_STATUS_OK;
1491                        }
1492                        free(* value_ref);
1493                        * value_ref = NULL;
1494                        _synctex_error("could not copy memory (2).");
1495                        return SYNCTEX_STATUS_ERROR;
1496                }
1497                /*  Huge memory problem */
1498                _synctex_error("could not allocate memory (2).");
1499                return SYNCTEX_STATUS_ERROR;
1500        }
1501}
1502
1503/*  Used when parsing the synctex file.
1504 *  Read an Input record.
1505 */
1506synctex_status_t _synctex_scan_input(synctex_scanner_t scanner) {
1507        synctex_status_t status = 0;
1508        size_t available = 0;
1509        synctex_node_t input = NULL;
1510        if (NULL == scanner) {
1511                return SYNCTEX_STATUS_BAD_ARGUMENT;
1512        }
1513        status = _synctex_match_string(scanner,SYNCTEX_INPUT_MARK);
1514        if (status<SYNCTEX_STATUS_OK) {
1515                return status;
1516        }
1517        /*  Create a node */
1518        input = _synctex_new_input(scanner);
1519        if (NULL == input) {
1520                _synctex_error("could not create an input node.");
1521                return SYNCTEX_STATUS_ERROR;
1522        }
1523        /*  Decode the synctag  */
1524        status = _synctex_decode_int(scanner,&(SYNCTEX_TAG(input)));
1525        if (status<SYNCTEX_STATUS_OK) {
1526                _synctex_error("bad format of input node.");
1527                SYNCTEX_FREE(input);
1528                return status;
1529        }
1530        /*  The next character is a field separator, we expect one character in the buffer. */
1531        available = 1;
1532        status = _synctex_buffer_get_available_size(scanner, &available);
1533        if (status<=SYNCTEX_STATUS_ERROR) {
1534                return status;
1535        }
1536        if (0 == available) {
1537                return SYNCTEX_STATUS_EOF;
1538        }
1539        /*  We can now safely advance to the next character, stepping over the field separator. */
1540        ++SYNCTEX_CUR;
1541        --available;
1542        /*  Then we scan the file name */
1543        status = _synctex_decode_string(scanner,&(SYNCTEX_NAME(input)));
1544        if (status<SYNCTEX_STATUS_OK) {
1545                SYNCTEX_FREE(input);
1546                return status;
1547        }
1548        /*  Prepend this input node to the input linked list of the scanner */
1549        SYNCTEX_SET_SIBLING(input,scanner->input);
1550        scanner->input = input;
1551#   if SYNCTEX_VERBOSE
1552        synctex_node_log(input);
1553#   endif
1554        return _synctex_next_line(scanner);/*  read the line termination character, if any */
1555        /*  Now, set up the path */
1556}
1557
1558typedef synctex_status_t (*synctex_decoder_t)(synctex_scanner_t,void *);
1559
1560synctex_status_t _synctex_scan_named(synctex_scanner_t scanner,const char * name,void * value_ref,synctex_decoder_t decoder);
1561
1562/*  Used when parsing the synctex file.
1563 *  Read one of the settings.
1564 *  On normal completion, returns SYNCTEX_STATUS_OK.
1565 *  On error, returns SYNCTEX_STATUS_ERROR.
1566 *  Both arguments must not be NULL.
1567 *  On return, the scanner points to the next character after the decoded object whatever it is.
1568 *  It is the responsibility of the caller to prepare the scanner for the next line.
1569 */
1570synctex_status_t _synctex_scan_named(synctex_scanner_t scanner,const char * name,void * value_ref,synctex_decoder_t decoder) {
1571        synctex_status_t status = 0;
1572        if (NULL == scanner || NULL == name || NULL == value_ref || NULL == decoder) {
1573                return SYNCTEX_STATUS_BAD_ARGUMENT;
1574        }
1575not_found:
1576        status = _synctex_match_string(scanner,name);
1577        if (status<SYNCTEX_STATUS_NOT_OK) {
1578                return status;
1579        } else if (status == SYNCTEX_STATUS_NOT_OK) {
1580                status = _synctex_next_line(scanner);
1581                if (status<SYNCTEX_STATUS_OK) {
1582                        return status;
1583                }
1584                goto not_found;
1585        }
1586        /*  A line is found, scan the value */
1587        return (*decoder)(scanner,value_ref);
1588}
1589
1590/*  Used when parsing the synctex file.
1591 *  Read the preamble.
1592 */
1593synctex_status_t _synctex_scan_preamble(synctex_scanner_t scanner) {
1594        synctex_status_t status = 0;
1595        if (NULL == scanner) {
1596                return SYNCTEX_STATUS_BAD_ARGUMENT;
1597        }
1598        status = _synctex_scan_named(scanner,"SyncTeX Version:",&(scanner->version),(synctex_decoder_t)&_synctex_decode_int);
1599        if (status<SYNCTEX_STATUS_OK) {
1600                return status;
1601        }
1602        status = _synctex_next_line(scanner);
1603        if (status<SYNCTEX_STATUS_OK) {
1604                return status;
1605        }
1606        /*  Read all the input records */
1607        do {
1608                status = _synctex_scan_input(scanner);
1609                if (status<SYNCTEX_STATUS_NOT_OK) {
1610                        return status;
1611                }
1612        } while(status == SYNCTEX_STATUS_OK);
1613        /*  the loop exits when status == SYNCTEX_STATUS_NOT_OK */
1614        /*  Now read all the required settings. */
1615        status = _synctex_scan_named(scanner,"Output:",&(scanner->output_fmt),(synctex_decoder_t)&_synctex_decode_string);
1616        if (status<SYNCTEX_STATUS_NOT_OK) {
1617                return status;
1618        }
1619        status = _synctex_next_line(scanner);
1620        if (status<SYNCTEX_STATUS_OK) {
1621                return status;
1622        }
1623        status = _synctex_scan_named(scanner,"Magnification:",&(scanner->pre_magnification),(synctex_decoder_t)&_synctex_decode_int);
1624        if (status<SYNCTEX_STATUS_OK) {
1625                return status;
1626        }
1627        status = _synctex_next_line(scanner);
1628        if (status<SYNCTEX_STATUS_OK) {
1629                return status;
1630        }
1631        status = _synctex_scan_named(scanner,"Unit:",&(scanner->pre_unit),(synctex_decoder_t)&_synctex_decode_int);
1632        if (status<SYNCTEX_STATUS_OK) {
1633                return status;
1634        }
1635        status = _synctex_next_line(scanner);
1636        if (status<SYNCTEX_STATUS_OK) {
1637                return status;
1638        }
1639        status = _synctex_scan_named(scanner,"X Offset:",&(scanner->pre_x_offset),(synctex_decoder_t)&_synctex_decode_int);
1640        if (status<SYNCTEX_STATUS_OK) {
1641                return status;
1642        }
1643        status = _synctex_next_line(scanner);
1644        if (status<SYNCTEX_STATUS_OK) {
1645                return status;
1646        }
1647        status = _synctex_scan_named(scanner,"Y Offset:",&(scanner->pre_y_offset),(synctex_decoder_t)&_synctex_decode_int);
1648        if (status<SYNCTEX_STATUS_OK) {
1649                return status;
1650        }
1651        return _synctex_next_line(scanner);
1652}
1653
1654/*  parse a float with a dimension */
1655synctex_status_t _synctex_scan_float_and_dimension(synctex_scanner_t scanner, float * value_ref) {
1656        synctex_status_t status = 0;
1657        char * endptr = NULL;
1658        float f = 0;
1659#ifdef HAVE_SETLOCALE
1660        char * loc = setlocale(LC_NUMERIC, NULL);
1661#endif
1662        size_t available = 0;
1663        if (NULL == scanner || NULL == value_ref) {
1664                return SYNCTEX_STATUS_BAD_ARGUMENT;
1665        }
1666        available = SYNCTEX_BUFFER_MIN_SIZE;
1667        status = _synctex_buffer_get_available_size(scanner, &available);
1668        if (status<SYNCTEX_STATUS_EOF) {
1669                _synctex_error("problem with float.");
1670                return status;
1671        }
1672#ifdef HAVE_SETLOCALE
1673        setlocale(LC_NUMERIC, "C");
1674#endif
1675        f = strtod(SYNCTEX_CUR,&endptr);
1676#ifdef HAVE_SETLOCALE
1677        setlocale(LC_NUMERIC, loc);
1678#endif
1679        if (endptr == SYNCTEX_CUR) {
1680                _synctex_error("a float was expected.");
1681                return SYNCTEX_STATUS_ERROR;
1682        }
1683        SYNCTEX_CUR = endptr;
1684        if ((status = _synctex_match_string(scanner,"in")) >= SYNCTEX_STATUS_OK) {
1685                f *= 72.27f*65536;
1686        } else if (status<SYNCTEX_STATUS_EOF) {
1687report_unit_error:
1688                _synctex_error("problem with unit.");
1689                return status;
1690        } else if ((status = _synctex_match_string(scanner,"cm")) >= SYNCTEX_STATUS_OK) {
1691                f *= 72.27f*65536/2.54f;
1692        } else if (status<0) {
1693                goto report_unit_error;
1694        } else if ((status = _synctex_match_string(scanner,"mm")) >= SYNCTEX_STATUS_OK) {
1695                f *= 72.27f*65536/25.4f;
1696        } else if (status<0) {
1697                goto report_unit_error;
1698        } else if ((status = _synctex_match_string(scanner,"pt")) >= SYNCTEX_STATUS_OK) {
1699                f *= 65536.0f;
1700        } else if (status<0) {
1701                goto report_unit_error;
1702        } else if ((status = _synctex_match_string(scanner,"bp")) >= SYNCTEX_STATUS_OK) {
1703                f *= 72.27f/72*65536.0f;
1704        }  else if (status<0) {
1705                goto report_unit_error;
1706        } else if ((status = _synctex_match_string(scanner,"pc")) >= SYNCTEX_STATUS_OK) {
1707                f *= 12.0*65536.0f;
1708        }  else if (status<0) {
1709                goto report_unit_error;
1710        } else if ((status = _synctex_match_string(scanner,"sp")) >= SYNCTEX_STATUS_OK) {
1711                f *= 1.0f;
1712        }  else if (status<0) {
1713                goto report_unit_error;
1714        } else if ((status = _synctex_match_string(scanner,"dd")) >= SYNCTEX_STATUS_OK) {
1715                f *= 1238.0f/1157*65536.0f;
1716        }  else if (status<0) {
1717                goto report_unit_error;
1718        } else if ((status = _synctex_match_string(scanner,"cc")) >= SYNCTEX_STATUS_OK) {
1719                f *= 14856.0f/1157*65536;
1720        } else if (status<0) {
1721                goto report_unit_error;
1722        } else if ((status = _synctex_match_string(scanner,"nd")) >= SYNCTEX_STATUS_OK) {
1723                f *= 685.0f/642*65536;
1724        }  else if (status<0) {
1725                goto report_unit_error;
1726        } else if ((status = _synctex_match_string(scanner,"nc")) >= SYNCTEX_STATUS_OK) {
1727                f *= 1370.0f/107*65536;
1728        } else if (status<0) {
1729                goto report_unit_error;
1730        }
1731        *value_ref = f;
1732        return SYNCTEX_STATUS_OK;
1733}
1734
1735/*  parse the post scriptum
1736 *  SYNCTEX_STATUS_OK is returned on completion
1737 *  a negative error is returned otherwise */
1738synctex_status_t _synctex_scan_post_scriptum(synctex_scanner_t scanner) {
1739        synctex_status_t status = 0;
1740        char * endptr = NULL;
1741#ifdef HAVE_SETLOCALE
1742        char * loc = setlocale(LC_NUMERIC, NULL);
1743#endif
1744        if (NULL == scanner) {
1745                return SYNCTEX_STATUS_BAD_ARGUMENT;
1746        }
1747        /*  Scan the file until a post scriptum line is found */
1748post_scriptum_not_found:
1749        status = _synctex_match_string(scanner,"Post scriptum:");
1750        if (status<SYNCTEX_STATUS_NOT_OK) {
1751                return status;
1752        }
1753        if (status == SYNCTEX_STATUS_NOT_OK) {
1754                status = _synctex_next_line(scanner);
1755                if (status<SYNCTEX_STATUS_EOF) {
1756                        return status;
1757                } else if (status<SYNCTEX_STATUS_OK) {
1758                        return SYNCTEX_STATUS_OK;/*  The EOF is found, we have properly scanned the file */
1759                }
1760                goto post_scriptum_not_found;
1761        }
1762        /*  We found the name, advance to the next line. */
1763next_line:
1764        status = _synctex_next_line(scanner);
1765        if (status<SYNCTEX_STATUS_EOF) {
1766                return status;
1767        } else if (status<SYNCTEX_STATUS_OK) {
1768                return SYNCTEX_STATUS_OK;/*  The EOF is found, we have properly scanned the file */
1769        }
1770        /*  Scanning the information */
1771        status = _synctex_match_string(scanner,"Magnification:");
1772        if (status == SYNCTEX_STATUS_OK ) {
1773#ifdef HAVE_SETLOCALE
1774                setlocale(LC_NUMERIC, "C");
1775#endif
1776                scanner->unit = strtod(SYNCTEX_CUR,&endptr);
1777#ifdef HAVE_SETLOCALE
1778                setlocale(LC_NUMERIC, loc);
1779#endif
1780                if (endptr == SYNCTEX_CUR) {
1781                        _synctex_error("bad magnification in the post scriptum, a float was expected.");
1782                        return SYNCTEX_STATUS_ERROR;
1783                }
1784                if (scanner->unit<=0) {
1785                        _synctex_error("bad magnification in the post scriptum, a positive float was expected.");
1786                        return SYNCTEX_STATUS_ERROR;
1787                }
1788                SYNCTEX_CUR = endptr;
1789                goto next_line;
1790        }
1791        if (status<SYNCTEX_STATUS_EOF){
1792report_record_problem:
1793                _synctex_error("Problem reading the Post Scriptum records");
1794                return status; /*  echo the error. */
1795        }
1796        status = _synctex_match_string(scanner,"X Offset:");
1797        if (status == SYNCTEX_STATUS_OK) {
1798                status = _synctex_scan_float_and_dimension(scanner, &(scanner->x_offset));
1799                if (status<SYNCTEX_STATUS_OK) {
1800                        _synctex_error("problem with X offset in the Post Scriptum.");
1801                        return status;
1802                }
1803                goto next_line;
1804        } else if (status<SYNCTEX_STATUS_EOF){
1805                goto report_record_problem;
1806        }
1807        status = _synctex_match_string(scanner,"Y Offset:");
1808        if (status==SYNCTEX_STATUS_OK) {
1809                status = _synctex_scan_float_and_dimension(scanner, &(scanner->y_offset));
1810                if (status<SYNCTEX_STATUS_OK) {
1811                        _synctex_error("problem with Y offset in the Post Scriptum.");
1812                        return status;
1813                }
1814                goto next_line;
1815        } else if (status<SYNCTEX_STATUS_EOF){
1816                goto report_record_problem;
1817        }
1818        goto next_line;
1819}
1820
1821/*  SYNCTEX_STATUS_OK is returned if the postamble is read
1822 *  SYNCTEX_STATUS_NOT_OK is returned if the postamble is not at the current location
1823 *  a negative error otherwise
1824 *  The postamble comprises the post scriptum section.
1825 */
1826synctex_status_t _synctex_scan_postamble(synctex_scanner_t scanner) {
1827        synctex_status_t status = 0;
1828        if (NULL == scanner) {
1829                return SYNCTEX_STATUS_BAD_ARGUMENT;
1830        }
1831        status = _synctex_match_string(scanner,"Postamble:");
1832        if (status < SYNCTEX_STATUS_OK) {
1833                return status;
1834        }
1835count_again:
1836        status = _synctex_next_line(scanner);
1837        if (status < SYNCTEX_STATUS_OK) {
1838                return status;
1839        }
1840        status = _synctex_scan_named(scanner,"Count:",&(scanner->count),(synctex_decoder_t)&_synctex_decode_int);
1841        if (status < SYNCTEX_STATUS_EOF) {
1842                return status; /*  forward the error */
1843        } else if (status < SYNCTEX_STATUS_OK) { /*  No Count record found */
1844                status = _synctex_next_line(scanner); /*  Advance one more line */
1845                if (status<SYNCTEX_STATUS_OK) {
1846                        return status;
1847                }
1848                goto count_again;
1849        }
1850        /*  Now we scan the last part of the SyncTeX file: the Post Scriptum section. */
1851        return _synctex_scan_post_scriptum(scanner);
1852}
1853
1854/*  Horizontal boxes also have visible size.
1855 *  Visible size are bigger than real size.
1856 *  For example 0 width boxes may contain text.
1857 *  At creation time, the visible size is set to the values of the real size.
1858 */
1859synctex_status_t _synctex_setup_visible_box(synctex_node_t box) {
1860        if (box) {
1861                switch(box->class->type) {
1862                        case synctex_node_type_hbox:
1863                                if (SYNCTEX_INFO(box) != NULL) {
1864                                        SYNCTEX_HORIZ_V(box)  = SYNCTEX_HORIZ(box);
1865                                        SYNCTEX_VERT_V(box)   = SYNCTEX_VERT(box);
1866                                        SYNCTEX_WIDTH_V(box)  = SYNCTEX_WIDTH(box);
1867                                        SYNCTEX_HEIGHT_V(box) = SYNCTEX_HEIGHT(box);
1868                                        SYNCTEX_DEPTH_V(box)  = SYNCTEX_DEPTH(box);
1869                                        return SYNCTEX_STATUS_OK;
1870                                }
1871                                return SYNCTEX_STATUS_ERROR;
1872                }
1873        }
1874        return SYNCTEX_STATUS_BAD_ARGUMENT;
1875}
1876
1877/*  This method is sent to an horizontal box to setup the visible size
1878 *  Some box have 0 width but do contain text material.
1879 *  With this method, one can enlarge the box to contain the given point (h,v).
1880 */
1881synctex_status_t _synctex_hbox_setup_visible(synctex_node_t node,int h, int v) {
1882#       ifdef __DARWIN_UNIX03
1883#       pragma unused(v)
1884#   endif
1885        int itsBtm, itsTop;
1886        if (NULL == node || node->class->type != synctex_node_type_hbox) {
1887                return SYNCTEX_STATUS_BAD_ARGUMENT;
1888        }
1889        if (SYNCTEX_WIDTH_V(node)<0) {
1890                itsBtm = SYNCTEX_HORIZ_V(node);
1891                itsTop = SYNCTEX_HORIZ_V(node)-SYNCTEX_WIDTH_V(node);
1892                if (h<itsBtm) {
1893                        SYNCTEX_HORIZ_V(node) = h;
1894                        SYNCTEX_WIDTH_V(node) = SYNCTEX_HORIZ_V(node) - itsTop;
1895                } else if (h>itsTop) {
1896                        SYNCTEX_WIDTH_V(node) = SYNCTEX_HORIZ_V(node) - h;
1897                }
1898        } else {
1899                itsBtm = SYNCTEX_HORIZ_V(node);
1900                itsTop = SYNCTEX_HORIZ_V(node)+SYNCTEX_WIDTH_V(node);
1901                if (h<itsBtm) {
1902                        SYNCTEX_HORIZ_V(node) = h;
1903                        SYNCTEX_WIDTH_V(node) = itsTop - SYNCTEX_HORIZ_V(node);
1904                } else if (h>itsTop) {
1905                        SYNCTEX_WIDTH_V(node) = h - SYNCTEX_HORIZ_V(node);
1906                }
1907        }
1908        return SYNCTEX_STATUS_OK;
1909}
1910
1911/*  Here are the control characters that strat each line of the synctex output file.
1912 *  Their values define the meaning of the line.
1913 */
1914#   define SYNCTEX_CHAR_BEGIN_SHEET '{'
1915#   define SYNCTEX_CHAR_END_SHEET   '}'
1916#   define SYNCTEX_CHAR_BEGIN_VBOX  '['
1917#   define SYNCTEX_CHAR_END_VBOX    ']'
1918#   define SYNCTEX_CHAR_BEGIN_HBOX  '('
1919#   define SYNCTEX_CHAR_END_HBOX    ')'
1920#   define SYNCTEX_CHAR_ANCHOR      '!'
1921#   define SYNCTEX_CHAR_VOID_VBOX   'v'
1922#   define SYNCTEX_CHAR_VOID_HBOX   'h'
1923#   define SYNCTEX_CHAR_KERN        'k'
1924#   define SYNCTEX_CHAR_GLUE        'g'
1925#   define SYNCTEX_CHAR_MATH        '$'
1926#   define SYNCTEX_CHAR_BOUNDARY    'x'
1927
1928#   define SYNCTEX_RETURN(STATUS) return STATUS;
1929
1930/*  Used when parsing the synctex file. A '{' character has just been parsed.
1931 *  The purpose is to gobble everything until the closing '}'.
1932 *  Actually only one nesting depth has been observed when using the clip option
1933 *  of \includegraphics option. Here we use arbitrary level of depth.
1934 */
1935synctex_status_t _synctex_scan_nested_sheet(synctex_scanner_t scanner) {
1936    unsigned int depth = 0;
1937deeper:
1938    ++depth;
1939    if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
1940        _synctex_error("Unexpected end of nested sheet (1).");
1941        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1942    }
1943scan_next_line:
1944    if (SYNCTEX_CUR<SYNCTEX_END) {
1945                if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_SHEET) {
1946                        ++SYNCTEX_CUR;
1947                        if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
1948                                _synctex_error("Unexpected end of nested sheet (2).");
1949                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1950                        }
1951            if (--depth>0) {
1952                goto scan_next_line;
1953            } else {
1954                SYNCTEX_RETURN(SYNCTEX_STATUS_OK);
1955            }
1956                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_SHEET) {
1957                        ++SYNCTEX_CUR;
1958                        goto deeper;
1959           
1960                } else if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
1961            _synctex_error("Unexpected end of nested sheet (3).");
1962            SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1963        }
1964    }
1965    _synctex_error("Unexpected end of nested sheet (4).");
1966    SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1967}
1968
1969/*  Used when parsing the synctex file.
1970 *  The sheet argument is a newly created sheet node that will hold the contents.
1971 *  Something is returned in case of error.
1972 */
1973synctex_status_t _synctex_scan_sheet(synctex_scanner_t scanner, synctex_node_t sheet) {
1974        synctex_node_t parent = sheet;
1975        synctex_node_t child = NULL;
1976        synctex_node_t sibling = NULL;
1977        synctex_node_t box = sheet;
1978        int friend_index = 0;
1979        synctex_info_t * info = NULL;
1980        synctex_status_t status = 0;
1981        size_t available = 0;
1982        if ((NULL == scanner) || (NULL == sheet)) {
1983                return SYNCTEX_STATUS_BAD_ARGUMENT;
1984        }
1985        /*  We MUST start with a box, so at this level, the unique possibility is '[', '(' or "}". */
1986prepare_loop:
1987        if (SYNCTEX_CUR<SYNCTEX_END) {
1988                if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_VBOX) {
1989scan_vbox:
1990                        if ((child = _synctex_new_vbox(scanner)) && (info = SYNCTEX_INFO(child))) {
1991#               define SYNCTEX_DECODE_FAILED(WHAT) \
1992                                        (_synctex_decode_int(scanner,&(info[WHAT].INT))<SYNCTEX_STATUS_OK)
1993                                if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
1994                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
1995                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
1996                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
1997                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
1998                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
1999                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2000                                                || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2001                                        _synctex_error("Bad vbox record.");
2002                                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2003                                }
2004                                SYNCTEX_SET_CHILD(parent,child);
2005                                parent = child;
2006                                child = NULL;
2007                                goto child_loop;/*  next created node will be a child */
2008                        } else {
2009                                _synctex_error("Can't create vbox record.");
2010                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2011                        }
2012                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_HBOX) {
2013scan_hbox:
2014                        if ((child = _synctex_new_hbox(scanner)) && (info = SYNCTEX_INFO(child))) {
2015                                if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2016                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2017                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2018                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2019                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2020                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2021                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2022                                                || _synctex_setup_visible_box(child)<SYNCTEX_STATUS_OK
2023                                                || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2024                                        _synctex_error("Bad hbox record.");
2025                                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2026                                }
2027                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2028                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child));
2029                                SYNCTEX_SET_CHILD(parent,child);
2030                                parent = child;
2031                                child = NULL;
2032                                goto child_loop;/*  next created node will be a child */
2033                        } else {
2034                                _synctex_error("Can't create hbox record.");
2035                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2036                        }
2037                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_SHEET) {
2038scan_teehs:
2039                        ++SYNCTEX_CUR;
2040                        if (NULL == parent || parent->class->type != synctex_node_type_sheet
2041                                        || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2042                                _synctex_error("Unexpected end of sheet.");
2043                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2044                        }
2045#           if SYNCTEX_VERBOSE
2046                synctex_node_log(parent);
2047#           endif
2048                        SYNCTEX_RETURN(SYNCTEX_STATUS_OK);
2049                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_SHEET) {
2050                        /*  Addendum to version 1.10 to manage nested sheets  */
2051                        ++SYNCTEX_CUR;
2052                        if (_synctex_scan_nested_sheet(scanner)<SYNCTEX_STATUS_OK) {
2053                                _synctex_error("Unexpected nested sheet.");
2054                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2055                        }
2056                        goto prepare_loop;
2057                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_ANCHOR) {
2058scan_anchor:
2059                        ++SYNCTEX_CUR;
2060                        if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2061                                _synctex_error("Missing anchor.");
2062                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2063                        }
2064                        goto prepare_loop;
2065                } else {
2066                        /*  _synctex_error("Ignored record %c\n",*SYNCTEX_CUR); */
2067                        ++SYNCTEX_CUR;
2068                        if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2069                                _synctex_error("Unexpected end.");
2070                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2071                        }
2072                        goto prepare_loop;
2073                }
2074        } else {
2075                available = 1;
2076                status = _synctex_buffer_get_available_size(scanner,&available);
2077                 if (status<SYNCTEX_STATUS_OK && available>0){
2078                        _synctex_error("Uncomplete sheet(0)");
2079                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2080                }
2081        goto prepare_loop;
2082        }
2083/*  The child loop means that we go down one level, when we just created a box node,
2084 *  the next node created is a child of this box. */
2085child_loop:
2086        if (SYNCTEX_CUR<SYNCTEX_END) {
2087                if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_VBOX) {
2088                        goto scan_vbox;
2089                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_VBOX) {
2090scan_xobv:
2091                        ++SYNCTEX_CUR;
2092                        if (NULL != parent && parent->class->type == synctex_node_type_vbox) {
2093                                #define SYNCTEX_UPDATE_BOX_FRIEND(NODE)\
2094                                friend_index = ((SYNCTEX_INFO(NODE))[SYNCTEX_TAG_IDX].INT+(SYNCTEX_INFO(NODE))[SYNCTEX_LINE_IDX].INT)%(scanner->number_of_lists);\
2095                                SYNCTEX_SET_FRIEND(NODE,(scanner->lists_of_friends)[friend_index]);\
2096                                (scanner->lists_of_friends)[friend_index] = NODE;
2097                                if (NULL == SYNCTEX_CHILD(parent)) {
2098                                        /*  only void boxes are friends */
2099                                        SYNCTEX_UPDATE_BOX_FRIEND(parent);
2100                                }
2101                                child = parent;
2102                                parent = SYNCTEX_PARENT(child);
2103                        } else {
2104                                _synctex_error("Unexpected end of vbox, ignored.");
2105                        }
2106                        if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2107                                _synctex_error("Uncomplete sheet.");
2108                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2109                        }
2110#           if SYNCTEX_VERBOSE
2111                synctex_node_log(child);
2112#           endif
2113                        goto sibling_loop;
2114                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_HBOX) {
2115                        goto scan_hbox;
2116                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_HBOX) {
2117scan_xobh:
2118                        ++SYNCTEX_CUR;
2119                        if ((parent) && parent->class->type == synctex_node_type_hbox) {
2120            /*  Update the mean line number */
2121                synctex_node_t node = SYNCTEX_CHILD(parent);
2122                if (node) {
2123                    unsigned int node_weight = 0;
2124                    unsigned int cumulated_line_numbers = 0;
2125                    do {
2126                        if (synctex_node_type(node)==synctex_node_type_hbox) {
2127                            if (SYNCTEX_NODE_WEIGHT(node)) {
2128                                node_weight += SYNCTEX_NODE_WEIGHT(node);
2129                                cumulated_line_numbers += SYNCTEX_MEAN_LINE(node)*SYNCTEX_NODE_WEIGHT(node);
2130                            } else {
2131                                ++node_weight;
2132                                cumulated_line_numbers += SYNCTEX_MEAN_LINE(node);
2133                            }
2134                        } else {
2135                            ++node_weight;
2136                            cumulated_line_numbers += SYNCTEX_LINE(node);
2137                        }
2138                    } while ((node = SYNCTEX_SIBLING(node)));
2139                    SYNCTEX_MEAN_LINE(parent)=(cumulated_line_numbers + node_weight/2)/node_weight;
2140                    SYNCTEX_NODE_WEIGHT(parent)=node_weight;
2141                } else {
2142                    SYNCTEX_MEAN_LINE(parent)=SYNCTEX_LINE(parent);
2143                    SYNCTEX_NODE_WEIGHT(parent)=1;
2144                }
2145                                if (NULL == child) {
2146                                        /*  Only boxes with no children are friends,
2147                                         *  boxes with children are indirectly friends through one of their contained nodes. */
2148                                        SYNCTEX_UPDATE_BOX_FRIEND(parent);
2149                                }
2150                                /*  setting the next horizontal box at the end ensures that a child is recorded before any of its ancestors. */
2151                                SYNCTEX_SET_NEXT_hbox(box,parent);
2152                                box = parent;
2153                                child = parent;
2154                                parent = SYNCTEX_PARENT(child);
2155                        } else {
2156                                _synctex_error("Unexpected end of hbox, ignored.");
2157                        }
2158                        if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2159                                _synctex_error("Uncomplete sheet.");
2160                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2161                        }
2162#           if SYNCTEX_VERBOSE
2163                synctex_node_log(child);
2164#           endif
2165                        goto sibling_loop;
2166                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_VOID_VBOX) {
2167                        if (NULL != (child = _synctex_new_void_vbox(scanner))
2168                                        && NULL != (info = SYNCTEX_INFO(child))) {
2169                                if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2170                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2171                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2172                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2173                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2174                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2175                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2176                                                || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2177                                        _synctex_error("Bad void vbox record.");
2178                                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2179                                }
2180                                SYNCTEX_SET_CHILD(parent,child);
2181                                #define SYNCTEX_UPDATE_FRIEND(NODE)\
2182                                friend_index = (info[SYNCTEX_TAG_IDX].INT+info[SYNCTEX_LINE_IDX].INT)%(scanner->number_of_lists);\
2183                                SYNCTEX_SET_FRIEND(NODE,(scanner->lists_of_friends)[friend_index]);\
2184                                (scanner->lists_of_friends)[friend_index] = NODE;
2185                                SYNCTEX_UPDATE_FRIEND(child);
2186#               if SYNCTEX_VERBOSE
2187                    synctex_node_log(child);
2188#               endif
2189                                goto sibling_loop;
2190                        } else {
2191                                _synctex_error("Can't create vbox record.");
2192                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2193                        }
2194                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_VOID_HBOX) {
2195                        if (NULL != (child = _synctex_new_void_hbox(scanner))
2196                                        && NULL != (info = SYNCTEX_INFO(child))) {
2197                                if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2198                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2199                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2200                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2201                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2202                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2203                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2204                                                || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2205                                        _synctex_error("Bad void hbox record.");
2206                                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2207                                }
2208                                SYNCTEX_SET_CHILD(parent,child);
2209                                SYNCTEX_UPDATE_FRIEND(child);
2210                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2211                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child));
2212#               if SYNCTEX_VERBOSE
2213                    synctex_node_log(child);
2214#               endif
2215                                goto sibling_loop;
2216                        } else {
2217                                _synctex_error("Can't create void hbox record.");
2218                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2219                        }
2220                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_KERN) {
2221                        if (NULL != (child = _synctex_new_kern(scanner))
2222                                        && NULL != (info = SYNCTEX_INFO(child))) {
2223                                if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2224                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2225                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2226                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2227                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2228                                                || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2229                                        _synctex_error("Bad kern record.");
2230                                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2231                                }
2232                                SYNCTEX_SET_CHILD(parent,child);
2233                                SYNCTEX_UPDATE_FRIEND(child);
2234                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2235                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child)-SYNCTEX_WIDTH(child),SYNCTEX_VERT(child));
2236#               if SYNCTEX_VERBOSE
2237                    synctex_node_log(child);
2238#               endif
2239                                goto sibling_loop;
2240                        } else {
2241                                _synctex_error("Can't create kern record.");
2242                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2243                        }
2244                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_GLUE) {
2245                        if (NULL != (child = _synctex_new_glue(scanner))
2246                                        && NULL != (info = SYNCTEX_INFO(child))) {
2247                                if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2248                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2249                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2250                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2251                                                || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2252                                        _synctex_error("Bad glue record.");
2253                                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2254                                }
2255                                SYNCTEX_SET_CHILD(parent,child);
2256                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2257                                SYNCTEX_UPDATE_FRIEND(child);
2258#               if SYNCTEX_VERBOSE
2259                    synctex_node_log(child);
2260#               endif
2261                                goto sibling_loop;
2262                        } else {
2263                                _synctex_error("Can't create glue record.");
2264                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2265                        }
2266                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_MATH) {
2267                        if (NULL != (child = _synctex_new_math(scanner))
2268                                        && NULL != (info = SYNCTEX_INFO(child))) {
2269                                if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2270                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2271                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2272                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2273                                                || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2274                                        _synctex_error("Bad math record.");
2275                                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2276                                }
2277                                SYNCTEX_SET_CHILD(parent,child);
2278                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2279                                SYNCTEX_UPDATE_FRIEND(child);
2280#               if SYNCTEX_VERBOSE
2281                    synctex_node_log(child);
2282#               endif
2283                                goto sibling_loop;
2284                        } else {
2285                                _synctex_error("Can't create math record.");
2286                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2287                        }
2288                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BOUNDARY) {
2289                        if (NULL != (child = _synctex_new_boundary(scanner))
2290                                        && NULL != (info = SYNCTEX_INFO(child))) {
2291                                if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2292                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2293                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2294                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2295                                                || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2296                                        _synctex_error("Bad boundary record.");
2297                                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2298                                }
2299                                SYNCTEX_SET_CHILD(parent,child);
2300                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2301                                SYNCTEX_UPDATE_FRIEND(child);
2302#               if SYNCTEX_VERBOSE
2303                    synctex_node_log(child);
2304#               endif
2305                                goto sibling_loop;
2306                        } else {
2307                                _synctex_error("Can't create math record.");
2308                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2309                        }
2310                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_SHEET) {
2311                        goto scan_teehs;
2312                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_SHEET) {
2313                        /*  Addendum to version 1.10 to manage nested sheets  */
2314                        ++SYNCTEX_CUR;
2315                        if (_synctex_scan_nested_sheet(scanner)<SYNCTEX_STATUS_OK) {
2316                                _synctex_error("Unexpected nested sheet.");
2317                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2318                        }
2319                        goto child_loop;
2320                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_ANCHOR) {
2321                        goto scan_anchor;
2322                } else {
2323                        /*  _synctex_error("Ignored record %c\n",*SYNCTEX_CUR); */
2324                        ++SYNCTEX_CUR;
2325                        if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2326                                _synctex_error("Unexpected end.");
2327                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2328                        }
2329                        goto child_loop;
2330                }
2331        } else {
2332                available = 1;
2333                status = _synctex_buffer_get_available_size(scanner,&available);
2334                 if (status<SYNCTEX_STATUS_OK && available>0){
2335                        _synctex_error("Uncomplete sheet(0)");
2336                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2337                } else {
2338                        goto child_loop;
2339                }
2340        }
2341/*  The vertical loop means that we are on the same level, for example when we just ended a box.
2342 *  If a node is created now, it will be a sibling of the current node, sharing the same parent. */
2343sibling_loop:
2344        if (SYNCTEX_CUR<SYNCTEX_END) {
2345                if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_VBOX) {
2346                        if (NULL != (sibling = _synctex_new_vbox(scanner))
2347                                        && NULL != (info = SYNCTEX_INFO(sibling))) {
2348                                if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2349                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2350                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2351                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2352                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2353                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2354                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2355                                                || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2356                                        _synctex_error("Bad vbox record (2).");
2357                                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2358                                }
2359                                SYNCTEX_SET_SIBLING(child,sibling);
2360                                parent = sibling;
2361                                child = NULL;
2362                                goto child_loop;
2363                        } else {
2364                                _synctex_error("Can't create vbox record (2).");
2365                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2366                        }
2367                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_VBOX) {
2368                        goto scan_xobv;
2369                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_HBOX) {
2370                        if (NULL != (sibling = _synctex_new_hbox(scanner)) &&
2371                                        NULL != (info = SYNCTEX_INFO(sibling))) {
2372                                if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2373                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2374                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2375                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2376                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2377                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2378                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2379                                                || _synctex_setup_visible_box(sibling)<SYNCTEX_STATUS_OK
2380                                                || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2381                                        _synctex_error("Bad hbox record (2).");
2382                                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2383                                }
2384                                SYNCTEX_SET_SIBLING(child,sibling);
2385                                child = sibling;
2386                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2387                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child));
2388#               if SYNCTEX_VERBOSE
2389                    synctex_node_log(child);
2390#               endif
2391                                parent = child;
2392                                child = NULL;
2393                                goto child_loop;
2394                        } else {
2395                                _synctex_error("Can't create hbox record (2).");
2396                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2397                        }
2398                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_HBOX) {
2399                        goto scan_xobh;
2400                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_VOID_VBOX) {
2401                        if (NULL != (sibling = _synctex_new_void_vbox(scanner)) &&
2402                                        NULL != (info = SYNCTEX_INFO(sibling))) {
2403                                if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2404                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2405                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2406                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2407                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2408                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2409                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2410                                                || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2411                                        _synctex_error("Bad void vbox record (2).");
2412                                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2413                                }
2414                                SYNCTEX_SET_SIBLING(child,sibling);
2415                                child = sibling;
2416#               if SYNCTEX_VERBOSE
2417                    synctex_node_log(child);
2418#               endif
2419                                SYNCTEX_UPDATE_FRIEND(child);
2420                                goto sibling_loop;
2421                        } else {
2422                                _synctex_error("can't create void vbox record (2).");
2423                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2424                        }
2425                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_VOID_HBOX) {
2426                        if (NULL != (sibling = _synctex_new_void_hbox(scanner)) &&
2427                                        NULL != (info = SYNCTEX_INFO(sibling))) {
2428                                if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2429                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2430                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2431                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2432                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2433                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2434                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2435                                                || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2436                                        _synctex_error("Bad void hbox record (2).");
2437                                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2438                                }
2439                                SYNCTEX_SET_SIBLING(child,sibling);
2440                                child = sibling;
2441#               if SYNCTEX_VERBOSE
2442                    synctex_node_log(child);
2443#               endif
2444                                SYNCTEX_UPDATE_FRIEND(child);
2445                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2446                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child));
2447                                goto sibling_loop;
2448                        } else {
2449                                _synctex_error("can't create void hbox record (2).");
2450                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2451                        }
2452                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_KERN) {
2453                        if (NULL != (sibling = _synctex_new_kern(scanner))
2454                                        && NULL != (info = SYNCTEX_INFO(sibling))) {
2455                                if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2456                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2457                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2458                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2459                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2460                                                || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2461                                        _synctex_error("Bad kern record (2).");
2462                                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2463                                }
2464                                SYNCTEX_SET_SIBLING(child,sibling);
2465                                child = sibling;
2466#               if SYNCTEX_VERBOSE
2467                    synctex_node_log(child);
2468#               endif
2469                                SYNCTEX_UPDATE_FRIEND(child);
2470                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2471                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child)-SYNCTEX_WIDTH(child),SYNCTEX_VERT(child));
2472                                goto sibling_loop;
2473                        } else {
2474                                _synctex_error("Can't create kern record (2).");
2475                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2476                        }
2477                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_GLUE) {
2478                        if (NULL != (sibling = _synctex_new_glue(scanner))
2479                                        && NULL != (info = SYNCTEX_INFO(sibling))) {
2480                                if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2481                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2482                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2483                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2484                                                || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2485                                        _synctex_error("Bad glue record (2).");
2486                                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2487                                }
2488                                SYNCTEX_SET_SIBLING(child,sibling);
2489                                child = sibling;
2490#               if SYNCTEX_VERBOSE
2491                    synctex_node_log(child);
2492#               endif
2493                                SYNCTEX_UPDATE_FRIEND(child);
2494                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2495                                goto sibling_loop;
2496                        } else {
2497                                _synctex_error("Can't create glue record (2).");
2498                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2499                        }
2500                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_MATH) {
2501                        if (NULL != (sibling = _synctex_new_math(scanner))
2502                                        && NULL != (info = SYNCTEX_INFO(sibling))) {
2503                                if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2504                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2505                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2506                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2507                                                || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2508                                        _synctex_error("Bad math record (2).");
2509                                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2510                                }
2511                                SYNCTEX_SET_SIBLING(child,sibling);
2512                                child = sibling;
2513#               if SYNCTEX_VERBOSE
2514                    synctex_node_log(child);
2515#               endif
2516                                SYNCTEX_UPDATE_FRIEND(child);
2517                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2518                                goto sibling_loop;
2519                        } else {
2520                                _synctex_error("Can't create math record (2).");
2521                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2522                        }
2523                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BOUNDARY) {
2524                        if (NULL != (sibling = _synctex_new_boundary(scanner))
2525                                        && NULL != (info = SYNCTEX_INFO(sibling))) {
2526                                if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2527                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2528                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2529                                                || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2530                                                || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2531                                        _synctex_error("Bad boundary record (2).");
2532                                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2533                                }
2534                                SYNCTEX_SET_SIBLING(child,sibling);
2535                                child = sibling;
2536#               if SYNCTEX_VERBOSE
2537                    synctex_node_log(child);
2538#               endif
2539                                SYNCTEX_UPDATE_FRIEND(child);
2540                                _synctex_hbox_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2541                                goto sibling_loop;
2542                        } else {
2543                                _synctex_error("Can't create boundary record (2).");
2544                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2545                        }
2546                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_SHEET) {
2547                        goto scan_teehs;
2548                } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_ANCHOR) {
2549                        ++SYNCTEX_CUR;
2550                        if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2551                                _synctex_error("Missing anchor (2).");
2552                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2553                        }
2554                        goto sibling_loop;
2555                } else {
2556                        ++SYNCTEX_CUR;
2557                        /* _synctex_error("Ignored record %c(2)\n",*SYNCTEX_CUR); */
2558                        if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2559                                SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2560                        }
2561                        goto sibling_loop;
2562                }
2563        } else {
2564                available = 1;
2565                status = _synctex_buffer_get_available_size(scanner,&available);
2566                if (status<SYNCTEX_STATUS_OK && available>0){
2567                        goto sibling_loop;
2568                } else {
2569                        _synctex_error("Uncomplete sheet(2)");
2570                        SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2571                }
2572        }
2573#   undef SYNCTEX_DECODE_FAILED
2574}
2575
2576#   define SYNCTEX_APPEND_SHEET(SCANNER,SHEET) if (SCANNER->sheet) {\
2577        synctex_node_t last_sheet = SCANNER->sheet;\
2578        synctex_node_t next_sheet = NULL;\
2579        while ((next_sheet = SYNCTEX_SIBLING(last_sheet))) {\
2580            last_sheet = next_sheet;\
2581        }\
2582                SYNCTEX_SET_SIBLING(last_sheet,SHEET);\
2583    } else {\
2584        SCANNER->sheet = SHEET;\
2585    }
2586
2587/*  Used when parsing the synctex file
2588 */
2589synctex_status_t _synctex_scan_content(synctex_scanner_t scanner) {
2590        synctex_node_t sheet = NULL;
2591        synctex_status_t status = 0;
2592        if (NULL == scanner) {
2593                return SYNCTEX_STATUS_BAD_ARGUMENT;
2594        }
2595        /*  set up the lists of friends */
2596        if (NULL == scanner->lists_of_friends) {
2597                scanner->number_of_lists = 1024;
2598                scanner->lists_of_friends = (synctex_node_t *)_synctex_malloc(scanner->number_of_lists*sizeof(synctex_node_t));
2599                if (NULL == scanner->lists_of_friends) {
2600                        _synctex_error("malloc:2");
2601                        return SYNCTEX_STATUS_ERROR;
2602                }
2603        }
2604        /*  Find where this section starts */
2605content_not_found:
2606        status = _synctex_match_string(scanner,"Content:");
2607        if (status<SYNCTEX_STATUS_EOF) {
2608                return status;
2609        }
2610        if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2611                _synctex_error("Uncomplete Content.");
2612                return SYNCTEX_STATUS_ERROR;
2613        }
2614        if (status == SYNCTEX_STATUS_NOT_OK) {
2615                goto content_not_found;
2616        }
2617next_sheet:
2618        if (*SYNCTEX_CUR != SYNCTEX_CHAR_BEGIN_SHEET) {
2619                status = _synctex_scan_postamble(scanner);
2620                if (status < SYNCTEX_STATUS_EOF) {
2621                        _synctex_error("Bad content.");
2622                        return status;
2623                }
2624                if (status<SYNCTEX_STATUS_OK) {
2625                        status = _synctex_next_line(scanner);
2626                        if (status < SYNCTEX_STATUS_OK) {
2627                                _synctex_error("Bad content.");
2628                                return status;
2629                        }
2630                        goto next_sheet;
2631                }
2632                return SYNCTEX_STATUS_OK;
2633        }
2634        /*  Create a new sheet node */
2635        sheet = _synctex_new_sheet(scanner);
2636        status = _synctex_decode_int(scanner,&(SYNCTEX_PAGE(sheet)));
2637        if (status<SYNCTEX_STATUS_OK) {
2638                _synctex_error("Missing sheet number.");
2639bail:
2640                SYNCTEX_FREE(sheet);
2641                return SYNCTEX_STATUS_ERROR;
2642        }
2643        status = _synctex_next_line(scanner);
2644        if (status<SYNCTEX_STATUS_OK) {
2645                _synctex_error("Uncomplete file.");
2646                goto bail;
2647        }
2648        status = _synctex_scan_sheet(scanner,sheet);
2649        if (status<SYNCTEX_STATUS_OK) {
2650                _synctex_error("Bad sheet content.");
2651                goto bail;
2652        }
2653        SYNCTEX_APPEND_SHEET(scanner,sheet);
2654        sheet = NULL;
2655        /*  Now read the list of Inputs between 2 sheets. */
2656        do {
2657                status = _synctex_scan_input(scanner);
2658                if (status<SYNCTEX_STATUS_EOF) {
2659                        _synctex_error("Bad input section.");
2660                        goto bail;
2661                }
2662        }
2663        while(status >= SYNCTEX_STATUS_OK);
2664        goto next_sheet;
2665}
2666
2667int _synctex_open(const char * output, const char * build_directory, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_modeRef);
2668
2669/*  Where the synctex scanner is created. */
2670synctex_scanner_t synctex_scanner_new_with_output_file(const char * output, const char * build_directory, int parse) {
2671        gzFile file = NULL;
2672        char * synctex = NULL;
2673        synctex_scanner_t scanner = NULL;
2674        synctex_io_mode_t io_mode = 0;
2675        /*  Here we assume that int are smaller than void * */
2676        if (sizeof(int)>sizeof(void*)) {
2677                _synctex_error("INTERNAL INCONSISTENCY: int's are unexpectedly bigger than pointers, bailing out.");
2678                return NULL;
2679        }
2680        /*  We ensure that SYNCTEX_BUFFER_SIZE < UINT_MAX, I don't know if it makes sense... */
2681        if (SYNCTEX_BUFFER_SIZE >= UINT_MAX) {
2682                _synctex_error("Internal inconsistency, bad SYNCTEX_BUFFER_SIZE (1)");
2683                return NULL;
2684        }
2685        /*  for integers: */
2686        if (SYNCTEX_BUFFER_SIZE < SYNCTEX_BUFFER_MIN_SIZE) {
2687                _synctex_error("Internal inconsistency, bad SYNCTEX_BUFFER_SIZE (2)");
2688                return NULL;
2689        }
2690        /*  now open the synctex file */
2691        if (_synctex_open(output,build_directory,&synctex,&file,synctex_ADD_QUOTES,&io_mode) || !file) {
2692                if (_synctex_open(output,build_directory,&synctex,&file,synctex_DONT_ADD_QUOTES,&io_mode) || !file) {
2693                        return NULL;
2694                }
2695        }
2696        scanner = (synctex_scanner_t)_synctex_malloc(sizeof(_synctex_scanner_t));
2697        if (NULL == scanner) {
2698                _synctex_error("malloc problem");
2699                free(synctex);
2700                gzclose(file);
2701                return NULL;
2702        }
2703        /*  make a private copy of output for the scanner */
2704        if (NULL == (scanner->output = (char *)malloc(strlen(output)+1))){
2705                _synctex_error("!  synctex_scanner_new_with_output_file: Memory problem (2), scanner's output is not reliable.");
2706        } else if (scanner->output != strcpy(scanner->output,output)) {
2707                _synctex_error("!  synctex_scanner_new_with_output_file: Copy problem, scanner's output is not reliable.");
2708        }
2709        scanner->synctex = synctex;/*  Now the scanner owns synctex */
2710        SYNCTEX_FILE = file;
2711        return parse? synctex_scanner_parse(scanner):scanner;
2712}
2713
2714/*      This functions opens the file at the "output" given location.
2715 *  It manages the problem of quoted filenames that appear with pdftex and filenames containing the space character.
2716 *  In TeXLive 2008, the synctex file created with pdftex did contain unexpected quotes.
2717 *      This function will remove them if possible.
2718 *  All the reference arguments will take a value on return. They must be non NULL.
2719 *      0 on success, non 0 on error. */
2720static int __synctex_open(const char * output, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_mode_ref) {
2721        if (synctex_name_ref && file_ref && io_mode_ref) {
2722        /*  1 local variables that uses dynamic memory */
2723        char * synctex_name = NULL;
2724        gzFile the_file = NULL;
2725        char * quoteless_synctex_name = NULL;
2726                size_t size = 0;
2727        synctex_io_mode_t io_mode = *io_mode_ref;
2728                const char * mode = _synctex_get_io_mode_name(io_mode);
2729                /*  now create the synctex file name */
2730                size = strlen(output)+strlen(synctex_suffix)+strlen(synctex_suffix_gz)+1;
2731                synctex_name = (char *)malloc(size);
2732                if (NULL == synctex_name) {
2733                        _synctex_error("!  __synctex_open: Memory problem (1)\n");
2734                        return 1;
2735                }
2736                /*  we have reserved for synctex enough memory to copy output (including its 2 eventual quotes), both suffices,
2737                 *  including the terminating character. size is free now. */
2738                if (synctex_name != strcpy(synctex_name,output)) {
2739                        _synctex_error("!  __synctex_open: Copy problem\n");
2740return_on_error:
2741                        free(synctex_name);
2742                        free(quoteless_synctex_name);
2743                        return 2;
2744                }
2745                /*  remove the last path extension if any */
2746                _synctex_strip_last_path_extension(synctex_name);
2747                if (!strlen(synctex_name)) {
2748                        goto return_on_error;           
2749                }
2750                /*  now insert quotes. */
2751                if (add_quotes) {
2752                        char * quoted = NULL;
2753                        if (_synctex_copy_with_quoting_last_path_component(synctex_name,&quoted,size) || (NULL == quoted)) {
2754                                /*      There was an error or quoting does not make sense: */
2755                                goto return_on_error;
2756                        }
2757                        quoteless_synctex_name = synctex_name;
2758                        synctex_name = quoted;
2759                }
2760                /*      Now add to synctex_name the first path extension. */
2761                if (synctex_name != strcat(synctex_name,synctex_suffix)){
2762                        _synctex_error("!  __synctex_open: Concatenation problem (can't add suffix '%s')\n",synctex_suffix);
2763                        goto return_on_error;
2764                }
2765                /*      Add to quoteless_synctex_name as well, if relevant. */
2766                if (quoteless_synctex_name && (quoteless_synctex_name != strcat(quoteless_synctex_name,synctex_suffix))){
2767                        free(quoteless_synctex_name);
2768                        quoteless_synctex_name = NULL;
2769                }
2770                if (NULL == (the_file = gzopen(synctex_name,mode))) {
2771                        /*  Could not open this file */
2772                        if (errno != ENOENT) {
2773                                /*  The file does exist, this is a lower level error, I can't do anything. */
2774                                _synctex_error("could not open %s, error %i\n",synctex_name,errno);
2775                                goto return_on_error;
2776                        }
2777                        /*  Apparently, there is no uncompressed synctex file. Try the compressed version */
2778                        if (synctex_name != strcat(synctex_name,synctex_suffix_gz)){
2779                                _synctex_error("!  __synctex_open: Concatenation problem (can't add suffix '%s')\n",synctex_suffix_gz);
2780                                goto return_on_error;
2781                        }
2782                        io_mode |= synctex_io_gz_mask;
2783                        mode = _synctex_get_io_mode_name(io_mode); /* the file is a compressed and is a binary file, this caused errors on Windows */
2784                        /*      Add the suffix to the quoteless_synctex_name as well. */
2785                        if (quoteless_synctex_name && (quoteless_synctex_name != strcat(quoteless_synctex_name,synctex_suffix_gz))){
2786                                free(quoteless_synctex_name);
2787                                quoteless_synctex_name = NULL;
2788                        }
2789                        if (NULL == (the_file = gzopen(synctex_name,mode))) {
2790                                /*  Could not open this file */
2791                                if (errno != ENOENT) {
2792                                        /*  The file does exist, this is a lower level error, I can't do anything. */
2793                                        _synctex_error("Could not open %s, error %i\n",synctex_name,errno);
2794                                }
2795                                goto return_on_error;
2796                        }
2797                }
2798                /*      At this point, the file is properly open.
2799                 *  If we are in the add_quotes mode, we change the file name by removing the quotes. */
2800                if (quoteless_synctex_name) {
2801                        gzclose(the_file);
2802                        if (rename(synctex_name,quoteless_synctex_name)) {
2803                                _synctex_error("Could not rename %s to %s, error %i\n",synctex_name,quoteless_synctex_name,errno);
2804                                /*      We could not rename, reopen the file with the quoted name. */
2805                                if (NULL == (the_file = gzopen(synctex_name,mode))) {
2806                                        /*  No luck, could not re open this file, something has happened meanwhile */
2807                                        if (errno != ENOENT) {
2808                                                /*  The file does not exist any more, it has certainly be removed somehow
2809                         *  this is a lower level error, I can't do anything. */
2810                                                _synctex_error("Could not open again %s, error %i\n",synctex_name,errno);
2811                                        }
2812                                        goto return_on_error;
2813                                }
2814                        } else {
2815                /*  The file has been successfully renamed */
2816                                if (NULL == (the_file = gzopen(quoteless_synctex_name,mode))) {
2817                                        /*  Could not open this file */
2818                                        if (errno != ENOENT) {
2819                                                /*  The file does exist, this is a lower level error, I can't do anything. */
2820                                                _synctex_error("Could not open renamed %s, error %i\n",quoteless_synctex_name,errno);
2821                                        }
2822                                        goto return_on_error;
2823                                }
2824                                /*  The quote free file name should replace the old one:*/
2825                                free(synctex_name);
2826                                synctex_name = quoteless_synctex_name;
2827                                quoteless_synctex_name = NULL;
2828                        }
2829                }
2830        /*  The operation is successfull, return the arguments by value.    */
2831        * file_ref = the_file;
2832        * io_mode_ref = io_mode;
2833        * synctex_name_ref = synctex_name;
2834                return 0;
2835        }
2836        return 3;       /*      Bad parameter.  */
2837}
2838
2839/*      Opens the ouput file, taking into account the eventual build_directory.
2840 *      0 on success, non 0 on error. */
2841int _synctex_open(const char * output, const char * build_directory, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_mode_ref) {
2842#       define synctex_name (*synctex_name_ref)
2843#       define the_file (*file_ref)
2844        int result = __synctex_open(output,synctex_name_ref,file_ref,add_quotes,io_mode_ref);
2845        if ((result || !*file_ref) && build_directory && strlen(build_directory)) {
2846                char * build_output;
2847                const char *lpc;
2848                size_t size;
2849                synctex_bool_t is_absolute;
2850                build_output = NULL;
2851                lpc = _synctex_last_path_component(output);
2852                size = strlen(build_directory)+strlen(lpc)+2;   /*  One for the '/' and one for the '\0'.   */
2853                is_absolute = _synctex_path_is_absolute(build_directory);
2854                if (!is_absolute) {
2855                        size += strlen(output);
2856                }
2857                if ((build_output = (char *)malloc(size))) {
2858                        if (is_absolute) {
2859                                build_output[0] = '\0';
2860                        } else {
2861                                if (build_output != strcpy(build_output,output)) {
2862                                        free(build_output);
2863                                        return -4;
2864                                }
2865                                build_output[lpc-output]='\0';
2866                        }
2867                        if (build_output == strcat(build_output,build_directory)) {
2868                                /*      Append a path separator if necessary. */
2869                                if (!SYNCTEX_IS_PATH_SEPARATOR(build_output[strlen(build_directory)-1])) {
2870                                        if (build_output != strcat(build_output,"/")) {
2871                                                free(build_output);
2872                                                return -2;
2873                                        }
2874                                }
2875                                /*      Append the last path component of the output. */
2876                                if (build_output != strcat(build_output,lpc)) {
2877                                        free(build_output);
2878                                        return -3;
2879                                }
2880                                result = __synctex_open(build_output,synctex_name_ref,file_ref,add_quotes,io_mode_ref);
2881                                free(build_output);
2882                                return result;
2883                        }
2884                        free(build_output);
2885                }
2886                return -1;
2887        }
2888        return result;
2889#       undef synctex_name
2890#       undef the_file
2891}
2892
2893/*  The scanner destructor
2894 */
2895void synctex_scanner_free(synctex_scanner_t scanner) {
2896        if (NULL == scanner) {
2897                return;
2898        }
2899        if (SYNCTEX_FILE) {
2900                gzclose(SYNCTEX_FILE);
2901                SYNCTEX_FILE = NULL;
2902        }
2903        SYNCTEX_FREE(scanner->sheet);
2904        SYNCTEX_FREE(scanner->input);
2905        free(SYNCTEX_START);
2906        free(scanner->output_fmt);
2907        free(scanner->output);
2908        free(scanner->synctex);
2909        free(scanner->lists_of_friends);
2910        free(scanner);
2911}
2912
2913/*  Where the synctex scanner parses the contents of the file. */
2914synctex_scanner_t synctex_scanner_parse(synctex_scanner_t scanner) {
2915        synctex_status_t status = 0;
2916        if (!scanner || scanner->flags.has_parsed) {
2917                return scanner;
2918        }
2919        scanner->flags.has_parsed=1;
2920        scanner->pre_magnification = 1000;
2921        scanner->pre_unit = 8192;
2922        scanner->pre_x_offset = scanner->pre_y_offset = 578;
2923        /*  initialize the offset with a fake unprobable value,
2924         *  If there is a post scriptum section, this value will be overriden by the real life value */
2925        scanner->x_offset = scanner->y_offset = 6.027e23f;
2926#   define DEFINE_synctex_scanner_class(NAME)\
2927        scanner->class[synctex_node_type_##NAME] = synctex_class_##NAME;\
2928        (scanner->class[synctex_node_type_##NAME]).scanner = scanner
2929    DEFINE_synctex_scanner_class(sheet);
2930    DEFINE_synctex_scanner_class(input);
2931    DEFINE_synctex_scanner_class(hbox);
2932    DEFINE_synctex_scanner_class(void_hbox);
2933    DEFINE_synctex_scanner_class(vbox);
2934    DEFINE_synctex_scanner_class(void_vbox);
2935    DEFINE_synctex_scanner_class(kern);
2936    DEFINE_synctex_scanner_class(glue);
2937    DEFINE_synctex_scanner_class(math);
2938    DEFINE_synctex_scanner_class(boundary);
2939        SYNCTEX_START = (char *)malloc(SYNCTEX_BUFFER_SIZE+1); /*  one more character for null termination */
2940        if (NULL == SYNCTEX_START) {
2941                _synctex_error("malloc error");
2942                synctex_scanner_free(scanner);
2943                return NULL;
2944        }
2945        SYNCTEX_END = SYNCTEX_START+SYNCTEX_BUFFER_SIZE;
2946        /*  SYNCTEX_END always points to a null terminating character.
2947         *  Maybe there is another null terminating character between SYNCTEX_CUR and SYNCTEX_END-1.
2948         *  At least, we are sure that SYNCTEX_CUR points to a string covering a valid part of the memory. */
2949        *SYNCTEX_END = '\0';
2950        SYNCTEX_CUR = SYNCTEX_END;
2951#   if defined(SYNCTEX_USE_CHARINDEX)
2952    scanner->charindex_offset = -SYNCTEX_BUFFER_SIZE;
2953#   endif
2954        status = _synctex_scan_preamble(scanner);
2955        if (status<SYNCTEX_STATUS_OK) {
2956                _synctex_error("SyncTeX Error: Bad preamble\n");
2957bailey:
2958                synctex_scanner_free(scanner);
2959                return NULL;
2960        }
2961        status = _synctex_scan_content(scanner);
2962        if (status<SYNCTEX_STATUS_OK) {
2963                _synctex_error("SyncTeX Error: Bad content\n");
2964                goto bailey;
2965        }
2966        /*  Everything is finished, free the buffer, close the file */
2967        free((void *)SYNCTEX_START);
2968        SYNCTEX_START = SYNCTEX_CUR = SYNCTEX_END = NULL;
2969        gzclose(SYNCTEX_FILE);
2970        SYNCTEX_FILE = NULL;
2971        /*  Final tuning: set the default values for various parameters */
2972        /*  1 pre_unit = (scanner->pre_unit)/65536 pt = (scanner->pre_unit)/65781.76 bp
2973         * 1 pt = 65536 sp */
2974        if (scanner->pre_unit<=0) {
2975                scanner->pre_unit = 8192;
2976        }
2977        if (scanner->pre_magnification<=0) {
2978                scanner->pre_magnification = 1000;
2979        }
2980        if (scanner->unit <= 0) {
2981                /*  no post magnification */
2982                scanner->unit = scanner->pre_unit / 65781.76;/*  65781.76 or 65536.0*/
2983        } else {
2984                /*  post magnification */
2985                scanner->unit *= scanner->pre_unit / 65781.76;
2986        }
2987        scanner->unit *= scanner->pre_magnification / 1000.0;
2988        if (scanner->x_offset > 6e23) {
2989                /*  no post offset */
2990                scanner->x_offset = scanner->pre_x_offset * (scanner->pre_unit / 65781.76);
2991                scanner->y_offset = scanner->pre_y_offset * (scanner->pre_unit / 65781.76);
2992        } else {
2993                /*  post offset */
2994                scanner->x_offset /= 65781.76f;
2995                scanner->y_offset /= 65781.76f;
2996        }
2997        return scanner;
2998        #undef SYNCTEX_FILE
2999}
3000
3001/*  Scanner accessors.
3002 */
3003int synctex_scanner_pre_x_offset(synctex_scanner_t scanner){
3004        return scanner?scanner->pre_x_offset:0;
3005}
3006int synctex_scanner_pre_y_offset(synctex_scanner_t scanner){
3007        return scanner?scanner->pre_y_offset:0;
3008}
3009int synctex_scanner_x_offset(synctex_scanner_t scanner){
3010        return scanner?scanner->x_offset:0;
3011}
3012int synctex_scanner_y_offset(synctex_scanner_t scanner){
3013        return scanner?scanner->y_offset:0;
3014}
3015float synctex_scanner_magnification(synctex_scanner_t scanner){
3016        return scanner?scanner->unit:1;
3017}
3018void synctex_scanner_display(synctex_scanner_t scanner) {
3019        if (NULL == scanner) {
3020                return;
3021        }
3022        printf("The scanner:\noutput:%s\noutput_fmt:%s\nversion:%i\n",scanner->output,scanner->output_fmt,scanner->version);
3023        printf("pre_unit:%i\nx_offset:%i\ny_offset:%i\n",scanner->pre_unit,scanner->pre_x_offset,scanner->pre_y_offset);
3024        printf("count:%i\npost_magnification:%f\npost_x_offset:%f\npost_y_offset:%f\n",
3025                scanner->count,scanner->unit,scanner->x_offset,scanner->y_offset);
3026        printf("The input:\n");
3027        SYNCTEX_DISPLAY(scanner->input);
3028        if (scanner->count<1000) {
3029                printf("The sheets:\n");
3030                SYNCTEX_DISPLAY(scanner->sheet);
3031                printf("The friends:\n");
3032                if (scanner->lists_of_friends) {
3033                        int i = scanner->number_of_lists;
3034                        synctex_node_t node;
3035                        while(i--) {
3036                                printf("Friend index:%i\n",i);
3037                                node = (scanner->lists_of_friends)[i];
3038                                while(node) {
3039                                        printf("%s:%i,%i\n",
3040                                                synctex_node_isa(node),
3041                                                SYNCTEX_TAG(node),
3042                                                SYNCTEX_LINE(node)
3043                                        );
3044                                        node = SYNCTEX_FRIEND(node);
3045                                }
3046                        }
3047                }
3048        } else {
3049                printf("SyncTeX Warning: Too many objects\n");
3050        }
3051}
3052/*  Public*/
3053const char * synctex_scanner_get_name(synctex_scanner_t scanner,int tag) {
3054        synctex_node_t input = NULL;
3055        if (NULL == scanner) {
3056                return NULL;
3057        }
3058        input = scanner->input;
3059        do {
3060                if (tag == SYNCTEX_TAG(input)) {
3061                        return (SYNCTEX_NAME(input));
3062                }
3063        } while((input = SYNCTEX_SIBLING(input)) != NULL);
3064        return NULL;
3065}
3066
3067int _synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name);
3068int _synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name) {
3069        synctex_node_t input = NULL;
3070        if (NULL == scanner) {
3071                return 0;
3072        }
3073        input = scanner->input;
3074        do {
3075                if (_synctex_is_equivalent_file_name(name,(SYNCTEX_NAME(input)))) {
3076                        return SYNCTEX_TAG(input);
3077                }
3078        } while((input = SYNCTEX_SIBLING(input)) != NULL);
3079    //  2011 version
3080    name = _synctex_base_name(name);
3081        input = scanner->input;
3082        do {
3083                if (_synctex_is_equivalent_file_name(name,_synctex_base_name(SYNCTEX_NAME(input)))) {
3084            synctex_node_t other_input = input;
3085            while((other_input = SYNCTEX_SIBLING(other_input)) != NULL) {
3086                if (_synctex_is_equivalent_file_name(name,_synctex_base_name(SYNCTEX_NAME(other_input)))
3087                    && (strlen(SYNCTEX_NAME(input))!=strlen(SYNCTEX_NAME(other_input))
3088                        || strncmp(SYNCTEX_NAME(other_input),SYNCTEX_NAME(input),strlen(SYNCTEX_NAME(input))))) {
3089                    // There is a second possible candidate
3090                    return 0;
3091                }
3092            }
3093                        return SYNCTEX_TAG(input);
3094                }
3095        } while((input = SYNCTEX_SIBLING(input)) != NULL);
3096        return 0;
3097}
3098
3099int synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name) {
3100        size_t char_index = strlen(name);
3101        if ((scanner = synctex_scanner_parse(scanner)) && (0 < char_index)) {
3102                /*  the name is not void */
3103                char_index -= 1;
3104                if (!SYNCTEX_IS_PATH_SEPARATOR(name[char_index])) {
3105                        /*  the last character of name is not a path separator */
3106                        int result = _synctex_scanner_get_tag(scanner,name);
3107                        if (result) {
3108                                return result;
3109                        } else {
3110                                /*  the given name was not the one known by TeX
3111                                 *  try a name relative to the enclosing directory of the scanner->output file */
3112                                const char * relative = name;
3113                                const char * ptr = scanner->output;
3114                                while((strlen(relative) > 0) && (strlen(ptr) > 0) && (*relative == *ptr))
3115                                {
3116                                        relative += 1;
3117                                        ptr += 1;
3118                                }
3119                                /*  Find the last path separator before relative */
3120                                while(relative > name) {
3121                                        if (SYNCTEX_IS_PATH_SEPARATOR(*(relative-1))) {
3122                                                break;
3123                                        }
3124                                        relative -= 1;
3125                                }
3126                                if ((relative > name) && (result = _synctex_scanner_get_tag(scanner,relative))) {
3127                                        return result;
3128                                }
3129                                if (SYNCTEX_IS_PATH_SEPARATOR(name[0])) {
3130                                        /*  No tag found for the given absolute name,
3131                                         *  Try each relative path starting from the shortest one */
3132                                        while(0<char_index) {
3133                                                char_index -= 1;
3134                                                if (SYNCTEX_IS_PATH_SEPARATOR(name[char_index])
3135                                                                && (result = _synctex_scanner_get_tag(scanner,name+char_index+1))) {
3136                                                        return result;
3137                                                }
3138                                        }
3139                                }
3140                        }
3141                        return result;
3142                }
3143        }
3144        return 0;
3145}
3146synctex_node_t synctex_scanner_input(synctex_scanner_t scanner) {
3147        return scanner?scanner->input:NULL;
3148}
3149const char * synctex_scanner_get_output_fmt(synctex_scanner_t scanner) {
3150        return NULL != scanner && scanner->output_fmt?scanner->output_fmt:"";
3151}
3152const char * synctex_scanner_get_output(synctex_scanner_t scanner) {
3153        return NULL != scanner && scanner->output?scanner->output:"";
3154}
3155const char * synctex_scanner_get_synctex(synctex_scanner_t scanner) {
3156        return NULL != scanner && scanner->synctex?scanner->synctex:"";
3157}
3158#       ifdef SYNCTEX_NOTHING
3159#       pragma mark -
3160#       pragma mark Public node attributes
3161#   endif
3162int synctex_node_h(synctex_node_t node){
3163        if (!node) {
3164                return 0;
3165        }
3166        return SYNCTEX_HORIZ(node);
3167}
3168int synctex_node_v(synctex_node_t node){
3169        if (!node) {
3170                return 0;
3171        }
3172        return SYNCTEX_VERT(node);
3173}
3174int synctex_node_width(synctex_node_t node){
3175        if (!node) {
3176                return 0;
3177        }
3178        return SYNCTEX_WIDTH(node);
3179}
3180int synctex_node_box_h(synctex_node_t node){
3181        if (!node) {
3182                return 0;
3183        }
3184        if (SYNCTEX_IS_BOX(node)) {
3185result:
3186                return SYNCTEX_HORIZ(node);
3187        }
3188        if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3189                goto result;
3190        }
3191        return 0;
3192}
3193int synctex_node_box_v(synctex_node_t node){
3194        if (!node) {
3195                return 0;
3196        }
3197        if (SYNCTEX_IS_BOX(node)) {
3198result:
3199                return SYNCTEX_VERT(node);
3200        }
3201        if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3202                goto result;
3203        }
3204        return 0;
3205}
3206int synctex_node_box_width(synctex_node_t node){
3207        if (!node) {
3208                return 0;
3209        }
3210        if (SYNCTEX_IS_BOX(node)) {
3211result:
3212                return SYNCTEX_WIDTH(node);
3213        }
3214        if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3215                goto result;
3216        }
3217        return 0;
3218}
3219int synctex_node_box_height(synctex_node_t node){
3220        if (!node) {
3221                return 0;
3222        }
3223        if (SYNCTEX_IS_BOX(node)) {
3224result:
3225                return SYNCTEX_HEIGHT(node);
3226        }
3227        if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3228                goto result;
3229        }
3230        return 0;
3231}
3232int synctex_node_box_depth(synctex_node_t node){
3233        if (!node) {
3234                return 0;
3235        }
3236        if (SYNCTEX_IS_BOX(node)) {
3237result:
3238                return SYNCTEX_DEPTH(node);
3239        }
3240        if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3241                goto result;
3242        }
3243        return 0;
3244}
3245#       ifdef SYNCTEX_NOTHING
3246#       pragma mark -
3247#       pragma mark Public node visible attributes
3248#   endif
3249float synctex_node_visible_h(synctex_node_t node){
3250        if (!node) {
3251                return 0;
3252        }
3253        return SYNCTEX_HORIZ(node)*node->class->scanner->unit+node->class->scanner->x_offset;
3254}
3255float synctex_node_visible_v(synctex_node_t node){
3256        if (!node) {
3257                return 0;
3258        }
3259        return SYNCTEX_VERT(node)*node->class->scanner->unit+node->class->scanner->y_offset;
3260}
3261float synctex_node_visible_width(synctex_node_t node){
3262        if (!node) {
3263                return 0;
3264        }
3265        return SYNCTEX_WIDTH(node)*node->class->scanner->unit;
3266}
3267float synctex_node_box_visible_h(synctex_node_t node){
3268        if (!node) {
3269                return 0;
3270        }
3271        switch(node->class->type) {
3272                case synctex_node_type_vbox:
3273                case synctex_node_type_void_vbox:
3274                case synctex_node_type_void_hbox:
3275                        return SYNCTEX_HORIZ(node)*node->class->scanner->unit+node->class->scanner->x_offset;
3276                case synctex_node_type_hbox:
3277result:
3278                        return SYNCTEX_HORIZ_V(node)*node->class->scanner->unit+node->class->scanner->x_offset;
3279        }
3280        if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3281                goto result;
3282        }
3283        return 0;
3284}
3285float synctex_node_box_visible_v(synctex_node_t node){
3286        if (!node) {
3287                return 0;
3288        }
3289        switch(node->class->type) {
3290                case synctex_node_type_vbox:
3291                case synctex_node_type_void_vbox:
3292                case synctex_node_type_void_hbox:
3293                        return SYNCTEX_VERT(node)*node->class->scanner->unit+node->class->scanner->y_offset;
3294                case synctex_node_type_hbox:
3295result:
3296                        return SYNCTEX_VERT_V(node)*node->class->scanner->unit+node->class->scanner->y_offset;
3297        }
3298        if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3299                goto result;
3300        }
3301        return 0;
3302}
3303float synctex_node_box_visible_width(synctex_node_t node){
3304        if (!node) {
3305                return 0;
3306        }
3307        switch(node->class->type) {
3308                case synctex_node_type_vbox:
3309                case synctex_node_type_void_vbox:
3310                case synctex_node_type_void_hbox:
3311                        return SYNCTEX_WIDTH(node)*node->class->scanner->unit;
3312                case synctex_node_type_hbox:
3313result:
3314                        return SYNCTEX_WIDTH_V(node)*node->class->scanner->unit;
3315        }
3316        if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3317                goto result;
3318        }
3319        return 0;
3320}
3321float synctex_node_box_visible_height(synctex_node_t node){
3322        if (!node) {
3323                return 0;
3324        }
3325        switch(node->class->type) {
3326                case synctex_node_type_vbox:
3327                case synctex_node_type_void_vbox:
3328                case synctex_node_type_void_hbox:
3329                        return SYNCTEX_HEIGHT(node)*node->class->scanner->unit;
3330                case synctex_node_type_hbox:
3331result:
3332                        return SYNCTEX_HEIGHT_V(node)*node->class->scanner->unit;
3333        }
3334        if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3335                goto result;
3336        }
3337        return 0;
3338}
3339float synctex_node_box_visible_depth(synctex_node_t node){
3340        if (!node) {
3341                return 0;
3342        }
3343        switch(node->class->type) {
3344                case synctex_node_type_vbox:
3345                case synctex_node_type_void_vbox:
3346                case synctex_node_type_void_hbox:
3347                        return SYNCTEX_DEPTH(node)*node->class->scanner->unit;
3348                case synctex_node_type_hbox:
3349result:
3350                        return SYNCTEX_DEPTH_V(node)*node->class->scanner->unit;
3351        }
3352        if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3353                goto result;
3354        }
3355        return 0;
3356}
3357#       ifdef SYNCTEX_NOTHING
3358#       pragma mark -
3359#       pragma mark Other public node attributes
3360#   endif
3361
3362int synctex_node_page(synctex_node_t node){
3363        synctex_node_t parent = NULL;
3364        if (!node) {
3365                return -1;
3366        }
3367        parent = SYNCTEX_PARENT(node);
3368        while(parent) {
3369                node = parent;
3370                parent = SYNCTEX_PARENT(node);
3371        }
3372        if (node->class->type == synctex_node_type_sheet) {
3373                return SYNCTEX_PAGE(node);
3374        }
3375        return -1;
3376}
3377synctex_charindex_t synctex_node_charindex(synctex_node_t node) {
3378        return node?SYNCTEX_CHARINDEX(node):0;
3379}
3380int synctex_node_tag(synctex_node_t node) {
3381        return node?SYNCTEX_TAG(node):-1;
3382}
3383int synctex_node_line(synctex_node_t node) {
3384        return node?SYNCTEX_LINE(node):-1;
3385}
3386int synctex_node_mean_line(synctex_node_t node) {
3387        return node?(node->class->type==synctex_node_type_hbox?SYNCTEX_MEAN_LINE(node):SYNCTEX_LINE(node)):-1;
3388}
3389int synctex_node_child_count(synctex_node_t node) {
3390        return node?(node->class->type==synctex_node_type_hbox?SYNCTEX_NODE_WEIGHT(node):0):-1;
3391}
3392int synctex_node_column(synctex_node_t node) {
3393#       ifdef __DARWIN_UNIX03
3394#       pragma unused(node)
3395#   endif
3396        return -1;
3397}
3398#       ifdef SYNCTEX_NOTHING
3399#       pragma mark -
3400#       pragma mark Sheet
3401#   endif
3402
3403synctex_node_t synctex_sheet(synctex_scanner_t scanner,int page) {
3404        if (scanner) {
3405                synctex_node_t sheet = scanner->sheet;
3406                while(sheet) {
3407                        if (page == SYNCTEX_PAGE(sheet)) {
3408                                return sheet;
3409                        }
3410                        sheet = SYNCTEX_SIBLING(sheet);
3411                }
3412        }
3413        return NULL;
3414}
3415
3416synctex_node_t synctex_sheet_content(synctex_scanner_t scanner,int page) {
3417        if (scanner) {
3418                return SYNCTEX_CHILD(synctex_sheet(scanner,page));
3419        }
3420        return NULL;
3421}
3422
3423#       ifdef SYNCTEX_NOTHING
3424#       pragma mark -
3425#       pragma mark Query
3426#   endif
3427
3428synctex_status_t synctex_display_query(synctex_scanner_t scanner,const char * name,int line,int column) {
3429#       ifdef __DARWIN_UNIX03
3430#       pragma unused(column)
3431#   endif
3432        int tag = synctex_scanner_get_tag(scanner,name);
3433        size_t size = 0;
3434        int friend_index = 0;
3435        int max_line = 0;
3436        synctex_node_t node = NULL;
3437        if (tag == 0) {
3438                printf("SyncTeX Warning: No tag for %s\n",name);
3439                return -1;
3440        }
3441        free(SYNCTEX_START);
3442        SYNCTEX_CUR = SYNCTEX_END = SYNCTEX_START = NULL;
3443        max_line = line < INT_MAX-scanner->number_of_lists ? line+scanner->number_of_lists:INT_MAX;
3444        while(line<max_line) {
3445                /*  This loop will only be performed once for advanced viewers */
3446                friend_index = (tag+line)%(scanner->number_of_lists);
3447                if ((node = (scanner->lists_of_friends)[friend_index])) {
3448                        do {
3449                                if ((synctex_node_type(node)>=synctex_node_type_boundary)
3450                                        && (tag == SYNCTEX_TAG(node))
3451                                                && (line == SYNCTEX_LINE(node))) {
3452                                        if (SYNCTEX_CUR == SYNCTEX_END) {
3453                                                size += 16;
3454                                                SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *));
3455                                                SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START;
3456                                                SYNCTEX_START = SYNCTEX_END;
3457                                                SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *);
3458                                        }                       
3459                                        *(synctex_node_t *)SYNCTEX_CUR = node;
3460                                        SYNCTEX_CUR += sizeof(synctex_node_t);
3461                                }
3462                        } while ((node = SYNCTEX_FRIEND(node)));
3463                        if (SYNCTEX_START == NULL) {
3464                                /*  We did not find any matching boundary, retry with glue or kern */
3465                                node = (scanner->lists_of_friends)[friend_index];/*  no need to test it again, already done */
3466                                do {
3467                                        if ((synctex_node_type(node)>=synctex_node_type_kern)
3468                                                && (tag == SYNCTEX_TAG(node))
3469                                                        && (line == SYNCTEX_LINE(node))) {
3470                                                if (SYNCTEX_CUR == SYNCTEX_END) {
3471                                                        size += 16;
3472                                                        SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *));
3473                                                        SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START;
3474                                                        SYNCTEX_START = SYNCTEX_END;
3475                                                        SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *);
3476                                                }                       
3477                                                *(synctex_node_t *)SYNCTEX_CUR = node;
3478                                                SYNCTEX_CUR += sizeof(synctex_node_t);
3479                                        }
3480                                } while ((node = SYNCTEX_FRIEND(node)));
3481                                if (SYNCTEX_START == NULL) {
3482                                        /*  We did not find any matching glue or kern, retry with boxes */
3483                                        node = (scanner->lists_of_friends)[friend_index];/*  no need to test it again, already done */
3484                                        do {
3485                                                if ((tag == SYNCTEX_TAG(node))
3486                                                                && (line == SYNCTEX_LINE(node))) {
3487                                                        if (SYNCTEX_CUR == SYNCTEX_END) {
3488                                                                size += 16;
3489                                                                SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *));
3490                                                                SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START;
3491                                                                SYNCTEX_START = SYNCTEX_END;
3492                                                                SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *);
3493                                                        }                       
3494                                                        *(synctex_node_t *)SYNCTEX_CUR = node;
3495                                                        SYNCTEX_CUR += sizeof(synctex_node_t);
3496                                                }
3497                                        } while((node = SYNCTEX_FRIEND(node)));
3498                                }
3499                        }
3500                        SYNCTEX_END = SYNCTEX_CUR;
3501                        /*  Now reverse the order to have nodes in display order, and then keep just a few nodes.
3502             *  Order first the best node. */
3503                        if ((SYNCTEX_START) && (SYNCTEX_END)) {
3504                unsigned int best_match = -1;
3505                unsigned int next_match = -1;
3506                unsigned int best_weight = 0;
3507                synctex_node_t * best_ref   = NULL;
3508                                synctex_node_t * start_ref = (synctex_node_t *)SYNCTEX_START;
3509                                synctex_node_t * end_ref   = (synctex_node_t *)SYNCTEX_END;
3510                                --end_ref;
3511                                while (start_ref < end_ref) {
3512                                        node = *start_ref;
3513                                        *start_ref = *end_ref;
3514                                        *end_ref = node;
3515                                        ++start_ref;
3516                                        --end_ref;
3517                                }
3518                /*  Now reorder the nodes to put first the one which fits best.
3519                 *  The idea is to walk along the list of nodes and pick up the first one
3520                 *  which line info is exactly the mean line of its parent, or at least very close.
3521                 *  Then we choose among all such node the one with the maximum number of child nodes.
3522                 *  Then we switch with the first node.
3523                 */
3524                best_ref = start_ref = (synctex_node_t *)SYNCTEX_START;
3525                node = *start_ref;
3526                best_match = abs(SYNCTEX_LINE(node)-SYNCTEX_MEAN_LINE(SYNCTEX_PARENT(node)));
3527                end_ref = (synctex_node_t *)SYNCTEX_END;
3528                                while (++start_ref<end_ref) {
3529                    synctex_node_t parent = NULL;
3530                                        node = *start_ref;
3531                    parent = SYNCTEX_PARENT(node);
3532                    next_match = abs(SYNCTEX_LINE(node)-SYNCTEX_MEAN_LINE(parent));
3533                    if (next_match < best_match
3534                            || (next_match == best_match && SYNCTEX_NODE_WEIGHT(parent)>best_weight)) {
3535                        best_match = next_match;
3536                        best_ref = start_ref;
3537                        best_weight = SYNCTEX_NODE_WEIGHT(parent);
3538                    }
3539                                }
3540                node = *best_ref;
3541                *best_ref = *(synctex_node_t *)SYNCTEX_START;
3542                *(synctex_node_t *)SYNCTEX_START = node;
3543                                /*  Basically, we keep the first node for each parent.
3544                                 *  More precisely, we keep only nodes that are not children of
3545                                 *  their predecessor's parent. */
3546                                start_ref = (synctex_node_t *)SYNCTEX_START;
3547                                end_ref   = (synctex_node_t *)SYNCTEX_START;
3548next_end:
3549                                end_ref += 1; /*  we allways have start_ref<= end_ref*/
3550                                if (end_ref < (synctex_node_t *)SYNCTEX_END) {
3551                                        node = *end_ref;
3552                                        while ((node = SYNCTEX_PARENT(node))) {
3553                                                if (SYNCTEX_PARENT(*start_ref) == node) {
3554                                                        goto next_end;
3555                                                }
3556                                        }
3557                                        start_ref += 1;
3558                                        *start_ref = *end_ref;
3559                                        goto next_end;
3560                                }
3561                                start_ref += 1;
3562                SYNCTEX_END = (char *)start_ref;
3563                SYNCTEX_CUR = NULL;// added on behalf of Jose Alliste
3564                                return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t);// added on behalf Jan Sundermeyer
3565            }
3566                        SYNCTEX_CUR = NULL;
3567                        // return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t); removed on behalf Jan Sundermeyer
3568                }
3569#       if defined(__SYNCTEX_STRONG_DISPLAY_QUERY__)
3570                break;
3571#       else
3572                ++line;
3573#       endif
3574        }
3575        return 0;
3576}
3577
3578synctex_node_t synctex_next_result(synctex_scanner_t scanner) {
3579        if (NULL == SYNCTEX_CUR) {
3580                SYNCTEX_CUR = SYNCTEX_START;
3581        } else {
3582                SYNCTEX_CUR+=sizeof(synctex_node_t);
3583        }
3584        if (SYNCTEX_CUR<SYNCTEX_END) {
3585                return *(synctex_node_t*)SYNCTEX_CUR;
3586        } else {
3587                return NULL;
3588        }
3589}
3590
3591/*  This struct records a point in TeX coordinates.*/
3592typedef struct {
3593        int h;
3594        int v;
3595} synctex_point_t;
3596
3597/*  This struct records distances, the left one is positive or 0 and the right one is negative or 0.
3598 *  When comparing the locations of 2 different graphical objects on the page, we will have to also record the
3599 *  horizontal distance as signed to keep track of the typesetting order.*/
3600typedef struct {
3601        int left;
3602        int right;
3603} synctex_distances_t;
3604
3605typedef struct {
3606        synctex_point_t left;
3607        synctex_point_t right;
3608} synctex_offsets_t;
3609
3610
3611typedef struct {
3612        synctex_node_t left;
3613        synctex_node_t right;
3614} synctex_node_set_t;
3615
3616/*  The smallest container between two has the smallest width or height.
3617 *  This comparison is used when there are 2 overlapping boxes that contain the hit point.
3618 *  For ConTeXt, the problem appears at each page.
3619 *  The chosen box is the one with the smallest height, then the smallest width. */
3620SYNCTEX_INLINE static synctex_node_t _synctex_smallest_container(synctex_node_t node, synctex_node_t other_node);
3621
3622/*  Returns the distance between the hit point hitPoint=(H,V) and the given node. */
3623synctex_bool_t _synctex_point_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible);
3624int _synctex_node_distance_to_point(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible);
3625
3626/*  The best container is the deeper box that contains the hit point (H,V).
3627 *  _synctex_eq_deepest_container starts with node whereas
3628 *  _synctex_box_child_deepest starts with node's children, if any
3629 *  if node is not a box, or a void box, NULL is returned.
3630 *  We traverse the node tree in a deep first manner and stop as soon as a result is found. */
3631static synctex_node_t _synctex_eq_deepest_container(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible);
3632
3633/*  Once a best container is found, the closest children are the closest nodes to the left or right of the hit point.
3634 *  Only horizontal and vertical offsets are used to compare the positions of the nodes. */
3635SYNCTEX_INLINE static int _synctex_eq_get_closest_children_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t*  bestNodesRef,synctex_distances_t*  bestDistancesRef, synctex_bool_t visible);
3636
3637/*  The closest container is the box that is the one closest to the given point.
3638 *  The "visible" version takes into account the visible dimensions instead of the real ones given by TeX. */
3639SYNCTEX_INLINE static synctex_node_t _synctex_eq_closest_child(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible);
3640
3641#define SYNCTEX_MASK_LEFT 1
3642#define SYNCTEX_MASK_RIGHT 2
3643
3644synctex_status_t synctex_edit_query(synctex_scanner_t scanner,int page,float h,float v) {
3645        synctex_node_t sheet = NULL;
3646        synctex_node_t node = NULL; /*  placeholder */
3647        synctex_node_t other_node = NULL; /*  placeholder */
3648        synctex_point_t hitPoint = {0,0}; /*  placeholder */
3649        synctex_node_set_t bestNodes = {NULL,NULL}; /*  holds the best node */
3650        synctex_distances_t bestDistances = {INT_MAX,INT_MAX}; /*  holds the best distances for the best node */
3651        synctex_node_t bestContainer = NULL; /*  placeholder */
3652        if (NULL == (scanner = synctex_scanner_parse(scanner)) || 0 >= scanner->unit) {/*  scanner->unit must be >0 */
3653                return 0;
3654        }
3655        /*  Convert the given point to scanner integer coordinates */
3656        hitPoint.h = (h-scanner->x_offset)/scanner->unit;
3657        hitPoint.v = (v-scanner->y_offset)/scanner->unit;
3658        /*  We will store in the scanner's buffer the result of the query. */
3659        free(SYNCTEX_START);
3660        SYNCTEX_START = SYNCTEX_END = SYNCTEX_CUR = NULL;
3661        /*  Find the proper sheet */
3662        sheet = scanner->sheet;
3663        while((sheet) && SYNCTEX_PAGE(sheet) != page) {
3664                sheet = SYNCTEX_SIBLING(sheet);
3665        }
3666        if (NULL == sheet) {
3667                return -1;
3668        }
3669        /*  Now sheet points to the sheet node with proper page number */
3670        /*  Here is how we work:
3671         *  At first we do not consider the visible box dimensions. This will cover the most frequent cases.
3672         *  Then we try with the visible box dimensions.
3673         *  We try to find a non void box containing the hit point.
3674         *  We browse all the horizontal boxes until we find one containing the hit point. */
3675        if ((node = SYNCTEX_NEXT_hbox(sheet))) {
3676                do {
3677                        if (_synctex_point_in_box(hitPoint,node,synctex_YES)) {
3678                                /*  Maybe the hitPoint belongs to a contained vertical box. */
3679end:
3680                                /*  This trick is for catching overlapping boxes */
3681                                if ((other_node = SYNCTEX_NEXT_hbox(node))) {
3682                                        do {
3683                                                if (_synctex_point_in_box(hitPoint,other_node,synctex_YES)) {
3684                                                        node = _synctex_smallest_container(other_node,node); 
3685                                                }
3686                                        } while((other_node = SYNCTEX_NEXT_hbox(other_node)));
3687                                }
3688                /*  node is the smallest horizontal box that contains hitPoint. */
3689                                if ((bestContainer = _synctex_eq_deepest_container(hitPoint,node,synctex_YES))) {
3690                                        node = bestContainer;
3691                                }
3692                                _synctex_eq_get_closest_children_in_box(hitPoint,node,&bestNodes,&bestDistances,synctex_YES);
3693                                if (bestNodes.right && bestNodes.left) {
3694                                        if ((SYNCTEX_TAG(bestNodes.right)!=SYNCTEX_TAG(bestNodes.left))
3695                                                        || (SYNCTEX_LINE(bestNodes.right)!=SYNCTEX_LINE(bestNodes.left))
3696                                                                || (SYNCTEX_COLUMN(bestNodes.right)!=SYNCTEX_COLUMN(bestNodes.left))) {
3697                                                if ((SYNCTEX_START = malloc(2*sizeof(synctex_node_t)))) {
3698                                                        if (bestDistances.left>bestDistances.right) {
3699                                                                ((synctex_node_t *)SYNCTEX_START)[0] = bestNodes.right;
3700                                                                ((synctex_node_t *)SYNCTEX_START)[1] = bestNodes.left;
3701                                                        } else {
3702                                                                ((synctex_node_t *)SYNCTEX_START)[0] = bestNodes.left;
3703                                                                ((synctex_node_t *)SYNCTEX_START)[1] = bestNodes.right;
3704                                                        }
3705                                                        SYNCTEX_END = SYNCTEX_START + 2*sizeof(synctex_node_t);
3706                                                        SYNCTEX_CUR = NULL;
3707                                                        return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t);
3708                                                }
3709                                                return SYNCTEX_STATUS_ERROR;
3710                                        }
3711                                        /*  both nodes have the same input coordinates
3712                                         *  We choose the one closest to the hit point  */
3713                                        if (bestDistances.left>bestDistances.right) {
3714                                                bestNodes.left = bestNodes.right;
3715                                        }
3716                                        bestNodes.right = NULL;
3717                                } else if (bestNodes.right) {
3718                                        bestNodes.left = bestNodes.right;
3719                                } else if (!bestNodes.left){
3720                                        bestNodes.left = node;
3721                                }
3722                                if ((SYNCTEX_START = malloc(sizeof(synctex_node_t)))) {
3723                                        * (synctex_node_t *)SYNCTEX_START = bestNodes.left;
3724                                        SYNCTEX_END = SYNCTEX_START + sizeof(synctex_node_t);
3725                                        SYNCTEX_CUR = NULL;
3726                                        return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t);
3727                                }
3728                                return SYNCTEX_STATUS_ERROR;
3729                        }
3730                } while ((node = SYNCTEX_NEXT_hbox(node)));
3731                /*  All the horizontal boxes have been tested,
3732                 *  None of them contains the hit point.
3733                 */
3734        }
3735        /*  We are not lucky */
3736        if ((node = SYNCTEX_CHILD(sheet))) {
3737                goto end;
3738        }
3739        return 0;
3740}
3741
3742#       ifdef SYNCTEX_NOTHING
3743#       pragma mark -
3744#       pragma mark Utilities
3745#   endif
3746
3747/*  Rougly speaking, this is:
3748 *  node's h coordinate - hitPoint's h coordinate.
3749 *  If node is to the right of the hit point, then this distance is positive,
3750 *  if node is to the left of the hit point, this distance is negative.*/
3751int _synctex_point_h_distance(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible);
3752int _synctex_point_h_distance(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) {
3753        if (node) {
3754                int min,med,max;
3755                switch(node->class->type) {
3756                        /*  The distance between a point and a box is special.
3757                         *  It is not the euclidian distance, nor something similar.
3758                         *  We have to take into account the particular layout,
3759                         *  and the box hierarchy.
3760                         *  Given a box, there are 9 regions delimited by the lines of the edges of the box.
3761                         *  The origin being at the top left corner of the page,
3762                         *  we also give names to the vertices of the box.
3763                         *
3764                         *   1 | 2 | 3
3765                         *  ---A---B--->
3766                         *   4 | 5 | 6
3767                         *  ---C---D--->
3768                         *   7 | 8 | 9
3769                         *     v   v
3770                         */
3771                        case synctex_node_type_hbox:
3772                                /*  getting the box bounds, taking into account negative width, height and depth. */
3773                                min = visible?SYNCTEX_HORIZ_V(node):SYNCTEX_HORIZ(node);
3774                                max = min + (visible?SYNCTEX_ABS_WIDTH_V(node):SYNCTEX_ABS_WIDTH(node));
3775                                /*  We allways have min <= max */
3776                                if (hitPoint.h<min) {
3777                                        return min - hitPoint.h; /*  regions 1+4+7, result is > 0 */
3778                                } else if (hitPoint.h>max) {
3779                                        return max - hitPoint.h; /*  regions 3+6+9, result is < 0 */
3780                                } else {
3781                                        return 0; /*  regions 2+5+8, inside the box, except for vertical coordinates */
3782                                }
3783                                break;
3784                        case synctex_node_type_vbox:
3785                        case synctex_node_type_void_vbox:
3786                        case synctex_node_type_void_hbox:
3787                                /*  getting the box bounds, taking into account negative width, height and depth.
3788                                 *  For these boxes, no visible dimension available */
3789                                min = SYNCTEX_HORIZ(node);
3790                                max = min + SYNCTEX_ABS_WIDTH(node);
3791                                /*  We allways have min <= max */
3792                                if (hitPoint.h<min) {
3793                                        return min - hitPoint.h; /*  regions 1+4+7, result is > 0 */
3794                                } else if (hitPoint.h>max) {
3795                                        return max - hitPoint.h; /*  regions 3+6+9, result is < 0 */
3796                                } else {
3797                                        return 0; /*  regions 2+5+8, inside the box, except for vertical coordinates */
3798                                }
3799                                break;
3800                        case synctex_node_type_kern:
3801                                /*  IMPORTANT NOTICE: the location of the kern is recorded AFTER the move.
3802                                 *  The distance to the kern is very special,
3803                                 *  in general, there is no text material in the kern,
3804                                 *  this is why we compute the offset relative to the closest edge of the kern.*/
3805                                max = SYNCTEX_WIDTH(node);
3806                                if (max<0) {
3807                                        min = SYNCTEX_HORIZ(node);
3808                                        max = min - max;
3809                                } else {
3810                                        min = -max;
3811                                        max = SYNCTEX_HORIZ(node);
3812                                        min += max;
3813                                }
3814                                med = (min+max)/2;
3815                                /*  positive kern: '.' means text, '>' means kern offset
3816                                 *      .............
3817                                 *                   min>>>>med>>>>max
3818                                 *                                    ...............
3819                                 *  negative kern: '.' means text, '<' means kern offset
3820                                 *      ............................
3821                                 *                 min<<<<med<<<<max
3822                                 *                 .................................
3823                                 *  Actually, we do not take into account negative widths.
3824                                 *  There is a problem for such situation when there is efectively overlapping text.
3825                                 *  But this should be extremely rare. I guess that in that case, many different choices
3826                                 *  could be made, one being in contradiction of the other.
3827                                 *  It means that the best choice should be made according to the situation that occurs
3828                                 *  most frequently.
3829                                 */
3830                                if (hitPoint.h<min) {
3831                                        return min - hitPoint.h + 1; /*  penalty to ensure other nodes are chosen first in case of overlapping ones */
3832                                } else if (hitPoint.h>max) {
3833                                        return max - hitPoint.h - 1; /*  same kind of penalty */
3834                                } else if (hitPoint.h>med) {
3835                                        /*  do things like if the node had 0 width and was placed at the max edge + 1*/
3836                                        return max - hitPoint.h + 1; /*  positive, the kern is to the right of the hitPoint */
3837                                } else {
3838                                        return min - hitPoint.h - 1; /*  negative, the kern is to the left of the hitPoint */
3839                                }
3840                        case synctex_node_type_glue:
3841                        case synctex_node_type_math:
3842                                return SYNCTEX_HORIZ(node) - hitPoint.h;
3843                }
3844        }
3845        return INT_MAX;/*  We always assume that the node is faraway to the right*/
3846}
3847/*  Rougly speaking, this is:
3848 *  node's v coordinate - hitPoint's v coordinate.
3849 *  If node is at the top of the hit point, then this distance is positive,
3850 *  if node is at the bottom of the hit point, this distance is negative.*/
3851int _synctex_point_v_distance(synctex_point_t hitPoint, synctex_node_t node,synctex_bool_t visible);
3852int _synctex_point_v_distance(synctex_point_t hitPoint, synctex_node_t node,synctex_bool_t visible) {
3853#       ifdef __DARWIN_UNIX03
3854#       pragma unused(visible)
3855#   endif
3856        if (node) {
3857                int min,max;
3858                switch(node->class->type) {
3859                        /*  The distance between a point and a box is special.
3860                         *  It is not the euclidian distance, nor something similar.
3861                         *  We have to take into account the particular layout,
3862                         *  and the box hierarchy.
3863                         *  Given a box, there are 9 regions delimited by the lines of the edges of the box.
3864                         *  The origin being at the top left corner of the page,
3865                         *  we also give names to the vertices of the box.
3866                         *
3867                         *   1 | 2 | 3
3868                         *  ---A---B--->
3869                         *   4 | 5 | 6
3870                         *  ---C---D--->
3871                         *   7 | 8 | 9
3872                         *     v   v
3873                         */
3874                        case synctex_node_type_hbox:
3875                                /*  getting the box bounds, taking into account negative width, height and depth. */
3876                                min = SYNCTEX_VERT_V(node);
3877                                max = min + SYNCTEX_ABS_DEPTH_V(node);
3878                                min -= SYNCTEX_ABS_HEIGHT_V(node);
3879                                /*  We allways have min <= max */
3880                                if (hitPoint.v<min) {
3881                                        return min - hitPoint.v; /*  regions 1+2+3, result is > 0 */
3882                                } else if (hitPoint.v>max) {
3883                                        return max - hitPoint.v; /*  regions 7+8+9, result is < 0 */
3884                                } else {
3885                                        return 0; /*  regions 4.5.6, inside the box, except for horizontal coordinates */
3886                                }
3887                                break;
3888                        case synctex_node_type_vbox:
3889                        case synctex_node_type_void_vbox:
3890                        case synctex_node_type_void_hbox:
3891                                /*  getting the box bounds, taking into account negative width, height and depth. */
3892                                min = SYNCTEX_VERT(node);
3893                                max = min + SYNCTEX_ABS_DEPTH(node);
3894                                min -= SYNCTEX_ABS_HEIGHT(node);
3895                                /*  We allways have min <= max */
3896                                if (hitPoint.v<min) {
3897                                        return min - hitPoint.v; /*  regions 1+2+3, result is > 0 */
3898                                } else if (hitPoint.v>max) {
3899                                        return max - hitPoint.v; /*  regions 7+8+9, result is < 0 */
3900                                } else {
3901                                        return 0; /*  regions 4.5.6, inside the box, except for horizontal coordinates */
3902                                }
3903                                break;
3904                        case synctex_node_type_kern:
3905                        case synctex_node_type_glue:
3906                        case synctex_node_type_math:
3907                                return SYNCTEX_VERT(node) - hitPoint.v;
3908                }
3909        }
3910        return INT_MAX;/*  We always assume that the node is faraway to the top*/
3911}
3912
3913SYNCTEX_INLINE static synctex_node_t _synctex_smallest_container(synctex_node_t node, synctex_node_t other_node) {
3914        float height, other_height;
3915        if (SYNCTEX_ABS_WIDTH(node)<SYNCTEX_ABS_WIDTH(other_node)) {
3916                return node;
3917        }
3918        if (SYNCTEX_ABS_WIDTH(node)>SYNCTEX_ABS_WIDTH(other_node)) {
3919                return other_node;
3920        }
3921        height = SYNCTEX_ABS_DEPTH(node) + SYNCTEX_ABS_HEIGHT(node);
3922        other_height = SYNCTEX_ABS_DEPTH(other_node) + SYNCTEX_ABS_HEIGHT(other_node);
3923        if (height<other_height) {
3924                return node;
3925        }
3926        if (height>other_height) {
3927                return other_node;
3928    }
3929    return node;
3930}
3931
3932synctex_bool_t _synctex_point_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) {
3933        if (node) {
3934                if (0 == _synctex_point_h_distance(hitPoint,node,visible)
3935                                && 0 == _synctex_point_v_distance(hitPoint,node,visible)) {
3936                        return synctex_YES;
3937                }
3938        }
3939        return synctex_NO;     
3940}
3941
3942int _synctex_node_distance_to_point(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) {
3943#       ifdef __DARWIN_UNIX03
3944#       pragma unused(visible)
3945#   endif
3946        int result = INT_MAX; /*  when the distance is meaning less (sheet, input...)  */
3947        if (node) {
3948                int minH,maxH,minV,maxV;
3949                switch(node->class->type) {
3950                        /*  The distance between a point and a box is special.
3951                         *  It is not the euclidian distance, nor something similar.
3952                         *  We have to take into account the particular layout,
3953                         *  and the box hierarchy.
3954                         *  Given a box, there are 9 regions delimited by the lines of the edges of the box.
3955                         *  The origin being at the top left corner of the page,
3956                         *  we also give names to the vertices of the box.
3957                         *
3958                         *   1 | 2 | 3
3959                         *  ---A---B--->
3960                         *   4 | 5 | 6
3961                         *  ---C---D--->
3962                         *   7 | 8 | 9
3963                         *     v   v
3964                         *  In each region, there is a different formula.
3965                         *  In the end we have a continuous distance which may not be a mathematical distance but who cares. */
3966                        case synctex_node_type_vbox:
3967                        case synctex_node_type_void_vbox:
3968                        case synctex_node_type_hbox:
3969                        case synctex_node_type_void_hbox:
3970                                /*  getting the box bounds, taking into account negative widths. */
3971                                minH = SYNCTEX_HORIZ(node);
3972                                maxH = minH + SYNCTEX_ABS_WIDTH(node);
3973                                minV = SYNCTEX_VERT(node);
3974                                maxV = minV + SYNCTEX_ABS_DEPTH(node);
3975                                minV -= SYNCTEX_ABS_HEIGHT(node);
3976                                /*  In what region is the point hitPoint=(H,V) ? */
3977                                if (hitPoint.v<minV) {
3978                                        if (hitPoint.h<minH) {
3979                                                /*  This is region 1. The distance to the box is the L1 distance PA. */
3980                                                result = minV - hitPoint.v + minH - hitPoint.h;/*  Integer overflow? probability epsilon */
3981                                        } else if (hitPoint.h<=maxH) {
3982                                                /*  This is region 2. The distance to the box is the geometrical distance to the top edge.  */
3983                                                result = minV - hitPoint.v;
3984                                        } else {
3985                                                /*  This is region 3. The distance to the box is the L1 distance PB. */
3986                                                result = minV - hitPoint.v + hitPoint.h - maxH;
3987                                        }
3988                                } else if (hitPoint.v<=maxV) {
3989                                        if (hitPoint.h<minH) {
3990                                                /*  This is region 4. The distance to the box is the geometrical distance to the left edge.  */
3991                                                result = minH - hitPoint.h;
3992                                        } else if (hitPoint.h<=maxH) {
3993                                                /*  This is region 4. We are inside the box.  */
3994                                                result = 0;
3995                                        } else {
3996                                                /*  This is region 6. The distance to the box is the geometrical distance to the right edge.  */
3997                                                result = hitPoint.h - maxH;
3998                                        }
3999                                } else {
4000                                        if (hitPoint.h<minH) {
4001                                                /*  This is region 7. The distance to the box is the L1 distance PC. */
4002                                                result = hitPoint.v - maxV + minH - hitPoint.h;
4003                                        } else if (hitPoint.h<=maxH) {
4004                                                /*  This is region 8. The distance to the box is the geometrical distance to the top edge.  */
4005                                                result = hitPoint.v - maxV;
4006                                        } else {
4007                                                /*  This is region 9. The distance to the box is the L1 distance PD. */
4008                                                result = hitPoint.v - maxV + hitPoint.h - maxH;
4009                                        }
4010                                }
4011                                break;
4012                        case synctex_node_type_kern:
4013                                maxH = SYNCTEX_WIDTH(node);
4014                                if (maxH<0) {
4015                                        minH = SYNCTEX_HORIZ(node);
4016                                        maxH = minH - maxH;
4017                                } else {
4018                                        minH = -maxH;
4019                                        maxH = SYNCTEX_HORIZ(node);
4020                                        minH += maxH;
4021                                }
4022                                minV = SYNCTEX_VERT(node);
4023                                if (hitPoint.h<minH) {
4024                                        if (hitPoint.v>minV) {
4025                                                result = hitPoint.v - minV + minH - hitPoint.h;
4026                                        } else {
4027                                                result = minV - hitPoint.v + minH - hitPoint.h;
4028                                        }
4029                                } else if (hitPoint.h>maxH) {
4030                                        if (hitPoint.v>minV) {
4031                                                result = hitPoint.v - minV + hitPoint.h - maxH;
4032                                        } else {
4033                                                result = minV - hitPoint.v + hitPoint.h - maxH;
4034                                        }
4035                                } else if (hitPoint.v>minV) {
4036                                        result = hitPoint.v - minV;
4037                                } else {
4038                                        result = minV - hitPoint.v;
4039                                }
4040                                break;
4041                        case synctex_node_type_glue:
4042                        case synctex_node_type_math:
4043                                minH = SYNCTEX_HORIZ(node);
4044                                minV = SYNCTEX_VERT(node);
4045                                if (hitPoint.h<minH) {
4046                                        if (hitPoint.v>minV) {
4047                                                result = hitPoint.v - minV + minH - hitPoint.h;
4048                                        } else {
4049                                                result = minV - hitPoint.v + minH - hitPoint.h;
4050                                        }
4051                                } else if (hitPoint.v>minV) {
4052                                        result = hitPoint.v - minV + hitPoint.h - minH;
4053                                } else {
4054                                        result = minV - hitPoint.v + hitPoint.h - minH;
4055                                }
4056                                break;
4057                }
4058        }
4059        return result;
4060}
4061
4062static synctex_node_t _synctex_eq_deepest_container(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible) {
4063        if (node) {
4064                synctex_node_t result = NULL;
4065                synctex_node_t child = NULL;
4066                switch(node->class->type) {
4067                        case synctex_node_type_vbox:
4068                        case synctex_node_type_hbox:
4069                                /*  test the deep nodes first */
4070                                if ((child = SYNCTEX_CHILD(node))) {
4071                                        do {
4072                                                if ((result = _synctex_eq_deepest_container(hitPoint,child,visible))) {
4073                                                        return result;
4074                                                }
4075                                        } while((child = SYNCTEX_SIBLING(child)));
4076                                }
4077                                /*  is the hit point inside the box? */
4078                                if (_synctex_point_in_box(hitPoint,node,visible)) {
4079                                        /*  for vboxes we try to use some node inside.
4080                                         *  Walk through the list of siblings until we find the closest one.
4081                                         *  Only consider siblings with children. */
4082                                        if ((node->class->type == synctex_node_type_vbox) && (child = SYNCTEX_CHILD(node))) {
4083                                                int bestDistance = INT_MAX;
4084                                                do {
4085                                                        if (SYNCTEX_CHILD(child)) {
4086                                                                int distance = _synctex_node_distance_to_point(hitPoint,child,visible);
4087                                                                if (distance < bestDistance) {
4088                                                                        bestDistance = distance;
4089                                                                        node = child;
4090                                                                }
4091                                                        }
4092                                                } while((child = SYNCTEX_SIBLING(child)));
4093                                        }
4094                                        return node;
4095                                }
4096                }
4097        }
4098        return NULL;
4099}
4100
4101/*  Compares the locations of the hitPoint with the locations of the various nodes contained in the box.
4102 *  As it is an horizontal box, we only compare horizontal coordinates. */
4103SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_hbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t*  bestNodesRef,synctex_distances_t*  bestDistancesRef, synctex_bool_t visible);
4104SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_hbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t*  bestNodesRef,synctex_distances_t*  bestDistancesRef, synctex_bool_t visible) {
4105        int result = 0;
4106        if ((node = SYNCTEX_CHILD(node))) {
4107                do {
4108                        int off7 = _synctex_point_h_distance(hitPoint,node,visible);
4109                        if (off7 > 0) {
4110                                /*  node is to the right of the hit point.
4111                                 *  We compare node and the previously recorded one, through the recorded distance.
4112                                 *  If the nodes have the same tag, prefer the one with the smallest line number,
4113                                 *  if the nodes also have the same line number, prefer the one with the smallest column. */
4114                                if (bestDistancesRef->right > off7) {
4115                                        bestDistancesRef->right = off7;
4116                                        bestNodesRef->right = node;
4117                                        result |= SYNCTEX_MASK_RIGHT;
4118                                } else if (bestDistancesRef->right == off7 && bestNodesRef->right) {
4119                                        if (SYNCTEX_TAG(bestNodesRef->right) == SYNCTEX_TAG(node)
4120                                                && (SYNCTEX_LINE(bestNodesRef->right) > SYNCTEX_LINE(node)
4121                                                        || (SYNCTEX_LINE(bestNodesRef->right) == SYNCTEX_LINE(node)
4122                                                                && SYNCTEX_COLUMN(bestNodesRef->right) > SYNCTEX_COLUMN(node)))) {
4123                                                bestNodesRef->right = node;
4124                                                result |= SYNCTEX_MASK_RIGHT;
4125                                        }
4126                                }
4127                        } else if (off7 == 0) {
4128                                /*  hitPoint is inside node. */ 
4129                                bestDistancesRef->left = bestDistancesRef->right = 0;
4130                                bestNodesRef->left = node;
4131                                bestNodesRef->right = NULL;
4132                                result |= SYNCTEX_MASK_LEFT;
4133                        } else { /*  here off7 < 0, hitPoint is to the right of node */
4134                                off7 = -off7;
4135                                if (bestDistancesRef->left > off7) {
4136                                        bestDistancesRef->left = off7;
4137                                        bestNodesRef->left = node;
4138                                        result |= SYNCTEX_MASK_LEFT;
4139                                } else if (bestDistancesRef->left == off7 && bestNodesRef->left) {
4140                                        if (SYNCTEX_TAG(bestNodesRef->left) == SYNCTEX_TAG(node)
4141                                                && (SYNCTEX_LINE(bestNodesRef->left) > SYNCTEX_LINE(node)
4142                                                        || (SYNCTEX_LINE(bestNodesRef->left) == SYNCTEX_LINE(node)
4143                                                                && SYNCTEX_COLUMN(bestNodesRef->left) > SYNCTEX_COLUMN(node)))) {
4144                                                bestNodesRef->left = node;
4145                                                result |= SYNCTEX_MASK_LEFT;
4146                                        }
4147                                }
4148                        }
4149                } while((node = SYNCTEX_SIBLING(node)));
4150                if (result & SYNCTEX_MASK_LEFT) {
4151                        /*  the left node is new, try to narrow the result */
4152                        if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->left,visible))) {
4153                                bestNodesRef->left = node;
4154                        } 
4155                        if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->left,visible))) {
4156                                bestNodesRef->left = node;
4157                        } 
4158                }
4159                if (result & SYNCTEX_MASK_RIGHT) {
4160                        /*  the right node is new, try to narrow the result */
4161                        if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->right,visible))) {
4162                                bestNodesRef->right = node;
4163                        } 
4164                        if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->right,visible))) {
4165                                bestNodesRef->right = node;
4166                        } 
4167                }
4168        }
4169        return result;
4170}
4171SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_vbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t*  bestNodesRef,synctex_distances_t*  bestDistancesRef,synctex_bool_t visible);
4172SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_vbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t*  bestNodesRef,synctex_distances_t*  bestDistancesRef,synctex_bool_t visible) {
4173        int result = 0;
4174        if ((node = SYNCTEX_CHILD(node))) {
4175                do {
4176                        int off7 = _synctex_point_v_distance(hitPoint,node,visible);/*  this is what makes the difference with the h version above */
4177                        if (off7 > 0) {
4178                                /*  node is to the top of the hit point (below because TeX is oriented from top to bottom.
4179                                 *  We compare node and the previously recorded one, through the recorded distance.
4180                                 *  If the nodes have the same tag, prefer the one with the smallest line number,
4181                                 *  if the nodes also have the same line number, prefer the one with the smallest column. */
4182                                if (bestDistancesRef->right > off7) {
4183                                        bestDistancesRef->right = off7;
4184                                        bestNodesRef->right = node;
4185                                        result |= SYNCTEX_MASK_RIGHT;
4186                                } else if (bestDistancesRef->right == off7 && bestNodesRef->right) {
4187                                        if (SYNCTEX_TAG(bestNodesRef->right) == SYNCTEX_TAG(node)
4188                                                && (SYNCTEX_LINE(bestNodesRef->right) > SYNCTEX_LINE(node)
4189                                                        || (SYNCTEX_LINE(bestNodesRef->right) == SYNCTEX_LINE(node)
4190                                                                && SYNCTEX_COLUMN(bestNodesRef->right) > SYNCTEX_COLUMN(node)))) {
4191                                                bestNodesRef->right = node;
4192                                                result |= SYNCTEX_MASK_RIGHT;
4193                                        }
4194                                }
4195                        } else if (off7 == 0) {
4196                                bestDistancesRef->left = bestDistancesRef->right = 0;
4197                                bestNodesRef->left = node;
4198                                bestNodesRef->right = NULL;
4199                                result |= SYNCTEX_MASK_LEFT;
4200                        } else { /*  here off7 < 0 */
4201                                off7 = -off7;
4202                                if (bestDistancesRef->left > off7) {
4203                                        bestDistancesRef->left = off7;
4204                                        bestNodesRef->left = node;
4205                                        result |= SYNCTEX_MASK_LEFT;
4206                                } else if (bestDistancesRef->left == off7 && bestNodesRef->left) {
4207                                        if (SYNCTEX_TAG(bestNodesRef->left) == SYNCTEX_TAG(node)
4208                                                && (SYNCTEX_LINE(bestNodesRef->left) > SYNCTEX_LINE(node)
4209                                                        || (SYNCTEX_LINE(bestNodesRef->left) == SYNCTEX_LINE(node)
4210                                                                && SYNCTEX_COLUMN(bestNodesRef->left) > SYNCTEX_COLUMN(node)))) {
4211                                                bestNodesRef->left = node;
4212                                                result |= SYNCTEX_MASK_LEFT;
4213                                        }
4214                                }
4215                        }
4216                } while((node = SYNCTEX_SIBLING(node)));
4217                if (result & SYNCTEX_MASK_LEFT) {
4218                        /*  the left node is new, try to narrow the result */
4219                        if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->left,visible))) {
4220                                bestNodesRef->left = node;
4221                        } 
4222                        if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->left,visible))) {
4223                                bestNodesRef->left = node;
4224                        } 
4225                }
4226                if (result & SYNCTEX_MASK_RIGHT) {
4227                        /*  the right node is new, try to narrow the result */
4228                        if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->right,visible))) {
4229                                bestNodesRef->right = node;
4230                        } 
4231                        if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->right,visible))) {
4232                                bestNodesRef->right = node;
4233                        } 
4234                }
4235        }
4236        return result;
4237}
4238SYNCTEX_INLINE static int _synctex_eq_get_closest_children_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t*  bestNodesRef,synctex_distances_t*  bestDistancesRef,synctex_bool_t visible) {
4239        if (node) {
4240                switch(node->class->type) {
4241                        case synctex_node_type_hbox:
4242                                return __synctex_eq_get_closest_children_in_hbox(hitPoint, node, bestNodesRef, bestDistancesRef,visible);
4243                        case synctex_node_type_vbox:
4244                                return __synctex_eq_get_closest_children_in_vbox(hitPoint, node, bestNodesRef, bestDistancesRef,visible);
4245                }
4246        }
4247        return 0;
4248}
4249
4250SYNCTEX_INLINE static synctex_node_t __synctex_eq_closest_child(synctex_point_t hitPoint, synctex_node_t node,int*  distanceRef, synctex_bool_t visible);
4251SYNCTEX_INLINE static synctex_node_t __synctex_eq_closest_child(synctex_point_t hitPoint, synctex_node_t node,int*  distanceRef, synctex_bool_t visible) {
4252        synctex_node_t best_node = NULL;
4253        if ((node = SYNCTEX_CHILD(node))) {
4254                do {
4255                        int distance = _synctex_node_distance_to_point(hitPoint,node,visible);
4256                        synctex_node_t candidate = NULL;
4257                        if (distance<=*distanceRef) {
4258                                *distanceRef = distance;
4259                                best_node = node;
4260                        }
4261                        switch(node->class->type) {
4262                                case synctex_node_type_vbox:
4263                                case synctex_node_type_hbox:
4264                                        if ((candidate = __synctex_eq_closest_child(hitPoint,node,distanceRef,visible))) {
4265                                                best_node = candidate;
4266                                        }
4267                        }
4268                } while((node = SYNCTEX_SIBLING(node)));
4269        }
4270        return best_node;
4271}
4272SYNCTEX_INLINE static synctex_node_t _synctex_eq_closest_child(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible) {
4273        if (node) {
4274                switch(node->class->type) {
4275                        case synctex_node_type_hbox:
4276                        case synctex_node_type_vbox:
4277                        {
4278                                int best_distance = INT_MAX;
4279                                synctex_node_t best_node = __synctex_eq_closest_child(hitPoint,node,&best_distance,visible);
4280                                if ((best_node)) {
4281                                        synctex_node_t child = NULL;
4282                                        switch(best_node->class->type) {
4283                                                case synctex_node_type_vbox:
4284                                                case synctex_node_type_hbox:
4285                                                        if ((child = SYNCTEX_CHILD(best_node))) {
4286                                                                best_distance = _synctex_node_distance_to_point(hitPoint,child,visible);
4287                                                                while((child = SYNCTEX_SIBLING(child))) {
4288                                                                        int distance = _synctex_node_distance_to_point(hitPoint,child,visible);
4289                                                                        if (distance<=best_distance) {
4290                                                                                best_distance = distance;
4291                                                                                best_node = child;
4292                                                                        }
4293                                                                }
4294                                                        }
4295                                        }
4296                                }
4297                                return best_node;
4298                        }
4299                }
4300        }
4301        return NULL;
4302}
4303
4304#       ifdef SYNCTEX_NOTHING
4305#       pragma mark -
4306#       pragma mark Updater
4307#   endif
4308
4309typedef int (*synctex_fprintf_t)(void *, const char * , ...); /*  print formatted to either FILE *  or gzFile */
4310
4311#   define SYNCTEX_BITS_PER_BYTE 8
4312
4313struct __synctex_updater_t {
4314    gzFile file;                /*  the foo.synctex or foo.synctex.gz I/O identifier  */
4315    synctex_fprintf_t fprintf;  /*  either fprintf or gzprintf */
4316    int length;                 /*  the number of chars appended */
4317    struct _flags {
4318        unsigned int no_gz:1;   /*  Whether zlib is used or not */
4319        unsigned int reserved:SYNCTEX_BITS_PER_BYTE*sizeof(int)-1; /*  Align */
4320        } flags;
4321};
4322#   define SYNCTEX_FILE updater->file
4323#   define SYNCTEX_NO_GZ ((updater->flags).no_gz)
4324#   define SYNCTEX_fprintf (*(updater->fprintf))
4325
4326synctex_updater_t synctex_updater_new_with_output_file(const char * output, const char * build_directory) {
4327        synctex_updater_t updater = NULL;
4328        char * synctex = NULL;
4329        synctex_io_mode_t io_mode = 0;
4330        const char * mode = NULL;
4331        /*  prepare the updater, the memory is the only one dynamically allocated */
4332        updater = (synctex_updater_t)_synctex_malloc(sizeof(synctex_updater_t));
4333        if (NULL == updater) {
4334                _synctex_error("!  synctex_updater_new_with_file: malloc problem");
4335                return NULL;
4336        }
4337        if (_synctex_open(output,build_directory,&synctex,&SYNCTEX_FILE,synctex_ADD_QUOTES,&io_mode)
4338                && _synctex_open(output,build_directory,&synctex,&SYNCTEX_FILE,synctex_DONT_ADD_QUOTES,&io_mode)) {
4339return_on_error:
4340                free(updater);
4341        updater = NULL;
4342                return NULL;
4343        }
4344        /*  OK, the file exists, we close it and reopen it with the correct mode.
4345     *  The receiver is now the owner of the "synctex" variable. */
4346        gzclose(SYNCTEX_FILE);
4347        SYNCTEX_FILE = NULL;
4348        SYNCTEX_NO_GZ = (io_mode&synctex_io_gz_mask)?synctex_NO:synctex_YES;
4349    mode = _synctex_get_io_mode_name(io_mode|synctex_io_append_mask);/* either "a" or "ab", depending on the file extension */
4350        if (SYNCTEX_NO_GZ) {
4351                if (NULL == (SYNCTEX_FILE = (void *)fopen(synctex,mode))) {
4352no_write_error:
4353                        _synctex_error("!  synctex_updater_new_with_file: Can't append to %s",synctex);
4354                        free(synctex);
4355                        goto return_on_error;
4356                }
4357                updater->fprintf = (synctex_fprintf_t)(&fprintf);
4358        } else {
4359                if (NULL == (SYNCTEX_FILE = (void *)gzopen(synctex,mode))) {
4360                        goto no_write_error;
4361                }
4362                updater->fprintf = (synctex_fprintf_t)(&gzprintf);
4363        }
4364        printf("SyncTeX: updating %s...",synctex);
4365        free(synctex);
4366        return updater;
4367}
4368
4369
4370void synctex_updater_append_magnification(synctex_updater_t updater, char * magnification){
4371        if (NULL==updater) {
4372                return;
4373        }
4374        if (magnification && strlen(magnification)) {
4375                updater->length += SYNCTEX_fprintf(SYNCTEX_FILE,"Magnification:%s\n",magnification);
4376        }
4377}
4378
4379void synctex_updater_append_x_offset(synctex_updater_t updater, char * x_offset){
4380        if (NULL==updater) {
4381                return;
4382        }
4383        if (x_offset && strlen(x_offset)) {
4384                updater->length += SYNCTEX_fprintf(SYNCTEX_FILE,"X Offset:%s\n",x_offset);
4385        }
4386}
4387
4388void synctex_updater_append_y_offset(synctex_updater_t updater, char * y_offset){
4389        if (NULL==updater) {
4390                return;
4391        }
4392        if (y_offset && strlen(y_offset)) {
4393                updater->length += SYNCTEX_fprintf(SYNCTEX_FILE,"Y Offset:%s\n",y_offset);
4394        }
4395}
4396
4397void synctex_updater_free(synctex_updater_t updater){
4398        if (NULL==updater) {
4399                return;
4400        }
4401        if (updater->length>0) {
4402                SYNCTEX_fprintf(SYNCTEX_FILE,"!%i\n",updater->length);
4403        }
4404        if (SYNCTEX_NO_GZ) {
4405                fclose((FILE *)SYNCTEX_FILE);
4406        } else {
4407                gzclose((gzFile)SYNCTEX_FILE);
4408        }
4409        free(updater);
4410        printf("... done.\n");
4411        return;
4412}
Note: See TracBrowser for help on using the repository browser.