2 Copyright (c) 2008, 2009, 2010 , 2011 jerome DOT laurens AT u-bourgogne DOT fr
4 This file is part of the SyncTeX package.
6 Latest Revision: Fri Mar 11 07:39:12 UTC 2011
10 See synctex_parser_readme.txt for more details
14 Permission is hereby granted, free of charge, to any person
15 obtaining a copy of this software and associated documentation
16 files (the "Software"), to deal in the Software without
17 restriction, including without limitation the rights to use,
18 copy, modify, merge, publish, distribute, sublicense, and/or sell
19 copies of the Software, and to permit persons to whom the
20 Software is furnished to do so, subject to the following
23 The above copyright notice and this permission notice shall be
24 included in all copies or substantial portions of the Software.
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
28 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
30 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
31 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33 OTHER DEALINGS IN THE SOFTWARE
35 Except as contained in this notice, the name of the copyright holder
36 shall not be used in advertising or otherwise to promote the sale,
37 use or other dealings in this Software without prior written
38 authorization from the copyright holder.
42 The author received useful remarks from the pdfTeX developers, especially Hahn The Thanh,
43 and significant help from XeTeX developer Jonathan Kew
47 If you include or use a significant part of the synctex package into a software,
48 I would appreciate to be listed as contributor and see "SyncTeX" highlighted.
51 Thu Jun 19 09:39:21 UTC 2008
55 /* We assume that high level application like pdf viewers will want
56 * to embed this code as is. We assume that they also have locale.h and setlocale.
57 * For other tools such as TeXLive tools, you must define SYNCTEX_USE_LOCAL_HEADER,
58 * when building. You also have to create and customize synctex_parser_local.h to fit your system.
59 * In particular, the HAVE_LOCALE_H and HAVE_SETLOCALE macros should be properly defined.
60 * With this design, you should not need to edit this file. */
62 # if defined(SYNCTEX_USE_LOCAL_HEADER)
63 # include "synctex_parser_local.h"
65 # define HAVE_LOCALE_H 1
66 # define HAVE_SETLOCALE 1
67 # if defined(_MSC_VER)
68 # define SYNCTEX_INLINE __inline
70 # define SYNCTEX_INLINE inline
80 #if defined(HAVE_LOCALE_H)
84 /* The data is organized in a graph with multiple entries.
85 * The root object is a scanner, it is created with the contents on a synctex file.
86 * Each leaf of the tree is a synctex_node_t object.
87 * There are 3 subtrees, two of them sharing the same leaves.
88 * The first tree is the list of input records, where input file names are associated with tags.
89 * The second tree is the box tree as given by TeX when shipping pages out.
90 * First level objects are sheets, containing boxes, glues, kerns...
91 * The third tree allows to browse leaves according to tag and line.
94 #include "synctex_parser.h"
95 #include "synctex_parser_utils.h"
97 /* These are the possible extensions of the synctex file */
98 const char * synctex_suffix = ".synctex";
99 const char * synctex_suffix_gz = ".gz";
101 /* each synctex node has a class */
102 typedef struct __synctex_class_t _synctex_class_t;
103 typedef _synctex_class_t * synctex_class_t;
106 /* synctex_node_t is a pointer to a node
107 * _synctex_node is the target of the synctex_node_t pointer
108 * It is a pseudo object oriented program.
109 * class is a pointer to the class object the node belongs to.
110 * implementation is meant to contain the private data of the node
111 * basically, there are 2 kinds of information: navigation information and
112 * synctex information. Both will depend on the type of the node,
113 * thus different nodes will have different private data.
114 * There is no inheritancy overhead.
116 typedef union _synctex_info_t {
121 struct _synctex_node {
122 synctex_class_t class;
123 synctex_info_t * implementation;
126 /* Each node of the tree, except the scanner itself belongs to a class.
127 * The class object is just a struct declaring the owning scanner
128 * This is a pointer to the scanner as root of the tree.
129 * The type is used to identify the kind of node.
130 * The class declares pointers to a creator and a destructor method.
131 * The log and display fields are used to log and display the node.
132 * display will also display the child, sibling and parent sibling.
133 * parent, child and sibling are used to navigate the tree,
134 * from TeX box hierarchy point of view.
135 * The friend field points to a method which allows to navigate from friend to friend.
136 * A friend is a node with very close tag and line numbers.
137 * Finally, the info field point to a method giving the private node info offset.
140 typedef synctex_node_t *(*_synctex_node_getter_t)(synctex_node_t);
141 typedef synctex_info_t *(*_synctex_info_getter_t)(synctex_node_t);
143 struct __synctex_class_t {
144 synctex_scanner_t scanner;
146 synctex_node_t (*new)(synctex_scanner_t scanner);
147 void (*free)(synctex_node_t);
148 void (*log)(synctex_node_t);
149 void (*display)(synctex_node_t);
150 _synctex_node_getter_t parent;
151 _synctex_node_getter_t child;
152 _synctex_node_getter_t sibling;
153 _synctex_node_getter_t friend;
154 _synctex_node_getter_t next_box;
155 _synctex_info_getter_t info;
158 # ifdef SYNCTEX_NOTHING
160 # pragma mark Abstract OBJECTS and METHODS
163 /* These macros are shortcuts
164 * This macro checks if a message can be sent.
166 # define SYNCTEX_CAN_PERFORM(NODE,SELECTOR)\
167 (NULL!=((((NODE)->class))->SELECTOR))
169 /* This macro is some kind of objc_msg_send.
170 * It takes care of sending the proper message if possible.
172 # define SYNCTEX_MSG_SEND(NODE,SELECTOR) if (NODE && SYNCTEX_CAN_PERFORM(NODE,SELECTOR)) {\
173 (*((((NODE)->class))->SELECTOR))(NODE);\
176 /* read only safe getter
178 # define SYNCTEX_GET(NODE,SELECTOR)((NODE && SYNCTEX_CAN_PERFORM(NODE,SELECTOR))?SYNCTEX_GETTER(NODE,SELECTOR)[0]:(NULL))
182 # define SYNCTEX_GETTER(NODE,SELECTOR)\
183 ((synctex_node_t *)((*((((NODE)->class))->SELECTOR))(NODE)))
185 # define SYNCTEX_FREE(NODE) SYNCTEX_MSG_SEND(NODE,free);
187 /* Parent getter and setter
189 # define SYNCTEX_PARENT(NODE) SYNCTEX_GET(NODE,parent)
190 # define SYNCTEX_SET_PARENT(NODE,NEW_PARENT) if (NODE && NEW_PARENT && SYNCTEX_CAN_PERFORM(NODE,parent)){\
191 SYNCTEX_GETTER(NODE,parent)[0]=NEW_PARENT;\
194 /* Child getter and setter
196 # define SYNCTEX_CHILD(NODE) SYNCTEX_GET(NODE,child)
197 # define SYNCTEX_SET_CHILD(NODE,NEW_CHILD) if (NODE && NEW_CHILD){\
198 SYNCTEX_GETTER(NODE,child)[0]=NEW_CHILD;\
199 SYNCTEX_GETTER(NEW_CHILD,parent)[0]=NODE;\
202 /* Sibling getter and setter
204 # define SYNCTEX_SIBLING(NODE) SYNCTEX_GET(NODE,sibling)
205 # define SYNCTEX_SET_SIBLING(NODE,NEW_SIBLING) if (NODE && NEW_SIBLING) {\
206 SYNCTEX_GETTER(NODE,sibling)[0]=NEW_SIBLING;\
207 if (SYNCTEX_CAN_PERFORM(NEW_SIBLING,parent) && SYNCTEX_CAN_PERFORM(NODE,parent)) {\
208 SYNCTEX_GETTER(NEW_SIBLING,parent)[0]=SYNCTEX_GETTER(NODE,parent)[0];\
211 /* Friend getter and setter. A friend is a kern, math, glue or void box node which tag and line numbers are similar.
212 * This is a first filter on the nodes that avoids testing all of them.
213 * Friends are used mainly in forward synchronization aka from source to output.
215 # define SYNCTEX_FRIEND(NODE) SYNCTEX_GET(NODE,friend)
216 # define SYNCTEX_SET_FRIEND(NODE,NEW_FRIEND) if (NODE && NEW_FRIEND){\
217 SYNCTEX_GETTER(NODE,friend)[0]=NEW_FRIEND;\
220 /* Next box getter and setter. The box tree can be traversed from one horizontal box to the other.
221 * Navigation starts with the deeper boxes.
223 # define SYNCTEX_NEXT_HORIZ_BOX(NODE) SYNCTEX_GET(NODE,next_box)
224 # define SYNCTEX_SET_NEXT_HORIZ_BOX(NODE,NEXT_BOX) if (NODE && NEXT_BOX){\
225 SYNCTEX_GETTER(NODE,next_box)[0]=NEXT_BOX;\
228 void _synctex_free_node(synctex_node_t node);
229 void _synctex_free_leaf(synctex_node_t node);
231 /* A node is meant to own its child and sibling.
232 * It is not owned by its parent, unless it is its first child.
233 * This destructor is for all nodes with children.
235 void _synctex_free_node(synctex_node_t node) {
237 (*((node->class)->sibling))(node);
238 SYNCTEX_FREE(SYNCTEX_SIBLING(node));
239 SYNCTEX_FREE(SYNCTEX_CHILD(node));
245 /* A node is meant to own its child and sibling.
246 * It is not owned by its parent, unless it is its first child.
247 * This destructor is for nodes with no child.
249 void _synctex_free_leaf(synctex_node_t node) {
251 SYNCTEX_FREE(SYNCTEX_SIBLING(node));
256 # ifdef __SYNCTEX_WORK__
257 # include "/usr/include/zlib.h"
262 /* The synctex scanner is the root object.
263 * Is is initialized with the contents of a text file or a gzipped file.
264 * The buffer_? are first used to parse the text.
266 struct __synctex_scanner_t {
267 gzFile file; /* The (possibly compressed) file */
268 char * buffer_cur; /* current location in the buffer */
269 char * buffer_start; /* start of the buffer */
270 char * buffer_end; /* end of the buffer */
271 char * output_fmt; /* dvi or pdf, not yet used */
272 char * output; /* the output name used to create the scanner */
273 char * synctex; /* the .synctex or .synctex.gz name used to create the scanner */
274 int version; /* 1, not yet used */
276 unsigned has_parsed:1; /* Whether the scanner has parsed its underlying synctex file. */
277 unsigned reserved:sizeof(unsigned)-1; /* alignment */
279 int pre_magnification; /* magnification from the synctex preamble */
280 int pre_unit; /* unit from the synctex preamble */
281 int pre_x_offset; /* X offste from the synctex preamble */
282 int pre_y_offset; /* Y offset from the synctex preamble */
283 int count; /* Number of records, from the synctex postamble */
284 float unit; /* real unit, from synctex preamble or post scriptum */
285 float x_offset; /* X offset, from synctex preamble or post scriptum */
286 float y_offset; /* Y Offset, from synctex preamble or post scriptum */
287 synctex_node_t sheet; /* The first sheet node, its siblings are the other sheet nodes */
288 synctex_node_t input; /* The first input node, its siblings are the other input nodes */
289 int number_of_lists; /* The number of friend lists */
290 synctex_node_t * lists_of_friends;/* The friend lists */
291 _synctex_class_t class[synctex_node_number_of_types]; /* The classes of the nodes of the scanner */
294 /* SYNCTEX_CUR, SYNCTEX_START and SYNCTEX_END are convenient shortcuts
296 # define SYNCTEX_CUR (scanner->buffer_cur)
297 # define SYNCTEX_START (scanner->buffer_start)
298 # define SYNCTEX_END (scanner->buffer_end)
300 # ifdef SYNCTEX_NOTHING
302 # pragma mark OBJECTS, their creators and destructors.
305 /* Here, we define the indices for the different informations.
306 * They are used to declare the size of the implementation.
307 * For example, if one object uses SYNCTEX_HORIZ_IDX is its size,
308 * then its info will contain a tag, line, column, horiz but no width nor height nor depth
311 /* The sheet is a first level node.
312 * It has no parent (the parent is the scanner itself)
313 * Its sibling points to another sheet.
314 * Its child points to its first child, in general a box.
315 * A sheet node contains only one synctex information: the page.
316 * This is the 1 based page index as given by TeX.
318 /* The next macros are used to access the node info
319 * SYNCTEX_INFO(node) points to the first synctex integer or pointer data of node
320 * SYNCTEX_INFO(node)[index] is the information at index
321 * for example, the page of a sheet is stored in SYNCTEX_INFO(sheet)[SYNCTEX_PAGE_IDX]
323 # define SYNCTEX_INFO(NODE) ((*((((NODE)->class))->info))(NODE))
324 # define SYNCTEX_PAGE_IDX 0
325 # define SYNCTEX_PAGE(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_PAGE_IDX].INT
327 /* This macro defines implementation offsets
328 * It is only used for pointer values
330 # define SYNCTEX_MAKE_GET(SYNCTEX_GETTER,OFFSET)\
331 synctex_node_t * SYNCTEX_GETTER (synctex_node_t node);\
332 synctex_node_t * SYNCTEX_GETTER (synctex_node_t node) {\
333 return node?(synctex_node_t *)((&((node)->implementation))+OFFSET):NULL;\
335 SYNCTEX_MAKE_GET(_synctex_implementation_0,0)
336 SYNCTEX_MAKE_GET(_synctex_implementation_1,1)
337 SYNCTEX_MAKE_GET(_synctex_implementation_2,2)
338 SYNCTEX_MAKE_GET(_synctex_implementation_3,3)
339 SYNCTEX_MAKE_GET(_synctex_implementation_4,4)
340 SYNCTEX_MAKE_GET(_synctex_implementation_5,5)
343 synctex_class_t class;
344 synctex_info_t implementation[3+SYNCTEX_PAGE_IDX+1];/* child, sibling, next box,
345 * SYNCTEX_PAGE_IDX */
348 synctex_node_t _synctex_new_sheet(synctex_scanner_t scanner);
349 void _synctex_display_sheet(synctex_node_t sheet);
350 void _synctex_log_sheet(synctex_node_t sheet);
352 static _synctex_class_t synctex_class_sheet = {
353 NULL, /* No scanner yet */
354 synctex_node_type_sheet, /* Node type */
355 &_synctex_new_sheet, /* creator */
356 &_synctex_free_node, /* destructor */
357 &_synctex_log_sheet, /* log */
358 &_synctex_display_sheet, /* display */
359 NULL, /* No parent */
360 &_synctex_implementation_0, /* child */
361 &_synctex_implementation_1, /* sibling */
362 NULL, /* No friend */
363 &_synctex_implementation_2, /* Next box */
364 (_synctex_info_getter_t)&_synctex_implementation_3 /* info */
367 /* sheet node creator */
368 synctex_node_t _synctex_new_sheet(synctex_scanner_t scanner) {
369 synctex_node_t node = _synctex_malloc(sizeof(synctex_sheet_t));
371 node->class = scanner?scanner->class+synctex_node_type_sheet:(synctex_class_t)&synctex_class_sheet;
376 /* A box node contains navigation and synctex information
377 * There are different kind of boxes.
378 * Only horizontal boxes are treated differently because of their visible size.
380 # define SYNCTEX_TAG_IDX 0
381 # define SYNCTEX_LINE_IDX (SYNCTEX_TAG_IDX+1)
382 # define SYNCTEX_COLUMN_IDX (SYNCTEX_LINE_IDX+1)
383 # define SYNCTEX_HORIZ_IDX (SYNCTEX_COLUMN_IDX+1)
384 # define SYNCTEX_VERT_IDX (SYNCTEX_HORIZ_IDX+1)
385 # define SYNCTEX_WIDTH_IDX (SYNCTEX_VERT_IDX+1)
386 # define SYNCTEX_HEIGHT_IDX (SYNCTEX_WIDTH_IDX+1)
387 # define SYNCTEX_DEPTH_IDX (SYNCTEX_HEIGHT_IDX+1)
388 /* the corresponding info accessors */
389 # define SYNCTEX_TAG(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_TAG_IDX].INT
390 # define SYNCTEX_LINE(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_LINE_IDX].INT
391 # define SYNCTEX_COLUMN(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_COLUMN_IDX].INT
392 # define SYNCTEX_HORIZ(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HORIZ_IDX].INT
393 # define SYNCTEX_VERT(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_VERT_IDX].INT
394 # define SYNCTEX_WIDTH(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_WIDTH_IDX].INT
395 # define SYNCTEX_HEIGHT(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HEIGHT_IDX].INT
396 # define SYNCTEX_DEPTH(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_DEPTH_IDX].INT
397 # define SYNCTEX_ABS_WIDTH(NODE) ((SYNCTEX_WIDTH(NODE)>0?SYNCTEX_WIDTH(NODE):-SYNCTEX_WIDTH(NODE)))
398 # define SYNCTEX_ABS_HEIGHT(NODE) ((SYNCTEX_HEIGHT(NODE)>0?SYNCTEX_HEIGHT(NODE):-SYNCTEX_HEIGHT(NODE)))
399 # define SYNCTEX_ABS_DEPTH(NODE) ((SYNCTEX_DEPTH(NODE)>0?SYNCTEX_DEPTH(NODE):-SYNCTEX_DEPTH(NODE)))
402 synctex_class_t class;
403 synctex_info_t implementation[5+SYNCTEX_DEPTH_IDX+1]; /* parent,child,sibling,friend,next box,
404 * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
405 * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH */
406 } synctex_vert_box_node_t;
408 synctex_node_t _synctex_new_vbox(synctex_scanner_t scanner);
409 void _synctex_log_box(synctex_node_t sheet);
410 void _synctex_display_vbox(synctex_node_t node);
412 /* These are static class objects, each scanner will make a copy of them and setup the scanner field.
414 static _synctex_class_t synctex_class_vbox = {
415 NULL, /* No scanner yet */
416 synctex_node_type_vbox, /* Node type */
417 &_synctex_new_vbox, /* creator */
418 &_synctex_free_node, /* destructor */
419 &_synctex_log_box, /* log */
420 &_synctex_display_vbox, /* display */
421 &_synctex_implementation_0, /* parent */
422 &_synctex_implementation_1, /* child */
423 &_synctex_implementation_2, /* sibling */
424 &_synctex_implementation_3, /* friend */
425 &_synctex_implementation_4, /* next box */
426 (_synctex_info_getter_t)&_synctex_implementation_5
429 /* vertical box node creator */
430 synctex_node_t _synctex_new_vbox(synctex_scanner_t scanner) {
431 synctex_node_t node = _synctex_malloc(sizeof(synctex_vert_box_node_t));
433 node->class = scanner?scanner->class+synctex_node_type_vbox:(synctex_class_t)&synctex_class_vbox;
438 # define SYNCTEX_HORIZ_V_IDX (SYNCTEX_DEPTH_IDX+1)
439 # define SYNCTEX_VERT_V_IDX (SYNCTEX_HORIZ_V_IDX+1)
440 # define SYNCTEX_WIDTH_V_IDX (SYNCTEX_VERT_V_IDX+1)
441 # define SYNCTEX_HEIGHT_V_IDX (SYNCTEX_WIDTH_V_IDX+1)
442 # define SYNCTEX_DEPTH_V_IDX (SYNCTEX_HEIGHT_V_IDX+1)
443 /* the corresponding info accessors */
444 # define SYNCTEX_HORIZ_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HORIZ_V_IDX].INT
445 # define SYNCTEX_VERT_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_VERT_V_IDX].INT
446 # define SYNCTEX_WIDTH_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_WIDTH_V_IDX].INT
447 # define SYNCTEX_HEIGHT_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HEIGHT_V_IDX].INT
448 # define SYNCTEX_DEPTH_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_DEPTH_V_IDX].INT
449 # define SYNCTEX_ABS_WIDTH_V(NODE) ((SYNCTEX_WIDTH_V(NODE)>0?SYNCTEX_WIDTH_V(NODE):-SYNCTEX_WIDTH_V(NODE)))
450 # define SYNCTEX_ABS_HEIGHT_V(NODE) ((SYNCTEX_HEIGHT_V(NODE)>0?SYNCTEX_HEIGHT_V(NODE):-SYNCTEX_HEIGHT_V(NODE)))
451 # define SYNCTEX_ABS_DEPTH_V(NODE) ((SYNCTEX_DEPTH_V(NODE)>0?SYNCTEX_DEPTH_V(NODE):-SYNCTEX_DEPTH_V(NODE)))
453 /* Horizontal boxes must contain visible size, because 0 width does not mean emptiness */
455 synctex_class_t class;
456 synctex_info_t implementation[5+SYNCTEX_DEPTH_V_IDX+1]; /*parent,child,sibling,friend,next box,
457 * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
458 * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH,
459 * SYNCTEX_HORIZ_V,SYNCTEX_VERT_V,SYNCTEX_WIDTH_V,SYNCTEX_HEIGHT_V,SYNCTEX_DEPTH_V*/
460 } synctex_horiz_box_node_t;
462 synctex_node_t _synctex_new_hbox(synctex_scanner_t scanner);
463 void _synctex_display_hbox(synctex_node_t node);
464 void _synctex_log_horiz_box(synctex_node_t sheet);
467 static _synctex_class_t synctex_class_hbox = {
468 NULL, /* No scanner yet */
469 synctex_node_type_hbox, /* Node type */
470 &_synctex_new_hbox, /* creator */
471 &_synctex_free_node, /* destructor */
472 &_synctex_log_horiz_box, /* log */
473 &_synctex_display_hbox, /* display */
474 &_synctex_implementation_0, /* parent */
475 &_synctex_implementation_1, /* child */
476 &_synctex_implementation_2, /* sibling */
477 &_synctex_implementation_3, /* friend */
478 &_synctex_implementation_4, /* next box */
479 (_synctex_info_getter_t)&_synctex_implementation_5
482 /* horizontal box node creator */
483 synctex_node_t _synctex_new_hbox(synctex_scanner_t scanner) {
484 synctex_node_t node = _synctex_malloc(sizeof(synctex_horiz_box_node_t));
486 node->class = scanner?scanner->class+synctex_node_type_hbox:(synctex_class_t)&synctex_class_hbox;
491 /* This void box node implementation is either horizontal or vertical
492 * It does not contain a child field.
495 synctex_class_t class;
496 synctex_info_t implementation[3+SYNCTEX_DEPTH_IDX+1]; /* parent,sibling,friend,
497 * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
498 * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH*/
499 } synctex_void_box_node_t;
501 synctex_node_t _synctex_new_void_vbox(synctex_scanner_t scanner);
502 void _synctex_log_void_box(synctex_node_t sheet);
503 void _synctex_display_void_vbox(synctex_node_t node);
505 static _synctex_class_t synctex_class_void_vbox = {
506 NULL, /* No scanner yet */
507 synctex_node_type_void_vbox,/* Node type */
508 &_synctex_new_void_vbox, /* creator */
509 &_synctex_free_node, /* destructor */
510 &_synctex_log_void_box, /* log */
511 &_synctex_display_void_vbox,/* display */
512 &_synctex_implementation_0, /* parent */
514 &_synctex_implementation_1, /* sibling */
515 &_synctex_implementation_2, /* friend */
516 NULL, /* No next box */
517 (_synctex_info_getter_t)&_synctex_implementation_3
520 /* vertical void box node creator */
521 synctex_node_t _synctex_new_void_vbox(synctex_scanner_t scanner) {
522 synctex_node_t node = _synctex_malloc(sizeof(synctex_void_box_node_t));
524 node->class = scanner?scanner->class+synctex_node_type_void_vbox:(synctex_class_t)&synctex_class_void_vbox;
529 synctex_node_t _synctex_new_void_hbox(synctex_scanner_t scanner);
530 void _synctex_display_void_hbox(synctex_node_t node);
532 static _synctex_class_t synctex_class_void_hbox = {
533 NULL, /* No scanner yet */
534 synctex_node_type_void_hbox,/* Node type */
535 &_synctex_new_void_hbox, /* creator */
536 &_synctex_free_node, /* destructor */
537 &_synctex_log_void_box, /* log */
538 &_synctex_display_void_hbox,/* display */
539 &_synctex_implementation_0, /* parent */
541 &_synctex_implementation_1, /* sibling */
542 &_synctex_implementation_2, /* friend */
543 NULL, /* No next box */
544 (_synctex_info_getter_t)&_synctex_implementation_3
547 /* horizontal void box node creator */
548 synctex_node_t _synctex_new_void_hbox(synctex_scanner_t scanner) {
549 synctex_node_t node = _synctex_malloc(sizeof(synctex_void_box_node_t));
551 node->class = scanner?scanner->class+synctex_node_type_void_hbox:(synctex_class_t)&synctex_class_void_hbox;
556 /* The medium nodes correspond to kern, glue, penalty and math nodes. */
558 synctex_class_t class;
559 synctex_info_t implementation[3+SYNCTEX_WIDTH_IDX+1]; /* parent,sibling,friend,
560 * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
561 * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH */
562 } synctex_medium_node_t;
564 #define SYNCTEX_IS_BOX(NODE)\
565 ((NODE->class->type == synctex_node_type_vbox)\
566 || (NODE->class->type == synctex_node_type_void_vbox)\
567 || (NODE->class->type == synctex_node_type_hbox)\
568 || (NODE->class->type == synctex_node_type_void_hbox))
570 #define SYNCTEX_HAS_CHILDREN(NODE) (NODE && SYNCTEX_CHILD(NODE))
572 void _synctex_log_medium_node(synctex_node_t node);
574 /* math node creator */
575 synctex_node_t _synctex_new_math(synctex_scanner_t scanner);
576 void _synctex_display_math(synctex_node_t node);
578 static _synctex_class_t synctex_class_math = {
579 NULL, /* No scanner yet */
580 synctex_node_type_math, /* Node type */
581 &_synctex_new_math, /* creator */
582 &_synctex_free_leaf, /* destructor */
583 &_synctex_log_medium_node, /* log */
584 &_synctex_display_math, /* display */
585 &_synctex_implementation_0, /* parent */
587 &_synctex_implementation_1, /* sibling */
588 &_synctex_implementation_2, /* friend */
589 NULL, /* No next box */
590 (_synctex_info_getter_t)&_synctex_implementation_3
593 synctex_node_t _synctex_new_math(synctex_scanner_t scanner) {
594 synctex_node_t node = _synctex_malloc(sizeof(synctex_medium_node_t));
596 node->class = scanner?scanner->class+synctex_node_type_math:(synctex_class_t)&synctex_class_math;
601 /* kern node creator */
602 synctex_node_t _synctex_new_kern(synctex_scanner_t scanner);
603 void _synctex_display_kern(synctex_node_t node);
605 static _synctex_class_t synctex_class_kern = {
606 NULL, /* No scanner yet */
607 synctex_node_type_kern, /* Node type */
608 &_synctex_new_kern, /* creator */
609 &_synctex_free_leaf, /* destructor */
610 &_synctex_log_medium_node, /* log */
611 &_synctex_display_kern, /* display */
612 &_synctex_implementation_0, /* parent */
614 &_synctex_implementation_1, /* sibling */
615 &_synctex_implementation_2, /* friend */
616 NULL, /* No next box */
617 (_synctex_info_getter_t)&_synctex_implementation_3
620 synctex_node_t _synctex_new_kern(synctex_scanner_t scanner) {
621 synctex_node_t node = _synctex_malloc(sizeof(synctex_medium_node_t));
623 node->class = scanner?scanner->class+synctex_node_type_kern:(synctex_class_t)&synctex_class_kern;
628 /* The small nodes correspond to glue and boundary nodes. */
630 synctex_class_t class;
631 synctex_info_t implementation[3+SYNCTEX_VERT_IDX+1]; /* parent,sibling,friend,
632 * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN,
633 * SYNCTEX_HORIZ,SYNCTEX_VERT */
634 } synctex_small_node_t;
636 void _synctex_log_small_node(synctex_node_t node);
637 /* glue node creator */
638 synctex_node_t _synctex_new_glue(synctex_scanner_t scanner);
639 void _synctex_display_glue(synctex_node_t node);
641 static _synctex_class_t synctex_class_glue = {
642 NULL, /* No scanner yet */
643 synctex_node_type_glue, /* Node type */
644 &_synctex_new_glue, /* creator */
645 &_synctex_free_leaf, /* destructor */
646 &_synctex_log_medium_node, /* log */
647 &_synctex_display_glue, /* display */
648 &_synctex_implementation_0, /* parent */
650 &_synctex_implementation_1, /* sibling */
651 &_synctex_implementation_2, /* friend */
652 NULL, /* No next box */
653 (_synctex_info_getter_t)&_synctex_implementation_3
655 synctex_node_t _synctex_new_glue(synctex_scanner_t scanner) {
656 synctex_node_t node = _synctex_malloc(sizeof(synctex_medium_node_t));
658 node->class = scanner?scanner->class+synctex_node_type_glue:(synctex_class_t)&synctex_class_glue;
663 /* boundary node creator */
664 synctex_node_t _synctex_new_boundary(synctex_scanner_t scanner);
665 void _synctex_display_boundary(synctex_node_t node);
667 static _synctex_class_t synctex_class_boundary = {
668 NULL, /* No scanner yet */
669 synctex_node_type_boundary, /* Node type */
670 &_synctex_new_boundary, /* creator */
671 &_synctex_free_leaf, /* destructor */
672 &_synctex_log_small_node, /* log */
673 &_synctex_display_boundary, /* display */
674 &_synctex_implementation_0, /* parent */
676 &_synctex_implementation_1, /* sibling */
677 &_synctex_implementation_2, /* friend */
678 NULL, /* No next box */
679 (_synctex_info_getter_t)&_synctex_implementation_3
682 synctex_node_t _synctex_new_boundary(synctex_scanner_t scanner) {
683 synctex_node_t node = _synctex_malloc(sizeof(synctex_small_node_t));
685 node->class = scanner?scanner->class+synctex_node_type_boundary:(synctex_class_t)&synctex_class_boundary;
690 # define SYNCTEX_NAME_IDX (SYNCTEX_TAG_IDX+1)
691 # define SYNCTEX_NAME(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_NAME_IDX].PTR
693 /* Input nodes only know about their sibling, which is another input node.
694 * The synctex information is the SYNCTEX_TAG and SYNCTEX_NAME*/
696 synctex_class_t class;
697 synctex_info_t implementation[1+SYNCTEX_NAME_IDX+1]; /* sibling,
698 * SYNCTEX_TAG,SYNCTEX_NAME */
701 synctex_node_t _synctex_new_input(synctex_scanner_t scanner);
702 void _synctex_free_input(synctex_node_t node);
703 void _synctex_display_input(synctex_node_t node);
704 void _synctex_log_input(synctex_node_t sheet);
706 static _synctex_class_t synctex_class_input = {
707 NULL, /* No scanner yet */
708 synctex_node_type_input, /* Node type */
709 &_synctex_new_input, /* creator */
710 &_synctex_free_input, /* destructor */
711 &_synctex_log_input, /* log */
712 &_synctex_display_input, /* display */
713 NULL, /* No parent */
715 &_synctex_implementation_0, /* sibling */
716 NULL, /* No friend */
717 NULL, /* No next box */
718 (_synctex_info_getter_t)&_synctex_implementation_1
721 synctex_node_t _synctex_new_input(synctex_scanner_t scanner) {
722 synctex_node_t node = _synctex_malloc(sizeof(synctex_input_t));
724 node->class = scanner?scanner->class+synctex_node_type_input:(synctex_class_t)&synctex_class_input;
728 void _synctex_free_input(synctex_node_t node){
730 SYNCTEX_FREE(SYNCTEX_SIBLING(node));
731 free(SYNCTEX_NAME(node));
735 # ifdef SYNCTEX_NOTHING
737 # pragma mark Navigation
739 synctex_node_t synctex_node_parent(synctex_node_t node)
741 return SYNCTEX_PARENT(node);
743 synctex_node_t synctex_node_sheet(synctex_node_t node)
745 while(node && node->class->type != synctex_node_type_sheet) {
746 node = SYNCTEX_PARENT(node);
748 /* exit the while loop either when node is NULL or node is a sheet */
751 synctex_node_t synctex_node_child(synctex_node_t node)
753 return SYNCTEX_CHILD(node);
755 synctex_node_t synctex_node_sibling(synctex_node_t node)
757 return SYNCTEX_SIBLING(node);
759 synctex_node_t synctex_node_next(synctex_node_t node) {
760 if (SYNCTEX_CHILD(node)) {
761 return SYNCTEX_CHILD(node);
764 if (SYNCTEX_SIBLING(node)) {
765 return SYNCTEX_SIBLING(node);
767 if ((node = SYNCTEX_PARENT(node))) {
768 if (node->class->type == synctex_node_type_sheet) {/* EXC_BAD_ACCESS? */
775 # ifdef SYNCTEX_NOTHING
780 /* Public node accessor: the type */
781 synctex_node_type_t synctex_node_type(synctex_node_t node) {
783 return (((node)->class))->type;
785 return synctex_node_type_error;
788 /* Public node accessor: the human readable type */
789 const char * synctex_node_isa(synctex_node_t node) {
790 static const char * isa[synctex_node_number_of_types] =
791 {"Not a node","input","sheet","vbox","void vbox","hbox","void hbox","kern","glue","math","boundary"};
792 return isa[synctex_node_type(node)];
795 # ifdef SYNCTEX_NOTHING
797 # pragma mark SYNCTEX_LOG
800 # define SYNCTEX_LOG(NODE) SYNCTEX_MSG_SEND(NODE,log)
802 /* Public node logger */
803 void synctex_node_log(synctex_node_t node) {
807 # define SYNCTEX_DISPLAY(NODE) SYNCTEX_MSG_SEND(NODE,display)
809 void synctex_node_display(synctex_node_t node) {
810 SYNCTEX_DISPLAY(node);
813 void _synctex_display_input(synctex_node_t node) {
814 printf("....Input:%i:%s\n",
817 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
820 void _synctex_log_sheet(synctex_node_t sheet) {
822 printf("%s:%i\n",synctex_node_isa(sheet),SYNCTEX_PAGE(sheet));
823 printf("SELF:%p",(void *)sheet);
824 printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(sheet));
825 printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(sheet));
826 printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(sheet));
827 printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(sheet));
831 void _synctex_log_small_node(synctex_node_t node) {
832 printf("%s:%i,%i:%i,%i\n",
833 synctex_node_isa(node),
838 printf("SELF:%p",(void *)node);
839 printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
840 printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
841 printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
842 printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node));
845 void _synctex_log_medium_node(synctex_node_t node) {
846 printf("%s:%i,%i:%i,%i:%i\n",
847 synctex_node_isa(node),
852 SYNCTEX_WIDTH(node));
853 printf("SELF:%p",(void *)node);
854 printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
855 printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
856 printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
857 printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node));
860 void _synctex_log_void_box(synctex_node_t node) {
861 printf("%s",synctex_node_isa(node));
862 printf(":%i",SYNCTEX_TAG(node));
863 printf(",%i",SYNCTEX_LINE(node));
865 printf(":%i",SYNCTEX_HORIZ(node));
866 printf(",%i",SYNCTEX_VERT(node));
867 printf(":%i",SYNCTEX_WIDTH(node));
868 printf(",%i",SYNCTEX_HEIGHT(node));
869 printf(",%i",SYNCTEX_DEPTH(node));
870 printf("\nSELF:%p",(void *)node);
871 printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
872 printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
873 printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
874 printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node));
877 void _synctex_log_box(synctex_node_t node) {
878 printf("%s",synctex_node_isa(node));
879 printf(":%i",SYNCTEX_TAG(node));
880 printf(",%i",SYNCTEX_LINE(node));
882 printf(":%i",SYNCTEX_HORIZ(node));
883 printf(",%i",SYNCTEX_VERT(node));
884 printf(":%i",SYNCTEX_WIDTH(node));
885 printf(",%i",SYNCTEX_HEIGHT(node));
886 printf(",%i",SYNCTEX_DEPTH(node));
887 printf("\nSELF:%p",(void *)node);
888 printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
889 printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
890 printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
891 printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node));
894 void _synctex_log_horiz_box(synctex_node_t node) {
895 printf("%s",synctex_node_isa(node));
896 printf(":%i",SYNCTEX_TAG(node));
897 printf(",%i",SYNCTEX_LINE(node));
899 printf(":%i",SYNCTEX_HORIZ(node));
900 printf(",%i",SYNCTEX_VERT(node));
901 printf(":%i",SYNCTEX_WIDTH(node));
902 printf(",%i",SYNCTEX_HEIGHT(node));
903 printf(",%i",SYNCTEX_DEPTH(node));
904 printf("/%i",SYNCTEX_HORIZ_V(node));
905 printf(",%i",SYNCTEX_VERT_V(node));
906 printf(":%i",SYNCTEX_WIDTH_V(node));
907 printf(",%i",SYNCTEX_HEIGHT_V(node));
908 printf(",%i",SYNCTEX_DEPTH_V(node));
909 printf("\nSELF:%p",(void *)node);
910 printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node));
911 printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node));
912 printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
913 printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node));
916 void _synctex_log_input(synctex_node_t node) {
917 printf("%s",synctex_node_isa(node));
918 printf(":%i",SYNCTEX_TAG(node));
919 printf(",%s",SYNCTEX_NAME(node));
920 printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node));
923 void _synctex_display_sheet(synctex_node_t sheet) {
925 printf("....{%i\n",SYNCTEX_PAGE(sheet));
926 SYNCTEX_DISPLAY(SYNCTEX_CHILD(sheet));
928 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(sheet));
932 void _synctex_display_vbox(synctex_node_t node) {
933 printf("....[%i,%i:%i,%i:%i,%i,%i\n",
939 SYNCTEX_HEIGHT(node),
940 SYNCTEX_DEPTH(node));
941 SYNCTEX_DISPLAY(SYNCTEX_CHILD(node));
943 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
946 void _synctex_display_hbox(synctex_node_t node) {
947 printf("....(%i,%i:%i,%i:%i,%i,%i\n",
953 SYNCTEX_HEIGHT(node),
954 SYNCTEX_DEPTH(node));
955 SYNCTEX_DISPLAY(SYNCTEX_CHILD(node));
957 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
960 void _synctex_display_void_vbox(synctex_node_t node) {
961 printf("....v%i,%i;%i,%i:%i,%i,%i\n",
967 SYNCTEX_HEIGHT(node),
968 SYNCTEX_DEPTH(node));
969 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
972 void _synctex_display_void_hbox(synctex_node_t node) {
973 printf("....h%i,%i:%i,%i:%i,%i,%i\n",
979 SYNCTEX_HEIGHT(node),
980 SYNCTEX_DEPTH(node));
981 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
984 void _synctex_display_glue(synctex_node_t node) {
985 printf("....glue:%i,%i:%i,%i\n",
990 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
993 void _synctex_display_math(synctex_node_t node) {
994 printf("....math:%i,%i:%i,%i\n",
999 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
1002 void _synctex_display_kern(synctex_node_t node) {
1003 printf("....kern:%i,%i:%i,%i:%i\n",
1006 SYNCTEX_HORIZ(node),
1008 SYNCTEX_WIDTH(node));
1009 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
1012 void _synctex_display_boundary(synctex_node_t node) {
1013 printf("....boundary:%i,%i:%i,%i\n",
1016 SYNCTEX_HORIZ(node),
1017 SYNCTEX_VERT(node));
1018 SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node));
1021 # ifdef SYNCTEX_NOTHING
1023 # pragma mark SCANNER
1026 /* Here are gathered all the possible status that the next scanning functions will return.
1027 * All these functions return a status, and pass their result through pointers.
1028 * Negative values correspond to errors.
1029 * The management of the buffer is causing some significant overhead.
1030 * Every function that may access the buffer returns a status related to the buffer and file state.
1031 * status >= SYNCTEX_STATUS_OK means the function worked as expected
1032 * status < SYNCTEX_STATUS_OK means the function did not work as expected
1033 * status == SYNCTEX_STATUS_NOT_OK means the function did not work as expected but there is still some material to parse.
1034 * status == SYNCTEX_STATUS_EOF means the function did not work as expected and there is no more material.
1035 * status<SYNCTEX_STATUS_EOF means an error
1037 typedef int synctex_status_t;
1038 /* When the end of the synctex file has been reached: */
1039 # define SYNCTEX_STATUS_EOF 0
1040 /* When the function could not return the value it was asked for: */
1041 # define SYNCTEX_STATUS_NOT_OK (SYNCTEX_STATUS_EOF+1)
1042 /* When the function returns the value it was asked for: */
1043 # define SYNCTEX_STATUS_OK (SYNCTEX_STATUS_NOT_OK+1)
1044 /* Generic error: */
1045 # define SYNCTEX_STATUS_ERROR -1
1046 /* Parameter error: */
1047 # define SYNCTEX_STATUS_BAD_ARGUMENT -2
1049 # define SYNCTEX_FILE (scanner->file)
1051 /* Actually, the minimum buffer size is driven by integer and float parsing.
1054 # define SYNCTEX_BUFFER_MIN_SIZE 16
1055 # define SYNCTEX_BUFFER_SIZE 32768
1057 # ifdef SYNCTEX_NOTHING
1059 # pragma mark Prototypes
1061 void _synctex_log_void_box(synctex_node_t node);
1062 void _synctex_log_box(synctex_node_t node);
1063 void _synctex_log_horiz_box(synctex_node_t node);
1064 void _synctex_log_input(synctex_node_t node);
1065 synctex_status_t _synctex_buffer_get_available_size(synctex_scanner_t scanner, size_t * size_ptr);
1066 synctex_status_t _synctex_next_line(synctex_scanner_t scanner);
1067 synctex_status_t _synctex_match_string(synctex_scanner_t scanner, const char * the_string);
1068 synctex_status_t _synctex_decode_int(synctex_scanner_t scanner, int* value_ref);
1069 synctex_status_t _synctex_decode_string(synctex_scanner_t scanner, char ** value_ref);
1070 synctex_status_t _synctex_scan_input(synctex_scanner_t scanner);
1071 synctex_status_t _synctex_scan_preamble(synctex_scanner_t scanner);
1072 synctex_status_t _synctex_scan_float_and_dimension(synctex_scanner_t scanner, float * value_ref);
1073 synctex_status_t _synctex_scan_post_scriptum(synctex_scanner_t scanner);
1074 int _synctex_scan_postamble(synctex_scanner_t scanner);
1075 synctex_status_t _synctex_setup_visible_box(synctex_node_t box);
1076 synctex_status_t _synctex_horiz_box_setup_visible(synctex_node_t node,int h, int v);
1077 synctex_status_t _synctex_scan_sheet(synctex_scanner_t scanner, synctex_node_t parent);
1078 synctex_status_t _synctex_scan_nested_sheet(synctex_scanner_t scanner);
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 a possible error in reading the file */
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);
1139 return SYNCTEX_STATUS_ERROR;
1140 } else if (errnum) {
1141 _synctex_error("gzread error (%i:%i,%s)",already_read,errnum,error_string);
1142 return SYNCTEX_STATUS_ERROR;
1145 /* Nothing was read, we are at the end of the file. */
1146 gzclose(SYNCTEX_FILE);
1147 SYNCTEX_FILE = NULL;
1148 SYNCTEX_END = SYNCTEX_CUR;
1149 SYNCTEX_CUR = SYNCTEX_START;
1150 * SYNCTEX_END = '\0';/* Terminate the string properly.*/
1151 size = SYNCTEX_END - SYNCTEX_CUR;
1152 return SYNCTEX_STATUS_EOF; /* there might be a bit of text left */
1154 /* We cannot enlarge the buffer because the end of the file was reached. */
1156 return SYNCTEX_STATUS_EOF;
1160 /* Used when parsing the synctex file.
1161 * Advance to the next character starting a line.
1162 * Actually, only '\n' is recognized as end of line marker.
1163 * On normal completion, the returned value is the number of unparsed characters available in the buffer.
1164 * In general, it is a positive value, 0 meaning that the end of file was reached.
1165 * -1 is returned in case of error, actually because there was an error while feeding the buffer.
1166 * When the function returns with no error, SYNCTEX_CUR points to the first character of the next line, if any.
1167 * J. Laurens: Sat May 10 07:52:31 UTC 2008
1169 synctex_status_t _synctex_next_line(synctex_scanner_t scanner) {
1170 synctex_status_t status = SYNCTEX_STATUS_OK;
1171 size_t available = 0;
1172 if (NULL == scanner) {
1173 return SYNCTEX_STATUS_BAD_ARGUMENT;
1176 while(SYNCTEX_CUR<SYNCTEX_END) {
1177 if (*SYNCTEX_CUR == '\n') {
1180 return _synctex_buffer_get_available_size(scanner, &available);
1184 /* Here, we have SYNCTEX_CUR == SYNCTEX_END, such that the next call to _synctex_buffer_get_available_size
1185 * will read another bunch of synctex file. Little by little, we advance to the end of the file. */
1187 status = _synctex_buffer_get_available_size(scanner, &available);
1194 /* Scan the given string.
1195 * Both scanner and the_string must not be NULL, and the_string must not be 0 length.
1196 * SYNCTEX_STATUS_OK is returned if the string is found,
1197 * SYNCTEX_STATUS_EOF is returned when the EOF is reached,
1198 * SYNCTEX_STATUS_NOT_OK is returned is the string is not found,
1199 * an error status is returned otherwise.
1200 * This is a critical method because buffering renders things more difficult.
1201 * The given string might be as long as the maximum size_t value.
1202 * As side effect, the buffer state may have changed if the given argument string can't fit into the buffer.
1204 synctex_status_t _synctex_match_string(synctex_scanner_t scanner, const char * the_string) {
1205 size_t tested_len = 0; /* the number of characters at the beginning of the_string that match */
1206 size_t remaining_len = 0; /* the number of remaining characters of the_string that should match */
1207 size_t available = 0;
1208 synctex_status_t status = 0;
1209 if (NULL == scanner || NULL == the_string) {
1210 return SYNCTEX_STATUS_BAD_ARGUMENT;
1212 remaining_len = strlen(the_string); /* All the_string should match */
1213 if (0 == remaining_len) {
1214 return SYNCTEX_STATUS_BAD_ARGUMENT;
1216 /* How many characters available in the buffer? */
1217 available = remaining_len;
1218 status = _synctex_buffer_get_available_size(scanner,&available);
1219 if (status<SYNCTEX_STATUS_EOF) {
1222 /* Maybe we have less characters than expected because the buffer is too small. */
1223 if (available>=remaining_len) {
1224 /* The buffer is sufficiently big to hold the expected number of characters. */
1225 if (strncmp((char *)SYNCTEX_CUR,the_string,remaining_len)) {
1226 return SYNCTEX_STATUS_NOT_OK;
1229 /* Advance SYNCTEX_CUR to the next character after the_string. */
1230 SYNCTEX_CUR += remaining_len;
1231 return SYNCTEX_STATUS_OK;
1232 } else if (strncmp((char *)SYNCTEX_CUR,the_string,available)) {
1233 /* No need to goo further, this is not the expected string in the buffer. */
1234 return SYNCTEX_STATUS_NOT_OK;
1235 } else if (SYNCTEX_FILE) {
1236 /* The buffer was too small to contain remaining_len characters.
1237 * We have to cut the string into pieces. */
1238 z_off_t offset = 0L;
1239 /* the first part of the string is found, advance the_string to the next untested character. */
1240 the_string += available;
1241 /* update the remaining length and the parsed length. */
1242 remaining_len -= available;
1243 tested_len += available;
1244 SYNCTEX_CUR += available; /* We validate the tested characters. */
1245 if (0 == remaining_len) {
1246 /* Nothing left to test, we have found the given string, we return the length. */
1249 /* We also have to record the current state of the file cursor because
1250 * if the_string does not match, all this should be a totally blank operation,
1251 * for which the file and buffer states should not be modified at all.
1252 * In fact, the states of the buffer before and after this function are in general different
1253 * but they are totally equivalent as long as the values of the buffer before SYNCTEX_CUR
1254 * can be safely discarded. */
1255 offset = gztell(SYNCTEX_FILE);
1256 /* offset now corresponds to the first character of the file that was not buffered. */
1257 available = SYNCTEX_CUR - SYNCTEX_START; /* available can be used as temporary placeholder. */
1258 /* available now corresponds to the number of chars that where already buffered and
1259 * that match the head of the_string. If in fine the_string does not match, all these chars must be recovered
1260 * because the buffer contents is completely replaced by _synctex_buffer_get_available_size.
1261 * They were buffered from offset-len location in the file. */
1262 offset -= available;
1264 /* There is still some work to be done, so read another bunch of file.
1265 * This is the second call to _synctex_buffer_get_available_size,
1266 * which means that the actual contents of the buffer will be discarded.
1267 * We will definitely have to recover the previous state in case we do not find the expected string. */
1268 available = remaining_len;
1269 status = _synctex_buffer_get_available_size(scanner,&available);
1270 if (status<SYNCTEX_STATUS_EOF) {
1271 return status; /* This is an error, no need to go further. */
1274 /* Missing characters: recover the initial state of the file and return. */
1276 if (offset != gzseek(SYNCTEX_FILE,offset,SEEK_SET)) {
1277 /* This is a critical error, we could not recover the previous state. */
1278 _synctex_error("can't seek file");
1279 return SYNCTEX_STATUS_ERROR;
1281 /* Next time we are asked to fill the buffer,
1282 * we will read a complete bunch of text from the file. */
1283 SYNCTEX_CUR = SYNCTEX_END;
1284 return SYNCTEX_STATUS_NOT_OK;
1286 if (available<remaining_len) {
1287 /* We'll have to loop one more time. */
1288 if (strncmp((char *)SYNCTEX_CUR,the_string,available)) {
1289 /* This is not the expected string, recover the previous state and return. */
1292 /* Advance the_string to the first untested character. */
1293 the_string += available;
1294 /* update the remaining length and the parsed length. */
1295 remaining_len -= available;
1296 tested_len += available;
1297 SYNCTEX_CUR += available; /* We validate the tested characters. */
1298 if (0 == remaining_len) {
1299 /* Nothing left to test, we have found the given string. */
1300 return SYNCTEX_STATUS_OK;
1302 goto more_characters;
1304 /* This is the last step. */
1305 if (strncmp((char *)SYNCTEX_CUR,the_string,remaining_len)) {
1306 /* This is not the expected string, recover the previous state and return. */
1311 /* The buffer can't contain the given string argument, and the EOF was reached */
1312 return SYNCTEX_STATUS_EOF;
1316 /* Used when parsing the synctex file.
1317 * Decode an integer.
1318 * First, field separators, namely ':' and ',' characters are skipped
1319 * The returned value is negative if there is an unrecoverable error.
1320 * It is SYNCTEX_STATUS_NOT_OK if an integer could not be parsed, for example
1321 * if the characters at the current cursor position are not digits or
1322 * if the end of the file has been reached.
1323 * It is SYNCTEX_STATUS_OK if an int has been successfully parsed.
1324 * The given scanner argument must not be NULL, on the contrary, value_ref may be NULL.
1326 synctex_status_t _synctex_decode_int(synctex_scanner_t scanner, int* value_ref) {
1330 size_t available = 0;
1331 synctex_status_t status = 0;
1332 if (NULL == scanner) {
1333 return SYNCTEX_STATUS_BAD_ARGUMENT;
1335 available = SYNCTEX_BUFFER_MIN_SIZE;
1336 status = _synctex_buffer_get_available_size(scanner, &available);
1337 if (status<SYNCTEX_STATUS_EOF) {
1338 return status;/* Forward error. */
1341 return SYNCTEX_STATUS_EOF;/* it is the end of file. */
1344 if (*ptr==':' || *ptr==',') {
1348 return SYNCTEX_STATUS_NOT_OK;/* It is not possible to scan an int */
1351 result = (int)strtol(ptr, &end, 10);
1355 * value_ref = result;
1357 return SYNCTEX_STATUS_OK;/* Successfully scanned an int */
1359 return SYNCTEX_STATUS_NOT_OK;/* Could not scan an int */
1362 /* The purpose of this function is to read a string.
1363 * A string is an array of characters from the current parser location
1364 * and before the next '\n' character.
1365 * If a string was properly decoded, it is returned in value_ref and
1366 * the cursor points to the new line marker.
1367 * The returned string was alloced on the heap, the caller is the owner and
1368 * is responsible to free it in due time.
1369 * If no string is parsed, * value_ref is undefined.
1370 * The maximum length of a string that a scanner can decode is platform dependent, namely UINT_MAX.
1371 * If you just want to blindly parse the file up to the end of the current line,
1372 * use _synctex_next_line instead.
1373 * On return, the scanner cursor is unchanged if a string could not be scanned or
1374 * points to the terminating '\n' character otherwise. As a consequence,
1375 * _synctex_next_line is necessary after.
1376 * If either scanner or value_ref is NULL, it is considered as an error and
1377 * SYNCTEX_STATUS_BAD_ARGUMENT is returned.
1379 synctex_status_t _synctex_decode_string(synctex_scanner_t scanner, char ** value_ref) {
1381 size_t current_size = 0;
1382 size_t new_size = 0;
1383 size_t len = 0;/* The number of bytes to copy */
1384 size_t available = 0;
1385 synctex_status_t status = 0;
1386 if (NULL == scanner || NULL == value_ref) {
1387 return SYNCTEX_STATUS_BAD_ARGUMENT;
1389 /* The buffer must at least contain one character: the '\n' end of line marker */
1390 if (SYNCTEX_CUR>=SYNCTEX_END) {
1392 status = _synctex_buffer_get_available_size(scanner,&available);
1396 if (0 == available) {
1397 return SYNCTEX_STATUS_EOF;
1400 /* Now we are sure that there is at least one available character, either because
1401 * SYNCTEX_CUR was already < SYNCTEX_END, or because the buffer has been properly filled. */
1402 /* end will point to the next unparsed '\n' character in the file, when mapped to the buffer. */
1404 * value_ref = NULL;/* Initialize, it will be realloc'ed */
1405 /* We scan all the characters up to the next '\n' */
1407 if (end<SYNCTEX_END) {
1409 /* OK, we found where to stop */
1410 len = end - SYNCTEX_CUR;
1411 if (current_size>UINT_MAX-len-1) {
1412 /* But we have reached the limit: we do not have current_size+len+1>UINT_MAX.
1413 * We return the missing amount of memory.
1414 * This will never occur in practice. */
1415 return UINT_MAX-len-1 - current_size;
1417 new_size = current_size+len;
1418 /* We have current_size+len+1<=UINT_MAX
1419 * or equivalently new_size<UINT_MAX,
1420 * where we have assumed that len<UINT_MAX */
1421 if ((* value_ref = realloc(* value_ref,new_size+1)) != NULL) {
1422 if (memcpy((*value_ref)+current_size,SYNCTEX_CUR,len)) {
1423 (* value_ref)[new_size]='\0'; /* Terminate the string */
1424 SYNCTEX_CUR += len;/* Advance to the terminating '\n' */
1425 return SYNCTEX_STATUS_OK;
1429 _synctex_error("could not copy memory (1).");
1430 return SYNCTEX_STATUS_ERROR;
1432 _synctex_error("could not allocate memory (1).");
1433 return SYNCTEX_STATUS_ERROR;
1436 goto next_character;
1439 /* end == SYNCTEX_END */
1440 len = SYNCTEX_END - SYNCTEX_CUR;
1441 if (current_size>UINT_MAX-len-1) {
1442 /* We have reached the limit. */
1443 _synctex_error("limit reached (missing %i).",current_size-(UINT_MAX-len-1));
1444 return SYNCTEX_STATUS_ERROR;
1446 new_size = current_size+len;
1447 if ((* value_ref = realloc(* value_ref,new_size+1)) != NULL) {
1448 if (memcpy((*value_ref)+current_size,SYNCTEX_CUR,len)) {
1449 (* value_ref)[new_size]='\0'; /* Terminate the string */
1450 SYNCTEX_CUR = SYNCTEX_END;/* Advance the cursor to the end of the bufer */
1451 return SYNCTEX_STATUS_OK;
1455 _synctex_error("could not copy memory (2).");
1456 return SYNCTEX_STATUS_ERROR;
1458 /* Huge memory problem */
1459 _synctex_error("could not allocate memory (2).");
1460 return SYNCTEX_STATUS_ERROR;
1464 /* Used when parsing the synctex file.
1465 * Read an Input record.
1467 synctex_status_t _synctex_scan_input(synctex_scanner_t scanner) {
1468 synctex_status_t status = 0;
1469 size_t available = 0;
1470 synctex_node_t input = NULL;
1471 if (NULL == scanner) {
1472 return SYNCTEX_STATUS_BAD_ARGUMENT;
1474 status = _synctex_match_string(scanner,"Input:");
1475 if (status<SYNCTEX_STATUS_OK) {
1479 input = _synctex_new_input(scanner);
1480 if (NULL == input) {
1481 _synctex_error("could not create an input node.");
1482 return SYNCTEX_STATUS_ERROR;
1484 /* Decode the synctag */
1485 status = _synctex_decode_int(scanner,&(SYNCTEX_TAG(input)));
1486 if (status<SYNCTEX_STATUS_OK) {
1487 _synctex_error("bad format of input node.");
1488 SYNCTEX_FREE(input);
1491 /* The next character is a field separator, we expect one character in the buffer. */
1493 status = _synctex_buffer_get_available_size(scanner, &available);
1494 if (status<=SYNCTEX_STATUS_ERROR) {
1497 if (0 == available) {
1498 return SYNCTEX_STATUS_EOF;
1500 /* We can now safely advance to the next character, stepping over the field separator. */
1503 /* Then we scan the file name */
1504 status = _synctex_decode_string(scanner,&(SYNCTEX_NAME(input)));
1505 if (status<SYNCTEX_STATUS_OK) {
1506 SYNCTEX_FREE(input);
1509 /* Prepend this input node to the input linked list of the scanner */
1510 SYNCTEX_SET_SIBLING(input,scanner->input);
1511 scanner->input = input;
1512 return _synctex_next_line(scanner);/* read the line termination character, if any */
1513 /* Now, set up the path */
1516 typedef synctex_status_t (*synctex_decoder_t)(synctex_scanner_t,void *);
1518 synctex_status_t _synctex_scan_named(synctex_scanner_t scanner,const char * name,void * value_ref,synctex_decoder_t decoder);
1520 /* Used when parsing the synctex file.
1521 * Read one of the settings.
1522 * On normal completion, returns SYNCTEX_STATUS_OK.
1523 * On error, returns SYNCTEX_STATUS_ERROR.
1524 * Both arguments must not be NULL.
1525 * On return, the scanner points to the next character after the decoded object whatever it is.
1526 * It is the responsibility of the caller to prepare the scanner for the next line.
1528 synctex_status_t _synctex_scan_named(synctex_scanner_t scanner,const char * name,void * value_ref,synctex_decoder_t decoder) {
1529 synctex_status_t status = 0;
1530 if (NULL == scanner || NULL == name || NULL == value_ref || NULL == decoder) {
1531 return SYNCTEX_STATUS_BAD_ARGUMENT;
1534 status = _synctex_match_string(scanner,name);
1535 if (status<SYNCTEX_STATUS_NOT_OK) {
1537 } else if (status == SYNCTEX_STATUS_NOT_OK) {
1538 status = _synctex_next_line(scanner);
1539 if (status<SYNCTEX_STATUS_OK) {
1544 /* A line is found, scan the value */
1545 return (*decoder)(scanner,value_ref);
1548 /* Used when parsing the synctex file.
1549 * Read the preamble.
1551 synctex_status_t _synctex_scan_preamble(synctex_scanner_t scanner) {
1552 synctex_status_t status = 0;
1553 if (NULL == scanner) {
1554 return SYNCTEX_STATUS_BAD_ARGUMENT;
1556 status = _synctex_scan_named(scanner,"SyncTeX Version:",&(scanner->version),(synctex_decoder_t)&_synctex_decode_int);
1557 if (status<SYNCTEX_STATUS_OK) {
1560 status = _synctex_next_line(scanner);
1561 if (status<SYNCTEX_STATUS_OK) {
1564 /* Read all the input records */
1566 status = _synctex_scan_input(scanner);
1567 if (status<SYNCTEX_STATUS_NOT_OK) {
1570 } while(status == SYNCTEX_STATUS_OK);
1571 /* the loop exits when status == SYNCTEX_STATUS_NOT_OK */
1572 /* Now read all the required settings. */
1573 status = _synctex_scan_named(scanner,"Output:",&(scanner->output_fmt),(synctex_decoder_t)&_synctex_decode_string);
1574 if (status<SYNCTEX_STATUS_NOT_OK) {
1577 status = _synctex_next_line(scanner);
1578 if (status<SYNCTEX_STATUS_OK) {
1581 status = _synctex_scan_named(scanner,"Magnification:",&(scanner->pre_magnification),(synctex_decoder_t)&_synctex_decode_int);
1582 if (status<SYNCTEX_STATUS_OK) {
1585 status = _synctex_next_line(scanner);
1586 if (status<SYNCTEX_STATUS_OK) {
1589 status = _synctex_scan_named(scanner,"Unit:",&(scanner->pre_unit),(synctex_decoder_t)&_synctex_decode_int);
1590 if (status<SYNCTEX_STATUS_OK) {
1593 status = _synctex_next_line(scanner);
1594 if (status<SYNCTEX_STATUS_OK) {
1597 status = _synctex_scan_named(scanner,"X Offset:",&(scanner->pre_x_offset),(synctex_decoder_t)&_synctex_decode_int);
1598 if (status<SYNCTEX_STATUS_OK) {
1601 status = _synctex_next_line(scanner);
1602 if (status<SYNCTEX_STATUS_OK) {
1605 status = _synctex_scan_named(scanner,"Y Offset:",&(scanner->pre_y_offset),(synctex_decoder_t)&_synctex_decode_int);
1606 if (status<SYNCTEX_STATUS_OK) {
1609 return _synctex_next_line(scanner);
1612 /* parse a float with a dimension */
1613 synctex_status_t _synctex_scan_float_and_dimension(synctex_scanner_t scanner, float * value_ref) {
1614 synctex_status_t status = 0;
1615 char * endptr = NULL;
1617 #ifdef HAVE_SETLOCALE
1618 char * loc = setlocale(LC_NUMERIC, NULL);
1620 size_t available = 0;
1621 if (NULL == scanner || NULL == value_ref) {
1622 return SYNCTEX_STATUS_BAD_ARGUMENT;
1624 available = SYNCTEX_BUFFER_MIN_SIZE;
1625 status = _synctex_buffer_get_available_size(scanner, &available);
1626 if (status<SYNCTEX_STATUS_EOF) {
1627 _synctex_error("problem with float.");
1630 #ifdef HAVE_SETLOCALE
1631 setlocale(LC_NUMERIC, "C");
1633 f = strtod(SYNCTEX_CUR,&endptr);
1634 #ifdef HAVE_SETLOCALE
1635 setlocale(LC_NUMERIC, loc);
1637 if (endptr == SYNCTEX_CUR) {
1638 _synctex_error("a float was expected.");
1639 return SYNCTEX_STATUS_ERROR;
1641 SYNCTEX_CUR = endptr;
1642 if ((status = _synctex_match_string(scanner,"in")) >= SYNCTEX_STATUS_OK) {
1644 } else if (status<SYNCTEX_STATUS_EOF) {
1646 _synctex_error("problem with unit.");
1648 } else if ((status = _synctex_match_string(scanner,"cm")) >= SYNCTEX_STATUS_OK) {
1649 f *= 72.27f*65536/2.54f;
1650 } else if (status<0) {
1651 goto report_unit_error;
1652 } else if ((status = _synctex_match_string(scanner,"mm")) >= SYNCTEX_STATUS_OK) {
1653 f *= 72.27f*65536/25.4f;
1654 } else if (status<0) {
1655 goto report_unit_error;
1656 } else if ((status = _synctex_match_string(scanner,"pt")) >= SYNCTEX_STATUS_OK) {
1658 } else if (status<0) {
1659 goto report_unit_error;
1660 } else if ((status = _synctex_match_string(scanner,"bp")) >= SYNCTEX_STATUS_OK) {
1661 f *= 72.27f/72*65536.0f;
1662 } else if (status<0) {
1663 goto report_unit_error;
1664 } else if ((status = _synctex_match_string(scanner,"pc")) >= SYNCTEX_STATUS_OK) {
1666 } else if (status<0) {
1667 goto report_unit_error;
1668 } else if ((status = _synctex_match_string(scanner,"sp")) >= SYNCTEX_STATUS_OK) {
1670 } else if (status<0) {
1671 goto report_unit_error;
1672 } else if ((status = _synctex_match_string(scanner,"dd")) >= SYNCTEX_STATUS_OK) {
1673 f *= 1238.0f/1157*65536.0f;
1674 } else if (status<0) {
1675 goto report_unit_error;
1676 } else if ((status = _synctex_match_string(scanner,"cc")) >= SYNCTEX_STATUS_OK) {
1677 f *= 14856.0f/1157*65536;
1678 } else if (status<0) {
1679 goto report_unit_error;
1680 } else if ((status = _synctex_match_string(scanner,"nd")) >= SYNCTEX_STATUS_OK) {
1681 f *= 685.0f/642*65536;
1682 } else if (status<0) {
1683 goto report_unit_error;
1684 } else if ((status = _synctex_match_string(scanner,"nc")) >= SYNCTEX_STATUS_OK) {
1685 f *= 1370.0f/107*65536;
1686 } else if (status<0) {
1687 goto report_unit_error;
1690 return SYNCTEX_STATUS_OK;
1693 /* parse the post scriptum
1694 * SYNCTEX_STATUS_OK is returned on completion
1695 * a negative error is returned otherwise */
1696 synctex_status_t _synctex_scan_post_scriptum(synctex_scanner_t scanner) {
1697 synctex_status_t status = 0;
1698 char * endptr = NULL;
1699 #ifdef HAVE_SETLOCALE
1700 char * loc = setlocale(LC_NUMERIC, NULL);
1702 if (NULL == scanner) {
1703 return SYNCTEX_STATUS_BAD_ARGUMENT;
1705 /* Scan the file until a post scriptum line is found */
1706 post_scriptum_not_found:
1707 status = _synctex_match_string(scanner,"Post scriptum:");
1708 if (status<SYNCTEX_STATUS_NOT_OK) {
1711 if (status == SYNCTEX_STATUS_NOT_OK) {
1712 status = _synctex_next_line(scanner);
1713 if (status<SYNCTEX_STATUS_EOF) {
1715 } else if (status<SYNCTEX_STATUS_OK) {
1716 return SYNCTEX_STATUS_OK;/* The EOF is found, we have properly scanned the file */
1718 goto post_scriptum_not_found;
1720 /* We found the name, advance to the next line. */
1722 status = _synctex_next_line(scanner);
1723 if (status<SYNCTEX_STATUS_EOF) {
1725 } else if (status<SYNCTEX_STATUS_OK) {
1726 return SYNCTEX_STATUS_OK;/* The EOF is found, we have properly scanned the file */
1728 /* Scanning the information */
1729 status = _synctex_match_string(scanner,"Magnification:");
1730 if (status == SYNCTEX_STATUS_OK ) {
1731 #ifdef HAVE_SETLOCALE
1732 setlocale(LC_NUMERIC, "C");
1734 scanner->unit = strtod(SYNCTEX_CUR,&endptr);
1735 #ifdef HAVE_SETLOCALE
1736 setlocale(LC_NUMERIC, loc);
1738 if (endptr == SYNCTEX_CUR) {
1739 _synctex_error("bad magnification in the post scriptum, a float was expected.");
1740 return SYNCTEX_STATUS_ERROR;
1742 if (scanner->unit<=0) {
1743 _synctex_error("bad magnification in the post scriptum, a positive float was expected.");
1744 return SYNCTEX_STATUS_ERROR;
1746 SYNCTEX_CUR = endptr;
1749 if (status<SYNCTEX_STATUS_EOF){
1750 report_record_problem:
1751 _synctex_error("Problem reading the Post Scriptum records");
1752 return status; /* echo the error. */
1754 status = _synctex_match_string(scanner,"X Offset:");
1755 if (status == SYNCTEX_STATUS_OK) {
1756 status = _synctex_scan_float_and_dimension(scanner, &(scanner->x_offset));
1757 if (status<SYNCTEX_STATUS_OK) {
1758 _synctex_error("problem with X offset in the Post Scriptum.");
1762 } else if (status<SYNCTEX_STATUS_EOF){
1763 goto report_record_problem;
1765 status = _synctex_match_string(scanner,"Y Offset:");
1766 if (status==SYNCTEX_STATUS_OK) {
1767 status = _synctex_scan_float_and_dimension(scanner, &(scanner->y_offset));
1768 if (status<SYNCTEX_STATUS_OK) {
1769 _synctex_error("problem with Y offset in the Post Scriptum.");
1773 } else if (status<SYNCTEX_STATUS_EOF){
1774 goto report_record_problem;
1779 /* SYNCTEX_STATUS_OK is returned if the postamble is read
1780 * SYNCTEX_STATUS_NOT_OK is returned if the postamble is not at the current location
1781 * a negative error otherwise
1782 * The postamble comprises the post scriptum section.
1784 int _synctex_scan_postamble(synctex_scanner_t scanner) {
1786 if (NULL == scanner) {
1787 return SYNCTEX_STATUS_BAD_ARGUMENT;
1789 status = _synctex_match_string(scanner,"Postamble:");
1790 if (status < SYNCTEX_STATUS_OK) {
1794 status = _synctex_next_line(scanner);
1795 if (status < SYNCTEX_STATUS_OK) {
1798 status = _synctex_scan_named(scanner,"Count:",&(scanner->count),(synctex_decoder_t)&_synctex_decode_int);
1799 if (status < SYNCTEX_STATUS_EOF) {
1800 return status; /* forward the error */
1801 } else if (status < SYNCTEX_STATUS_OK) { /* No Count record found */
1802 status = _synctex_next_line(scanner); /* Advance one more line */
1803 if (status<SYNCTEX_STATUS_OK) {
1808 /* Now we scan the last part of the SyncTeX file: the Post Scriptum section. */
1809 return _synctex_scan_post_scriptum(scanner);
1812 /* Horizontal boxes also have visible size.
1813 * Visible size are bigger than real size.
1814 * For example 0 width boxes may contain text.
1815 * At creation time, the visible size is set to the values of the real size.
1817 synctex_status_t _synctex_setup_visible_box(synctex_node_t box) {
1819 switch(box->class->type) {
1820 case synctex_node_type_hbox:
1821 if (SYNCTEX_INFO(box) != NULL) {
1822 SYNCTEX_HORIZ_V(box) = SYNCTEX_HORIZ(box);
1823 SYNCTEX_VERT_V(box) = SYNCTEX_VERT(box);
1824 SYNCTEX_WIDTH_V(box) = SYNCTEX_WIDTH(box);
1825 SYNCTEX_HEIGHT_V(box) = SYNCTEX_HEIGHT(box);
1826 SYNCTEX_DEPTH_V(box) = SYNCTEX_DEPTH(box);
1827 return SYNCTEX_STATUS_OK;
1829 return SYNCTEX_STATUS_ERROR;
1832 return SYNCTEX_STATUS_BAD_ARGUMENT;
1835 /* This method is sent to an horizontal box to setup the visible size
1836 * Some box have 0 width but do contain text material.
1837 * With this method, one can enlarge the box to contain the given point (h,v).
1839 synctex_status_t _synctex_horiz_box_setup_visible(synctex_node_t node,int h, int v) {
1840 # ifdef __DARWIN_UNIX03
1844 if (NULL == node || node->class->type != synctex_node_type_hbox) {
1845 return SYNCTEX_STATUS_BAD_ARGUMENT;
1847 if (SYNCTEX_WIDTH_V(node)<0) {
1848 itsBtm = SYNCTEX_HORIZ_V(node);
1849 itsTop = SYNCTEX_HORIZ_V(node)-SYNCTEX_WIDTH_V(node);
1851 SYNCTEX_HORIZ_V(node) = h;
1852 SYNCTEX_WIDTH_V(node) = SYNCTEX_HORIZ_V(node) - itsTop;
1853 } else if (h>itsTop) {
1854 SYNCTEX_WIDTH_V(node) = SYNCTEX_HORIZ_V(node) - h;
1857 itsBtm = SYNCTEX_HORIZ_V(node);
1858 itsTop = SYNCTEX_HORIZ_V(node)+SYNCTEX_WIDTH_V(node);
1860 SYNCTEX_HORIZ_V(node) = h;
1861 SYNCTEX_WIDTH_V(node) = itsTop - SYNCTEX_HORIZ_V(node);
1862 } else if (h>itsTop) {
1863 SYNCTEX_WIDTH_V(node) = h - SYNCTEX_HORIZ_V(node);
1866 return SYNCTEX_STATUS_OK;
1869 /* Here are the control characters that strat each line of the synctex output file.
1870 * Their values define the meaning of the line.
1872 # define SYNCTEX_CHAR_BEGIN_SHEET '{'
1873 # define SYNCTEX_CHAR_END_SHEET '}'
1874 # define SYNCTEX_CHAR_BEGIN_VBOX '['
1875 # define SYNCTEX_CHAR_END_VBOX ']'
1876 # define SYNCTEX_CHAR_BEGIN_HBOX '('
1877 # define SYNCTEX_CHAR_END_HBOX ')'
1878 # define SYNCTEX_CHAR_ANCHOR '!'
1879 # define SYNCTEX_CHAR_VOID_VBOX 'v'
1880 # define SYNCTEX_CHAR_VOID_HBOX 'h'
1881 # define SYNCTEX_CHAR_KERN 'k'
1882 # define SYNCTEX_CHAR_GLUE 'g'
1883 # define SYNCTEX_CHAR_MATH '$'
1884 # define SYNCTEX_CHAR_BOUNDARY 'x'
1886 # define SYNCTEX_RETURN(STATUS) return STATUS;
1888 /* Used when parsing the synctex file. A '{' character has just been parsed.
1889 * The purpose is to gobble everything until the closing '}'.
1890 * Actually only one nesting depth has been observed when using the clip option
1891 * of \includegraphics option. Here we use arbitrary level of depth.
1893 synctex_status_t _synctex_scan_nested_sheet(synctex_scanner_t scanner) {
1894 unsigned int depth = 0;
1897 if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
1898 _synctex_error("Unexpected end of nested sheet (1).");
1899 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1902 if (SYNCTEX_CUR<SYNCTEX_END) {
1903 if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_SHEET) {
1905 if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
1906 _synctex_error("Unexpected end of nested sheet (2).");
1907 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1910 goto scan_next_line;
1912 SYNCTEX_RETURN(SYNCTEX_STATUS_OK);
1914 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_SHEET) {
1918 } else if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
1919 _synctex_error("Unexpected end of nested sheet (3).");
1920 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1923 _synctex_error("Unexpected end of nested sheet (4).");
1924 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1927 /* Used when parsing the synctex file.
1928 * The sheet argument is a newly created sheet node that will hold the contents.
1929 * Something is returned in case of error.
1931 synctex_status_t _synctex_scan_sheet(synctex_scanner_t scanner, synctex_node_t sheet) {
1932 synctex_node_t parent = sheet;
1933 synctex_node_t child = NULL;
1934 synctex_node_t sibling = NULL;
1935 synctex_node_t box = sheet;
1936 int friend_index = 0;
1937 synctex_info_t * info = NULL;
1938 synctex_status_t status = 0;
1939 size_t available = 0;
1940 if ((NULL == scanner) || (NULL == sheet)) {
1941 return SYNCTEX_STATUS_BAD_ARGUMENT;
1943 /* We MUST start with a box, so at this level, the unique possibility is '[', '(' or "}". */
1945 if (SYNCTEX_CUR<SYNCTEX_END) {
1946 if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_VBOX) {
1949 if ((child = _synctex_new_vbox(scanner)) && (info = SYNCTEX_INFO(child))) {
1950 # define SYNCTEX_DECODE_FAILED(WHAT) \
1951 (_synctex_decode_int(scanner,&(info[WHAT].INT))<SYNCTEX_STATUS_OK)
1952 if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
1953 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
1954 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
1955 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
1956 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
1957 || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
1958 || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
1959 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
1960 _synctex_error("Bad vbox record.");
1961 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1963 SYNCTEX_SET_CHILD(parent,child);
1966 goto child_loop;/* next created node will be a child */
1968 _synctex_error("Can't create vbox record.");
1969 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1971 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_HBOX) {
1974 if ((child = _synctex_new_hbox(scanner)) && (info = SYNCTEX_INFO(child))) {
1975 if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
1976 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
1977 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
1978 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
1979 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
1980 || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
1981 || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
1982 || _synctex_setup_visible_box(child)<SYNCTEX_STATUS_OK
1983 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
1984 _synctex_error("Bad hbox record.");
1985 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1987 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
1988 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child));
1989 SYNCTEX_SET_CHILD(parent,child);
1992 goto child_loop;/* next created node will be a child */
1994 _synctex_error("Can't create hbox record.");
1995 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
1997 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_SHEET) {
2000 if (NULL == parent || parent->class->type != synctex_node_type_sheet
2001 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2002 _synctex_error("Unexpected end of sheet.");
2003 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2005 SYNCTEX_RETURN(SYNCTEX_STATUS_OK);
2006 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_SHEET) {
2007 /* Addendum to version 1.10 to manage nested sheets */
2009 if (_synctex_scan_nested_sheet(scanner)<SYNCTEX_STATUS_OK) {
2010 _synctex_error("Unexpected nested sheet.");
2011 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2014 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_ANCHOR) {
2017 if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2018 _synctex_error("Missing anchor.");
2019 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2023 /* _synctex_error("Ignored record %c\n",*SYNCTEX_CUR); */
2025 if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2026 _synctex_error("Unexpected end.");
2027 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2033 status = _synctex_buffer_get_available_size(scanner,&available);
2034 if (status<SYNCTEX_STATUS_OK && available>0){
2035 _synctex_error("Uncomplete sheet(0)");
2036 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2042 /* The child loop means that we go do one level, when we just created a box node,
2043 * the next node created is a child of this box. */
2045 if (SYNCTEX_CUR<SYNCTEX_END) {
2046 if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_VBOX) {
2048 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_VBOX) {
2051 if (NULL != parent && parent->class->type == synctex_node_type_vbox) {
2052 #define SYNCTEX_UPDATE_BOX_FRIEND(NODE)\
2053 friend_index = ((SYNCTEX_INFO(NODE))[SYNCTEX_TAG_IDX].INT+(SYNCTEX_INFO(NODE))[SYNCTEX_LINE_IDX].INT)%(scanner->number_of_lists);\
2054 SYNCTEX_SET_FRIEND(NODE,(scanner->lists_of_friends)[friend_index]);\
2055 (scanner->lists_of_friends)[friend_index] = NODE;
2056 if (NULL == SYNCTEX_CHILD(parent)) {
2057 /* only void boxes are friends */
2058 SYNCTEX_UPDATE_BOX_FRIEND(parent);
2061 parent = SYNCTEX_PARENT(child);
2063 _synctex_error("Unexpected end of vbox, ignored.");
2065 if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2066 _synctex_error("Uncomplete sheet.");
2067 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2070 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_HBOX) {
2072 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_HBOX) {
2075 if ((parent) && parent->class->type == synctex_node_type_hbox) {
2076 if (NULL == child) {
2077 /* Only boxes with no children are friends,
2078 * boxes with children are indirectly friends through one of their descendants. */
2079 SYNCTEX_UPDATE_BOX_FRIEND(parent);
2081 /* setting the next horizontal box at the end ensures that a child is recorded before any of its ancestors. */
2082 SYNCTEX_SET_NEXT_HORIZ_BOX(box,parent);
2085 parent = SYNCTEX_PARENT(child);
2087 _synctex_error("Unexpected enf of hbox, ignored.");
2089 if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2090 _synctex_error("Uncomplete sheet.");
2091 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2094 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_VOID_VBOX) {
2096 if (NULL != (child = _synctex_new_void_vbox(scanner))
2097 && NULL != (info = SYNCTEX_INFO(child))) {
2098 if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2099 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2100 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2101 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2102 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2103 || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2104 || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2105 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2106 _synctex_error("Bad void vbox record.");
2107 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2109 SYNCTEX_SET_CHILD(parent,child);
2110 #define SYNCTEX_UPDATE_FRIEND(NODE)\
2111 friend_index = (info[SYNCTEX_TAG_IDX].INT+info[SYNCTEX_LINE_IDX].INT)%(scanner->number_of_lists);\
2112 SYNCTEX_SET_FRIEND(NODE,(scanner->lists_of_friends)[friend_index]);\
2113 (scanner->lists_of_friends)[friend_index] = NODE;
2114 SYNCTEX_UPDATE_FRIEND(child);
2117 _synctex_error("Can't create vbox record.");
2118 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2120 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_VOID_HBOX) {
2122 if (NULL != (child = _synctex_new_void_hbox(scanner))
2123 && NULL != (info = SYNCTEX_INFO(child))) {
2124 if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2125 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2126 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2127 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2128 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2129 || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2130 || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2131 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2132 _synctex_error("Bad void hbox record.");
2133 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2135 SYNCTEX_SET_CHILD(parent,child);
2136 SYNCTEX_UPDATE_FRIEND(child);
2137 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2138 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child));
2141 _synctex_error("Can't create void hbox record.");
2142 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2144 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_KERN) {
2146 if (NULL != (child = _synctex_new_kern(scanner))
2147 && NULL != (info = SYNCTEX_INFO(child))) {
2148 if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2149 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2150 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2151 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2152 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2153 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2154 _synctex_error("Bad kern record.");
2155 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2157 SYNCTEX_SET_CHILD(parent,child);
2158 SYNCTEX_UPDATE_FRIEND(child);
2159 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2160 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)-SYNCTEX_WIDTH(child),SYNCTEX_VERT(child));
2163 _synctex_error("Can't create kern record.");
2164 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2166 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_GLUE) {
2168 if (NULL != (child = _synctex_new_glue(scanner))
2169 && NULL != (info = SYNCTEX_INFO(child))) {
2170 if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2171 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2172 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2173 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2174 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2175 _synctex_error("Bad glue record.");
2176 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2178 SYNCTEX_SET_CHILD(parent,child);
2179 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2180 SYNCTEX_UPDATE_FRIEND(child);
2183 _synctex_error("Can't create glue record.");
2184 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2186 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_MATH) {
2188 if (NULL != (child = _synctex_new_math(scanner))
2189 && NULL != (info = SYNCTEX_INFO(child))) {
2190 if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2191 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2192 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2193 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2194 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2195 _synctex_error("Bad math record.");
2196 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2198 SYNCTEX_SET_CHILD(parent,child);
2199 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2200 SYNCTEX_UPDATE_FRIEND(child);
2203 _synctex_error("Can't create math record.");
2204 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2206 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BOUNDARY) {
2208 if (NULL != (child = _synctex_new_boundary(scanner))
2209 && NULL != (info = SYNCTEX_INFO(child))) {
2210 if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2211 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2212 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2213 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2214 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2215 _synctex_error("Bad boundary record.");
2216 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2218 SYNCTEX_SET_CHILD(parent,child);
2219 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2220 SYNCTEX_UPDATE_FRIEND(child);
2223 _synctex_error("Can't create math record.");
2224 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2226 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_SHEET) {
2228 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_SHEET) {
2229 /* Addendum to version 1.10 to manage nested sheets */
2231 if (_synctex_scan_nested_sheet(scanner)<SYNCTEX_STATUS_OK) {
2232 _synctex_error("Unexpected nested sheet.");
2233 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2236 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_ANCHOR) {
2239 /* _synctex_error("Ignored record %c\n",*SYNCTEX_CUR); */
2241 if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2242 _synctex_error("Unexpected end.");
2243 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2249 status = _synctex_buffer_get_available_size(scanner,&available);
2250 if (status<SYNCTEX_STATUS_OK && available>0){
2251 _synctex_error("Uncomplete sheet(0)");
2252 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2258 /* The vertical loop means that we are on the same level, for example when we just ended a box.
2259 * If a node is created now, it will be a sibling of the current node, sharing the same parent. */
2261 if (SYNCTEX_CUR<SYNCTEX_END) {
2262 if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_VBOX) {
2264 if (NULL != (sibling = _synctex_new_vbox(scanner))
2265 && NULL != (info = SYNCTEX_INFO(sibling))) {
2266 if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2267 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2268 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2269 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2270 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2271 || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2272 || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2273 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2274 _synctex_error("Bad vbox record (2).");
2275 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2277 SYNCTEX_SET_SIBLING(child,sibling);
2282 _synctex_error("Can't create vbox record (2).");
2283 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2285 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_VBOX) {
2287 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_HBOX) {
2289 if (NULL != (sibling = _synctex_new_hbox(scanner)) &&
2290 NULL != (info = SYNCTEX_INFO(sibling))) {
2291 if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2292 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2293 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2294 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2295 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2296 || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2297 || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2298 || _synctex_setup_visible_box(sibling)<SYNCTEX_STATUS_OK
2299 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2300 _synctex_error("Bad hbox record (2).");
2301 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2303 SYNCTEX_SET_SIBLING(child,sibling);
2305 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2306 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child));
2311 _synctex_error("Can't create hbox record (2).");
2312 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2314 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_HBOX) {
2316 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_VOID_VBOX) {
2318 if (NULL != (sibling = _synctex_new_void_vbox(scanner)) &&
2319 NULL != (info = SYNCTEX_INFO(sibling))) {
2320 if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2321 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2322 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2323 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2324 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2325 || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2326 || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2327 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2328 _synctex_error("Bad void vbox record (2).");
2329 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2331 SYNCTEX_SET_SIBLING(child,sibling);
2333 SYNCTEX_UPDATE_FRIEND(child);
2336 _synctex_error("can't create void vbox record (2).");
2337 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2339 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_VOID_HBOX) {
2341 if (NULL != (sibling = _synctex_new_void_hbox(scanner)) &&
2342 NULL != (info = SYNCTEX_INFO(sibling))) {
2343 if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2344 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2345 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2346 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2347 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2348 || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX)
2349 || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX)
2350 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2351 _synctex_error("Bad void hbox record (2).");
2352 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2354 SYNCTEX_SET_SIBLING(child,sibling);
2356 SYNCTEX_UPDATE_FRIEND(child);
2357 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2358 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child));
2361 _synctex_error("can't create void hbox record (2).");
2362 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2364 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_KERN) {
2366 if (NULL != (sibling = _synctex_new_kern(scanner))
2367 && NULL != (info = SYNCTEX_INFO(sibling))) {
2368 if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2369 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2370 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2371 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2372 || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX)
2373 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2374 _synctex_error("Bad kern record (2).");
2375 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2377 SYNCTEX_SET_SIBLING(child,sibling);
2379 SYNCTEX_UPDATE_FRIEND(child);
2380 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2381 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)-SYNCTEX_WIDTH(child),SYNCTEX_VERT(child));
2384 _synctex_error("Can't create kern record (2).");
2385 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2387 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_GLUE) {
2389 if (NULL != (sibling = _synctex_new_glue(scanner))
2390 && NULL != (info = SYNCTEX_INFO(sibling))) {
2391 if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2392 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2393 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2394 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2395 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2396 _synctex_error("Bad glue record (2).");
2397 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2399 SYNCTEX_SET_SIBLING(child,sibling);
2401 SYNCTEX_UPDATE_FRIEND(child);
2402 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2405 _synctex_error("Can't create glue record (2).");
2406 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2408 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_MATH) {
2410 if (NULL != (sibling = _synctex_new_math(scanner))
2411 && NULL != (info = SYNCTEX_INFO(sibling))) {
2412 if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2413 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2414 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2415 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2416 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2417 _synctex_error("Bad math record (2).");
2418 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2420 SYNCTEX_SET_SIBLING(child,sibling);
2422 SYNCTEX_UPDATE_FRIEND(child);
2423 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2426 _synctex_error("Can't create math record (2).");
2427 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2429 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BOUNDARY) {
2431 if (NULL != (sibling = _synctex_new_boundary(scanner))
2432 && NULL != (info = SYNCTEX_INFO(sibling))) {
2433 if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX)
2434 || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX)
2435 || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX)
2436 || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX)
2437 || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2438 _synctex_error("Bad boundary record (2).");
2439 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2441 SYNCTEX_SET_SIBLING(child,sibling);
2443 SYNCTEX_UPDATE_FRIEND(child);
2444 _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child));
2447 _synctex_error("Can't create boundary record (2).");
2448 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2450 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_END_SHEET) {
2452 } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_ANCHOR) {
2454 if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2455 _synctex_error("Missing anchor (2).");
2456 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2461 /* _synctex_error("Ignored record %c(2)\n",*SYNCTEX_CUR); */
2462 if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2463 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2469 status = _synctex_buffer_get_available_size(scanner,&available);
2470 if (status<SYNCTEX_STATUS_OK && available>0){
2473 _synctex_error("Uncomplete sheet(2)");
2474 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR);
2477 # undef SYNCTEX_DECODE_FAILED
2480 /* Used when parsing the synctex file
2482 synctex_status_t _synctex_scan_content(synctex_scanner_t scanner) {
2483 synctex_node_t sheet = NULL;
2484 synctex_status_t status = 0;
2485 if (NULL == scanner) {
2486 return SYNCTEX_STATUS_BAD_ARGUMENT;
2488 /* set up the lists of friends */
2489 if (NULL == scanner->lists_of_friends) {
2490 scanner->number_of_lists = 1024;
2491 scanner->lists_of_friends = (synctex_node_t *)_synctex_malloc(scanner->number_of_lists*sizeof(synctex_node_t));
2492 if (NULL == scanner->lists_of_friends) {
2493 _synctex_error("malloc:2");
2494 return SYNCTEX_STATUS_ERROR;
2497 /* Find where this section starts */
2499 status = _synctex_match_string(scanner,"Content:");
2500 if (status<SYNCTEX_STATUS_EOF) {
2503 if (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) {
2504 _synctex_error("Uncomplete Content.");
2505 return SYNCTEX_STATUS_ERROR;
2507 if (status == SYNCTEX_STATUS_NOT_OK) {
2508 goto content_not_found;
2511 if (*SYNCTEX_CUR != SYNCTEX_CHAR_BEGIN_SHEET) {
2512 status = _synctex_scan_postamble(scanner);
2513 if (status < SYNCTEX_STATUS_EOF) {
2514 _synctex_error("Bad content.");
2517 if (status<SYNCTEX_STATUS_OK) {
2518 status = _synctex_next_line(scanner);
2519 if (status < SYNCTEX_STATUS_OK) {
2520 _synctex_error("Bad content.");
2525 return SYNCTEX_STATUS_OK;
2528 /* Create a new sheet node */
2529 sheet = _synctex_new_sheet(scanner);
2530 status = _synctex_decode_int(scanner,&(SYNCTEX_PAGE(sheet)));
2531 if (status<SYNCTEX_STATUS_OK) {
2532 _synctex_error("Missing sheet number.");
2534 SYNCTEX_FREE(sheet);
2535 return SYNCTEX_STATUS_ERROR;
2537 status = _synctex_next_line(scanner);
2538 if (status<SYNCTEX_STATUS_OK) {
2539 _synctex_error("Uncomplete file.");
2542 status = _synctex_scan_sheet(scanner,sheet);
2543 if (status<SYNCTEX_STATUS_OK) {
2544 _synctex_error("Bad sheet content.");
2547 SYNCTEX_SET_SIBLING(sheet,scanner->sheet);
2548 scanner->sheet = sheet;
2550 /* Now read the list of Inputs between 2 sheets. */
2552 status = _synctex_scan_input(scanner);
2553 if (status<SYNCTEX_STATUS_EOF) {
2554 _synctex_error("Bad input section.");
2558 while(status >= SYNCTEX_STATUS_OK);
2562 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);
2564 /* Where the synctex scanner is created. */
2565 synctex_scanner_t synctex_scanner_new_with_output_file(const char * output, const char * build_directory, int parse) {
2567 char * synctex = NULL;
2568 synctex_scanner_t scanner = NULL;
2569 synctex_io_mode_t io_mode = 0;
2570 /* Here we assume that int are smaller than void * */
2571 if (sizeof(int)>sizeof(void*)) {
2572 _synctex_error("INTERNAL INCONSISTENCY: int's are unexpectedly bigger than pointers, bailing out.");
2575 /* We ensure that SYNCTEX_BUFFER_SIZE < UINT_MAX, I don't know if it makes sense... */
2576 if (SYNCTEX_BUFFER_SIZE >= UINT_MAX) {
2577 _synctex_error("SyncTeX BUG: Internal inconsistency, bad SYNCTEX_BUFFER_SIZE (1)");
2581 if (SYNCTEX_BUFFER_SIZE < SYNCTEX_BUFFER_MIN_SIZE) {
2582 _synctex_error("SyncTeX BUG: Internal inconsistency, bad SYNCTEX_BUFFER_SIZE (2)");
2585 /* now open the synctex file */
2586 if (_synctex_open(output,build_directory,&synctex,&file,synctex_ADD_QUOTES,&io_mode) || !file) {
2587 if (_synctex_open(output,build_directory,&synctex,&file,synctex_DONT_ADD_QUOTES,&io_mode) || !file) {
2591 scanner = (synctex_scanner_t)_synctex_malloc(sizeof(_synctex_scanner_t));
2592 if (NULL == scanner) {
2593 _synctex_error("SyncTeX: malloc problem");
2598 /* make a private copy of output for the scanner */
2599 if (NULL == (scanner->output = (char *)malloc(strlen(output)+1))){
2600 _synctex_error("! synctex_scanner_new_with_output_file: Memory problem (2), scanner's output is not reliable.");
2601 } else if (scanner->output != strcpy(scanner->output,output)) {
2602 _synctex_error("! synctex_scanner_new_with_output_file: Copy problem, scanner's output is not reliable.");
2604 scanner->synctex = synctex;/* Now the scanner owns synctex */
2605 SYNCTEX_FILE = file;
2606 return parse? synctex_scanner_parse(scanner):scanner;
2609 int __synctex_open(const char * output, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_mode_ref);
2611 /* This functions opens the file at the "output" given location.
2612 * It manages the problem of quoted filenames that appear with pdftex and filenames containing the space character.
2613 * In TeXLive 2008, the synctex file created with pdftex did contain unexpected quotes.
2614 * This function will remove them if possible.
2615 * All the reference arguments will take a value on return. They must be non NULL.
2616 * 0 on success, non 0 on error. */
2617 int __synctex_open(const char * output, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_mode_ref) {
2618 if (synctex_name_ref && file_ref && io_mode_ref) {
2619 /* 1 local variables that uses dynamic memory */
2620 char * synctex_name = NULL;
2621 gzFile the_file = NULL;
2622 char * quoteless_synctex_name = NULL;
2624 synctex_io_mode_t io_mode = *io_mode_ref;
2625 const char * mode = _synctex_get_io_mode_name(io_mode);
2626 /* now create the synctex file name */
2627 size = strlen(output)+strlen(synctex_suffix)+strlen(synctex_suffix_gz)+1;
2628 synctex_name = (char *)malloc(size);
2629 if (NULL == synctex_name) {
2630 _synctex_error("! __synctex_open: Memory problem (1)\n");
2633 /* we have reserved for synctex enough memory to copy output (including its 2 eventual quotes), both suffices,
2634 * including the terminating character. size is free now. */
2635 if (synctex_name != strcpy(synctex_name,output)) {
2636 _synctex_error("! __synctex_open: Copy problem\n");
2639 free(quoteless_synctex_name);
2642 /* remove the last path extension if any */
2643 _synctex_strip_last_path_extension(synctex_name);
2644 if (!strlen(synctex_name)) {
2645 goto return_on_error;
2647 /* now insert quotes. */
2649 char * quoted = NULL;
2650 if (_synctex_copy_with_quoting_last_path_component(synctex_name,"ed,size) || (NULL == quoted)) {
2651 /* There was an error or quoting does not make sense: */
2652 goto return_on_error;
2654 quoteless_synctex_name = synctex_name;
2655 synctex_name = quoted;
2657 /* Now add to synctex_name the first path extension. */
2658 if (synctex_name != strcat(synctex_name,synctex_suffix)){
2659 _synctex_error("! __synctex_open: Concatenation problem (can't add suffix '%s')\n",synctex_suffix);
2660 goto return_on_error;
2662 /* Add to quoteless_synctex_name as well, if relevant. */
2663 if (quoteless_synctex_name && (quoteless_synctex_name != strcat(quoteless_synctex_name,synctex_suffix))){
2664 free(quoteless_synctex_name);
2665 quoteless_synctex_name = NULL;
2667 if (NULL == (the_file = gzopen(synctex_name,mode))) {
2668 /* Could not open this file */
2669 if (errno != ENOENT) {
2670 /* The file does exist, this is a lower level error, I can't do anything. */
2671 _synctex_error("SyncTeX: could not open %s, error %i\n",synctex_name,errno);
2672 goto return_on_error;
2674 /* Apparently, there is no uncompressed synctex file. Try the compressed version */
2675 if (synctex_name != strcat(synctex_name,synctex_suffix_gz)){
2676 _synctex_error("! __synctex_open: Concatenation problem (can't add suffix '%s')\n",synctex_suffix_gz);
2677 goto return_on_error;
2679 io_mode |= synctex_io_gz_mask;
2680 mode = _synctex_get_io_mode_name(io_mode); /* the file is a compressed and is a binary file, this caused errors on Windows */
2681 /* Add the suffix to the quoteless_synctex_name as well. */
2682 if (quoteless_synctex_name && (quoteless_synctex_name != strcat(quoteless_synctex_name,synctex_suffix_gz))){
2683 free(quoteless_synctex_name);
2684 quoteless_synctex_name = NULL;
2686 if (NULL == (the_file = gzopen(synctex_name,mode))) {
2687 /* Could not open this file */
2688 if (errno != ENOENT) {
2689 /* The file does exist, this is a lower level error, I can't do anything. */
2690 _synctex_error("SyncTeX: could not open %s, error %i\n",synctex_name,errno);
2692 goto return_on_error;
2695 /* At this point, the file is properly open.
2696 * If we are in the add_quotes mode, we change the file name by removing the quotes. */
2697 if (quoteless_synctex_name) {
2699 if (rename(synctex_name,quoteless_synctex_name)) {
2700 _synctex_error("SyncTeX: could not rename %s to %s, error %i\n",synctex_name,quoteless_synctex_name,errno);
2701 /* We could not rename, reopen the file with the quoted name. */
2702 if (NULL == (the_file = gzopen(synctex_name,mode))) {
2703 /* No luck, could not re open this file, something has happened meanwhile */
2704 if (errno != ENOENT) {
2705 /* The file does not exist any more, it has certainly be removed somehow
2706 * this is a lower level error, I can't do anything. */
2707 _synctex_error("SyncTeX: could not open again %s, error %i\n",synctex_name,errno);
2709 goto return_on_error;
2712 /* The file has been successfully renamed */
2713 if (NULL == (the_file = gzopen(quoteless_synctex_name,mode))) {
2714 /* Could not open this file */
2715 if (errno != ENOENT) {
2716 /* The file does exist, this is a lower level error, I can't do anything. */
2717 _synctex_error("SyncTeX: could not open renamed %s, error %i\n",quoteless_synctex_name,errno);
2719 goto return_on_error;
2721 /* The quote free file name should replace the old one:*/
2723 synctex_name = quoteless_synctex_name;
2724 quoteless_synctex_name = NULL;
2727 /* The operation is successfull, return the arguments by value. */
2728 * file_ref = the_file;
2729 * io_mode_ref = io_mode;
2730 * synctex_name_ref = synctex_name;
2733 return 3; /* Bad parameter. */
2736 /* Opens the ouput file, taking into account the eventual build_directory.
2737 * 0 on success, non 0 on error. */
2738 int _synctex_open(const char * output, const char * build_directory, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_mode_ref) {
2739 # define synctex_name (*synctex_name_ref)
2740 # define the_file (*file_ref)
2741 int result = __synctex_open(output,synctex_name_ref,file_ref,add_quotes,io_mode_ref);
2742 if ((result || !*file_ref) && build_directory && strlen(build_directory)) {
2743 char * build_output;
2746 synctex_bool_t is_absolute;
2747 build_output = NULL;
2748 lpc = _synctex_last_path_component(output);
2749 size = strlen(build_directory)+strlen(lpc)+2; /* One for the '/' and one for the '\0'. */
2750 is_absolute = _synctex_path_is_absolute(build_directory);
2752 size += strlen(output);
2754 if ((build_output = (char *)malloc(size))) {
2756 build_output[0] = '\0';
2758 if (build_output != strcpy(build_output,output)) {
2761 build_output[lpc-output]='\0';
2763 if (build_output == strcat(build_output,build_directory)) {
2764 /* Append a path separator if necessary. */
2765 if (!SYNCTEX_IS_PATH_SEPARATOR(build_output[strlen(build_directory)-1])) {
2766 if (build_output != strcat(build_output,"/")) {
2770 /* Append the last path component of the output. */
2771 if (build_output != strcat(build_output,lpc)) {
2774 return __synctex_open(build_output,synctex_name_ref,file_ref,add_quotes,io_mode_ref);
2780 # undef synctex_name
2784 /* The scanner destructor
2786 void synctex_scanner_free(synctex_scanner_t scanner) {
2787 if (NULL == scanner) {
2791 gzclose(SYNCTEX_FILE);
2792 SYNCTEX_FILE = NULL;
2794 SYNCTEX_FREE(scanner->sheet);
2795 SYNCTEX_FREE(scanner->input);
2796 free(SYNCTEX_START);
2797 free(scanner->output_fmt);
2798 free(scanner->output);
2799 free(scanner->synctex);
2800 free(scanner->lists_of_friends);
2804 /* Where the synctex scanner parses the contents of the file. */
2805 synctex_scanner_t synctex_scanner_parse(synctex_scanner_t scanner) {
2806 synctex_status_t status = 0;
2807 if (!scanner || scanner->flags.has_parsed) {
2810 scanner->flags.has_parsed=1;
2811 scanner->pre_magnification = 1000;
2812 scanner->pre_unit = 8192;
2813 scanner->pre_x_offset = scanner->pre_y_offset = 578;
2814 /* initialize the offset with a fake unprobable value,
2815 * If there is a post scriptum section, this value will be overriden by the real life value */
2816 scanner->x_offset = scanner->y_offset = 6.027e23f;
2817 scanner->class[synctex_node_type_sheet] = synctex_class_sheet;
2818 scanner->class[synctex_node_type_input] = synctex_class_input;
2819 (scanner->class[synctex_node_type_input]).scanner = scanner;
2820 (scanner->class[synctex_node_type_sheet]).scanner = scanner;
2821 scanner->class[synctex_node_type_vbox] = synctex_class_vbox;
2822 (scanner->class[synctex_node_type_vbox]).scanner = scanner;
2823 scanner->class[synctex_node_type_void_vbox] = synctex_class_void_vbox;
2824 (scanner->class[synctex_node_type_void_vbox]).scanner = scanner;
2825 scanner->class[synctex_node_type_hbox] = synctex_class_hbox;
2826 (scanner->class[synctex_node_type_hbox]).scanner = scanner;
2827 scanner->class[synctex_node_type_void_hbox] = synctex_class_void_hbox;
2828 (scanner->class[synctex_node_type_void_hbox]).scanner = scanner;
2829 scanner->class[synctex_node_type_kern] = synctex_class_kern;
2830 (scanner->class[synctex_node_type_kern]).scanner = scanner;
2831 scanner->class[synctex_node_type_glue] = synctex_class_glue;
2832 (scanner->class[synctex_node_type_glue]).scanner = scanner;
2833 scanner->class[synctex_node_type_math] = synctex_class_math;
2834 (scanner->class[synctex_node_type_math]).scanner = scanner;
2835 scanner->class[synctex_node_type_boundary] = synctex_class_boundary;
2836 (scanner->class[synctex_node_type_boundary]).scanner = scanner;
2837 SYNCTEX_START = (char *)malloc(SYNCTEX_BUFFER_SIZE+1); /* one more character for null termination */
2838 if (NULL == SYNCTEX_START) {
2839 _synctex_error("SyncTeX: malloc error");
2840 synctex_scanner_free(scanner);
2843 SYNCTEX_END = SYNCTEX_START+SYNCTEX_BUFFER_SIZE;
2844 /* SYNCTEX_END always points to a null terminating character.
2845 * Maybe there is another null terminating character between SYNCTEX_CUR and SYNCTEX_END-1.
2846 * At least, we are sure that SYNCTEX_CUR points to a string covering a valid part of the memory. */
2847 *SYNCTEX_END = '\0';
2848 SYNCTEX_CUR = SYNCTEX_END;
2849 status = _synctex_scan_preamble(scanner);
2850 if (status<SYNCTEX_STATUS_OK) {
2851 _synctex_error("SyncTeX Error: Bad preamble\n");
2853 synctex_scanner_free(scanner);
2856 status = _synctex_scan_content(scanner);
2857 if (status<SYNCTEX_STATUS_OK) {
2858 _synctex_error("SyncTeX Error: Bad content\n");
2861 /* Everything is finished, free the buffer, close the file */
2862 free((void *)SYNCTEX_START);
2863 SYNCTEX_START = SYNCTEX_CUR = SYNCTEX_END = NULL;
2864 gzclose(SYNCTEX_FILE);
2865 SYNCTEX_FILE = NULL;
2866 /* Final tuning: set the default values for various parameters */
2867 /* 1 pre_unit = (scanner->pre_unit)/65536 pt = (scanner->pre_unit)/65781.76 bp
2868 * 1 pt = 65536 sp */
2869 if (scanner->pre_unit<=0) {
2870 scanner->pre_unit = 8192;
2872 if (scanner->pre_magnification<=0) {
2873 scanner->pre_magnification = 1000;
2875 if (scanner->unit <= 0) {
2876 /* no post magnification */
2877 scanner->unit = scanner->pre_unit / 65781.76;/* 65781.76 or 65536.0*/
2879 /* post magnification */
2880 scanner->unit *= scanner->pre_unit / 65781.76;
2882 scanner->unit *= scanner->pre_magnification / 1000.0;
2883 if (scanner->x_offset > 6e23) {
2884 /* no post offset */
2885 scanner->x_offset = scanner->pre_x_offset * (scanner->pre_unit / 65781.76);
2886 scanner->y_offset = scanner->pre_y_offset * (scanner->pre_unit / 65781.76);
2889 scanner->x_offset /= 65781.76f;
2890 scanner->y_offset /= 65781.76f;
2896 /* Scanner accessors.
2898 int synctex_scanner_pre_x_offset(synctex_scanner_t scanner){
2899 return scanner?scanner->pre_x_offset:0;
2901 int synctex_scanner_pre_y_offset(synctex_scanner_t scanner){
2902 return scanner?scanner->pre_y_offset:0;
2904 int synctex_scanner_x_offset(synctex_scanner_t scanner){
2905 return scanner?scanner->x_offset:0;
2907 int synctex_scanner_y_offset(synctex_scanner_t scanner){
2908 return scanner?scanner->y_offset:0;
2910 float synctex_scanner_magnification(synctex_scanner_t scanner){
2911 return scanner?scanner->unit:1;
2913 void synctex_scanner_display(synctex_scanner_t scanner) {
2914 if (NULL == scanner) {
2917 printf("The scanner:\noutput:%s\noutput_fmt:%s\nversion:%i\n",scanner->output,scanner->output_fmt,scanner->version);
2918 printf("pre_unit:%i\nx_offset:%i\ny_offset:%i\n",scanner->pre_unit,scanner->pre_x_offset,scanner->pre_y_offset);
2919 printf("count:%i\npost_magnification:%f\npost_x_offset:%f\npost_y_offset:%f\n",
2920 scanner->count,scanner->unit,scanner->x_offset,scanner->y_offset);
2921 printf("The input:\n");
2922 SYNCTEX_DISPLAY(scanner->input);
2923 if (scanner->count<1000) {
2924 printf("The sheets:\n");
2925 SYNCTEX_DISPLAY(scanner->sheet);
2926 printf("The friends:\n");
2927 if (scanner->lists_of_friends) {
2928 int i = scanner->number_of_lists;
2929 synctex_node_t node;
2931 printf("Friend index:%i\n",i);
2932 node = (scanner->lists_of_friends)[i];
2934 printf("%s:%i,%i\n",
2935 synctex_node_isa(node),
2939 node = SYNCTEX_FRIEND(node);
2944 printf("SyncTeX Warning: Too many objects\n");
2948 const char * synctex_scanner_get_name(synctex_scanner_t scanner,int tag) {
2949 synctex_node_t input = NULL;
2950 if (NULL == scanner) {
2953 input = scanner->input;
2955 if (tag == SYNCTEX_TAG(input)) {
2956 return (SYNCTEX_NAME(input));
2958 } while((input = SYNCTEX_SIBLING(input)) != NULL);
2962 int _synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name);
2963 int _synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name) {
2964 synctex_node_t input = NULL;
2965 if (NULL == scanner) {
2968 input = scanner->input;
2970 if (_synctex_is_equivalent_file_name(name,(SYNCTEX_NAME(input)))) {
2971 return SYNCTEX_TAG(input);
2973 } while((input = SYNCTEX_SIBLING(input)) != NULL);
2977 int synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name) {
2978 size_t char_index = strlen(name);
2979 if ((scanner = synctex_scanner_parse(scanner)) && (0 < char_index)) {
2980 /* the name is not void */
2982 if (!SYNCTEX_IS_PATH_SEPARATOR(name[char_index])) {
2983 /* the last character of name is not a path separator */
2984 int result = _synctex_scanner_get_tag(scanner,name);
2988 /* the given name was not the one known by TeX
2989 * try a name relative to the enclosing directory of the scanner->output file */
2990 const char * relative = name;
2991 const char * ptr = scanner->output;
2992 while((strlen(relative) > 0) && (strlen(ptr) > 0) && (*relative == *ptr))
2997 /* Find the last path separator before relative */
2998 while(relative > name) {
2999 if (SYNCTEX_IS_PATH_SEPARATOR(*(relative-1))) {
3004 if ((relative > name) && (result = _synctex_scanner_get_tag(scanner,relative))) {
3007 if (SYNCTEX_IS_PATH_SEPARATOR(name[0])) {
3008 /* No tag found for the given absolute name,
3009 * Try each relative path starting from the shortest one */
3010 while(0<char_index) {
3012 if (SYNCTEX_IS_PATH_SEPARATOR(name[char_index])
3013 && (result = _synctex_scanner_get_tag(scanner,name+char_index+1))) {
3024 synctex_node_t synctex_scanner_input(synctex_scanner_t scanner) {
3025 return scanner?scanner->input:NULL;
3027 const char * synctex_scanner_get_output_fmt(synctex_scanner_t scanner) {
3028 return NULL != scanner && scanner->output_fmt?scanner->output_fmt:"";
3030 const char * synctex_scanner_get_output(synctex_scanner_t scanner) {
3031 return NULL != scanner && scanner->output?scanner->output:"";
3033 const char * synctex_scanner_get_synctex(synctex_scanner_t scanner) {
3034 return NULL != scanner && scanner->synctex?scanner->synctex:"";
3036 # ifdef SYNCTEX_NOTHING
3038 # pragma mark Public node attributes
3040 int synctex_node_h(synctex_node_t node){
3044 return SYNCTEX_HORIZ(node);
3046 int synctex_node_v(synctex_node_t node){
3050 return SYNCTEX_VERT(node);
3052 int synctex_node_width(synctex_node_t node){
3056 return SYNCTEX_WIDTH(node);
3058 int synctex_node_box_h(synctex_node_t node){
3062 if (SYNCTEX_IS_BOX(node)) {
3064 return SYNCTEX_HORIZ(node);
3066 if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3071 int synctex_node_box_v(synctex_node_t node){
3075 if (SYNCTEX_IS_BOX(node)) {
3077 return SYNCTEX_VERT(node);
3079 if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3084 int synctex_node_box_width(synctex_node_t node){
3088 if (SYNCTEX_IS_BOX(node)) {
3090 return SYNCTEX_WIDTH(node);
3092 if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3097 int synctex_node_box_height(synctex_node_t node){
3101 if (SYNCTEX_IS_BOX(node)) {
3103 return SYNCTEX_HEIGHT(node);
3105 if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3110 int synctex_node_box_depth(synctex_node_t node){
3114 if (SYNCTEX_IS_BOX(node)) {
3116 return SYNCTEX_DEPTH(node);
3118 if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3123 # ifdef SYNCTEX_NOTHING
3125 # pragma mark Public node visible attributes
3127 float synctex_node_visible_h(synctex_node_t node){
3131 return SYNCTEX_HORIZ(node)*node->class->scanner->unit+node->class->scanner->x_offset;
3133 float synctex_node_visible_v(synctex_node_t node){
3137 return SYNCTEX_VERT(node)*node->class->scanner->unit+node->class->scanner->y_offset;
3139 float synctex_node_visible_width(synctex_node_t node){
3143 return SYNCTEX_WIDTH(node)*node->class->scanner->unit;
3145 float synctex_node_box_visible_h(synctex_node_t node){
3149 switch(node->class->type) {
3150 case synctex_node_type_vbox:
3151 case synctex_node_type_void_vbox:
3152 case synctex_node_type_void_hbox:
3153 return SYNCTEX_HORIZ(node)*node->class->scanner->unit+node->class->scanner->x_offset;
3154 case synctex_node_type_hbox:
3156 return SYNCTEX_HORIZ_V(node)*node->class->scanner->unit+node->class->scanner->x_offset;
3158 if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3163 float synctex_node_box_visible_v(synctex_node_t node){
3167 switch(node->class->type) {
3168 case synctex_node_type_vbox:
3169 case synctex_node_type_void_vbox:
3170 case synctex_node_type_void_hbox:
3171 return SYNCTEX_VERT(node)*node->class->scanner->unit+node->class->scanner->y_offset;
3172 case synctex_node_type_hbox:
3174 return SYNCTEX_VERT_V(node)*node->class->scanner->unit+node->class->scanner->y_offset;
3176 if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3181 float synctex_node_box_visible_width(synctex_node_t node){
3185 switch(node->class->type) {
3186 case synctex_node_type_vbox:
3187 case synctex_node_type_void_vbox:
3188 case synctex_node_type_void_hbox:
3189 return SYNCTEX_WIDTH(node)*node->class->scanner->unit;
3190 case synctex_node_type_hbox:
3192 return SYNCTEX_WIDTH_V(node)*node->class->scanner->unit;
3194 if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3199 float synctex_node_box_visible_height(synctex_node_t node){
3203 switch(node->class->type) {
3204 case synctex_node_type_vbox:
3205 case synctex_node_type_void_vbox:
3206 case synctex_node_type_void_hbox:
3207 return SYNCTEX_HEIGHT(node)*node->class->scanner->unit;
3208 case synctex_node_type_hbox:
3210 return SYNCTEX_HEIGHT_V(node)*node->class->scanner->unit;
3212 if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3217 float synctex_node_box_visible_depth(synctex_node_t node){
3221 switch(node->class->type) {
3222 case synctex_node_type_vbox:
3223 case synctex_node_type_void_vbox:
3224 case synctex_node_type_void_hbox:
3225 return SYNCTEX_DEPTH(node)*node->class->scanner->unit;
3226 case synctex_node_type_hbox:
3228 return SYNCTEX_DEPTH_V(node)*node->class->scanner->unit;
3230 if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) {
3235 # ifdef SYNCTEX_NOTHING
3237 # pragma mark Other public node attributes
3240 int synctex_node_page(synctex_node_t node){
3241 synctex_node_t parent = NULL;
3245 parent = SYNCTEX_PARENT(node);
3248 parent = SYNCTEX_PARENT(node);
3250 if (node->class->type == synctex_node_type_sheet) {
3251 return SYNCTEX_PAGE(node);
3255 int synctex_node_tag(synctex_node_t node) {
3256 return node?SYNCTEX_TAG(node):-1;
3258 int synctex_node_line(synctex_node_t node) {
3259 return node?SYNCTEX_LINE(node):-1;
3261 int synctex_node_column(synctex_node_t node) {
3262 # ifdef __DARWIN_UNIX03
3263 # pragma unused(node)
3267 # ifdef SYNCTEX_NOTHING
3272 synctex_node_t synctex_sheet_content(synctex_scanner_t scanner,int page) {
3274 synctex_node_t sheet = scanner->sheet;
3276 if (page == SYNCTEX_PAGE(sheet)) {
3277 return SYNCTEX_CHILD(sheet);
3279 sheet = SYNCTEX_SIBLING(sheet);
3285 # ifdef SYNCTEX_NOTHING
3290 int synctex_display_query(synctex_scanner_t scanner,const char * name,int line,int column) {
3291 # ifdef __DARWIN_UNIX03
3292 # pragma unused(column)
3294 int tag = synctex_scanner_get_tag(scanner,name);
3296 int friend_index = 0;
3298 synctex_node_t node = NULL;
3300 printf("SyncTeX Warning: No tag for %s\n",name);
3303 free(SYNCTEX_START);
3304 SYNCTEX_CUR = SYNCTEX_END = SYNCTEX_START = NULL;
3305 max_line = line < INT_MAX-scanner->number_of_lists ? line+scanner->number_of_lists:INT_MAX;
3306 while(line<max_line) {
3307 /* This loop will only be performed once for advanced viewers */
3308 friend_index = (tag+line)%(scanner->number_of_lists);
3309 if ((node = (scanner->lists_of_friends)[friend_index])) {
3311 if ((synctex_node_type(node)>=synctex_node_type_boundary)
3312 && (tag == SYNCTEX_TAG(node))
3313 && (line == SYNCTEX_LINE(node))) {
3314 if (SYNCTEX_CUR == SYNCTEX_END) {
3316 SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *));
3317 SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START;
3318 SYNCTEX_START = SYNCTEX_END;
3319 SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *);
3321 *(synctex_node_t *)SYNCTEX_CUR = node;
3322 SYNCTEX_CUR += sizeof(synctex_node_t);
3324 } while((node = SYNCTEX_FRIEND(node)));
3325 if (SYNCTEX_START == NULL) {
3326 /* We did not find any matching boundary, retry with glue or kern */
3327 node = (scanner->lists_of_friends)[friend_index];/* no need to test it again, already done */
3329 if ((synctex_node_type(node)>=synctex_node_type_kern)
3330 && (tag == SYNCTEX_TAG(node))
3331 && (line == SYNCTEX_LINE(node))) {
3332 if (SYNCTEX_CUR == SYNCTEX_END) {
3334 SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *));
3335 SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START;
3336 SYNCTEX_START = SYNCTEX_END;
3337 SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *);
3339 *(synctex_node_t *)SYNCTEX_CUR = node;
3340 SYNCTEX_CUR += sizeof(synctex_node_t);
3342 } while((node = SYNCTEX_FRIEND(node)));
3343 if (SYNCTEX_START == NULL) {
3344 /* We did not find any matching glue or kern, retry with boxes */
3345 node = (scanner->lists_of_friends)[friend_index];/* no need to test it again, already done */
3347 if ((tag == SYNCTEX_TAG(node))
3348 && (line == SYNCTEX_LINE(node))) {
3349 if (SYNCTEX_CUR == SYNCTEX_END) {
3351 SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *));
3352 SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START;
3353 SYNCTEX_START = SYNCTEX_END;
3354 SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *);
3356 *(synctex_node_t *)SYNCTEX_CUR = node;
3357 SYNCTEX_CUR += sizeof(synctex_node_t);
3359 } while((node = SYNCTEX_FRIEND(node)));
3362 SYNCTEX_END = SYNCTEX_CUR;
3363 /* Now reverse the order to have nodes in display order, and keep just a few nodes */
3364 if ((SYNCTEX_START) && (SYNCTEX_END))
3366 synctex_node_t * start_ref = (synctex_node_t *)SYNCTEX_START;
3367 synctex_node_t * end_ref = (synctex_node_t *)SYNCTEX_END;
3369 while(start_ref < end_ref) {
3371 *start_ref = *end_ref;
3376 /* Basically, we keep the first node for each parent.
3377 * More precisely, we keep only nodes that are not descendants of
3378 * their predecessor's parent. */
3379 start_ref = (synctex_node_t *)SYNCTEX_START;
3380 end_ref = (synctex_node_t *)SYNCTEX_START;
3382 end_ref += 1; /* we allways have start_ref<= end_ref*/
3383 if (end_ref < (synctex_node_t *)SYNCTEX_END) {
3385 while((node = SYNCTEX_PARENT(node))) {
3386 if (SYNCTEX_PARENT(*start_ref) == node) {
3391 *start_ref = *end_ref;
3395 SYNCTEX_END = (char *)start_ref;
3396 return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t);// added on behalf Jan Sundermeyer
3399 // return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t); removed on behalf Jan Sundermeyer
3401 # if defined(__SYNCTEX_STRONG_DISPLAY_QUERY__)
3410 synctex_node_t synctex_next_result(synctex_scanner_t scanner) {
3411 if (NULL == SYNCTEX_CUR) {
3412 SYNCTEX_CUR = SYNCTEX_START;
3414 SYNCTEX_CUR+=sizeof(synctex_node_t);
3416 if (SYNCTEX_CUR<SYNCTEX_END) {
3417 return *(synctex_node_t*)SYNCTEX_CUR;
3423 /* This struct records a point in TeX coordinates.*/
3429 /* This struct records distances, the left one is positive or 0 and the right one is negative or 0.
3430 * When comparing the locations of 2 different graphical objects on the page, we will have to also record the
3431 * horizontal distance as signed to keep track of the typesetting order.*/
3435 } synctex_distances_t;
3438 synctex_point_t left;
3439 synctex_point_t right;
3440 } synctex_offsets_t;
3444 synctex_node_t left;
3445 synctex_node_t right;
3446 } synctex_node_set_t;
3448 /* The smallest container between two has the smallest width or height.
3449 * This comparison is used when there are 2 overlapping boxes that contain the hit point.
3450 * For ConTeXt, the problem appears at each page.
3451 * The chosen box is the one with the smallest height, then the smallest width. */
3452 SYNCTEX_INLINE static synctex_node_t _synctex_smallest_container(synctex_node_t node, synctex_node_t other_node);
3454 /* Returns the distance between the hit point hitPoint=(H,V) and the given node. */
3455 synctex_bool_t _synctex_point_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible);
3456 int _synctex_node_distance_to_point(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible);
3458 /* The best container is the deeper box that contains the hit point (H,V).
3459 * _synctex_eq_deepest_container starts with node whereas
3460 * _synctex_box_child_deepest starts with node's children, if any
3461 * if node is not a box, or a void box, NULL is returned.
3462 * We traverse the node tree in a deep first manner and stop as soon as a result is found. */
3463 static synctex_node_t _synctex_eq_deepest_container(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible);
3465 /* Once a best container is found, the closest children are the closest nodes to the left or right of the hit point.
3466 * Only horizontal and vertical offsets are used to compare the positions of the nodes. */
3467 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);
3469 /* The closest container is the box that is the one closest to the given point.
3470 * The "visible" version takes into account the visible dimensions instead of the real ones given by TeX. */
3471 SYNCTEX_INLINE static synctex_node_t _synctex_eq_closest_child(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible);
3473 #define SYNCTEX_MASK_LEFT 1
3474 #define SYNCTEX_MASK_RIGHT 2
3476 int synctex_edit_query(synctex_scanner_t scanner,int page,float h,float v) {
3477 synctex_node_t sheet = NULL;
3478 synctex_node_t node = NULL; /* placeholder */
3479 synctex_node_t other_node = NULL; /* placeholder */
3480 synctex_point_t hitPoint = {0,0}; /* placeholder */
3481 synctex_node_set_t bestNodes = {NULL,NULL}; /* holds the best node */
3482 synctex_distances_t bestDistances = {INT_MAX,INT_MAX}; /* holds the best distances for the best node */
3483 synctex_node_t bestContainer = NULL; /* placeholder */
3484 if (NULL == (scanner = synctex_scanner_parse(scanner)) || 0 >= scanner->unit) {/* scanner->unit must be >0 */
3487 /* Convert the given point to scanner integer coordinates */
3488 hitPoint.h = (h-scanner->x_offset)/scanner->unit;
3489 hitPoint.v = (v-scanner->y_offset)/scanner->unit;
3490 /* We will store in the scanner's buffer the result of the query. */
3491 free(SYNCTEX_START);
3492 SYNCTEX_START = SYNCTEX_END = SYNCTEX_CUR = NULL;
3493 /* Find the proper sheet */
3494 sheet = scanner->sheet;
3495 while((sheet) && SYNCTEX_PAGE(sheet) != page) {
3496 sheet = SYNCTEX_SIBLING(sheet);
3498 if (NULL == sheet) {
3501 /* Now sheet points to the sheet node with proper page number */
3502 /* Here is how we work:
3503 * At first we do not consider the visible box dimensions. This will cover the most frequent cases.
3504 * Then we try with the visible box dimensions.
3505 * We try to find a non void box containing the hit point.
3506 * We browse all the horizontal boxes until we find one containing the hit point. */
3507 if ((node = SYNCTEX_NEXT_HORIZ_BOX(sheet))) {
3509 if (_synctex_point_in_box(hitPoint,node,synctex_YES)) {
3510 /* Maybe the hitPoint belongs to a contained vertical box. */
3512 /* This trick is for catching overlapping boxes */
3513 if ((other_node = SYNCTEX_NEXT_HORIZ_BOX(node))) {
3515 if (_synctex_point_in_box(hitPoint,other_node,synctex_YES)) {
3516 node = _synctex_smallest_container(other_node,node);
3518 } while((other_node = SYNCTEX_NEXT_HORIZ_BOX(other_node)));
3520 /* node is the smallest horizontal box that contains hitPoint. */
3521 if ((bestContainer = _synctex_eq_deepest_container(hitPoint,node,synctex_YES))) {
3522 node = bestContainer;
3524 _synctex_eq_get_closest_children_in_box(hitPoint,node,&bestNodes,&bestDistances,synctex_YES);
3525 if (bestNodes.right && bestNodes.left) {
3526 if ((SYNCTEX_TAG(bestNodes.right)!=SYNCTEX_TAG(bestNodes.left))
3527 || (SYNCTEX_LINE(bestNodes.right)!=SYNCTEX_LINE(bestNodes.left))
3528 || (SYNCTEX_COLUMN(bestNodes.right)!=SYNCTEX_COLUMN(bestNodes.left))) {
3529 if ((SYNCTEX_START = malloc(2*sizeof(synctex_node_t)))) {
3530 if (bestDistances.left>bestDistances.right) {
3531 ((synctex_node_t *)SYNCTEX_START)[0] = bestNodes.right;
3532 ((synctex_node_t *)SYNCTEX_START)[1] = bestNodes.left;
3534 ((synctex_node_t *)SYNCTEX_START)[0] = bestNodes.left;
3535 ((synctex_node_t *)SYNCTEX_START)[1] = bestNodes.right;
3537 SYNCTEX_END = SYNCTEX_START + 2*sizeof(synctex_node_t);
3539 return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t);
3541 return SYNCTEX_STATUS_ERROR;
3543 /* both nodes have the same input coordinates
3544 * We choose the one closest to the hit point */
3545 if (bestDistances.left>bestDistances.right) {
3546 bestNodes.left = bestNodes.right;
3548 bestNodes.right = NULL;
3549 } else if (bestNodes.right) {
3550 bestNodes.left = bestNodes.right;
3551 } else if (!bestNodes.left){
3552 bestNodes.left = node;
3554 if ((SYNCTEX_START = malloc(sizeof(synctex_node_t)))) {
3555 * (synctex_node_t *)SYNCTEX_START = bestNodes.left;
3556 SYNCTEX_END = SYNCTEX_START + sizeof(synctex_node_t);
3558 return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t);
3560 return SYNCTEX_STATUS_ERROR;
3562 } while ((node = SYNCTEX_NEXT_HORIZ_BOX(node)));
3563 /* All the horizontal boxes have been tested,
3564 * None of them contains the hit point.
3567 /* We are not lucky */
3568 if ((node = SYNCTEX_CHILD(sheet))) {
3574 # ifdef SYNCTEX_NOTHING
3576 # pragma mark Utilities
3579 int _synctex_bail(void) {
3580 _synctex_error("SyncTeX ERROR\n");
3583 /* Rougly speaking, this is:
3584 * node's h coordinate - hitPoint's h coordinate.
3585 * If node is to the right of the hit point, then this distance is positive,
3586 * if node is to the left of the hit point, this distance is negative.*/
3587 int _synctex_point_h_distance(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible);
3588 int _synctex_point_h_distance(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) {
3591 switch(node->class->type) {
3592 /* The distance between a point and a box is special.
3593 * It is not the euclidian distance, nor something similar.
3594 * We have to take into account the particular layout,
3595 * and the box hierarchy.
3596 * Given a box, there are 9 regions delimited by the lines of the edges of the box.
3597 * The origin being at the top left corner of the page,
3598 * we also give names to the vertices of the box.
3607 case synctex_node_type_hbox:
3608 /* getting the box bounds, taking into account negative width, height and depth. */
3609 min = visible?SYNCTEX_HORIZ_V(node):SYNCTEX_HORIZ(node);
3610 max = min + (visible?SYNCTEX_ABS_WIDTH_V(node):SYNCTEX_ABS_WIDTH(node));
3611 /* We allways have min <= max */
3612 if (hitPoint.h<min) {
3613 return min - hitPoint.h; /* regions 1+4+7, result is > 0 */
3614 } else if (hitPoint.h>max) {
3615 return max - hitPoint.h; /* regions 3+6+9, result is < 0 */
3617 return 0; /* regions 2+5+8, inside the box, except for vertical coordinates */
3620 case synctex_node_type_vbox:
3621 case synctex_node_type_void_vbox:
3622 case synctex_node_type_void_hbox:
3623 /* getting the box bounds, taking into account negative width, height and depth.
3624 * For these boxes, no visible dimension available */
3625 min = SYNCTEX_HORIZ(node);
3626 max = min + SYNCTEX_ABS_WIDTH(node);
3627 /* We allways have min <= max */
3628 if (hitPoint.h<min) {
3629 return min - hitPoint.h; /* regions 1+4+7, result is > 0 */
3630 } else if (hitPoint.h>max) {
3631 return max - hitPoint.h; /* regions 3+6+9, result is < 0 */
3633 return 0; /* regions 2+5+8, inside the box, except for vertical coordinates */
3636 case synctex_node_type_kern:
3637 /* IMPORTANT NOTICE: the location of the kern is recorded AFTER the move.
3638 * The distance to the kern is very special,
3639 * in general, there is no text material in the kern,
3640 * this is why we compute the offset relative to the closest edge of the kern.*/
3641 max = SYNCTEX_WIDTH(node);
3643 min = SYNCTEX_HORIZ(node);
3647 max = SYNCTEX_HORIZ(node);
3651 /* positive kern: '.' means text, '>' means kern offset
3655 * negative kern: '.' means text, '<' means kern offset
3656 * ............................
3658 * .................................
3659 * Actually, we do not take into account negative widths.
3660 * There is a problem for such situation when there is efectively overlapping text.
3661 * But this should be extremely rare. I guess that in that case, many different choices
3662 * could be made, one being in contradiction of the other.
3663 * It means that the best choice should be made according to the situation that occurs
3666 if (hitPoint.h<min) {
3667 return min - hitPoint.h + 1; /* penalty to ensure other nodes are chosen first in case of overlapping ones */
3668 } else if (hitPoint.h>max) {
3669 return max - hitPoint.h - 1; /* same kind of penalty */
3670 } else if (hitPoint.h>med) {
3671 /* do things like if the node had 0 width and was placed at the max edge + 1*/
3672 return max - hitPoint.h + 1; /* positive, the kern is to the right of the hitPoint */
3674 return min - hitPoint.h - 1; /* negative, the kern is to the left of the hitPoint */
3676 case synctex_node_type_glue:
3677 case synctex_node_type_math:
3678 return SYNCTEX_HORIZ(node) - hitPoint.h;
3681 return INT_MAX;/* We always assume that the node is faraway to the right*/
3683 /* Rougly speaking, this is:
3684 * node's v coordinate - hitPoint's v coordinate.
3685 * If node is at the top of the hit point, then this distance is positive,
3686 * if node is at the bottom of the hit point, this distance is negative.*/
3687 int _synctex_point_v_distance(synctex_point_t hitPoint, synctex_node_t node,synctex_bool_t visible);
3688 int _synctex_point_v_distance(synctex_point_t hitPoint, synctex_node_t node,synctex_bool_t visible) {
3689 # ifdef __DARWIN_UNIX03
3690 # pragma unused(visible)
3694 switch(node->class->type) {
3695 /* The distance between a point and a box is special.
3696 * It is not the euclidian distance, nor something similar.
3697 * We have to take into account the particular layout,
3698 * and the box hierarchy.
3699 * Given a box, there are 9 regions delimited by the lines of the edges of the box.
3700 * The origin being at the top left corner of the page,
3701 * we also give names to the vertices of the box.
3710 case synctex_node_type_hbox:
3711 /* getting the box bounds, taking into account negative width, height and depth. */
3712 min = SYNCTEX_VERT_V(node);
3713 max = min + SYNCTEX_ABS_DEPTH_V(node);
3714 min -= SYNCTEX_ABS_HEIGHT_V(node);
3715 /* We allways have min <= max */
3716 if (hitPoint.v<min) {
3717 return min - hitPoint.v; /* regions 1+2+3, result is > 0 */
3718 } else if (hitPoint.v>max) {
3719 return max - hitPoint.v; /* regions 7+8+9, result is < 0 */
3721 return 0; /* regions 4.5.6, inside the box, except for horizontal coordinates */
3724 case synctex_node_type_vbox:
3725 case synctex_node_type_void_vbox:
3726 case synctex_node_type_void_hbox:
3727 /* getting the box bounds, taking into account negative width, height and depth. */
3728 min = SYNCTEX_VERT(node);
3729 max = min + SYNCTEX_ABS_DEPTH(node);
3730 min -= SYNCTEX_ABS_HEIGHT(node);
3731 /* We allways have min <= max */
3732 if (hitPoint.v<min) {
3733 return min - hitPoint.v; /* regions 1+2+3, result is > 0 */
3734 } else if (hitPoint.v>max) {
3735 return max - hitPoint.v; /* regions 7+8+9, result is < 0 */
3737 return 0; /* regions 4.5.6, inside the box, except for horizontal coordinates */
3740 case synctex_node_type_kern:
3741 case synctex_node_type_glue:
3742 case synctex_node_type_math:
3743 return SYNCTEX_VERT(node) - hitPoint.v;
3746 return INT_MAX;/* We always assume that the node is faraway to the top*/
3749 SYNCTEX_INLINE static synctex_node_t _synctex_smallest_container(synctex_node_t node, synctex_node_t other_node) {
3750 float height, other_height;
3751 if (SYNCTEX_ABS_WIDTH(node)<SYNCTEX_ABS_WIDTH(other_node)) {
3754 if (SYNCTEX_ABS_WIDTH(node)>SYNCTEX_ABS_WIDTH(other_node)) {
3757 height = SYNCTEX_ABS_DEPTH(node) + SYNCTEX_ABS_HEIGHT(node);
3758 other_height = SYNCTEX_ABS_DEPTH(other_node) + SYNCTEX_ABS_HEIGHT(other_node);
3759 if (height<other_height) {
3762 if (height>other_height) {
3768 synctex_bool_t _synctex_point_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) {
3770 if (0 == _synctex_point_h_distance(hitPoint,node,visible)
3771 && 0 == _synctex_point_v_distance(hitPoint,node,visible)) {
3778 int _synctex_node_distance_to_point(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) {
3779 # ifdef __DARWIN_UNIX03
3780 # pragma unused(visible)
3782 int result = INT_MAX; /* when the distance is meaning less (sheet, input...) */
3784 int minH,maxH,minV,maxV;
3785 switch(node->class->type) {
3786 /* The distance between a point and a box is special.
3787 * It is not the euclidian distance, nor something similar.
3788 * We have to take into account the particular layout,
3789 * and the box hierarchy.
3790 * Given a box, there are 9 regions delimited by the lines of the edges of the box.
3791 * The origin being at the top left corner of the page,
3792 * we also give names to the vertices of the box.
3800 * In each region, there is a different formula.
3801 * In the end we have a continuous distance which may not be a mathematical distance but who cares. */
3802 case synctex_node_type_vbox:
3803 case synctex_node_type_void_vbox:
3804 case synctex_node_type_hbox:
3805 case synctex_node_type_void_hbox:
3806 /* getting the box bounds, taking into account negative widths. */
3807 minH = SYNCTEX_HORIZ(node);
3808 maxH = minH + SYNCTEX_ABS_WIDTH(node);
3809 minV = SYNCTEX_VERT(node);
3810 maxV = minV + SYNCTEX_ABS_DEPTH(node);
3811 minV -= SYNCTEX_ABS_HEIGHT(node);
3812 /* In what region is the point hitPoint=(H,V) ? */
3813 if (hitPoint.v<minV) {
3814 if (hitPoint.h<minH) {
3815 /* This is region 1. The distance to the box is the L1 distance PA. */
3816 result = minV - hitPoint.v + minH - hitPoint.h;/* Integer overflow? probability epsilon */
3817 } else if (hitPoint.h<=maxH) {
3818 /* This is region 2. The distance to the box is the geometrical distance to the top edge. */
3819 result = minV - hitPoint.v;
3821 /* This is region 3. The distance to the box is the L1 distance PB. */
3822 result = minV - hitPoint.v + hitPoint.h - maxH;
3824 } else if (hitPoint.v<=maxV) {
3825 if (hitPoint.h<minH) {
3826 /* This is region 4. The distance to the box is the geometrical distance to the left edge. */
3827 result = minH - hitPoint.h;
3828 } else if (hitPoint.h<=maxH) {
3829 /* This is region 4. We are inside the box. */
3832 /* This is region 6. The distance to the box is the geometrical distance to the right edge. */
3833 result = hitPoint.h - maxH;
3836 if (hitPoint.h<minH) {
3837 /* This is region 7. The distance to the box is the L1 distance PC. */
3838 result = hitPoint.v - maxV + minH - hitPoint.h;
3839 } else if (hitPoint.h<=maxH) {
3840 /* This is region 8. The distance to the box is the geometrical distance to the top edge. */
3841 result = hitPoint.v - maxV;
3843 /* This is region 9. The distance to the box is the L1 distance PD. */
3844 result = hitPoint.v - maxV + hitPoint.h - maxH;
3848 case synctex_node_type_kern:
3849 maxH = SYNCTEX_WIDTH(node);
3851 minH = SYNCTEX_HORIZ(node);
3855 maxH = SYNCTEX_HORIZ(node);
3858 minV = SYNCTEX_VERT(node);
3859 if (hitPoint.h<minH) {
3860 if (hitPoint.v>minV) {
3861 result = hitPoint.v - minV + minH - hitPoint.h;
3863 result = minV - hitPoint.v + minH - hitPoint.h;
3865 } else if (hitPoint.h>maxH) {
3866 if (hitPoint.v>minV) {
3867 result = hitPoint.v - minV + hitPoint.h - maxH;
3869 result = minV - hitPoint.v + hitPoint.h - maxH;
3871 } else if (hitPoint.v>minV) {
3872 result = hitPoint.v - minV;
3874 result = minV - hitPoint.v;
3877 case synctex_node_type_glue:
3878 case synctex_node_type_math:
3879 minH = SYNCTEX_HORIZ(node);
3880 minV = SYNCTEX_VERT(node);
3881 if (hitPoint.h<minH) {
3882 if (hitPoint.v>minV) {
3883 result = hitPoint.v - minV + minH - hitPoint.h;
3885 result = minV - hitPoint.v + minH - hitPoint.h;
3887 } else if (hitPoint.v>minV) {
3888 result = hitPoint.v - minV + hitPoint.h - minH;
3890 result = minV - hitPoint.v + hitPoint.h - minH;
3898 static synctex_node_t _synctex_eq_deepest_container(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible) {
3900 synctex_node_t result = NULL;
3901 synctex_node_t child = NULL;
3902 switch(node->class->type) {
3903 case synctex_node_type_vbox:
3904 case synctex_node_type_hbox:
3905 /* test the deep nodes first */
3906 if ((child = SYNCTEX_CHILD(node))) {
3908 if ((result = _synctex_eq_deepest_container(hitPoint,child,visible))) {
3911 } while((child = SYNCTEX_SIBLING(child)));
3913 /* is the hit point inside the box? */
3914 if (_synctex_point_in_box(hitPoint,node,visible)) {
3915 /* for vboxes we try to use some node inside.
3916 * Walk through the list of siblings until we find the closest one.
3917 * Only consider siblings with children. */
3918 if ((node->class->type == synctex_node_type_vbox) && (child = SYNCTEX_CHILD(node))) {
3919 int bestDistance = INT_MAX;
3921 if (SYNCTEX_CHILD(child)) {
3922 int distance = _synctex_node_distance_to_point(hitPoint,child,visible);
3923 if (distance < bestDistance) {
3924 bestDistance = distance;
3928 } while((child = SYNCTEX_SIBLING(child)));
3937 /* Compares the locations of the hitPoint with the locations of the various nodes contained in the box.
3938 * As it is an horizontal box, we only compare horizontal coordinates. */
3939 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);
3940 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) {
3942 if ((node = SYNCTEX_CHILD(node))) {
3944 int off7 = _synctex_point_h_distance(hitPoint,node,visible);
3946 /* node is to the right of the hit point.
3947 * We compare node and the previously recorded one, through the recorded distance.
3948 * If the nodes have the same tag, prefer the one with the smallest line number,
3949 * if the nodes also have the same line number, prefer the one with the smallest column. */
3950 if (bestDistancesRef->right > off7) {
3951 bestDistancesRef->right = off7;
3952 bestNodesRef->right = node;
3953 result |= SYNCTEX_MASK_RIGHT;
3954 } else if (bestDistancesRef->right == off7 && bestNodesRef->right) {
3955 if (SYNCTEX_TAG(bestNodesRef->right) == SYNCTEX_TAG(node)
3956 && (SYNCTEX_LINE(bestNodesRef->right) > SYNCTEX_LINE(node)
3957 || (SYNCTEX_LINE(bestNodesRef->right) == SYNCTEX_LINE(node)
3958 && SYNCTEX_COLUMN(bestNodesRef->right) > SYNCTEX_COLUMN(node)))) {
3959 bestNodesRef->right = node;
3960 result |= SYNCTEX_MASK_RIGHT;
3963 } else if (off7 == 0) {
3964 /* hitPoint is inside node. */
3965 bestDistancesRef->left = bestDistancesRef->right = 0;
3966 bestNodesRef->left = node;
3967 bestNodesRef->right = NULL;
3968 result |= SYNCTEX_MASK_LEFT;
3969 } else { /* here off7 < 0, hitPoint is to the right of node */
3971 if (bestDistancesRef->left > off7) {
3972 bestDistancesRef->left = off7;
3973 bestNodesRef->left = node;
3974 result |= SYNCTEX_MASK_LEFT;
3975 } else if (bestDistancesRef->left == off7 && bestNodesRef->left) {
3976 if (SYNCTEX_TAG(bestNodesRef->left) == SYNCTEX_TAG(node)
3977 && (SYNCTEX_LINE(bestNodesRef->left) > SYNCTEX_LINE(node)
3978 || (SYNCTEX_LINE(bestNodesRef->left) == SYNCTEX_LINE(node)
3979 && SYNCTEX_COLUMN(bestNodesRef->left) > SYNCTEX_COLUMN(node)))) {
3980 bestNodesRef->left = node;
3981 result |= SYNCTEX_MASK_LEFT;
3985 } while((node = SYNCTEX_SIBLING(node)));
3986 if (result & SYNCTEX_MASK_LEFT) {
3987 /* the left node is new, try to narrow the result */
3988 if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->left,visible))) {
3989 bestNodesRef->left = node;
3991 if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->left,visible))) {
3992 bestNodesRef->left = node;
3995 if (result & SYNCTEX_MASK_RIGHT) {
3996 /* the right node is new, try to narrow the result */
3997 if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->right,visible))) {
3998 bestNodesRef->right = node;
4000 if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->right,visible))) {
4001 bestNodesRef->right = node;
4007 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);
4008 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) {
4010 if ((node = SYNCTEX_CHILD(node))) {
4012 int off7 = _synctex_point_v_distance(hitPoint,node,visible);/* this is what makes the difference with the h version above */
4014 /* node is to the top of the hit point (below because TeX is oriented from top to bottom.
4015 * We compare node and the previously recorded one, through the recorded distance.
4016 * If the nodes have the same tag, prefer the one with the smallest line number,
4017 * if the nodes also have the same line number, prefer the one with the smallest column. */
4018 if (bestDistancesRef->right > off7) {
4019 bestDistancesRef->right = off7;
4020 bestNodesRef->right = node;
4021 result |= SYNCTEX_MASK_RIGHT;
4022 } else if (bestDistancesRef->right == off7 && bestNodesRef->right) {
4023 if (SYNCTEX_TAG(bestNodesRef->right) == SYNCTEX_TAG(node)
4024 && (SYNCTEX_LINE(bestNodesRef->right) > SYNCTEX_LINE(node)
4025 || (SYNCTEX_LINE(bestNodesRef->right) == SYNCTEX_LINE(node)
4026 && SYNCTEX_COLUMN(bestNodesRef->right) > SYNCTEX_COLUMN(node)))) {
4027 bestNodesRef->right = node;
4028 result |= SYNCTEX_MASK_RIGHT;
4031 } else if (off7 == 0) {
4032 bestDistancesRef->left = bestDistancesRef->right = 0;
4033 bestNodesRef->left = node;
4034 bestNodesRef->right = NULL;
4035 result |= SYNCTEX_MASK_LEFT;
4036 } else { /* here off7 < 0 */
4038 if (bestDistancesRef->left > off7) {
4039 bestDistancesRef->left = off7;
4040 bestNodesRef->left = node;
4041 result |= SYNCTEX_MASK_LEFT;
4042 } else if (bestDistancesRef->left == off7 && bestNodesRef->left) {
4043 if (SYNCTEX_TAG(bestNodesRef->left) == SYNCTEX_TAG(node)
4044 && (SYNCTEX_LINE(bestNodesRef->left) > SYNCTEX_LINE(node)
4045 || (SYNCTEX_LINE(bestNodesRef->left) == SYNCTEX_LINE(node)
4046 && SYNCTEX_COLUMN(bestNodesRef->left) > SYNCTEX_COLUMN(node)))) {
4047 bestNodesRef->left = node;
4048 result |= SYNCTEX_MASK_LEFT;
4052 } while((node = SYNCTEX_SIBLING(node)));
4053 if (result & SYNCTEX_MASK_LEFT) {
4054 /* the left node is new, try to narrow the result */
4055 if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->left,visible))) {
4056 bestNodesRef->left = node;
4058 if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->left,visible))) {
4059 bestNodesRef->left = node;
4062 if (result & SYNCTEX_MASK_RIGHT) {
4063 /* the right node is new, try to narrow the result */
4064 if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->right,visible))) {
4065 bestNodesRef->right = node;
4067 if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->right,visible))) {
4068 bestNodesRef->right = node;
4074 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) {
4076 switch(node->class->type) {
4077 case synctex_node_type_hbox:
4078 return __synctex_eq_get_closest_children_in_hbox(hitPoint, node, bestNodesRef, bestDistancesRef,visible);
4079 case synctex_node_type_vbox:
4080 return __synctex_eq_get_closest_children_in_vbox(hitPoint, node, bestNodesRef, bestDistancesRef,visible);
4086 SYNCTEX_INLINE static synctex_node_t __synctex_eq_closest_child(synctex_point_t hitPoint, synctex_node_t node,int* distanceRef, synctex_bool_t visible);
4087 SYNCTEX_INLINE static synctex_node_t __synctex_eq_closest_child(synctex_point_t hitPoint, synctex_node_t node,int* distanceRef, synctex_bool_t visible) {
4088 synctex_node_t best_node = NULL;
4089 if ((node = SYNCTEX_CHILD(node))) {
4091 int distance = _synctex_node_distance_to_point(hitPoint,node,visible);
4092 synctex_node_t candidate = NULL;
4093 if (distance<=*distanceRef) {
4094 *distanceRef = distance;
4097 switch(node->class->type) {
4098 case synctex_node_type_vbox:
4099 case synctex_node_type_hbox:
4100 if ((candidate = __synctex_eq_closest_child(hitPoint,node,distanceRef,visible))) {
4101 best_node = candidate;
4104 } while((node = SYNCTEX_SIBLING(node)));
4108 SYNCTEX_INLINE static synctex_node_t _synctex_eq_closest_child(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible) {
4110 switch(node->class->type) {
4111 case synctex_node_type_hbox:
4112 case synctex_node_type_vbox:
4114 int best_distance = INT_MAX;
4115 synctex_node_t best_node = __synctex_eq_closest_child(hitPoint,node,&best_distance,visible);
4117 synctex_node_t child = NULL;
4118 switch(best_node->class->type) {
4119 case synctex_node_type_vbox:
4120 case synctex_node_type_hbox:
4121 if ((child = SYNCTEX_CHILD(best_node))) {
4122 best_distance = _synctex_node_distance_to_point(hitPoint,child,visible);
4123 while((child = SYNCTEX_SIBLING(child))) {
4124 int distance = _synctex_node_distance_to_point(hitPoint,child,visible);
4125 if (distance<=best_distance) {
4126 best_distance = distance;
4140 # ifdef SYNCTEX_NOTHING
4142 # pragma mark Updater
4145 typedef int (*synctex_fprintf_t)(void *, const char * , ...); /* print formatted to either FILE * or gzFile */
4147 # define SYNCTEX_BITS_PER_BYTE 8
4149 struct __synctex_updater_t {
4150 void *file; /* the foo.synctex or foo.synctex.gz I/O identifier */
4151 synctex_fprintf_t fprintf; /* either fprintf or gzprintf */
4152 int length; /* the number of chars appended */
4154 unsigned int no_gz:1; /* Whether zlib is used or not */
4155 unsigned int reserved:SYNCTEX_BITS_PER_BYTE*sizeof(int)-1; /* Align */
4158 # define SYNCTEX_FILE updater->file
4159 # define SYNCTEX_NO_GZ ((updater->flags).no_gz)
4160 # define SYNCTEX_fprintf (*(updater->fprintf))
4162 synctex_updater_t synctex_updater_new_with_output_file(const char * output, const char * build_directory) {
4163 synctex_updater_t updater = NULL;
4164 char * synctex = NULL;
4165 synctex_io_mode_t io_mode = 0;
4166 const char * mode = NULL;
4167 /* prepare the updater, the memory is the only one dynamically allocated */
4168 updater = (synctex_updater_t)_synctex_malloc(sizeof(synctex_updater_t));
4169 if (NULL == updater) {
4170 _synctex_error("! synctex_updater_new_with_file: malloc problem");
4173 if (_synctex_open(output,build_directory,&synctex,&SYNCTEX_FILE,synctex_ADD_QUOTES,&io_mode)
4174 && _synctex_open(output,build_directory,&synctex,&SYNCTEX_FILE,synctex_DONT_ADD_QUOTES,&io_mode)) {
4180 /* OK, the file exists, we close it and reopen it with the correct mode.
4181 * The receiver is now the owner of the "synctex" variable. */
4182 gzclose(SYNCTEX_FILE);
4183 SYNCTEX_FILE = NULL;
4184 SYNCTEX_NO_GZ = (io_mode&synctex_io_gz_mask)?synctex_NO:synctex_YES;
4185 mode = _synctex_get_io_mode_name(io_mode|synctex_io_append_mask);/* either "a" or "ab", depending on the file extension */
4186 if (SYNCTEX_NO_GZ) {
4187 if (NULL == (SYNCTEX_FILE = (void *)fopen(synctex,mode))) {
4189 _synctex_error("! synctex_updater_new_with_file: Can't append to %s",synctex);
4191 goto return_on_error;
4193 updater->fprintf = (synctex_fprintf_t)(&fprintf);
4195 if (NULL == (SYNCTEX_FILE = (void *)gzopen(synctex,mode))) {
4196 goto no_write_error;
4198 updater->fprintf = (synctex_fprintf_t)(&gzprintf);
4200 printf("SyncTeX: updating %s...",synctex);
4206 void synctex_updater_append_magnification(synctex_updater_t updater, char * magnification){
4207 if (NULL==updater) {
4210 if (magnification && strlen(magnification)) {
4211 updater->length += SYNCTEX_fprintf(SYNCTEX_FILE,"Magnification:%s\n",magnification);
4215 void synctex_updater_append_x_offset(synctex_updater_t updater, char * x_offset){
4216 if (NULL==updater) {
4219 if (x_offset && strlen(x_offset)) {
4220 updater->length += SYNCTEX_fprintf(SYNCTEX_FILE,"X Offset:%s\n",x_offset);
4224 void synctex_updater_append_y_offset(synctex_updater_t updater, char * y_offset){
4225 if (NULL==updater) {
4228 if (y_offset && strlen(y_offset)) {
4229 updater->length += SYNCTEX_fprintf(SYNCTEX_FILE,"Y Offset:%s\n",y_offset);
4233 void synctex_updater_free(synctex_updater_t updater){
4234 if (NULL==updater) {
4237 if (updater->length>0) {
4238 SYNCTEX_fprintf(SYNCTEX_FILE,"!%i\n",updater->length);
4240 if (SYNCTEX_NO_GZ) {
4241 fclose((FILE *)SYNCTEX_FILE);
4243 gzclose((gzFile)SYNCTEX_FILE);
4246 printf("... done.\n");