2 Copyright (c) 2008, 2009; 2010 jerome DOT laurens AT u-bourgogne DOT fr
4 This file is part of the SyncTeX package.
7 See synctex_parser_readme.txt for more details
9 Latest Revision: Mon Jul 19 21:50:36 UTC 2010
13 Permission is hereby granted, free of charge, to any person
14 obtaining a copy of this software and associated documentation
15 files (the "Software"), to deal in the Software without
16 restriction, including without limitation the rights to use,
17 copy, modify, merge, publish, distribute, sublicense, and/or sell
18 copies of the Software, and to permit persons to whom the
19 Software is furnished to do so, subject to the following
22 The above copyright notice and this permission notice shall be
23 included in all copies or substantial portions of the Software.
25 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
27 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
29 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
30 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
32 OTHER DEALINGS IN THE SOFTWARE
34 Except as contained in this notice, the name of the copyright holder
35 shall not be used in advertising or otherwise to promote the sale,
36 use or other dealings in this Software without prior written
37 authorization from the copyright holder.
41 The author received useful remarks from the pdfTeX developers, especially Hahn The Thanh,
42 and significant help from XeTeX developer Jonathan Kew
46 If you include or use a significant part of the synctex package into a software,
47 I would appreciate to be listed as contributor and see "SyncTeX" highlighted.
50 Thu Jun 19 09:39:21 UTC 2008
54 /* We assume that high level application like pdf viewers will want
55 * to embed this code as is. We assume that they also have locale.h and setlocale.
56 * For other tools such as TeXLive tools, you must define SYNCTEX_USE_LOCAL_HEADER,
57 * when building. You also have to create and customize synctex_parser_local.h to fit your system.
58 * In particular, the HAVE_LOCALE_H and HAVE_SETLOCALE macros should be properly defined.
59 * With this design, you should not need to edit this file. */
61 # if defined(SYNCTEX_USE_LOCAL_HEADER)
62 # include "synctex_parser_local.h"
64 # define HAVE_LOCALE_H 1
65 # define HAVE_SETLOCALE 1
66 # if defined(_MSC_VER)
67 # define SYNCTEX_INLINE __inline
69 # define SYNCTEX_INLINE inline
79 #if defined(HAVE_LOCALE_H)
83 /* The data is organized in a graph with multiple entries.
84 * The root object is a scanner, it is created with the contents on a synctex file.
85 * Each leaf of the tree is a synctex_node_t object.
86 * There are 3 subtrees, two of them sharing the same leaves.
87 * The first tree is the list of input records, where input file names are associated with tags.
88 * The second tree is the box tree as given by TeX when shipping pages out.
89 * First level objects are sheets, containing boxes, glues, kerns...
90 * The third tree allows to browse leaves according to tag and line.
93 #include "synctex_parser.h"
94 #include <synctex_parser_utils.h>
96 /* These are the possible extensions of the synctex file */
97 const char * synctex_suffix = ".synctex";
98 const char * synctex_suffix_gz = ".gz";
100 static const char * synctex_io_modes[synctex_io_mode_append+2] = {"r","rb","a","ab"};
102 /* each synctex node has a class */
103 typedef struct __synctex_class_t _synctex_class_t;
104 typedef _synctex_class_t * synctex_class_t;
107 /* synctex_node_t is a pointer to a node
108 * _synctex_node is the target of the synctex_node_t pointer
109 * It is a pseudo object oriented program.
110 * class is a pointer to the class object the node belongs to.
111 * implementation is meant to contain the private data of the node
112 * basically, there are 2 kinds of information: navigation information and
113 * synctex information. Both will depend on the type of the node,
114 * thus different nodes will have different private data.
115 * There is no inheritancy overhead.
117 typedef union _synctex_info_t {
122 struct _synctex_node {
123 synctex_class_t class;
124 synctex_info_t * implementation;
127 /* Each node of the tree, except the scanner itself belongs to a class.
128 * The class object is just a struct declaring the owning scanner
129 * This is a pointer to the scanner as root of the tree.
130 * The type is used to identify the kind of node.
131 * The class declares pointers to a creator and a destructor method.
132 * The log and display fields are used to log and display the node.
133 * display will also display the child, sibling and parent sibling.
134 * parent, child and sibling are used to navigate the tree,
135 * from TeX box hierarchy point of view.
136 * The friend field points to a method which allows to navigate from friend to friend.
137 * A friend is a node with very close tag and line numbers.
138 * Finally, the info field point to a method giving the private node info offset.
141 typedef synctex_node_t *(*_synctex_node_getter_t)(synctex_node_t);
142 typedef synctex_info_t *(*_synctex_info_getter_t)(synctex_node_t);
144 struct __synctex_class_t {
145 synctex_scanner_t scanner;
147 synctex_node_t (*new)(synctex_scanner_t scanner);
148 void (*free)(synctex_node_t);
149 void (*log)(synctex_node_t);
150 void (*display)(synctex_node_t);
151 _synctex_node_getter_t parent;
152 _synctex_node_getter_t child;
153 _synctex_node_getter_t sibling;
154 _synctex_node_getter_t friend;
155 _synctex_node_getter_t next_box;
156 _synctex_info_getter_t info;
159 # ifdef SYNCTEX_NOTHING
161 # pragma mark Abstract OBJECTS and METHODS
164 /* These macros are shortcuts
165 * This macro checks if a message can be sent.
167 # define SYNCTEX_CAN_PERFORM(NODE,SELECTOR)\
168 (NULL!=((((NODE)->class))->SELECTOR))
170 /* This macro is some kind of objc_msg_send.
171 * It takes care of sending the proper message if possible.
173 # define SYNCTEX_MSG_SEND(NODE,SELECTOR) if(NODE && SYNCTEX_CAN_PERFORM(NODE,SELECTOR)) {\
174 (*((((NODE)->class))->SELECTOR))(NODE);\
177 /* read only safe getter
179 # define SYNCTEX_GET(NODE,SELECTOR)((NODE && SYNCTEX_CAN_PERFORM(NODE,SELECTOR))?SYNCTEX_GETTER(NODE,SELECTOR)[0]:(NULL))
183 # define SYNCTEX_GETTER(NODE,SELECTOR)\
184 ((synctex_node_t *)((*((((NODE)->class))->SELECTOR))(NODE)))
186 # define SYNCTEX_FREE(NODE) SYNCTEX_MSG_SEND(NODE,free);
188 /* Parent getter and setter
190 # define SYNCTEX_PARENT(NODE) SYNCTEX_GET(NODE,parent)
191 # define SYNCTEX_SET_PARENT(NODE,NEW_PARENT) if(NODE && NEW_PARENT && SYNCTEX_CAN_PERFORM(NODE,parent)){\
192 SYNCTEX_GETTER(NODE,parent)[0]=NEW_PARENT;\
195 /* Child getter and setter
197 # define SYNCTEX_CHILD(NODE) SYNCTEX_GET(NODE,child)
198 # define SYNCTEX_SET_CHILD(NODE,NEW_CHILD) if(NODE && NEW_CHILD){\
199 SYNCTEX_GETTER(NODE,child)[0]=NEW_CHILD;\
200 SYNCTEX_GETTER(NEW_CHILD,parent)[0]=NODE;\
203 /* Sibling getter and setter
205 # define SYNCTEX_SIBLING(NODE) SYNCTEX_GET(NODE,sibling)
206 # define SYNCTEX_SET_SIBLING(NODE,NEW_SIBLING) if(NODE && NEW_SIBLING) {\
207 SYNCTEX_GETTER(NODE,sibling)[0]=NEW_SIBLING;\
208 if(SYNCTEX_CAN_PERFORM(NEW_SIBLING,parent) && SYNCTEX_CAN_PERFORM(NODE,parent)) {\
209 SYNCTEX_GETTER(NEW_SIBLING,parent)[0]=SYNCTEX_GETTER(NODE,parent)[0];\
212 /* Friend getter and setter. A friend is a kern, math, glue or void box node which tag and line numbers are similar.
213 * This is a first filter on the nodes that avoids testing all of them.
214 * Friends are used mainly in forward synchronization aka from source to output.
216 # define SYNCTEX_FRIEND(NODE) SYNCTEX_GET(NODE,friend)
217 # define SYNCTEX_SET_FRIEND(NODE,NEW_FRIEND) if(NODE && NEW_FRIEND){\
218 SYNCTEX_GETTER(NODE,friend)[0]=NEW_FRIEND;\
221 /* Next box getter and setter. The box tree can be traversed from one horizontal box to the other.
222 * Navigation starts with the deeper boxes.
224 # define SYNCTEX_NEXT_HORIZ_BOX(NODE) SYNCTEX_GET(NODE,next_box)
225 # define SYNCTEX_SET_NEXT_HORIZ_BOX(NODE,NEXT_BOX) if(NODE && NEXT_BOX){\
226 SYNCTEX_GETTER(NODE,next_box)[0]=NEXT_BOX;\
229 void _synctex_free_node(synctex_node_t node);
230 void _synctex_free_leaf(synctex_node_t node);
232 /* A node is meant to own its child and sibling.
233 * It is not owned by its parent, unless it is its first child.
234 * This destructor is for all nodes with children.
236 void _synctex_free_node(synctex_node_t node) {
238 (*((node->class)->sibling))(node);
239 SYNCTEX_FREE(SYNCTEX_SIBLING(node));
240 SYNCTEX_FREE(SYNCTEX_CHILD(node));
246 /* A node is meant to own its child and sibling.
247 * It is not owned by its parent, unless it is its first child.
248 * This destructor is for nodes with no child.
250 void _synctex_free_leaf(synctex_node_t node) {
252 SYNCTEX_FREE(SYNCTEX_SIBLING(node));
257 # ifdef __SYNCTEX_WORK__
258 # include "/usr/include/zlib.h"
263 /* The synctex scanner is the root object.
264 * Is is initialized with the contents of a text file or a gzipped file.
265 * The buffer_? are first used to parse the text.
267 struct __synctex_scanner_t {
268 gzFile file; /* The (possibly compressed) file */
269 char * buffer_cur; /* current location in the buffer */
270 char * buffer_start; /* start of the buffer */
271 char * buffer_end; /* end of the buffer */
272 char * output_fmt; /* dvi or pdf, not yet used */
273 char * output; /* the output name used to create the scanner */
274 char * synctex; /* the .synctex or .synctex.gz name used to create the scanner */
275 int version; /* 1, not yet used */
277 unsigned has_parsed:1; /* Whether the scanner has parsed its underlying synctex file. */
278 unsigned reserved:sizeof(unsigned)-1; /* alignment */
280 int pre_magnification; /* magnification from the synctex preamble */
281 int pre_unit; /* unit from the synctex preamble */
282 int pre_x_offset; /* X offste from the synctex preamble */
283 int pre_y_offset; /* Y offset from the synctex preamble */
284 int count; /* Number of records, from the synctex postamble */
285 float unit; /* real unit, from synctex preamble or post scriptum */
286 float x_offset; /* X offset, from synctex preamble or post scriptum */
287 float y_offset; /* Y Offset, from synctex preamble or post scriptum */
288 synctex_node_t sheet; /* The first sheet node, its siblings are the other sheet nodes */
289 synctex_node_t input; /* The first input node, its siblings are the other input nodes */
290 int number_of_lists; /* The number of friend lists */
291 synctex_node_t * lists_of_friends;/* The friend lists */
292 _synctex_class_t class[synctex_node_number_of_types]; /* The classes of the nodes of the scanner */
295 /* SYNCTEX_CUR, SYNCTEX_START and SYNCTEX_END are convenient shortcuts
297 # define SYNCTEX_CUR (scanner->buffer_cur)
298 # define SYNCTEX_START (scanner->buffer_start)
299 # define SYNCTEX_END (scanner->buffer_end)
301 # ifdef SYNCTEX_NOTHING
303 # pragma mark OBJECTS, their creators and destructors.
306 /* Here, we define the indices for the different informations.
307 * They are used to declare the size of the implementation.
308 * For example, if one object uses SYNCTEX_HORIZ_IDX is its size,
309 * then its info will contain a tag, line, column, horiz but no width nor height nor depth
312 /* The sheet is a first level node.
313 * It has no parent (the parent is the scanner itself)
314 * Its sibling points to another sheet.
315 * Its child points to its first child, in general a box.
316 * A sheet node contains only one synctex information: the page.
317 * This is the 1 based page index as given by TeX.
319 /* The next macros are used to access the node info
320 * SYNCTEX_INFO(node) points to the first synctex integer or pointer data of node
321 * SYNCTEX_INFO(node)[index] is the information at index
322 * for example, the page of a sheet is stored in SYNCTEX_INFO(sheet)[SYNCTEX_PAGE_IDX]
324 # define SYNCTEX_INFO(NODE) ((*((((NODE)->class))->info))(NODE))
325 # define SYNCTEX_PAGE_IDX 0
326 # define SYNCTEX_PAGE(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_PAGE_IDX].INT
328 /* This macro defines implementation offsets
329 * It is only used for pointer values
331 # define SYNCTEX_MAKE_GET(SYNCTEX_GETTER,OFFSET)\
332 synctex_node_t * SYNCTEX_GETTER (synctex_node_t node);\
333 synctex_node_t * SYNCTEX_GETTER (synctex_node_t node) {\
334 return node?(synctex_node_t *)((&((node)->implementation))+OFFSET):NULL;\
336 SYNCTEX_MAKE_GET(_synctex_implementation_0,0)
337 SYNCTEX_MAKE_GET(_synctex_implementation_1,1)
338 SYNCTEX_MAKE_GET(_synctex_implementation_2,2)
339 SYNCTEX_MAKE_GET(_synctex_implementation_3,3)
340 SYNCTEX_MAKE_GET(_synctex_implementation_4,4)
341 SYNCTEX_MAKE_GET(_synctex_implementation_5,5)
344 synctex_class_t class;
345 synctex_info_t implementation[3+SYNCTEX_PAGE_IDX+1];/* child, sibling, next box,
346 * SYNCTEX_PAGE_IDX */
349 synctex_node_t _synctex_new_sheet(synctex_scanner_t scanner);
350 void _synctex_display_sheet(synctex_node_t sheet);
351 void _synctex_log_sheet(synctex_node_t sheet);
353 static _synctex_class_t synctex_class_sheet = {
354 NULL, /* No scanner yet */
355 synctex_node_type_sheet, /* Node type */
356 &_synctex_new_sheet, /* creator */
357 &_synctex_free_node, /* destructor */
358 &_synctex_log_sheet, /* log */
359 &_synctex_display_sheet, /* display */
360 NULL, /* No parent */
361 &_synctex_implementation_0, /* child */
362 &_synctex_implementation_1, /* sibling */
363 NULL, /* No friend */
364 &_synctex_implementation_2, /* Next box */
365 (_synctex_info_getter_t)&_synctex_implementation_3 /* info */
368 /* sheet node creator */
369 synctex_node_t _synctex_new_sheet(synctex_scanner_t scanner) {
370 synctex_node_t node = _synctex_malloc(sizeof(synctex_sheet_t));
372 node->class = scanner?scanner->class+synctex_node_type_sheet:(synctex_class_t)&synctex_class_sheet;
377 /* A box node contains navigation and synctex information
378 * There are different kind of boxes.
379 * Only horizontal boxes are treated differently because of their visible size.
381 # define SYNCTEX_TAG_IDX 0
382 # define SYNCTEX_LINE_IDX (SYNCTEX_TAG_IDX+1)
383 # define SYNCTEX_COLUMN_IDX (SYNCTEX_LINE_IDX+1)
384 # define SYNCTEX_HORIZ_IDX (SYNCTEX_COLUMN_IDX+1)
385 # define SYNCTEX_VERT_IDX (SYNCTEX_HORIZ_IDX+1)
386 # define SYNCTEX_WIDTH_IDX (SYNCTEX_VERT_IDX+1)
387 # define SYNCTEX_HEIGHT_IDX (SYNCTEX_WIDTH_IDX+1)
388 # define SYNCTEX_DEPTH_IDX (SYNCTEX_HEIGHT_IDX+1)
389 /* the corresponding info accessors */
390 # define SYNCTEX_TAG(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_TAG_IDX].INT
391 # define SYNCTEX_LINE(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_LINE_IDX].INT
392 # define SYNCTEX_COLUMN(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_COLUMN_IDX].INT
393 # define SYNCTEX_HORIZ(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HORIZ_IDX].INT
394 # define SYNCTEX_VERT(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_VERT_IDX].INT
395 # define SYNCTEX_WIDTH(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_WIDTH_IDX].INT
396 # define SYNCTEX_HEIGHT(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HEIGHT_IDX].INT
397 # define SYNCTEX_DEPTH(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_DEPTH_IDX].INT
398 # define SYNCTEX_ABS_WIDTH(NODE) ((SYNCTEX_WIDTH(NODE)>0?SYNCTEX_WIDTH(NODE):-SYNCTEX_WIDTH(NODE)))
399 # define SYNCTEX_ABS_HEIGHT(NODE) ((SYNCTEX_HEIGHT(NODE)>0?SYNCTEX_HEIGHT(NODE):-SYNCTEX_HEIGHT(NODE)))
400 # define SYNCTEX_ABS_DEPTH(NODE) ((SYNCTEX_DEPTH(NODE)>0?SYNCTEX_DEPTH(NODE):-SYNCTEX_DEPTH(NODE)))
403 synctex_class_t class;
404 synctex_info_t implementation[5+SYNCTEX_DEPTH_IDX+1]; /* parent,child,sibling,friend,next box,
405 * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
406 * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH */
407 } synctex_vert_box_node_t;
409 synctex_node_t _synctex_new_vbox(synctex_scanner_t scanner);
410 void _synctex_log_box(synctex_node_t sheet);
411 void _synctex_display_vbox(synctex_node_t node);
413 /* These are static class objects, each scanner will make a copy of them and setup the scanner field.
415 static _synctex_class_t synctex_class_vbox = {
416 NULL, /* No scanner yet */
417 synctex_node_type_vbox, /* Node type */
418 &_synctex_new_vbox, /* creator */
419 &_synctex_free_node, /* destructor */
420 &_synctex_log_box, /* log */
421 &_synctex_display_vbox, /* display */
422 &_synctex_implementation_0, /* parent */
423 &_synctex_implementation_1, /* child */
424 &_synctex_implementation_2, /* sibling */
425 &_synctex_implementation_3, /* friend */
426 &_synctex_implementation_4, /* next box */
427 (_synctex_info_getter_t)&_synctex_implementation_5
430 /* vertical box node creator */
431 synctex_node_t _synctex_new_vbox(synctex_scanner_t scanner) {
432 synctex_node_t node = _synctex_malloc(sizeof(synctex_vert_box_node_t));
434 node->class = scanner?scanner->class+synctex_node_type_vbox:(synctex_class_t)&synctex_class_vbox;
439 # define SYNCTEX_HORIZ_V_IDX (SYNCTEX_DEPTH_IDX+1)
440 # define SYNCTEX_VERT_V_IDX (SYNCTEX_HORIZ_V_IDX+1)
441 # define SYNCTEX_WIDTH_V_IDX (SYNCTEX_VERT_V_IDX+1)
442 # define SYNCTEX_HEIGHT_V_IDX (SYNCTEX_WIDTH_V_IDX+1)
443 # define SYNCTEX_DEPTH_V_IDX (SYNCTEX_HEIGHT_V_IDX+1)
444 /* the corresponding info accessors */
445 # define SYNCTEX_HORIZ_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HORIZ_V_IDX].INT
446 # define SYNCTEX_VERT_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_VERT_V_IDX].INT
447 # define SYNCTEX_WIDTH_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_WIDTH_V_IDX].INT
448 # define SYNCTEX_HEIGHT_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HEIGHT_V_IDX].INT
449 # define SYNCTEX_DEPTH_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_DEPTH_V_IDX].INT
450 # define SYNCTEX_ABS_WIDTH_V(NODE) ((SYNCTEX_WIDTH_V(NODE)>0?SYNCTEX_WIDTH_V(NODE):-SYNCTEX_WIDTH_V(NODE)))
451 # define SYNCTEX_ABS_HEIGHT_V(NODE) ((SYNCTEX_HEIGHT_V(NODE)>0?SYNCTEX_HEIGHT_V(NODE):-SYNCTEX_HEIGHT_V(NODE)))
452 # define SYNCTEX_ABS_DEPTH_V(NODE) ((SYNCTEX_DEPTH_V(NODE)>0?SYNCTEX_DEPTH_V(NODE):-SYNCTEX_DEPTH_V(NODE)))
454 /* Horizontal boxes must contain visible size, because 0 width does not mean emptiness */
456 synctex_class_t class;
457 synctex_info_t implementation[5+SYNCTEX_DEPTH_V_IDX+1]; /*parent,child,sibling,friend,next box,
458 * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
459 * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH,
460 * SYNCTEX_HORIZ_V,SYNCTEX_VERT_V,SYNCTEX_WIDTH_V,SYNCTEX_HEIGHT_V,SYNCTEX_DEPTH_V*/
461 } synctex_horiz_box_node_t;
463 synctex_node_t _synctex_new_hbox(synctex_scanner_t scanner);
464 void _synctex_display_hbox(synctex_node_t node);
465 void _synctex_log_horiz_box(synctex_node_t sheet);
468 static _synctex_class_t synctex_class_hbox = {
469 NULL, /* No scanner yet */
470 synctex_node_type_hbox, /* Node type */
471 &_synctex_new_hbox, /* creator */
472 &_synctex_free_node, /* destructor */
473 &_synctex_log_horiz_box, /* log */
474 &_synctex_display_hbox, /* display */
475 &_synctex_implementation_0, /* parent */
476 &_synctex_implementation_1, /* child */
477 &_synctex_implementation_2, /* sibling */
478 &_synctex_implementation_3, /* friend */
479 &_synctex_implementation_4, /* next box */
480 (_synctex_info_getter_t)&_synctex_implementation_5
483 /* horizontal box node creator */
484 synctex_node_t _synctex_new_hbox(synctex_scanner_t scanner) {
485 synctex_node_t node = _synctex_malloc(sizeof(synctex_horiz_box_node_t));
487 node->class = scanner?scanner->class+synctex_node_type_hbox:(synctex_class_t)&synctex_class_hbox;
492 /* This void box node implementation is either horizontal or vertical
493 * It does not contain a child field.
496 synctex_class_t class;
497 synctex_info_t implementation[3+SYNCTEX_DEPTH_IDX+1]; /* parent,sibling,friend,
498 * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
499 * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH*/
500 } synctex_void_box_node_t;
502 synctex_node_t _synctex_new_void_vbox(synctex_scanner_t scanner);
503 void _synctex_log_void_box(synctex_node_t sheet);
504 void _synctex_display_void_vbox(synctex_node_t node);
506 static _synctex_class_t synctex_class_void_vbox = {
507 NULL, /* No scanner yet */
508 synctex_node_type_void_vbox,/* Node type */
509 &_synctex_new_void_vbox, /* creator */
510 &_synctex_free_node, /* destructor */
511 &_synctex_log_void_box, /* log */
512 &_synctex_display_void_vbox,/* display */
513 &_synctex_implementation_0, /* parent */
515 &_synctex_implementation_1, /* sibling */
516 &_synctex_implementation_2, /* friend */
517 NULL, /* No next box */
518 (_synctex_info_getter_t)&_synctex_implementation_3
521 /* vertical void box node creator */
522 synctex_node_t _synctex_new_void_vbox(synctex_scanner_t scanner) {
523 synctex_node_t node = _synctex_malloc(sizeof(synctex_void_box_node_t));
525 node->class = scanner?scanner->class+synctex_node_type_void_vbox:(synctex_class_t)&synctex_class_void_vbox;
530 synctex_node_t _synctex_new_void_hbox(synctex_scanner_t scanner);
531 void _synctex_display_void_hbox(synctex_node_t node);
533 static _synctex_class_t synctex_class_void_hbox = {
534 NULL, /* No scanner yet */
535 synctex_node_type_void_hbox,/* Node type */
536 &_synctex_new_void_hbox, /* creator */
537 &_synctex_free_node, /* destructor */
538 &_synctex_log_void_box, /* log */
539 &_synctex_display_void_hbox,/* display */
540 &_synctex_implementation_0, /* parent */
542 &_synctex_implementation_1, /* sibling */
543 &_synctex_implementation_2, /* friend */
544 NULL, /* No next box */
545 (_synctex_info_getter_t)&_synctex_implementation_3
548 /* horizontal void box node creator */
549 synctex_node_t _synctex_new_void_hbox(synctex_scanner_t scanner) {
550 synctex_node_t node = _synctex_malloc(sizeof(synctex_void_box_node_t));
552 node->class = scanner?scanner->class+synctex_node_type_void_hbox:(synctex_class_t)&synctex_class_void_hbox;
557 /* The medium nodes correspond to kern, glue, penalty and math nodes. */
559 synctex_class_t class;
560 synctex_info_t implementation[3+SYNCTEX_WIDTH_IDX+1]; /* parent,sibling,friend,
561 * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
562 * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH */
563 } synctex_medium_node_t;
565 #define SYNCTEX_IS_BOX(NODE)\
566 ((NODE->class->type == synctex_node_type_vbox)\
567 || (NODE->class->type == synctex_node_type_void_vbox)\
568 || (NODE->class->type == synctex_node_type_hbox)\
569 || (NODE->class->type == synctex_node_type_void_hbox))
571 #define SYNCTEX_HAS_CHILDREN(NODE) (NODE && SYNCTEX_CHILD(NODE))
573 void _synctex_log_medium_node(synctex_node_t node);
575 /* math node creator */
576 synctex_node_t _synctex_new_math(synctex_scanner_t scanner);
577 void _synctex_display_math(synctex_node_t node);
579 static _synctex_class_t synctex_class_math = {
580 NULL, /* No scanner yet */
581 synctex_node_type_math, /* Node type */
582 &_synctex_new_math, /* creator */
583 &_synctex_free_leaf, /* destructor */
584 &_synctex_log_medium_node, /* log */
585 &_synctex_display_math, /* display */
586 &_synctex_implementation_0, /* parent */
588 &_synctex_implementation_1, /* sibling */
589 &_synctex_implementation_2, /* friend */
590 NULL, /* No next box */
591 (_synctex_info_getter_t)&_synctex_implementation_3
594 synctex_node_t _synctex_new_math(synctex_scanner_t scanner) {
595 synctex_node_t node = _synctex_malloc(sizeof(synctex_medium_node_t));
597 node->class = scanner?scanner->class+synctex_node_type_math:(synctex_class_t)&synctex_class_math;
602 /* kern node creator */
603 synctex_node_t _synctex_new_kern(synctex_scanner_t scanner);
604 void _synctex_display_kern(synctex_node_t node);
606 static _synctex_class_t synctex_class_kern = {
607 NULL, /* No scanner yet */
608 synctex_node_type_kern, /* Node type */
609 &_synctex_new_kern, /* creator */
610 &_synctex_free_leaf, /* destructor */
611 &_synctex_log_medium_node, /* log */
612 &_synctex_display_kern, /* display */
613 &_synctex_implementation_0, /* parent */
615 &_synctex_implementation_1, /* sibling */
616 &_synctex_implementation_2, /* friend */
617 NULL, /* No next box */
618 (_synctex_info_getter_t)&_synctex_implementation_3
621 synctex_node_t _synctex_new_kern(synctex_scanner_t scanner) {
622 synctex_node_t node = _synctex_malloc(sizeof(synctex_medium_node_t));
624 node->class = scanner?scanner->class+synctex_node_type_kern:(synctex_class_t)&synctex_class_kern;
629 /* The small nodes correspond to glue and boundary nodes. */
631 synctex_class_t class;
632 synctex_info_t implementation[3+SYNCTEX_VERT_IDX+1]; /* parent,sibling,friend,
633 * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
634 * SYNCTEX_HORIZ,SYNCTEX_VERT */
635 } synctex_small_node_t;
637 void _synctex_log_small_node(synctex_node_t node);
638 /* glue node creator */
639 synctex_node_t _synctex_new_glue(synctex_scanner_t scanner);
640 void _synctex_display_glue(synctex_node_t node);
642 static _synctex_class_t synctex_class_glue = {
643 NULL, /* No scanner yet */
644 synctex_node_type_glue, /* Node type */
645 &_synctex_new_glue, /* creator */
646 &_synctex_free_leaf, /* destructor */
647 &_synctex_log_medium_node, /* log */
648 &_synctex_display_glue, /* display */
649 &_synctex_implementation_0, /* parent */
651 &_synctex_implementation_1, /* sibling */
652 &_synctex_implementation_2, /* friend */
653 NULL, /* No next box */
654 (_synctex_info_getter_t)&_synctex_implementation_3
656 synctex_node_t _synctex_new_glue(synctex_scanner_t scanner) {
657 synctex_node_t node = _synctex_malloc(sizeof(synctex_medium_node_t));
659 node->class = scanner?scanner->class+synctex_node_type_glue:(synctex_class_t)&synctex_class_glue;
664 /* boundary node creator */
665 synctex_node_t _synctex_new_boundary(synctex_scanner_t scanner);
666 void _synctex_display_boundary(synctex_node_t node);
668 static _synctex_class_t synctex_class_boundary = {
669 NULL, /* No scanner yet */
670 synctex_node_type_boundary, /* Node type */
671 &_synctex_new_boundary, /* creator */
672 &_synctex_free_leaf, /* destructor */
673 &_synctex_log_small_node, /* log */
674 &_synctex_display_boundary, /* display */
675 &_synctex_implementation_0, /* parent */
677 &_synctex_implementation_1, /* sibling */
678 &_synctex_implementation_2, /* friend */
679 NULL, /* No next box */
680 (_synctex_info_getter_t)&_synctex_implementation_3
683 synctex_node_t _synctex_new_boundary(synctex_scanner_t scanner) {
684 synctex_node_t node = _synctex_malloc(sizeof(synctex_small_node_t));
686 node->class = scanner?scanner->class+synctex_node_type_boundary:(synctex_class_t)&synctex_class_boundary;
691 # define SYNCTEX_NAME_IDX (SYNCTEX_TAG_IDX+1)
692 # define SYNCTEX_NAME(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_NAME_IDX].PTR
694 /* Input nodes only know about their sibling, which is another input node.
695 * The synctex information is the SYNCTEX_TAG and SYNCTEX_NAME*/
697 synctex_class_t class;
698 synctex_info_t implementation[1+SYNCTEX_NAME_IDX+1]; /* sibling,
699 * SYNCTEX_TAG,SYNCTEX_NAME */
702 synctex_node_t _synctex_new_input(synctex_scanner_t scanner);
703 void _synctex_free_input(synctex_node_t node);
704 void _synctex_display_input(synctex_node_t node);
705 void _synctex_log_input(synctex_node_t sheet);
707 static _synctex_class_t synctex_class_input = {
708 NULL, /* No scanner yet */
709 synctex_node_type_input, /* Node type */
710 &_synctex_new_input, /* creator */
711 &_synctex_free_input, /* destructor */
712 &_synctex_log_input, /* log */
713 &_synctex_display_input, /* display */
714 NULL, /* No parent */
716 &_synctex_implementation_0, /* sibling */
717 NULL, /* No friend */
718 NULL, /* No next box */
719 (_synctex_info_getter_t)&_synctex_implementation_1
722 synctex_node_t _synctex_new_input(synctex_scanner_t scanner) {
723 synctex_node_t node = _synctex_malloc(sizeof(synctex_input_t));
725 node->class = scanner?scanner->class+synctex_node_type_input:(synctex_class_t)&synctex_class_input;
729 void _synctex_free_input(synctex_node_t node){
731 SYNCTEX_FREE(SYNCTEX_SIBLING(node));
732 free(SYNCTEX_NAME(node));
736 # ifdef SYNCTEX_NOTHING
738 # pragma mark Navigation
740 synctex_node_t synctex_node_parent(synctex_node_t node)
742 return SYNCTEX_PARENT(node);
744 synctex_node_t synctex_node_sheet(synctex_node_t node)
746 while(node && node->class->type != synctex_node_type_sheet) {
747 node = SYNCTEX_PARENT(node);
749 /* exit the while loop either when node is NULL or node is a sheet */
752 synctex_node_t synctex_node_child(synctex_node_t node)
754 return SYNCTEX_CHILD(node);
756 synctex_node_t synctex_node_sibling(synctex_node_t node)
758 return SYNCTEX_SIBLING(node);
760 synctex_node_t synctex_node_next(synctex_node_t node) {
761 if(SYNCTEX_CHILD(node)) {
762 return SYNCTEX_CHILD(node);
765 if(SYNCTEX_SIBLING(node)) {
766 return SYNCTEX_SIBLING(node);
768 if((node = SYNCTEX_PARENT(node))) {
769 if(node->class->type == synctex_node_type_sheet) {/* EXC_BAD_ACCESS? */
776 # ifdef SYNCTEX_NOTHING
781 /* Public node accessor: the type */
782 synctex_node_type_t synctex_node_type(synctex_node_t node) {
784 return (((node)->class))->type;
786 return synctex_node_type_error;
789 /* Public node accessor: the human readable type */
790 const char * synctex_node_isa(synctex_node_t node) {
791 static const char * isa[synctex_node_number_of_types] =
792 {"Not a node","input","sheet","vbox","void vbox","hbox","void hbox","kern","glue","math","boundary"};
793 return isa[synctex_node_type(node)];
796 # ifdef SYNCTEX_NOTHING
798 # pragma mark SYNCTEX_LOG
801 # define SYNCTEX_LOG(NODE) SYNCTEX_MSG_SEND(NODE,log)
803 /* Public node logger */
804 void synctex_node_log(synctex_node_t node) {
808 # define SYNCTEX_DISPLAY(NODE) SYNCTEX_MSG_SEND(NODE,display)
810 void synctex_node_display(synctex_node_t node) {
811 SYNCTEX_DISPLAY(node);
814 void _synctex_display_input(synctex_node_t node) {
815 printf("....Input:%i:%s\n",
818 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
821 void _synctex_log_sheet(synctex_node_t sheet) {
823 printf("%s:%i\n",synctex_node_isa(sheet),SYNCTEX_PAGE(sheet));
824 printf("SELF:%p",(void *)sheet);
825 printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(sheet));
826 printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(sheet));
827 printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(sheet));
828 printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(sheet));
832 void _synctex_log_small_node(synctex_node_t node) {
833 printf("%s:%i,%i:%i,%i\n",
834 synctex_node_isa(node),
839 printf("SELF:%p",(void *)node);
840 printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
841 printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
842 printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
843 printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node));
846 void _synctex_log_medium_node(synctex_node_t node) {
847 printf("%s:%i,%i:%i,%i:%i\n",
848 synctex_node_isa(node),
853 SYNCTEX_WIDTH(node));
854 printf("SELF:%p",(void *)node);
855 printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
856 printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
857 printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
858 printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node));
861 void _synctex_log_void_box(synctex_node_t node) {
862 printf("%s",synctex_node_isa(node));
863 printf(":%i",SYNCTEX_TAG(node));
864 printf(",%i",SYNCTEX_LINE(node));
866 printf(":%i",SYNCTEX_HORIZ(node));
867 printf(",%i",SYNCTEX_VERT(node));
868 printf(":%i",SYNCTEX_WIDTH(node));
869 printf(",%i",SYNCTEX_HEIGHT(node));
870 printf(",%i",SYNCTEX_DEPTH(node));
871 printf("\nSELF:%p",(void *)node);
872 printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
873 printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
874 printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
875 printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node));
878 void _synctex_log_box(synctex_node_t node) {
879 printf("%s",synctex_node_isa(node));
880 printf(":%i",SYNCTEX_TAG(node));
881 printf(",%i",SYNCTEX_LINE(node));
883 printf(":%i",SYNCTEX_HORIZ(node));
884 printf(",%i",SYNCTEX_VERT(node));
885 printf(":%i",SYNCTEX_WIDTH(node));
886 printf(",%i",SYNCTEX_HEIGHT(node));
887 printf(",%i",SYNCTEX_DEPTH(node));
888 printf("\nSELF:%p",(void *)node);
889 printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
890 printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
891 printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
892 printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node));
895 void _synctex_log_horiz_box(synctex_node_t node) {
896 printf("%s",synctex_node_isa(node));
897 printf(":%i",SYNCTEX_TAG(node));
898 printf(",%i",SYNCTEX_LINE(node));
900 printf(":%i",SYNCTEX_HORIZ(node));
901 printf(",%i",SYNCTEX_VERT(node));
902 printf(":%i",SYNCTEX_WIDTH(node));
903 printf(",%i",SYNCTEX_HEIGHT(node));
904 printf(",%i",SYNCTEX_DEPTH(node));
905 printf("/%i",SYNCTEX_HORIZ_V(node));
906 printf(",%i",SYNCTEX_VERT_V(node));
907 printf(":%i",SYNCTEX_WIDTH_V(node));
908 printf(",%i",SYNCTEX_HEIGHT_V(node));
909 printf(",%i",SYNCTEX_DEPTH_V(node));
910 printf("\nSELF:%p",(void *)node);
911 printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
912 printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
913 printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
914 printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node));
917 void _synctex_log_input(synctex_node_t node) {
918 printf("%s",synctex_node_isa(node));
919 printf(":%i",SYNCTEX_TAG(node));
920 printf(",%s",SYNCTEX_NAME(node));
921 printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
924 void _synctex_display_sheet(synctex_node_t sheet) {
926 printf("....{%i\n",SYNCTEX_PAGE(sheet));
927 SYNCTEX_DISPLAY(SYNCTEX_CHILD(sheet));
929 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(sheet));
933 void _synctex_display_vbox(synctex_node_t node) {
934 printf("....[%i,%i:%i,%i:%i,%i,%i\n",
940 SYNCTEX_HEIGHT(node),
941 SYNCTEX_DEPTH(node));
942 SYNCTEX_DISPLAY(SYNCTEX_CHILD(node));
944 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
947 void _synctex_display_hbox(synctex_node_t node) {
948 printf("....(%i,%i:%i,%i:%i,%i,%i\n",
954 SYNCTEX_HEIGHT(node),
955 SYNCTEX_DEPTH(node));
956 SYNCTEX_DISPLAY(SYNCTEX_CHILD(node));
958 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
961 void _synctex_display_void_vbox(synctex_node_t node) {
962 printf("....v%i,%i;%i,%i:%i,%i,%i\n",
968 SYNCTEX_HEIGHT(node),
969 SYNCTEX_DEPTH(node));
970 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
973 void _synctex_display_void_hbox(synctex_node_t node) {
974 printf("....h%i,%i:%i,%i:%i,%i,%i\n",
980 SYNCTEX_HEIGHT(node),
981 SYNCTEX_DEPTH(node));
982 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
985 void _synctex_display_glue(synctex_node_t node) {
986 printf("....glue:%i,%i:%i,%i\n",
991 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
994 void _synctex_display_math(synctex_node_t node) {
995 printf("....math:%i,%i:%i,%i\n",
1000 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
1003 void _synctex_display_kern(synctex_node_t node) {
1004 printf("....kern:%i,%i:%i,%i:%i\n",
1007 SYNCTEX_HORIZ(node),
1009 SYNCTEX_WIDTH(node));
1010 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
1013 void _synctex_display_boundary(synctex_node_t node) {
1014 printf("....boundary:%i,%i:%i,%i\n",
1017 SYNCTEX_HORIZ(node),
1018 SYNCTEX_VERT(node));
1019 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
1022 # ifdef SYNCTEX_NOTHING
1024 # pragma mark SCANNER
1027 /* Here are gathered all the possible status that the next scanning functions will return.
1028 * All these functions return a status, and pass their result through pointers.
1029 * Negative values correspond to errors.
1030 * The management of the buffer is causing some significant overhead.
1031 * Every function that may access the buffer returns a status related to the buffer and file state.
1032 * status >= SYNCTEX_STATUS_OK means the function worked as expected
1033 * status < SYNCTEX_STATUS_OK means the function did not work as expected
1034 * status == SYNCTEX_STATUS_NOT_OK means the function did not work as expected but there is still some material to parse.
1035 * status == SYNCTEX_STATUS_EOF means the function did not work as expected and there is no more material.
1036 * status<SYNCTEX_STATUS_EOF means an error
1038 typedef int synctex_status_t;
1039 /* When the end of the synctex file has been reached: */
1040 # define SYNCTEX_STATUS_EOF 0
1041 /* When the function could not return the value it was asked for: */
1042 # define SYNCTEX_STATUS_NOT_OK (SYNCTEX_STATUS_EOF+1)
1043 /* When the function returns the value it was asked for: */
1044 # define SYNCTEX_STATUS_OK (SYNCTEX_STATUS_NOT_OK+1)
1045 /* Generic error: */
1046 # define SYNCTEX_STATUS_ERROR -1
1047 /* Parameter error: */
1048 # define SYNCTEX_STATUS_BAD_ARGUMENT -2
1050 # define SYNCTEX_FILE (scanner->file)
1052 /* Actually, the minimum buffer size is driven by integer and float parsing.
1053 * ±0.123456789e123
1055 # define SYNCTEX_BUFFER_MIN_SIZE 16
1056 # define SYNCTEX_BUFFER_SIZE 32768
1058 # ifdef SYNCTEX_NOTHING
1060 # pragma mark Prototypes
1062 void _synctex_log_void_box(synctex_node_t node);
1063 void _synctex_log_box(synctex_node_t node);
1064 void _synctex_log_horiz_box(synctex_node_t node);
1065 void _synctex_log_input(synctex_node_t node);
1066 synctex_status_t _synctex_buffer_get_available_size(synctex_scanner_t scanner, size_t * size_ptr);
1067 synctex_status_t _synctex_next_line(synctex_scanner_t scanner);
1068 synctex_status_t _synctex_match_string(synctex_scanner_t scanner, const char * the_string);
1069 synctex_status_t _synctex_decode_int(synctex_scanner_t scanner, int* value_ref);
1070 synctex_status_t _synctex_decode_string(synctex_scanner_t scanner, char ** value_ref);
1071 synctex_status_t _synctex_scan_input(synctex_scanner_t scanner);
1072 synctex_status_t _synctex_scan_preamble(synctex_scanner_t scanner);
1073 synctex_status_t _synctex_scan_float_and_dimension(synctex_scanner_t scanner, float * value_ref);
1074 synctex_status_t _synctex_scan_post_scriptum(synctex_scanner_t scanner);
1075 int _synctex_scan_postamble(synctex_scanner_t scanner);
1076 synctex_status_t _synctex_setup_visible_box(synctex_node_t box);
1077 synctex_status_t _synctex_horiz_box_setup_visible(synctex_node_t node,int h, int v);
1078 synctex_status_t _synctex_scan_sheet(synctex_scanner_t scanner, synctex_node_t parent);
1079 synctex_status_t _synctex_scan_content(synctex_scanner_t scanner);
1080 int synctex_scanner_pre_x_offset(synctex_scanner_t scanner);
1081 int synctex_scanner_pre_y_offset(synctex_scanner_t scanner);
1082 const char * synctex_scanner_get_output_fmt(synctex_scanner_t scanner);
1083 int _synctex_node_is_box(synctex_node_t node);
1084 int _synctex_bail(void);
1086 /* Try to ensure that the buffer contains at least size bytes.
1087 * Passing a huge size argument means the whole buffer length.
1088 * Passing a null size argument means return the available buffer length, without reading the file.
1089 * In that case, the return status is always SYNCTEX_STATUS_OK unless the given scanner is NULL,
1090 * in which case, SYNCTEX_STATUS_BAD_ARGUMENT is returned.
1091 * The value returned in size_ptr is the number of bytes now available in the buffer.
1092 * This is a nonnegative integer, it may take the value 0.
1093 * It is the responsibility of the caller to test whether this size is conforming to its needs.
1094 * Negative values may return in case of error, actually
1095 * when there was an error reading the synctex file. */
1096 synctex_status_t _synctex_buffer_get_available_size(synctex_scanner_t scanner, size_t * size_ptr) {
1097 size_t available = 0;
1098 if(NULL == scanner || NULL == size_ptr) {
1099 return SYNCTEX_STATUS_BAD_ARGUMENT;
1101 # define size (* size_ptr)
1102 if(size>SYNCTEX_BUFFER_SIZE){
1103 size = SYNCTEX_BUFFER_SIZE;
1105 available = SYNCTEX_END - SYNCTEX_CUR; /* available is the number of unparsed chars in the buffer */
1106 if(size<=available) {
1107 /* There are already sufficiently many characters in the buffer */
1109 return SYNCTEX_STATUS_OK;
1112 /* Copy the remaining part of the buffer to the beginning,
1113 * then read the next part of the file */
1114 int already_read = 0;
1116 memmove(SYNCTEX_START, SYNCTEX_CUR, available);
1118 SYNCTEX_CUR = SYNCTEX_START + available; /* the next character after the move, will change. */
1119 /* Fill the buffer up to its end */
1120 already_read = gzread(SYNCTEX_FILE,(void *)SYNCTEX_CUR,SYNCTEX_BUFFER_SIZE - available);
1121 if(already_read>0) {
1122 /* We assume that 0<already_read<=SYNCTEX_BUFFER_SIZE - available, such that
1123 * SYNCTEX_CUR + already_read = SYNCTEX_START + available + already_read <= SYNCTEX_START + SYNCTEX_BUFFER_SIZE */
1124 SYNCTEX_END = SYNCTEX_CUR + already_read;
1125 /* If the end of the file was reached, all the required SYNCTEX_BUFFER_SIZE - available
1126 * may not be filled with values from the file.
1127 * In that case, the buffer should stop properly after already_read characters. */
1128 * SYNCTEX_END = '\0';
1129 SYNCTEX_CUR = SYNCTEX_START;
1130 size = SYNCTEX_END - SYNCTEX_CUR; /* == old available + already_read*/
1131 return SYNCTEX_STATUS_OK; /* May be available is less than size, the caller will have to test. */
1132 } else if(0>already_read) {
1133 /* There is an error in zlib */
1135 const char * error_string = gzerror(SYNCTEX_FILE, &errnum);
1136 if(Z_ERRNO == errnum) {
1137 /* There is an error in zlib caused by the file system */
1138 _synctex_error("gzread error from the file system (%i)",errno);
1140 _synctex_error("gzread error (%i:%i,%s)",already_read,errnum,error_string);
1142 return SYNCTEX_STATUS_ERROR;
1144 /* Nothing was read, we are at the end of the file. */
1145 gzclose(SYNCTEX_FILE);
1146 SYNCTEX_FILE = NULL;
1147 SYNCTEX_END = SYNCTEX_CUR;
1148 SYNCTEX_CUR = SYNCTEX_START;
1149 * SYNCTEX_END = '\0';/* Terminate the string properly.*/
1150 size = SYNCTEX_END - SYNCTEX_CUR;
1151 return SYNCTEX_STATUS_EOF; /* there might be a bit of text left */
1153 /* At this point, the function has already returned from above */
1155 /* We cannot enlarge the buffer because the end of the file was reached. */
1157 return SYNCTEX_STATUS_EOF;
1161 /* Used when parsing the synctex file.
1162 * Advance to the next character starting a line.
1163 * Actually, only '\n' is recognized as end of line marker.
1164 * On normal completion, the returned value is the number of unparsed characters available in the buffer.
1165 * In general, it is a positive value, 0 meaning that the end of file was reached.
1166 * -1 is returned in case of error, actually because there was an error while feeding the buffer.
1167 * When the function returns with no error, SYNCTEX_CUR points to the first character of the next line, if any.
1168 * J. Laurens: Sat May 10 07:52:31 UTC 2008
1170 synctex_status_t _synctex_next_line(synctex_scanner_t scanner) {
1171 synctex_status_t status = SYNCTEX_STATUS_OK;
1172 size_t available = 0;
1173 if(NULL == scanner) {
1174 return SYNCTEX_STATUS_BAD_ARGUMENT;
1177 while(SYNCTEX_CUR<SYNCTEX_END) {
1178 if(*SYNCTEX_CUR == '\n') {
1181 return _synctex_buffer_get_available_size(scanner, &available);
1185 /* Here, we have SYNCTEX_CUR == SYNCTEX_END, such that the next call to _synctex_buffer_get_available_size
1186 * will read another bunch of synctex file. Little by little, we advance to the end of the file. */
1188 status = _synctex_buffer_get_available_size(scanner, &available);
1195 /* Scan the given string.
1196 * Both scanner and the_string must not be NULL, and the_string must not be 0 length.
1197 * SYNCTEX_STATUS_OK is returned if the string is found,
1198 * SYNCTEX_STATUS_EOF is returned when the EOF is reached,
1199 * SYNCTEX_STATUS_NOT_OK is returned is the string is not found,
1200 * an error status is returned otherwise.
1201 * This is a critical method because buffering renders things more difficult.
1202 * The given string might be as long as the maximum size_t value.
1203 * As side effect, the buffer state may have changed if the given argument string can't fit into the buffer.
1205 synctex_status_t _synctex_match_string(synctex_scanner_t scanner, const char * the_string) {
1206 size_t tested_len = 0; /* the number of characters at the beginning of the_string that match */
1207 size_t remaining_len = 0; /* the number of remaining characters of the_string that should match */
1208 size_t available = 0;
1209 synctex_status_t status = 0;
1210 if(NULL == scanner || NULL == the_string) {
1211 return SYNCTEX_STATUS_BAD_ARGUMENT;
1213 remaining_len = strlen(the_string); /* All the_string should match */
1214 if(0 == remaining_len) {
1215 return SYNCTEX_STATUS_BAD_ARGUMENT;
1217 /* How many characters available in the buffer? */
1218 available = remaining_len;
1219 status = _synctex_buffer_get_available_size(scanner,&available);
1220 if(status<SYNCTEX_STATUS_EOF) {
1223 /* Maybe we have less characters than expected because the buffer is too small. */
1224 if(available>=remaining_len) {
1225 /* The buffer is sufficiently big to hold the expected number of characters. */
1226 if(strncmp((char *)SYNCTEX_CUR,the_string,remaining_len)) {
1227 return SYNCTEX_STATUS_NOT_OK;
1230 /* Advance SYNCTEX_CUR to the next character after the_string. */
1231 SYNCTEX_CUR += remaining_len;
1232 return SYNCTEX_STATUS_OK;
1233 } else if(strncmp((char *)SYNCTEX_CUR,the_string,available)) {
1234 /* No need to goo further, this is not the expected string in the buffer. */
1235 return SYNCTEX_STATUS_NOT_OK;
1236 } else if(SYNCTEX_FILE) {
1237 /* The buffer was too small to contain remaining_len characters.
1238 * We have to cut the string into pieces. */
1239 z_off_t offset = 0L;
1240 /* the first part of the string is found, advance the_string to the next untested character. */
1241 the_string += available;
1242 /* update the remaining length and the parsed length. */
1243 remaining_len -= available;
1244 tested_len += available;
1245 SYNCTEX_CUR += available; /* We validate the tested characters. */
1246 if(0 == remaining_len) {
1247 /* Nothing left to test, we have found the given string, we return the length. */
1250 /* We also have to record the current state of the file cursor because
1251 * if the_string does not match, all this should be a totally blank operation,
1252 * for which the file and buffer states should not be modified at all.
1253 * In fact, the states of the buffer before and after this function are in general different
1254 * but they are totally equivalent as long as the values of the buffer before SYNCTEX_CUR
1255 * can be safely discarded. */
1256 offset = gztell(SYNCTEX_FILE);
1257 /* offset now corresponds to the first character of the file that was not buffered. */
1258 available = SYNCTEX_CUR - SYNCTEX_START; /* available can be used as temporary placeholder. */
1259 /* available now corresponds to the number of chars that where already buffered and
1260 * that match the head of the_string. If in fine the_string does not match, all these chars must be recovered
1261 * because the buffer contents is completely replaced by _synctex_buffer_get_available_size.
1262 * They were buffered from offset-len location in the file. */
1263 offset -= available;
1265 /* There is still some work to be done, so read another bunch of file.
1266 * This is the second call to _synctex_buffer_get_available_size,
1267 * which means that the actual contents of the buffer will be discarded.
1268 * We will definitely have to recover the previous state in case we do not find the expected string. */
1269 available = remaining_len;
1270 status = _synctex_buffer_get_available_size(scanner,&available);
1271 if(status<SYNCTEX_STATUS_EOF) {
1272 return status; /* This is an error, no need to go further. */
1275 /* Missing characters: recover the initial state of the file and return. */
1277 if(offset != gzseek(SYNCTEX_FILE,offset,SEEK_SET)) {
1278 /* This is a critical error, we could not recover the previous state. */
1279 _synctex_error("can't seek file");
1280 return SYNCTEX_STATUS_ERROR;
1282 /* Next time we are asked to fill the buffer,
1283 * we will read a complete bunch of text from the file. */
1284 SYNCTEX_CUR = SYNCTEX_END;
1285 return SYNCTEX_STATUS_NOT_OK;
1287 if(available<remaining_len) {
1288 /* We'll have to loop one more time. */
1289 if(strncmp((char *)SYNCTEX_CUR,the_string,available)) {
1290 /* This is not the expected string, recover the previous state and return. */
1293 /* Advance the_string to the first untested character. */
1294 the_string += available;
1295 /* update the remaining length and the parsed length. */
1296 remaining_len -= available;
1297 tested_len += available;
1298 SYNCTEX_CUR += available; /* We validate the tested characters. */
1299 if(0 == remaining_len) {
1300 /* Nothing left to test, we have found the given string. */
1301 return SYNCTEX_STATUS_OK;
1303 goto more_characters;
1305 /* This is the last step. */
1306 if(strncmp((char *)SYNCTEX_CUR,the_string,remaining_len)) {
1307 /* This is not the expected string, recover the previous state and return. */
1312 /* The buffer can't contain the given string argument, and the EOF was reached */
1313 return SYNCTEX_STATUS_EOF;
1317 /* Used when parsing the synctex file.
1318 * Decode an integer.
1319 * First, field separators, namely ':' and ',' characters are skipped
1320 * The returned value is negative if there is an unrecoverable error.
1321 * It is SYNCTEX_STATUS_NOT_OK if an integer could not be parsed, for example
1322 * if the characters at the current cursor position are not digits or
1323 * if the end of the file has been reached.
1324 * It is SYNCTEX_STATUS_OK if an int has been successfully parsed.
1325 * The given scanner argument must not be NULL, on the contrary, value_ref may be NULL.
1327 synctex_status_t _synctex_decode_int(synctex_scanner_t scanner, int* value_ref) {
1331 size_t available = 0;
1332 synctex_status_t status = 0;
1333 if(NULL == scanner) {
1334 return SYNCTEX_STATUS_BAD_ARGUMENT;
1336 available = SYNCTEX_BUFFER_MIN_SIZE;
1337 status = _synctex_buffer_get_available_size(scanner, &available);
1338 if(status<SYNCTEX_STATUS_EOF) {
1339 return status;/* Forward error. */
1342 return SYNCTEX_STATUS_EOF;/* it is the end of file. */
1345 if(*ptr==':' || *ptr==',') {
1349 return SYNCTEX_STATUS_NOT_OK;/* It is not possible to scan an int */
1352 result = (int)strtol(ptr, &end, 10);
1356 * value_ref = result;
1358 return SYNCTEX_STATUS_OK;/* Successfully scanned an int */
1360 return SYNCTEX_STATUS_NOT_OK;/* Could not scan an int */
1363 /* The purpose of this function is to read a string.
1364 * A string is an array of characters from the current parser location
1365 * and before the next '\n' character.
1366 * If a string was properly decoded, it is returned in value_ref and
1367 * the cursor points to the new line marker.
1368 * The returned string was alloced on the heap, the caller is the owner and
1369 * is responsible to free it in due time.
1370 * If no string is parsed, * value_ref is undefined.
1371 * The maximum length of a string that a scanner can decode is platform dependent, namely UINT_MAX.
1372 * If you just want to blindly parse the file up to the end of the current line,
1373 * use _synctex_next_line instead.
1374 * On return, the scanner cursor is unchanged if a string could not be scanned or
1375 * points to the terminating '\n' character otherwise. As a consequence,
1376 * _synctex_next_line is necessary after.
1377 * If either scanner or value_ref is NULL, it is considered as an error and
1378 * SYNCTEX_STATUS_BAD_ARGUMENT is returned.
1380 synctex_status_t _synctex_decode_string(synctex_scanner_t scanner, char ** value_ref) {
1382 size_t current_size = 0;
1383 size_t new_size = 0;
1384 size_t len = 0;/* The number of bytes to copy */
1385 size_t available = 0;
1386 synctex_status_t status = 0;
1387 if(NULL == scanner || NULL == value_ref) {
1388 return SYNCTEX_STATUS_BAD_ARGUMENT;
1390 /* The buffer must at least contain one character: the '\n' end of line marker */
1391 if(SYNCTEX_CUR>=SYNCTEX_END) {
1393 status = _synctex_buffer_get_available_size(scanner,&available);
1397 if(0 == available) {
1398 return SYNCTEX_STATUS_EOF;
1401 /* Now we are sure that there is at least one available character, either because
1402 * SYNCTEX_CUR was already < SYNCTEX_END, or because the buffer has been properly filled. */
1403 /* end will point to the next unparsed '\n' character in the file, when mapped to the buffer. */
1405 * value_ref = NULL;/* Initialize, it will be realloc'ed */
1406 /* We scan all the characters up to the next '\n' */
1408 if(end<SYNCTEX_END) {
1410 /* OK, we found where to stop */
1411 len = end - SYNCTEX_CUR;
1412 if(current_size>UINT_MAX-len-1) {
1413 /* But we have reached the limit: we do not have current_size+len+1>UINT_MAX.
1414 * We return the missing amount of memory.
1415 * This will never occur in practice. */
1416 return UINT_MAX-len-1 - current_size;
1418 new_size = current_size+len;
1419 /* We have current_size+len+1<=UINT_MAX
1420 * or equivalently new_size<UINT_MAX,
1421 * where we have assumed that len<UINT_MAX */
1422 if((* value_ref = realloc(* value_ref,new_size+1)) != NULL) {
1423 if(memcpy((*value_ref)+current_size,SYNCTEX_CUR,len)) {
1424 (* value_ref)[new_size]='\0'; /* Terminate the string */
1425 SYNCTEX_CUR += len;/* Advance to the terminating '\n' */
1426 return SYNCTEX_STATUS_OK;
1430 _synctex_error("could not copy memory (1).");
1431 return SYNCTEX_STATUS_ERROR;
1433 _synctex_error("could not allocate memory (1).");
1434 return SYNCTEX_STATUS_ERROR;
1437 goto next_character;
1440 /* end == SYNCTEX_END */
1441 len = SYNCTEX_END - SYNCTEX_CUR;
1442 if(current_size>UINT_MAX-len-1) {
1443 /* We have reached the limit. */
1444 _synctex_error("limit reached (missing %i).",current_size-(UINT_MAX-len-1));
1445 return SYNCTEX_STATUS_ERROR;
1447 new_size = current_size+len;
1448 if((* value_ref = realloc(* value_ref,new_size+1)) != NULL) {
1449 if(memcpy((*value_ref)+current_size,SYNCTEX_CUR,len)) {
1450 (* value_ref)[new_size]='\0'; /* Terminate the string */
1451 SYNCTEX_CUR = SYNCTEX_END;/* Advance the cursor to the end of the bufer */
1452 return SYNCTEX_STATUS_OK;
1456 _synctex_error("could not copy memory (2).");
1457 return SYNCTEX_STATUS_ERROR;
1459 /* Huge memory problem */
1460 _synctex_error("could not allocate memory (2).");
1461 return SYNCTEX_STATUS_ERROR;
1465 /* Used when parsing the synctex file.
1466 * Read an Input record.
1468 synctex_status_t _synctex_scan_input(synctex_scanner_t scanner) {
1469 synctex_status_t status = 0;
1470 size_t available = 0;
1471 synctex_node_t input = NULL;
1472 if(NULL == scanner) {
1473 return SYNCTEX_STATUS_BAD_ARGUMENT;
1475 status = _synctex_match_string(scanner,"Input:");
1476 if(status<SYNCTEX_STATUS_OK) {
1480 input = _synctex_new_input(scanner);
1482 _synctex_error("could not create an input node.");
1483 return SYNCTEX_STATUS_ERROR;
1485 /* Decode the synctag */
1486 status = _synctex_decode_int(scanner,&(SYNCTEX_TAG(input)));
1487 if(status<SYNCTEX_STATUS_OK) {
1488 _synctex_error("bad format of input node.");
1489 SYNCTEX_FREE(input);
1492 /* The next character is a field separator, we expect one character in the buffer. */
1494 status = _synctex_buffer_get_available_size(scanner, &available);
1495 if(status<=SYNCTEX_STATUS_ERROR) {
1498 if(0 == available) {
1499 return SYNCTEX_STATUS_EOF;
1501 /* We can now safely advance to the next character, stepping over the field separator. */
1504 /* Then we scan the file name */
1505 status = _synctex_decode_string(scanner,&(SYNCTEX_NAME(input)));
1506 if(status<SYNCTEX_STATUS_OK) {
1507 SYNCTEX_FREE(input);
1510 /* Prepend this input node to the input linked list of the scanner */
1511 SYNCTEX_SET_SIBLING(input,scanner->input);
1512 scanner->input = input;
1513 return _synctex_next_line(scanner);/* read the line termination character, if any */
1514 /* Now, set up the path */
1517 typedef synctex_status_t (*synctex_decoder_t)(synctex_scanner_t,void *);
1519 synctex_status_t _synctex_scan_named(synctex_scanner_t scanner,const char * name,void * value_ref,synctex_decoder_t decoder);
1521 /* Used when parsing the synctex file.
1522 * Read one of the settings.
1523 * On normal completion, returns SYNCTEX_STATUS_OK.
1524 * On error, returns SYNCTEX_STATUS_ERROR.
1525 * Both arguments must not be NULL.
1526 * On return, the scanner points to the next character after the decoded object whatever it is.
1527 * It is the responsibility of the caller to prepare the scanner for the next line.
1529 synctex_status_t _synctex_scan_named(synctex_scanner_t scanner,const char * name,void * value_ref,synctex_decoder_t decoder) {
1530 synctex_status_t status = 0;
1531 if(NULL == scanner || NULL == name || NULL == value_ref || NULL == decoder) {
1532 return SYNCTEX_STATUS_BAD_ARGUMENT;
1535 status = _synctex_match_string(scanner,name);
1536 if(status<SYNCTEX_STATUS_NOT_OK) {
1538 } else if(status == SYNCTEX_STATUS_NOT_OK) {
1539 status = _synctex_next_line(scanner);
1540 if(status<SYNCTEX_STATUS_OK) {
1545 /* A line is found, scan the value */
1546 return (*decoder)(scanner,value_ref);
1549 /* Used when parsing the synctex file.
1550 * Read the preamble.
1552 synctex_status_t _synctex_scan_preamble(synctex_scanner_t scanner) {
1553 synctex_status_t status = 0;
1554 if(NULL == scanner) {
1555 return SYNCTEX_STATUS_BAD_ARGUMENT;
1557 status = _synctex_scan_named(scanner,"SyncTeX Version:",&(scanner->version),(synctex_decoder_t)&_synctex_decode_int);
1558 if(status<SYNCTEX_STATUS_OK) {
1561 status = _synctex_next_line(scanner);
1562 if(status<SYNCTEX_STATUS_OK) {
1565 /* Read all the input records */
1567 status = _synctex_scan_input(scanner);
1568 if(status<SYNCTEX_STATUS_NOT_OK) {
1571 } while(status == SYNCTEX_STATUS_OK);
1572 /* the loop exits when status == SYNCTEX_STATUS_NOT_OK */
1573 /* Now read all the required settings. */
1574 status = _synctex_scan_named(scanner,"Output:",&(scanner->output_fmt),(synctex_decoder_t)&_synctex_decode_string);
1575 if(status<SYNCTEX_STATUS_NOT_OK) {
1578 status = _synctex_next_line(scanner);
1579 if(status<SYNCTEX_STATUS_OK) {
1582 status = _synctex_scan_named(scanner,"Magnification:",&(scanner->pre_magnification),(synctex_decoder_t)&_synctex_decode_int);
1583 if(status<SYNCTEX_STATUS_OK) {
1586 status = _synctex_next_line(scanner);
1587 if(status<SYNCTEX_STATUS_OK) {
1590 status = _synctex_scan_named(scanner,"Unit:",&(scanner->pre_unit),(synctex_decoder_t)&_synctex_decode_int);
1591 if(status<SYNCTEX_STATUS_OK) {
1594 status = _synctex_next_line(scanner);
1595 if(status<SYNCTEX_STATUS_OK) {
1598 status = _synctex_scan_named(scanner,"X Offset:",&(scanner->pre_x_offset),(synctex_decoder_t)&_synctex_decode_int);
1599 if(status<SYNCTEX_STATUS_OK) {
1602 status = _synctex_next_line(scanner);
1603 if(status<SYNCTEX_STATUS_OK) {
1606 status = _synctex_scan_named(scanner,"Y Offset:",&(scanner->pre_y_offset),(synctex_decoder_t)&_synctex_decode_int);
1607 if(status<SYNCTEX_STATUS_OK) {
1610 return _synctex_next_line(scanner);
1613 /* parse a float with a dimension */
1614 synctex_status_t _synctex_scan_float_and_dimension(synctex_scanner_t scanner, float * value_ref) {
1615 synctex_status_t status = 0;
1616 char * endptr = NULL;
1618 #ifdef HAVE_SETLOCALE
1619 char * loc = setlocale(LC_NUMERIC, NULL);
1621 size_t available = 0;
1622 if(NULL == scanner || NULL == value_ref) {
1623 return SYNCTEX_STATUS_BAD_ARGUMENT;
1625 available = SYNCTEX_BUFFER_MIN_SIZE;
1626 status = _synctex_buffer_get_available_size(scanner, &available);
1627 if(status<SYNCTEX_STATUS_EOF) {
1628 _synctex_error("problem with float.");
1631 #ifdef HAVE_SETLOCALE
1632 setlocale(LC_NUMERIC, "C");
1634 f = strtod(SYNCTEX_CUR,&endptr);
1635 #ifdef HAVE_SETLOCALE
1636 setlocale(LC_NUMERIC, loc);
1638 if(endptr == SYNCTEX_CUR) {
1639 _synctex_error("a float was expected.");
1640 return SYNCTEX_STATUS_ERROR;
1642 SYNCTEX_CUR = endptr;
1643 if((status = _synctex_match_string(scanner,"in")) >= SYNCTEX_STATUS_OK) {
1645 } else if(status<SYNCTEX_STATUS_EOF) {
1647 _synctex_error("problem with unit.");
1649 } else if((status = _synctex_match_string(scanner,"cm")) >= SYNCTEX_STATUS_OK) {
1650 f *= 72.27f*65536/2.54f;
1651 } else if(status<0) {
1652 goto report_unit_error;
1653 } else if((status = _synctex_match_string(scanner,"mm")) >= SYNCTEX_STATUS_OK) {
1654 f *= 72.27f*65536/25.4f;
1655 } else if(status<0) {
1656 goto report_unit_error;
1657 } else if((status = _synctex_match_string(scanner,"pt")) >= SYNCTEX_STATUS_OK) {
1659 } else if(status<0) {
1660 goto report_unit_error;
1661 } else if((status = _synctex_match_string(scanner,"bp")) >= SYNCTEX_STATUS_OK) {
1662 f *= 72.27f/72*65536.0f;
1663 } else if(status<0) {
1664 goto report_unit_error;
1665 } else if((status = _synctex_match_string(scanner,"pc")) >= SYNCTEX_STATUS_OK) {
1667 } else if(status<0) {
1668 goto report_unit_error;
1669 } else if((status = _synctex_match_string(scanner,"sp")) >= SYNCTEX_STATUS_OK) {
1671 } else if(status<0) {
1672 goto report_unit_error;
1673 } else if((status = _synctex_match_string(scanner,"dd")) >= SYNCTEX_STATUS_OK) {
1674 f *= 1238.0f/1157*65536.0f;
1675 } else if(status<0) {
1676 goto report_unit_error;
1677 } else if((status = _synctex_match_string(scanner,"cc")) >= SYNCTEX_STATUS_OK) {
1678 f *= 14856.0f/1157*65536;
1679 } else if(status<0) {
1680 goto report_unit_error;
1681 } else if((status = _synctex_match_string(scanner,"nd")) >= SYNCTEX_STATUS_OK) {
1682 f *= 685.0f/642*65536;
1683 } else if(status<0) {
1684 goto report_unit_error;
1685 } else if((status = _synctex_match_string(scanner,"nc")) >= SYNCTEX_STATUS_OK) {
1686 f *= 1370.0f/107*65536;
1687 } else if(status<0) {
1688 goto report_unit_error;
1691 return SYNCTEX_STATUS_OK;
1694 /* parse the post scriptum
1695 * SYNCTEX_STATUS_OK is returned on completion
1696 * a negative error is returned otherwise */
1697 synctex_status_t _synctex_scan_post_scriptum(synctex_scanner_t scanner) {
1698 synctex_status_t status = 0;
1699 char * endptr = NULL;
1700 #ifdef HAVE_SETLOCALE
1701 char * loc = setlocale(LC_NUMERIC, NULL);
1703 if(NULL == scanner) {
1704 return SYNCTEX_STATUS_BAD_ARGUMENT;
1706 /* Scan the file until a post scriptum line is found */
1707 post_scriptum_not_found:
1708 status = _synctex_match_string(scanner,"Post scriptum:");
1709 if(status<SYNCTEX_STATUS_NOT_OK) {
1712 if(status == SYNCTEX_STATUS_NOT_OK) {
1713 status = _synctex_next_line(scanner);
1714 if(status<SYNCTEX_STATUS_EOF) {
1716 } else if(status<SYNCTEX_STATUS_OK) {
1717 return SYNCTEX_STATUS_OK;/* The EOF is found, we have properly scanned the file */
1719 goto post_scriptum_not_found;
1721 /* We found the name, advance to the next line. */
1723 status = _synctex_next_line(scanner);
1724 if(status<SYNCTEX_STATUS_EOF) {
1726 } else if(status<SYNCTEX_STATUS_OK) {
1727 return SYNCTEX_STATUS_OK;/* The EOF is found, we have properly scanned the file */
1729 /* Scanning the information */
1730 status = _synctex_match_string(scanner,"Magnification:");
1731 if(status == SYNCTEX_STATUS_OK ) {
1732 #ifdef HAVE_SETLOCALE
1733 setlocale(LC_NUMERIC, "C");
1735 scanner->unit = strtod(SYNCTEX_CUR,&endptr);
1736 #ifdef HAVE_SETLOCALE
1737 setlocale(LC_NUMERIC, loc);
1739 if(endptr == SYNCTEX_CUR) {
1740 _synctex_error("bad magnification in the post scriptum, a float was expected.");
1741 return SYNCTEX_STATUS_ERROR;
1743 if(scanner->unit<=0) {
1744 _synctex_error("bad magnification in the post scriptum, a positive float was expected.");
1745 return SYNCTEX_STATUS_ERROR;
1747 SYNCTEX_CUR = endptr;
1750 if(status<SYNCTEX_STATUS_EOF){
1751 report_record_problem:
1752 _synctex_error("Problem reading the Post Scriptum records");
1753 return status; /* echo the error. */
1755 status = _synctex_match_string(scanner,"X Offset:");
1756 if(status == SYNCTEX_STATUS_OK) {
1757 status = _synctex_scan_float_and_dimension(scanner, &(scanner->x_offset));
1758 if(status<SYNCTEX_STATUS_OK) {
1759 _synctex_error("problem with X offset in the Post Scriptum.");
1763 } else if(status<SYNCTEX_STATUS_EOF){
1764 goto report_record_problem;
1766 status = _synctex_match_string(scanner,"Y Offset:");
1767 if(status==SYNCTEX_STATUS_OK) {
1768 status = _synctex_scan_float_and_dimension(scanner, &(scanner->y_offset));
1769 if(status<SYNCTEX_STATUS_OK) {
1770 _synctex_error("problem with Y offset in the Post Scriptum.");
1774 } else if(status<SYNCTEX_STATUS_EOF){
1775 goto report_record_problem;
1780 /* SYNCTEX_STATUS_OK is returned if the postamble is read
1781 * SYNCTEX_STATUS_NOT_OK is returned if the postamble is not at the current location
1782 * a negative error otherwise
1783 * The postamble comprises the post scriptum section.
1785 int _synctex_scan_postamble(synctex_scanner_t scanner) {
1787 if(NULL == scanner) {
1788 return SYNCTEX_STATUS_BAD_ARGUMENT;
1790 status = _synctex_match_string(scanner,"Postamble:");
1791 if(status < SYNCTEX_STATUS_OK) {
1795 status = _synctex_next_line(scanner);
1796 if(status < SYNCTEX_STATUS_OK) {
1799 status = _synctex_scan_named(scanner,"Count:",&(scanner->count),(synctex_decoder_t)&_synctex_decode_int);
1800 if(status < SYNCTEX_STATUS_EOF) {
1801 return status; /* forward the error */
1802 } else if(status < SYNCTEX_STATUS_OK) { /* No Count record found */
1803 status = _synctex_next_line(scanner); /* Advance one more line */
1804 if(status<SYNCTEX_STATUS_OK) {
1809 /* Now we scan the last part of the SyncTeX file: the Post Scriptum section. */
1810 return _synctex_scan_post_scriptum(scanner);
1813 /* Horizontal boxes also have visible size.
1814 * Visible size are bigger than real size.
1815 * For example 0 width boxes may contain text.
1816 * At creation time, the visible size is set to the values of the real size.
1818 synctex_status_t _synctex_setup_visible_box(synctex_node_t box) {
1820 switch(box->class->type) {
1821 case synctex_node_type_hbox:
1822 if(SYNCTEX_INFO(box) != NULL) {
1823 SYNCTEX_HORIZ_V(box) = SYNCTEX_HORIZ(box);
1824 SYNCTEX_VERT_V(box) = SYNCTEX_VERT(box);
1825 SYNCTEX_WIDTH_V(box) = SYNCTEX_WIDTH(box);
1826 SYNCTEX_HEIGHT_V(box) = SYNCTEX_HEIGHT(box);
1827 SYNCTEX_DEPTH_V(box) = SYNCTEX_DEPTH(box);
1828 return SYNCTEX_STATUS_OK;
1830 return SYNCTEX_STATUS_ERROR;
1833 return SYNCTEX_STATUS_BAD_ARGUMENT;
1836 /* This method is sent to an horizontal box to setup the visible size
1837 * Some box have 0 width but do contain text material.
1838 * With this method, one can enlarge the box to contain the given point (h,v).
1840 synctex_status_t _synctex_horiz_box_setup_visible(synctex_node_t node,int h, int v) {
1841 # ifdef __DARWIN_UNIX03
1845 if(NULL == node || node->class->type != synctex_node_type_hbox) {
1846 return SYNCTEX_STATUS_BAD_ARGUMENT;
1848 if(SYNCTEX_WIDTH_V(node)<0) {
1849 itsBtm = SYNCTEX_HORIZ_V(node);
1850 itsTop = SYNCTEX_HORIZ_V(node)-SYNCTEX_WIDTH_V(node);
1852 SYNCTEX_HORIZ_V(node) = h;
1853 SYNCTEX_WIDTH_V(node) = SYNCTEX_HORIZ_V(node) - itsTop;
1854 } else if(h>itsTop) {
1855 SYNCTEX_WIDTH_V(node) = SYNCTEX_HORIZ_V(node) - h;
1858 itsBtm = SYNCTEX_HORIZ_V(node);
1859 itsTop = SYNCTEX_HORIZ_V(node)+SYNCTEX_WIDTH_V(node);
1861 SYNCTEX_HORIZ_V(node) = h;
1862 SYNCTEX_WIDTH_V(node) = itsTop - SYNCTEX_HORIZ_V(node);
1863 } else if(h>itsTop) {
1864 SYNCTEX_WIDTH_V(node) = h - SYNCTEX_HORIZ_V(node);
1867 return SYNCTEX_STATUS_OK;
1870 /* Used when parsing the synctex file.
1871 * The sheet argument is a newly created sheet node that will hold the contents.
1872 * Something is returned in case of error.
1874 synctex_status_t _synctex_scan_sheet(synctex_scanner_t scanner, synctex_node_t sheet) {
1875 synctex_node_t parent = sheet;
1876 synctex_node_t child = NULL;
1877 synctex_node_t sibling = NULL;
1878 synctex_node_t box = sheet;
1879 int friend_index = 0;
1880 synctex_info_t * info = NULL;
1881 synctex_status_t status = 0;
1882 size_t available = 0;
1883 if((NULL == scanner) || (NULL == sheet)) {
1884 return SYNCTEX_STATUS_BAD_ARGUMENT;
1886 /* We MUST start with a box, so at this level, the unique possibility is '[', '(' or "}". */
1888 if(SYNCTEX_CUR<SYNCTEX_END) {
1889 if(*SYNCTEX_CUR == '[') {
1892 if((child = _synctex_new_vbox(scanner)) && (info = SYNCTEX_INFO(child))) {
1893 # define SYNCTEX_DECODE_FAILED(WHAT) \
1894 (_synctex_decode_int(scanner,&(info[WHAT].INT))<SYNCTEX_STATUS_OK)
1895 if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
1896 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
1897 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
1898 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
1899 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
1900 || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
1901 || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
1902 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
1903 _synctex_error("Bad vbox record.");
1904 #define SYNCTEX_RETURN(STATUS) return STATUS;
1905 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1907 SYNCTEX_SET_CHILD(parent,child);
1910 goto child_loop;/* next created node will be a child */
1912 _synctex_error("Can't create vbox record.");
1913 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1915 } else if(*SYNCTEX_CUR == '(') {
1918 if((child = _synctex_new_hbox(scanner)) && (info = SYNCTEX_INFO(child))) {
1919 if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
1920 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
1921 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
1922 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
1923 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
1924 || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
1925 || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
1926 || _synctex_setup_visible_box(child)<SYNCTEX_STATUS_OK
1927 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
1928 _synctex_error("Bad hbox record.");
1929 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1931 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
1932 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child));
1933 SYNCTEX_SET_CHILD(parent,child);
1936 goto child_loop;/* next created node will be a child */
1938 _synctex_error("Can't create hbox record.");
1939 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1941 } else if(*SYNCTEX_CUR == '}') {
1944 if(NULL == parent || parent->class->type != synctex_node_type_sheet
1945 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
1946 _synctex_error("Unexpected end of sheet.");
1947 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1949 SYNCTEX_RETURN(SYNCTEX_STATUS_OK);
1950 } else if(*SYNCTEX_CUR == '!') {
1953 if(_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
1954 _synctex_error("Missing anchor.");
1955 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1959 /* _synctex_error("Ignored record %c\n",*SYNCTEX_CUR); */
1961 if(_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
1962 _synctex_error("Unexpected end.");
1963 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1969 status = _synctex_buffer_get_available_size(scanner,&available);
1970 if(status<SYNCTEX_STATUS_OK && available>0){
1971 _synctex_error("Uncomplete sheet(0)");
1972 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1978 /* The child loop means that we go do one level, when we just created a box node,
1979 * the next node created is a child of this box. */
1981 if(SYNCTEX_CUR<SYNCTEX_END) {
1982 if(*SYNCTEX_CUR == '[') {
1984 } else if(*SYNCTEX_CUR == ']') {
1987 if(NULL != parent && parent->class->type == synctex_node_type_vbox) {
1988 #define SYNCTEX_UPDATE_BOX_FRIEND(NODE)\
1989 friend_index = ((SYNCTEX_INFO(NODE))[SYNCTEX_TAG_IDX].INT+(SYNCTEX_INFO(NODE))[SYNCTEX_LINE_IDX].INT)%(scanner->number_of_lists);\
1990 SYNCTEX_SET_FRIEND(NODE,(scanner->lists_of_friends)[friend_index]);\
1991 (scanner->lists_of_friends)[friend_index] = NODE;
1992 if(NULL == SYNCTEX_CHILD(parent)) {
1993 /* only void boxes are friends */
1994 SYNCTEX_UPDATE_BOX_FRIEND(parent);
1997 parent = SYNCTEX_PARENT(child);
1999 _synctex_error("Unexpected ']', ignored.");
2001 if(_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2002 _synctex_error("Uncomplete sheet.");
2003 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2006 } else if(*SYNCTEX_CUR == '(') {
2008 } else if(*SYNCTEX_CUR == ')') {
2011 if((parent) && parent->class->type == synctex_node_type_hbox) {
2013 /* Only boxes with no children are friends,
2014 * boxes with children are indirectly friends through one of their descendants. */
2015 SYNCTEX_UPDATE_BOX_FRIEND(parent);
2017 /* setting the next horizontal box at the end ensures that a child is recorded before any of its ancestors. */
2018 SYNCTEX_SET_NEXT_HORIZ_BOX(box,parent);
2021 parent = SYNCTEX_PARENT(child);
2023 _synctex_error("Unexpected ')', ignored.");
2025 if(_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2026 _synctex_error("Uncomplete sheet.");
2027 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2030 } else if(*SYNCTEX_CUR == 'v') {
2032 if(NULL != (child = _synctex_new_void_vbox(scanner))
2033 && NULL != (info = SYNCTEX_INFO(child))) {
2034 if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2035 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2036 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2037 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2038 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2039 || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2040 || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2041 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2042 _synctex_error("Bad void vbox record.");
2043 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2045 SYNCTEX_SET_CHILD(parent,child);
2046 #define SYNCTEX_UPDATE_FRIEND(NODE)\
2047 friend_index = (info[SYNCTEX_TAG_IDX].INT+info[SYNCTEX_LINE_IDX].INT)%(scanner->number_of_lists);\
2048 SYNCTEX_SET_FRIEND(NODE,(scanner->lists_of_friends)[friend_index]);\
2049 (scanner->lists_of_friends)[friend_index] = NODE;
2050 SYNCTEX_UPDATE_FRIEND(child);
2053 _synctex_error("Can't create vbox record.");
2054 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2056 } else if(*SYNCTEX_CUR == 'h') {
2058 if(NULL != (child = _synctex_new_void_hbox(scanner))
2059 && NULL != (info = SYNCTEX_INFO(child))) {
2060 if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2061 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2062 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2063 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2064 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2065 || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2066 || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2067 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2068 _synctex_error("Bad void hbox record.");
2069 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2071 SYNCTEX_SET_CHILD(parent,child);
2072 SYNCTEX_UPDATE_FRIEND(child);
2073 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2074 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child));
2077 _synctex_error("Can't create void hbox record.");
2078 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2080 } else if(*SYNCTEX_CUR == 'k') {
2082 if(NULL != (child = _synctex_new_kern(scanner))
2083 && NULL != (info = SYNCTEX_INFO(child))) {
2084 if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2085 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2086 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2087 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2088 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2089 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2090 _synctex_error("Bad kern record.");
2091 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2093 SYNCTEX_SET_CHILD(parent,child);
2094 SYNCTEX_UPDATE_FRIEND(child);
2095 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2096 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)-SYNCTEX_WIDTH(child),SYNCTEX_VERT(child));
2099 _synctex_error("Can't create kern record.");
2100 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2102 } else if(*SYNCTEX_CUR == 'g') {
2104 if(NULL != (child = _synctex_new_glue(scanner))
2105 && NULL != (info = SYNCTEX_INFO(child))) {
2106 if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2107 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2108 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2109 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2110 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2111 _synctex_error("Bad glue record.");
2112 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2114 SYNCTEX_SET_CHILD(parent,child);
2115 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2116 SYNCTEX_UPDATE_FRIEND(child);
2119 _synctex_error("Can't create glue record.");
2120 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2122 } else if(*SYNCTEX_CUR == '$') {
2124 if(NULL != (child = _synctex_new_math(scanner))
2125 && NULL != (info = SYNCTEX_INFO(child))) {
2126 if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2127 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2128 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2129 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2130 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2131 _synctex_error("Bad math record.");
2132 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2134 SYNCTEX_SET_CHILD(parent,child);
2135 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2136 SYNCTEX_UPDATE_FRIEND(child);
2139 _synctex_error("Can't create math record.");
2140 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2142 } else if(*SYNCTEX_CUR == 'x') {
2144 if(NULL != (child = _synctex_new_boundary(scanner))
2145 && NULL != (info = SYNCTEX_INFO(child))) {
2146 if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2147 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2148 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2149 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2150 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2151 _synctex_error("Bad boundary record.");
2152 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2154 SYNCTEX_SET_CHILD(parent,child);
2155 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2156 SYNCTEX_UPDATE_FRIEND(child);
2159 _synctex_error("Can't create math record.");
2160 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2162 } else if(*SYNCTEX_CUR == '}') {
2164 } else if(*SYNCTEX_CUR == '!') {
2167 /* _synctex_error("Ignored record %c\n",*SYNCTEX_CUR); */
2169 if(_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2170 _synctex_error("Unexpected end.");
2171 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2177 status = _synctex_buffer_get_available_size(scanner,&available);
2178 if(status<SYNCTEX_STATUS_OK && available>0){
2179 _synctex_error("Uncomplete sheet(0)");
2180 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2186 /* The vertical loop means that we are on the same level, for example when we just ended a box.
2187 * If a node is created now, it will be a sibling of the current node, sharing the same parent. */
2189 if(SYNCTEX_CUR<SYNCTEX_END) {
2190 if(*SYNCTEX_CUR == '[') {
2192 if(NULL != (sibling = _synctex_new_vbox(scanner))
2193 && NULL != (info = SYNCTEX_INFO(sibling))) {
2194 if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2195 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2196 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2197 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2198 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2199 || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2200 || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2201 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2202 _synctex_error("Bad vbox record (2).");
2203 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2205 SYNCTEX_SET_SIBLING(child,sibling);
2210 _synctex_error("Can't create vbox record (2).");
2211 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2213 } else if(*SYNCTEX_CUR == ']') {
2215 } else if(*SYNCTEX_CUR == '(') {
2217 if(NULL != (sibling = _synctex_new_hbox(scanner)) &&
2218 NULL != (info = SYNCTEX_INFO(sibling))) {
2219 if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2220 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2221 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2222 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2223 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2224 || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2225 || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2226 || _synctex_setup_visible_box(sibling)<SYNCTEX_STATUS_OK
2227 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2228 _synctex_error("Bad hbox record (2).");
2229 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2231 SYNCTEX_SET_SIBLING(child,sibling);
2233 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2234 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child));
2239 _synctex_error("Can't create hbox record (2).");
2240 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2242 } else if(*SYNCTEX_CUR == ')') {
2244 } else if(*SYNCTEX_CUR == 'v') {
2246 if(NULL != (sibling = _synctex_new_void_vbox(scanner)) &&
2247 NULL != (info = SYNCTEX_INFO(sibling))) {
2248 if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2249 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2250 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2251 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2252 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2253 || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2254 || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2255 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2256 _synctex_error("Bad void vbox record (2).");
2257 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2259 SYNCTEX_SET_SIBLING(child,sibling);
2261 SYNCTEX_UPDATE_FRIEND(child);
2264 _synctex_error("can't create void vbox record (2).");
2265 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2267 } else if(*SYNCTEX_CUR == 'h') {
2269 if(NULL != (sibling = _synctex_new_void_hbox(scanner)) &&
2270 NULL != (info = SYNCTEX_INFO(sibling))) {
2271 if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2272 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2273 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2274 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2275 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2276 || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2277 || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2278 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2279 _synctex_error("Bad void hbox record (2).");
2280 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2282 SYNCTEX_SET_SIBLING(child,sibling);
2284 SYNCTEX_UPDATE_FRIEND(child);
2285 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2286 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child));
2289 _synctex_error("can't create void hbox record (2).");
2290 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2292 } else if(*SYNCTEX_CUR == 'k') {
2294 if(NULL != (sibling = _synctex_new_kern(scanner))
2295 && NULL != (info = SYNCTEX_INFO(sibling))) {
2296 if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2297 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2298 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2299 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2300 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2301 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2302 _synctex_error("Bad kern record (2).");
2303 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2305 SYNCTEX_SET_SIBLING(child,sibling);
2307 SYNCTEX_UPDATE_FRIEND(child);
2308 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2309 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)-SYNCTEX_WIDTH(child),SYNCTEX_VERT(child));
2312 _synctex_error("Can't create kern record (2).");
2313 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2315 } else if(*SYNCTEX_CUR == 'g') {
2317 if(NULL != (sibling = _synctex_new_glue(scanner))
2318 && NULL != (info = SYNCTEX_INFO(sibling))) {
2319 if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2320 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2321 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2322 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2323 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2324 _synctex_error("Bad glue record (2).");
2325 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2327 SYNCTEX_SET_SIBLING(child,sibling);
2329 SYNCTEX_UPDATE_FRIEND(child);
2330 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2333 _synctex_error("Can't create glue record (2).");
2334 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2336 } else if(*SYNCTEX_CUR == '$') {
2338 if(NULL != (sibling = _synctex_new_math(scanner))
2339 && NULL != (info = SYNCTEX_INFO(sibling))) {
2340 if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2341 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2342 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2343 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2344 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2345 _synctex_error("Bad math record (2).");
2346 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2348 SYNCTEX_SET_SIBLING(child,sibling);
2350 SYNCTEX_UPDATE_FRIEND(child);
2351 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2354 _synctex_error("Can't create math record (2).");
2355 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2357 } else if(*SYNCTEX_CUR == 'x') {
2359 if(NULL != (sibling = _synctex_new_boundary(scanner))
2360 && NULL != (info = SYNCTEX_INFO(sibling))) {
2361 if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2362 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2363 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2364 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2365 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2366 _synctex_error("Bad boundary record (2).");
2367 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2369 SYNCTEX_SET_SIBLING(child,sibling);
2371 SYNCTEX_UPDATE_FRIEND(child);
2372 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2375 _synctex_error("Can't create boundary record (2).");
2376 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2378 } else if(*SYNCTEX_CUR == '}') {
2380 } else if(*SYNCTEX_CUR == '!') {
2382 if(_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2383 _synctex_error("Missing anchor (2).");
2384 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2389 /* _synctex_error("Ignored record %c(2)\n",*SYNCTEX_CUR); */
2390 if(_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2391 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2397 status = _synctex_buffer_get_available_size(scanner,&available);
2398 if(status<SYNCTEX_STATUS_OK && available>0){
2401 _synctex_error("Uncomplete sheet(2)");
2402 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2405 # undef SYNCTEX_DECODE_FAILED
2408 /* Used when parsing the synctex file
2410 synctex_status_t _synctex_scan_content(synctex_scanner_t scanner) {
2411 synctex_node_t sheet = NULL;
2412 synctex_status_t status = 0;
2413 if(NULL == scanner) {
2414 return SYNCTEX_STATUS_BAD_ARGUMENT;
2416 /* set up the lists of friends */
2417 if(NULL == scanner->lists_of_friends) {
2418 scanner->number_of_lists = 1024;
2419 scanner->lists_of_friends = (synctex_node_t *)_synctex_malloc(scanner->number_of_lists*sizeof(synctex_node_t));
2420 if(NULL == scanner->lists_of_friends) {
2421 _synctex_error("malloc:2");
2422 return SYNCTEX_STATUS_ERROR;
2425 /* Find where this section starts */
2427 status = _synctex_match_string(scanner,"Content:");
2428 if(status<SYNCTEX_STATUS_EOF) {
2431 if(_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2432 _synctex_error("Uncomplete Content.");
2433 return SYNCTEX_STATUS_ERROR;
2435 if(status == SYNCTEX_STATUS_NOT_OK) {
2436 goto content_not_found;
2439 if(*SYNCTEX_CUR != '{') {
2440 status = _synctex_scan_postamble(scanner);
2441 if(status < SYNCTEX_STATUS_EOF) {
2442 _synctex_error("Bad content.");
2445 if(status<SYNCTEX_STATUS_OK) {
2446 status = _synctex_next_line(scanner);
2447 if(status < SYNCTEX_STATUS_OK) {
2448 _synctex_error("Bad content.");
2453 return SYNCTEX_STATUS_OK;
2456 /* Create a new sheet node */
2457 sheet = _synctex_new_sheet(scanner);
2458 status = _synctex_decode_int(scanner,&(SYNCTEX_PAGE(sheet)));
2459 if(status<SYNCTEX_STATUS_OK) {
2460 _synctex_error("Missing sheet number.");
2462 SYNCTEX_FREE(sheet);
2463 return SYNCTEX_STATUS_ERROR;
2465 status = _synctex_next_line(scanner);
2466 if(status<SYNCTEX_STATUS_OK) {
2467 _synctex_error("Uncomplete file.");
2470 status = _synctex_scan_sheet(scanner,sheet);
2471 if(status<SYNCTEX_STATUS_OK) {
2472 _synctex_error("Bad sheet content.");
2475 SYNCTEX_SET_SIBLING(sheet,scanner->sheet);
2476 scanner->sheet = sheet;
2478 /* Now read the list of Inputs between 2 sheets. */
2480 status = _synctex_scan_input(scanner);
2481 if(status<SYNCTEX_STATUS_EOF) {
2482 _synctex_error("Bad input section.");
2486 while(status >= SYNCTEX_STATUS_OK);
2490 int _synctex_open(const char * output, const char * build_directory, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_modeRef);
2492 /* Where the synctex scanner is created. */
2493 synctex_scanner_t synctex_scanner_new_with_output_file(const char * output, const char * build_directory, int parse) {
2495 char * synctex = NULL;
2496 synctex_scanner_t scanner = NULL;
2497 synctex_io_mode_t io_mode = synctex_io_mode_read;
2498 /* Here we assume that int are smaller than void * */
2499 if(sizeof(int)>sizeof(void*)) {
2500 _synctex_error("INTERNAL INCONSISTENCY: int's are unexpectedly bigger than pointers, bailing out.");
2503 /* We ensure that SYNCTEX_BUFFER_SIZE < UINT_MAX, I don't know if it makes sense... */
2504 if(SYNCTEX_BUFFER_SIZE >= UINT_MAX) {
2505 _synctex_error("SyncTeX BUG: Internal inconsistency, bad SYNCTEX_BUFFER_SIZE (1)");
2509 if(SYNCTEX_BUFFER_SIZE < SYNCTEX_BUFFER_MIN_SIZE) {
2510 _synctex_error("SyncTeX BUG: Internal inconsistency, bad SYNCTEX_BUFFER_SIZE (2)");
2513 /* now open the synctex file */
2514 if(_synctex_open(output,build_directory,&synctex,&file,synctex_NO,&io_mode) || !file) {
2515 if(_synctex_open(output,build_directory,&synctex,&file,synctex_YES,&io_mode) || !file) {
2519 scanner = (synctex_scanner_t)_synctex_malloc(sizeof(_synctex_scanner_t));
2520 if(NULL == scanner) {
2521 _synctex_error("SyncTeX: malloc problem");
2526 /* make a private copy of output for the scanner */
2527 if(NULL == (scanner->output = (char *)malloc(strlen(output)+1))){
2528 _synctex_error("! synctex_scanner_new_with_output_file: Memory problem (2), scanner's output is not reliable.");
2529 } else if(scanner->output != strcpy(scanner->output,output)) {
2530 _synctex_error("! synctex_scanner_new_with_output_file: Copy problem, scanner's output is not reliable.");
2532 scanner->synctex = synctex;/* Now the scanner owns synctex */
2533 SYNCTEX_FILE = file;
2534 return parse? synctex_scanner_parse(scanner):scanner;
2537 int __synctex_open(const char * output, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_modeRef);
2539 /* This functions opens the file at the "output" given location.
2540 * It manages the problem of quoted filenames that appear with pdftex an filenames containing the space character.
2541 * In TeXLive 2008, the synctex file created with pdftex did contain unexpected quotes.
2542 * This function will remove them if possible.
2543 * 0 on success, non 0 on error. */
2544 int __synctex_open(const char * output, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_modeRef) {
2545 # define synctex_name (*synctex_name_ref)
2546 # define the_file (*file_ref)
2547 if(synctex_name_ref && file_ref) {
2548 char * quoteless = NULL;
2549 synctex_io_mode_t io_mode = *io_modeRef;
2550 const char * mode = synctex_io_modes[io_mode];
2552 /* now create the synctex file name */
2553 size = strlen(output)+strlen(synctex_suffix)+strlen(synctex_suffix_gz)+1;
2554 synctex_name = (char *)malloc(size);
2555 if(NULL == synctex_name) {
2556 _synctex_error("! __synctex_open: Memory problem (1)\n");
2559 /* we have reserved for synctex enough memory to copy output, both suffices and 2 quotes,
2560 * including the terminating character. size is free now. */
2561 if(synctex_name != strcpy(synctex_name,output)) {
2562 _synctex_error("! __synctex_open: Copy problem\n");
2565 synctex_name = NULL;/* Don't forget to reinitialize. */
2566 the_file = NULL; /* Here as well */
2570 /* remove the last path extension if any */
2571 _synctex_strip_last_path_extension(synctex_name);
2572 if(!strlen(synctex_name)) {
2573 goto return_on_error;
2575 /* now insert quotes. */
2577 char * quoted = NULL;
2578 if(_synctex_copy_with_quoting_last_path_component(synctex_name,"ed,size) || (NULL == quoted)) {
2579 /* There was an error or quoting does not make sense: */
2580 goto return_on_error;
2582 quoteless = synctex_name;
2583 synctex_name = quoted;
2585 /* Now add the first path extension. */
2586 if(synctex_name != strcat(synctex_name,synctex_suffix)){
2587 _synctex_error("! __synctex_open: Concatenation problem (can't add suffix '%s')\n",synctex_suffix);
2588 goto return_on_error;
2590 /* To quoteless as well. */
2591 if(quoteless && (quoteless != strcat(quoteless,synctex_suffix))){
2595 if(NULL == (the_file = gzopen(synctex_name,mode))) {
2596 /* Could not open this file */
2597 if(errno != ENOENT) {
2598 /* The file does exist, this is a lower lever error, I can't do anything. */
2599 _synctex_error("SyncTeX: could not open %s, error %i\n",synctex_name,errno);
2600 goto return_on_error;
2602 /* Try the compressed version */
2603 if(synctex_name != strcat(synctex_name,synctex_suffix_gz)){
2604 _synctex_error("! __synctex_open: Concatenation problem (can't add suffix '%s')\n",synctex_suffix_gz);
2605 goto return_on_error;
2608 mode = synctex_io_modes[io_mode]; /* the file is a compressed and is a binary file, this caused errors on Windows */
2609 /* To quoteless as well. */
2610 if(quoteless && (quoteless != strcat(quoteless,synctex_suffix_gz))){
2614 if(NULL == (the_file = gzopen(synctex_name,mode))) {
2615 /* Could not open this file */
2616 if(errno != ENOENT) {
2617 /* The file does exist, this is a lower lever error, I can't do anything. */
2618 _synctex_error("SyncTeX: could not open %s, error %i\n",synctex_name,errno);
2620 goto return_on_error;
2623 /* At this point, the file is properly open.
2624 * If we are in the add_quotes mode, we change the file name by removing the quotes. */
2627 if(rename(synctex_name,quoteless)) {
2628 _synctex_error("SyncTeX: could not rename %s to %s, error %i\n",synctex_name,quoteless,errno);
2629 /* Reopen the file. */
2630 if(NULL == (the_file = gzopen(synctex_name,mode))) {
2631 /* Could not open this file */
2632 if(errno != ENOENT) {
2633 /* The file does exist, this is a lower lever error, I can't do anything. */
2634 _synctex_error("SyncTeX: could not open again %s, error %i\n",synctex_name,errno);
2636 goto return_on_error;
2639 if(NULL == (the_file = gzopen(quoteless,mode))) {
2640 /* Could not open this file */
2641 if(errno != ENOENT) {
2642 /* The file does exist, this is a lower lever error, I can't do anything. */
2643 _synctex_error("SyncTeX: could not open renamed %s, error %i\n",quoteless,errno);
2645 goto return_on_error;
2647 /* The quote free file name should replace the old one:*/
2649 synctex_name = quoteless;
2653 /* We are returning properly so we can also return the proper io_mode */
2654 *io_modeRef = io_mode;
2657 return 3; /* Bad parameter. */
2658 # undef synctex_name
2662 /* Opens the ouput file, taking into account the eventual build_directory.
2663 * 0 on success, non 0 on error. */
2664 int _synctex_open(const char * output, const char * build_directory, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_modeRef) {
2665 # define synctex_name (*synctex_name_ref)
2666 # define the_file (*file_ref)
2667 int result = __synctex_open(output,synctex_name_ref,file_ref,add_quotes,io_modeRef);
2668 if((result || !*file_ref) && build_directory && strlen(build_directory)) {
2669 char * build_output;
2672 synctex_bool_t is_absolute;
2673 build_output = NULL;
2674 lpc = _synctex_last_path_component(output);
2675 size = strlen(build_directory)+strlen(lpc)+2;
2676 is_absolute = _synctex_path_is_absolute(build_directory);
2678 size += strlen(output);
2680 if((build_output = (char *)malloc(size))) {
2682 build_output[0] = '\0';
2684 if(build_output != strcpy(build_output,output)) {
2687 build_output[lpc-output]='\0';
2689 if(build_output == strcat(build_output,build_directory)) {
2690 /* Append a path separator if necessary. */
2691 if(!SYNCTEX_IS_PATH_SEPARATOR(build_output[strlen(build_directory)-1])) {
2692 if(build_output != strcat(build_output,"/")) {
2696 /* Append the last path component of the output. */
2697 if(build_output != strcat(build_output,lpc)) {
2700 return __synctex_open(build_output,synctex_name_ref,file_ref,add_quotes,io_modeRef);
2706 # undef synctex_name
2710 /* The scanner destructor
2712 void synctex_scanner_free(synctex_scanner_t scanner) {
2713 if(NULL == scanner) {
2717 gzclose(SYNCTEX_FILE);
2718 SYNCTEX_FILE = NULL;
2720 SYNCTEX_FREE(scanner->sheet);
2721 SYNCTEX_FREE(scanner->input);
2722 free(SYNCTEX_START);
2723 free(scanner->output_fmt);
2724 free(scanner->output);
2725 free(scanner->synctex);
2726 free(scanner->lists_of_friends);
2730 /* Where the synctex scanner parses the contents of the file. */
2731 synctex_scanner_t synctex_scanner_parse(synctex_scanner_t scanner) {
2732 synctex_status_t status = 0;
2733 if(!scanner || scanner->flags.has_parsed) {
2736 scanner->flags.has_parsed=1;
2737 scanner->pre_magnification = 1000;
2738 scanner->pre_unit = 8192;
2739 scanner->pre_x_offset = scanner->pre_y_offset = 578;
2740 /* initialize the offset with a fake unprobable value,
2741 * If there is a post scriptum section, this value will be overriden by the real life value */
2742 scanner->x_offset = scanner->y_offset = 6.027e23f;
2743 scanner->class[synctex_node_type_sheet] = synctex_class_sheet;
2744 scanner->class[synctex_node_type_input] = synctex_class_input;
2745 (scanner->class[synctex_node_type_input]).scanner = scanner;
2746 (scanner->class[synctex_node_type_sheet]).scanner = scanner;
2747 scanner->class[synctex_node_type_vbox] = synctex_class_vbox;
2748 (scanner->class[synctex_node_type_vbox]).scanner = scanner;
2749 scanner->class[synctex_node_type_void_vbox] = synctex_class_void_vbox;
2750 (scanner->class[synctex_node_type_void_vbox]).scanner = scanner;
2751 scanner->class[synctex_node_type_hbox] = synctex_class_hbox;
2752 (scanner->class[synctex_node_type_hbox]).scanner = scanner;
2753 scanner->class[synctex_node_type_void_hbox] = synctex_class_void_hbox;
2754 (scanner->class[synctex_node_type_void_hbox]).scanner = scanner;
2755 scanner->class[synctex_node_type_kern] = synctex_class_kern;
2756 (scanner->class[synctex_node_type_kern]).scanner = scanner;
2757 scanner->class[synctex_node_type_glue] = synctex_class_glue;
2758 (scanner->class[synctex_node_type_glue]).scanner = scanner;
2759 scanner->class[synctex_node_type_math] = synctex_class_math;
2760 (scanner->class[synctex_node_type_math]).scanner = scanner;
2761 scanner->class[synctex_node_type_boundary] = synctex_class_boundary;
2762 (scanner->class[synctex_node_type_boundary]).scanner = scanner;
2763 SYNCTEX_START = (char *)malloc(SYNCTEX_BUFFER_SIZE+1); /* one more character for null termination */
2764 if(NULL == SYNCTEX_START) {
2765 _synctex_error("SyncTeX: malloc error");
2766 synctex_scanner_free(scanner);
2769 SYNCTEX_END = SYNCTEX_START+SYNCTEX_BUFFER_SIZE;
2770 /* SYNCTEX_END always points to a null terminating character.
2771 * Maybe there is another null terminating character between SYNCTEX_CUR and SYNCTEX_END-1.
2772 * At least, we are sure that SYNCTEX_CUR points to a string covering a valid part of the memory. */
2773 *SYNCTEX_END = '\0';
2774 SYNCTEX_CUR = SYNCTEX_END;
2775 status = _synctex_scan_preamble(scanner);
2776 if(status<SYNCTEX_STATUS_OK) {
2777 _synctex_error("SyncTeX Error: Bad preamble\n");
2779 synctex_scanner_free(scanner);
2782 status = _synctex_scan_content(scanner);
2783 if(status<SYNCTEX_STATUS_OK) {
2784 _synctex_error("SyncTeX Error: Bad content\n");
2787 /* Everything is finished, free the buffer, close the file */
2788 free((void *)SYNCTEX_START);
2789 SYNCTEX_START = SYNCTEX_CUR = SYNCTEX_END = NULL;
2790 gzclose(SYNCTEX_FILE);
2791 SYNCTEX_FILE = NULL;
2792 /* Final tuning: set the default values for various parameters */
2793 /* 1 pre_unit = (scanner->pre_unit)/65536 pt = (scanner->pre_unit)/65781.76 bp
2794 * 1 pt = 65536 sp */
2795 if(scanner->pre_unit<=0) {
2796 scanner->pre_unit = 8192;
2798 if(scanner->pre_magnification<=0) {
2799 scanner->pre_magnification = 1000;
2801 if(scanner->unit <= 0) {
2802 /* no post magnification */
2803 scanner->unit = scanner->pre_unit / 65781.76;/* 65781.76 or 65536.0*/
2805 /* post magnification */
2806 scanner->unit *= scanner->pre_unit / 65781.76;
2808 scanner->unit *= scanner->pre_magnification / 1000.0;
2809 if(scanner->x_offset > 6e23) {
2810 /* no post offset */
2811 scanner->x_offset = scanner->pre_x_offset * (scanner->pre_unit / 65781.76);
2812 scanner->y_offset = scanner->pre_y_offset * (scanner->pre_unit / 65781.76);
2815 scanner->x_offset /= 65781.76f;
2816 scanner->y_offset /= 65781.76f;
2822 /* Scanner accessors.
2824 int synctex_scanner_pre_x_offset(synctex_scanner_t scanner){
2825 return scanner?scanner->pre_x_offset:0;
2827 int synctex_scanner_pre_y_offset(synctex_scanner_t scanner){
2828 return scanner?scanner->pre_y_offset:0;
2830 int synctex_scanner_x_offset(synctex_scanner_t scanner){
2831 return scanner?scanner->x_offset:0;
2833 int synctex_scanner_y_offset(synctex_scanner_t scanner){
2834 return scanner?scanner->y_offset:0;
2836 float synctex_scanner_magnification(synctex_scanner_t scanner){
2837 return scanner?scanner->unit:1;
2839 void synctex_scanner_display(synctex_scanner_t scanner) {
2840 if(NULL == scanner) {
2843 printf("The scanner:\noutput:%s\noutput_fmt:%s\nversion:%i\n",scanner->output,scanner->output_fmt,scanner->version);
2844 printf("pre_unit:%i\nx_offset:%i\ny_offset:%i\n",scanner->pre_unit,scanner->pre_x_offset,scanner->pre_y_offset);
2845 printf("count:%i\npost_magnification:%f\npost_x_offset:%f\npost_y_offset:%f\n",
2846 scanner->count,scanner->unit,scanner->x_offset,scanner->y_offset);
2847 printf("The input:\n");
2848 SYNCTEX_DISPLAY(scanner->input);
2849 if(scanner->count<1000) {
2850 printf("The sheets:\n");
2851 SYNCTEX_DISPLAY(scanner->sheet);
2852 printf("The friends:\n");
2853 if(scanner->lists_of_friends) {
2854 int i = scanner->number_of_lists;
2855 synctex_node_t node;
2857 printf("Friend index:%i\n",i);
2858 node = (scanner->lists_of_friends)[i];
2860 printf("%s:%i,%i\n",
2861 synctex_node_isa(node),
2865 node = SYNCTEX_FRIEND(node);
2870 printf("SyncTeX Warning: Too many objects\n");
2874 const char * synctex_scanner_get_name(synctex_scanner_t scanner,int tag) {
2875 synctex_node_t input = NULL;
2876 if(NULL == scanner) {
2879 input = scanner->input;
2881 if(tag == SYNCTEX_TAG(input)) {
2882 return (SYNCTEX_NAME(input));
2884 } while((input = SYNCTEX_SIBLING(input)) != NULL);
2888 int _synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name);
2889 int _synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name) {
2890 synctex_node_t input = NULL;
2891 if(NULL == scanner) {
2894 input = scanner->input;
2896 if(_synctex_is_equivalent_file_name(name,(SYNCTEX_NAME(input)))) {
2897 return SYNCTEX_TAG(input);
2899 } while((input = SYNCTEX_SIBLING(input)) != NULL);
2903 int synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name) {
2904 size_t char_index = strlen(name);
2905 if((scanner = synctex_scanner_parse(scanner)) && (0 < char_index)) {
2906 /* the name is not void */
2908 if(!SYNCTEX_IS_PATH_SEPARATOR(name[char_index])) {
2909 /* the last character of name is not a path separator */
2910 int result = _synctex_scanner_get_tag(scanner,name);
2914 /* the given name was not the one known by TeX
2915 * try a name relative to the enclosing directory of the scanner->output file */
2916 const char * relative = name;
2917 const char * ptr = scanner->output;
2918 while((strlen(relative) > 0) && (strlen(ptr) > 0) && (*relative == *ptr))
2923 /* Find the last path separator before relative */
2924 while(relative > name) {
2925 if(SYNCTEX_IS_PATH_SEPARATOR(*(relative-1))) {
2930 if((relative > name) && (result = _synctex_scanner_get_tag(scanner,relative))) {
2933 if(SYNCTEX_IS_PATH_SEPARATOR(name[0])) {
2934 /* No tag found for the given absolute name,
2935 * Try each relative path starting from the shortest one */
2936 while(0<char_index) {
2938 if(SYNCTEX_IS_PATH_SEPARATOR(name[char_index])
2939 && (result = _synctex_scanner_get_tag(scanner,name+char_index+1))) {
2950 synctex_node_t synctex_scanner_input(synctex_scanner_t scanner) {
2951 return scanner?scanner->input:NULL;
2953 const char * synctex_scanner_get_output_fmt(synctex_scanner_t scanner) {
2954 return NULL != scanner && scanner->output_fmt?scanner->output_fmt:"";
2956 const char * synctex_scanner_get_output(synctex_scanner_t scanner) {
2957 return NULL != scanner && scanner->output?scanner->output:"";
2959 const char * synctex_scanner_get_synctex(synctex_scanner_t scanner) {
2960 return NULL != scanner && scanner->synctex?scanner->synctex:"";
2962 # ifdef SYNCTEX_NOTHING
2964 # pragma mark Public node attributes
2966 int synctex_node_h(synctex_node_t node){
2970 return SYNCTEX_HORIZ(node);
2972 int synctex_node_v(synctex_node_t node){
2976 return SYNCTEX_VERT(node);
2978 int synctex_node_width(synctex_node_t node){
2982 return SYNCTEX_WIDTH(node);
2984 int synctex_node_box_h(synctex_node_t node){
2988 if(SYNCTEX_IS_BOX(node)) {
2990 return SYNCTEX_HORIZ(node);
2992 if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
2997 int synctex_node_box_v(synctex_node_t node){
3001 if(SYNCTEX_IS_BOX(node)) {
3003 return SYNCTEX_VERT(node);
3005 if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3010 int synctex_node_box_width(synctex_node_t node){
3014 if(SYNCTEX_IS_BOX(node)) {
3016 return SYNCTEX_WIDTH(node);
3018 if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3023 int synctex_node_box_height(synctex_node_t node){
3027 if(SYNCTEX_IS_BOX(node)) {
3029 return SYNCTEX_HEIGHT(node);
3031 if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3036 int synctex_node_box_depth(synctex_node_t node){
3040 if(SYNCTEX_IS_BOX(node)) {
3042 return SYNCTEX_DEPTH(node);
3044 if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3049 # ifdef SYNCTEX_NOTHING
3051 # pragma mark Public node visible attributes
3053 float synctex_node_visible_h(synctex_node_t node){
3057 return SYNCTEX_HORIZ(node)*node->class->scanner->unit+node->class->scanner->x_offset;
3059 float synctex_node_visible_v(synctex_node_t node){
3063 return SYNCTEX_VERT(node)*node->class->scanner->unit+node->class->scanner->y_offset;
3065 float synctex_node_visible_width(synctex_node_t node){
3069 return SYNCTEX_WIDTH(node)*node->class->scanner->unit;
3071 float synctex_node_box_visible_h(synctex_node_t node){
3075 switch(node->class->type) {
3076 case synctex_node_type_vbox:
3077 case synctex_node_type_void_vbox:
3078 case synctex_node_type_void_hbox:
3079 return SYNCTEX_HORIZ(node)*node->class->scanner->unit+node->class->scanner->x_offset;
3080 case synctex_node_type_hbox:
3082 return SYNCTEX_HORIZ_V(node)*node->class->scanner->unit+node->class->scanner->x_offset;
3084 if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3089 float synctex_node_box_visible_v(synctex_node_t node){
3093 switch(node->class->type) {
3094 case synctex_node_type_vbox:
3095 case synctex_node_type_void_vbox:
3096 case synctex_node_type_void_hbox:
3097 return SYNCTEX_VERT(node)*node->class->scanner->unit+node->class->scanner->y_offset;
3098 case synctex_node_type_hbox:
3100 return SYNCTEX_VERT_V(node)*node->class->scanner->unit+node->class->scanner->y_offset;
3102 if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3107 float synctex_node_box_visible_width(synctex_node_t node){
3111 switch(node->class->type) {
3112 case synctex_node_type_vbox:
3113 case synctex_node_type_void_vbox:
3114 case synctex_node_type_void_hbox:
3115 return SYNCTEX_WIDTH(node)*node->class->scanner->unit;
3116 case synctex_node_type_hbox:
3118 return SYNCTEX_WIDTH_V(node)*node->class->scanner->unit;
3120 if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3125 float synctex_node_box_visible_height(synctex_node_t node){
3129 switch(node->class->type) {
3130 case synctex_node_type_vbox:
3131 case synctex_node_type_void_vbox:
3132 case synctex_node_type_void_hbox:
3133 return SYNCTEX_HEIGHT(node)*node->class->scanner->unit;
3134 case synctex_node_type_hbox:
3136 return SYNCTEX_HEIGHT_V(node)*node->class->scanner->unit;
3138 if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3143 float synctex_node_box_visible_depth(synctex_node_t node){
3147 switch(node->class->type) {
3148 case synctex_node_type_vbox:
3149 case synctex_node_type_void_vbox:
3150 case synctex_node_type_void_hbox:
3151 return SYNCTEX_DEPTH(node)*node->class->scanner->unit;
3152 case synctex_node_type_hbox:
3154 return SYNCTEX_DEPTH_V(node)*node->class->scanner->unit;
3156 if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3161 # ifdef SYNCTEX_NOTHING
3163 # pragma mark Other public node attributes
3166 int synctex_node_page(synctex_node_t node){
3167 synctex_node_t parent = NULL;
3171 parent = SYNCTEX_PARENT(node);
3174 parent = SYNCTEX_PARENT(node);
3176 if(node->class->type == synctex_node_type_sheet) {
3177 return SYNCTEX_PAGE(node);
3181 int synctex_node_tag(synctex_node_t node) {
3182 return node?SYNCTEX_TAG(node):-1;
3184 int synctex_node_line(synctex_node_t node) {
3185 return node?SYNCTEX_LINE(node):-1;
3187 int synctex_node_column(synctex_node_t node) {
3188 # ifdef __DARWIN_UNIX03
3189 # pragma unused(node)
3193 # ifdef SYNCTEX_NOTHING
3198 synctex_node_t synctex_sheet_content(synctex_scanner_t scanner,int page) {
3200 synctex_node_t sheet = scanner->sheet;
3202 if(page == SYNCTEX_PAGE(sheet)) {
3203 return SYNCTEX_CHILD(sheet);
3205 sheet = SYNCTEX_SIBLING(sheet);
3211 # ifdef SYNCTEX_NOTHING
3216 int synctex_display_query(synctex_scanner_t scanner,const char * name,int line,int column) {
3217 # ifdef __DARWIN_UNIX03
3218 # pragma unused(column)
3220 int tag = synctex_scanner_get_tag(scanner,name);
3222 int friend_index = 0;
3224 synctex_node_t node = NULL;
3226 printf("SyncTeX Warning: No tag for %s\n",name);
3229 free(SYNCTEX_START);
3230 SYNCTEX_CUR = SYNCTEX_END = SYNCTEX_START = NULL;
3231 max_line = line < INT_MAX-scanner->number_of_lists ? line+scanner->number_of_lists:INT_MAX;
3232 while(line<max_line) {
3233 /* This loop will only be performed once for advanced viewers */
3234 friend_index = (tag+line)%(scanner->number_of_lists);
3235 if((node = (scanner->lists_of_friends)[friend_index])) {
3237 if((synctex_node_type(node)>=synctex_node_type_boundary)
3238 && (tag == SYNCTEX_TAG(node))
3239 && (line == SYNCTEX_LINE(node))) {
3240 if(SYNCTEX_CUR == SYNCTEX_END) {
3242 SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *));
3243 SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START;
3244 SYNCTEX_START = SYNCTEX_END;
3245 SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *);
3247 *(synctex_node_t *)SYNCTEX_CUR = node;
3248 SYNCTEX_CUR += sizeof(synctex_node_t);
3250 } while((node = SYNCTEX_FRIEND(node)));
3251 if(SYNCTEX_START == NULL) {
3252 /* We did not find any matching boundary, retry with glue or kern */
3253 node = (scanner->lists_of_friends)[friend_index];/* no need to test it again, already done */
3255 if((synctex_node_type(node)>=synctex_node_type_kern)
3256 && (tag == SYNCTEX_TAG(node))
3257 && (line == SYNCTEX_LINE(node))) {
3258 if(SYNCTEX_CUR == SYNCTEX_END) {
3260 SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *));
3261 SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START;
3262 SYNCTEX_START = SYNCTEX_END;
3263 SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *);
3265 *(synctex_node_t *)SYNCTEX_CUR = node;
3266 SYNCTEX_CUR += sizeof(synctex_node_t);
3268 } while((node = SYNCTEX_FRIEND(node)));
3269 if(SYNCTEX_START == NULL) {
3270 /* We did not find any matching glue or kern, retry with boxes */
3271 node = (scanner->lists_of_friends)[friend_index];/* no need to test it again, already done */
3273 if((tag == SYNCTEX_TAG(node))
3274 && (line == SYNCTEX_LINE(node))) {
3275 if(SYNCTEX_CUR == SYNCTEX_END) {
3277 SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *));
3278 SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START;
3279 SYNCTEX_START = SYNCTEX_END;
3280 SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *);
3282 *(synctex_node_t *)SYNCTEX_CUR = node;
3283 SYNCTEX_CUR += sizeof(synctex_node_t);
3285 } while((node = SYNCTEX_FRIEND(node)));
3288 SYNCTEX_END = SYNCTEX_CUR;
3289 /* Now reverse the order to have nodes in display order, and keep just a few nodes */
3290 if((SYNCTEX_START) && (SYNCTEX_END))
3292 synctex_node_t * start_ref = (synctex_node_t *)SYNCTEX_START;
3293 synctex_node_t * end_ref = (synctex_node_t *)SYNCTEX_END;
3295 while(start_ref < end_ref) {
3297 *start_ref = *end_ref;
3302 /* Basically, we keep the first node for each parent.
3303 * More precisely, we keep only nodes that are not descendants of
3304 * their predecessor's parent. */
3305 start_ref = (synctex_node_t *)SYNCTEX_START;
3306 end_ref = (synctex_node_t *)SYNCTEX_START;
3308 end_ref += 1; /* we allways have start_ref<= end_ref*/
3309 if(end_ref < (synctex_node_t *)SYNCTEX_END) {
3311 while((node = SYNCTEX_PARENT(node))) {
3312 if(SYNCTEX_PARENT(*start_ref) == node) {
3317 *start_ref = *end_ref;
3321 SYNCTEX_END = (char *)start_ref;
3324 return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t);
3326 # if defined(__SYNCTEX_STRONG_DISPLAY_QUERY__)
3335 synctex_node_t synctex_next_result(synctex_scanner_t scanner) {
3336 if(NULL == SYNCTEX_CUR) {
3337 SYNCTEX_CUR = SYNCTEX_START;
3339 SYNCTEX_CUR+=sizeof(synctex_node_t);
3341 if(SYNCTEX_CUR<SYNCTEX_END) {
3342 return *(synctex_node_t*)SYNCTEX_CUR;
3348 /* This struct records a point in TeX coordinates.*/
3354 /* This struct records distances, the left one is positive or 0 and the right one is negative or 0.
3355 * When comparing the locations of 2 different graphical objects on the page, we will have to also record the
3356 * horizontal distance as signed to keep track of the typesetting order.*/
3360 } synctex_distances_t;
3363 synctex_point_t left;
3364 synctex_point_t right;
3365 } synctex_offsets_t;
3369 synctex_node_t left;
3370 synctex_node_t right;
3371 } synctex_node_set_t;
3373 /* The smallest container between two has the smallest width or height.
3374 * This comparison is used when there are 2 overlapping boxes that contain the hit point.
3375 * For ConTeXt, the problem appears at each page.
3376 * The chosen box is the one with the smallest height, then the smallest width. */
3377 SYNCTEX_INLINE static synctex_node_t _synctex_smallest_container(synctex_node_t node, synctex_node_t other_node);
3379 /* Returns the distance between the hit point hitPoint=(H,V) and the given node. */
3380 synctex_bool_t _synctex_point_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible);
3381 int _synctex_node_distance_to_point(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible);
3383 /* The best container is the deeper box that contains the hit point (H,V).
3384 * _synctex_eq_deepest_container starts with node whereas
3385 * _synctex_box_child_deepest starts with node's children, if any
3386 * if node is not a box, or a void box, NULL is returned.
3387 * We traverse the node tree in a deep first manner and stop as soon as a result is found. */
3388 static synctex_node_t _synctex_eq_deepest_container(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible);
3390 /* Once a best container is found, the closest children are the closest nodes to the left or right of the hit point.
3391 * Only horizontal and vertical offsets are used to compare the positions of the nodes. */
3392 SYNCTEX_INLINE static int _synctex_eq_get_closest_children_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef, synctex_bool_t visible);
3394 /* The closest container is the box that is the one closest to the given point.
3395 * The "visible" version takes into account the visible dimensions instead of the real ones given by TeX. */
3396 SYNCTEX_INLINE static synctex_node_t _synctex_eq_closest_child(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible);
3398 #define SYNCTEX_MASK_LEFT 1
3399 #define SYNCTEX_MASK_RIGHT 2
3401 int synctex_edit_query(synctex_scanner_t scanner,int page,float h,float v) {
3402 synctex_node_t sheet = NULL;
3403 synctex_node_t node = NULL; /* placeholder */
3404 synctex_node_t other_node = NULL; /* placeholder */
3405 synctex_point_t hitPoint = {0,0}; /* placeholder */
3406 synctex_node_set_t bestNodes = {NULL,NULL}; /* holds the best node */
3407 synctex_distances_t bestDistances = {INT_MAX,INT_MAX}; /* holds the best distances for the best node */
3408 synctex_node_t bestContainer = NULL; /* placeholder */
3409 if(NULL == (scanner = synctex_scanner_parse(scanner)) || 0 >= scanner->unit) {/* scanner->unit must be >0 */
3412 /* Convert the given point to scanner integer coordinates */
3413 hitPoint.h = (h-scanner->x_offset)/scanner->unit;
3414 hitPoint.v = (v-scanner->y_offset)/scanner->unit;
3415 /* We will store in the scanner's buffer the result of the query. */
3416 free(SYNCTEX_START);
3417 SYNCTEX_START = SYNCTEX_END = SYNCTEX_CUR = NULL;
3418 /* Find the proper sheet */
3419 sheet = scanner->sheet;
3420 while((sheet) && SYNCTEX_PAGE(sheet) != page) {
3421 sheet = SYNCTEX_SIBLING(sheet);
3426 /* Now sheet points to the sheet node with proper page number */
3427 /* Here is how we work:
3428 * At first we do not consider the visible box dimensions. This will cover the most frequent cases.
3429 * Then we try with the visible box dimensions.
3430 * We try to find a non void box containing the hit point.
3431 * We browse all the horizontal boxes until we find one containing the hit point. */
3432 if((node = SYNCTEX_NEXT_HORIZ_BOX(sheet))) {
3434 if(_synctex_point_in_box(hitPoint,node,synctex_YES)) {
3435 /* Maybe the hitPoint belongs to a contained vertical box. */
3437 /* This trick is for catching overlapping boxes */
3438 if((other_node = SYNCTEX_NEXT_HORIZ_BOX(node))) {
3440 if(_synctex_point_in_box(hitPoint,other_node,synctex_YES)) {
3441 node = _synctex_smallest_container(other_node,node);
3443 } while((other_node = SYNCTEX_NEXT_HORIZ_BOX(other_node)));
3445 /* node is the smallest horizontal box that contains hitPoint. */
3446 if((bestContainer = _synctex_eq_deepest_container(hitPoint,node,synctex_YES))) {
3447 node = bestContainer;
3449 _synctex_eq_get_closest_children_in_box(hitPoint,node,&bestNodes,&bestDistances,synctex_YES);
3450 if(bestNodes.right && bestNodes.left) {
3451 if((SYNCTEX_TAG(bestNodes.right)!=SYNCTEX_TAG(bestNodes.left))
3452 || (SYNCTEX_LINE(bestNodes.right)!=SYNCTEX_LINE(bestNodes.left))
3453 || (SYNCTEX_COLUMN(bestNodes.right)!=SYNCTEX_COLUMN(bestNodes.left))) {
3454 if((SYNCTEX_START = malloc(2*sizeof(synctex_node_t)))) {
3455 if(bestDistances.left>bestDistances.right) {
3456 ((synctex_node_t *)SYNCTEX_START)[0] = bestNodes.right;
3457 ((synctex_node_t *)SYNCTEX_START)[1] = bestNodes.left;
3459 ((synctex_node_t *)SYNCTEX_START)[0] = bestNodes.left;
3460 ((synctex_node_t *)SYNCTEX_START)[1] = bestNodes.right;
3462 SYNCTEX_END = SYNCTEX_START + 2*sizeof(synctex_node_t);
3464 return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t);
3466 return SYNCTEX_STATUS_ERROR;
3468 /* both nodes have the same input coordinates
3469 * We choose the one closest to the hit point */
3470 if(bestDistances.left>bestDistances.right) {
3471 bestNodes.left = bestNodes.right;
3473 bestNodes.right = NULL;
3474 } else if(bestNodes.right) {
3475 bestNodes.left = bestNodes.right;
3476 } else if(!bestNodes.left){
3477 bestNodes.left = node;
3479 if((SYNCTEX_START = malloc(sizeof(synctex_node_t)))) {
3480 * (synctex_node_t *)SYNCTEX_START = bestNodes.left;
3481 SYNCTEX_END = SYNCTEX_START + sizeof(synctex_node_t);
3483 return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t);
3485 return SYNCTEX_STATUS_ERROR;
3487 } while ((node = SYNCTEX_NEXT_HORIZ_BOX(node)));
3488 /* All the horizontal boxes have been tested,
3489 * None of them contains the hit point.
3492 /* We are not lucky */
3493 if((node = SYNCTEX_CHILD(sheet))) {
3499 # ifdef SYNCTEX_NOTHING
3501 # pragma mark Utilities
3504 int _synctex_bail(void) {
3505 _synctex_error("SyncTeX ERROR\n");
3508 /* Rougly speaking, this is:
3509 * node's h coordinate - hitPoint's h coordinate.
3510 * If node is to the right of the hit point, then this distance is positive,
3511 * if node is to the left of the hit point, this distance is negative.*/
3512 int _synctex_point_h_distance(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible);
3513 int _synctex_point_h_distance(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) {
3516 switch(node->class->type) {
3517 /* The distance between a point and a box is special.
3518 * It is not the euclidian distance, nor something similar.
3519 * We have to take into account the particular layout,
3520 * and the box hierarchy.
3521 * Given a box, there are 9 regions delimited by the lines of the edges of the box.
3522 * The origin being at the top left corner of the page,
3523 * we also give names to the vertices of the box.
3532 case synctex_node_type_hbox:
3533 /* getting the box bounds, taking into account negative width, height and depth. */
3534 min = visible?SYNCTEX_HORIZ_V(node):SYNCTEX_HORIZ(node);
3535 max = min + (visible?SYNCTEX_ABS_WIDTH_V(node):SYNCTEX_ABS_WIDTH(node));
3536 /* We allways have min <= max */
3537 if(hitPoint.h<min) {
3538 return min - hitPoint.h; /* regions 1+4+7, result is > 0 */
3539 } else if (hitPoint.h>max) {
3540 return max - hitPoint.h; /* regions 3+6+9, result is < 0 */
3542 return 0; /* regions 2+5+8, inside the box, except for vertical coordinates */
3545 case synctex_node_type_vbox:
3546 case synctex_node_type_void_vbox:
3547 case synctex_node_type_void_hbox:
3548 /* getting the box bounds, taking into account negative width, height and depth.
3549 * For these boxes, no visible dimension available */
3550 min = SYNCTEX_HORIZ(node);
3551 max = min + SYNCTEX_ABS_WIDTH(node);
3552 /* We allways have min <= max */
3553 if(hitPoint.h<min) {
3554 return min - hitPoint.h; /* regions 1+4+7, result is > 0 */
3555 } else if (hitPoint.h>max) {
3556 return max - hitPoint.h; /* regions 3+6+9, result is < 0 */
3558 return 0; /* regions 2+5+8, inside the box, except for vertical coordinates */
3561 case synctex_node_type_kern:
3562 /* IMPORTANT NOTICE: the location of the kern is recorded AFTER the move.
3563 * The distance to the kern is very special,
3564 * in general, there is no text material in the kern,
3565 * this is why we compute the offset relative to the closest edge of the kern.*/
3566 max = SYNCTEX_WIDTH(node);
3568 min = SYNCTEX_HORIZ(node);
3572 max = SYNCTEX_HORIZ(node);
3576 /* positive kern: '.' means text, '>' means kern offset
3580 * negative kern: '.' means text, '<' means kern offset
3581 * ............................
3583 * .................................
3584 * Actually, we do not take into account negative widths.
3585 * There is a problem for such situation when there is efectively overlapping text.
3586 * But this should be extremely rare. I guess that in that case, many different choices
3587 * could be made, one being in contradiction of the other.
3588 * It means that the best choice should be made according to the situation that occurs
3591 if(hitPoint.h<min) {
3592 return min - hitPoint.h + 1; /* penalty to ensure other nodes are chosen first in case of overlapping ones */
3593 } else if (hitPoint.h>max) {
3594 return max - hitPoint.h - 1; /* same kind of penalty */
3595 } else if (hitPoint.h>med) {
3596 /* do things like if the node had 0 width and was placed at the max edge + 1*/
3597 return max - hitPoint.h + 1; /* positive, the kern is to the right of the hitPoint */
3599 return min - hitPoint.h - 1; /* negative, the kern is to the left of the hitPoint */
3601 case synctex_node_type_glue:
3602 case synctex_node_type_math:
3603 return SYNCTEX_HORIZ(node) - hitPoint.h;
3606 return INT_MAX;/* We always assume that the node is faraway to the right*/
3608 /* Rougly speaking, this is:
3609 * node's v coordinate - hitPoint's v coordinate.
3610 * If node is at the top of the hit point, then this distance is positive,
3611 * if node is at the bottom of the hit point, this distance is negative.*/
3612 int _synctex_point_v_distance(synctex_point_t hitPoint, synctex_node_t node,synctex_bool_t visible);
3613 int _synctex_point_v_distance(synctex_point_t hitPoint, synctex_node_t node,synctex_bool_t visible) {
3614 # ifdef __DARWIN_UNIX03
3615 # pragma unused(visible)
3619 switch(node->class->type) {
3620 /* The distance between a point and a box is special.
3621 * It is not the euclidian distance, nor something similar.
3622 * We have to take into account the particular layout,
3623 * and the box hierarchy.
3624 * Given a box, there are 9 regions delimited by the lines of the edges of the box.
3625 * The origin being at the top left corner of the page,
3626 * we also give names to the vertices of the box.
3635 case synctex_node_type_hbox:
3636 /* getting the box bounds, taking into account negative width, height and depth. */
3637 min = SYNCTEX_VERT_V(node);
3638 max = min + SYNCTEX_ABS_DEPTH_V(node);
3639 min -= SYNCTEX_ABS_HEIGHT_V(node);
3640 /* We allways have min <= max */
3641 if(hitPoint.v<min) {
3642 return min - hitPoint.v; /* regions 1+2+3, result is > 0 */
3643 } else if (hitPoint.v>max) {
3644 return max - hitPoint.v; /* regions 7+8+9, result is < 0 */
3646 return 0; /* regions 4.5.6, inside the box, except for horizontal coordinates */
3649 case synctex_node_type_vbox:
3650 case synctex_node_type_void_vbox:
3651 case synctex_node_type_void_hbox:
3652 /* getting the box bounds, taking into account negative width, height and depth. */
3653 min = SYNCTEX_VERT(node);
3654 max = min + SYNCTEX_ABS_DEPTH(node);
3655 min -= SYNCTEX_ABS_HEIGHT(node);
3656 /* We allways have min <= max */
3657 if(hitPoint.v<min) {
3658 return min - hitPoint.v; /* regions 1+2+3, result is > 0 */
3659 } else if (hitPoint.v>max) {
3660 return max - hitPoint.v; /* regions 7+8+9, result is < 0 */
3662 return 0; /* regions 4.5.6, inside the box, except for horizontal coordinates */
3665 case synctex_node_type_kern:
3666 case synctex_node_type_glue:
3667 case synctex_node_type_math:
3668 return SYNCTEX_VERT(node) - hitPoint.v;
3671 return INT_MAX;/* We always assume that the node is faraway to the top*/
3674 SYNCTEX_INLINE static synctex_node_t _synctex_smallest_container(synctex_node_t node, synctex_node_t other_node) {
3675 float height, other_height;
3676 if(SYNCTEX_ABS_WIDTH(node)<SYNCTEX_ABS_WIDTH(other_node)) {
3679 if(SYNCTEX_ABS_WIDTH(node)>SYNCTEX_ABS_WIDTH(other_node)) {
3682 height = SYNCTEX_ABS_DEPTH(node) + SYNCTEX_ABS_HEIGHT(node);
3683 other_height = SYNCTEX_ABS_DEPTH(other_node) + SYNCTEX_ABS_HEIGHT(other_node);
3684 if(height<other_height) {
3687 if(height>other_height) {
3693 synctex_bool_t _synctex_point_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) {
3695 if(0 == _synctex_point_h_distance(hitPoint,node,visible)
3696 && 0 == _synctex_point_v_distance(hitPoint,node,visible)) {
3703 int _synctex_node_distance_to_point(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) {
3704 # ifdef __DARWIN_UNIX03
3705 # pragma unused(visible)
3707 int result = INT_MAX; /* when the distance is meaning less (sheet, input...) */
3709 int minH,maxH,minV,maxV;
3710 switch(node->class->type) {
3711 /* The distance between a point and a box is special.
3712 * It is not the euclidian distance, nor something similar.
3713 * We have to take into account the particular layout,
3714 * and the box hierarchy.
3715 * Given a box, there are 9 regions delimited by the lines of the edges of the box.
3716 * The origin being at the top left corner of the page,
3717 * we also give names to the vertices of the box.
3725 * In each region, there is a different formula.
3726 * In the end we have a continuous distance which may not be a mathematical distance but who cares. */
3727 case synctex_node_type_vbox:
3728 case synctex_node_type_void_vbox:
3729 case synctex_node_type_hbox:
3730 case synctex_node_type_void_hbox:
3731 /* getting the box bounds, taking into account negative widths. */
3732 minH = SYNCTEX_HORIZ(node);
3733 maxH = minH + SYNCTEX_ABS_WIDTH(node);
3734 minV = SYNCTEX_VERT(node);
3735 maxV = minV + SYNCTEX_ABS_DEPTH(node);
3736 minV -= SYNCTEX_ABS_HEIGHT(node);
3737 /* In what region is the point hitPoint=(H,V) ? */
3738 if(hitPoint.v<minV) {
3739 if(hitPoint.h<minH) {
3740 /* This is region 1. The distance to the box is the L1 distance PA. */
3741 result = minV - hitPoint.v + minH - hitPoint.h;/* Integer overflow? probability epsilon */
3742 } else if(hitPoint.h<=maxH) {
3743 /* This is region 2. The distance to the box is the geometrical distance to the top edge. */
3744 result = minV - hitPoint.v;
3746 /* This is region 3. The distance to the box is the L1 distance PB. */
3747 result = minV - hitPoint.v + hitPoint.h - maxH;
3749 } else if(hitPoint.v<=maxV) {
3750 if(hitPoint.h<minH) {
3751 /* This is region 4. The distance to the box is the geometrical distance to the left edge. */
3752 result = minH - hitPoint.h;
3753 } else if(hitPoint.h<=maxH) {
3754 /* This is region 4. We are inside the box. */
3757 /* This is region 6. The distance to the box is the geometrical distance to the right edge. */
3758 result = hitPoint.h - maxH;
3761 if(hitPoint.h<minH) {
3762 /* This is region 7. The distance to the box is the L1 distance PC. */
3763 result = hitPoint.v - maxV + minH - hitPoint.h;
3764 } else if(hitPoint.h<=maxH) {
3765 /* This is region 8. The distance to the box is the geometrical distance to the top edge. */
3766 result = hitPoint.v - maxV;
3768 /* This is region 9. The distance to the box is the L1 distance PD. */
3769 result = hitPoint.v - maxV + hitPoint.h - maxH;
3773 case synctex_node_type_kern:
3774 maxH = SYNCTEX_WIDTH(node);
3776 minH = SYNCTEX_HORIZ(node);
3780 maxH = SYNCTEX_HORIZ(node);
3783 minV = SYNCTEX_VERT(node);
3784 if(hitPoint.h<minH) {
3785 if(hitPoint.v>minV) {
3786 result = hitPoint.v - minV + minH - hitPoint.h;
3788 result = minV - hitPoint.v + minH - hitPoint.h;
3790 } else if (hitPoint.h>maxH) {
3791 if(hitPoint.v>minV) {
3792 result = hitPoint.v - minV + hitPoint.h - maxH;
3794 result = minV - hitPoint.v + hitPoint.h - maxH;
3796 } else if(hitPoint.v>minV) {
3797 result = hitPoint.v - minV;
3799 result = minV - hitPoint.v;
3802 case synctex_node_type_glue:
3803 case synctex_node_type_math:
3804 minH = SYNCTEX_HORIZ(node);
3805 minV = SYNCTEX_VERT(node);
3806 if(hitPoint.h<minH) {
3807 if(hitPoint.v>minV) {
3808 result = hitPoint.v - minV + minH - hitPoint.h;
3810 result = minV - hitPoint.v + minH - hitPoint.h;
3812 } else if(hitPoint.v>minV) {
3813 result = hitPoint.v - minV + hitPoint.h - minH;
3815 result = minV - hitPoint.v + hitPoint.h - minH;
3823 static synctex_node_t _synctex_eq_deepest_container(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible) {
3825 synctex_node_t result = NULL;
3826 synctex_node_t child = NULL;
3827 switch(node->class->type) {
3828 case synctex_node_type_vbox:
3829 case synctex_node_type_hbox:
3830 /* test the deep nodes first */
3831 if((child = SYNCTEX_CHILD(node))) {
3833 if((result = _synctex_eq_deepest_container(hitPoint,child,visible))) {
3836 } while((child = SYNCTEX_SIBLING(child)));
3838 /* is the hit point inside the box? */
3839 if(_synctex_point_in_box(hitPoint,node,visible)) {
3840 /* for vboxes we try to use some node inside.
3841 * Walk through the list of siblings until we find the closest one.
3842 * Only consider siblings with children. */
3843 if((node->class->type == synctex_node_type_vbox) && (child = SYNCTEX_CHILD(node))) {
3844 int bestDistance = INT_MAX;
3846 if(SYNCTEX_CHILD(child)) {
3847 int distance = _synctex_node_distance_to_point(hitPoint,child,visible);
3848 if(distance < bestDistance) {
3849 bestDistance = distance;
3853 } while((child = SYNCTEX_SIBLING(child)));
3862 /* Compares the locations of the hitPoint with the locations of the various nodes contained in the box.
3863 * As it is an horizontal box, we only compare horizontal coordinates. */
3864 SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_hbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef, synctex_bool_t visible);
3865 SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_hbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef, synctex_bool_t visible) {
3867 if((node = SYNCTEX_CHILD(node))) {
3869 int off7 = _synctex_point_h_distance(hitPoint,node,visible);
3871 /* node is to the right of the hit point.
3872 * We compare node and the previously recorded one, through the recorded distance.
3873 * If the nodes have the same tag, prefer the one with the smallest line number,
3874 * if the nodes also have the same line number, prefer the one with the smallest column. */
3875 if(bestDistancesRef->right > off7) {
3876 bestDistancesRef->right = off7;
3877 bestNodesRef->right = node;
3878 result |= SYNCTEX_MASK_RIGHT;
3879 } else if(bestDistancesRef->right == off7 && bestNodesRef->right) {
3880 if(SYNCTEX_TAG(bestNodesRef->right) == SYNCTEX_TAG(node)
3881 && (SYNCTEX_LINE(bestNodesRef->right) > SYNCTEX_LINE(node)
3882 || (SYNCTEX_LINE(bestNodesRef->right) == SYNCTEX_LINE(node)
3883 && SYNCTEX_COLUMN(bestNodesRef->right) > SYNCTEX_COLUMN(node)))) {
3884 bestNodesRef->right = node;
3885 result |= SYNCTEX_MASK_RIGHT;
3888 } else if(off7 == 0) {
3889 /* hitPoint is inside node. */
3890 bestDistancesRef->left = bestDistancesRef->right = 0;
3891 bestNodesRef->left = node;
3892 bestNodesRef->right = NULL;
3893 result |= SYNCTEX_MASK_LEFT;
3894 } else { /* here off7 < 0, hitPoint is to the right of node */
3896 if(bestDistancesRef->left > off7) {
3897 bestDistancesRef->left = off7;
3898 bestNodesRef->left = node;
3899 result |= SYNCTEX_MASK_LEFT;
3900 } else if(bestDistancesRef->left == off7 && bestNodesRef->left) {
3901 if(SYNCTEX_TAG(bestNodesRef->left) == SYNCTEX_TAG(node)
3902 && (SYNCTEX_LINE(bestNodesRef->left) > SYNCTEX_LINE(node)
3903 || (SYNCTEX_LINE(bestNodesRef->left) == SYNCTEX_LINE(node)
3904 && SYNCTEX_COLUMN(bestNodesRef->left) > SYNCTEX_COLUMN(node)))) {
3905 bestNodesRef->left = node;
3906 result |= SYNCTEX_MASK_LEFT;
3910 } while((node = SYNCTEX_SIBLING(node)));
3911 if(result & SYNCTEX_MASK_LEFT) {
3912 /* the left node is new, try to narrow the result */
3913 if((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->left,visible))) {
3914 bestNodesRef->left = node;
3916 if((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->left,visible))) {
3917 bestNodesRef->left = node;
3920 if(result & SYNCTEX_MASK_RIGHT) {
3921 /* the right node is new, try to narrow the result */
3922 if((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->right,visible))) {
3923 bestNodesRef->right = node;
3925 if((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->right,visible))) {
3926 bestNodesRef->right = node;
3932 SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_vbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef,synctex_bool_t visible);
3933 SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_vbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef,synctex_bool_t visible) {
3935 if((node = SYNCTEX_CHILD(node))) {
3937 int off7 = _synctex_point_v_distance(hitPoint,node,visible);/* this is what makes the difference with the h version above */
3939 /* node is to the top of the hit point (below because TeX is oriented from top to bottom.
3940 * We compare node and the previously recorded one, through the recorded distance.
3941 * If the nodes have the same tag, prefer the one with the smallest line number,
3942 * if the nodes also have the same line number, prefer the one with the smallest column. */
3943 if(bestDistancesRef->right > off7) {
3944 bestDistancesRef->right = off7;
3945 bestNodesRef->right = node;
3946 result |= SYNCTEX_MASK_RIGHT;
3947 } else if(bestDistancesRef->right == off7 && bestNodesRef->right) {
3948 if(SYNCTEX_TAG(bestNodesRef->right) == SYNCTEX_TAG(node)
3949 && (SYNCTEX_LINE(bestNodesRef->right) > SYNCTEX_LINE(node)
3950 || (SYNCTEX_LINE(bestNodesRef->right) == SYNCTEX_LINE(node)
3951 && SYNCTEX_COLUMN(bestNodesRef->right) > SYNCTEX_COLUMN(node)))) {
3952 bestNodesRef->right = node;
3953 result |= SYNCTEX_MASK_RIGHT;
3956 } else if(off7 == 0) {
3957 bestDistancesRef->left = bestDistancesRef->right = 0;
3958 bestNodesRef->left = node;
3959 bestNodesRef->right = NULL;
3960 result |= SYNCTEX_MASK_LEFT;
3961 } else { /* here off7 < 0 */
3963 if(bestDistancesRef->left > off7) {
3964 bestDistancesRef->left = off7;
3965 bestNodesRef->left = node;
3966 result |= SYNCTEX_MASK_LEFT;
3967 } else if(bestDistancesRef->left == off7 && bestNodesRef->left) {
3968 if(SYNCTEX_TAG(bestNodesRef->left) == SYNCTEX_TAG(node)
3969 && (SYNCTEX_LINE(bestNodesRef->left) > SYNCTEX_LINE(node)
3970 || (SYNCTEX_LINE(bestNodesRef->left) == SYNCTEX_LINE(node)
3971 && SYNCTEX_COLUMN(bestNodesRef->left) > SYNCTEX_COLUMN(node)))) {
3972 bestNodesRef->left = node;
3973 result |= SYNCTEX_MASK_LEFT;
3977 } while((node = SYNCTEX_SIBLING(node)));
3978 if(result & SYNCTEX_MASK_LEFT) {
3979 /* the left node is new, try to narrow the result */
3980 if((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->left,visible))) {
3981 bestNodesRef->left = node;
3983 if((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->left,visible))) {
3984 bestNodesRef->left = node;
3987 if(result & SYNCTEX_MASK_RIGHT) {
3988 /* the right node is new, try to narrow the result */
3989 if((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->right,visible))) {
3990 bestNodesRef->right = node;
3992 if((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->right,visible))) {
3993 bestNodesRef->right = node;
3999 SYNCTEX_INLINE static int _synctex_eq_get_closest_children_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef,synctex_bool_t visible) {
4001 switch(node->class->type) {
4002 case synctex_node_type_hbox:
4003 return __synctex_eq_get_closest_children_in_hbox(hitPoint, node, bestNodesRef, bestDistancesRef,visible);
4004 case synctex_node_type_vbox:
4005 return __synctex_eq_get_closest_children_in_vbox(hitPoint, node, bestNodesRef, bestDistancesRef,visible);
4011 SYNCTEX_INLINE static synctex_node_t __synctex_eq_closest_child(synctex_point_t hitPoint, synctex_node_t node,int* distanceRef, synctex_bool_t visible);
4012 SYNCTEX_INLINE static synctex_node_t __synctex_eq_closest_child(synctex_point_t hitPoint, synctex_node_t node,int* distanceRef, synctex_bool_t visible) {
4013 synctex_node_t best_node = NULL;
4014 if((node = SYNCTEX_CHILD(node))) {
4016 int distance = _synctex_node_distance_to_point(hitPoint,node,visible);
4017 synctex_node_t candidate = NULL;
4018 if(distance<=*distanceRef) {
4019 *distanceRef = distance;
4022 switch(node->class->type) {
4023 case synctex_node_type_vbox:
4024 case synctex_node_type_hbox:
4025 if((candidate = __synctex_eq_closest_child(hitPoint,node,distanceRef,visible))) {
4026 best_node = candidate;
4029 } while((node = SYNCTEX_SIBLING(node)));
4033 SYNCTEX_INLINE static synctex_node_t _synctex_eq_closest_child(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible) {
4035 switch(node->class->type) {
4036 case synctex_node_type_hbox:
4037 case synctex_node_type_vbox:
4039 int best_distance = INT_MAX;
4040 synctex_node_t best_node = __synctex_eq_closest_child(hitPoint,node,&best_distance,visible);
4042 synctex_node_t child = NULL;
4043 switch(best_node->class->type) {
4044 case synctex_node_type_vbox:
4045 case synctex_node_type_hbox:
4046 if((child = SYNCTEX_CHILD(best_node))) {
4047 best_distance = _synctex_node_distance_to_point(hitPoint,child,visible);
4048 while((child = SYNCTEX_SIBLING(child))) {
4049 int distance = _synctex_node_distance_to_point(hitPoint,child,visible);
4050 if(distance<=best_distance) {
4051 best_distance = distance;
4065 # ifdef SYNCTEX_NOTHING
4067 # pragma mark Updater
4070 typedef int (*synctex_fprintf_t)(void *, const char * , ...); /* print formatted to either FILE * or gzFile */
4072 # define SYNCTEX_BITS_PER_BYTE 8
4074 struct __synctex_updater_t {
4075 void *file; /* the foo.synctex or foo.synctex.gz I/O identifier */
4076 synctex_fprintf_t fprintf; /* either fprintf or gzprintf */
4077 int length; /* the number of chars appended */
4079 unsigned int no_gz:1; /* Whether zlib is used or not */
4080 unsigned int reserved:SYNCTEX_BITS_PER_BYTE*sizeof(int)-1; /* Align */
4083 # define SYNCTEX_FILE updater->file
4084 # define SYNCTEX_NO_GZ ((updater->flags).no_gz)
4085 # define SYNCTEX_fprintf (*(updater->fprintf))
4087 synctex_updater_t synctex_updater_new_with_output_file(const char * output, const char * build_directory) {
4088 synctex_updater_t updater = NULL;
4089 char * synctex = NULL;
4090 synctex_io_mode_t io_mode = synctex_io_mode_read;
4092 /* prepare the updater */
4093 updater = (synctex_updater_t)_synctex_malloc(sizeof(synctex_updater_t));
4094 if(NULL == updater) {
4095 _synctex_error("! synctex_updater_new_with_file: malloc problem");
4098 if(_synctex_open(output,build_directory,&synctex,&SYNCTEX_FILE,synctex_NO,&io_mode)
4099 && _synctex_open(output,build_directory,&synctex,&SYNCTEX_FILE,synctex_YES,&io_mode)) {
4104 /* OK, the file exists */
4105 gzclose(SYNCTEX_FILE);
4106 SYNCTEX_FILE = NULL;
4107 SYNCTEX_NO_GZ = io_mode%2?synctex_NO:synctex_YES;
4108 mode = synctex_io_modes[io_mode+synctex_io_mode_append];/* either "a" or "ab", depending on the file extension */
4110 if(NULL == (SYNCTEX_FILE = (void *)fopen(synctex,mode))) {
4112 _synctex_error("! synctex_updater_new_with_file: Can't append to %s",synctex);
4114 goto return_on_error;
4116 updater->fprintf = (synctex_fprintf_t)(&fprintf);
4118 if(NULL == (SYNCTEX_FILE = (void *)gzopen(synctex,mode))) {
4119 goto no_write_error;
4121 updater->fprintf = (synctex_fprintf_t)(&gzprintf);
4123 printf("SyncTeX: updating %s...",synctex);
4129 void synctex_updater_append_magnification(synctex_updater_t updater, char * magnification){
4133 if(magnification && strlen(magnification)) {
4134 updater->length += SYNCTEX_fprintf(SYNCTEX_FILE,"Magnification:%s\n",magnification);
4138 void synctex_updater_append_x_offset(synctex_updater_t updater, char * x_offset){
4142 if(x_offset && strlen(x_offset)) {
4143 updater->length += SYNCTEX_fprintf(SYNCTEX_FILE,"X Offset:%s\n",x_offset);
4147 void synctex_updater_append_y_offset(synctex_updater_t updater, char * y_offset){
4151 if(y_offset && strlen(y_offset)) {
4152 updater->length += SYNCTEX_fprintf(SYNCTEX_FILE,"Y Offset:%s\n",y_offset);
4156 void synctex_updater_free(synctex_updater_t updater){
4160 if(updater->length>0) {
4161 SYNCTEX_fprintf(SYNCTEX_FILE,"!%i\n",updater->length);
4163 if (SYNCTEX_NO_GZ) {
4164 fclose((FILE *)SYNCTEX_FILE);
4166 gzclose((gzFile)SYNCTEX_FILE);
4169 printf("... done.\n");