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