File indexing completed on 2024-05-12 04:33:36
0001 /* 0002 SPDX-FileCopyrightText: 2008-2017 jerome DOT laurens AT u-bourgogne DOT fr 0003 SPDX-License-Identifier: X11 0004 0005 This file is part of the __SyncTeX__ package. 0006 0007 [//]: # (Latest Revision: Fri Jul 14 16:20:41 UTC 2017) 0008 [//]: # (Version: 1.19) 0009 0010 See `synctex_parser_readme.md` for more details 0011 0012 Acknowledgments: 0013 ---------------- 0014 The author received useful remarks from the pdfTeX developers, especially Hahn The Thanh, 0015 and significant help from XeTeX developer Jonathan Kew 0016 0017 Nota Bene: 0018 ---------- 0019 If you include or use a significant part of the synctex package into a software, 0020 I would appreciate to be listed as contributor and see "SyncTeX" highlighted. 0021 */ 0022 0023 /* We assume that high level application like pdf viewers will want 0024 * to embed this code as is. We assume that they also have locale.h and setlocale. 0025 * For other tools such as TeXLive tools, you must define SYNCTEX_USE_LOCAL_HEADER, 0026 * when building. You also have to create and customize synctex_parser_local.h to fit your system. 0027 * In particular, the HAVE_LOCALE_H and HAVE_SETLOCALE macros should be properly defined. 0028 * With this design, you should not need to edit this file. */ 0029 0030 /** 0031 * \file synctex_parser.c 0032 * \brief SyncTeX file parser and controller. 0033 * - author: Jérôme LAURENS 0034 * \version 1.19 0035 * \date Mon Apr 24 07:08:56 UTC 2017 0036 * 0037 * Reads and parse *.synctex[.gz] files, 0038 * performs edit and display queries. 0039 * 0040 * See 0041 * - synctex_scanner_new_with_output_file 0042 * - synctex_scanner_parse 0043 * - synctex_scanner_free 0044 * - synctex_display_query 0045 * - synctex_edit_query 0046 * - synctex_scanner_next_result 0047 * - synctex_scanner_reset_result 0048 * 0049 * The data is organized in a graph with multiple entries. 0050 * The root object is a scanner, it is created with the contents on a synctex file. 0051 * Each node of the tree is a synctex_node_t object. 0052 * There are 3 subtrees, two of them sharing the same leaves. 0053 * The first tree is the list of input records, where input file names are associated with tags. 0054 * The second tree is the box tree as given by TeX when shipping pages out. 0055 * First level objects are sheets and forms, containing boxes, glues, kerns... 0056 * The third tree allows to browse leaves according to tag and line. 0057 */ 0058 #if defined(SYNCTEX_USE_LOCAL_HEADER) 0059 #include "synctex_parser_local.h" 0060 #else 0061 #define HAVE_LOCALE_H 1 0062 #define HAVE_SETLOCALE 1 0063 #if defined(_MSC_VER) 0064 #define SYNCTEX_INLINE __inline 0065 #else 0066 #define SYNCTEX_INLINE 0067 #endif 0068 #endif 0069 0070 #include <errno.h> 0071 #include <limits.h> 0072 #include <stdarg.h> 0073 #include <stdio.h> 0074 #include <stdlib.h> 0075 #include <string.h> 0076 0077 #if defined(HAVE_LOCALE_H) 0078 #include <locale.h> 0079 #endif 0080 0081 #include "synctex_parser_advanced.h" 0082 0083 SYNCTEX_INLINE static int _synctex_abs(int x) 0084 { 0085 return x > 0 ? x : -x; 0086 } 0087 /* These are the possible extensions of the synctex file */ 0088 const char *synctex_suffix = ".synctex"; 0089 const char *synctex_suffix_gz = ".gz"; 0090 0091 typedef synctex_node_p (*synctex_node_new_f)(synctex_scanner_p); 0092 typedef void (*synctex_node_fld_f)(synctex_node_p); 0093 typedef char *(*synctex_node_str_f)(synctex_node_p); 0094 0095 /** 0096 * Pseudo class. 0097 * - author: J. Laurens 0098 * 0099 * Each nodes has a class, it is therefore called an object. 0100 * Each class has a unique scanner. 0101 * Each class has a type which is a unique identifier. 0102 * Each class has a node mask which identifies node's attributes. 0103 * Each class has an info mask which info's attributes. 0104 * The class points to various methods, 0105 * each of them vary amongst objects. 0106 * The navigator records the offsets of the tree members getters. 0107 * The modelator records the offsets of the data members getters, relative to the last navigator getter. 0108 */ 0109 0110 /* 8 fields + size: spcflnat */ 0111 typedef struct synctex_tree_model_t { 0112 int sibling; 0113 int parent; 0114 int child; 0115 int friend; 0116 int last; 0117 int next_hbox; 0118 int arg_sibling; 0119 int target; 0120 int size; 0121 } synctex_tree_model_s; 0122 typedef const synctex_tree_model_s *synctex_tree_model_p; 0123 0124 typedef struct synctex_data_model_t { 0125 int tag; 0126 int line; 0127 int column; 0128 int h; 0129 int v; 0130 int width; 0131 int height; 0132 int depth; 0133 int mean_line; 0134 int weight; 0135 int h_V; 0136 int v_V; 0137 int width_V; 0138 int height_V; 0139 int depth_V; 0140 int name; 0141 int page; 0142 int size; 0143 } synctex_data_model_s; 0144 0145 static const synctex_data_model_s synctex_data_model_none = {-1, /* tag */ 0146 -1, /* line */ 0147 -1, /* column */ 0148 -1, /* h */ 0149 -1, /* v */ 0150 -1, /* width */ 0151 -1, /* height */ 0152 -1, /* depth */ 0153 -1, /* mean_line */ 0154 -1, /* weight */ 0155 -1, /* h_V */ 0156 -1, /* v_V */ 0157 -1, /* width_V */ 0158 -1, /* height_V */ 0159 -1, /* depth_V */ 0160 -1, /* name */ 0161 -1, /* page */ 0162 0}; 0163 typedef const synctex_data_model_s *synctex_data_model_p; 0164 0165 typedef int (*synctex_int_getter_f)(synctex_node_p); 0166 typedef struct synctex_tlcpector_t { 0167 synctex_int_getter_f tag; 0168 synctex_int_getter_f line; 0169 synctex_int_getter_f column; 0170 } synctex_tlcpector_s; 0171 typedef const synctex_tlcpector_s *synctex_tlcpector_p; 0172 static int _synctex_int_none(synctex_node_p node) 0173 { 0174 (void)node; /* unused */ 0175 return 0; 0176 } 0177 static const synctex_tlcpector_s synctex_tlcpector_none = { 0178 &_synctex_int_none, /* tag */ 0179 &_synctex_int_none, /* line */ 0180 &_synctex_int_none, /* column */ 0181 }; 0182 0183 typedef struct synctex_inspector_t { 0184 synctex_int_getter_f h; 0185 synctex_int_getter_f v; 0186 synctex_int_getter_f width; 0187 synctex_int_getter_f height; 0188 synctex_int_getter_f depth; 0189 } synctex_inspector_s; 0190 typedef const synctex_inspector_s *synctex_inspector_p; 0191 static const synctex_inspector_s synctex_inspector_none = { 0192 &_synctex_int_none, /* h */ 0193 &_synctex_int_none, /* v */ 0194 &_synctex_int_none, /* width */ 0195 &_synctex_int_none, /* height */ 0196 &_synctex_int_none, /* depth */ 0197 }; 0198 0199 typedef float (*synctex_float_getter_f)(synctex_node_p); 0200 typedef struct synctex_vispector_t { 0201 synctex_float_getter_f h; 0202 synctex_float_getter_f v; 0203 synctex_float_getter_f width; 0204 synctex_float_getter_f height; 0205 synctex_float_getter_f depth; 0206 } synctex_vispector_s; 0207 static float _synctex_float_none(synctex_node_p node) 0208 { 0209 (void)node; /* unused */ 0210 return 0; 0211 } 0212 static const synctex_vispector_s synctex_vispector_none = { 0213 &_synctex_float_none, /* h */ 0214 &_synctex_float_none, /* v */ 0215 &_synctex_float_none, /* width */ 0216 &_synctex_float_none, /* height */ 0217 &_synctex_float_none, /* depth */ 0218 }; 0219 typedef const synctex_vispector_s *synctex_vispector_p; 0220 0221 struct synctex_class_t { 0222 synctex_scanner_p scanner; 0223 synctex_node_type_t type; 0224 synctex_node_new_f new; 0225 synctex_node_fld_f free; 0226 synctex_node_fld_f log; 0227 synctex_node_fld_f display; 0228 synctex_node_str_f abstract; 0229 synctex_tree_model_p navigator; 0230 synctex_data_model_p modelator; 0231 synctex_tlcpector_p tlcpector; 0232 synctex_inspector_p inspector; 0233 synctex_vispector_p vispector; 0234 }; 0235 0236 /** 0237 * Nota bene: naming convention. 0238 * For static API, when the name contains proxy, it applies to proxies. 0239 * When the name contains noxy, it applies to non proxies only. 0240 * When the name contains node, weel it depends... 0241 */ 0242 0243 typedef synctex_node_p synctex_proxy_p; 0244 typedef synctex_node_p synctex_noxy_p; 0245 0246 #ifdef SYNCTEX_NOTHING 0247 #pragma mark - 0248 #pragma mark Abstract OBJECTS and METHODS 0249 #endif 0250 0251 /** 0252 * \def SYNCTEX_MSG_SEND 0253 * \brief Takes care of sending the given message if possible. 0254 * - parameter NODE: of type synctex_node_p 0255 * - parameter SELECTOR: one of the class pointer properties 0256 */ 0257 #define SYNCTEX_MSG_SEND(NODE, SELECTOR) \ 0258 do { \ 0259 synctex_node_p N__ = NODE; \ 0260 if (N__ && N__->class->SELECTOR) { \ 0261 (*(N__->class->SELECTOR))(N__); \ 0262 } \ 0263 } while (synctex_NO) 0264 0265 /** 0266 * Free the given node by sending the free message. 0267 * - parameter NODE: of type synctex_node_p 0268 */ 0269 void synctex_node_free(synctex_node_p node) 0270 { 0271 SYNCTEX_MSG_SEND(node, free); 0272 } 0273 #if defined(SYNCTEX_TESTING) 0274 #if !defined(SYNCTEX_USE_HANDLE) 0275 #define SYNCTEX_USE_HANDLE 1 0276 #endif 0277 #if !defined(SYNCTEX_USE_CHARINDEX) 0278 #define SYNCTEX_USE_CHARINDEX 1 0279 #endif 0280 #endif 0281 SYNCTEX_INLINE static synctex_node_p _synctex_new_handle_with_target(synctex_node_p target); 0282 #if defined(SYNCTEX_USE_HANDLE) 0283 #define SYNCTEX_SCANNER_FREE_HANDLE(SCANR) __synctex_scanner_free_handle(SCANR) 0284 #define SYNCTEX_SCANNER_REMOVE_HANDLE_TO(WHAT) __synctex_scanner_remove_handle_to(WHAT) 0285 #define SYNCTEX_REGISTER_HANDLE_TO(NODE) __synctex_scanner_register_handle_to(NODE) 0286 #else 0287 #define SYNCTEX_SCANNER_FREE_HANDLE(SCANR) 0288 #define SYNCTEX_SCANNER_REMOVE_HANDLE_TO(WHAT) 0289 #define SYNCTEX_REGISTER_HANDLE_TO(NODE) 0290 #endif 0291 0292 #if defined(SYNCTEX_USE_CHARINDEX) 0293 #define SYNCTEX_CHARINDEX(NODE) (NODE->char_index) 0294 #define SYNCTEX_LINEINDEX(NODE) (NODE->line_index) 0295 #define SYNCTEX_PRINT_CHARINDEX_FMT "#%i" 0296 #define SYNCTEX_PRINT_CHARINDEX_WHAT , SYNCTEX_CHARINDEX(node) 0297 #define SYNCTEX_PRINT_CHARINDEX printf(SYNCTEX_PRINT_CHARINDEX_FMT SYNCTEX_PRINT_CHARINDEX_WHAT) 0298 #define SYNCTEX_PRINT_LINEINDEX_FMT "L#%i" 0299 #define SYNCTEX_PRINT_LINEINDEX_WHAT , SYNCTEX_LINEINDEX(node) 0300 #define SYNCTEX_PRINT_LINEINDEX printf(SYNCTEX_PRINT_LINEINDEX_FMT SYNCTEX_PRINT_LINEINDEX_WHAT) 0301 #define SYNCTEX_PRINT_CHARINDEX_NL printf(SYNCTEX_PRINT_CHARINDEX_FMT "\n" SYNCTEX_PRINT_CHARINDEX_WHAT) 0302 #define SYNCTEX_PRINT_LINEINDEX_NL printf(SYNCTEX_PRINT_CHARINDEX_FMT "\n" SYNCTEX_PRINT_LINEINDEX_WHAT) 0303 #define SYNCTEX_IMPLEMENT_CHARINDEX(NODE, CORRECTION) \ 0304 NODE->char_index = (synctex_charindex_t)(scanner->reader->charindex_offset + SYNCTEX_CUR - SYNCTEX_START + (CORRECTION)); \ 0305 NODE->line_index = scanner->reader->line_number; 0306 #else 0307 #define SYNCTEX_CHARINDEX(NODE) 0 0308 #define SYNCTEX_LINEINDEX(NODE) 0 0309 #define SYNCTEX_PRINT_CHARINDEX_FMT 0310 #define SYNCTEX_PRINT_CHARINDEX_WHAT 0311 #define SYNCTEX_PRINT_CHARINDEX 0312 #define SYNCTEX_PRINT_CHARINDEX 0313 #define SYNCTEX_PRINT_LINEINDEX_FMT 0314 #define SYNCTEX_PRINT_LINEINDEX_WHAT 0315 #define SYNCTEX_PRINT_LINEINDEX 0316 #define SYNCTEX_PRINT_CHARINDEX_NL printf("\n") 0317 #define SYNCTEX_PRINT_LINEINDEX_NL printf("\n") 0318 #define SYNCTEX_IMPLEMENT_CHARINDEX(NODE, CORRECTION) 0319 #endif 0320 0321 /** 0322 * The next macros are used to access the node tree info 0323 * SYNCTEX_DATA(node) points to the first synctex integer or pointer data of node 0324 * SYNCTEX_DATA(node)[index] is the information at index 0325 * for example, the page of a sheet is stored in SYNCTEX_DATA(sheet)[_synctex_data_page_idx] 0326 * - parameter NODE: of type synctex_node_p 0327 * If the name starts with "__", the argument is nonullable 0328 */ 0329 #ifdef SYNCTEX_NOTHING 0330 #pragma mark - 0331 #pragma mark Tree SETGET 0332 #endif 0333 0334 #if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 1000 0335 #define SYNCTEX_PARAMETER_ASSERT(WHAT) \ 0336 do { \ 0337 if (!(WHAT)) { \ 0338 printf("! Parameter failure: %s\n", #WHAT); \ 0339 } \ 0340 } while (synctex_NO) 0341 #define DEFINE_SYNCTEX_TREE_HAS(WHAT) \ 0342 static synctex_bool_t _synctex_tree_has_##WHAT(synctex_node_p node) \ 0343 { \ 0344 if (node) { \ 0345 if (node->class->navigator->WHAT >= 0) { \ 0346 return synctex_YES; \ 0347 } else { \ 0348 printf("WARNING: NO tree %s for %s\n", #WHAT, synctex_node_isa(node)); \ 0349 } \ 0350 } \ 0351 return synctex_NO; \ 0352 } 0353 #else 0354 #define SYNCTEX_PARAMETER_ASSERT(WHAT) 0355 #define DEFINE_SYNCTEX_TREE_HAS(WHAT) \ 0356 static synctex_bool_t _synctex_tree_has_##WHAT(synctex_node_p node) \ 0357 { \ 0358 return (node && (node->class->navigator->WHAT >= 0)); \ 0359 } 0360 #endif 0361 0362 #define DEFINE_SYNCTEX_TREE__GET(WHAT) \ 0363 SYNCTEX_INLINE static synctex_node_p __synctex_tree_##WHAT(synctex_non_null_node_p node) \ 0364 { \ 0365 return node->data[node->class->navigator->WHAT].as_node; \ 0366 } 0367 #define DEFINE_SYNCTEX_TREE_GET(WHAT) \ 0368 DEFINE_SYNCTEX_TREE__GET(WHAT) \ 0369 static synctex_node_p _synctex_tree_##WHAT(synctex_node_p node) \ 0370 { \ 0371 if (_synctex_tree_has_##WHAT(node)) { \ 0372 return __synctex_tree_##WHAT(node); \ 0373 } \ 0374 return 0; \ 0375 } 0376 #define DEFINE_SYNCTEX_TREE__RESET(WHAT) \ 0377 SYNCTEX_INLINE static synctex_node_p __synctex_tree_reset_##WHAT(synctex_non_null_node_p node) \ 0378 { \ 0379 synctex_node_p old = node->data[node->class->navigator->WHAT].as_node; \ 0380 node->data[node->class->navigator->WHAT].as_node = NULL; \ 0381 return old; \ 0382 } 0383 #define DEFINE_SYNCTEX_TREE_RESET(WHAT) \ 0384 DEFINE_SYNCTEX_TREE__RESET(WHAT) \ 0385 SYNCTEX_INLINE static synctex_node_p _synctex_tree_reset_##WHAT(synctex_node_p node) \ 0386 { \ 0387 return _synctex_tree_has_##WHAT(node) ? __synctex_tree_reset_##WHAT(node) : NULL; \ 0388 } 0389 #define DEFINE_SYNCTEX_TREE__SET(WHAT) \ 0390 SYNCTEX_INLINE static synctex_node_p __synctex_tree_set_##WHAT(synctex_non_null_node_p node, synctex_node_p new_value) \ 0391 { \ 0392 synctex_node_p old = __synctex_tree_##WHAT(node); \ 0393 node->data[node->class->navigator->WHAT].as_node = new_value; \ 0394 return old; \ 0395 } 0396 #define DEFINE_SYNCTEX_TREE_SET(WHAT) \ 0397 DEFINE_SYNCTEX_TREE__SET(WHAT) \ 0398 SYNCTEX_INLINE static synctex_node_p _synctex_tree_set_##WHAT(synctex_node_p node, synctex_node_p new_value) \ 0399 { \ 0400 return _synctex_tree_has_##WHAT(node) ? __synctex_tree_set_##WHAT(node, new_value) : NULL; \ 0401 } 0402 #define DEFINE_SYNCTEX_TREE__GETSETRESET(WHAT) \ 0403 DEFINE_SYNCTEX_TREE__GET(WHAT) \ 0404 DEFINE_SYNCTEX_TREE__SET(WHAT) \ 0405 DEFINE_SYNCTEX_TREE__RESET(WHAT) 0406 0407 #define DEFINE_SYNCTEX_TREE_GETSET(WHAT) \ 0408 DEFINE_SYNCTEX_TREE_HAS(WHAT) \ 0409 DEFINE_SYNCTEX_TREE_GET(WHAT) \ 0410 DEFINE_SYNCTEX_TREE_SET(WHAT) 0411 0412 #define DEFINE_SYNCTEX_TREE_GETRESET(WHAT) \ 0413 DEFINE_SYNCTEX_TREE_HAS(WHAT) \ 0414 DEFINE_SYNCTEX_TREE_GET(WHAT) \ 0415 DEFINE_SYNCTEX_TREE_RESET(WHAT) 0416 0417 #define DEFINE_SYNCTEX_TREE_GETSETRESET(WHAT) \ 0418 DEFINE_SYNCTEX_TREE_HAS(WHAT) \ 0419 DEFINE_SYNCTEX_TREE_GET(WHAT) \ 0420 DEFINE_SYNCTEX_TREE_SET(WHAT) \ 0421 DEFINE_SYNCTEX_TREE_RESET(WHAT) 0422 0423 /* 0424 * _synctex_tree_set_... methods return the old value. 0425 * The return value of _synctex_tree_set_child and 0426 * _synctex_tree_set_sibling must be released somehown. 0427 */ 0428 DEFINE_SYNCTEX_TREE__GETSETRESET(sibling) 0429 DEFINE_SYNCTEX_TREE_GETSETRESET(parent) 0430 DEFINE_SYNCTEX_TREE_GETSETRESET(child) 0431 DEFINE_SYNCTEX_TREE_GETSETRESET(friend) 0432 DEFINE_SYNCTEX_TREE_GETSET(last) 0433 DEFINE_SYNCTEX_TREE_GETSET(next_hbox) 0434 DEFINE_SYNCTEX_TREE_GETSET(arg_sibling) 0435 DEFINE_SYNCTEX_TREE_GETSET(target) 0436 0437 #if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 1000 0438 #undef SYNCTEX_USE_NODE_COUNT 0439 #define SYNCTEX_USE_NODE_COUNT 1 0440 #endif 0441 #if defined SYNCTEX_USE_NODE_COUNT && SYNCTEX_USE_NODE_COUNT > 0 0442 #define SYNCTEX_DECLARE_NODE_COUNT int node_count; 0443 #define SYNCTEX_INIT_NODE_COUNT \ 0444 do { \ 0445 node_count = 0; \ 0446 } while (synctex_NO) 0447 #else 0448 #define SYNCTEX_DECLARE_NODE_COUNT 0449 #define SYNCTEX_INIT_NODE_COUNT 0450 #endif 0451 0452 #if defined SYNCTEX_USE_NODE_COUNT && SYNCTEX_USE_NODE_COUNT > 10 0453 #define SYNCTEX_DID_NEW(N) _synctex_did_new(N) 0454 #define SYNCTEX_WILL_FREE(N) _synctex_will_free(N) 0455 #else 0456 #define SYNCTEX_DID_NEW(N) 0457 #define SYNCTEX_WILL_FREE(N) 0458 #endif 0459 0460 #define SYNCTEX_HAS_CHILDREN(NODE) (NODE && _synctex_tree_child(NODE)) 0461 #ifdef __SYNCTEX_WORK__ 0462 #include "/usr/include/zlib.h" 0463 #else 0464 #include <zlib.h> 0465 #endif 0466 0467 #ifdef SYNCTEX_NOTHING 0468 #pragma mark - 0469 #pragma mark STATUS 0470 #endif 0471 /* When the end of the synctex file has been reached: */ 0472 #define SYNCTEX_STATUS_EOF 0 0473 /* When the function could not return the value it was asked for: */ 0474 #define SYNCTEX_STATUS_NOT_OK (SYNCTEX_STATUS_EOF + 1) 0475 /* When the function returns the value it was asked for: 0476 It must be the biggest one */ 0477 #define SYNCTEX_STATUS_OK (SYNCTEX_STATUS_NOT_OK + 1) 0478 /* Generic error: */ 0479 #define SYNCTEX_STATUS_ERROR (SYNCTEX_STATUS_EOF - 1) 0480 /* Parameter error: */ 0481 #define SYNCTEX_STATUS_BAD_ARGUMENT (SYNCTEX_STATUS_ERROR - 1) 0482 0483 #ifdef SYNCTEX_NOTHING 0484 #pragma mark - 0485 #pragma mark File reader 0486 #endif 0487 0488 /* We ensure that SYNCTEX_BUFFER_SIZE < UINT_MAX, I don't know if it makes sense... */ 0489 /* Actually, the minimum buffer size is driven by integer and float parsing, including the unit. 0490 * ±0.123456789e123?? 0491 */ 0492 #define SYNCTEX_BUFFER_MIN_SIZE 32 0493 #define SYNCTEX_BUFFER_SIZE 32768 0494 0495 #if SYNCTEX_BUFFER_SIZE >= UINT_MAX 0496 #error BAD BUFFER SIZE(1) 0497 #endif 0498 #if SYNCTEX_BUFFER_SIZE < SYNCTEX_BUFFER_MIN_SIZE 0499 #error BAD BUFFER SIZE(2) 0500 #endif 0501 0502 typedef struct synctex_reader_t { 0503 gzFile file; /* The (possibly compressed) file */ 0504 char *output; 0505 char *synctex; 0506 char *current; /* current location in the buffer */ 0507 char *start; /* start of the buffer */ 0508 char *end; /* end of the buffer */ 0509 size_t min_size; 0510 size_t size; 0511 int lastv; 0512 int line_number; 0513 SYNCTEX_DECLARE_CHAR_OFFSET 0514 } synctex_reader_s; 0515 0516 typedef synctex_reader_s *synctex_reader_p; 0517 0518 typedef struct { 0519 synctex_status_t status; 0520 char *synctex; 0521 gzFile file; 0522 synctex_io_mode_t io_mode; 0523 } synctex_open_s; 0524 0525 /* This functions opens the file at the "output" given location. 0526 * It manages the problem of quoted filenames that appear with pdftex and filenames containing the space character. 0527 * In TeXLive 2008, the synctex file created with pdftex did contain unexpected quotes. 0528 * This function will remove them if possible. 0529 * All the reference arguments will take a value on return. They must be non NULL. 0530 * - returns: an open structure which status is 0531 * SYNCTEX_STATUS_OK on success, 0532 * SYNCTEX_STATUS_ERROR on failure. 0533 * - note: on success, the caller is the owner 0534 * of the fields of the returned open structure. 0535 */ 0536 static synctex_open_s __synctex_open_v2(const char *output, synctex_io_mode_t io_mode, synctex_bool_t add_quotes) 0537 { 0538 synctex_open_s open = {SYNCTEX_STATUS_ERROR, NULL, NULL, io_mode}; 0539 char *quoteless_synctex_name = NULL; 0540 const char *mode = _synctex_get_io_mode_name(open.io_mode); 0541 size_t size = strlen(output) + strlen(synctex_suffix) + strlen(synctex_suffix_gz) + 1; 0542 if (NULL == (open.synctex = (char *)malloc(size))) { 0543 _synctex_error("! __synctex_open_v2: Memory problem (1)\n"); 0544 return open; 0545 } 0546 /* we have reserved for synctex enough memory to copy output (including its 2 eventual quotes), both suffices, 0547 * including the terminating character. size is free now. */ 0548 if (open.synctex != strcpy(open.synctex, output)) { 0549 _synctex_error("! __synctex_open_v2: Copy problem\n"); 0550 return_on_error: 0551 free(open.synctex); 0552 open.synctex = NULL; 0553 free(quoteless_synctex_name); /* We MUST have quoteless_synctex_name<>synctex_name */ 0554 return open; 0555 } 0556 /* remove the last path extension if any */ 0557 _synctex_strip_last_path_extension(open.synctex); 0558 if (!strlen(open.synctex)) { 0559 goto return_on_error; 0560 } 0561 /* now insert quotes. */ 0562 if (add_quotes) { 0563 char *quoted = NULL; 0564 if (_synctex_copy_with_quoting_last_path_component(open.synctex, "ed, size) || quoted == NULL) { 0565 /* There was an error or quoting does not make sense: */ 0566 goto return_on_error; 0567 } 0568 quoteless_synctex_name = open.synctex; 0569 open.synctex = quoted; 0570 } 0571 /* Now add to open.synctex the first path extension. */ 0572 if (open.synctex != strcat(open.synctex, synctex_suffix)) { 0573 _synctex_error("! __synctex_open_v2: Concatenation problem (can't add suffix '%s')\n", synctex_suffix); 0574 goto return_on_error; 0575 } 0576 /* Add to quoteless_synctex_name as well, if relevant. */ 0577 if (quoteless_synctex_name && (quoteless_synctex_name != strcat(quoteless_synctex_name, synctex_suffix))) { 0578 free(quoteless_synctex_name); 0579 quoteless_synctex_name = NULL; 0580 } 0581 if (NULL == (open.file = gzopen(open.synctex, mode))) { 0582 /* Could not open this file */ 0583 if (errno != ENOENT) { 0584 /* The file does exist, this is a lower level error, I can't do anything. */ 0585 _synctex_error("could not open %s, error %i\n", open.synctex, errno); 0586 goto return_on_error; 0587 } 0588 /* Apparently, there is no uncompressed synctex file. Try the compressed version */ 0589 if (open.synctex != strcat(open.synctex, synctex_suffix_gz)) { 0590 _synctex_error("! __synctex_open_v2: Concatenation problem (can't add suffix '%s')\n", synctex_suffix_gz); 0591 goto return_on_error; 0592 } 0593 open.io_mode |= synctex_io_gz_mask; 0594 mode = _synctex_get_io_mode_name(open.io_mode); /* the file is a compressed and is a binary file, this caused errors on Windows */ 0595 /* Add the suffix to the quoteless_synctex_name as well. */ 0596 if (quoteless_synctex_name && (quoteless_synctex_name != strcat(quoteless_synctex_name, synctex_suffix_gz))) { 0597 free(quoteless_synctex_name); 0598 quoteless_synctex_name = NULL; 0599 } 0600 if (NULL == (open.file = gzopen(open.synctex, mode))) { 0601 /* Could not open this file */ 0602 if (errno != ENOENT) { 0603 /* The file does exist, this is a lower level error, I can't do anything. */ 0604 _synctex_error("Could not open %s, error %i\n", open.synctex, errno); 0605 } 0606 goto return_on_error; 0607 } 0608 } 0609 /* At this point, the file is properly open. 0610 * If we are in the add_quotes mode, we change the file name by removing the quotes. */ 0611 if (quoteless_synctex_name) { 0612 gzclose(open.file); 0613 if (rename(open.synctex, quoteless_synctex_name)) { 0614 _synctex_error("Could not rename %s to %s, error %i\n", open.synctex, quoteless_synctex_name, errno); 0615 /* We could not rename, reopen the file with the quoted name. */ 0616 if (NULL == (open.file = gzopen(open.synctex, mode))) { 0617 /* No luck, could not re open this file, something has happened meanwhile */ 0618 if (errno != ENOENT) { 0619 /* The file does not exist any more, it has certainly be removed somehow 0620 * this is a lower level error, I can't do anything. */ 0621 _synctex_error("Could not open again %s, error %i\n", open.synctex, errno); 0622 } 0623 goto return_on_error; 0624 } 0625 } else { 0626 /* The file has been successfully renamed */ 0627 if (NULL == (open.file = gzopen(quoteless_synctex_name, mode))) { 0628 /* Could not open this file */ 0629 if (errno != ENOENT) { 0630 /* The file does exist, this is a lower level error, I can't do anything. */ 0631 _synctex_error("Could not open renamed %s, error %i\n", quoteless_synctex_name, errno); 0632 } 0633 goto return_on_error; 0634 } 0635 /* The quote free file name should replace the old one:*/ 0636 free(open.synctex); 0637 open.synctex = quoteless_synctex_name; 0638 quoteless_synctex_name = NULL; 0639 } 0640 } 0641 /* The operation is successful, return the arguments by value. */ 0642 open.status = SYNCTEX_STATUS_OK; 0643 return open; 0644 } 0645 0646 /* Opens the output file, taking into account the eventual build_directory. 0647 * - returns: an open structure which status is 0648 * SYNCTEX_STATUS_OK on success, 0649 * SYNCTEX_STATUS_ERROR on failure. 0650 * - note: on success, the caller is the owner 0651 * of the fields of the returned open structure. 0652 */ 0653 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) 0654 { 0655 synctex_open_s open = __synctex_open_v2(output, io_mode, add_quotes); 0656 if (open.status == SYNCTEX_STATUS_OK) { 0657 return open; 0658 } 0659 if (build_directory && strlen(build_directory)) { 0660 char *build_output; 0661 const char *lpc; 0662 size_t size; 0663 synctex_bool_t is_absolute; 0664 build_output = NULL; 0665 lpc = _synctex_last_path_component(output); 0666 size = strlen(build_directory) + strlen(lpc) + 2; /* One for the '/' and one for the '\0'. */ 0667 is_absolute = _synctex_path_is_absolute(build_directory); 0668 if (!is_absolute) { 0669 size += strlen(output); 0670 } 0671 if ((build_output = (char *)_synctex_malloc(size))) { 0672 if (is_absolute) { 0673 build_output[0] = '\0'; 0674 } else { 0675 if (build_output != strcpy(build_output, output)) { 0676 _synctex_free(build_output); 0677 return open; 0678 } 0679 build_output[lpc - output] = '\0'; 0680 } 0681 if (build_output == strcat(build_output, build_directory)) { 0682 /* Append a path separator if necessary. */ 0683 if (!SYNCTEX_IS_PATH_SEPARATOR(build_output[strlen(build_directory) - 1])) { 0684 if (build_output != strcat(build_output, "/")) { 0685 _synctex_free(build_output); 0686 return open; 0687 } 0688 } 0689 /* Append the last path component of the output. */ 0690 if (build_output != strcat(build_output, lpc)) { 0691 _synctex_free(build_output); 0692 return open; 0693 } 0694 open = __synctex_open_v2(build_output, io_mode, add_quotes); 0695 } 0696 _synctex_free(build_output); 0697 } /* if ((build_output... */ 0698 } /* if (build_directory...) */ 0699 return open; 0700 } 0701 void synctex_reader_free(synctex_reader_p reader) 0702 { 0703 if (reader) { 0704 _synctex_free(reader->output); 0705 _synctex_free(reader->synctex); 0706 _synctex_free(reader->start); 0707 gzclose(reader->file); 0708 _synctex_free(reader); 0709 } 0710 } 0711 /* 0712 * Return reader on success. 0713 * Deallocate reader and return NULL on failure. 0714 */ 0715 synctex_reader_p synctex_reader_init_with_output_file(synctex_reader_p reader, const char *output, const char *build_directory) 0716 { 0717 if (reader) { 0718 /* now open the synctex file */ 0719 synctex_open_s open = _synctex_open_v2(output, build_directory, 0, synctex_ADD_QUOTES); 0720 if (open.status < SYNCTEX_STATUS_OK) { 0721 open = _synctex_open_v2(output, build_directory, 0, synctex_DONT_ADD_QUOTES); 0722 if (open.status < SYNCTEX_STATUS_OK) { 0723 synctex_reader_free(reader); 0724 return NULL; 0725 } 0726 } 0727 reader->synctex = open.synctex; 0728 reader->file = open.file; 0729 /* make a private copy of output */ 0730 if (NULL == (reader->output = (char *)_synctex_malloc(strlen(output) + 1))) { 0731 _synctex_error("! synctex_scanner_new_with_output_file: Memory problem (2), reader's output is not reliable."); 0732 } else if (reader->output != strcpy(reader->output, output)) { 0733 _synctex_free(reader->output); 0734 reader->output = NULL; 0735 _synctex_error("! synctex_scanner_new_with_output_file: Copy problem, reader's output is not reliable."); 0736 } 0737 reader->start = reader->end = reader->current = NULL; 0738 reader->min_size = SYNCTEX_BUFFER_MIN_SIZE; 0739 reader->size = SYNCTEX_BUFFER_SIZE; 0740 reader->start = reader->current = (char *)_synctex_malloc(reader->size + 1); /* one more character for null termination */ 0741 if (NULL == reader->start) { 0742 _synctex_error("! malloc error in synctex_reader_init_with_output_file."); 0743 #ifdef SYNCTEX_DEBUG 0744 return reader; 0745 #else 0746 synctex_reader_free(reader); 0747 return NULL; 0748 #endif 0749 } 0750 reader->end = reader->start + reader->size; 0751 /* reader->end always points to a null terminating character. 0752 * Maybe there is another null terminating character between reader->current and reader->end-1. 0753 * At least, we are sure that reader->current points to a string covering a valid part of the memory. */ 0754 #if defined(SYNCTEX_USE_CHARINDEX) 0755 reader->charindex_offset = -reader->size; 0756 #endif 0757 } 0758 return reader; 0759 } 0760 0761 #if defined(SYNCTEX_USE_HANDLE) 0762 #define SYNCTEX_DECLARE_HANDLE synctex_node_p handle; 0763 #else 0764 #define SYNCTEX_DECLARE_HANDLE 0765 #endif 0766 0767 #ifdef SYNCTEX_NOTHING 0768 #pragma mark - 0769 #pragma mark SCANNER 0770 #endif 0771 /** 0772 * The synctex scanner is the root object. 0773 * Is is initialized with the contents of a text file or a gzipped file. 0774 * The buffer_.* are first used to parse the text. 0775 */ 0776 struct synctex_scanner_t { 0777 synctex_reader_p reader; 0778 SYNCTEX_DECLARE_NODE_COUNT 0779 SYNCTEX_DECLARE_HANDLE 0780 char *output_fmt; /* dvi or pdf, not yet used */ 0781 synctex_iterator_p iterator; /* result iterator */ 0782 int version; /* 1, not yet used */ 0783 struct { 0784 unsigned has_parsed : 1; /* Whether the scanner has parsed its underlying synctex file. */ 0785 unsigned postamble : 1; /* Whether the scanner has parsed its underlying synctex file. */ 0786 unsigned reserved : sizeof(unsigned) - 2; /* alignment */ 0787 } flags; 0788 int pre_magnification; /* magnification from the synctex preamble */ 0789 int pre_unit; /* unit from the synctex preamble */ 0790 int pre_x_offset; /* X offset from the synctex preamble */ 0791 int pre_y_offset; /* Y offset from the synctex preamble */ 0792 int count; /* Number of records, from the synctex postamble */ 0793 float unit; /* real unit, from synctex preamble or post scriptum */ 0794 float x_offset; /* X offset, from synctex preamble or post scriptum */ 0795 float y_offset; /* Y Offset, from synctex preamble or post scriptum */ 0796 synctex_node_p input; /* The first input node, its siblings are the other input nodes */ 0797 synctex_node_p sheet; /* The first sheet node, its siblings are the other sheet nodes */ 0798 synctex_node_p form; /* The first form, its siblings are the other forms */ 0799 synctex_node_p ref_in_sheet; /* The first form ref node in sheet, its friends are the other form ref nodes */ 0800 synctex_node_p ref_in_form; /* The first form ref node, its friends are the other form ref nodes in sheet */ 0801 int number_of_lists; /* The number of friend lists */ 0802 synctex_node_r lists_of_friends; /* The friend lists */ 0803 synctex_class_s class[synctex_node_number_of_types]; /* The classes of the nodes of the scanner */ 0804 int display_switcher; 0805 char *display_prompt; 0806 }; 0807 0808 /** 0809 * Create a new node of the given type. 0810 * - parameter scanner: of type synctex_node_p 0811 * - parameter type: a type, the client is responsible 0812 * to ask for an acceptable type. 0813 */ 0814 synctex_node_p synctex_node_new(synctex_scanner_p scanner, synctex_node_type_t type) 0815 { 0816 return scanner ? scanner->class[type].new(scanner) : NULL; 0817 } 0818 #if defined(SYNCTEX_USE_HANDLE) 0819 SYNCTEX_INLINE static void __synctex_scanner_free_handle(synctex_scanner_p scanner) 0820 { 0821 synctex_node_free(scanner->handle); 0822 } 0823 SYNCTEX_INLINE static void __synctex_scanner_remove_handle_to(synctex_node_p node) 0824 { 0825 synctex_node_p arg_sibling = NULL; 0826 synctex_node_p handle = node->class->scanner->handle; 0827 while (handle) { 0828 synctex_node_p sibling; 0829 if (node == _synctex_tree_target(handle)) { 0830 sibling = __synctex_tree_reset_sibling(handle); 0831 if (arg_sibling) { 0832 __synctex_tree_set_sibling(arg_sibling, sibling); 0833 } else { 0834 node->class->scanner->handle = sibling; 0835 } 0836 synctex_node_free(handle); 0837 break; 0838 } else { 0839 sibling = __synctex_tree_sibling(handle); 0840 } 0841 arg_sibling = handle; 0842 handle = sibling; 0843 } 0844 } 0845 SYNCTEX_INLINE static void __synctex_scanner_register_handle_to(synctex_node_p node) 0846 { 0847 synctex_node_p NNN = _synctex_new_handle_with_target(node); 0848 __synctex_tree_set_sibling(NNN, node->class->scanner->handle); 0849 node->class->scanner->handle = NNN; 0850 } 0851 #endif 0852 #if defined SYNCTEX_USE_NODE_COUNT && SYNCTEX_USE_NODE_COUNT > 10 0853 SYNCTEX_INLINE static void _synctex_did_new(synctex_node_p node) 0854 { 0855 printf("NODE CREATED # %i, %s, %p\n", (node->class->scanner->node_count)++, synctex_node_isa(node), node); 0856 } 0857 SYNCTEX_INLINE static void _synctex_will_free(synctex_node_p node) 0858 { 0859 printf("NODE DELETED # %i, %s, %p\n", --(node->class->scanner->node_count), synctex_node_isa(node), node); 0860 } 0861 #endif 0862 0863 /** 0864 * Free the given node. 0865 * - parameter node: of type synctex_node_p 0866 * - note: a node is meant to own its child and sibling. 0867 * It is not owned by its parent, unless it is its first child. 0868 * This destructor is for all nodes with children. 0869 */ 0870 static void _synctex_free_node(synctex_node_p node) 0871 { 0872 if (node) { 0873 SYNCTEX_SCANNER_REMOVE_HANDLE_TO(node); 0874 SYNCTEX_WILL_FREE(node); 0875 synctex_node_free(__synctex_tree_sibling(node)); 0876 synctex_node_free(_synctex_tree_child(node)); 0877 _synctex_free(node); 0878 } 0879 return; 0880 } 0881 0882 /** 0883 * Free the given leaf node. 0884 * - parameter node: of type synctex_node_p, with no child nor sibling. 0885 * - note: a node is meant to own its child and sibling. 0886 * It is not owned by its parent, unless it is its first child. 0887 * This destructor is for all nodes with no children. 0888 */ 0889 static void _synctex_free_leaf(synctex_node_p node) 0890 { 0891 if (node) { 0892 SYNCTEX_SCANNER_REMOVE_HANDLE_TO(node); 0893 SYNCTEX_WILL_FREE(node); 0894 synctex_node_free(__synctex_tree_sibling(node)); 0895 _synctex_free(node); 0896 } 0897 return; 0898 } 0899 0900 /** 0901 SYNCTEX_CUR, SYNCTEX_START and SYNCTEX_END are convenient shortcuts 0902 */ 0903 #define SYNCTEX_CUR (scanner->reader->current) 0904 #define SYNCTEX_START (scanner->reader->start) 0905 #define SYNCTEX_END (scanner->reader->end) 0906 0907 /* Here are gathered all the possible status that the next scanning functions will return. 0908 * All these functions return a status, and pass their result through pointers. 0909 * Negative values correspond to errors. 0910 * The management of the buffer is causing some significant overhead. 0911 * Every function that may access the buffer returns a status related to the buffer and file state. 0912 * status >= SYNCTEX_STATUS_OK means the function worked as expected 0913 * status < SYNCTEX_STATUS_OK means the function did not work as expected 0914 * status == SYNCTEX_STATUS_NOT_OK means the function did not work as expected but there is still some material to parse. 0915 * status == SYNCTEX_STATUS_EOF means the function did not work as expected and there is no more material. 0916 * status<SYNCTEX_STATUS_EOF means an error 0917 */ 0918 #if defined(SYNCTEX_USE_CHARINDEX) 0919 synctex_node_p synctex_scanner_handle(synctex_scanner_p scanner) 0920 { 0921 return scanner ? scanner->handle : NULL; 0922 } 0923 #endif 0924 0925 #ifdef SYNCTEX_NOTHING 0926 #pragma mark - 0927 #pragma mark Decoding prototypes 0928 #endif 0929 0930 typedef struct { 0931 int integer; 0932 synctex_status_t status; 0933 } synctex_is_s; 0934 0935 static synctex_is_s _synctex_decode_int(synctex_scanner_p scanner); 0936 static synctex_is_s _synctex_decode_int_opt(synctex_scanner_p scanner, int default_value); 0937 static synctex_is_s _synctex_decode_int_v(synctex_scanner_p scanner); 0938 0939 typedef struct { 0940 char *string; 0941 synctex_status_t status; 0942 } synctex_ss_s; 0943 0944 static synctex_ss_s _synctex_decode_string(synctex_scanner_p scanner); 0945 0946 #ifdef SYNCTEX_NOTHING 0947 #pragma mark - 0948 #pragma mark Data SETGET 0949 #endif 0950 0951 /** 0952 * The next macros are used to access the node data info 0953 * through the class modelator integer fields. 0954 * - parameter NODE: of type synctex_node_p 0955 */ 0956 #define SYNCTEX_DATA(NODE) ((*((((NODE)->class))->info))(NODE)) 0957 #if defined SYNCTEX_DEBUG > 1000 0958 #define DEFINE_SYNCTEX_DATA_HAS(WHAT) \ 0959 SYNCTEX_INLINE static synctex_bool_t __synctex_data_has_##WHAT(synctex_node_p node) \ 0960 { \ 0961 return (node && (node->class->modelator->WHAT >= 0)); \ 0962 } \ 0963 SYNCTEX_INLINE static synctex_bool_t _synctex_data_has_##WHAT(synctex_node_p node) \ 0964 { \ 0965 if (node && (node->class->modelator->WHAT < 0)) { \ 0966 printf("WARNING: NO %s for %s\n", #WHAT, synctex_node_isa(node)); \ 0967 } \ 0968 return __synctex_data_has_##WHAT(node); \ 0969 } 0970 #else 0971 #define DEFINE_SYNCTEX_DATA_HAS(WHAT) \ 0972 SYNCTEX_INLINE static synctex_bool_t __synctex_data_has_##WHAT(synctex_node_p node) \ 0973 { \ 0974 return (node && (node->class->modelator->WHAT >= 0)); \ 0975 } \ 0976 SYNCTEX_INLINE static synctex_bool_t _synctex_data_has_##WHAT(synctex_node_p node) \ 0977 { \ 0978 return __synctex_data_has_##WHAT(node); \ 0979 } 0980 #endif 0981 0982 SYNCTEX_INLINE static synctex_data_p __synctex_data(synctex_node_p node) 0983 { 0984 return node->data + node->class->navigator->size; 0985 } 0986 #define DEFINE_SYNCTEX_DATA_INT_GETSET(WHAT) \ 0987 DEFINE_SYNCTEX_DATA_HAS(WHAT) \ 0988 static int _synctex_data_##WHAT(synctex_node_p node) \ 0989 { \ 0990 if (_synctex_data_has_##WHAT(node)) { \ 0991 return __synctex_data(node)[node->class->modelator->WHAT].as_integer; \ 0992 } \ 0993 return 0; \ 0994 } \ 0995 static int _synctex_data_set_##WHAT(synctex_node_p node, int new_value) \ 0996 { \ 0997 int old = 0; \ 0998 if (_synctex_data_has_##WHAT(node)) { \ 0999 old = __synctex_data(node)[node->class->modelator->WHAT].as_integer; \ 1000 __synctex_data(node)[node->class->modelator->WHAT].as_integer = new_value; \ 1001 } \ 1002 return old; \ 1003 } 1004 #define DEFINE_SYNCTEX_DATA_INT_DECODE(WHAT) \ 1005 static synctex_status_t _synctex_data_decode_##WHAT(synctex_node_p node) \ 1006 { \ 1007 if (_synctex_data_has_##WHAT(node)) { \ 1008 synctex_is_s is = _synctex_decode_int(node->class->scanner); \ 1009 if (is.status == SYNCTEX_STATUS_OK) { \ 1010 _synctex_data_set_##WHAT(node, is.integer); \ 1011 } \ 1012 return is.status; \ 1013 } \ 1014 return SYNCTEX_STATUS_BAD_ARGUMENT; \ 1015 } 1016 #define DEFINE_SYNCTEX_DATA_INT_DECODE_v(WHAT) \ 1017 static synctex_status_t _synctex_data_decode_##WHAT##_v(synctex_node_p node) \ 1018 { \ 1019 if (_synctex_data_has_##WHAT(node)) { \ 1020 synctex_is_s is = _synctex_decode_int_v(node->class->scanner); \ 1021 if (is.status == SYNCTEX_STATUS_OK) { \ 1022 _synctex_data_set_##WHAT(node, is.integer); \ 1023 } \ 1024 return is.status; \ 1025 } \ 1026 return SYNCTEX_STATUS_BAD_ARGUMENT; \ 1027 } 1028 #define DEFINE_SYNCTEX_DATA_STR_GETSET(WHAT) \ 1029 DEFINE_SYNCTEX_DATA_HAS(WHAT) \ 1030 static char *_synctex_data_##WHAT(synctex_node_p node) \ 1031 { \ 1032 if (_synctex_data_has_##WHAT(node)) { \ 1033 return node->data[node->class->navigator->size + node->class->modelator->WHAT].as_string; \ 1034 } \ 1035 return NULL; \ 1036 } \ 1037 static const char *_synctex_data_set_##WHAT(synctex_node_p node, char *new_value) \ 1038 { \ 1039 const char *old = ""; \ 1040 if (_synctex_data_has_##WHAT(node)) { \ 1041 old = node->data[node->class->navigator->size + node->class->modelator->WHAT].as_string; \ 1042 node->data[node->class->navigator->size + node->class->modelator->WHAT].as_string = new_value; \ 1043 } \ 1044 return old; \ 1045 } 1046 #define DEFINE_SYNCTEX_DATA_STR_DECODE(WHAT) \ 1047 static synctex_status_t _synctex_data_decode_##WHAT(synctex_node_p node) \ 1048 { \ 1049 if (_synctex_data_has_##WHAT(node)) { \ 1050 synctex_ss_s ss = _synctex_decode_string(node->class->scanner); \ 1051 if (ss.status == SYNCTEX_STATUS_OK) { \ 1052 _synctex_data_set_##WHAT(node, ss.string); \ 1053 } \ 1054 return ss.status; \ 1055 } \ 1056 return SYNCTEX_STATUS_BAD_ARGUMENT; \ 1057 } 1058 #define DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(WHAT) \ 1059 DEFINE_SYNCTEX_DATA_INT_GETSET(WHAT) \ 1060 DEFINE_SYNCTEX_DATA_INT_DECODE(WHAT) 1061 #define DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE_v(WHAT) \ 1062 DEFINE_SYNCTEX_DATA_INT_GETSET(WHAT) \ 1063 DEFINE_SYNCTEX_DATA_INT_DECODE_v(WHAT) 1064 #define DEFINE_SYNCTEX_DATA_STR_GETSET_DECODE(WHAT) \ 1065 DEFINE_SYNCTEX_DATA_STR_GETSET(WHAT) \ 1066 DEFINE_SYNCTEX_DATA_STR_DECODE(WHAT) 1067 1068 #ifdef SYNCTEX_NOTHING 1069 #pragma mark - 1070 #pragma mark OBJECTS, their creators and destructors. 1071 #endif 1072 1073 #ifdef SYNCTEX_NOTHING 1074 #pragma mark input. 1075 #endif 1076 1077 DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(tag) 1078 DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(line) 1079 DEFINE_SYNCTEX_DATA_STR_GETSET_DECODE(name) 1080 1081 /* Input nodes only know about their sibling, which is another input node. 1082 * The synctex information is the _synctex_data_tag and _synctex_data_name 1083 * note: the input owns its name. */ 1084 1085 #define SYNCTEX_INPUT_MARK "Input:" 1086 1087 static const synctex_tree_model_s synctex_tree_model_input = {synctex_tree_sibling_idx, /* sibling */ 1088 -1, /* parent */ 1089 -1, /* child */ 1090 -1, /* friend */ 1091 -1, /* last */ 1092 -1, /* next_hbox */ 1093 -1, /* arg_sibling */ 1094 -1, /* target */ 1095 synctex_tree_s_input_max}; 1096 static const synctex_data_model_s synctex_data_model_input = {synctex_data_input_tag_idx, /* tag */ 1097 synctex_data_input_line_idx, /* line */ 1098 -1, /* column */ 1099 -1, /* h */ 1100 -1, /* v */ 1101 -1, /* width */ 1102 -1, /* height */ 1103 -1, /* depth */ 1104 -1, /* mean_line */ 1105 -1, /* weight */ 1106 -1, /* h_V */ 1107 -1, /* v_V */ 1108 -1, /* width_V */ 1109 -1, /* height_V */ 1110 -1, /* depth_V */ 1111 synctex_data_input_name_idx, /* name */ 1112 -1, /* page */ 1113 synctex_data_input_tln_max}; 1114 1115 #define SYNCTEX_INSPECTOR_GETTER_F(WHAT) &_synctex_data_##WHAT, &_synctex_data_set_##WHAT 1116 1117 static synctex_node_p _synctex_new_input(synctex_scanner_p scanner); 1118 static void _synctex_free_input(synctex_node_p node); 1119 static void _synctex_log_input(synctex_node_p node); 1120 static char *_synctex_abstract_input(synctex_node_p node); 1121 static void _synctex_display_input(synctex_node_p node); 1122 1123 static const synctex_tlcpector_s synctex_tlcpector_input = { 1124 &_synctex_data_tag, /* tag */ 1125 &_synctex_int_none, /* line */ 1126 &_synctex_int_none, /* column */ 1127 }; 1128 1129 static synctex_class_s synctex_class_input = { 1130 NULL, /* No scanner yet */ 1131 synctex_node_type_input, /* Node type */ 1132 &_synctex_new_input, /* creator */ 1133 &_synctex_free_input, /* destructor */ 1134 &_synctex_log_input, /* log */ 1135 &_synctex_display_input, /* display */ 1136 &_synctex_abstract_input, /* abstract */ 1137 &synctex_tree_model_input, /* tree model */ 1138 &synctex_data_model_input, /* data model */ 1139 &synctex_tlcpector_input, /* inspector */ 1140 &synctex_inspector_none, /* inspector */ 1141 &synctex_vispector_none, /* vispector */ 1142 }; 1143 1144 typedef struct { 1145 SYNCTEX_DECLARE_CHARINDEX 1146 synctex_class_p class; 1147 synctex_data_u data[synctex_tree_s_input_max + synctex_data_input_tln_max]; 1148 } synctex_input_s; 1149 1150 static synctex_node_p _synctex_new_input(synctex_scanner_p scanner) 1151 { 1152 if (scanner) { 1153 synctex_node_p node = _synctex_malloc(sizeof(synctex_input_s)); 1154 if (node) { 1155 node->class = scanner->class + synctex_node_type_input; 1156 SYNCTEX_DID_NEW(node); 1157 SYNCTEX_IMPLEMENT_CHARINDEX(node, 0); 1158 SYNCTEX_REGISTER_HANDLE_TO(node); 1159 } 1160 return node; 1161 } 1162 return NULL; 1163 } 1164 1165 static void _synctex_free_input(synctex_node_p node) 1166 { 1167 if (node) { 1168 SYNCTEX_SCANNER_REMOVE_HANDLE_TO(node); 1169 SYNCTEX_WILL_FREE(node); 1170 synctex_node_free(__synctex_tree_sibling(node)); 1171 _synctex_free(_synctex_data_name(node)); 1172 _synctex_free(node); 1173 } 1174 } 1175 1176 /* The sheet is a first level node. 1177 * It has no parent (the owner is the scanner itself) 1178 * Its sibling points to another sheet. 1179 * Its child points to its first child, in general a box. 1180 * A sheet node contains only one synctex information: the page. 1181 * This is the 1 based page index as given by TeX. 1182 */ 1183 1184 #ifdef SYNCTEX_NOTHING 1185 #pragma mark sheet. 1186 #endif 1187 /** 1188 * Every node has the same structure, but not the same size. 1189 */ 1190 1191 DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(page) 1192 1193 typedef struct { 1194 SYNCTEX_DECLARE_CHARINDEX 1195 synctex_class_p class; 1196 synctex_data_u data[synctex_tree_scn_sheet_max + synctex_data_p_sheet_max]; 1197 } synctex_node_sheet_s; 1198 1199 /* sheet node creator */ 1200 1201 #define DEFINE_synctex_new_scanned_NODE(NAME) \ 1202 static synctex_node_p _synctex_new_##NAME(synctex_scanner_p scanner) \ 1203 { \ 1204 if (scanner) { \ 1205 ++SYNCTEX_CUR; \ 1206 synctex_node_p node = _synctex_malloc(sizeof(synctex_node_##NAME##_s)); \ 1207 if (node) { \ 1208 node->class = scanner->class + synctex_node_type_##NAME; \ 1209 SYNCTEX_DID_NEW(node); \ 1210 SYNCTEX_IMPLEMENT_CHARINDEX(node, -1); \ 1211 SYNCTEX_REGISTER_HANDLE_TO(node); \ 1212 } \ 1213 return node; \ 1214 } \ 1215 return NULL; \ 1216 } 1217 /* NB: -1 in SYNCTEX_IMPLEMENT_CHARINDEX above because 1218 * the first char of the line has been scanned 1219 */ 1220 DEFINE_synctex_new_scanned_NODE(sheet) static void _synctex_log_sheet(synctex_node_p node); 1221 static char *_synctex_abstract_sheet(synctex_node_p node); 1222 static void _synctex_display_sheet(synctex_node_p node); 1223 1224 static const synctex_tree_model_s synctex_tree_model_sheet = {synctex_tree_sibling_idx, /* sibling */ 1225 -1, /* parent */ 1226 synctex_tree_s_child_idx, /* child */ 1227 -1, /* friend */ 1228 -1, /* last */ 1229 synctex_tree_sc_next_hbox_idx, /* next_hbox */ 1230 -1, /* arg_sibling */ 1231 -1, /* target */ 1232 synctex_tree_scn_sheet_max}; 1233 static const synctex_data_model_s synctex_data_model_sheet = {-1, /* tag */ 1234 -1, /* line */ 1235 -1, /* column */ 1236 -1, /* h */ 1237 -1, /* v */ 1238 -1, /* width */ 1239 -1, /* height */ 1240 -1, /* depth */ 1241 -1, /* mean_line */ 1242 -1, /* weight */ 1243 -1, /* h_V */ 1244 -1, /* v_V */ 1245 -1, /* width_V */ 1246 -1, /* height_V */ 1247 -1, /* depth_V */ 1248 -1, /* name */ 1249 synctex_data_sheet_page_idx, /* page */ 1250 synctex_data_p_sheet_max}; 1251 static synctex_class_s synctex_class_sheet = { 1252 NULL, /* No scanner yet */ 1253 synctex_node_type_sheet, /* Node type */ 1254 &_synctex_new_sheet, /* creator */ 1255 &_synctex_free_node, /* destructor */ 1256 &_synctex_log_sheet, /* log */ 1257 &_synctex_display_sheet, /* display */ 1258 &_synctex_abstract_sheet, /* abstract */ 1259 &synctex_tree_model_sheet, /* tree model */ 1260 &synctex_data_model_sheet, /* data model */ 1261 &synctex_tlcpector_none, /* tlcpector */ 1262 &synctex_inspector_none, /* inspector */ 1263 &synctex_vispector_none, /* vispector */ 1264 }; 1265 1266 #ifdef SYNCTEX_NOTHING 1267 #pragma mark form. 1268 #endif 1269 /** 1270 * Every node has the same structure, but not the same size. 1271 */ 1272 typedef struct { 1273 SYNCTEX_DECLARE_CHARINDEX 1274 synctex_class_p class; 1275 synctex_data_u data[synctex_tree_sct_form_max + synctex_data_t_form_max]; 1276 } synctex_node_form_s; 1277 1278 DEFINE_synctex_new_scanned_NODE(form) 1279 1280 static char *_synctex_abstract_form(synctex_node_p node); 1281 static void _synctex_display_form(synctex_node_p node); 1282 static void _synctex_log_form(synctex_node_p node); 1283 1284 static const synctex_tree_model_s synctex_tree_model_form = {synctex_tree_sibling_idx, /* sibling */ 1285 -1, /* parent */ 1286 synctex_tree_s_child_idx, /* child */ 1287 -1, /* friend */ 1288 -1, /* last */ 1289 -1, /* next_hbox */ 1290 -1, /* arg_sibling */ 1291 synctex_tree_sc_target_idx, /* target */ 1292 synctex_tree_sct_form_max}; 1293 static const synctex_data_model_s synctex_data_model_form = {synctex_data_form_tag_idx, /* tag */ 1294 -1, /* line */ 1295 -1, /* column */ 1296 -1, /* h */ 1297 -1, /* v */ 1298 -1, /* width */ 1299 -1, /* height */ 1300 -1, /* depth */ 1301 -1, /* mean_line */ 1302 -1, /* weight */ 1303 -1, /* h_V */ 1304 -1, /* v_V */ 1305 -1, /* width_V */ 1306 -1, /* height_V */ 1307 -1, /* depth_V */ 1308 -1, /* name */ 1309 -1, /* page */ 1310 synctex_data_t_form_max}; 1311 static synctex_class_s synctex_class_form = { 1312 NULL, /* No scanner yet */ 1313 synctex_node_type_form, /* Node type */ 1314 &_synctex_new_form, /* creator */ 1315 &_synctex_free_node, /* destructor */ 1316 &_synctex_log_form, /* log */ 1317 &_synctex_display_form, /* display */ 1318 &_synctex_abstract_form, /* abstract */ 1319 &synctex_tree_model_form, /* tree model */ 1320 &synctex_data_model_form, /* data model */ 1321 &synctex_tlcpector_none, /* tlcpector */ 1322 &synctex_inspector_none, /* inspector */ 1323 &synctex_vispector_none, /* vispector */ 1324 }; 1325 1326 #ifdef SYNCTEX_NOTHING 1327 #pragma mark vbox. 1328 #endif 1329 1330 /* A box node contains navigation and synctex information 1331 * There are different kinds of boxes. 1332 * Only horizontal boxes are treated differently because of their visible size. 1333 */ 1334 typedef struct { 1335 SYNCTEX_DECLARE_CHARINDEX 1336 synctex_class_p class; 1337 synctex_data_u data[synctex_tree_spcfl_vbox_max + synctex_data_box_max]; 1338 } synctex_node_vbox_s; 1339 1340 /* vertical box node creator */ 1341 DEFINE_synctex_new_scanned_NODE(vbox) 1342 1343 static char *_synctex_abstract_vbox(synctex_node_p node); 1344 static void _synctex_display_vbox(synctex_node_p node); 1345 static void _synctex_log_vbox(synctex_node_p node); 1346 1347 static const synctex_tree_model_s synctex_tree_model_vbox = {synctex_tree_sibling_idx, /* sibling */ 1348 synctex_tree_s_parent_idx, /* parent */ 1349 synctex_tree_sp_child_idx, /* child */ 1350 synctex_tree_spc_friend_idx, /* friend */ 1351 synctex_tree_spcf_last_idx, /* last */ 1352 -1, /* next_hbox */ 1353 -1, /* arg_sibling */ 1354 -1, /* target */ 1355 synctex_tree_spcfl_vbox_max}; 1356 1357 DEFINE_SYNCTEX_DATA_INT_GETSET(column) 1358 static synctex_status_t _synctex_data_decode_column(synctex_node_p node) 1359 { 1360 if (_synctex_data_has_column(node)) { 1361 synctex_is_s is = _synctex_decode_int_opt(node->class->scanner, -1); 1362 if (is.status == SYNCTEX_STATUS_OK) { 1363 _synctex_data_set_column(node, is.integer); 1364 } 1365 return is.status; 1366 } 1367 return SYNCTEX_STATUS_BAD_ARGUMENT; 1368 } 1369 DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(h) 1370 DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE_v(v) DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(width) DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(height) DEFINE_SYNCTEX_DATA_INT_GETSET_DECODE(depth) 1371 1372 static const synctex_data_model_s synctex_data_model_box = {synctex_data_tag_idx, /* tag */ 1373 synctex_data_line_idx, /* line */ 1374 synctex_data_column_idx, /* column */ 1375 synctex_data_h_idx, /* h */ 1376 synctex_data_v_idx, /* v */ 1377 synctex_data_width_idx, /* width */ 1378 synctex_data_height_idx, /* height */ 1379 synctex_data_depth_idx, /* depth */ 1380 -1, /* mean_line */ 1381 -1, /* weight */ 1382 -1, /* h_V */ 1383 -1, /* v_V */ 1384 -1, /* width_V */ 1385 -1, /* height_V */ 1386 -1, /* depth_V */ 1387 -1, /* name */ 1388 -1, /* page */ 1389 synctex_data_box_max}; 1390 static const synctex_tlcpector_s synctex_tlcpector_default = { 1391 &_synctex_data_tag, /* tag */ 1392 &_synctex_data_line, /* line */ 1393 &_synctex_data_column, /* column */ 1394 }; 1395 static const synctex_inspector_s synctex_inspector_box = { 1396 &_synctex_data_h, 1397 &_synctex_data_v, 1398 &_synctex_data_width, 1399 &_synctex_data_height, 1400 &_synctex_data_depth, 1401 }; 1402 static float __synctex_node_visible_h(synctex_node_p node); 1403 static float __synctex_node_visible_v(synctex_node_p node); 1404 static float __synctex_node_visible_width(synctex_node_p node); 1405 static float __synctex_node_visible_height(synctex_node_p node); 1406 static float __synctex_node_visible_depth(synctex_node_p node); 1407 static synctex_vispector_s synctex_vispector_box = { 1408 &__synctex_node_visible_h, 1409 &__synctex_node_visible_v, 1410 &__synctex_node_visible_width, 1411 &__synctex_node_visible_height, 1412 &__synctex_node_visible_depth, 1413 }; 1414 /* These are static class objects, each scanner will make a copy of them and setup the scanner field. 1415 */ 1416 static synctex_class_s synctex_class_vbox = { 1417 NULL, /* No scanner yet */ 1418 synctex_node_type_vbox, /* Node type */ 1419 &_synctex_new_vbox, /* creator */ 1420 &_synctex_free_node, /* destructor */ 1421 &_synctex_log_vbox, /* log */ 1422 &_synctex_display_vbox, /* display */ 1423 &_synctex_abstract_vbox, /* abstract */ 1424 &synctex_tree_model_vbox, /* tree model */ 1425 &synctex_data_model_box, /* data model */ 1426 &synctex_tlcpector_default, /* tlcpector */ 1427 &synctex_inspector_box, /* inspector */ 1428 &synctex_vispector_box, /* vispector */ 1429 }; 1430 1431 #ifdef SYNCTEX_NOTHING 1432 #pragma mark hbox. 1433 #endif 1434 1435 /* Horizontal boxes must contain visible size, because 0 width does not mean emptiness. 1436 * They also contain an average of the line numbers of the containing nodes. */ 1437 1438 static const synctex_tree_model_s synctex_tree_model_hbox = {synctex_tree_sibling_idx, /* sibling */ 1439 synctex_tree_s_parent_idx, /* parent */ 1440 synctex_tree_sp_child_idx, /* child */ 1441 synctex_tree_spc_friend_idx, /* friend */ 1442 synctex_tree_spcf_last_idx, /* last */ 1443 synctex_tree_spcfl_next_hbox_idx, /* next_hbox */ 1444 -1, /* arg_sibling */ 1445 -1, /* target */ 1446 synctex_tree_spcfln_hbox_max}; 1447 1448 DEFINE_SYNCTEX_DATA_INT_GETSET(mean_line) 1449 DEFINE_SYNCTEX_DATA_INT_GETSET(weight) 1450 DEFINE_SYNCTEX_DATA_INT_GETSET(h_V) 1451 DEFINE_SYNCTEX_DATA_INT_GETSET(v_V) 1452 DEFINE_SYNCTEX_DATA_INT_GETSET(width_V) 1453 DEFINE_SYNCTEX_DATA_INT_GETSET(height_V) 1454 DEFINE_SYNCTEX_DATA_INT_GETSET(depth_V) 1455 1456 /** 1457 * The hbox model. 1458 * It contains V variants of geometrical information. 1459 * It happens that hboxes contain material that is not used to compute 1460 * the bounding box. Some letters may appear out of the box given by TeX. 1461 * In such a situation, the visible bounding box is bigger than the V variant. 1462 * Only hboxes have such variant. It does not make sense for void boxes 1463 * and it is not used here for vboxes. 1464 * - author: JL 1465 */ 1466 1467 static const synctex_data_model_s synctex_data_model_hbox = {synctex_data_tag_idx, /* tag */ 1468 synctex_data_line_idx, /* line */ 1469 synctex_data_column_idx, /* column */ 1470 synctex_data_h_idx, /* h */ 1471 synctex_data_v_idx, /* v */ 1472 synctex_data_width_idx, /* width */ 1473 synctex_data_height_idx, /* height */ 1474 synctex_data_depth_idx, /* depth */ 1475 synctex_data_mean_line_idx, /* mean_line */ 1476 synctex_data_weight_idx, /* weight */ 1477 synctex_data_h_V_idx, /* h_V */ 1478 synctex_data_v_V_idx, /* v_V */ 1479 synctex_data_width_V_idx, /* width_V */ 1480 synctex_data_height_V_idx, /* height_V */ 1481 synctex_data_depth_V_idx, /* depth_V */ 1482 -1, /* name */ 1483 -1, /* page */ 1484 synctex_data_hbox_max}; 1485 1486 typedef struct { 1487 SYNCTEX_DECLARE_CHARINDEX 1488 synctex_class_p class; 1489 synctex_data_u data[synctex_tree_spcfln_hbox_max + synctex_data_hbox_max]; 1490 } synctex_node_hbox_s; 1491 1492 /* horizontal box node creator */ 1493 DEFINE_synctex_new_scanned_NODE(hbox) 1494 1495 static void _synctex_log_hbox(synctex_node_p node); 1496 static char *_synctex_abstract_hbox(synctex_node_p node); 1497 static void _synctex_display_hbox(synctex_node_p node); 1498 1499 static synctex_class_s synctex_class_hbox = { 1500 NULL, /* No scanner yet */ 1501 synctex_node_type_hbox, /* Node type */ 1502 &_synctex_new_hbox, /* creator */ 1503 &_synctex_free_node, /* destructor */ 1504 &_synctex_log_hbox, /* log */ 1505 &_synctex_display_hbox, /* display */ 1506 &_synctex_abstract_hbox, /* abstract */ 1507 &synctex_tree_model_hbox, /* tree model */ 1508 &synctex_data_model_hbox, /* data model */ 1509 &synctex_tlcpector_default, /* tlcpector */ 1510 &synctex_inspector_box, /* inspector */ 1511 &synctex_vispector_box, /* vispector */ 1512 }; 1513 1514 #ifdef SYNCTEX_NOTHING 1515 #pragma mark void vbox. 1516 #endif 1517 1518 /* This void box node implementation is either horizontal or vertical 1519 * It does not contain a child field. 1520 */ 1521 static const synctex_tree_model_s synctex_tree_model_spf = {synctex_tree_sibling_idx, /* sibling */ 1522 synctex_tree_s_parent_idx, /* parent */ 1523 -1, /* child */ 1524 synctex_tree_sp_friend_idx, /* friend */ 1525 -1, /* last */ 1526 -1, /* next_hbox */ 1527 -1, /* arg_sibling */ 1528 -1, /* target */ 1529 synctex_tree_spf_max}; 1530 typedef struct { 1531 SYNCTEX_DECLARE_CHARINDEX 1532 synctex_class_p class; 1533 synctex_data_u data[synctex_tree_spf_max + synctex_data_box_max]; 1534 } synctex_node_void_vbox_s; 1535 1536 /* vertical void box node creator */ 1537 DEFINE_synctex_new_scanned_NODE(void_vbox) 1538 1539 static void _synctex_log_void_box(synctex_node_p node); 1540 static char *_synctex_abstract_void_vbox(synctex_node_p node); 1541 static void _synctex_display_void_vbox(synctex_node_p node); 1542 1543 static synctex_class_s synctex_class_void_vbox = { 1544 NULL, /* No scanner yet */ 1545 synctex_node_type_void_vbox, /* Node type */ 1546 &_synctex_new_void_vbox, /* creator */ 1547 &_synctex_free_leaf, /* destructor */ 1548 &_synctex_log_void_box, /* log */ 1549 &_synctex_display_void_vbox, /* display */ 1550 &_synctex_abstract_void_vbox, /* abstract */ 1551 &synctex_tree_model_spf, /* tree model */ 1552 &synctex_data_model_box, /* data model */ 1553 &synctex_tlcpector_default, /* tlcpector */ 1554 &synctex_inspector_box, /* inspector */ 1555 &synctex_vispector_box, /* vispector */ 1556 }; 1557 1558 #ifdef SYNCTEX_NOTHING 1559 #pragma mark void hbox. 1560 #endif 1561 1562 typedef synctex_node_void_vbox_s synctex_node_void_hbox_s; 1563 1564 /* horizontal void box node creator */ 1565 DEFINE_synctex_new_scanned_NODE(void_hbox) 1566 1567 static char *_synctex_abstract_void_hbox(synctex_node_p node); 1568 static void _synctex_display_void_hbox(synctex_node_p node); 1569 1570 static synctex_class_s synctex_class_void_hbox = { 1571 NULL, /* No scanner yet */ 1572 synctex_node_type_void_hbox, /* Node type */ 1573 &_synctex_new_void_hbox, /* creator */ 1574 &_synctex_free_leaf, /* destructor */ 1575 &_synctex_log_void_box, /* log */ 1576 &_synctex_display_void_hbox, /* display */ 1577 &_synctex_abstract_void_hbox, /* abstract */ 1578 &synctex_tree_model_spf, /* tree model */ 1579 &synctex_data_model_box, /* data model */ 1580 &synctex_tlcpector_default, /* tlcpector */ 1581 &synctex_inspector_box, /* inspector */ 1582 &synctex_vispector_box, /* vispector */ 1583 }; 1584 1585 #ifdef SYNCTEX_NOTHING 1586 #pragma mark form ref. 1587 #endif 1588 1589 /* The form ref node. */ 1590 typedef struct { 1591 SYNCTEX_DECLARE_CHARINDEX 1592 synctex_class_p class; 1593 synctex_data_u data[synctex_tree_spfa_max + synctex_data_ref_thv_max]; 1594 } synctex_node_ref_s; 1595 1596 /* form ref node creator */ 1597 DEFINE_synctex_new_scanned_NODE(ref) 1598 1599 static void _synctex_log_ref(synctex_node_p node); 1600 static char *_synctex_abstract_ref(synctex_node_p node); 1601 static void _synctex_display_ref(synctex_node_p node); 1602 1603 static const synctex_tree_model_s synctex_tree_model_spfa = {synctex_tree_sibling_idx, /* sibling */ 1604 synctex_tree_s_parent_idx, /* parent */ 1605 -1, /* child */ 1606 synctex_tree_sp_friend_idx, /* friend */ 1607 -1, /* last */ 1608 -1, /* next_hbox */ 1609 synctex_tree_spf_arg_sibling_idx, /* arg_sibling */ 1610 -1, /* target */ 1611 synctex_tree_spfa_max}; 1612 static const synctex_data_model_s synctex_data_model_ref = {synctex_data_tag_idx, /* tag */ 1613 -1, /* line */ 1614 -1, /* column */ 1615 synctex_data_ref_h_idx, /* h */ 1616 synctex_data_ref_v_idx, /* v */ 1617 -1, /* width */ 1618 -1, /* height */ 1619 -1, /* depth */ 1620 -1, /* mean_line */ 1621 -1, /* weight */ 1622 -1, /* h_V */ 1623 -1, /* v_V */ 1624 -1, /* width_V */ 1625 -1, /* height_V */ 1626 -1, /* depth_V */ 1627 synctex_data_ref_thv_max}; 1628 static synctex_class_s synctex_class_ref = { 1629 NULL, /* No scanner yet */ 1630 synctex_node_type_ref, /* Node type */ 1631 &_synctex_new_ref, /* creator */ 1632 &_synctex_free_leaf, /* destructor */ 1633 &_synctex_log_ref, /* log */ 1634 &_synctex_display_ref, /* display */ 1635 &_synctex_abstract_ref, /* abstract */ 1636 &synctex_tree_model_spfa, /* navigator */ 1637 &synctex_data_model_ref, /* data model */ 1638 &synctex_tlcpector_none, /* tlcpector */ 1639 &synctex_inspector_none, /* inspector */ 1640 &synctex_vispector_none, /* vispector */ 1641 }; 1642 #ifdef SYNCTEX_NOTHING 1643 #pragma mark small node. 1644 #endif 1645 1646 /* The small nodes correspond to glue, penalty, math and boundary nodes. */ 1647 static const synctex_data_model_s synctex_data_model_tlchv = {synctex_data_tag_idx, /* tag */ 1648 synctex_data_line_idx, /* line */ 1649 synctex_data_column_idx, /* column */ 1650 synctex_data_h_idx, /* h */ 1651 synctex_data_v_idx, /* v */ 1652 -1, /* width */ 1653 -1, /* height */ 1654 -1, /* depth */ 1655 -1, /* mean_line */ 1656 -1, /* weight */ 1657 -1, /* h_V */ 1658 -1, /* v_V */ 1659 -1, /* width_V */ 1660 -1, /* height_V */ 1661 -1, /* depth_V */ 1662 -1, /* name */ 1663 -1, /* page */ 1664 synctex_data_tlchv_max}; 1665 1666 typedef struct { 1667 SYNCTEX_DECLARE_CHARINDEX 1668 synctex_class_p class; 1669 synctex_data_u data[synctex_tree_spf_max + synctex_data_tlchv_max]; 1670 } synctex_node_tlchv_s; 1671 1672 static void _synctex_log_tlchv_node(synctex_node_p node); 1673 1674 #ifdef SYNCTEX_NOTHING 1675 #pragma mark math. 1676 #endif 1677 1678 typedef synctex_node_tlchv_s synctex_node_math_s; 1679 1680 /* math node creator */ 1681 DEFINE_synctex_new_scanned_NODE(math) 1682 1683 static char *_synctex_abstract_math(synctex_node_p node); 1684 static void _synctex_display_math(synctex_node_p node); 1685 static synctex_inspector_s synctex_inspector_hv = { 1686 &_synctex_data_h, 1687 &_synctex_data_v, 1688 &_synctex_int_none, 1689 &_synctex_int_none, 1690 &_synctex_int_none, 1691 }; 1692 static synctex_vispector_s synctex_vispector_hv = { 1693 &__synctex_node_visible_h, 1694 &__synctex_node_visible_v, 1695 &_synctex_float_none, 1696 &_synctex_float_none, 1697 &_synctex_float_none, 1698 }; 1699 1700 static synctex_class_s synctex_class_math = { 1701 NULL, /* No scanner yet */ 1702 synctex_node_type_math, /* Node type */ 1703 &_synctex_new_math, /* creator */ 1704 &_synctex_free_leaf, /* destructor */ 1705 &_synctex_log_tlchv_node, /* log */ 1706 &_synctex_display_math, /* display */ 1707 &_synctex_abstract_math, /* abstract */ 1708 &synctex_tree_model_spf, /* tree model */ 1709 &synctex_data_model_tlchv, /* data model */ 1710 &synctex_tlcpector_default, /* tlcpector */ 1711 &synctex_inspector_hv, /* inspector */ 1712 &synctex_vispector_hv, /* vispector */ 1713 }; 1714 1715 #ifdef SYNCTEX_NOTHING 1716 #pragma mark kern node. 1717 #endif 1718 1719 static const synctex_data_model_s synctex_data_model_tlchvw = {synctex_data_tag_idx, /* tag */ 1720 synctex_data_line_idx, /* line */ 1721 synctex_data_column_idx, /* column */ 1722 synctex_data_h_idx, /* h */ 1723 synctex_data_v_idx, /* v */ 1724 synctex_data_width_idx, /* width */ 1725 -1, /* height */ 1726 -1, /* depth */ 1727 -1, /* mean_line */ 1728 -1, /* weight */ 1729 -1, /* h_V */ 1730 -1, /* v_V */ 1731 -1, /* width_V */ 1732 -1, /* height_V */ 1733 -1, /* depth_V */ 1734 -1, /* name */ 1735 -1, /* page */ 1736 synctex_data_tlchvw_max}; 1737 typedef struct { 1738 SYNCTEX_DECLARE_CHARINDEX 1739 synctex_class_p class; 1740 synctex_data_u data[synctex_tree_spf_max + synctex_data_tlchvw_max]; 1741 } synctex_node_kern_s; 1742 1743 /* kern node creator */ 1744 DEFINE_synctex_new_scanned_NODE(kern) 1745 1746 static void _synctex_log_kern_node(synctex_node_p node); 1747 static char *_synctex_abstract_kern(synctex_node_p node); 1748 static void _synctex_display_kern(synctex_node_p node); 1749 1750 static synctex_inspector_s synctex_inspector_kern = { 1751 &_synctex_data_h, 1752 &_synctex_data_v, 1753 &_synctex_data_width, 1754 &_synctex_int_none, 1755 &_synctex_int_none, 1756 }; 1757 static float __synctex_kern_visible_h(synctex_node_p node); 1758 static float __synctex_kern_visible_width(synctex_node_p node); 1759 static synctex_vispector_s synctex_vispector_kern = { 1760 &__synctex_kern_visible_h, 1761 &__synctex_node_visible_v, 1762 &__synctex_kern_visible_width, 1763 &_synctex_float_none, 1764 &_synctex_float_none, 1765 }; 1766 1767 static synctex_class_s synctex_class_kern = { 1768 NULL, /* No scanner yet */ 1769 synctex_node_type_kern, /* Node type */ 1770 &_synctex_new_kern, /* creator */ 1771 &_synctex_free_leaf, /* destructor */ 1772 &_synctex_log_kern_node, /* log */ 1773 &_synctex_display_kern, /* display */ 1774 &_synctex_abstract_kern, /* abstract */ 1775 &synctex_tree_model_spf, /* tree model */ 1776 &synctex_data_model_tlchvw, /* data model */ 1777 &synctex_tlcpector_default, /* tlcpector */ 1778 &synctex_inspector_kern, /* inspector */ 1779 &synctex_vispector_kern, /* vispector */ 1780 }; 1781 1782 #ifdef SYNCTEX_NOTHING 1783 #pragma mark glue. 1784 #endif 1785 1786 /* glue node creator */ 1787 typedef synctex_node_tlchv_s synctex_node_glue_s; 1788 DEFINE_synctex_new_scanned_NODE(glue) 1789 1790 static char *_synctex_abstract_glue(synctex_node_p node); 1791 static void _synctex_display_glue(synctex_node_p node); 1792 1793 static synctex_class_s synctex_class_glue = { 1794 NULL, /* No scanner yet */ 1795 synctex_node_type_glue, /* Node type */ 1796 &_synctex_new_glue, /* creator */ 1797 &_synctex_free_leaf, /* destructor */ 1798 &_synctex_log_tlchv_node, /* log */ 1799 &_synctex_display_glue, /* display */ 1800 &_synctex_abstract_glue, /* abstract */ 1801 &synctex_tree_model_spf, /* tree model */ 1802 &synctex_data_model_tlchv, /* data model */ 1803 &synctex_tlcpector_default, /* tlcpector */ 1804 &synctex_inspector_hv, /* inspector */ 1805 &synctex_vispector_hv, /* vispector */ 1806 }; 1807 1808 /* The small nodes correspond to glue and boundary nodes. */ 1809 1810 #ifdef SYNCTEX_NOTHING 1811 #pragma mark rule. 1812 #endif 1813 1814 typedef struct { 1815 SYNCTEX_DECLARE_CHARINDEX 1816 synctex_class_p class; 1817 synctex_data_u data[synctex_tree_spf_max + synctex_data_box_max]; 1818 } synctex_node_rule_s; 1819 1820 DEFINE_synctex_new_scanned_NODE(rule) 1821 1822 static void _synctex_log_rule(synctex_node_p node); 1823 static char *_synctex_abstract_rule(synctex_node_p node); 1824 static void _synctex_display_rule(synctex_node_p node); 1825 1826 static float __synctex_rule_visible_h(synctex_node_p node); 1827 static float __synctex_rule_visible_v(synctex_node_p node); 1828 static float __synctex_rule_visible_width(synctex_node_p node); 1829 static float __synctex_rule_visible_height(synctex_node_p node); 1830 static float __synctex_rule_visible_depth(synctex_node_p node); 1831 static synctex_vispector_s synctex_vispector_rule = { 1832 &__synctex_rule_visible_h, 1833 &__synctex_rule_visible_v, 1834 &__synctex_rule_visible_width, 1835 &__synctex_rule_visible_height, 1836 &__synctex_rule_visible_depth, 1837 }; 1838 1839 static synctex_class_s synctex_class_rule = { 1840 NULL, /* No scanner yet */ 1841 synctex_node_type_rule, /* Node type */ 1842 &_synctex_new_rule, /* creator */ 1843 &_synctex_free_leaf, /* destructor */ 1844 &_synctex_log_rule, /* log */ 1845 &_synctex_display_rule, /* display */ 1846 &_synctex_abstract_rule, /* abstract */ 1847 &synctex_tree_model_spf, /* tree model */ 1848 &synctex_data_model_box, /* data model */ 1849 &synctex_tlcpector_default, /* tlcpector */ 1850 &synctex_inspector_box, /* inspector */ 1851 &synctex_vispector_rule, /* vispector */ 1852 }; 1853 1854 #ifdef SYNCTEX_NOTHING 1855 #pragma mark boundary. 1856 #endif 1857 1858 /* boundary node creator */ 1859 typedef synctex_node_tlchv_s synctex_node_boundary_s; 1860 DEFINE_synctex_new_scanned_NODE(boundary) 1861 1862 static char *_synctex_abstract_boundary(synctex_node_p node); 1863 static void _synctex_display_boundary(synctex_node_p node); 1864 1865 static synctex_class_s synctex_class_boundary = { 1866 NULL, /* No scanner yet */ 1867 synctex_node_type_boundary, /* Node type */ 1868 &_synctex_new_boundary, /* creator */ 1869 &_synctex_free_leaf, /* destructor */ 1870 &_synctex_log_tlchv_node, /* log */ 1871 &_synctex_display_boundary, /* display */ 1872 &_synctex_abstract_boundary, /* abstract */ 1873 &synctex_tree_model_spf, /* tree model */ 1874 &synctex_data_model_tlchv, /* data model */ 1875 &synctex_tlcpector_default, /* tlcpector */ 1876 &synctex_inspector_hv, /* inspector */ 1877 &synctex_vispector_hv, /* vispector */ 1878 }; 1879 1880 #ifdef SYNCTEX_NOTHING 1881 #pragma mark box boundary. 1882 #endif 1883 1884 typedef struct { 1885 SYNCTEX_DECLARE_CHARINDEX 1886 synctex_class_p class; 1887 synctex_data_u data[synctex_tree_spfa_max + synctex_data_tlchv_max]; 1888 } synctex_node_box_bdry_s; 1889 1890 #define DEFINE_synctex_new_unscanned_NODE(NAME) \ 1891 SYNCTEX_INLINE static synctex_node_p _synctex_new_##NAME(synctex_scanner_p scanner) \ 1892 { \ 1893 if (scanner) { \ 1894 synctex_node_p node = _synctex_malloc(sizeof(synctex_node_##NAME##_s)); \ 1895 if (node) { \ 1896 node->class = scanner->class + synctex_node_type_##NAME; \ 1897 SYNCTEX_DID_NEW(node); \ 1898 } \ 1899 return node; \ 1900 } \ 1901 return NULL; \ 1902 } 1903 DEFINE_synctex_new_unscanned_NODE(box_bdry) 1904 1905 static char *_synctex_abstract_box_bdry(synctex_node_p node); 1906 static void _synctex_display_box_bdry(synctex_node_p node); 1907 1908 static synctex_class_s synctex_class_box_bdry = { 1909 NULL, /* No scanner yet */ 1910 synctex_node_type_box_bdry, /* Node type */ 1911 &_synctex_new_box_bdry, /* creator */ 1912 &_synctex_free_leaf, /* destructor */ 1913 &_synctex_log_tlchv_node, /* log */ 1914 &_synctex_display_box_bdry, /* display */ 1915 &_synctex_abstract_box_bdry, /* display */ 1916 &synctex_tree_model_spfa, /* tree model */ 1917 &synctex_data_model_tlchv, /* data model */ 1918 &synctex_tlcpector_default, /* tlcpector */ 1919 &synctex_inspector_hv, /* inspector */ 1920 &synctex_vispector_hv, /* vispector */ 1921 }; 1922 1923 #ifdef SYNCTEX_NOTHING 1924 #pragma mark hbox proxy. 1925 #endif 1926 1927 /** 1928 * Standard nodes refer to TeX nodes: math, kern, boxes... 1929 * Proxy nodes are used to support forms. 1930 * A form is parsed as a tree of standard nodes starting 1931 * at the top left position. 1932 * When a reference is used, the form is duplicated 1933 * to the location specified by the reference. 1934 * As the same form can be duplicated at different locations, 1935 * the geometrical information is relative to its own top left point. 1936 * As we need absolute locations, we use proxy nodes. 1937 * A proxy node records an offset and the target node. 1938 * The target partly acts as a delegate. 1939 * The h and v position of the proxy node is the h and v 1940 * position of the target shifted by the proxy's offset. 1941 * The width, height and depth are not sensitive to offsets. 1942 * When are proxies created ? 1943 * 1) when the synctex file has been parsed, all the form refs 1944 * are replaced by proxies to the content of a form. 1945 * This content is a node with siblings (actually none). 1946 * Those root proxies have the parent of the ref they replace, 1947 * so their parents exist and are no proxy. 1948 * Moreover, if they have no sibling, it means that their target have no 1949 * sibling as well. 1950 * Such nodes are called root proxies. 1951 * 2) On the fly, when a proxy is asked for its child 1952 * (or sibling) and has none, a proxy to its target's child 1953 * (or sibling) is created if any. There are only 2 possible situations: 1954 * either the newly created proxy is the child of a proxy, 1955 * or it is the sibling of a proxy created on the fly. 1956 * In both cases, the parent is a proxy with children. 1957 * Such nodes are called child proxies. 1958 * How to compute the offset of a proxy ? 1959 * The offset of root proxy objects is exactly 1960 * the offset of the ref they replace. 1961 * The offset of other proxies is their owner's, 1962 * except when pointing to a root proxy. 1963 * What happens for cascading forms ? 1964 * Here is an example diagram 1965 * 1966 * At parse time, the arrow means "owns": 1967 * sheet0 -> ref_to1 1968 * 1969 * target1 -> ref_to2 1970 * 1971 * target2 -> child22 1972 * 1973 * After replacing the refs: 1974 * sheet0 -> proxy00 -> proxy01 -> proxy02 1975 * | | | 1976 * target1 -> proxy11 -> proxy12 1977 * | | 1978 * target2 -> proxy22 1979 * 1980 * proxy00, proxy11 and proxy22 are root proxies. 1981 * Their offset is the one of the ref they replace 1982 * proxy01, proxy02 and proxy12 are child proxies. 1983 * Their proxy is the one of their parent. 1984 * Optimization. 1985 * After all the refs are replaced, there are only root nodes 1986 * targeting standard node. We make sure that each child proxy 1987 * also targets a standard node. 1988 * It is possible for a proxy to have a standard sibling 1989 * whereas its target has no sibling at all. Root proxies 1990 * are such nodes, and are the only ones. 1991 * The consequence is that proxies created on the fly 1992 * must take into account this situation. 1993 */ 1994 1995 /* A proxy to a hbox. 1996 * A proxy do have a target, which can be a proxy 1997 */ 1998 1999 static const synctex_tree_model_s synctex_tree_model_proxy_hbox = {synctex_tree_sibling_idx, /* sibling */ 2000 synctex_tree_s_parent_idx, /* parent */ 2001 synctex_tree_sp_child_idx, /* child */ 2002 synctex_tree_spc_friend_idx, /* friend */ 2003 synctex_tree_spcf_last_idx, /* last */ 2004 synctex_tree_spcfl_next_hbox_idx, /* next_hbox */ 2005 -1, /* arg_sibling */ 2006 synctex_tree_spcfln_target_idx, /* target */ 2007 synctex_tree_spcflnt_proxy_hbox_max}; 2008 static const synctex_data_model_s synctex_data_model_proxy = {-1, /* tag */ 2009 -1, /* line */ 2010 -1, /* column */ 2011 synctex_data_proxy_h_idx, /* h */ 2012 synctex_data_proxy_v_idx, /* v */ 2013 -1, /* width */ 2014 -1, /* height */ 2015 -1, /* depth */ 2016 -1, /* mean_line */ 2017 -1, /* weight */ 2018 -1, /* h_V */ 2019 -1, /* v_V */ 2020 -1, /* width_V */ 2021 -1, /* height_V */ 2022 -1, /* depth_V */ 2023 -1, /* name */ 2024 -1, /* page */ 2025 synctex_data_proxy_hv_max}; 2026 typedef struct { 2027 SYNCTEX_DECLARE_CHARINDEX 2028 synctex_class_p class; 2029 synctex_data_u data[synctex_tree_spcflnt_proxy_hbox_max + synctex_data_proxy_hv_max]; 2030 } synctex_node_proxy_hbox_s; 2031 2032 /* box proxy node creator */ 2033 DEFINE_synctex_new_unscanned_NODE(proxy_hbox) 2034 2035 static void _synctex_log_proxy(synctex_node_p node); 2036 static char *_synctex_abstract_proxy_hbox(synctex_node_p node); 2037 static void _synctex_display_proxy_hbox(synctex_node_p node); 2038 2039 static int _synctex_proxy_tag(synctex_node_p); 2040 static int _synctex_proxy_line(synctex_node_p); 2041 static int _synctex_proxy_column(synctex_node_p); 2042 2043 static synctex_tlcpector_s synctex_tlcpector_proxy = { 2044 &_synctex_proxy_tag, 2045 &_synctex_proxy_line, 2046 &_synctex_proxy_column, 2047 }; 2048 static int _synctex_proxy_h(synctex_node_p); 2049 static int _synctex_proxy_v(synctex_node_p); 2050 static int _synctex_proxy_width(synctex_node_p); 2051 static int _synctex_proxy_height(synctex_node_p); 2052 static int _synctex_proxy_depth(synctex_node_p); 2053 static synctex_inspector_s synctex_inspector_proxy_box = { 2054 &_synctex_proxy_h, 2055 &_synctex_proxy_v, 2056 &_synctex_proxy_width, 2057 &_synctex_proxy_height, 2058 &_synctex_proxy_depth, 2059 }; 2060 2061 static float __synctex_proxy_visible_h(synctex_node_p); 2062 static float __synctex_proxy_visible_v(synctex_node_p); 2063 static float __synctex_proxy_visible_width(synctex_node_p); 2064 static float __synctex_proxy_visible_height(synctex_node_p); 2065 static float __synctex_proxy_visible_depth(synctex_node_p); 2066 2067 static synctex_vispector_s synctex_vispector_proxy_box = { 2068 &__synctex_proxy_visible_h, 2069 &__synctex_proxy_visible_v, 2070 &__synctex_proxy_visible_width, 2071 &__synctex_proxy_visible_height, 2072 &__synctex_proxy_visible_depth, 2073 }; 2074 2075 static synctex_class_s synctex_class_proxy_hbox = { 2076 NULL, /* No scanner yet */ 2077 synctex_node_type_proxy_hbox, /* Node type */ 2078 &_synctex_new_proxy_hbox, /* creator */ 2079 &_synctex_free_node, /* destructor */ 2080 &_synctex_log_proxy, /* log */ 2081 &_synctex_display_proxy_hbox, /* display */ 2082 &_synctex_abstract_proxy_hbox, /* abstract */ 2083 &synctex_tree_model_proxy_hbox, /* tree model */ 2084 &synctex_data_model_proxy, /* data model */ 2085 &synctex_tlcpector_proxy, /* tlcpector */ 2086 &synctex_inspector_proxy_box, /* inspector */ 2087 &synctex_vispector_proxy_box, /* vispector */ 2088 }; 2089 2090 #ifdef SYNCTEX_NOTHING 2091 #pragma mark vbox proxy. 2092 #endif 2093 2094 /* A proxy to a vbox. */ 2095 2096 static const synctex_tree_model_s synctex_tree_model_proxy_vbox = {synctex_tree_sibling_idx, /* sibling */ 2097 synctex_tree_s_parent_idx, /* parent */ 2098 synctex_tree_sp_child_idx, /* child */ 2099 synctex_tree_spc_friend_idx, /* friend */ 2100 synctex_tree_spcf_last_idx, /* last */ 2101 -1, /* next_hbox */ 2102 -1, /* arg_sibling */ 2103 synctex_tree_spcfl_target_idx, /* target */ 2104 synctex_tree_spcflt_proxy_vbox_max}; 2105 2106 typedef struct { 2107 SYNCTEX_DECLARE_CHARINDEX 2108 synctex_class_p class; 2109 synctex_data_u data[synctex_tree_spcflt_proxy_vbox_max + synctex_data_proxy_hv_max]; 2110 } synctex_node_proxy_vbox_s; 2111 2112 /* box proxy node creator */ 2113 DEFINE_synctex_new_unscanned_NODE(proxy_vbox) 2114 2115 static void _synctex_log_proxy(synctex_node_p node); 2116 static char *_synctex_abstract_proxy_vbox(synctex_node_p node); 2117 static void _synctex_display_proxy_vbox(synctex_node_p node); 2118 2119 static synctex_class_s synctex_class_proxy_vbox = { 2120 NULL, /* No scanner yet */ 2121 synctex_node_type_proxy_vbox, /* Node type */ 2122 &_synctex_new_proxy_vbox, /* creator */ 2123 &_synctex_free_node, /* destructor */ 2124 &_synctex_log_proxy, /* log */ 2125 &_synctex_display_proxy_vbox, /* display */ 2126 &_synctex_abstract_proxy_vbox, /* abstract */ 2127 &synctex_tree_model_proxy_vbox, /* tree model */ 2128 &synctex_data_model_proxy, /* data model */ 2129 &synctex_tlcpector_proxy, /* tlcpector */ 2130 &synctex_inspector_proxy_box, /* inspector */ 2131 &synctex_vispector_proxy_box, /* vispector */ 2132 }; 2133 2134 #ifdef SYNCTEX_NOTHING 2135 #pragma mark proxy. 2136 #endif 2137 2138 /** 2139 * A proxy to a node but a box. 2140 */ 2141 2142 static const synctex_tree_model_s synctex_tree_model_proxy = {synctex_tree_sibling_idx, /* sibling */ 2143 synctex_tree_s_parent_idx, /* parent */ 2144 -1, /* child */ 2145 synctex_tree_sp_friend_idx, /* friend */ 2146 -1, /* last */ 2147 -1, /* next_hbox */ 2148 -1, /* arg_sibling */ 2149 synctex_tree_spf_target_idx, /* target */ 2150 synctex_tree_spft_proxy_max}; 2151 2152 typedef struct { 2153 SYNCTEX_DECLARE_CHARINDEX 2154 synctex_class_p class; 2155 synctex_data_u data[synctex_tree_spft_proxy_max + synctex_data_proxy_hv_max]; 2156 } synctex_node_proxy_s; 2157 2158 /* proxy node creator */ 2159 DEFINE_synctex_new_unscanned_NODE(proxy) 2160 2161 static void _synctex_log_proxy(synctex_node_p node); 2162 static char *_synctex_abstract_proxy(synctex_node_p node); 2163 static void _synctex_display_proxy(synctex_node_p node); 2164 2165 static synctex_vispector_s synctex_vispector_proxy = { 2166 &__synctex_proxy_visible_h, 2167 &__synctex_proxy_visible_v, 2168 &__synctex_proxy_visible_width, 2169 &_synctex_float_none, 2170 &_synctex_float_none, 2171 }; 2172 2173 static synctex_class_s synctex_class_proxy = { 2174 NULL, /* No scanner yet */ 2175 synctex_node_type_proxy, /* Node type */ 2176 &_synctex_new_proxy, /* creator */ 2177 &_synctex_free_leaf, /* destructor */ 2178 &_synctex_log_proxy, /* log */ 2179 &_synctex_display_proxy, /* display */ 2180 &_synctex_abstract_proxy, /* abstract */ 2181 &synctex_tree_model_proxy, /* tree model */ 2182 &synctex_data_model_proxy, /* data model */ 2183 &synctex_tlcpector_proxy, /* tlcpector */ 2184 &synctex_inspector_proxy_box, /* inspector */ 2185 &synctex_vispector_proxy, /* vispector */ 2186 }; 2187 2188 #ifdef SYNCTEX_NOTHING 2189 #pragma mark last proxy. 2190 #endif 2191 2192 /** 2193 * A proxy to the last proxy/box boundary. 2194 */ 2195 2196 static const synctex_tree_model_s synctex_tree_model_proxy_last = {synctex_tree_sibling_idx, /* sibling */ 2197 synctex_tree_s_parent_idx, /* parent */ 2198 -1, /* child */ 2199 synctex_tree_sp_friend_idx, /* friend */ 2200 -1, /* last */ 2201 -1, /* next_hbox */ 2202 synctex_tree_spf_arg_sibling_idx, /* arg_sibling */ 2203 synctex_tree_spfa_target_idx, /* target */ 2204 synctex_tree_spfat_proxy_last_max}; 2205 2206 typedef struct { 2207 SYNCTEX_DECLARE_CHARINDEX 2208 synctex_class_p class; 2209 synctex_data_u data[synctex_tree_spfat_proxy_last_max + synctex_data_proxy_hv_max]; 2210 } synctex_node_proxy_last_s; 2211 2212 /* proxy node creator */ 2213 DEFINE_synctex_new_unscanned_NODE(proxy_last) 2214 2215 static void _synctex_log_proxy(synctex_node_p node); 2216 static char *_synctex_abstract_proxy(synctex_node_p node); 2217 static void _synctex_display_proxy(synctex_node_p node); 2218 2219 static synctex_class_s synctex_class_proxy_last = { 2220 NULL, /* No scanner yet */ 2221 synctex_node_type_proxy_last, /* Node type */ 2222 &_synctex_new_proxy, /* creator */ 2223 &_synctex_free_leaf, /* destructor */ 2224 &_synctex_log_proxy, /* log */ 2225 &_synctex_display_proxy, /* display */ 2226 &_synctex_abstract_proxy, /* abstract */ 2227 &synctex_tree_model_proxy_last, /* tree model */ 2228 &synctex_data_model_proxy, /* data model */ 2229 &synctex_tlcpector_proxy, /* tlcpector */ 2230 &synctex_inspector_proxy_box, /* inspector */ 2231 &synctex_vispector_proxy, /* vispector */ 2232 }; 2233 2234 #ifdef SYNCTEX_NOTHING 2235 #pragma mark handle. 2236 #endif 2237 2238 /** 2239 * A result node. 2240 */ 2241 2242 static const synctex_tree_model_s synctex_tree_model_handle = {synctex_tree_sibling_idx, /* sibling */ 2243 synctex_tree_s_parent_idx, /* parent */ 2244 synctex_tree_sp_child_idx, /* child */ 2245 -1, /* friend */ 2246 -1, /* last */ 2247 -1, /* next_hbox */ 2248 -1, /* arg_sibling */ 2249 synctex_tree_spc_target_idx, /* target */ 2250 synctex_tree_spct_handle_max}; 2251 2252 typedef struct { 2253 SYNCTEX_DECLARE_CHARINDEX 2254 synctex_class_p class; 2255 synctex_data_u data[synctex_tree_spct_handle_max + 0]; 2256 } synctex_node_handle_s; 2257 2258 /* result node creator */ 2259 DEFINE_synctex_new_unscanned_NODE(handle) 2260 2261 static void _synctex_log_handle(synctex_node_p node); 2262 static char *_synctex_abstract_handle(synctex_node_p node); 2263 static void _synctex_display_handle(synctex_node_p node); 2264 2265 static synctex_class_s synctex_class_handle = { 2266 NULL, /* No scanner yet */ 2267 synctex_node_type_handle, /* Node type */ 2268 &_synctex_new_handle, /* creator */ 2269 &_synctex_free_node, /* destructor */ 2270 &_synctex_log_handle, /* log */ 2271 &_synctex_display_handle, /* display */ 2272 &_synctex_abstract_handle, /* abstract */ 2273 &synctex_tree_model_handle, /* tree model */ 2274 &synctex_data_model_none, /* data model */ 2275 &synctex_tlcpector_proxy, /* tlcpector */ 2276 &synctex_inspector_proxy_box, /* inspector */ 2277 &synctex_vispector_proxy_box, /* vispector */ 2278 }; 2279 2280 SYNCTEX_INLINE static synctex_node_p _synctex_new_handle_with_target(synctex_node_p target) 2281 { 2282 if (target) { 2283 synctex_node_p result = _synctex_new_handle(target->class->scanner); 2284 if (result) { 2285 _synctex_tree_set_target(result, target); 2286 return result; 2287 } 2288 } 2289 return NULL; 2290 } 2291 2292 #ifdef SYNCTEX_NOTHING 2293 #pragma mark - 2294 #pragma mark Navigation 2295 #endif 2296 synctex_node_p synctex_node_parent(synctex_node_p node) 2297 { 2298 return _synctex_tree_parent(node); 2299 } 2300 synctex_node_p synctex_node_parent_sheet(synctex_node_p node) 2301 { 2302 while (node && synctex_node_type(node) != synctex_node_type_sheet) { 2303 node = _synctex_tree_parent(node); 2304 } 2305 /* exit the while loop either when node is NULL or node is a sheet */ 2306 return node; 2307 } 2308 synctex_node_p synctex_node_parent_form(synctex_node_p node) 2309 { 2310 while (node && synctex_node_type(node) != synctex_node_type_form) { 2311 node = _synctex_tree_parent(node); 2312 } 2313 /* exit the while loop either when node is NULL or node is a form */ 2314 return node; 2315 } 2316 2317 /** 2318 * The returned proxy will be the child or a sibling of source. 2319 * The returned proxy has no parent, child nor sibling. 2320 * Used only by __synctex_replace_ref. 2321 * argument to_node: a box, not a proxy nor anything else. 2322 */ 2323 SYNCTEX_INLINE static synctex_node_p __synctex_new_proxy_from_ref_to(synctex_node_p ref, synctex_node_p to_node) 2324 { 2325 synctex_node_p proxy = NULL; 2326 if (!ref || !to_node) { 2327 return NULL; 2328 } 2329 switch (synctex_node_type(to_node)) { 2330 case synctex_node_type_vbox: 2331 proxy = _synctex_new_proxy_vbox(ref->class->scanner); 2332 break; 2333 case synctex_node_type_hbox: 2334 proxy = _synctex_new_proxy_hbox(ref->class->scanner); 2335 break; 2336 default: 2337 _synctex_error("! __synctex_new_proxy_from_ref_to. Unexpected form child (%s). Please report.", synctex_node_isa(to_node)); 2338 return NULL; 2339 } 2340 if (!proxy) { 2341 _synctex_error("! __synctex_new_proxy_from_ref_to. Internal error. Please report."); 2342 return NULL; 2343 } 2344 _synctex_data_set_h(proxy, _synctex_data_h(ref)); 2345 _synctex_data_set_v(proxy, _synctex_data_v(ref)); 2346 _synctex_tree_set_target(proxy, to_node); 2347 #if defined(SYNCTEX_USE_CHARINDEX) 2348 proxy->line_index = to_node ? to_node->line_index : 0; 2349 proxy->char_index = to_node ? to_node->char_index : 0; 2350 #endif 2351 return proxy; 2352 } 2353 /** 2354 * The returned proxy will be the child or a sibling of owning_proxy. 2355 * The returned proxy has no parent, nor child. 2356 * Used only by synctex_node_child and synctex_node_sibling 2357 * to create proxies on the fly. 2358 * If the to_node has an already computed sibling, 2359 * then the returned proxy has itself a sibling 2360 * pointing to that already computed sibling. 2361 */ 2362 SYNCTEX_INLINE static synctex_node_p __synctex_new_child_proxy_to(synctex_node_p owner, synctex_node_p to_node) 2363 { 2364 synctex_node_p proxy = NULL; 2365 synctex_node_p target = to_node; 2366 if (!owner) { 2367 return NULL; 2368 } 2369 switch (synctex_node_type(target)) { 2370 case synctex_node_type_vbox: 2371 if ((proxy = _synctex_new_proxy_vbox(owner->class->scanner))) { 2372 exit_standard: 2373 _synctex_data_set_h(proxy, _synctex_data_h(owner)); 2374 _synctex_data_set_v(proxy, _synctex_data_v(owner)); 2375 exit0: 2376 _synctex_tree_set_target(proxy, target); 2377 #if defined(SYNCTEX_USE_CHARINDEX) 2378 proxy->line_index = to_node ? to_node->line_index : 0; 2379 proxy->char_index = to_node ? to_node->char_index : 0; 2380 #endif 2381 return proxy; 2382 }; 2383 break; 2384 case synctex_node_type_proxy_vbox: 2385 if ((proxy = _synctex_new_proxy_vbox(owner->class->scanner))) { 2386 exit_proxy: 2387 target = _synctex_tree_target(to_node); 2388 _synctex_data_set_h(proxy, _synctex_data_h(owner) + _synctex_data_h(to_node)); 2389 _synctex_data_set_v(proxy, _synctex_data_v(owner) + _synctex_data_v(to_node)); 2390 goto exit0; 2391 }; 2392 break; 2393 case synctex_node_type_hbox: 2394 if ((proxy = _synctex_new_proxy_hbox(owner->class->scanner))) { 2395 goto exit_standard; 2396 }; 2397 break; 2398 case synctex_node_type_proxy_hbox: 2399 if ((proxy = _synctex_new_proxy_hbox(owner->class->scanner))) { 2400 goto exit_proxy; 2401 }; 2402 break; 2403 case synctex_node_type_proxy: 2404 case synctex_node_type_proxy_last: 2405 if ((proxy = _synctex_new_proxy(owner->class->scanner))) { 2406 goto exit_proxy; 2407 }; 2408 break; 2409 default: 2410 if ((proxy = _synctex_new_proxy(owner->class->scanner))) { 2411 goto exit_standard; 2412 }; 2413 break; 2414 } 2415 _synctex_error( 2416 "! __synctex_new_child_proxy_to. " 2417 "Internal error. " 2418 "Please report."); 2419 return NULL; 2420 } 2421 SYNCTEX_INLINE static synctex_node_p _synctex_tree_set_sibling(synctex_node_p node, synctex_node_p new_sibling); 2422 typedef struct synctex_nns_t { 2423 synctex_node_p first; 2424 synctex_node_p last; 2425 synctex_status_t status; 2426 } synctex_nns_s; 2427 /** 2428 * Given a target node, create a list of proxies. 2429 * The first proxy points to the target node, 2430 * its sibling points to the target's sibling and so on. 2431 * Returns the first created proxy, the last one and 2432 * an error status. 2433 */ 2434 SYNCTEX_INLINE static synctex_nns_s _synctex_new_child_proxies_to(synctex_node_p owner, synctex_node_p to_node) 2435 { 2436 synctex_nns_s nns = {NULL, NULL, SYNCTEX_STATUS_OK}; 2437 if ((nns.first = nns.last = __synctex_new_child_proxy_to(owner, to_node))) { 2438 synctex_node_p to_next_sibling = __synctex_tree_sibling(to_node); 2439 synctex_node_p to_sibling; 2440 while ((to_sibling = to_next_sibling)) { 2441 synctex_node_p sibling; 2442 if ((to_next_sibling = __synctex_tree_sibling(to_sibling))) { 2443 /* This is not the last sibling */ 2444 if ((sibling = __synctex_new_child_proxy_to(owner, to_sibling))) { 2445 _synctex_tree_set_sibling(nns.last, sibling); 2446 nns.last = sibling; 2447 continue; 2448 } else { 2449 _synctex_error( 2450 "! _synctex_new_child_proxy_to. " 2451 "Internal error (1). " 2452 "Please report."); 2453 nns.status = SYNCTEX_STATUS_ERROR; 2454 } 2455 } else if ((sibling = _synctex_new_proxy_last(owner->class->scanner))) { 2456 _synctex_tree_set_sibling(nns.last, sibling); 2457 nns.last = sibling; 2458 _synctex_data_set_h(nns.last, _synctex_data_h(nns.first)); 2459 _synctex_data_set_v(nns.last, _synctex_data_v(nns.first)); 2460 _synctex_tree_set_target(nns.last, to_sibling); 2461 #if defined(SYNCTEX_USE_CHARINDEX) 2462 nns.last->line_index = to_sibling->line_index; 2463 nns.last->char_index = to_sibling->char_index; 2464 #endif 2465 } else { 2466 _synctex_error( 2467 "! _synctex_new_child_proxy_to. " 2468 "Internal error (2). " 2469 "Please report."); 2470 nns.status = SYNCTEX_STATUS_ERROR; 2471 } 2472 break; 2473 } 2474 } 2475 return nns; 2476 } 2477 static const char *_synctex_node_abstract(synctex_node_p node); 2478 SYNCTEX_INLINE static synctex_node_p synctex_tree_set_friend(synctex_node_p node, synctex_node_p new_friend) 2479 { 2480 #if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG 2481 synctex_node_p F = new_friend; 2482 while (F) { 2483 if (node == F) { 2484 printf("THIS IS AN ERROR\n"); 2485 F = new_friend; 2486 while (F) { 2487 printf("%s\n", _synctex_node_abstract(F)); 2488 if (node == F) { 2489 return NULL; 2490 } 2491 F = _synctex_tree_friend(F); 2492 } 2493 return NULL; 2494 } 2495 F = _synctex_tree_friend(F); 2496 } 2497 #endif 2498 return new_friend ? _synctex_tree_set_friend(node, new_friend) : _synctex_tree_reset_friend(node); 2499 } 2500 /** 2501 * 2502 */ 2503 SYNCTEX_INLINE static synctex_node_p __synctex_node_make_friend(synctex_node_p node, int i) 2504 { 2505 synctex_node_p old = NULL; 2506 if (i >= 0) { 2507 i = i % (node->class->scanner->number_of_lists); 2508 old = synctex_tree_set_friend(node, (node->class->scanner->lists_of_friends)[i]); 2509 (node->class->scanner->lists_of_friends)[i] = node; 2510 #if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500 2511 printf("tl(%i)=>", i); 2512 synctex_node_log(node); 2513 if (synctex_node_parent_form(node)) { 2514 printf("! ERROR. No registration expected!\n"); 2515 } 2516 #endif 2517 } 2518 return old; 2519 } 2520 /** 2521 * All proxies have tlc attributes, on behalf of their target. 2522 * The purpose is to register all af them. 2523 * - argument node: is the proxy, must not be NULL 2524 */ 2525 SYNCTEX_INLINE static synctex_node_p __synctex_proxy_make_friend_and_next_hbox(synctex_node_p node) 2526 { 2527 synctex_node_p old = NULL; 2528 synctex_node_p target = _synctex_tree_target(node); 2529 if (target) { 2530 int i = _synctex_data_tag(target) + _synctex_data_line(target); 2531 old = __synctex_node_make_friend(node, i); 2532 } else { 2533 old = __synctex_tree_reset_friend(node); 2534 } 2535 if (synctex_node_type(node) == synctex_node_type_proxy_hbox) { 2536 synctex_node_p sheet = synctex_node_parent_sheet(node); 2537 if (sheet) { 2538 _synctex_tree_set_next_hbox(node, _synctex_tree_next_hbox(sheet)); 2539 _synctex_tree_set_next_hbox(sheet, node); 2540 } 2541 } 2542 return old; 2543 } 2544 /** 2545 * Register a node which have tag, line and column. 2546 * - argument node: the node 2547 */ 2548 SYNCTEX_INLINE static synctex_node_p __synctex_node_make_friend_tlc(synctex_node_p node) 2549 { 2550 int i = synctex_node_tag(node) + synctex_node_line(node); 2551 return __synctex_node_make_friend(node, i); 2552 } 2553 /** 2554 * Register a node which have tag, line and column. 2555 * Does nothing if the argument is NULL. 2556 * Calls __synctex_node_make_friend_tlc. 2557 * - argument node: the node 2558 */ 2559 SYNCTEX_INLINE static void _synctex_node_make_friend_tlc(synctex_node_p node) 2560 { 2561 if (node) { 2562 __synctex_node_make_friend_tlc(node); 2563 } 2564 } 2565 static synctex_node_p _synctex_node_set_child(synctex_node_p node, synctex_node_p new_child); 2566 /** 2567 * The (first) child of the node, if any, NULL otherwise. 2568 * At parse time, non void box nodes have children. 2569 * All other nodes have no children. 2570 * In order to support pdf forms, proxies are created 2571 * to place form nodes at real locations. 2572 * Ref nodes are replaced by root proxies targeting 2573 * form contents. If root proxies have no children, 2574 * they are created on the fly as proxies to the 2575 * children of the targeted box. 2576 * As such, proxies created here are targeting a 2577 * node that belongs to a form. 2578 * This is the only place where child proxies are created. 2579 */ 2580 synctex_node_p synctex_node_child(synctex_node_p node) 2581 { 2582 synctex_node_p child = NULL; 2583 synctex_node_p target = NULL; 2584 if ((child = _synctex_tree_child(node))) { 2585 return child; 2586 } else if ((target = _synctex_tree_target(node))) { 2587 if ((child = synctex_node_child(target))) { 2588 /* This is a proxy with no child 2589 * which target does have a child. */ 2590 synctex_nns_s nns = _synctex_new_child_proxies_to(node, child); 2591 if (nns.first) { 2592 _synctex_node_set_child(node, nns.first); 2593 return nns.first; 2594 } else { 2595 _synctex_error("! synctex_node_child. Internal inconsistency. Please report."); 2596 } 2597 } 2598 } 2599 return NULL; 2600 } 2601 /* 2602 * Set the parent/child bound. 2603 * Things get complicated when new_child has siblings. 2604 * The caller is responsible for releasing the returned value. 2605 */ 2606 static synctex_node_p _synctex_node_set_child(synctex_node_p parent, synctex_node_p new_child) 2607 { 2608 if (parent) { 2609 synctex_node_p old = _synctex_tree_set_child(parent, new_child); 2610 synctex_node_p last_child = NULL; 2611 synctex_node_p child; 2612 if ((child = old)) { 2613 do { 2614 _synctex_tree_reset_parent(child); 2615 } while ((child = __synctex_tree_sibling(child))); 2616 } 2617 if ((child = new_child)) { 2618 do { 2619 _synctex_tree_set_parent(child, parent); 2620 last_child = child; 2621 } while ((child = __synctex_tree_sibling(child))); 2622 } 2623 _synctex_tree_set_last(parent, last_child); 2624 return old; 2625 } 2626 return NULL; 2627 } 2628 2629 /* The last child of the given node, or NULL. 2630 */ 2631 synctex_node_p synctex_node_last_child(synctex_node_p node) 2632 { 2633 return _synctex_tree_last(node); 2634 } 2635 /** 2636 * All nodes siblings are properly set up at parse time 2637 * except for non root proxies. 2638 */ 2639 synctex_node_p synctex_node_sibling(synctex_node_p node) 2640 { 2641 return node ? __synctex_tree_sibling(node) : NULL; 2642 } 2643 /** 2644 * All the _synctex_tree_... methods refer to the tree model. 2645 * __synctex_tree_... methods are low level. 2646 */ 2647 /** 2648 * Replace the sibling. 2649 * Connect to the arg_sibling of the new_sibling if relevant. 2650 * - returns the old sibling. 2651 * The caller is responsible for releasing the old sibling. 2652 * The bound to the parent is managed below. 2653 */ 2654 SYNCTEX_INLINE static synctex_node_p _synctex_tree_set_sibling(synctex_node_p node, synctex_node_p new_sibling) 2655 { 2656 if (node == new_sibling) { 2657 printf("BOF\n"); 2658 } 2659 synctex_node_p old = node ? __synctex_tree_set_sibling(node, new_sibling) : NULL; 2660 _synctex_tree_set_arg_sibling(new_sibling, node); 2661 return old; 2662 } 2663 /** 2664 * Replace the sibling. 2665 * Set the parent of the new sibling (and further siblings) 2666 * to the parent of the receiver. 2667 * Also set the last sibling of parent. 2668 * - argument new_sibling: must not be NULL. 2669 * - returns the old sibling. 2670 * The caller is responsible for releasing the old sibling. 2671 */ 2672 static synctex_node_p _synctex_node_set_sibling(synctex_node_p node, synctex_node_p new_sibling) 2673 { 2674 if (node && new_sibling) { 2675 synctex_node_p old = _synctex_tree_set_sibling(node, new_sibling); 2676 if (_synctex_tree_has_parent(node)) { 2677 synctex_node_p parent = __synctex_tree_parent(node); 2678 if (parent) { 2679 synctex_node_p N = new_sibling; 2680 while (synctex_YES) { 2681 if (_synctex_tree_has_parent(N)) { 2682 __synctex_tree_set_parent(N, parent); 2683 _synctex_tree_set_last(parent, N); 2684 N = __synctex_tree_sibling(N); 2685 continue; 2686 } else if (N) { 2687 _synctex_error( 2688 "! synctex_node_sibling. " 2689 "Internal inconsistency. " 2690 "Please report."); 2691 } 2692 break; 2693 } 2694 } 2695 } 2696 return old; 2697 } 2698 return NULL; 2699 } 2700 /** 2701 * The last sibling of the given node, or NULL with node. 2702 */ 2703 synctex_node_p synctex_node_last_sibling(synctex_node_p node) 2704 { 2705 synctex_node_p sibling; 2706 do { 2707 sibling = node; 2708 } while ((node = synctex_node_sibling(node))); 2709 return sibling; 2710 } 2711 /** 2712 * The next nodes corresponds to a deep first tree traversal. 2713 * Does not create child proxies as side effect contrary to 2714 * the synctex_node_next method above. 2715 * May loop infinitely many times if the tree 2716 * is not properly built (contains loops). 2717 */ 2718 SYNCTEX_INLINE static synctex_node_p _synctex_node_sibling_or_parents(synctex_node_p node) 2719 { 2720 while (node) { 2721 synctex_node_p N; 2722 if ((N = __synctex_tree_sibling(node))) { 2723 return N; 2724 } else if ((node = _synctex_tree_parent(node))) { 2725 if (synctex_node_type(node) == synctex_node_type_sheet) { /* EXC_BAD_ACCESS? */ 2726 return NULL; 2727 } else if (synctex_node_type(node) == synctex_node_type_form) { 2728 return NULL; 2729 } 2730 } else { 2731 return NULL; 2732 } 2733 } 2734 return NULL; 2735 } 2736 /** 2737 * The next nodes corresponds to a deep first tree traversal. 2738 * Creates child proxies as side effect. 2739 * May loop infinitely many times if the tree 2740 * is not properly built (contains loops). 2741 */ 2742 synctex_node_p synctex_node_next(synctex_node_p node) 2743 { 2744 synctex_node_p N = synctex_node_child(node); 2745 if (N) { 2746 return N; 2747 } 2748 return _synctex_node_sibling_or_parents(node); 2749 } 2750 /** 2751 * The next nodes corresponds to a deep first tree traversal. 2752 * Does not create child proxies as side effect contrary to 2753 * the synctex_node_next method above. 2754 * May loop infinitely many times if the tree 2755 * is not properly built (contains loops). 2756 */ 2757 synctex_node_p _synctex_node_next(synctex_node_p node) 2758 { 2759 synctex_node_p N = _synctex_tree_child(node); 2760 if (N) { 2761 return N; 2762 } 2763 return _synctex_node_sibling_or_parents(node); 2764 } 2765 /** 2766 * The node which argument is the sibling. 2767 * - return: NULL if the argument has no parent or 2768 * is the first child of its parent. 2769 * - Input nodes have no arg siblings 2770 */ 2771 synctex_node_p synctex_node_arg_sibling(synctex_node_p node) 2772 { 2773 #if 1 2774 return _synctex_tree_arg_sibling(node); 2775 #else 2776 synctex_node_p N = _synctex_tree_parent(node); 2777 if ((N = _synctex_tree_child(N))) { 2778 do { 2779 synctex_node_p NN = __synctex_tree_sibling(N); 2780 if (NN == node) { 2781 return N; 2782 } 2783 N = NN; 2784 } while (N); 2785 } 2786 return N; 2787 #endif 2788 } 2789 #ifdef SYNCTEX_NOTHING 2790 #pragma mark - 2791 #pragma mark CLASS 2792 #endif 2793 2794 /* Public node accessor: the type */ 2795 synctex_node_type_t synctex_node_type(synctex_node_p node) 2796 { 2797 return node ? node->class->type : synctex_node_type_none; 2798 } 2799 2800 /* Public node accessor: the type */ 2801 synctex_node_type_t synctex_node_target_type(synctex_node_p node) 2802 { 2803 synctex_node_p target = _synctex_tree_target(node); 2804 if (target) { 2805 return (((target)->class))->type; 2806 } else if (node) { 2807 return (((node)->class))->type; 2808 } 2809 return synctex_node_type_none; 2810 } 2811 2812 /* Public node accessor: the human readable type */ 2813 const char *synctex_node_isa(synctex_node_p node) 2814 { 2815 static const char *isa[synctex_node_number_of_types] = {"Not a node", "input", "sheet", "form", "ref", "vbox", "void vbox", "hbox", "void hbox", "kern", 2816 "glue", "rule", "math", "boundary", "box_bdry", "proxy", "last proxy", "vbox proxy", "hbox proxy", "handle"}; 2817 return isa[synctex_node_type(node)]; 2818 } 2819 2820 #ifdef SYNCTEX_NOTHING 2821 #pragma mark - 2822 #pragma mark LOG 2823 #endif 2824 2825 /* Public node logger */ 2826 void synctex_node_log(synctex_node_p node) 2827 { 2828 SYNCTEX_MSG_SEND(node, log); 2829 } 2830 2831 static void _synctex_log_input(synctex_node_p node) 2832 { 2833 if (node) { 2834 printf("%s:%i,%s(%i)\n", synctex_node_isa(node), _synctex_data_tag(node), _synctex_data_name(node), _synctex_data_line(node)); 2835 printf("SELF:%p\n", (void *)node); 2836 printf(" SIBLING:%p\n", (void *)__synctex_tree_sibling(node)); 2837 } 2838 } 2839 2840 static void _synctex_log_sheet(synctex_node_p node) 2841 { 2842 if (node) { 2843 printf("%s:%i", synctex_node_isa(node), _synctex_data_page(node)); 2844 SYNCTEX_PRINT_CHARINDEX_NL; 2845 printf("SELF:%p\n", (void *)node); 2846 printf(" SIBLING:%p\n", (void *)__synctex_tree_sibling(node)); 2847 printf(" PARENT:%p\n", (void *)_synctex_tree_parent(node)); 2848 printf(" CHILD:%p\n", (void *)_synctex_tree_child(node)); 2849 printf(" LEFT:%p\n", (void *)_synctex_tree_friend(node)); 2850 printf(" NEXT_hbox:%p\n", (void *)_synctex_tree_next_hbox(node)); 2851 } 2852 } 2853 2854 static void _synctex_log_form(synctex_node_p node) 2855 { 2856 if (node) { 2857 printf("%s:%i", synctex_node_isa(node), _synctex_data_tag(node)); 2858 SYNCTEX_PRINT_CHARINDEX_NL; 2859 printf("SELF:%p\n", (void *)node); 2860 printf(" SIBLING:%p\n", (void *)__synctex_tree_sibling(node)); 2861 printf(" PARENT:%p\n", (void *)_synctex_tree_parent(node)); 2862 printf(" CHILD:%p\n", (void *)_synctex_tree_child(node)); 2863 printf(" LEFT:%p\n", (void *)_synctex_tree_friend(node)); 2864 } 2865 } 2866 2867 static void _synctex_log_ref(synctex_node_p node) 2868 { 2869 if (node) { 2870 printf("%s:%i:%i,%i", synctex_node_isa(node), _synctex_data_tag(node), _synctex_data_h(node), _synctex_data_v(node)); 2871 SYNCTEX_PRINT_CHARINDEX_NL; 2872 printf("SELF:%p\n", (void *)node); 2873 printf(" SIBLING:%p\n", (void *)__synctex_tree_sibling(node)); 2874 printf(" PARENT:%p\n", (void *)_synctex_tree_parent(node)); 2875 } 2876 } 2877 2878 static void _synctex_log_tlchv_node(synctex_node_p node) 2879 { 2880 if (node) { 2881 printf("%s:%i,%i:%i,%i", synctex_node_isa(node), _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node)); 2882 SYNCTEX_PRINT_CHARINDEX_NL; 2883 printf("SELF:%p\n", (void *)node); 2884 printf(" SIBLING:%p\n", (void *)__synctex_tree_sibling(node)); 2885 printf(" PARENT:%p\n", (void *)_synctex_tree_parent(node)); 2886 printf(" CHILD:%p\n", (void *)_synctex_tree_child(node)); 2887 printf(" LEFT:%p\n", (void *)_synctex_tree_friend(node)); 2888 } 2889 } 2890 2891 static void _synctex_log_kern_node(synctex_node_p node) 2892 { 2893 if (node) { 2894 printf("%s:%i,%i:%i,%i:%i", synctex_node_isa(node), _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node), _synctex_data_width(node)); 2895 SYNCTEX_PRINT_CHARINDEX_NL; 2896 printf("SELF:%p\n", (void *)node); 2897 printf(" SIBLING:%p\n", (void *)__synctex_tree_sibling(node)); 2898 printf(" PARENT:%p\n", (void *)_synctex_tree_parent(node)); 2899 printf(" CHILD:%p\n", (void *)_synctex_tree_child(node)); 2900 printf(" LEFT:%p\n", (void *)_synctex_tree_friend(node)); 2901 } 2902 } 2903 2904 static void _synctex_log_rule(synctex_node_p node) 2905 { 2906 if (node) { 2907 printf("%s:%i,%i:%i,%i", synctex_node_isa(node), _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node)); 2908 printf(":%i", _synctex_data_width(node)); 2909 printf(",%i", _synctex_data_height(node)); 2910 printf(",%i", _synctex_data_depth(node)); 2911 SYNCTEX_PRINT_CHARINDEX_NL; 2912 printf("SELF:%p\n", (void *)node); 2913 printf(" SIBLING:%p\n", (void *)__synctex_tree_sibling(node)); 2914 printf(" PARENT:%p\n", (void *)_synctex_tree_parent(node)); 2915 printf(" LEFT:%p\n", (void *)_synctex_tree_friend(node)); 2916 } 2917 } 2918 2919 static void _synctex_log_void_box(synctex_node_p node) 2920 { 2921 if (node) { 2922 printf("%s", synctex_node_isa(node)); 2923 printf(":%i", _synctex_data_tag(node)); 2924 printf(",%i", _synctex_data_line(node)); 2925 printf(",%i", 0); 2926 printf(":%i", _synctex_data_h(node)); 2927 printf(",%i", _synctex_data_v(node)); 2928 printf(":%i", _synctex_data_width(node)); 2929 printf(",%i", _synctex_data_height(node)); 2930 printf(",%i", _synctex_data_depth(node)); 2931 SYNCTEX_PRINT_CHARINDEX_NL; 2932 printf("SELF:%p\n", (void *)node); 2933 printf(" SIBLING:%p\n", (void *)__synctex_tree_sibling(node)); 2934 printf(" PARENT:%p\n", (void *)_synctex_tree_parent(node)); 2935 printf(" CHILD:%p\n", (void *)_synctex_tree_child(node)); 2936 printf(" LEFT:%p\n", (void *)_synctex_tree_friend(node)); 2937 } 2938 } 2939 2940 static void _synctex_log_vbox(synctex_node_p node) 2941 { 2942 if (node) { 2943 printf("%s", synctex_node_isa(node)); 2944 printf(":%i", _synctex_data_tag(node)); 2945 printf(",%i", _synctex_data_line(node)); 2946 printf(",%i", 0); 2947 printf(":%i", _synctex_data_h(node)); 2948 printf(",%i", _synctex_data_v(node)); 2949 printf(":%i", _synctex_data_width(node)); 2950 printf(",%i", _synctex_data_height(node)); 2951 printf(",%i", _synctex_data_depth(node)); 2952 SYNCTEX_PRINT_CHARINDEX_NL; 2953 printf("SELF:%p\n", (void *)node); 2954 printf(" SIBLING:%p\n", (void *)__synctex_tree_sibling(node)); 2955 printf(" PARENT:%p\n", (void *)_synctex_tree_parent(node)); 2956 printf(" CHILD:%p\n", (void *)_synctex_tree_child(node)); 2957 printf(" LEFT:%p\n", (void *)_synctex_tree_friend(node)); 2958 printf(" NEXT_hbox:%p\n", (void *)_synctex_tree_next_hbox(node)); 2959 } 2960 } 2961 2962 static void _synctex_log_hbox(synctex_node_p node) 2963 { 2964 if (node) { 2965 printf("%s", synctex_node_isa(node)); 2966 printf(":%i", _synctex_data_tag(node)); 2967 printf(",%i~%i*%i", _synctex_data_line(node), _synctex_data_mean_line(node), _synctex_data_weight(node)); 2968 printf(",%i", 0); 2969 printf(":%i", _synctex_data_h(node)); 2970 printf(",%i", _synctex_data_v(node)); 2971 printf(":%i", _synctex_data_width(node)); 2972 printf(",%i", _synctex_data_height(node)); 2973 printf(",%i", _synctex_data_depth(node)); 2974 printf("/%i", _synctex_data_h_V(node)); 2975 printf(",%i", _synctex_data_v_V(node)); 2976 printf(":%i", _synctex_data_width_V(node)); 2977 printf(",%i", _synctex_data_height_V(node)); 2978 printf(",%i", _synctex_data_depth_V(node)); 2979 SYNCTEX_PRINT_CHARINDEX_NL; 2980 printf("SELF:%p\n", (void *)node); 2981 printf(" SIBLING:%p\n", (void *)__synctex_tree_sibling(node)); 2982 printf(" PARENT:%p\n", (void *)_synctex_tree_parent(node)); 2983 printf(" CHILD:%p\n", (void *)_synctex_tree_child(node)); 2984 printf(" LEFT:%p\n", (void *)_synctex_tree_friend(node)); 2985 printf(" NEXT_hbox:%p\n", (void *)_synctex_tree_next_hbox(node)); 2986 } 2987 } 2988 static void _synctex_log_proxy(synctex_node_p node) 2989 { 2990 if (node) { 2991 synctex_node_p N = _synctex_tree_target(node); 2992 printf("%s", synctex_node_isa(node)); 2993 printf(":%i", _synctex_data_h(node)); 2994 printf(",%i", _synctex_data_v(node)); 2995 SYNCTEX_PRINT_CHARINDEX_NL; 2996 printf("SELF:%p\n", (void *)node); 2997 printf(" SIBLING:%p\n", (void *)__synctex_tree_sibling(node)); 2998 printf(" LEFT:%p\n", (void *)_synctex_tree_friend(node)); 2999 printf(" ->%s\n", _synctex_node_abstract(N)); 3000 } 3001 } 3002 static void _synctex_log_handle(synctex_node_p node) 3003 { 3004 if (node) { 3005 synctex_node_p N = _synctex_tree_target(node); 3006 printf("%s", synctex_node_isa(node)); 3007 SYNCTEX_PRINT_CHARINDEX_NL; 3008 printf("SELF:%p\n", (void *)node); 3009 printf(" SIBLING:%p\n", (void *)__synctex_tree_sibling(node)); 3010 printf(" ->%s\n", _synctex_node_abstract(N)); 3011 } 3012 } 3013 3014 #ifdef SYNCTEX_NOTHING 3015 #pragma mark - 3016 #pragma mark SYNCTEX_DISPLAY 3017 #endif 3018 3019 int synctex_scanner_display_switcher(synctex_scanner_p scanR) 3020 { 3021 return scanR->display_switcher; 3022 } 3023 void synctex_scanner_set_display_switcher(synctex_scanner_p scanR, int switcher) 3024 { 3025 scanR->display_switcher = switcher; 3026 } 3027 static const char *const _synctex_display_prompt = "................................"; 3028 3029 static char *_synctex_scanner_display_prompt_down(synctex_scanner_p scanR) 3030 { 3031 if (scanR->display_prompt > _synctex_display_prompt) { 3032 --scanR->display_prompt; 3033 } 3034 return scanR->display_prompt; 3035 } 3036 static char *_synctex_scanner_display_prompt_up(synctex_scanner_p scanR) 3037 { 3038 if (scanR->display_prompt + 1 < _synctex_display_prompt + strlen(_synctex_display_prompt)) { 3039 ++scanR->display_prompt; 3040 } 3041 return scanR->display_prompt; 3042 } 3043 3044 void synctex_node_display(synctex_node_p node) 3045 { 3046 if (node) { 3047 synctex_scanner_p scanR = node->class->scanner; 3048 if (scanR) { 3049 if (scanR->display_switcher < 0) { 3050 SYNCTEX_MSG_SEND(node, display); 3051 } else if (scanR->display_switcher > 0 && --scanR->display_switcher > 0) { 3052 SYNCTEX_MSG_SEND(node, display); 3053 } else if (scanR->display_switcher-- >= 0) { 3054 printf("%s Next display skipped. Reset display switcher.\n", node->class->scanner->display_prompt); 3055 } 3056 } else { 3057 SYNCTEX_MSG_SEND(node, display); 3058 } 3059 } 3060 } 3061 static const char *_synctex_node_abstract(synctex_node_p node) 3062 { 3063 SYNCTEX_PARAMETER_ASSERT(node || node->class); 3064 return (node && node->class->abstract) ? node->class->abstract(node) : "none"; 3065 } 3066 3067 SYNCTEX_INLINE static void _synctex_display_child(synctex_node_p node) 3068 { 3069 synctex_node_p N = _synctex_tree_child(node); 3070 if (N) { 3071 _synctex_scanner_display_prompt_down(N->class->scanner); 3072 synctex_node_display(N); 3073 _synctex_scanner_display_prompt_up(N->class->scanner); 3074 } 3075 } 3076 3077 SYNCTEX_INLINE static void _synctex_display_sibling(synctex_node_p node) 3078 { 3079 synctex_node_display(__synctex_tree_sibling(node)); 3080 } 3081 #define SYNCTEX_ABSTRACT_MAX 128 3082 static char *_synctex_abstract_input(synctex_node_p node) 3083 { 3084 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3085 if (node) { 3086 snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "Input:%i:%s(%i)" SYNCTEX_PRINT_CHARINDEX_FMT, _synctex_data_tag(node), _synctex_data_name(node), _synctex_data_line(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3087 } 3088 return abstract; 3089 } 3090 3091 static void _synctex_display_input(synctex_node_p node) 3092 { 3093 if (node) { 3094 printf("Input:%i:%s(%i)" SYNCTEX_PRINT_CHARINDEX_FMT "\n", _synctex_data_tag(node), _synctex_data_name(node), _synctex_data_line(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3095 synctex_node_display(__synctex_tree_sibling(node)); 3096 } 3097 } 3098 3099 static char *_synctex_abstract_sheet(synctex_node_p node) 3100 { 3101 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3102 if (node) { 3103 snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "{%i...}" SYNCTEX_PRINT_CHARINDEX_FMT, _synctex_data_page(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3104 } 3105 return abstract; 3106 } 3107 3108 static void _synctex_display_sheet(synctex_node_p node) 3109 { 3110 if (node) { 3111 printf("%s{%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", node->class->scanner->display_prompt, _synctex_data_page(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3112 _synctex_display_child(node); 3113 printf("%s}\n", node->class->scanner->display_prompt); 3114 _synctex_display_sibling(node); 3115 } 3116 } 3117 3118 static char *_synctex_abstract_form(synctex_node_p node) 3119 { 3120 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3121 if (node) { 3122 snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "<%i...>" SYNCTEX_PRINT_CHARINDEX_FMT, _synctex_data_tag(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3123 SYNCTEX_PRINT_CHARINDEX; 3124 } 3125 return abstract; 3126 } 3127 3128 static void _synctex_display_form(synctex_node_p node) 3129 { 3130 if (node) { 3131 printf("%s<%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", node->class->scanner->display_prompt, _synctex_data_tag(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3132 _synctex_display_child(node); 3133 printf("%s>\n", node->class->scanner->display_prompt); 3134 _synctex_display_sibling(node); 3135 } 3136 } 3137 3138 static char *_synctex_abstract_vbox(synctex_node_p node) 3139 { 3140 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3141 if (node) { 3142 snprintf(abstract, 3143 SYNCTEX_ABSTRACT_MAX, 3144 "[%i,%i:%i,%i:%i,%i,%i...]" SYNCTEX_PRINT_CHARINDEX_FMT, 3145 _synctex_data_tag(node), 3146 _synctex_data_line(node), 3147 _synctex_data_h(node), 3148 _synctex_data_v(node), 3149 _synctex_data_width(node), 3150 _synctex_data_height(node), 3151 _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3152 } 3153 return abstract; 3154 } 3155 3156 static void _synctex_display_vbox(synctex_node_p node) 3157 { 3158 if (node) { 3159 printf("%s[%i,%i:%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", 3160 node->class->scanner->display_prompt, 3161 _synctex_data_tag(node), 3162 _synctex_data_line(node), 3163 _synctex_data_h(node), 3164 _synctex_data_v(node), 3165 _synctex_data_width(node), 3166 _synctex_data_height(node), 3167 _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3168 _synctex_display_child(node); 3169 printf("%s]\n%slast:%s\n", node->class->scanner->display_prompt, node->class->scanner->display_prompt, _synctex_node_abstract(_synctex_tree_last(node))); 3170 _synctex_display_sibling(node); 3171 } 3172 } 3173 3174 static char *_synctex_abstract_hbox(synctex_node_p node) 3175 { 3176 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3177 if (node) { 3178 snprintf(abstract, 3179 SYNCTEX_ABSTRACT_MAX, 3180 "(%i,%i~%i*%i:%i,%i:%i,%i,%i...)" SYNCTEX_PRINT_CHARINDEX_FMT, 3181 _synctex_data_tag(node), 3182 _synctex_data_line(node), 3183 _synctex_data_mean_line(node), 3184 _synctex_data_weight(node), 3185 _synctex_data_h(node), 3186 _synctex_data_v(node), 3187 _synctex_data_width(node), 3188 _synctex_data_height(node), 3189 _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3190 } 3191 return abstract; 3192 } 3193 3194 static void _synctex_display_hbox(synctex_node_p node) 3195 { 3196 if (node) { 3197 printf("%s(%i,%i~%i*%i:%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", 3198 node->class->scanner->display_prompt, 3199 _synctex_data_tag(node), 3200 _synctex_data_line(node), 3201 _synctex_data_mean_line(node), 3202 _synctex_data_weight(node), 3203 _synctex_data_h(node), 3204 _synctex_data_v(node), 3205 _synctex_data_width(node), 3206 _synctex_data_height(node), 3207 _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3208 _synctex_display_child(node); 3209 printf("%s)\n%slast:%s\n", node->class->scanner->display_prompt, node->class->scanner->display_prompt, _synctex_node_abstract(_synctex_tree_last(node))); 3210 _synctex_display_sibling(node); 3211 } 3212 } 3213 3214 static char *_synctex_abstract_void_vbox(synctex_node_p node) 3215 { 3216 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3217 if (node) { 3218 snprintf(abstract, 3219 SYNCTEX_ABSTRACT_MAX, 3220 "v%i,%i;%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", 3221 _synctex_data_tag(node), 3222 _synctex_data_line(node), 3223 _synctex_data_h(node), 3224 _synctex_data_v(node), 3225 _synctex_data_width(node), 3226 _synctex_data_height(node), 3227 _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3228 } 3229 return abstract; 3230 } 3231 3232 static void _synctex_display_void_vbox(synctex_node_p node) 3233 { 3234 if (node) { 3235 printf("%sv%i,%i;%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", 3236 node->class->scanner->display_prompt, 3237 _synctex_data_tag(node), 3238 _synctex_data_line(node), 3239 _synctex_data_h(node), 3240 _synctex_data_v(node), 3241 _synctex_data_width(node), 3242 _synctex_data_height(node), 3243 _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3244 _synctex_display_sibling(node); 3245 } 3246 } 3247 3248 static char *_synctex_abstract_void_hbox(synctex_node_p node) 3249 { 3250 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3251 if (node) { 3252 snprintf(abstract, 3253 SYNCTEX_ABSTRACT_MAX, 3254 "h%i,%i:%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT, 3255 _synctex_data_tag(node), 3256 _synctex_data_line(node), 3257 _synctex_data_h(node), 3258 _synctex_data_v(node), 3259 _synctex_data_width(node), 3260 _synctex_data_height(node), 3261 _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3262 } 3263 return abstract; 3264 } 3265 3266 static void _synctex_display_void_hbox(synctex_node_p node) 3267 { 3268 if (node) { 3269 printf("%sh%i,%i:%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", 3270 node->class->scanner->display_prompt, 3271 _synctex_data_tag(node), 3272 _synctex_data_line(node), 3273 _synctex_data_h(node), 3274 _synctex_data_v(node), 3275 _synctex_data_width(node), 3276 _synctex_data_height(node), 3277 _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3278 _synctex_display_sibling(node); 3279 } 3280 } 3281 3282 static char *_synctex_abstract_glue(synctex_node_p node) 3283 { 3284 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3285 if (node) { 3286 snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "glue:%i,%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT, _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3287 } 3288 return abstract; 3289 } 3290 3291 static void _synctex_display_glue(synctex_node_p node) 3292 { 3293 if (node) { 3294 printf("%sglue:%i,%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", node->class->scanner->display_prompt, _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3295 _synctex_display_sibling(node); 3296 } 3297 } 3298 3299 static char *_synctex_abstract_rule(synctex_node_p node) 3300 { 3301 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3302 if (node) { 3303 snprintf(abstract, 3304 SYNCTEX_ABSTRACT_MAX, 3305 "rule:%i,%i:%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT, 3306 _synctex_data_tag(node), 3307 _synctex_data_line(node), 3308 _synctex_data_h(node), 3309 _synctex_data_v(node), 3310 _synctex_data_width(node), 3311 _synctex_data_height(node), 3312 _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3313 } 3314 return abstract; 3315 } 3316 3317 static void _synctex_display_rule(synctex_node_p node) 3318 { 3319 if (node) { 3320 printf("%srule:%i,%i:%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", 3321 node->class->scanner->display_prompt, 3322 _synctex_data_tag(node), 3323 _synctex_data_line(node), 3324 _synctex_data_h(node), 3325 _synctex_data_v(node), 3326 _synctex_data_width(node), 3327 _synctex_data_height(node), 3328 _synctex_data_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3329 _synctex_display_sibling(node); 3330 } 3331 } 3332 3333 static char *_synctex_abstract_math(synctex_node_p node) 3334 { 3335 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3336 if (node) { 3337 snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "math:%i,%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT, _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3338 } 3339 return abstract; 3340 } 3341 3342 static void _synctex_display_math(synctex_node_p node) 3343 { 3344 if (node) { 3345 printf("%smath:%i,%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", node->class->scanner->display_prompt, _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3346 _synctex_display_sibling(node); 3347 } 3348 } 3349 3350 static char *_synctex_abstract_kern(synctex_node_p node) 3351 { 3352 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3353 if (node) { 3354 snprintf(abstract, 3355 SYNCTEX_ABSTRACT_MAX, 3356 "kern:%i,%i:%i,%i:%i" SYNCTEX_PRINT_CHARINDEX_FMT, 3357 _synctex_data_tag(node), 3358 _synctex_data_line(node), 3359 _synctex_data_h(node), 3360 _synctex_data_v(node), 3361 _synctex_data_width(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3362 } 3363 return abstract; 3364 } 3365 3366 static void _synctex_display_kern(synctex_node_p node) 3367 { 3368 if (node) { 3369 printf("%skern:%i,%i:%i,%i:%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", 3370 node->class->scanner->display_prompt, 3371 _synctex_data_tag(node), 3372 _synctex_data_line(node), 3373 _synctex_data_h(node), 3374 _synctex_data_v(node), 3375 _synctex_data_width(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3376 _synctex_display_sibling(node); 3377 } 3378 } 3379 3380 static char *_synctex_abstract_boundary(synctex_node_p node) 3381 { 3382 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3383 if (node) { 3384 snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "boundary:%i,%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT, _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3385 } 3386 return abstract; 3387 } 3388 3389 static void _synctex_display_boundary(synctex_node_p node) 3390 { 3391 if (node) { 3392 printf("%sboundary:%i,%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", node->class->scanner->display_prompt, _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3393 _synctex_display_sibling(node); 3394 } 3395 } 3396 3397 static char *_synctex_abstract_box_bdry(synctex_node_p node) 3398 { 3399 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3400 if (node) { 3401 snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "box bdry:%i,%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT, _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3402 } 3403 return abstract; 3404 } 3405 3406 static void _synctex_display_box_bdry(synctex_node_p node) 3407 { 3408 if (node) { 3409 printf("%sbox bdry:%i,%i:%i,%i", node->class->scanner->display_prompt, _synctex_data_tag(node), _synctex_data_line(node), _synctex_data_h(node), _synctex_data_v(node)); 3410 SYNCTEX_PRINT_CHARINDEX_NL; 3411 _synctex_display_sibling(node); 3412 } 3413 } 3414 3415 static char *_synctex_abstract_ref(synctex_node_p node) 3416 { 3417 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3418 if (node) { 3419 snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "form ref:%i:%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT, _synctex_data_tag(node), _synctex_data_h(node), _synctex_data_v(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3420 } 3421 return abstract; 3422 } 3423 3424 static void _synctex_display_ref(synctex_node_p node) 3425 { 3426 if (node) { 3427 printf("%sform ref:%i:%i,%i", node->class->scanner->display_prompt, _synctex_data_tag(node), _synctex_data_h(node), _synctex_data_v(node)); 3428 SYNCTEX_PRINT_CHARINDEX_NL; 3429 _synctex_display_sibling(node); 3430 } 3431 } 3432 static char *_synctex_abstract_proxy(synctex_node_p node) 3433 { 3434 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3435 if (node) { 3436 synctex_node_p N = _synctex_tree_target(node); 3437 snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "%s:%i,%i:%i,%i/%p%s", synctex_node_isa(node), synctex_node_tag(node), synctex_node_line(node), _synctex_data_h(node), _synctex_data_v(node), node, _synctex_node_abstract(N)); 3438 } 3439 return abstract; 3440 } 3441 static void _synctex_display_proxy(synctex_node_p node) 3442 { 3443 if (node) { 3444 synctex_node_p N = _synctex_tree_target(node); 3445 printf("%s%s:%i,%i:%i,%i", node->class->scanner->display_prompt, synctex_node_isa(node), synctex_node_tag(node), synctex_node_line(node), _synctex_data_h(node), _synctex_data_v(node)); 3446 if (N) { 3447 printf("=%i,%i:%i,%i,%i->%s", synctex_node_h(node), synctex_node_v(node), synctex_node_width(node), synctex_node_height(node), synctex_node_depth(node), _synctex_node_abstract(N)); 3448 } 3449 printf("\n"); 3450 _synctex_display_child(node); 3451 _synctex_display_sibling(node); 3452 } 3453 } 3454 static char *_synctex_abstract_proxy_vbox(synctex_node_p node) 3455 { 3456 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3457 if (node) { 3458 snprintf(abstract, 3459 SYNCTEX_ABSTRACT_MAX, 3460 "[*%i,%i:%i,%i:%i,%i,%i...*]" SYNCTEX_PRINT_CHARINDEX_FMT, 3461 synctex_node_tag(node), 3462 synctex_node_line(node), 3463 synctex_node_h(node), 3464 synctex_node_v(node), 3465 synctex_node_width(node), 3466 synctex_node_height(node), 3467 synctex_node_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3468 } 3469 return abstract; 3470 } 3471 3472 static void _synctex_display_proxy_vbox(synctex_node_p node) 3473 { 3474 if (node) { 3475 printf("%s[*%i,%i:%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", 3476 node->class->scanner->display_prompt, 3477 synctex_node_tag(node), 3478 synctex_node_line(node), 3479 synctex_node_h(node), 3480 synctex_node_v(node), 3481 synctex_node_width(node), 3482 synctex_node_height(node), 3483 synctex_node_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3484 _synctex_display_child(node); 3485 printf("%s*]\n%slast:%s\n", node->class->scanner->display_prompt, node->class->scanner->display_prompt, _synctex_node_abstract(_synctex_tree_last(node))); 3486 _synctex_display_sibling(node); 3487 } 3488 } 3489 3490 static char *_synctex_abstract_proxy_hbox(synctex_node_p node) 3491 { 3492 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3493 if (node) { 3494 snprintf(abstract, 3495 SYNCTEX_ABSTRACT_MAX, 3496 "(*%i,%i~%i*%i:%i,%i:%i,%i,%i...*)/%p" SYNCTEX_PRINT_CHARINDEX_FMT, 3497 synctex_node_tag(node), 3498 synctex_node_line(node), 3499 synctex_node_mean_line(node), 3500 synctex_node_weight(node), 3501 synctex_node_h(node), 3502 synctex_node_v(node), 3503 synctex_node_width(node), 3504 synctex_node_height(node), 3505 synctex_node_depth(node), 3506 node SYNCTEX_PRINT_CHARINDEX_WHAT); 3507 } 3508 return abstract; 3509 } 3510 3511 static void _synctex_display_proxy_hbox(synctex_node_p node) 3512 { 3513 if (node) { 3514 printf("%s(*%i,%i~%i*%i:%i,%i:%i,%i,%i" SYNCTEX_PRINT_CHARINDEX_FMT "\n", 3515 node->class->scanner->display_prompt, 3516 synctex_node_tag(node), 3517 synctex_node_line(node), 3518 synctex_node_mean_line(node), 3519 synctex_node_weight(node), 3520 synctex_node_h(node), 3521 synctex_node_v(node), 3522 synctex_node_width(node), 3523 synctex_node_height(node), 3524 synctex_node_depth(node) SYNCTEX_PRINT_CHARINDEX_WHAT); 3525 _synctex_display_child(node); 3526 printf("%s*)\n%slast:%s\n", node->class->scanner->display_prompt, node->class->scanner->display_prompt, _synctex_node_abstract(_synctex_tree_last(node))); 3527 _synctex_display_sibling(node); 3528 } 3529 } 3530 3531 static char *_synctex_abstract_handle(synctex_node_p node) 3532 { 3533 static char abstract[SYNCTEX_ABSTRACT_MAX] = "none"; 3534 if (node) { 3535 synctex_node_p N = _synctex_tree_target(node); 3536 if (N && !N->class) { 3537 exit(1); 3538 } 3539 snprintf(abstract, SYNCTEX_ABSTRACT_MAX, "%s:%s", synctex_node_isa(node), (N ? _synctex_node_abstract(N) : "")); 3540 } 3541 return abstract; 3542 } 3543 static void _synctex_display_handle(synctex_node_p node) 3544 { 3545 if (node) { 3546 synctex_node_p N = _synctex_tree_target(node); 3547 printf("%s%s:->%s\n", node->class->scanner->display_prompt, synctex_node_isa(node), _synctex_node_abstract(N)); 3548 _synctex_display_child(node); 3549 _synctex_display_sibling(node); 3550 } 3551 } 3552 #ifdef SYNCTEX_NOTHING 3553 #pragma mark - 3554 #pragma mark STATUS 3555 #endif 3556 3557 #ifdef SYNCTEX_NOTHING 3558 #pragma mark - 3559 #pragma mark Prototypes 3560 #endif 3561 typedef struct { 3562 size_t size; 3563 synctex_status_t status; 3564 } synctex_zs_s; 3565 static synctex_zs_s _synctex_buffer_get_available_size(synctex_scanner_p scanner, size_t size); 3566 static synctex_status_t _synctex_next_line(synctex_scanner_p scanner); 3567 static synctex_status_t _synctex_match_string(synctex_scanner_p scanner, const char *the_string); 3568 3569 typedef struct synctex_ns_t { 3570 synctex_node_p node; 3571 synctex_status_t status; 3572 } synctex_ns_s; 3573 static synctex_ns_s __synctex_parse_new_input(synctex_scanner_p scanner); 3574 static synctex_status_t _synctex_scan_preamble(synctex_scanner_p scanner); 3575 typedef struct { 3576 float value; 3577 synctex_status_t status; 3578 } synctex_fs_s; 3579 static synctex_fs_s _synctex_scan_float_and_dimension(synctex_scanner_p scanner); 3580 static synctex_status_t _synctex_scan_post_scriptum(synctex_scanner_p scanner); 3581 static synctex_status_t _synctex_scan_postamble(synctex_scanner_p scanner); 3582 static synctex_status_t _synctex_setup_visible_hbox(synctex_node_p box); 3583 static synctex_status_t _synctex_scan_content(synctex_scanner_p scanner); 3584 int synctex_scanner_pre_x_offset(synctex_scanner_p scanner); 3585 int synctex_scanner_pre_y_offset(synctex_scanner_p scanner); 3586 const char *synctex_scanner_get_output_fmt(synctex_scanner_p scanner); 3587 3588 #ifdef SYNCTEX_NOTHING 3589 #pragma mark - 3590 #pragma mark SCANNER UTILITIES 3591 #endif 3592 3593 #define SYNCTEX_FILE (scanner->reader->file) 3594 3595 /** 3596 * Try to ensure that the buffer contains at least size bytes. 3597 * Passing a huge size argument means the whole buffer length. 3598 * Passing a 0 size argument means return the available buffer length, without reading the file. 3599 * In that case, the return status is always SYNCTEX_STATUS_OK unless the given scanner is NULL. 3600 * 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. 3601 * It is the responsibility of the caller to test whether this size is conforming to its needs. 3602 * Negative values may return in case of error, actually 3603 * when there was an error reading the synctex file. 3604 * - parameter scanner: The owning scanner. When NULL, returns SYNCTEX_STATUS_BAD_ARGUMENT. 3605 * - parameter expected: expected number of bytes. 3606 * - returns: a size and a status. 3607 */ 3608 static synctex_zs_s _synctex_buffer_get_available_size(synctex_scanner_p scanner, size_t expected) 3609 { 3610 size_t size = 0; 3611 if (NULL == scanner) { 3612 return (synctex_zs_s) {0, SYNCTEX_STATUS_BAD_ARGUMENT}; 3613 } 3614 if (expected > scanner->reader->size) { 3615 expected = scanner->reader->size; 3616 } 3617 size = SYNCTEX_END - SYNCTEX_CUR; /* available is the number of unparsed chars in the buffer */ 3618 if (expected <= size) { 3619 /* There are already sufficiently many characters in the buffer */ 3620 return (synctex_zs_s) {size, SYNCTEX_STATUS_OK}; 3621 } 3622 if (SYNCTEX_FILE) { 3623 /* Copy the remaining part of the buffer to the beginning, 3624 * then read the next part of the file */ 3625 int already_read = 0; 3626 #if defined(SYNCTEX_USE_CHARINDEX) 3627 scanner->reader->charindex_offset += SYNCTEX_CUR - SYNCTEX_START; 3628 #endif 3629 if (size) { 3630 memmove(SYNCTEX_START, SYNCTEX_CUR, size); 3631 } 3632 SYNCTEX_CUR = SYNCTEX_START + size; /* the next character after the move, will change. */ 3633 /* Fill the buffer up to its end */ 3634 already_read = gzread(SYNCTEX_FILE, (void *)SYNCTEX_CUR, (int)(SYNCTEX_BUFFER_SIZE - size)); 3635 if (already_read > 0) { 3636 /* We assume that 0<already_read<=SYNCTEX_BUFFER_SIZE - size, such that 3637 * SYNCTEX_CUR + already_read = SYNCTEX_START + size + already_read <= SYNCTEX_START + SYNCTEX_BUFFER_SIZE */ 3638 SYNCTEX_END = SYNCTEX_CUR + already_read; 3639 /* If the end of the file was reached, all the required SYNCTEX_BUFFER_SIZE - available 3640 * may not be filled with values from the file. 3641 * In that case, the buffer should stop properly after already_read characters. */ 3642 *SYNCTEX_END = '\0'; /* there is enough room */ 3643 SYNCTEX_CUR = SYNCTEX_START; 3644 /* May be available is less than size, the caller will have to test. */ 3645 return (synctex_zs_s) {SYNCTEX_END - SYNCTEX_CUR, SYNCTEX_STATUS_OK}; 3646 } else if (0 > already_read) { 3647 /* There is a possible error in reading the file */ 3648 int errnum = 0; 3649 const char *error_string = gzerror(SYNCTEX_FILE, &errnum); 3650 if (Z_ERRNO == errnum) { 3651 /* There is an error in zlib caused by the file system */ 3652 _synctex_error("gzread error from the file system (%i)", errno); 3653 return (synctex_zs_s) {0, SYNCTEX_STATUS_ERROR}; 3654 } else if (errnum) { 3655 _synctex_error("gzread error (%i:%i,%s)", already_read, errnum, error_string); 3656 return (synctex_zs_s) {0, SYNCTEX_STATUS_ERROR}; 3657 } 3658 } 3659 /* Nothing was read, we are at the end of the file. */ 3660 gzclose(SYNCTEX_FILE); 3661 SYNCTEX_FILE = NULL; 3662 SYNCTEX_END = SYNCTEX_CUR; 3663 SYNCTEX_CUR = SYNCTEX_START; 3664 *SYNCTEX_END = '\0'; /* Terminate the string properly.*/ 3665 /* there might be a bit of text left */ 3666 return (synctex_zs_s) {SYNCTEX_END - SYNCTEX_CUR, SYNCTEX_STATUS_EOF}; 3667 } 3668 /* We cannot enlarge the buffer because the end of the file was reached. */ 3669 return (synctex_zs_s) {size, SYNCTEX_STATUS_EOF}; 3670 } 3671 3672 /* Used when parsing the synctex file. 3673 * Advance to the next character starting a line. 3674 * Actually, only '\n' is recognized as end of line marker. 3675 * On normal completion, the returned value is the number of unparsed characters available in the buffer. 3676 * In general, it is a positive value, 0 meaning that the end of file was reached. 3677 * -1 is returned in case of error, actually because there was an error while feeding the buffer. 3678 * When the function returns with no error, SYNCTEX_CUR points to the first character of the next line, if any. 3679 * J. Laurens: Sat May 10 07:52:31 UTC 2008 3680 */ 3681 static synctex_status_t _synctex_next_line(synctex_scanner_p scanner) 3682 { 3683 synctex_status_t status = SYNCTEX_STATUS_OK; 3684 if (NULL == scanner) { 3685 return SYNCTEX_STATUS_BAD_ARGUMENT; 3686 } 3687 infinite_loop: 3688 while (SYNCTEX_CUR < SYNCTEX_END) { 3689 if (*SYNCTEX_CUR == '\n') { 3690 ++SYNCTEX_CUR; 3691 ++scanner->reader->line_number; 3692 return _synctex_buffer_get_available_size(scanner, 1).status; 3693 } 3694 ++SYNCTEX_CUR; 3695 } 3696 /* Here, we have SYNCTEX_CUR == SYNCTEX_END, such that the next call to _synctex_buffer_get_available_size 3697 * will read another bunch of synctex file. Little by little, we advance to the end of the file. */ 3698 status = _synctex_buffer_get_available_size(scanner, 1).status; 3699 if (status <= SYNCTEX_STATUS_EOF) { 3700 return status; 3701 } 3702 goto infinite_loop; 3703 } 3704 3705 /* Scan the given string. 3706 * Both scanner and the_string must not be NULL, and the_string must not be 0 length. 3707 * SYNCTEX_STATUS_OK is returned if the string is found, 3708 * SYNCTEX_STATUS_EOF is returned when the EOF is reached, 3709 * SYNCTEX_STATUS_NOT_OK is returned is the string is not found, 3710 * an error status is returned otherwise. 3711 * This is a critical method because buffering renders things more difficult. 3712 * The given string might be as long as the maximum size_t value. 3713 * As side effect, the buffer state may have changed if the given argument string can't fit into the buffer. 3714 */ 3715 static synctex_status_t _synctex_match_string(synctex_scanner_p scanner, const char *the_string) 3716 { 3717 size_t tested_len = 0; /* the number of characters at the beginning of the_string that match */ 3718 size_t remaining_len = 0; /* the number of remaining characters of the_string that should match */ 3719 size_t available = 0; 3720 synctex_zs_s zs = {0, 0}; 3721 if (NULL == scanner || NULL == the_string) { 3722 return SYNCTEX_STATUS_BAD_ARGUMENT; 3723 } 3724 remaining_len = strlen(the_string); /* All the_string should match */ 3725 if (0 == remaining_len) { 3726 return SYNCTEX_STATUS_BAD_ARGUMENT; 3727 } 3728 /* How many characters available in the buffer? */ 3729 zs = _synctex_buffer_get_available_size(scanner, remaining_len); 3730 if (zs.status < SYNCTEX_STATUS_EOF) { 3731 return zs.status; 3732 } 3733 /* Maybe we have less characters than expected because the buffer is too small. */ 3734 if (zs.size >= remaining_len) { 3735 /* The buffer is sufficiently big to hold the expected number of characters. */ 3736 if (strncmp((char *)SYNCTEX_CUR, the_string, remaining_len)) { 3737 return SYNCTEX_STATUS_NOT_OK; 3738 } 3739 return_OK: 3740 /* Advance SYNCTEX_CUR to the next character after the_string. */ 3741 SYNCTEX_CUR += remaining_len; 3742 return SYNCTEX_STATUS_OK; 3743 } else if (strncmp((char *)SYNCTEX_CUR, the_string, zs.size)) { 3744 /* No need to go further, this is not the expected string in the buffer. */ 3745 return SYNCTEX_STATUS_NOT_OK; 3746 } else if (SYNCTEX_FILE) { 3747 /* The buffer was too small to contain remaining_len characters. 3748 * We have to cut the string into pieces. */ 3749 z_off_t offset = 0L; 3750 /* the first part of the string is found, advance the_string to the next untested character. */ 3751 the_string += zs.size; 3752 /* update the remaining length and the parsed length. */ 3753 remaining_len -= zs.size; 3754 tested_len += zs.size; 3755 SYNCTEX_CUR += zs.size; /* We validate the tested characters. */ 3756 if (0 == remaining_len) { 3757 /* Nothing left to test, we have found the given string. */ 3758 return SYNCTEX_STATUS_OK; 3759 } 3760 /* We also have to record the current state of the file cursor because 3761 * if the_string does not match, all this should be a totally blank operation, 3762 * for which the file and buffer states should not be modified at all. 3763 * In fact, the states of the buffer before and after this function are in general different 3764 * but they are totally equivalent as long as the values of the buffer before SYNCTEX_CUR 3765 * can be safely discarded. */ 3766 offset = gztell(SYNCTEX_FILE); 3767 /* offset now corresponds to the first character of the file that was not buffered. */ 3768 /* SYNCTEX_CUR - SYNCTEX_START is the number of chars that where already buffered and 3769 * that match the head of the_string. If in fine the_string does not match, all these chars must be recovered 3770 * because the whole buffer contents is replaced in _synctex_buffer_get_available_size. 3771 * They were buffered from offset-len location in the file. */ 3772 offset -= SYNCTEX_CUR - SYNCTEX_START; 3773 more_characters: 3774 /* There is still some work to be done, so read another bunch of file. 3775 * This is the second call to _synctex_buffer_get_available_size, 3776 * which means that the actual contents of the buffer will be discarded. 3777 * We will definitely have to recover the previous state in case we do not find the expected string. */ 3778 zs = _synctex_buffer_get_available_size(scanner, remaining_len); 3779 if (zs.status < SYNCTEX_STATUS_EOF) { 3780 return zs.status; /* This is an error, no need to go further. */ 3781 } 3782 if (zs.size == 0) { 3783 /* Missing characters: recover the initial state of the file and return. */ 3784 return_NOT_OK: 3785 if (offset != gzseek(SYNCTEX_FILE, offset, SEEK_SET)) { 3786 /* This is a critical error, we could not recover the previous state. */ 3787 _synctex_error("Can't seek file"); 3788 return SYNCTEX_STATUS_ERROR; 3789 } 3790 /* Next time we are asked to fill the buffer, 3791 * we will read a complete bunch of text from the file. */ 3792 SYNCTEX_CUR = SYNCTEX_END; 3793 return SYNCTEX_STATUS_NOT_OK; 3794 } 3795 if (zs.size < remaining_len) { 3796 /* We'll have to loop one more time. */ 3797 if (strncmp((char *)SYNCTEX_CUR, the_string, zs.size)) { 3798 /* This is not the expected string, recover the previous state and return. */ 3799 goto return_NOT_OK; 3800 } 3801 /* Advance the_string to the first untested character. */ 3802 the_string += available; 3803 /* update the remaining length and the parsed length. */ 3804 remaining_len -= zs.size; 3805 tested_len += zs.size; 3806 SYNCTEX_CUR += zs.size; /* We validate the tested characters. */ 3807 goto more_characters; 3808 } 3809 /* This is the last step. */ 3810 if (strncmp((char *)SYNCTEX_CUR, the_string, remaining_len)) { 3811 /* This is not the expected string, recover the previous state and return. */ 3812 goto return_NOT_OK; 3813 } 3814 goto return_OK; 3815 } else { 3816 /* The buffer can't contain the given string argument, and the EOF was reached */ 3817 return SYNCTEX_STATUS_EOF; 3818 } 3819 } 3820 3821 /* Used when parsing the synctex file. 3822 * Decode an integer. 3823 * First, field separators, namely ':' and ',' characters are skipped 3824 * The returned value is negative if there is an unrecoverable error. 3825 * It is SYNCTEX_STATUS_NOT_OK if an integer could not be parsed, for example 3826 * if the characters at the current cursor position are not digits or 3827 * if the end of the file has been reached. 3828 * It is SYNCTEX_STATUS_OK if an int has been successfully parsed. 3829 * The given scanner argument must not be NULL, on the contrary, value_ref may be NULL. 3830 */ 3831 static synctex_is_s _synctex_decode_int(synctex_scanner_p scanner) 3832 { 3833 char *ptr = NULL; 3834 char *end = NULL; 3835 synctex_zs_s zs = {0, 0}; 3836 int result; 3837 if (NULL == scanner) { 3838 return (synctex_is_s) {0, SYNCTEX_STATUS_BAD_ARGUMENT}; 3839 } 3840 zs = _synctex_buffer_get_available_size(scanner, SYNCTEX_BUFFER_MIN_SIZE); 3841 if (zs.status < SYNCTEX_STATUS_EOF) { 3842 return (synctex_is_s) {0, zs.status}; 3843 } 3844 if (zs.size == 0) { 3845 return (synctex_is_s) {0, SYNCTEX_STATUS_NOT_OK}; 3846 } 3847 ptr = SYNCTEX_CUR; 3848 /* Optionally parse the separator */ 3849 if (*ptr == ':' || *ptr == ',') { 3850 ++ptr; 3851 --zs.size; 3852 if (zs.size == 0) { 3853 return (synctex_is_s) {0, SYNCTEX_STATUS_NOT_OK}; 3854 } 3855 } 3856 result = (int)strtol(ptr, &end, 10); 3857 if (end > ptr) { 3858 SYNCTEX_CUR = end; 3859 return (synctex_is_s) {result, SYNCTEX_STATUS_OK}; 3860 } 3861 return (synctex_is_s) {result, SYNCTEX_STATUS_NOT_OK}; 3862 } 3863 static synctex_is_s _synctex_decode_int_opt(synctex_scanner_p scanner, int default_value) 3864 { 3865 char *ptr = NULL; 3866 char *end = NULL; 3867 synctex_zs_s zs = {0, 0}; 3868 if (NULL == scanner) { 3869 return (synctex_is_s) {default_value, SYNCTEX_STATUS_BAD_ARGUMENT}; 3870 } 3871 zs = _synctex_buffer_get_available_size(scanner, SYNCTEX_BUFFER_MIN_SIZE); 3872 if (zs.status < SYNCTEX_STATUS_EOF) { 3873 return (synctex_is_s) {default_value, zs.status}; 3874 } 3875 if (zs.size == 0) { 3876 return (synctex_is_s) {default_value, SYNCTEX_STATUS_OK}; 3877 } 3878 ptr = SYNCTEX_CUR; 3879 /* Comma separator required */ 3880 if (*ptr == ',') { 3881 int result; 3882 ++ptr; 3883 --zs.size; 3884 if (zs.size == 0) { 3885 return (synctex_is_s) {default_value, SYNCTEX_STATUS_NOT_OK}; 3886 } 3887 result = (int)strtol(ptr, &end, 10); 3888 if (end > ptr) { 3889 SYNCTEX_CUR = end; 3890 return (synctex_is_s) {result, SYNCTEX_STATUS_OK}; 3891 } 3892 return (synctex_is_s) {default_value, SYNCTEX_STATUS_NOT_OK}; 3893 } 3894 return (synctex_is_s) {default_value, SYNCTEX_STATUS_OK}; 3895 } 3896 /* Used when parsing the synctex file. 3897 * Decode an integer for a v field. 3898 * Try the _synctex_decode_int version and set the last v field scanned. 3899 * If it does not succeed, tries to match an '=' sign, 3900 * which is a shortcut for the last v field scanned. 3901 */ 3902 #define SYNCTEX_INPUT_COMEQUALS ",=" 3903 static synctex_is_s _synctex_decode_int_v(synctex_scanner_p scanner) 3904 { 3905 synctex_is_s is = _synctex_decode_int(scanner); 3906 if (SYNCTEX_STATUS_OK == is.status) { 3907 scanner->reader->lastv = is.integer; 3908 return is; 3909 } 3910 is.status = _synctex_match_string(scanner, SYNCTEX_INPUT_COMEQUALS); 3911 if (is.status < SYNCTEX_STATUS_OK) { 3912 return is; 3913 } 3914 is.integer = scanner->reader->lastv; 3915 return is; 3916 } 3917 3918 /* The purpose of this function is to read a string. 3919 * A string is an array of characters from the current parser location 3920 * and before the next '\n' character. 3921 * If a string was properly decoded, it is returned in value_ref and 3922 * the cursor points to the new line marker. 3923 * The returned string was alloced on the heap, the caller is the owner and 3924 * is responsible to free it in due time, 3925 * unless it transfers the ownership to another object. 3926 * If no string is parsed, * value_ref is undefined. 3927 * The maximum length of a string that a scanner can decode is platform dependent, namely UINT_MAX. 3928 * If you just want to blindly parse the file up to the end of the current line, 3929 * use _synctex_next_line instead. 3930 * On return, the scanner cursor is unchanged if a string could not be scanned or 3931 * points to the terminating '\n' character otherwise. As a consequence, 3932 * _synctex_next_line is necessary after. 3933 * If either scanner or value_ref is NULL, it is considered as an error and 3934 * SYNCTEX_STATUS_BAD_ARGUMENT is returned. 3935 */ 3936 static synctex_ss_s _synctex_decode_string(synctex_scanner_p scanner) 3937 { 3938 char *end = NULL; 3939 size_t len = 0; /* The number of bytes to copy */ 3940 size_t already_len = 0; 3941 synctex_zs_s zs = {0, 0}; 3942 char *string = NULL; 3943 if (NULL == scanner) { 3944 return (synctex_ss_s) {NULL, SYNCTEX_STATUS_BAD_ARGUMENT}; 3945 } 3946 /* The buffer must at least contain one character: the '\n' end of line marker */ 3947 if (SYNCTEX_CUR >= SYNCTEX_END) { 3948 more_characters: 3949 zs = _synctex_buffer_get_available_size(scanner, 1); 3950 if (zs.status < SYNCTEX_STATUS_EOF) { 3951 return (synctex_ss_s) {NULL, zs.status}; 3952 } else if (0 == zs.size) { 3953 return (synctex_ss_s) {NULL, SYNCTEX_STATUS_EOF}; 3954 } 3955 } 3956 /* Now we are sure that there is at least one available character, either because 3957 * SYNCTEX_CUR was already < SYNCTEX_END, or because the buffer has been properly filled. */ 3958 /* end will point to the next unparsed '\n' character in the file, when mapped to the buffer. */ 3959 end = SYNCTEX_CUR; 3960 /* We scan all the characters up to the next '\n' */ 3961 while (end < SYNCTEX_END && *end != '\n') { 3962 ++end; 3963 } 3964 /* OK, we found where to stop: 3965 * either end == SYNCTEX_END 3966 * or *end == '\n' */ 3967 len = end - SYNCTEX_CUR; 3968 if (len < UINT_MAX - already_len) { 3969 if ((string = realloc(string, len + already_len + 1)) != NULL) { 3970 if (memcpy(string + already_len, SYNCTEX_CUR, len)) { 3971 already_len += len; 3972 string[already_len] = '\0'; /* Terminate the string */ 3973 SYNCTEX_CUR += len; /* Eventually advance to the terminating '\n' */ 3974 if (SYNCTEX_CUR == SYNCTEX_END) { 3975 /* No \n found*/ 3976 goto more_characters; 3977 } 3978 /* trim the trailing whites */ 3979 len = already_len; 3980 while (len > 0) { 3981 already_len = len--; 3982 if (string[len] != ' ') { 3983 break; 3984 } 3985 } 3986 string[already_len] = '\0'; 3987 return (synctex_ss_s) {string, SYNCTEX_STATUS_OK}; 3988 } 3989 free(string); 3990 _synctex_error("could not copy memory (1)."); 3991 return (synctex_ss_s) {NULL, SYNCTEX_STATUS_ERROR}; 3992 } 3993 } 3994 _synctex_error("could not (re)allocate memory (1)."); 3995 return (synctex_ss_s) {NULL, SYNCTEX_STATUS_ERROR}; 3996 } 3997 3998 /* Used when parsing the synctex file. 3999 * Read an Input record. 4000 * - parameter scanner: non NULL scanner 4001 * - returns SYNCTEX_STATUS_OK on successful completions, others values otherwise. 4002 */ 4003 static synctex_ns_s __synctex_parse_new_input(synctex_scanner_p scanner) 4004 { 4005 synctex_node_p input = NULL; 4006 synctex_status_t status = SYNCTEX_STATUS_BAD_ARGUMENT; 4007 synctex_zs_s zs = {0, 0}; 4008 if (NULL == scanner) { 4009 return (synctex_ns_s) {NULL, status}; 4010 } 4011 if ((status = _synctex_match_string(scanner, SYNCTEX_INPUT_MARK)) < SYNCTEX_STATUS_OK) { 4012 return (synctex_ns_s) {NULL, status}; 4013 } 4014 /* Create a node */ 4015 if (NULL == (input = _synctex_new_input(scanner))) { 4016 _synctex_error("Could not create an input node."); 4017 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4018 } 4019 /* Decode the tag */ 4020 if ((status = _synctex_data_decode_tag(input)) < SYNCTEX_STATUS_OK) { 4021 _synctex_error("Bad format of input node."); 4022 synctex_node_free(input); 4023 return (synctex_ns_s) {NULL, status}; 4024 } 4025 /* The next character is a field separator, we expect one character in the buffer. */ 4026 zs = _synctex_buffer_get_available_size(scanner, 1); 4027 if (zs.status <= SYNCTEX_STATUS_ERROR) { 4028 return (synctex_ns_s) {NULL, status}; 4029 } 4030 if (0 == zs.size) { 4031 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_EOF}; 4032 } 4033 /* We can now safely advance to the next character, stepping over the field separator. */ 4034 ++SYNCTEX_CUR; 4035 --zs.size; 4036 /* Then we scan the file name */ 4037 if ((status = _synctex_data_decode_name(input)) < SYNCTEX_STATUS_OK) { 4038 synctex_node_free(input); 4039 _synctex_next_line(scanner); /* Ignore this whole line */ 4040 return (synctex_ns_s) {NULL, status}; 4041 } 4042 /* Prepend this input node to the input linked list of the scanner */ 4043 __synctex_tree_set_sibling(input, scanner->input); /* input has no parent */ 4044 scanner->input = input; 4045 #ifdef SYNCTEX_VERBOSE 4046 synctex_node_log(input); 4047 #endif 4048 return (synctex_ns_s) {input, _synctex_next_line(scanner)}; /* read the line termination character, if any */ 4049 } 4050 4051 typedef synctex_is_s (*synctex_decoder_t)(synctex_scanner_p); 4052 4053 /* Used when parsing the synctex file. 4054 * Read one of the settings. 4055 * On normal completion, returns SYNCTEX_STATUS_OK. 4056 * On error, returns SYNCTEX_STATUS_ERROR. 4057 * Both arguments must not be NULL. 4058 * On return, the scanner points to the next character after the decoded object whatever it is. 4059 * It is the responsibility of the caller to prepare the scanner for the next line. 4060 */ 4061 static synctex_status_t _synctex_scan_named(synctex_scanner_p scanner, const char *name) 4062 { 4063 synctex_status_t status = 0; 4064 if (NULL == scanner || NULL == name) { 4065 return SYNCTEX_STATUS_BAD_ARGUMENT; 4066 } 4067 not_found: 4068 status = _synctex_match_string(scanner, name); 4069 if (status < SYNCTEX_STATUS_NOT_OK) { 4070 return status; 4071 } else if (status == SYNCTEX_STATUS_NOT_OK) { 4072 status = _synctex_next_line(scanner); 4073 if (status < SYNCTEX_STATUS_OK) { 4074 return status; 4075 } 4076 goto not_found; 4077 } 4078 return SYNCTEX_STATUS_OK; 4079 } 4080 4081 /* Used when parsing the synctex file. 4082 * Read the preamble. 4083 */ 4084 static synctex_status_t _synctex_scan_preamble(synctex_scanner_p scanner) 4085 { 4086 synctex_status_t status = 0; 4087 synctex_is_s is = {0, 0}; 4088 synctex_ss_s ss = {NULL, 0}; 4089 if (NULL == scanner) { 4090 return SYNCTEX_STATUS_BAD_ARGUMENT; 4091 } 4092 status = _synctex_scan_named(scanner, "SyncTeX Version:"); 4093 if (status < SYNCTEX_STATUS_OK) { 4094 return status; 4095 } 4096 is = _synctex_decode_int(scanner); 4097 if (is.status < SYNCTEX_STATUS_OK) { 4098 return is.status; 4099 } 4100 status = _synctex_next_line(scanner); 4101 if (status < SYNCTEX_STATUS_OK) { 4102 return status; 4103 } 4104 scanner->version = is.integer; 4105 /* Read all the input records */ 4106 do { 4107 status = __synctex_parse_new_input(scanner).status; 4108 if (status < SYNCTEX_STATUS_NOT_OK) { 4109 return status; 4110 } 4111 } while (status == SYNCTEX_STATUS_OK); 4112 /* the loop exits when status == SYNCTEX_STATUS_NOT_OK */ 4113 /* Now read all the required settings. */ 4114 if ((status = _synctex_scan_named(scanner, "Output:")) < SYNCTEX_STATUS_OK) { 4115 return status; 4116 } 4117 if ((ss = _synctex_decode_string(scanner)).status < SYNCTEX_STATUS_OK) { 4118 return is.status; 4119 } 4120 if ((status = _synctex_next_line(scanner)) < SYNCTEX_STATUS_OK) { 4121 return status; 4122 } 4123 scanner->output_fmt = ss.string; 4124 if ((status = _synctex_scan_named(scanner, "Magnification:")) < SYNCTEX_STATUS_OK) { 4125 return status; 4126 } 4127 if ((is = _synctex_decode_int(scanner)).status < SYNCTEX_STATUS_OK) { 4128 return is.status; 4129 } 4130 if ((status = _synctex_next_line(scanner)) < SYNCTEX_STATUS_OK) { 4131 return status; 4132 } 4133 scanner->pre_magnification = is.integer; 4134 if ((status = _synctex_scan_named(scanner, "Unit:")) < SYNCTEX_STATUS_OK) { 4135 return status; 4136 } 4137 if ((is = _synctex_decode_int(scanner)).status < SYNCTEX_STATUS_OK) { 4138 return is.status; 4139 } 4140 if ((status = _synctex_next_line(scanner)) < SYNCTEX_STATUS_OK) { 4141 return status; 4142 } 4143 scanner->pre_unit = is.integer; 4144 if ((status = _synctex_scan_named(scanner, "X Offset:")) < SYNCTEX_STATUS_OK) { 4145 return status; 4146 } 4147 if ((is = _synctex_decode_int(scanner)).status < SYNCTEX_STATUS_OK) { 4148 return is.status; 4149 } 4150 if ((status = _synctex_next_line(scanner)) < SYNCTEX_STATUS_OK) { 4151 return status; 4152 } 4153 scanner->pre_x_offset = is.integer; 4154 if ((status = _synctex_scan_named(scanner, "Y Offset:")) < SYNCTEX_STATUS_OK) { 4155 return status; 4156 } 4157 if ((is = _synctex_decode_int(scanner)).status < SYNCTEX_STATUS_OK) { 4158 return is.status; 4159 } 4160 if ((status = _synctex_next_line(scanner)) < SYNCTEX_STATUS_OK) { 4161 return status; 4162 } 4163 scanner->pre_y_offset = is.integer; 4164 return SYNCTEX_STATUS_OK; 4165 } 4166 4167 /* parse a float with a dimension */ 4168 static synctex_fs_s _synctex_scan_float_and_dimension(synctex_scanner_p scanner) 4169 { 4170 synctex_fs_s fs = {0, 0}; 4171 synctex_zs_s zs = {0, 0}; 4172 char *endptr = NULL; 4173 #ifdef HAVE_SETLOCALE 4174 char *loc = setlocale(LC_NUMERIC, NULL); 4175 #endif 4176 if (NULL == scanner) { 4177 return (synctex_fs_s) {0, SYNCTEX_STATUS_BAD_ARGUMENT}; 4178 } 4179 zs = _synctex_buffer_get_available_size(scanner, SYNCTEX_BUFFER_MIN_SIZE); 4180 if (zs.status < SYNCTEX_STATUS_EOF) { 4181 _synctex_error("Problem with float."); 4182 return (synctex_fs_s) {0, zs.status}; 4183 } 4184 #ifdef HAVE_SETLOCALE 4185 setlocale(LC_NUMERIC, "C"); 4186 #endif 4187 fs.value = strtod(SYNCTEX_CUR, &endptr); 4188 #ifdef HAVE_SETLOCALE 4189 setlocale(LC_NUMERIC, loc); 4190 #endif 4191 if (endptr == SYNCTEX_CUR) { 4192 _synctex_error("A float was expected."); 4193 return (synctex_fs_s) {0, SYNCTEX_STATUS_ERROR}; 4194 } 4195 SYNCTEX_CUR = endptr; 4196 if ((fs.status = _synctex_match_string(scanner, "in")) >= SYNCTEX_STATUS_OK) { 4197 fs.value *= 72.27f * 65536; 4198 } else if (fs.status < SYNCTEX_STATUS_EOF) { 4199 report_unit_error: 4200 _synctex_error("problem with unit."); 4201 return fs; 4202 } else if ((fs.status = _synctex_match_string(scanner, "cm")) >= SYNCTEX_STATUS_OK) { 4203 fs.value *= 72.27f * 65536 / 2.54f; 4204 } else if (fs.status < SYNCTEX_STATUS_EOF) { 4205 goto report_unit_error; 4206 } else if ((fs.status = _synctex_match_string(scanner, "mm")) >= SYNCTEX_STATUS_OK) { 4207 fs.value *= 72.27f * 65536 / 25.4f; 4208 } else if (fs.status < SYNCTEX_STATUS_EOF) { 4209 goto report_unit_error; 4210 } else if ((fs.status = _synctex_match_string(scanner, "pt")) >= SYNCTEX_STATUS_OK) { 4211 fs.value *= 65536.0f; 4212 } else if (fs.status < SYNCTEX_STATUS_EOF) { 4213 goto report_unit_error; 4214 } else if ((fs.status = _synctex_match_string(scanner, "bp")) >= SYNCTEX_STATUS_OK) { 4215 fs.value *= 72.27f / 72 * 65536.0f; 4216 } else if (fs.status < SYNCTEX_STATUS_EOF) { 4217 goto report_unit_error; 4218 } else if ((fs.status = _synctex_match_string(scanner, "pc")) >= SYNCTEX_STATUS_OK) { 4219 fs.value *= 12.0 * 65536.0f; 4220 } else if (fs.status < SYNCTEX_STATUS_EOF) { 4221 goto report_unit_error; 4222 } else if ((fs.status = _synctex_match_string(scanner, "sp")) >= SYNCTEX_STATUS_OK) { 4223 fs.value *= 1.0f; 4224 } else if (fs.status < SYNCTEX_STATUS_EOF) { 4225 goto report_unit_error; 4226 } else if ((fs.status = _synctex_match_string(scanner, "dd")) >= SYNCTEX_STATUS_OK) { 4227 fs.value *= 1238.0f / 1157 * 65536.0f; 4228 } else if (fs.status < SYNCTEX_STATUS_EOF) { 4229 goto report_unit_error; 4230 } else if ((fs.status = _synctex_match_string(scanner, "cc")) >= SYNCTEX_STATUS_OK) { 4231 fs.value *= 14856.0f / 1157 * 65536; 4232 } else if (fs.status < SYNCTEX_STATUS_EOF) { 4233 goto report_unit_error; 4234 } else if ((fs.status = _synctex_match_string(scanner, "nd")) >= SYNCTEX_STATUS_OK) { 4235 fs.value *= 685.0f / 642 * 65536; 4236 } else if (fs.status < SYNCTEX_STATUS_EOF) { 4237 goto report_unit_error; 4238 } else if ((fs.status = _synctex_match_string(scanner, "nc")) >= SYNCTEX_STATUS_OK) { 4239 fs.value *= 1370.0f / 107 * 65536; 4240 } else if (fs.status < SYNCTEX_STATUS_EOF) { 4241 goto report_unit_error; 4242 } 4243 return fs; 4244 } 4245 4246 /* parse the post scriptum 4247 * SYNCTEX_STATUS_OK is returned on completion 4248 * a negative error is returned otherwise */ 4249 static synctex_status_t _synctex_scan_post_scriptum(synctex_scanner_p scanner) 4250 { 4251 synctex_status_t status = 0; 4252 synctex_fs_s fs = {0, 0}; 4253 char *endptr = NULL; 4254 #ifdef HAVE_SETLOCALE 4255 char *loc = setlocale(LC_NUMERIC, NULL); 4256 #endif 4257 if (NULL == scanner) { 4258 return SYNCTEX_STATUS_BAD_ARGUMENT; 4259 } 4260 /* Scan the file until a post scriptum line is found */ 4261 post_scriptum_not_found: 4262 status = _synctex_match_string(scanner, "Post scriptum:"); 4263 if (status < SYNCTEX_STATUS_NOT_OK) { 4264 return status; 4265 } 4266 if (status == SYNCTEX_STATUS_NOT_OK) { 4267 status = _synctex_next_line(scanner); 4268 if (status < SYNCTEX_STATUS_EOF) { 4269 return status; 4270 } else if (status < SYNCTEX_STATUS_OK) { 4271 return SYNCTEX_STATUS_OK; /* The EOF is found, we have properly scanned the file */ 4272 } 4273 goto post_scriptum_not_found; 4274 } 4275 /* We found the name, advance to the next line. */ 4276 next_line: 4277 status = _synctex_next_line(scanner); 4278 if (status < SYNCTEX_STATUS_EOF) { 4279 return status; 4280 } else if (status < SYNCTEX_STATUS_OK) { 4281 return SYNCTEX_STATUS_OK; /* The EOF is found, we have properly scanned the file */ 4282 } 4283 /* Scanning the information */ 4284 status = _synctex_match_string(scanner, "Magnification:"); 4285 if (status == SYNCTEX_STATUS_OK) { 4286 #ifdef HAVE_SETLOCALE 4287 setlocale(LC_NUMERIC, "C"); 4288 #endif 4289 scanner->unit = strtod(SYNCTEX_CUR, &endptr); 4290 #ifdef HAVE_SETLOCALE 4291 setlocale(LC_NUMERIC, loc); 4292 #endif 4293 if (endptr == SYNCTEX_CUR) { 4294 _synctex_error("bad magnification in the post scriptum, a float was expected."); 4295 return SYNCTEX_STATUS_ERROR; 4296 } 4297 if (scanner->unit <= 0) { 4298 _synctex_error("bad magnification in the post scriptum, a positive float was expected."); 4299 return SYNCTEX_STATUS_ERROR; 4300 } 4301 SYNCTEX_CUR = endptr; 4302 goto next_line; 4303 } 4304 if (status < SYNCTEX_STATUS_EOF) { 4305 report_record_problem: 4306 _synctex_error("Problem reading the Post Scriptum records"); 4307 return status; /* echo the error. */ 4308 } 4309 status = _synctex_match_string(scanner, "X Offset:"); 4310 if (status == SYNCTEX_STATUS_OK) { 4311 fs = _synctex_scan_float_and_dimension(scanner); 4312 if (fs.status < SYNCTEX_STATUS_OK) { 4313 _synctex_error("Problem with X offset in the Post Scriptum."); 4314 return fs.status; 4315 } 4316 scanner->x_offset = fs.value; 4317 goto next_line; 4318 } else if (status < SYNCTEX_STATUS_EOF) { 4319 goto report_record_problem; 4320 } 4321 status = _synctex_match_string(scanner, "Y Offset:"); 4322 if (status == SYNCTEX_STATUS_OK) { 4323 fs = _synctex_scan_float_and_dimension(scanner); 4324 if (fs.status < SYNCTEX_STATUS_OK) { 4325 _synctex_error("Problem with Y offset in the Post Scriptum."); 4326 return fs.status; 4327 } 4328 scanner->x_offset = fs.value; 4329 goto next_line; 4330 } else if (status < SYNCTEX_STATUS_EOF) { 4331 goto report_record_problem; 4332 } 4333 goto next_line; 4334 } 4335 4336 /* SYNCTEX_STATUS_OK is returned if the postamble is read 4337 * SYNCTEX_STATUS_NOT_OK is returned if the postamble is not at the current location 4338 * a negative error otherwise 4339 * The postamble comprises the post scriptum section. 4340 */ 4341 static synctex_status_t _synctex_scan_postamble(synctex_scanner_p scanner) 4342 { 4343 synctex_status_t status = 0; 4344 synctex_is_s is = {0, 0}; 4345 if (NULL == scanner) { 4346 return SYNCTEX_STATUS_BAD_ARGUMENT; 4347 } 4348 if (!scanner->flags.postamble && (status = _synctex_match_string(scanner, "Postamble:")) < SYNCTEX_STATUS_OK) { 4349 return status; 4350 } 4351 count_again: 4352 if ((status = _synctex_next_line(scanner)) < SYNCTEX_STATUS_OK) { 4353 return status; 4354 } 4355 if ((status = _synctex_scan_named(scanner, "Count:")) < SYNCTEX_STATUS_EOF) { 4356 return status; /* forward the error */ 4357 } else if (status < SYNCTEX_STATUS_OK) { /* No Count record found */ 4358 goto count_again; 4359 } 4360 if ((is = _synctex_decode_int(scanner)).status < SYNCTEX_STATUS_OK) { 4361 return is.status; 4362 } 4363 if ((status = _synctex_next_line(scanner)) < SYNCTEX_STATUS_OK) { 4364 return status; 4365 } 4366 scanner->count = is.integer; 4367 /* Now we scan the last part of the SyncTeX file: the Post Scriptum section. */ 4368 return _synctex_scan_post_scriptum(scanner); 4369 } 4370 4371 /* Horizontal boxes also have visible size. 4372 * Visible size are bigger than real size. 4373 * For example 0 width boxes may contain text. 4374 * At creation time, the visible size is set to the values of the real size. 4375 */ 4376 static synctex_status_t _synctex_setup_visible_hbox(synctex_node_p box) 4377 { 4378 if (box) { 4379 switch (synctex_node_type(box)) { 4380 case synctex_node_type_hbox: 4381 _synctex_data_set_h_V(box, _synctex_data_h(box)); 4382 _synctex_data_set_v_V(box, _synctex_data_v(box)); 4383 _synctex_data_set_width_V(box, _synctex_data_width(box)); 4384 _synctex_data_set_height_V(box, _synctex_data_height(box)); 4385 _synctex_data_set_depth_V(box, _synctex_data_depth(box)); 4386 return SYNCTEX_STATUS_OK; 4387 default: 4388 break; 4389 } 4390 } 4391 return SYNCTEX_STATUS_BAD_ARGUMENT; 4392 } 4393 4394 /* This method is sent to an horizontal box to setup the visible size 4395 * Some box have 0 width but do contain text material. 4396 * With this method, one can enlarge the box to contain the given point (h,v). 4397 */ 4398 static synctex_status_t _synctex_make_hbox_contain_point(synctex_node_p node, synctex_point_s point) 4399 { 4400 int min, max, n; 4401 if (NULL == node || synctex_node_type(node) != synctex_node_type_hbox) { 4402 return SYNCTEX_STATUS_BAD_ARGUMENT; 4403 } 4404 if ((n = _synctex_data_width_V(node)) < 0) { 4405 max = _synctex_data_h_V(node); 4406 min = max + n; 4407 if (point.h < min) { 4408 _synctex_data_set_width_V(node, point.h - max); 4409 } else if (point.h > max) { 4410 _synctex_data_set_h_V(node, point.h); 4411 _synctex_data_set_width_V(node, min - point.h); 4412 } 4413 } else { 4414 min = _synctex_data_h_V(node); 4415 max = min + n; 4416 if (point.h < min) { 4417 _synctex_data_set_h_V(node, point.h); 4418 _synctex_data_set_width_V(node, max - point.h); 4419 } else if (point.h > max) { 4420 _synctex_data_set_width_V(node, point.h - min); 4421 } 4422 } 4423 n = _synctex_data_v_V(node); 4424 min = n - _synctex_data_height_V(node); 4425 max = n + _synctex_data_depth_V(node); 4426 if (point.v < min) { 4427 _synctex_data_set_height_V(node, n - point.v); 4428 } else if (point.v > max) { 4429 _synctex_data_set_depth_V(node, point.v - n); 4430 } 4431 return SYNCTEX_STATUS_OK; 4432 } 4433 static synctex_status_t _synctex_make_hbox_contain_box(synctex_node_p node, synctex_box_s box) 4434 { 4435 int min, max, n; 4436 if (NULL == node || synctex_node_type(node) != synctex_node_type_hbox) { 4437 return SYNCTEX_STATUS_BAD_ARGUMENT; 4438 } 4439 if ((n = _synctex_data_width_V(node)) < 0) { 4440 max = _synctex_data_h_V(node); 4441 min = max + n; 4442 if (box.min.h < min) { 4443 _synctex_data_set_width_V(node, box.min.h - max); 4444 } else if (box.max.h > max) { 4445 _synctex_data_set_h_V(node, box.max.h); 4446 _synctex_data_set_width_V(node, min - box.max.h); 4447 } 4448 } else { 4449 min = _synctex_data_h_V(node); 4450 max = min + n; 4451 if (box.min.h < min) { 4452 _synctex_data_set_h_V(node, box.min.h); 4453 _synctex_data_set_width_V(node, max - box.min.h); 4454 } else if (box.max.h > max) { 4455 _synctex_data_set_width_V(node, box.max.h - min); 4456 } 4457 } 4458 n = _synctex_data_v_V(node); 4459 min = n - _synctex_data_height_V(node); 4460 max = n + _synctex_data_depth_V(node); 4461 if (box.min.v < min) { 4462 _synctex_data_set_height_V(node, n - box.min.v); 4463 } else if (box.max.v > max) { 4464 _synctex_data_set_depth_V(node, box.max.v - n); 4465 } 4466 return SYNCTEX_STATUS_OK; 4467 } 4468 #ifdef SYNCTEX_NOTHING 4469 #pragma mark - 4470 #pragma mark SPECIAL CHARACTERS 4471 #endif 4472 4473 /* Here are the control characters that strat each line of the synctex output file. 4474 * Their values define the meaning of the line. 4475 */ 4476 #define SYNCTEX_CHAR_BEGIN_SHEET '{' 4477 #define SYNCTEX_CHAR_END_SHEET '}' 4478 #define SYNCTEX_CHAR_BEGIN_FORM '<' 4479 #define SYNCTEX_CHAR_END_FORM '>' 4480 #define SYNCTEX_CHAR_BEGIN_VBOX '[' 4481 #define SYNCTEX_CHAR_END_VBOX ']' 4482 #define SYNCTEX_CHAR_BEGIN_HBOX '(' 4483 #define SYNCTEX_CHAR_END_HBOX ')' 4484 #define SYNCTEX_CHAR_ANCHOR '!' 4485 #define SYNCTEX_CHAR_VOID_VBOX 'v' 4486 #define SYNCTEX_CHAR_VOID_HBOX 'h' 4487 #define SYNCTEX_CHAR_KERN 'k' 4488 #define SYNCTEX_CHAR_GLUE 'g' 4489 #define SYNCTEX_CHAR_RULE 'r' 4490 #define SYNCTEX_CHAR_MATH '$' 4491 #define SYNCTEX_CHAR_FORM_REF 'f' 4492 #define SYNCTEX_CHAR_BOUNDARY 'x' 4493 #define SYNCTEX_CHAR_CHARACTER 'c' 4494 #define SYNCTEX_CHAR_COMMENT '%' 4495 4496 #define SYNCTEX_RETURN(STATUS) return STATUS; 4497 4498 #ifdef SYNCTEX_NOTHING 4499 #pragma mark - 4500 #pragma mark SCANNERS & PARSERS 4501 #endif 4502 4503 #define SYNCTEX_DECODE_FAILED(NODE, WHAT) (_synctex_data_decode_##WHAT(NODE) < SYNCTEX_STATUS_OK) 4504 #define SYNCTEX_DECODE_FAILED_V(NODE, WHAT) (_synctex_data_decode_##WHAT##_v(NODE) < SYNCTEX_STATUS_OK) 4505 4506 #define SYNCTEX_NS_NULL \ 4507 (synctex_ns_s) \ 4508 { \ 4509 NULL, SYNCTEX_STATUS_NOT_OK \ 4510 } 4511 static synctex_ns_s _synctex_parse_new_sheet(synctex_scanner_p scanner) 4512 { 4513 synctex_node_p node; 4514 if ((node = _synctex_new_sheet(scanner))) { 4515 if (SYNCTEX_DECODE_FAILED(node, page)) { 4516 _synctex_error("Bad sheet record."); 4517 } else if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 4518 _synctex_error("Missing end of sheet."); 4519 } else { 4520 /* Now set the owner */ 4521 if (scanner->sheet) { 4522 synctex_node_p last_sheet = scanner->sheet; 4523 synctex_node_p next_sheet = NULL; 4524 while ((next_sheet = __synctex_tree_sibling(last_sheet))) { 4525 last_sheet = next_sheet; 4526 } 4527 __synctex_tree_set_sibling(last_sheet, node); /* sheets have no parent */ 4528 } else { 4529 scanner->sheet = node; 4530 } 4531 return (synctex_ns_s) {node, SYNCTEX_STATUS_OK}; 4532 } 4533 _synctex_free_node(node); 4534 } 4535 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4536 } 4537 /** 4538 * - requirement: scanner != NULL 4539 */ 4540 static synctex_ns_s _synctex_parse_new_form(synctex_scanner_p scanner) 4541 { 4542 synctex_node_p node; 4543 if ((node = _synctex_new_form(scanner))) { 4544 if (SYNCTEX_DECODE_FAILED(node, tag)) { 4545 _synctex_error("Bad sheet record."); 4546 } else if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 4547 _synctex_error("Missing end of form."); 4548 } else { 4549 /* Now set the owner */ 4550 if (scanner->form) { 4551 synctex_node_p last_form = scanner->form; 4552 synctex_node_p next_form = NULL; 4553 while ((next_form = __synctex_tree_sibling(last_form))) { 4554 last_form = next_form; 4555 } 4556 __synctex_tree_set_sibling(last_form, node); 4557 } else { 4558 scanner->form = node; 4559 } 4560 return (synctex_ns_s) {node, SYNCTEX_STATUS_OK}; 4561 } 4562 _synctex_free_node(node); 4563 } 4564 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4565 } 4566 #define SYNCTEX_SHOULD_DECODE_FAILED(NODE, WHAT) (_synctex_data_has_##WHAT(NODE) && (_synctex_data_decode_##WHAT(NODE) < SYNCTEX_STATUS_OK)) 4567 #define SYNCTEX_SHOULD_DECODE_FAILED_V(NODE, WHAT) (_synctex_data_has_##WHAT(NODE) && (_synctex_data_decode_##WHAT##_v(NODE) < SYNCTEX_STATUS_OK)) 4568 4569 static synctex_status_t _synctex_data_decode_tlchvwhd(synctex_node_p node) 4570 { 4571 return SYNCTEX_SHOULD_DECODE_FAILED(node, tag) || SYNCTEX_SHOULD_DECODE_FAILED(node, line) || SYNCTEX_SHOULD_DECODE_FAILED(node, column) || SYNCTEX_SHOULD_DECODE_FAILED(node, h) || SYNCTEX_SHOULD_DECODE_FAILED_V(node, v) || 4572 SYNCTEX_SHOULD_DECODE_FAILED(node, width) || SYNCTEX_SHOULD_DECODE_FAILED(node, height) || SYNCTEX_SHOULD_DECODE_FAILED(node, depth); 4573 } 4574 static synctex_ns_s _synctex_parse_new_vbox(synctex_scanner_p scanner) 4575 { 4576 synctex_node_p node; 4577 if ((node = _synctex_new_vbox(scanner))) { 4578 if (_synctex_data_decode_tlchvwhd(node)) { 4579 _synctex_error("Bad vbox record."); 4580 _synctex_next_line(scanner); 4581 out: 4582 _synctex_free_node(node); 4583 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4584 } 4585 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 4586 _synctex_error("Missing end of vbox."); 4587 goto out; 4588 } 4589 return (synctex_ns_s) {node, SYNCTEX_STATUS_OK}; 4590 } 4591 _synctex_next_line(scanner); 4592 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4593 } 4594 SYNCTEX_INLINE static synctex_node_p __synctex_node_make_friend_tlc(synctex_node_p node); 4595 static synctex_ns_s _synctex_parse_new_hbox(synctex_scanner_p scanner) 4596 { 4597 synctex_node_p node; 4598 if ((node = _synctex_new_hbox(scanner))) { 4599 if (_synctex_data_decode_tlchvwhd(node)) { 4600 _synctex_error("Bad hbox record."); 4601 _synctex_next_line(scanner); 4602 out: 4603 _synctex_free_node(node); 4604 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4605 } 4606 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 4607 _synctex_error("Missing end of hbox."); 4608 goto out; 4609 } 4610 if (_synctex_setup_visible_hbox(node) < SYNCTEX_STATUS_OK) { 4611 _synctex_error("Unexpected error (_synctex_parse_new_hbox)."); 4612 goto out; 4613 } 4614 return (synctex_ns_s) {node, SYNCTEX_STATUS_OK}; 4615 } 4616 _synctex_next_line(scanner); 4617 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4618 } 4619 static synctex_ns_s _synctex_parse_new_void_vbox(synctex_scanner_p scanner) 4620 { 4621 synctex_node_p node; 4622 if ((node = _synctex_new_void_vbox(scanner))) { 4623 if (_synctex_data_decode_tlchvwhd(node)) { 4624 _synctex_error("Bad void vbox record."); 4625 _synctex_next_line(scanner); 4626 out: 4627 _synctex_free_node(node); 4628 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4629 } 4630 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 4631 _synctex_error("Missing end of container."); 4632 goto out; 4633 } 4634 return (synctex_ns_s) {node, SYNCTEX_STATUS_OK}; 4635 } 4636 _synctex_next_line(scanner); 4637 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4638 } 4639 static synctex_ns_s _synctex_parse_new_void_hbox(synctex_scanner_p scanner) 4640 { 4641 synctex_node_p node; 4642 if ((node = _synctex_new_void_hbox(scanner))) { 4643 if (_synctex_data_decode_tlchvwhd(node)) { 4644 _synctex_error("Bad void hbox record."); 4645 _synctex_next_line(scanner); 4646 out: 4647 _synctex_free_node(node); 4648 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4649 } 4650 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 4651 _synctex_error("Missing end of container."); 4652 goto out; 4653 } 4654 return (synctex_ns_s) {node, SYNCTEX_STATUS_OK}; 4655 } 4656 _synctex_next_line(scanner); 4657 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4658 } 4659 static synctex_ns_s _synctex_parse_new_kern(synctex_scanner_p scanner) 4660 { 4661 synctex_node_p node; 4662 if ((node = _synctex_new_kern(scanner))) { 4663 if (_synctex_data_decode_tlchvwhd(node)) { 4664 _synctex_error("Bad kern record."); 4665 _synctex_next_line(scanner); 4666 out: 4667 _synctex_free_node(node); 4668 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4669 } 4670 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 4671 _synctex_error("Missing end of container."); 4672 goto out; 4673 } 4674 return (synctex_ns_s) {node, SYNCTEX_STATUS_OK}; 4675 } 4676 _synctex_next_line(scanner); 4677 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4678 } 4679 static synctex_ns_s _synctex_parse_new_glue(synctex_scanner_p scanner) 4680 { 4681 synctex_node_p node; 4682 if ((node = _synctex_new_glue(scanner))) { 4683 if (_synctex_data_decode_tlchvwhd(node)) { 4684 _synctex_error("Bad glue record."); 4685 _synctex_next_line(scanner); 4686 out: 4687 _synctex_free_node(node); 4688 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4689 } 4690 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 4691 _synctex_error("Missing end of container."); 4692 goto out; 4693 } 4694 return (synctex_ns_s) {node, SYNCTEX_STATUS_OK}; 4695 } 4696 _synctex_next_line(scanner); 4697 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4698 } 4699 static synctex_ns_s _synctex_parse_new_rule(synctex_scanner_p scanner) 4700 { 4701 synctex_node_p node; 4702 if ((node = _synctex_new_rule(scanner))) { 4703 if (_synctex_data_decode_tlchvwhd(node)) { 4704 _synctex_error("Bad rule record."); 4705 _synctex_next_line(scanner); 4706 out: 4707 _synctex_free_node(node); 4708 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4709 } 4710 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 4711 _synctex_error("Missing end of container."); 4712 goto out; 4713 } 4714 return (synctex_ns_s) {node, SYNCTEX_STATUS_OK}; 4715 } 4716 _synctex_next_line(scanner); 4717 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4718 } 4719 static synctex_ns_s _synctex_parse_new_math(synctex_scanner_p scanner) 4720 { 4721 synctex_node_p node; 4722 if ((node = _synctex_new_math(scanner))) { 4723 if (_synctex_data_decode_tlchvwhd(node)) { 4724 _synctex_error("Bad math record."); 4725 _synctex_next_line(scanner); 4726 out: 4727 _synctex_free_node(node); 4728 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4729 } 4730 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 4731 _synctex_error("Missing end of container."); 4732 goto out; 4733 } 4734 return (synctex_ns_s) {node, SYNCTEX_STATUS_OK}; 4735 } 4736 _synctex_next_line(scanner); 4737 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4738 } 4739 static synctex_ns_s _synctex_parse_new_boundary(synctex_scanner_p scanner) 4740 { 4741 synctex_node_p node; 4742 if ((node = _synctex_new_boundary(scanner))) { 4743 if (_synctex_data_decode_tlchvwhd(node)) { 4744 _synctex_error("Bad boundary record."); 4745 _synctex_next_line(scanner); 4746 out: 4747 _synctex_free_node(node); 4748 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4749 } 4750 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 4751 _synctex_error("Missing end of container."); 4752 goto out; 4753 } 4754 return (synctex_ns_s) {node, SYNCTEX_STATUS_OK}; 4755 } 4756 _synctex_next_line(scanner); 4757 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4758 } 4759 SYNCTEX_INLINE static synctex_ns_s _synctex_parse_new_ref(synctex_scanner_p scanner) 4760 { 4761 synctex_node_p node; 4762 if ((node = _synctex_new_ref(scanner))) { 4763 if (SYNCTEX_DECODE_FAILED(node, tag) || SYNCTEX_DECODE_FAILED(node, h) || SYNCTEX_DECODE_FAILED_V(node, v)) { 4764 _synctex_error("Bad form ref record."); 4765 _synctex_next_line(scanner); 4766 out: 4767 _synctex_free_node(node); 4768 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4769 } 4770 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 4771 _synctex_error("Missing end of container."); 4772 goto out; 4773 } 4774 return (synctex_ns_s) {node, SYNCTEX_STATUS_OK}; 4775 } 4776 _synctex_next_line(scanner); 4777 return (synctex_ns_s) {NULL, SYNCTEX_STATUS_ERROR}; 4778 } 4779 #undef SYNCTEX_DECODE_FAILED 4780 #undef SYNCTEX_DECODE_FAILED_V 4781 4782 SYNCTEX_INLINE static synctex_point_s _synctex_data_point(synctex_node_p node); 4783 SYNCTEX_INLINE static synctex_point_s _synctex_data_point_V(synctex_node_p node); 4784 SYNCTEX_INLINE static synctex_point_s _synctex_data_set_point(synctex_node_p node, synctex_point_s point); 4785 SYNCTEX_INLINE static synctex_box_s _synctex_data_box(synctex_node_p node); 4786 SYNCTEX_INLINE static synctex_box_s _synctex_data_xob(synctex_node_p node); 4787 SYNCTEX_INLINE static synctex_box_s _synctex_data_box_V(synctex_node_p node); 4788 4789 SYNCTEX_INLINE static synctex_node_p _synctex_input_register_line(synctex_node_p input, synctex_node_p node) 4790 { 4791 if (node && _synctex_data_tag(input) != _synctex_data_tag(node)) { 4792 input = synctex_scanner_input_with_tag(node->class->scanner, _synctex_data_tag(node)); 4793 } 4794 if (_synctex_data_line(node) > _synctex_data_line(input)) { 4795 _synctex_data_set_line(input, _synctex_data_line(node)); 4796 } 4797 return input; 4798 } 4799 /** 4800 * Scan sheets, forms and input records. 4801 * - parameter scanner: owning scanner 4802 * - returns: status 4803 */ 4804 static synctex_status_t __synctex_parse_sfi(synctex_scanner_p scanner) 4805 { 4806 synctex_status_t status = SYNCTEX_STATUS_OK; 4807 synctex_zs_s zs = {0, 0}; 4808 synctex_ns_s input = SYNCTEX_NS_NULL; 4809 synctex_node_p sheet = NULL; 4810 synctex_node_p form = NULL; 4811 synctex_node_p parent = NULL; 4812 synctex_node_p child = NULL; 4813 synctex_ns_s ns = SYNCTEX_NS_NULL; 4814 int form_depth = 0; 4815 int ignored_form_depth = 0; 4816 synctex_bool_t try_input = synctex_YES; 4817 #ifdef SYNCTEX_NOTHING 4818 #pragma mark MAIN LOOP 4819 #endif 4820 main_loop: 4821 status = SYNCTEX_STATUS_OK; 4822 sheet = form = parent = child = NULL; 4823 #define SYNCTEX_START_SCAN(WHAT) (*SYNCTEX_CUR == SYNCTEX_CHAR_##WHAT) 4824 if (SYNCTEX_CUR < SYNCTEX_END) { 4825 if (SYNCTEX_START_SCAN(BEGIN_FORM)) { 4826 #ifdef SYNCTEX_NOTHING 4827 #pragma mark + SCAN FORM 4828 #endif 4829 scan_form: 4830 ns = _synctex_parse_new_form(scanner); 4831 if (ns.status == SYNCTEX_STATUS_OK) { 4832 ++form_depth; 4833 if (_synctex_tree_parent(form)) { 4834 /* This form is already being parsed */ 4835 ++ignored_form_depth; 4836 goto ignore_loop; 4837 } 4838 _synctex_tree_set_parent(ns.node, form); 4839 form = ns.node; 4840 parent = form; 4841 child = NULL; 4842 goto content_loop; 4843 } 4844 if (form || sheet) { 4845 goto content_loop; 4846 } 4847 try_input = synctex_YES; 4848 goto main_loop; 4849 } else if (SYNCTEX_START_SCAN(BEGIN_SHEET)) { 4850 #ifdef SYNCTEX_NOTHING 4851 #pragma mark + SCAN SHEET 4852 #endif 4853 try_input = synctex_YES; 4854 ns = _synctex_parse_new_sheet(scanner); 4855 if (ns.status == SYNCTEX_STATUS_OK) { 4856 sheet = ns.node; 4857 parent = sheet; 4858 goto content_loop; 4859 } 4860 goto main_loop; 4861 } else if (SYNCTEX_START_SCAN(ANCHOR)) { 4862 #ifdef SYNCTEX_NOTHING 4863 #pragma mark + SCAN ANCHOR 4864 #endif 4865 scan_anchor: 4866 ++SYNCTEX_CUR; 4867 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 4868 _synctex_error("Missing anchor."); 4869 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); 4870 } 4871 if (form || sheet) { 4872 goto content_loop; 4873 } 4874 try_input = synctex_YES; 4875 goto main_loop; 4876 } else if (SYNCTEX_START_SCAN(ANCHOR)) { 4877 #ifdef SYNCTEX_NOTHING 4878 #pragma mark + SCAN COMMENT 4879 #endif 4880 ++SYNCTEX_CUR; 4881 _synctex_next_line(scanner); 4882 try_input = synctex_YES; 4883 goto main_loop; 4884 } else if (try_input) { 4885 #ifdef SYNCTEX_NOTHING 4886 #pragma mark + SCAN INPUT 4887 #endif 4888 try_input = synctex_NO; 4889 do { 4890 input = __synctex_parse_new_input(scanner); 4891 } while (input.status == SYNCTEX_STATUS_OK); 4892 goto main_loop; 4893 } 4894 status = _synctex_match_string(scanner, "Postamble:"); 4895 if (status == SYNCTEX_STATUS_OK) { 4896 scanner->flags.postamble = 1; 4897 return status; 4898 } 4899 status = _synctex_next_line(scanner); 4900 if (status < SYNCTEX_STATUS_OK) { 4901 return status; 4902 } 4903 } 4904 /* At least 1 more character */ 4905 zs = _synctex_buffer_get_available_size(scanner, 1); 4906 if (zs.size == 0) { 4907 _synctex_error("Uncomplete synctex file, postamble missing."); 4908 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); 4909 } 4910 goto main_loop; 4911 /* Unreachable. */ 4912 #ifdef SYNCTEX_NOTHING 4913 #pragma mark IGNORE LOOP 4914 #endif 4915 ignore_loop: 4916 ns = SYNCTEX_NS_NULL; 4917 if (SYNCTEX_CUR < SYNCTEX_END) { 4918 if (SYNCTEX_START_SCAN(BEGIN_FORM)) { 4919 ++ignored_form_depth; 4920 } else if (SYNCTEX_START_SCAN(END_FORM)) { 4921 --ignored_form_depth; 4922 } 4923 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 4924 _synctex_error("Uncomplete container."); 4925 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); 4926 } 4927 } else { 4928 zs = _synctex_buffer_get_available_size(scanner, 1); 4929 if (zs.size == 0) { 4930 _synctex_error("Uncomplete synctex file, postamble missing."); 4931 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); 4932 } 4933 } 4934 if (ignored_form_depth) { 4935 goto ignore_loop; 4936 } else { 4937 goto content_loop; 4938 } 4939 4940 #ifdef SYNCTEX_NOTHING 4941 #pragma mark CONTENT LOOP 4942 #endif 4943 content_loop: 4944 /* Either in a form, a sheet or a box. 4945 * - in a sheet, "{" is not possible, only boxes and "}" at top level. 4946 * - in a form, "{" is not possible, only boxes, "<" and ">" at top level. 4947 * - in a box, the unique possibility is '<', '[', '(' or ">". 4948 * We still keep the '(' for a sheet, because that dos not cost too much. 4949 * We must also consider void boxes as children. 4950 */ 4951 /* forms are everywhere */ 4952 ns = SYNCTEX_NS_NULL; 4953 #ifdef SYNCTEX_VERBOSE 4954 synctex_scanner_set_display_switcher(scanner, -1); 4955 printf("NEW CONTENT LOOP\n"); 4956 #if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500 4957 synctex_node_display(sheet); 4958 #endif 4959 #endif 4960 if (SYNCTEX_CUR < SYNCTEX_END) { 4961 if (SYNCTEX_START_SCAN(BEGIN_FORM)) { 4962 goto scan_form; 4963 } else if (SYNCTEX_START_SCAN(BEGIN_VBOX)) { 4964 #ifdef SYNCTEX_NOTHING 4965 #pragma mark + SCAN VBOX 4966 #endif 4967 ns = _synctex_parse_new_vbox(scanner); 4968 if (ns.status == SYNCTEX_STATUS_OK) { 4969 if (child) { 4970 _synctex_node_set_sibling(child, ns.node); 4971 } else { 4972 _synctex_node_set_child(parent, ns.node); 4973 } 4974 parent = ns.node; 4975 child = _synctex_tree_last(parent); 4976 #ifdef SYNCTEX_VERBOSE 4977 synctex_node_log(parent); 4978 #endif 4979 input.node = _synctex_input_register_line(input.node, parent); 4980 goto content_loop; 4981 } 4982 } else if (SYNCTEX_START_SCAN(END_VBOX)) { 4983 if (synctex_node_type(parent) == synctex_node_type_vbox) { 4984 #ifdef SYNCTEX_NOTHING 4985 #pragma mark + SCAN XOBV 4986 #endif 4987 ++SYNCTEX_CUR; 4988 if (NULL == _synctex_tree_child(parent) && !form) { 4989 /* only void v boxes are friends */ 4990 _synctex_node_make_friend_tlc(parent); 4991 } 4992 child = parent; 4993 parent = _synctex_tree_parent(child); 4994 #ifdef SYNCTEX_VERBOSE 4995 synctex_node_log(child); 4996 #endif 4997 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 4998 _synctex_error("Uncomplete container."); 4999 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); 5000 } 5001 goto content_loop; 5002 } 5003 } else if (SYNCTEX_START_SCAN(BEGIN_HBOX)) { 5004 #ifdef SYNCTEX_NOTHING 5005 #pragma mark + SCAN HBOX 5006 #endif 5007 #if defined(SYNCTEX_USE_CHARINDEX) 5008 synctex_charindex_t char_index = (synctex_charindex_t)(scanner->reader->charindex_offset + SYNCTEX_CUR - SYNCTEX_START); 5009 synctex_lineindex_t line_index = scanner->reader->line_number; 5010 #endif 5011 ns = _synctex_parse_new_hbox(scanner); 5012 if (ns.status == SYNCTEX_STATUS_OK) { 5013 if (child) { 5014 _synctex_node_set_sibling(child, ns.node); 5015 } else { 5016 _synctex_node_set_child(parent, ns.node); 5017 } 5018 parent = ns.node; 5019 /* add a box boundary node at the start */ 5020 if ((child = _synctex_new_box_bdry(scanner))) { 5021 #if defined(SYNCTEX_USE_CHARINDEX) 5022 child->line_index = line_index; 5023 child->char_index = char_index; 5024 #endif 5025 _synctex_node_set_child(parent, child); 5026 _synctex_data_set_tag(child, _synctex_data_tag(parent)); 5027 _synctex_data_set_line(child, _synctex_data_line(parent)); 5028 _synctex_data_set_h(child, _synctex_data_h(parent)); 5029 _synctex_data_set_v(child, _synctex_data_v(parent)); 5030 if (!form) { 5031 __synctex_node_make_friend_tlc(child); 5032 } 5033 } else { 5034 _synctex_error("Can't create box bdry record."); 5035 } 5036 #ifdef SYNCTEX_VERBOSE 5037 synctex_node_log(parent); 5038 #endif 5039 input.node = _synctex_input_register_line(input.node, parent); 5040 goto content_loop; 5041 } 5042 } else if (SYNCTEX_START_SCAN(END_HBOX)) { 5043 if (synctex_node_type(parent) == synctex_node_type_hbox) { 5044 #ifdef SYNCTEX_NOTHING 5045 #pragma mark + SCAN XOBH 5046 #endif 5047 ++SYNCTEX_CUR; 5048 { 5049 /* setting the next horizontal box at the end ensures 5050 * that a child is recorded before any of its ancestors. 5051 */ 5052 if (form == NULL /* && sheet != NULL*/) { 5053 _synctex_tree_set_next_hbox(parent, _synctex_tree_next_hbox(sheet)); 5054 _synctex_tree_set_next_hbox(sheet, parent); 5055 } 5056 /* Update the mean line number */ 5057 synctex_node_p node = _synctex_tree_child(parent); 5058 synctex_node_p sibling = NULL; 5059 /* Ignore the first node (a box_bdry) */ 5060 if (node && (node = __synctex_tree_sibling(node))) { 5061 unsigned int node_weight = 0; 5062 unsigned int cumulated_line_numbers = 0; 5063 do { 5064 if (synctex_node_type(node) == synctex_node_type_hbox) { 5065 if (_synctex_data_weight(node)) { 5066 node_weight += _synctex_data_weight(node); 5067 cumulated_line_numbers += _synctex_data_mean_line(node) * _synctex_data_weight(node); 5068 } else { 5069 ++node_weight; 5070 cumulated_line_numbers += _synctex_data_mean_line(node); 5071 } 5072 } else { 5073 ++node_weight; 5074 cumulated_line_numbers += synctex_node_line(node); 5075 } 5076 } while ((node = __synctex_tree_sibling(node))); 5077 _synctex_data_set_mean_line(parent, (cumulated_line_numbers + node_weight / 2) / node_weight); 5078 _synctex_data_set_weight(parent, node_weight); 5079 } else { 5080 _synctex_data_set_mean_line(parent, _synctex_data_line(parent)); 5081 _synctex_data_set_weight(parent, 1); 5082 } 5083 if ((sibling = _synctex_new_box_bdry(scanner))) { 5084 #if defined(SYNCTEX_USE_CHARINDEX) 5085 sibling->line_index = child->line_index; 5086 sibling->char_index = child->char_index; 5087 #endif 5088 _synctex_node_set_sibling(child, sibling); 5089 { 5090 synctex_node_p N = child; 5091 while (synctex_node_type(N) == synctex_node_type_ref) { 5092 N = _synctex_tree_arg_sibling(N); 5093 } 5094 _synctex_data_set_tag(sibling, _synctex_data_tag(N)); 5095 _synctex_data_set_line(sibling, _synctex_data_line(N)); 5096 } 5097 _synctex_data_set_h(sibling, _synctex_data_h_V(parent) + _synctex_data_width_V(parent)); 5098 _synctex_data_set_v(sibling, _synctex_data_v_V(parent)); 5099 child = sibling; 5100 } else { 5101 _synctex_error("Can't create box bdry record."); 5102 } 5103 sibling = _synctex_tree_child(parent); 5104 _synctex_data_set_point(sibling, _synctex_data_point_V(parent)); 5105 child = parent; 5106 parent = _synctex_tree_parent(child); 5107 _synctex_make_hbox_contain_box(parent, _synctex_data_box_V(child)); 5108 #ifdef SYNCTEX_VERBOSE 5109 synctex_node_log(child); 5110 #endif 5111 } 5112 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 5113 _synctex_error("Uncomplete container."); 5114 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); 5115 } 5116 goto content_loop; 5117 } 5118 } else if (SYNCTEX_START_SCAN(VOID_VBOX)) { 5119 #ifdef SYNCTEX_NOTHING 5120 #pragma mark + SCAN VOID VBOX 5121 #endif 5122 ns = _synctex_parse_new_void_vbox(scanner); 5123 if (ns.status == SYNCTEX_STATUS_OK) { 5124 if (child) { 5125 _synctex_node_set_sibling(child, ns.node); 5126 } else { 5127 _synctex_node_set_child(parent, ns.node); 5128 } 5129 child = ns.node; 5130 #ifdef SYNCTEX_VERBOSE 5131 synctex_node_log(child); 5132 #endif 5133 input.node = _synctex_input_register_line(input.node, child); 5134 goto content_loop; 5135 } 5136 } else if (SYNCTEX_START_SCAN(VOID_HBOX)) { 5137 #ifdef SYNCTEX_NOTHING 5138 #pragma mark + SCAN VOID HBOX 5139 #endif 5140 ns = _synctex_parse_new_void_hbox(scanner); 5141 if (ns.status == SYNCTEX_STATUS_OK) { 5142 if (_synctex_data_width(ns.node) < 0) { 5143 printf("Negative width\n"); 5144 } 5145 if (child) { 5146 _synctex_node_set_sibling(child, ns.node); 5147 } else { 5148 _synctex_node_set_child(parent, ns.node); 5149 } 5150 child = ns.node; 5151 _synctex_make_hbox_contain_box(parent, _synctex_data_box(child)); 5152 #ifdef SYNCTEX_VERBOSE 5153 synctex_node_log(child); 5154 #endif 5155 input.node = _synctex_input_register_line(input.node, child); 5156 goto content_loop; 5157 } 5158 } else if (SYNCTEX_START_SCAN(KERN)) { 5159 #ifdef SYNCTEX_NOTHING 5160 #pragma mark + SCAN KERN 5161 #endif 5162 ns = _synctex_parse_new_kern(scanner); 5163 /* continue_scan: */ 5164 if (ns.status == SYNCTEX_STATUS_OK) { 5165 if (child) { 5166 _synctex_node_set_sibling(child, ns.node); 5167 } else { 5168 _synctex_node_set_child(parent, ns.node); 5169 } 5170 child = ns.node; 5171 if (!form) { 5172 __synctex_node_make_friend_tlc(child); 5173 } 5174 _synctex_make_hbox_contain_box(parent, _synctex_data_xob(child)); 5175 #ifdef SYNCTEX_VERBOSE 5176 synctex_node_log(child); 5177 #endif 5178 input.node = _synctex_input_register_line(input.node, child); 5179 goto content_loop; 5180 } 5181 } else if (SYNCTEX_START_SCAN(GLUE)) { 5182 #ifdef SYNCTEX_NOTHING 5183 #pragma mark + SCAN GLUE 5184 #endif 5185 ns = _synctex_parse_new_glue(scanner); 5186 if (ns.status == SYNCTEX_STATUS_OK) { 5187 if (child) { 5188 _synctex_node_set_sibling(child, ns.node); 5189 } else { 5190 _synctex_node_set_child(parent, ns.node); 5191 } 5192 child = ns.node; 5193 if (!form) { 5194 __synctex_node_make_friend_tlc(child); 5195 } 5196 _synctex_make_hbox_contain_point(parent, _synctex_data_point(child)); 5197 #ifdef SYNCTEX_VERBOSE 5198 synctex_node_log(child); 5199 #endif 5200 input.node = _synctex_input_register_line(input.node, child); 5201 goto content_loop; 5202 } 5203 } else if (SYNCTEX_START_SCAN(RULE)) { 5204 #ifdef SYNCTEX_NOTHING 5205 #pragma mark + SCAN RULE 5206 #endif 5207 ns = _synctex_parse_new_rule(scanner); 5208 if (ns.status == SYNCTEX_STATUS_OK) { 5209 if (child) { 5210 _synctex_node_set_sibling(child, ns.node); 5211 } else { 5212 _synctex_node_set_child(parent, ns.node); 5213 } 5214 child = ns.node; 5215 if (!form) { 5216 __synctex_node_make_friend_tlc(child); 5217 } 5218 /* Rules are sometimes far too big 5219 _synctex_make_hbox_contain_box(parent,_synctex_data_box(child)); 5220 */ 5221 #ifdef SYNCTEX_VERBOSE 5222 synctex_node_log(child); 5223 #endif 5224 input.node = _synctex_input_register_line(input.node, child); 5225 goto content_loop; 5226 } 5227 } else if (SYNCTEX_START_SCAN(MATH)) { 5228 #ifdef SYNCTEX_NOTHING 5229 #pragma mark + SCAN MATH 5230 #endif 5231 ns = _synctex_parse_new_math(scanner); 5232 if (ns.status == SYNCTEX_STATUS_OK) { 5233 if (child) { 5234 _synctex_node_set_sibling(child, ns.node); 5235 } else { 5236 _synctex_node_set_child(parent, ns.node); 5237 } 5238 child = ns.node; 5239 if (!form) { 5240 __synctex_node_make_friend_tlc(child); 5241 } 5242 _synctex_make_hbox_contain_point(parent, _synctex_data_point(child)); 5243 #ifdef SYNCTEX_VERBOSE 5244 synctex_node_log(child); 5245 #endif 5246 input.node = _synctex_input_register_line(input.node, child); 5247 goto content_loop; 5248 } 5249 } else if (SYNCTEX_START_SCAN(FORM_REF)) { 5250 #ifdef SYNCTEX_NOTHING 5251 #pragma mark + SCAN FORM REF 5252 #endif 5253 #if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500 5254 synctex_node_display(parent); 5255 synctex_node_display(child); 5256 #endif 5257 ns = _synctex_parse_new_ref(scanner); 5258 if (ns.status == SYNCTEX_STATUS_OK) { 5259 if (child) { 5260 _synctex_node_set_sibling(child, ns.node); 5261 } else { 5262 _synctex_node_set_child(parent, ns.node); 5263 } 5264 child = ns.node; 5265 if (form) { 5266 if (scanner->ref_in_form) { 5267 synctex_tree_set_friend(child, scanner->ref_in_form); 5268 } 5269 scanner->ref_in_form = child; 5270 } else { 5271 if (scanner->ref_in_sheet) { 5272 synctex_tree_set_friend(child, scanner->ref_in_sheet); 5273 } 5274 scanner->ref_in_sheet = child; 5275 } 5276 #ifdef SYNCTEX_VERBOSE 5277 synctex_node_log(child); 5278 #endif 5279 goto content_loop; 5280 } 5281 } else if (SYNCTEX_START_SCAN(BOUNDARY)) { 5282 #ifdef SYNCTEX_NOTHING 5283 #pragma mark + SCAN BOUNDARY 5284 #endif 5285 ns = _synctex_parse_new_boundary(scanner); 5286 if (ns.status == SYNCTEX_STATUS_OK) { 5287 if (child) { 5288 _synctex_node_set_sibling(child, ns.node); 5289 } else { 5290 _synctex_node_set_child(parent, ns.node); 5291 } 5292 child = ns.node; 5293 if (!form) { 5294 __synctex_node_make_friend_tlc(child); 5295 } 5296 _synctex_make_hbox_contain_point(parent, _synctex_data_point(child)); 5297 #ifdef SYNCTEX_VERBOSE 5298 synctex_node_log(child); 5299 #endif 5300 input.node = _synctex_input_register_line(input.node, child); 5301 goto content_loop; 5302 } 5303 } else if (SYNCTEX_START_SCAN(CHARACTER)) { 5304 #ifdef SYNCTEX_NOTHING 5305 #pragma mark + SCAN CHARACTER 5306 #endif 5307 ++SYNCTEX_CUR; 5308 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 5309 _synctex_error("Missing end of container."); 5310 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); 5311 } 5312 goto content_loop; 5313 } else if (SYNCTEX_START_SCAN(ANCHOR)) { 5314 #ifdef SYNCTEX_NOTHING 5315 #pragma mark + SCAN ANCHOR 5316 #endif 5317 goto scan_anchor; 5318 } else if (SYNCTEX_START_SCAN(END_SHEET)) { 5319 if (sheet && parent == sheet) { 5320 #ifdef SYNCTEX_NOTHING 5321 #pragma mark + SCAN TEEHS 5322 #endif 5323 ++SYNCTEX_CUR; 5324 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 5325 _synctex_error("Missing anchor."); 5326 } 5327 parent = sheet = NULL; 5328 goto main_loop; 5329 } 5330 } else if (SYNCTEX_START_SCAN(END_FORM)) { 5331 if (parent == form && form_depth > 0) { 5332 #ifdef SYNCTEX_NOTHING 5333 #pragma mark + SCAN MROF 5334 #endif 5335 ++SYNCTEX_CUR; 5336 --form_depth; 5337 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK && (form_depth || sheet)) { 5338 _synctex_error("Missing end of container."); 5339 return SYNCTEX_STATUS_ERROR; 5340 } 5341 if ((parent = _synctex_tree_parent(form))) { 5342 _synctex_tree_reset_parent(form); 5343 child = form; 5344 form = parent; 5345 goto content_loop; 5346 } else if (sheet) { 5347 form = NULL; 5348 parent = sheet; 5349 child = synctex_node_last_sibling(child); 5350 goto content_loop; 5351 } 5352 goto main_loop; 5353 } 5354 } 5355 _synctex_error("Ignored record <%.20s...>(line %i)\n", SYNCTEX_CUR, scanner->reader->line_number + 1); 5356 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 5357 _synctex_error("Missing end of sheet/form."); 5358 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); 5359 } 5360 goto content_loop; 5361 } 5362 zs = _synctex_buffer_get_available_size(scanner, 1); 5363 if (zs.size == 0) { 5364 _synctex_error("Uncomplete synctex file, postamble missing."); 5365 SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); 5366 } 5367 goto content_loop; 5368 } 5369 /** 5370 * Replace ref in its tree hierarchy by a single box 5371 * proxy to the contents of the associated form. 5372 * - argument ref: a ref node with no friend 5373 * - return the proxy created. 5374 * - note: Does nothing if ref is not owned. 5375 * - note: On return, ref will have no parent nor sibling. 5376 * The caller is responsible for releasing ref. 5377 * - note: this is where root proxies are created. 5378 * - note: the target of the root proxy is the content 5379 * of a form. 5380 */ 5381 SYNCTEX_INLINE static synctex_ns_s __synctex_replace_ref(synctex_node_p ref) 5382 { 5383 synctex_ns_s ns = {NULL, SYNCTEX_STATUS_OK}; 5384 synctex_node_p parent; 5385 if ((parent = _synctex_tree_parent(ref))) { 5386 synctex_node_p sibling = __synctex_tree_reset_sibling(ref); 5387 synctex_node_p arg_sibling = synctex_node_arg_sibling(ref); 5388 /* arg_sibling != NULL because the child of a box 5389 * is always a box boundary, not a ref. */ 5390 synctex_node_p target = synctex_form_content(ref->class->scanner, _synctex_data_tag(ref)); 5391 /* The target is a single node (box) 5392 * with children and no siblings. */ 5393 if ((ns.node = __synctex_new_proxy_from_ref_to(ref, target))) { 5394 /* Insert this proxy instead of ref. */ 5395 _synctex_node_set_sibling(arg_sibling, ns.node); 5396 /* Then append the original sibling of ref. */ 5397 _synctex_node_set_sibling(ns.node, sibling); 5398 #if defined(SYNCTEX_USE_CHARINDEX) 5399 if (synctex_node_type(sibling) == synctex_node_type_box_bdry) { 5400 /* The sibling is the last box boundary 5401 * which may have a less accurate information */ 5402 sibling->char_index = arg_sibling->char_index; 5403 sibling->line_index = arg_sibling->line_index; 5404 } 5405 #endif 5406 #if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500 5407 printf("! Ref replacement:\n"); 5408 synctex_node_log(ref); 5409 synctex_node_display(synctex_node_sibling(ref)); 5410 #endif 5411 } else /* simply remove ref */ { 5412 _synctex_tree_set_sibling(arg_sibling, sibling); 5413 } 5414 __synctex_tree_reset_parent(ref); 5415 } else { 5416 _synctex_error( 5417 "! Missing parent in __synctex_replace_ref. " 5418 "Please report."); 5419 ns.status = SYNCTEX_STATUS_BAD_ARGUMENT; 5420 } 5421 return ns; 5422 } 5423 /** 5424 * - argument ref: is the starting point of a linked list 5425 * of refs. The link is made through the friend field. 5426 * - returns: the status and the list of all the proxies 5427 * created. The link is made through the friend field. 5428 * - note: All refs are freed 5429 */ 5430 SYNCTEX_INLINE static synctex_ns_s _synctex_post_process_ref(synctex_node_p ref) 5431 { 5432 synctex_ns_s ns = {NULL, SYNCTEX_STATUS_OK}; 5433 while (ref) { 5434 synctex_node_p next_ref = _synctex_tree_reset_friend(ref); 5435 synctex_ns_s sub_ns = __synctex_replace_ref(ref); 5436 if (sub_ns.status < ns.status) { 5437 ns.status = sub_ns.status; 5438 } else { 5439 /* Insert all the created proxies in the list 5440 * sub_ns.node is the last friend, 5441 */ 5442 synctex_tree_set_friend(sub_ns.node, ns.node); 5443 ns.node = sub_ns.node; 5444 } 5445 synctex_node_free(ref); 5446 ref = next_ref; 5447 } 5448 return ns; 5449 } 5450 typedef synctex_node_p (*synctex_processor_f)(synctex_node_p node); 5451 /** 5452 * Apply the processor f to the tree hierarchy rooted at proxy. 5453 * proxy has replaced a form ref, no children yet. 5454 * As a side effect all the hierarchy of nodes will be created. 5455 */ 5456 SYNCTEX_INLINE static synctex_status_t _synctex_post_process_proxy(synctex_node_p proxy, synctex_processor_f f) 5457 { 5458 while (proxy) { 5459 synctex_node_p next_proxy = _synctex_tree_friend(proxy); 5460 synctex_node_p halt = __synctex_tree_sibling(proxy); 5461 /* if proxy is the last sibling, halt is NULL. 5462 * Find what should be a next node, 5463 * without creating new nodes. */ 5464 if (!halt) { 5465 synctex_node_p parent = _synctex_tree_parent(proxy); 5466 halt = __synctex_tree_sibling(parent); 5467 while (!halt && parent) { 5468 parent = _synctex_tree_parent(parent); 5469 halt = __synctex_tree_sibling(parent); 5470 } 5471 } 5472 do { 5473 #if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500 5474 printf("POST PROCESSING %s\n", _synctex_node_abstract(proxy)); 5475 { 5476 int i, j = 0; 5477 for (i = 0; i < proxy->class->scanner->number_of_lists; ++i) { 5478 synctex_node_p N = proxy->class->scanner->lists_of_friends[i]; 5479 do { 5480 if (N == proxy) { 5481 ++j; 5482 printf("%s", _synctex_node_abstract(N)); 5483 } 5484 } while ((N = _synctex_tree_friend(N))); 5485 } 5486 if (j) { 5487 printf("\nBeforehand %i match\n", j); 5488 } 5489 } 5490 #endif 5491 f(proxy); 5492 #if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500 5493 { 5494 int i, j = 0; 5495 for (i = 0; i < proxy->class->scanner->number_of_lists; ++i) { 5496 synctex_node_p N = proxy->class->scanner->lists_of_friends[i]; 5497 do { 5498 if (N == proxy) { 5499 ++j; 5500 printf("%s", _synctex_node_abstract(N)); 5501 } 5502 } while ((N = _synctex_tree_friend(N))); 5503 } 5504 if (j) { 5505 printf("\n%i match\n", j); 5506 } 5507 } 5508 #endif 5509 /* Side effect: create the hierarchy on the fly */ 5510 proxy = synctex_node_next(proxy); /* Change is here */ 5511 #if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500 5512 if (proxy) { 5513 int i, j = 0; 5514 for (i = 0; i < proxy->class->scanner->number_of_lists; ++i) { 5515 synctex_node_p N = proxy->class->scanner->lists_of_friends[i]; 5516 do { 5517 if (N == proxy) { 5518 ++j; 5519 printf("%s", _synctex_node_abstract(N)); 5520 } 5521 } while ((N = _synctex_tree_friend(N))); 5522 } 5523 if (j) { 5524 printf("\nnext %i match\n", j); 5525 } 5526 } 5527 #endif 5528 } while (proxy && proxy != halt); 5529 proxy = next_proxy; 5530 } 5531 return SYNCTEX_STATUS_OK; 5532 } 5533 /** 5534 * Replace all the form refs by root box proxies. 5535 * Create the node hierarchy and update the friends. 5536 * On entry, the refs are collected as a friend list 5537 * in either a form or a sheet 5538 * - parameter: the owning scanner 5539 */ 5540 SYNCTEX_INLINE static synctex_status_t _synctex_post_process(synctex_scanner_p scanner) 5541 { 5542 synctex_status_t status = SYNCTEX_STATUS_OK; 5543 synctex_ns_s ns = {NULL, SYNCTEX_STATUS_NOT_OK}; 5544 #if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500 5545 printf("! entering _synctex_post_process.\n"); 5546 synctex_node_display(scanner->sheet); 5547 synctex_node_display(scanner->form); 5548 #endif 5549 /* replace form refs inside forms by box proxies */ 5550 ns = _synctex_post_process_ref(scanner->ref_in_form); 5551 scanner->ref_in_form = NULL; /* it was just released */ 5552 if (ns.status < status) { 5553 status = ns.status; 5554 } 5555 #if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500 5556 printf("! ref replaced in form _synctex_post_process.\n"); 5557 synctex_node_display(scanner->form); 5558 #endif 5559 /* Create all the form proxy nodes on the fly. 5560 * ns.node is the root of the list of 5561 * newly created proxies. 5562 * There might be a problem with cascading proxies. 5563 * In order to be properly managed, the data must 5564 * be organized in the right way. 5565 * The inserted form must be defined before 5566 * the inserting one. *TeX will take care of that. */ 5567 ns.status = _synctex_post_process_proxy(ns.node, &_synctex_tree_reset_friend); 5568 if (ns.status < status) { 5569 status = ns.status; 5570 } 5571 /* replace form refs inside sheets by box proxies */ 5572 ns = _synctex_post_process_ref(scanner->ref_in_sheet); 5573 if (ns.status < status) { 5574 status = ns.status; 5575 } 5576 scanner->ref_in_sheet = NULL; 5577 #if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500 5578 printf("! ref replaced in sheet _synctex_post_process.\n"); 5579 synctex_node_display(scanner->sheet); 5580 #endif 5581 5582 #if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 10000 5583 { 5584 int i; 5585 for (i = 0; i < scanner->number_of_lists; ++i) { 5586 synctex_node_p P = scanner->lists_of_friends[i]; 5587 int j = 0; 5588 while (P) { 5589 ++j; 5590 synctex_node_log(P); 5591 P = _synctex_tree_friend(P); 5592 } 5593 if (j) { 5594 printf("friends %i -> # %i\n", i, j); 5595 } 5596 } 5597 } 5598 #endif 5599 ns.status = _synctex_post_process_proxy(ns.node, &__synctex_proxy_make_friend_and_next_hbox); 5600 if (ns.status < status) { 5601 status = ns.status; 5602 } 5603 #if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500 5604 printf("! exiting _synctex_post_process.\n"); 5605 synctex_node_display(scanner->sheet); 5606 synctex_node_display(scanner->form); 5607 printf("! display all.\n"); 5608 synctex_node_display(scanner->sheet); 5609 synctex_node_display(scanner->form); 5610 #endif 5611 return status; 5612 } 5613 /* Used when parsing the synctex file 5614 */ 5615 static synctex_status_t _synctex_scan_content(synctex_scanner_p scanner) 5616 { 5617 scanner->reader->lastv = -1; 5618 synctex_status_t status = 0; 5619 if (NULL == scanner) { 5620 return SYNCTEX_STATUS_BAD_ARGUMENT; 5621 } 5622 /* Find where this section starts */ 5623 content_not_found: 5624 status = _synctex_match_string(scanner, "Content:"); 5625 if (status < SYNCTEX_STATUS_EOF) { 5626 return status; 5627 } 5628 if (_synctex_next_line(scanner) < SYNCTEX_STATUS_OK) { 5629 _synctex_error("Uncomplete Content."); 5630 return SYNCTEX_STATUS_ERROR; 5631 } 5632 if (status == SYNCTEX_STATUS_NOT_OK) { 5633 goto content_not_found; 5634 } 5635 status = __synctex_parse_sfi(scanner); 5636 if (status == SYNCTEX_STATUS_OK) { 5637 status = _synctex_post_process(scanner); 5638 } 5639 return status; 5640 } 5641 synctex_scanner_p synctex_scanner_new() 5642 { 5643 synctex_scanner_p scanner = (synctex_scanner_p)_synctex_malloc(sizeof(synctex_scanner_s)); 5644 if (scanner) { 5645 if (!(scanner->reader = _synctex_malloc(sizeof(synctex_reader_s)))) { 5646 _synctex_free(scanner); 5647 return NULL; 5648 } 5649 #ifdef SYNCTEX_NOTHING 5650 #pragma mark - 5651 #endif 5652 #define DEFINE_synctex_scanner_class(NAME) \ 5653 scanner->class[synctex_node_type_##NAME] = synctex_class_##NAME; \ 5654 (scanner->class[synctex_node_type_##NAME]).scanner = scanner 5655 DEFINE_synctex_scanner_class(input); 5656 DEFINE_synctex_scanner_class(sheet); 5657 DEFINE_synctex_scanner_class(form); 5658 DEFINE_synctex_scanner_class(hbox); 5659 DEFINE_synctex_scanner_class(void_hbox); 5660 DEFINE_synctex_scanner_class(vbox); 5661 DEFINE_synctex_scanner_class(void_vbox); 5662 DEFINE_synctex_scanner_class(kern); 5663 DEFINE_synctex_scanner_class(glue); 5664 DEFINE_synctex_scanner_class(rule); 5665 DEFINE_synctex_scanner_class(math); 5666 DEFINE_synctex_scanner_class(boundary); 5667 DEFINE_synctex_scanner_class(box_bdry); 5668 DEFINE_synctex_scanner_class(ref); 5669 DEFINE_synctex_scanner_class(proxy_hbox); 5670 DEFINE_synctex_scanner_class(proxy_vbox); 5671 DEFINE_synctex_scanner_class(proxy); 5672 DEFINE_synctex_scanner_class(proxy_last); 5673 DEFINE_synctex_scanner_class(handle); 5674 /* set up the lists of friends */ 5675 scanner->number_of_lists = 1024; 5676 scanner->lists_of_friends = (synctex_node_r)_synctex_malloc(scanner->number_of_lists * sizeof(synctex_node_p)); 5677 if (NULL == scanner->lists_of_friends) { 5678 synctex_scanner_free(scanner); 5679 _synctex_error("malloc:2"); 5680 return NULL; 5681 } 5682 scanner->display_switcher = 100; 5683 scanner->display_prompt = (char *)_synctex_display_prompt + strlen(_synctex_display_prompt) - 1; 5684 } 5685 return scanner; 5686 } 5687 /* Where the synctex scanner is created. */ 5688 synctex_scanner_p synctex_scanner_new_with_output_file(const char *output, const char *build_directory, int parse) 5689 { 5690 synctex_scanner_p scanner = synctex_scanner_new(); 5691 if (NULL == scanner) { 5692 _synctex_error("malloc problem"); 5693 return NULL; 5694 } 5695 if ((scanner->reader = synctex_reader_init_with_output_file(scanner->reader, output, build_directory))) { 5696 return parse ? synctex_scanner_parse(scanner) : scanner; 5697 } 5698 #if defined(SYNCTEX_DEBUG) 5699 _synctex_error("No file?"); 5700 #endif 5701 synctex_scanner_free(scanner); 5702 return NULL; 5703 } 5704 5705 /* The scanner destructor 5706 */ 5707 int synctex_scanner_free(synctex_scanner_p scanner) 5708 { 5709 int node_count = 0; 5710 if (scanner) { 5711 if (scanner->reader && SYNCTEX_FILE) { 5712 gzclose(SYNCTEX_FILE); 5713 SYNCTEX_FILE = NULL; 5714 } 5715 synctex_node_free(scanner->sheet); 5716 synctex_node_free(scanner->form); 5717 synctex_node_free(scanner->input); 5718 synctex_reader_free(scanner->reader); 5719 SYNCTEX_SCANNER_FREE_HANDLE(scanner); 5720 synctex_iterator_free(scanner->iterator); 5721 free(scanner->output_fmt); 5722 free(scanner->lists_of_friends); 5723 #if defined SYNCTEX_USE_NODE_COUNT && SYNCTEX_USE_NODE_COUNT > 0 5724 node_count = scanner->node_count; 5725 #endif 5726 free(scanner); 5727 } 5728 return node_count; 5729 } 5730 5731 /* Where the synctex scanner parses the contents of the file. */ 5732 synctex_scanner_p synctex_scanner_parse(synctex_scanner_p scanner) 5733 { 5734 synctex_status_t status = 0; 5735 if (!scanner || scanner->flags.has_parsed) { 5736 return scanner; 5737 } 5738 scanner->flags.has_parsed = 1; 5739 scanner->pre_magnification = 1000; 5740 scanner->pre_unit = 8192; 5741 scanner->pre_x_offset = scanner->pre_y_offset = 578; 5742 /* initialize the offset with a fake unprobable value, 5743 * If there is a post scriptum section, this value will be overridden by the real life value */ 5744 scanner->x_offset = scanner->y_offset = 6.027e23f; 5745 scanner->reader->line_number = 1; 5746 5747 /* TODO: cleanup 5748 * In some (all?) cases SYNCTEX_START is already initialized 5749 * in synctex_reader_init_with_output_file(). Much of the 5750 * following code seems like a duplicate and is perhaps a 5751 * candidate for deletion. To be on the safe side though, we 5752 * keep it for now and just free() any prior malloc() if 5753 * existing. */ 5754 _synctex_free(SYNCTEX_START); 5755 5756 SYNCTEX_START = (char *)malloc(SYNCTEX_BUFFER_SIZE + 1); /* one more character for null termination */ 5757 if (NULL == SYNCTEX_START) { 5758 _synctex_error("! malloc error in synctex_scanner_parse."); 5759 bailey: 5760 #ifdef SYNCTEX_DEBUG 5761 return scanner; 5762 #else 5763 synctex_scanner_free(scanner); 5764 return NULL; 5765 #endif 5766 } 5767 synctex_scanner_set_display_switcher(scanner, 1000); 5768 SYNCTEX_END = SYNCTEX_START + SYNCTEX_BUFFER_SIZE; 5769 /* SYNCTEX_END always points to a null terminating character. 5770 * Maybe there is another null terminating character between SYNCTEX_CUR and SYNCTEX_END-1. 5771 * At least, we are sure that SYNCTEX_CUR points to a string covering a valid part of the memory. */ 5772 *SYNCTEX_END = '\0'; 5773 SYNCTEX_CUR = SYNCTEX_END; 5774 #if defined(SYNCTEX_USE_CHARINDEX) 5775 scanner->reader->charindex_offset = -SYNCTEX_BUFFER_SIZE; 5776 #endif 5777 status = _synctex_scan_preamble(scanner); 5778 if (status < SYNCTEX_STATUS_OK) { 5779 _synctex_error("Bad preamble\n"); 5780 goto bailey; 5781 } 5782 status = _synctex_scan_content(scanner); 5783 if (status < SYNCTEX_STATUS_OK) { 5784 _synctex_error("Bad content\n"); 5785 goto bailey; 5786 } 5787 status = _synctex_scan_postamble(scanner); 5788 if (status < SYNCTEX_STATUS_OK) { 5789 _synctex_error("Bad postamble. Ignored\n"); 5790 } 5791 #if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500 5792 synctex_scanner_set_display_switcher(scanner, 100); 5793 synctex_node_display(scanner->sheet); 5794 synctex_node_display(scanner->form); 5795 #endif 5796 synctex_scanner_set_display_switcher(scanner, 1000); 5797 /* Everything is finished, free the buffer, close the file */ 5798 free((void *)SYNCTEX_START); 5799 SYNCTEX_START = SYNCTEX_CUR = SYNCTEX_END = NULL; 5800 gzclose(SYNCTEX_FILE); 5801 SYNCTEX_FILE = NULL; 5802 /* Final tuning: set the default values for various parameters */ 5803 /* 1 pre_unit = (scanner->pre_unit)/65536 pt = (scanner->pre_unit)/65781.76 bp 5804 * 1 pt = 65536 sp */ 5805 if (scanner->pre_unit <= 0) { 5806 scanner->pre_unit = 8192; 5807 } 5808 if (scanner->pre_magnification <= 0) { 5809 scanner->pre_magnification = 1000; 5810 } 5811 if (scanner->unit <= 0) { 5812 /* no post magnification */ 5813 scanner->unit = scanner->pre_unit / 65781.76; /* 65781.76 or 65536.0*/ 5814 } else { 5815 /* post magnification */ 5816 scanner->unit *= scanner->pre_unit / 65781.76; 5817 } 5818 scanner->unit *= scanner->pre_magnification / 1000.0; 5819 if (scanner->x_offset > 6e23) { 5820 /* no post offset */ 5821 scanner->x_offset = scanner->pre_x_offset * (scanner->pre_unit / 65781.76); 5822 scanner->y_offset = scanner->pre_y_offset * (scanner->pre_unit / 65781.76); 5823 } else { 5824 /* post offset */ 5825 scanner->x_offset /= 65781.76f; 5826 scanner->y_offset /= 65781.76f; 5827 } 5828 return scanner; 5829 #undef SYNCTEX_FILE 5830 } 5831 5832 /* Scanner accessors. 5833 */ 5834 int synctex_scanner_pre_x_offset(synctex_scanner_p scanner) 5835 { 5836 return scanner ? scanner->pre_x_offset : 0; 5837 } 5838 int synctex_scanner_pre_y_offset(synctex_scanner_p scanner) 5839 { 5840 return scanner ? scanner->pre_y_offset : 0; 5841 } 5842 int synctex_scanner_x_offset(synctex_scanner_p scanner) 5843 { 5844 return scanner ? scanner->x_offset : 0; 5845 } 5846 int synctex_scanner_y_offset(synctex_scanner_p scanner) 5847 { 5848 return scanner ? scanner->y_offset : 0; 5849 } 5850 float synctex_scanner_magnification(synctex_scanner_p scanner) 5851 { 5852 return scanner ? scanner->unit : 1; 5853 } 5854 void synctex_scanner_display(synctex_scanner_p scanner) 5855 { 5856 if (NULL == scanner) { 5857 return; 5858 } 5859 printf("The scanner:\noutput:%s\noutput_fmt:%s\nversion:%i\n", scanner->reader->output, scanner->output_fmt, scanner->version); 5860 printf("pre_unit:%i\nx_offset:%i\ny_offset:%i\n", scanner->pre_unit, scanner->pre_x_offset, scanner->pre_y_offset); 5861 printf("count:%i\npost_magnification:%f\npost_x_offset:%f\npost_y_offset:%f\n", scanner->count, scanner->unit, scanner->x_offset, scanner->y_offset); 5862 printf("The input:\n"); 5863 synctex_node_display(scanner->input); 5864 if (scanner->count < 1000) { 5865 printf("The sheets:\n"); 5866 synctex_node_display(scanner->sheet); 5867 printf("The friends:\n"); 5868 if (scanner->lists_of_friends) { 5869 int i = scanner->number_of_lists; 5870 synctex_node_p node; 5871 while (i--) { 5872 printf("Friend index:%i\n", i); 5873 node = (scanner->lists_of_friends)[i]; 5874 while (node) { 5875 printf("%s:%i,%i\n", synctex_node_isa(node), _synctex_data_tag(node), _synctex_data_line(node)); 5876 node = _synctex_tree_friend(node); 5877 } 5878 } 5879 } 5880 } else { 5881 printf("SyncTeX Warning: Too many objects\n"); 5882 } 5883 } 5884 /* Public */ 5885 const char *synctex_scanner_get_name(synctex_scanner_p scanner, int tag) 5886 { 5887 synctex_node_p input = NULL; 5888 if (NULL == scanner) { 5889 return NULL; 5890 } 5891 if ((input = scanner->input)) { 5892 ; 5893 do { 5894 if (tag == _synctex_data_tag(input)) { 5895 return (_synctex_data_name(input)); 5896 } 5897 } while ((input = __synctex_tree_sibling(input))); 5898 } 5899 return NULL; 5900 } 5901 const char *synctex_node_get_name(synctex_node_p node) 5902 { 5903 if (node) { 5904 return synctex_scanner_get_name(node->class->scanner, _synctex_data_tag(node)); 5905 } 5906 return NULL; 5907 } 5908 5909 static int _synctex_scanner_get_tag(synctex_scanner_p scanner, const char *name); 5910 static int _synctex_scanner_get_tag(synctex_scanner_p scanner, const char *name) 5911 { 5912 synctex_node_p input = NULL; 5913 if (NULL == scanner) { 5914 return 0; 5915 } 5916 if ((input = scanner->input)) { 5917 do { 5918 if (_synctex_is_equivalent_file_name(name, (_synctex_data_name(input)))) { 5919 return _synctex_data_tag(input); 5920 } 5921 } while ((input = __synctex_tree_sibling(input))); 5922 } 5923 /* 2011 version */ 5924 name = _synctex_base_name(name); 5925 if ((input = scanner->input)) { 5926 do { 5927 if (_synctex_is_equivalent_file_name(name, _synctex_base_name(_synctex_data_name(input)))) { 5928 synctex_node_p other_input = input; 5929 while ((other_input = __synctex_tree_sibling(other_input))) { 5930 if (_synctex_is_equivalent_file_name(name, _synctex_base_name(_synctex_data_name(other_input))) && 5931 (strlen(_synctex_data_name(input)) != strlen(_synctex_data_name(other_input)) || strncmp(_synctex_data_name(other_input), _synctex_data_name(input), strlen(_synctex_data_name(input))))) { 5932 /* There is a second possible candidate */ 5933 return 0; 5934 } 5935 } 5936 return _synctex_data_tag(input); 5937 } 5938 } while ((input = __synctex_tree_sibling(input))); 5939 } 5940 return 0; 5941 } 5942 5943 int synctex_scanner_get_tag(synctex_scanner_p scanner, const char *name) 5944 { 5945 size_t char_index = strlen(name); 5946 if ((scanner = synctex_scanner_parse(scanner)) && (0 < char_index)) { 5947 /* the name is not void */ 5948 char_index -= 1; 5949 if (!SYNCTEX_IS_PATH_SEPARATOR(name[char_index])) { 5950 /* the last character of name is not a path separator */ 5951 int result = _synctex_scanner_get_tag(scanner, name); 5952 if (result) { 5953 return result; 5954 } else { 5955 /* the given name was not the one known by TeX 5956 * try a name relative to the enclosing directory of the scanner->output file */ 5957 const char *relative = name; 5958 const char *ptr = scanner->reader->output; 5959 while ((strlen(relative) > 0) && (strlen(ptr) > 0) && (*relative == *ptr)) { 5960 relative += 1; 5961 ptr += 1; 5962 } 5963 /* Find the last path separator before relative */ 5964 while (relative > name) { 5965 if (SYNCTEX_IS_PATH_SEPARATOR(*(relative - 1))) { 5966 break; 5967 } 5968 relative -= 1; 5969 } 5970 if ((relative > name) && (result = _synctex_scanner_get_tag(scanner, relative))) { 5971 return result; 5972 } 5973 if (SYNCTEX_IS_PATH_SEPARATOR(name[0])) { 5974 /* No tag found for the given absolute name, 5975 * Try each relative path starting from the shortest one */ 5976 while (0 < char_index) { 5977 char_index -= 1; 5978 if (SYNCTEX_IS_PATH_SEPARATOR(name[char_index]) && (result = _synctex_scanner_get_tag(scanner, name + char_index + 1))) { 5979 return result; 5980 } 5981 } 5982 } 5983 } 5984 return result; 5985 } 5986 } 5987 return 0; 5988 } 5989 synctex_node_p synctex_scanner_input(synctex_scanner_p scanner) 5990 { 5991 return scanner ? scanner->input : NULL; 5992 } 5993 synctex_node_p synctex_scanner_input_with_tag(synctex_scanner_p scanner, int tag) 5994 { 5995 synctex_node_p input = scanner ? scanner->input : NULL; 5996 while (_synctex_data_tag(input) != tag) { 5997 if ((input = __synctex_tree_sibling(input))) { 5998 continue; 5999 } 6000 break; 6001 } 6002 return input; 6003 } 6004 const char *synctex_scanner_get_output_fmt(synctex_scanner_p scanner) 6005 { 6006 return NULL != scanner && scanner->output_fmt ? scanner->output_fmt : ""; 6007 } 6008 const char *synctex_scanner_get_output(synctex_scanner_p scanner) 6009 { 6010 return NULL != scanner && scanner->reader->output ? scanner->reader->output : ""; 6011 } 6012 const char *synctex_scanner_get_synctex(synctex_scanner_p scanner) 6013 { 6014 return NULL != scanner && scanner->reader->synctex ? scanner->reader->synctex : ""; 6015 } 6016 #ifdef SYNCTEX_NOTHING 6017 #pragma mark - 6018 #pragma mark Public node attributes 6019 #endif 6020 6021 #define SYNCTEX_DEFINE_NODE_HVWHD(WHAT) \ 6022 int synctex_node_##WHAT(synctex_node_p node) \ 6023 { \ 6024 return (node && node->class->inspector->WHAT) ? node->class->inspector->WHAT(node) : 0; \ 6025 } 6026 #define SYNCTEX_DEFINE_PROXY_HV(WHAT) \ 6027 static int _synctex_proxy_##WHAT(synctex_proxy_p proxy) \ 6028 { \ 6029 synctex_node_p target = _synctex_tree_target(proxy); \ 6030 if (target) { \ 6031 return _synctex_data_##WHAT(proxy) + synctex_node_##WHAT(target); \ 6032 } else { \ 6033 return proxy ? _synctex_data_##WHAT(proxy) : 0; \ 6034 } \ 6035 } 6036 #define SYNCTEX_DEFINE_PROXY_TLCWVD(WHAT) \ 6037 static int _synctex_proxy_##WHAT(synctex_proxy_p proxy) \ 6038 { \ 6039 synctex_node_p target = _synctex_tree_target(proxy); \ 6040 return target ? synctex_node_##WHAT(target) : 0; \ 6041 } 6042 6043 /** 6044 * The horizontal location of the node. 6045 * Idem for v, width, height and depth. 6046 * - parameter node: a node with geometrical information. 6047 * - returns: an integer. 6048 * - requires: every proxy node has a target. 6049 * - note: recursive call if the parameter has a proxy. 6050 * - author: JL 6051 */ 6052 SYNCTEX_DEFINE_NODE_HVWHD(h) 6053 SYNCTEX_DEFINE_NODE_HVWHD(v) 6054 SYNCTEX_DEFINE_NODE_HVWHD(width) 6055 SYNCTEX_DEFINE_NODE_HVWHD(height) 6056 SYNCTEX_DEFINE_NODE_HVWHD(depth) 6057 SYNCTEX_DEFINE_PROXY_TLCWVD(tag) 6058 SYNCTEX_DEFINE_PROXY_TLCWVD(line) 6059 SYNCTEX_DEFINE_PROXY_TLCWVD(column) 6060 SYNCTEX_DEFINE_PROXY_HV(h) 6061 SYNCTEX_DEFINE_PROXY_HV(v) 6062 SYNCTEX_DEFINE_PROXY_TLCWVD(width) 6063 SYNCTEX_DEFINE_PROXY_TLCWVD(height) 6064 SYNCTEX_DEFINE_PROXY_TLCWVD(depth) 6065 6066 /** 6067 * Whether the argument is a box, 6068 * either vertical or horizontal, 6069 * either void or not, 6070 * or a proxy to such a box. 6071 * - parameter NODE: of type synctex_node_p 6072 * - returns: yorn 6073 */ 6074 6075 SYNCTEX_INLINE static synctex_bool_t _synctex_node_is_box(synctex_node_p node) 6076 { 6077 return node && 6078 (node->class->type == synctex_node_type_hbox || node->class->type == synctex_node_type_void_hbox || node->class->type == synctex_node_type_vbox || node->class->type == synctex_node_type_void_vbox || 6079 _synctex_node_is_box(_synctex_tree_target(node))); 6080 } 6081 6082 /** 6083 * Whether the argument is a handle. 6084 * Handles are similar to proxies because they have a target. 6085 * They are used for query results. 6086 * - parameter NODE: of type synctex_node_p 6087 * - returns: yorn 6088 */ 6089 6090 SYNCTEX_INLINE static synctex_bool_t _synctex_node_is_handle(synctex_node_p node) 6091 { 6092 return node && (node->class->type == synctex_node_type_handle); 6093 } 6094 6095 /** 6096 * Resolves handle indirection. 6097 * - parameter node: of type synctex_node_p 6098 * - returns: node if it is not a handle, 6099 * its target otherwise. 6100 */ 6101 6102 SYNCTEX_INLINE static synctex_node_p _synctex_node_or_handle_target(synctex_node_p node) 6103 { 6104 return _synctex_node_is_handle(node) ? _synctex_tree_target(node) : node; 6105 } 6106 6107 /** 6108 * Whether the argument is an hbox. 6109 * - parameter NODE: of type synctex_node_p 6110 * - returns: yorn 6111 */ 6112 6113 SYNCTEX_INLINE static synctex_bool_t _synctex_node_is_hbox(synctex_node_p node) 6114 { 6115 return node && (node->class->type == synctex_node_type_hbox || node->class->type == synctex_node_type_void_hbox || _synctex_node_is_hbox(_synctex_tree_target(node))); 6116 } 6117 6118 /** 6119 * The horizontal location of the first box enclosing node. 6120 * - parameter node: a node with geometrical information. 6121 * - returns: an integer. 6122 * - author: JL 6123 */ 6124 int synctex_node_box_h(synctex_node_p node) 6125 { 6126 if (_synctex_node_is_box(node) || (node = _synctex_tree_parent(node))) { 6127 return synctex_node_h(node); 6128 } 6129 return 0; 6130 } 6131 /** 6132 * The vertical location of the first box enclosing node. 6133 * - parameter node: a node with geometrical information. 6134 * - returns: an integer. 6135 * - author: JL 6136 */ 6137 int synctex_node_box_v(synctex_node_p node) 6138 { 6139 if (_synctex_node_is_box(node) || (node = _synctex_tree_parent(node))) { 6140 return synctex_node_v(node); 6141 } 6142 return 0; 6143 } 6144 /** 6145 * The width of the first box enclosing node. 6146 * - parameter node: a node with geometrical information. 6147 * - returns: an integer. 6148 * - author: JL 6149 */ 6150 int synctex_node_box_width(synctex_node_p node) 6151 { 6152 if (_synctex_node_is_box(node) || (node = _synctex_tree_parent(node))) { 6153 return synctex_node_width(node); 6154 } 6155 return 0; 6156 } 6157 /** 6158 * The height of the first box enclosing node. 6159 * - parameter node: a node with geometrical information. 6160 * - returns: an integer. 6161 * - author: JL 6162 */ 6163 int synctex_node_box_height(synctex_node_p node) 6164 { 6165 if (_synctex_node_is_box(node) || (node = _synctex_tree_parent(node))) { 6166 return synctex_node_height(node); 6167 } 6168 return 0; 6169 } 6170 /** 6171 * The depth of the first box enclosing node. 6172 * - parameter node: a node with geometrical information. 6173 * - returns: an integer. 6174 * - author: JL 6175 */ 6176 int synctex_node_box_depth(synctex_node_p node) 6177 { 6178 if (_synctex_node_is_box(node) || (node = _synctex_tree_parent(node))) { 6179 return synctex_node_depth(node); 6180 } 6181 return 0; 6182 } 6183 /** 6184 * The horizontal location of an hbox, corrected with contents. 6185 * - parameter node: an hbox node. 6186 * - returns: an integer, 0 if node is not an hbox or an hbox proxy. 6187 * - note: recursive call when node is an hbox proxy. 6188 * - author: JL 6189 */ 6190 int synctex_node_hbox_h(synctex_node_p node) 6191 { 6192 switch (synctex_node_type(node)) { 6193 case synctex_node_type_hbox: 6194 return _synctex_data_h_V(node); 6195 case synctex_node_type_proxy_hbox: 6196 return _synctex_data_h(node) + synctex_node_hbox_h(_synctex_tree_target(node)); 6197 default: 6198 return 0; 6199 } 6200 } 6201 /** 6202 * The vertical location of an hbox, corrected with contents. 6203 * - parameter node: an hbox node. 6204 * - returns: an integer, 0 if node is not an hbox or an hbox proxy. 6205 * - note: recursive call when node is an hbox proxy. 6206 * - author: JL 6207 */ 6208 int synctex_node_hbox_v(synctex_node_p node) 6209 { 6210 switch (synctex_node_type(node)) { 6211 case synctex_node_type_hbox: 6212 return _synctex_data_v_V(node); 6213 case synctex_node_type_proxy_hbox: 6214 return _synctex_data_v(node) + synctex_node_hbox_v(_synctex_tree_target(node)); 6215 default: 6216 return 0; 6217 } 6218 } 6219 /** 6220 * The width of an hbox, corrected with contents. 6221 * - parameter node: an hbox node, 0 if node is not an hbox or an hbox proxy. 6222 * - returns: an integer. 6223 * - author: JL 6224 */ 6225 int synctex_node_hbox_width(synctex_node_p node) 6226 { 6227 synctex_node_p target = _synctex_tree_target(node); 6228 if (target) { 6229 node = target; 6230 } 6231 return synctex_node_type(node) == synctex_node_type_hbox ? _synctex_data_width_V(node) : 0; 6232 } 6233 /** 6234 * The height of an hbox, corrected with contents. 6235 * - parameter node: an hbox node. 6236 * - returns: an integer, 0 if node is not an hbox or an hbox proxy. 6237 * - author: JL 6238 */ 6239 int synctex_node_hbox_height(synctex_node_p node) 6240 { 6241 synctex_node_p target = _synctex_tree_target(node); 6242 if (target) { 6243 node = target; 6244 } 6245 return synctex_node_type(node) == synctex_node_type_hbox ? _synctex_data_height_V(node) : 0; 6246 } 6247 /** 6248 * The depth of an hbox, corrected with contents. 6249 * - parameter node: an hbox node. 6250 * - returns: an integer, 0 if node is not an hbox or an hbox proxy. 6251 * - note: recursive call when node is an hbox proxy. 6252 * - author: JL 6253 */ 6254 int synctex_node_hbox_depth(synctex_node_p node) 6255 { 6256 synctex_node_p target = _synctex_tree_target(node); 6257 if (target) { 6258 node = target; 6259 } 6260 return synctex_node_type(node) == synctex_node_type_hbox ? _synctex_data_depth_V(node) : 0; 6261 } 6262 #ifdef SYNCTEX_NOTHING 6263 #pragma mark - 6264 #pragma mark Public node visible attributes 6265 #endif 6266 6267 #define SYNCTEX_VISIBLE_SIZE(node, s) (s) * node->class->scanner->unit 6268 #define SYNCTEX_VISIBLE_DISTANCE_h(node, d) ((d)*node->class->scanner->unit + node->class->scanner->x_offset) 6269 #define SYNCTEX_VISIBLE_DISTANCE_v(node, d) ((d)*node->class->scanner->unit + node->class->scanner->y_offset) 6270 static float __synctex_node_visible_h(synctex_node_p node) 6271 { 6272 return SYNCTEX_VISIBLE_DISTANCE_h(node, synctex_node_h(node)); 6273 } 6274 static float __synctex_node_visible_v(synctex_node_p node) 6275 { 6276 return SYNCTEX_VISIBLE_DISTANCE_v(node, synctex_node_v(node)); 6277 } 6278 static float __synctex_node_visible_width(synctex_node_p node) 6279 { 6280 return SYNCTEX_VISIBLE_SIZE(node, synctex_node_width(node)); 6281 } 6282 static float __synctex_node_visible_height(synctex_node_p node) 6283 { 6284 return SYNCTEX_VISIBLE_SIZE(node, synctex_node_height(node)); 6285 } 6286 static float __synctex_node_visible_depth(synctex_node_p node) 6287 { 6288 return SYNCTEX_VISIBLE_SIZE(node, synctex_node_depth(node)); 6289 } 6290 static float __synctex_proxy_visible_h(synctex_node_p node) 6291 { 6292 return SYNCTEX_VISIBLE_DISTANCE_h(node, synctex_node_h(node)); 6293 } 6294 static float __synctex_proxy_visible_v(synctex_node_p node) 6295 { 6296 return SYNCTEX_VISIBLE_DISTANCE_v(node, synctex_node_v(node)); 6297 } 6298 static float __synctex_proxy_visible_width(synctex_node_p node) 6299 { 6300 synctex_node_p target = _synctex_tree_target(node); 6301 return __synctex_node_visible_width(target); 6302 } 6303 static float __synctex_proxy_visible_height(synctex_node_p node) 6304 { 6305 synctex_node_p target = _synctex_tree_target(node); 6306 return __synctex_node_visible_height(target); 6307 } 6308 static float __synctex_proxy_visible_depth(synctex_node_p node) 6309 { 6310 synctex_node_p target = _synctex_tree_target(node); 6311 return __synctex_node_visible_depth(target); 6312 } 6313 static float __synctex_kern_visible_h(synctex_noxy_p noxy) 6314 { 6315 int h = _synctex_data_h(noxy); 6316 int width = _synctex_data_width(noxy); 6317 return SYNCTEX_VISIBLE_DISTANCE_h(noxy, width > 0 ? h - width : h); 6318 } 6319 static float __synctex_kern_visible_width(synctex_noxy_p noxy) 6320 { 6321 int width = _synctex_data_width(noxy); 6322 return SYNCTEX_VISIBLE_SIZE(noxy, width > 0 ? width : -width); 6323 } 6324 static float __synctex_rule_visible_h(synctex_noxy_p noxy) 6325 { 6326 int h = _synctex_data_h(noxy); 6327 int width = _synctex_data_width(noxy); 6328 return SYNCTEX_VISIBLE_DISTANCE_h(noxy, width > 0 ? h : h - width); 6329 } 6330 static float __synctex_rule_visible_width(synctex_noxy_p noxy) 6331 { 6332 int width = _synctex_data_width(noxy); 6333 return SYNCTEX_VISIBLE_SIZE(noxy, width > 0 ? width : -width); 6334 } 6335 static float __synctex_rule_visible_v(synctex_noxy_p noxy) 6336 { 6337 return __synctex_node_visible_v(noxy); 6338 } 6339 static float __synctex_rule_visible_height(synctex_noxy_p noxy) 6340 { 6341 return __synctex_node_visible_height(noxy); 6342 } 6343 static float __synctex_rule_visible_depth(synctex_noxy_p noxy) 6344 { 6345 return __synctex_node_visible_depth(noxy); 6346 } 6347 6348 /** 6349 * The horizontal location of node, in page coordinates. 6350 * - parameter node: a node. 6351 * - returns: a float. 6352 * - author: JL 6353 */ 6354 float synctex_node_visible_h(synctex_node_p node) 6355 { 6356 return node ? node->class->vispector->h(node) : 0; 6357 } 6358 /** 6359 * The vertical location of node, in page coordinates. 6360 * - parameter node: a node. 6361 * - returns: a float. 6362 * - author: JL 6363 */ 6364 float synctex_node_visible_v(synctex_node_p node) 6365 { 6366 return node ? node->class->vispector->v(node) : 0; 6367 } 6368 /** 6369 * The width of node, in page coordinates. 6370 * - parameter node: a node. 6371 * - returns: a float. 6372 * - author: JL 6373 */ 6374 float synctex_node_visible_width(synctex_node_p node) 6375 { 6376 return node ? node->class->vispector->width(node) : 0; 6377 } 6378 /** 6379 * The height of node, in page coordinates. 6380 * - parameter node: a node. 6381 * - returns: a float. 6382 * - author: JL 6383 */ 6384 float synctex_node_visible_height(synctex_node_p node) 6385 { 6386 return node ? node->class->vispector->height(node) : 0; 6387 } 6388 /** 6389 * The depth of node, in page coordinates. 6390 * - parameter node: a node. 6391 * - returns: a float. 6392 * - author: JL 6393 */ 6394 float synctex_node_visible_depth(synctex_node_p node) 6395 { 6396 return node ? node->class->vispector->depth(node) : 0; 6397 } 6398 6399 /** 6400 * The V variant of geometrical information. 6401 * - parameter node: a node. 6402 * - returns: an integer. 6403 * - author: JL 6404 */ 6405 #define SYNCTEX_DEFINE_V(WHAT) \ 6406 SYNCTEX_INLINE static int _synctex_node_##WHAT##_V(synctex_node_p node) \ 6407 { \ 6408 synctex_node_p target = _synctex_tree_target(node); \ 6409 if (target) { \ 6410 return _synctex_data_##WHAT(node) + _synctex_node_##WHAT##_V(target); \ 6411 } else if (_synctex_data_has_##WHAT##_V(node)) { \ 6412 return _synctex_data_##WHAT##_V(node); \ 6413 } else { \ 6414 return _synctex_data_##WHAT(node); \ 6415 } \ 6416 } 6417 SYNCTEX_DEFINE_V(h) 6418 SYNCTEX_DEFINE_V(v) 6419 SYNCTEX_DEFINE_V(width) 6420 SYNCTEX_DEFINE_V(height) 6421 SYNCTEX_DEFINE_V(depth) 6422 6423 SYNCTEX_INLINE static synctex_point_s _synctex_data_point(synctex_node_p node) 6424 { 6425 return (synctex_point_s) {synctex_node_h(node), synctex_node_v(node)}; 6426 } 6427 SYNCTEX_INLINE static synctex_point_s _synctex_data_point_V(synctex_node_p node) 6428 { 6429 return (synctex_point_s) {_synctex_node_h_V(node), _synctex_node_v_V(node)}; 6430 } 6431 SYNCTEX_INLINE static synctex_point_s _synctex_data_set_point(synctex_node_p node, synctex_point_s point) 6432 { 6433 synctex_point_s old = _synctex_data_point(node); 6434 _synctex_data_set_h(node, point.h); 6435 _synctex_data_set_v(node, point.v); 6436 return old; 6437 } 6438 SYNCTEX_INLINE static synctex_box_s _synctex_data_box(synctex_node_p node) 6439 { 6440 synctex_box_s box = {{0, 0}, {0, 0}}; 6441 int n; 6442 n = synctex_node_width(node); 6443 if (n < 0) { 6444 box.max.h = synctex_node_h(node); 6445 box.min.h = box.max.h + n; 6446 } else { 6447 box.min.h = synctex_node_h(node); 6448 box.max.h = box.min.h + n; 6449 } 6450 n = synctex_node_v(node); 6451 box.min.v = n - synctex_node_height(node); 6452 box.max.v = n + synctex_node_depth(node); 6453 return box; 6454 } 6455 SYNCTEX_INLINE static synctex_box_s _synctex_data_xob(synctex_node_p node) 6456 { 6457 synctex_box_s box = {{0, 0}, {0, 0}}; 6458 int n; 6459 n = synctex_node_width(node); 6460 if (n > 0) { 6461 box.max.h = synctex_node_h(node); 6462 box.min.h = box.max.h - n; 6463 } else { 6464 box.min.h = synctex_node_h(node); 6465 box.max.h = box.min.h - n; 6466 } 6467 n = synctex_node_v(node); 6468 box.min.v = n - synctex_node_height(node); 6469 box.max.v = n + synctex_node_depth(node); 6470 return box; 6471 } 6472 SYNCTEX_INLINE static synctex_box_s _synctex_data_box_V(synctex_node_p node) 6473 { 6474 synctex_box_s box = {{0, 0}, {0, 0}}; 6475 int n; 6476 n = _synctex_node_width_V(node); 6477 if (n < 0) { 6478 box.max.h = _synctex_node_h_V(node); 6479 box.min.h = box.max.h + n; 6480 } else { 6481 box.min.h = _synctex_node_h_V(node); 6482 box.max.h = box.min.h + n; 6483 } 6484 n = _synctex_node_v_V(node); 6485 box.min.v = n - _synctex_node_height_V(node); 6486 box.max.v = n + _synctex_node_depth_V(node); 6487 return box; 6488 } 6489 6490 /** 6491 * The higher box node in the parent hierarchy which 6492 * mean line number is the one of node ±1. 6493 * This enclosing box is computed as follows 6494 * 1) get the first hbox in the parent linked list 6495 * starting at node. 6496 * If there is none, simply return the parent of node. 6497 * 2) compute the mean line number 6498 * 3) scans up the tree for the higher hbox with 6499 * the same mean line number, ±1 eventually 6500 * - parameter node: a node. 6501 * - returns: a (proxy to a) box node. 6502 * - author: JL 6503 */ 6504 static synctex_node_p _synctex_node_box_visible(synctex_node_p node) 6505 { 6506 if ((node = _synctex_node_or_handle_target(node))) { 6507 int mean = 0; 6508 int bound = 1500000 / (node->class->scanner->pre_magnification / 1000); 6509 synctex_node_p parent = NULL; 6510 /* get the first enclosing parent 6511 * then get the highest enclosing parent with the same mean line ±1 */ 6512 node = _synctex_node_or_handle_target(node); 6513 if (!_synctex_node_is_box(node)) { 6514 if ((parent = _synctex_tree_parent(node))) { 6515 node = parent; 6516 } else if ((node = _synctex_tree_target(node))) { 6517 if (!_synctex_node_is_box(node)) { 6518 if ((parent = _synctex_tree_parent(node))) { 6519 node = parent; 6520 } else { 6521 return NULL; 6522 } 6523 } 6524 } 6525 } 6526 parent = node; 6527 mean = synctex_node_mean_line(node); 6528 while ((parent = _synctex_tree_parent(parent))) { 6529 if (_synctex_node_is_hbox(parent)) { 6530 if (_synctex_abs(mean - synctex_node_mean_line(parent)) > 1) { 6531 return node; 6532 } else if (synctex_node_width(parent) > bound) { 6533 return parent; 6534 } else if (synctex_node_height(parent) + synctex_node_depth(parent) > bound) { 6535 return parent; 6536 } 6537 node = parent; 6538 } 6539 } 6540 } 6541 return node; 6542 } 6543 /** 6544 * The horizontal location of the first box enclosing node, in page coordinates. 6545 * - parameter node: a node. 6546 * - returns: a float. 6547 * - author: JL 6548 */ 6549 float synctex_node_box_visible_h(synctex_node_p node) 6550 { 6551 return SYNCTEX_VISIBLE_DISTANCE_h(node, _synctex_node_h_V(_synctex_node_box_visible(node))); 6552 } 6553 /** 6554 * The vertical location of the first box enclosing node, in page coordinates. 6555 * - parameter node: a node. 6556 * - returns: a float. 6557 * - author: JL 6558 */ 6559 float synctex_node_box_visible_v(synctex_node_p node) 6560 { 6561 return SYNCTEX_VISIBLE_DISTANCE_v(node, _synctex_node_v_V(_synctex_node_box_visible(node))); 6562 } 6563 /** 6564 * The width of the first box enclosing node, in page coordinates. 6565 * - parameter node: a node. 6566 * - returns: a float. 6567 * - author: JL 6568 */ 6569 float synctex_node_box_visible_width(synctex_node_p node) 6570 { 6571 return SYNCTEX_VISIBLE_SIZE(node, _synctex_node_width_V(_synctex_node_box_visible(node))); 6572 } 6573 /** 6574 * The height of the first box enclosing node, in page coordinates. 6575 * - parameter node: a node. 6576 * - returns: a float. 6577 * - author: JL 6578 */ 6579 float synctex_node_box_visible_height(synctex_node_p node) 6580 { 6581 return SYNCTEX_VISIBLE_SIZE(node, _synctex_node_height_V(_synctex_node_box_visible(node))); 6582 } 6583 /** 6584 * The depth of the first box enclosing node, in page coordinates. 6585 * - parameter node: a node. 6586 * - returns: a float. 6587 * - author: JL 6588 */ 6589 float synctex_node_box_visible_depth(synctex_node_p node) 6590 { 6591 return SYNCTEX_VISIBLE_SIZE(node, _synctex_node_depth_V(_synctex_node_box_visible(node))); 6592 } 6593 #ifdef SYNCTEX_NOTHING 6594 #pragma mark - 6595 #pragma mark Other public node attributes 6596 #endif 6597 6598 /** 6599 * The page number of the sheet enclosing node. 6600 * - parameter node: a node. 6601 * - returns: the page number or -1 if node does not belong to a sheet tree. 6602 * - note: a proxy target does not belong to a sheet 6603 * but a form, its page number is always -1. 6604 * - note: a handles does not belong to a sheet not a form. 6605 * its page number is -1. 6606 * - author: JL 6607 */ 6608 int synctex_node_page(synctex_node_p node) 6609 { 6610 synctex_node_p parent = NULL; 6611 while ((parent = _synctex_tree_parent(node))) { 6612 node = parent; 6613 } 6614 if (synctex_node_type(node) == synctex_node_type_sheet) { 6615 return _synctex_data_page(node); 6616 } 6617 return -1; 6618 } 6619 /** 6620 * The page number of the target. 6621 * - author: JL 6622 */ 6623 SYNCTEX_INLINE static int _synctex_node_target_page(synctex_node_p node) 6624 { 6625 return synctex_node_page(_synctex_tree_target(node)); 6626 } 6627 6628 #if defined(SYNCTEX_USE_CHARINDEX) 6629 synctex_charindex_t synctex_node_charindex(synctex_node_p node) 6630 { 6631 synctex_node_p target = _synctex_tree_target(node); 6632 return target ? SYNCTEX_CHARINDEX(target) : (node ? SYNCTEX_CHARINDEX(node) : 0); 6633 } 6634 #endif 6635 6636 /** 6637 * The tag of the node. 6638 * - parameter node: a node. 6639 * - returns: the tag or -1 if node is NULL. 6640 * - author: JL 6641 */ 6642 int synctex_node_tag(synctex_node_p node) 6643 { 6644 return node ? node->class->tlcpector->tag(node) : -1; 6645 } 6646 /** 6647 * The line of the node. 6648 * - parameter node: a node. 6649 * - returns: the line or -1 if node is NULL. 6650 * - author: JL 6651 */ 6652 int synctex_node_line(synctex_node_p node) 6653 { 6654 return node ? node->class->tlcpector->line(node) : -1; 6655 } 6656 /** 6657 * The column of the node. 6658 * - parameter node: a node. 6659 * - returns: the column or -1 if node is NULL. 6660 * - author: JL 6661 */ 6662 int synctex_node_column(synctex_node_p node) 6663 { 6664 return node ? node->class->tlcpector->column(node) : -1; 6665 } 6666 /** 6667 * The mean line number of the node. 6668 * - parameter node: a node. 6669 * - returns: the mean line or -1 if node is NULL. 6670 * - author: JL 6671 */ 6672 int synctex_node_mean_line(synctex_node_p node) 6673 { 6674 synctex_node_p target = _synctex_tree_target(node); 6675 if (target) { 6676 node = target; 6677 } 6678 return _synctex_data_has_mean_line(node) ? _synctex_data_mean_line(node) : _synctex_data_line(node); 6679 } 6680 /** 6681 * The weight of the node. 6682 * - parameter node: a node. 6683 * - returns: the weight or -1 if node is NULL. 6684 * - author: JL 6685 */ 6686 int synctex_node_weight(synctex_node_p node) 6687 { 6688 synctex_node_p target = _synctex_tree_target(node); 6689 if (target) { 6690 node = target; 6691 } 6692 return node ? (synctex_node_type(node) == synctex_node_type_hbox ? _synctex_data_weight(node) : 0) : -1; 6693 } 6694 /** 6695 * The number of children of the node. 6696 * - parameter node: a node. 6697 * - returns: the count or -1 if node is NULL. 6698 * - author: JL 6699 */ 6700 int synctex_node_child_count(synctex_node_p node) 6701 { 6702 synctex_node_p target = _synctex_tree_target(node); 6703 if (target) { 6704 node = target; 6705 } 6706 return node ? (synctex_node_type(node) == synctex_node_type_hbox ? _synctex_data_weight(node) : 0) : -1; 6707 } 6708 #ifdef SYNCTEX_NOTHING 6709 #pragma mark - 6710 #pragma mark Sheet & Form 6711 #endif 6712 6713 /** 6714 * The sheet of the scanner with a given page number. 6715 * - parameter scanner: a scanner. 6716 * - parameter page: a 1 based page number. 6717 * If page == 0, returns the first sheet. 6718 * - returns: a sheet or NULL. 6719 * - author: JL 6720 */ 6721 synctex_node_p synctex_sheet(synctex_scanner_p scanner, int page) 6722 { 6723 if (scanner) { 6724 synctex_node_p sheet = scanner->sheet; 6725 while (sheet) { 6726 if (page == _synctex_data_page(sheet)) { 6727 return sheet; 6728 } 6729 sheet = __synctex_tree_sibling(sheet); 6730 } 6731 if (page == 0) { 6732 return scanner->sheet; 6733 } 6734 } 6735 return NULL; 6736 } 6737 /** 6738 * The form of the scanner with a given tag. 6739 * - parameter scanner: a scanner. 6740 * - parameter tag: an integer identifier. 6741 * If tag == 0, returns the first form. 6742 * - returns: a form. 6743 * - author: JL 6744 */ 6745 synctex_node_p synctex_form(synctex_scanner_p scanner, int tag) 6746 { 6747 if (scanner) { 6748 synctex_node_p form = scanner->form; 6749 while (form) { 6750 if (tag == _synctex_data_tag(form)) { 6751 return form; 6752 } 6753 form = __synctex_tree_sibling(form); 6754 } 6755 if (tag == 0) { 6756 return scanner->form; 6757 } 6758 } 6759 return NULL; 6760 } 6761 6762 /** 6763 * The content of the sheet with given page number. 6764 * - parameter scanner: a scanner. 6765 * - parameter page: a 1 based page number. 6766 * - returns: a (vertical) box node. 6767 * - author: JL 6768 */ 6769 synctex_node_p synctex_sheet_content(synctex_scanner_p scanner, int page) 6770 { 6771 if (scanner) { 6772 return _synctex_tree_child(synctex_sheet(scanner, page)); 6773 } 6774 return NULL; 6775 } 6776 6777 /** 6778 * The content of the sheet with given page number. 6779 * - parameter scanner: a scanner. 6780 * - parameter tag: an integer identifier. 6781 * - returns: a box node. 6782 * - author: JL 6783 */ 6784 synctex_node_p synctex_form_content(synctex_scanner_p scanner, int tag) 6785 { 6786 if (scanner) { 6787 return _synctex_tree_child(synctex_form(scanner, tag)); 6788 } 6789 return NULL; 6790 } 6791 6792 SYNCTEX_INLINE static synctex_node_p _synctex_scanner_friend(synctex_scanner_p scanner, int i) 6793 { 6794 if (i >= 0) { 6795 i = _synctex_abs(i) % (scanner->number_of_lists); 6796 return (scanner->lists_of_friends)[i]; 6797 } 6798 return NULL; 6799 } 6800 SYNCTEX_INLINE static synctex_bool_t _synctex_nodes_are_friend(synctex_node_p left, synctex_node_p right) 6801 { 6802 return synctex_node_tag(left) == synctex_node_tag(right) && synctex_node_line(left) == synctex_node_line(right); 6803 } 6804 SYNCTEX_INLINE static synctex_node_p _synctex_vertically_sorted_v2(synctex_node_p sibling) 6805 { 6806 synctex_node_p child = NULL; 6807 synctex_node_p best_child = sibling; 6808 synctex_node_p next_child = _synctex_tree_reset_child(best_child); 6809 synctex_node_p target = _synctex_tree_target(best_child); 6810 synctex_node_p parent = _synctex_tree_parent(target); 6811 unsigned int best_count = 0; 6812 unsigned int count = 0; 6813 synctex_node_p N = _synctex_tree_child(parent); 6814 do { 6815 if (_synctex_nodes_are_friend(N, best_child)) { 6816 ++best_count; 6817 } 6818 } while ((N = __synctex_tree_sibling(N))); 6819 /* Navigate through the other children */ 6820 while ((child = next_child)) { 6821 next_child = _synctex_tree_reset_child(child); 6822 target = _synctex_tree_target(child); 6823 parent = _synctex_tree_parent(target); 6824 count = 0; 6825 N = _synctex_tree_child(parent); 6826 do { 6827 if (_synctex_nodes_are_friend(N, best_child)) { 6828 ++count; 6829 } 6830 } while ((N = __synctex_tree_sibling(N))); 6831 if (count > best_count) { 6832 best_count = count; 6833 synctex_node_free(best_child); 6834 best_child = child; 6835 } else { 6836 synctex_node_free(child); 6837 } 6838 } 6839 return best_child; 6840 } 6841 6842 SYNCTEX_INLINE static synctex_bool_t _synctex_point_in_box_v2(synctex_point_p hitP, synctex_node_p node); 6843 6844 /* This struct records distances, the left one is non negative and the right one is non positive. 6845 * When comparing the locations of 2 different graphical objects on the page, we will have to also record the 6846 * horizontal distance as signed to keep track of the typesetting order.*/ 6847 6848 typedef struct { 6849 synctex_node_p node; 6850 int distance; 6851 } synctex_nd_s; 6852 6853 #define SYNCTEX_ND_0 \ 6854 (synctex_nd_s) \ 6855 { \ 6856 NULL, INT_MAX \ 6857 } 6858 6859 typedef synctex_nd_s *synctex_nd_p; 6860 6861 typedef struct { 6862 synctex_nd_s l; 6863 synctex_nd_s r; 6864 } synctex_nd_lr_s; 6865 6866 /* The best container is the deeper box that contains the hit point (H,V). 6867 * _synctex_eq_deepest_container_v2 starts with node whereas 6868 * _synctex_box_child_deepest starts with node's children, if any 6869 * if node is not a box, or a void box, NULL is returned. 6870 * We traverse the node tree in a deep first manner and stop as soon as a result is found. */ 6871 static synctex_node_p _synctex_eq_deepest_container_v2(synctex_point_p hitP, synctex_node_p node); 6872 6873 SYNCTEX_INLINE static synctex_nd_lr_s _synctex_eq_get_closest_children_in_box_v2(synctex_point_p hitP, synctex_node_p node); 6874 6875 /* Closest child, recursive. */ 6876 static synctex_nd_s __synctex_closest_deep_child_v2(synctex_point_p hitP, synctex_node_p node); 6877 6878 /* The smallest container between two has the smallest width or height. 6879 * This comparison is used when there are 2 overlapping boxes that contain the hit point. 6880 * For ConTeXt, the problem appears at each page. 6881 * The chosen box is the one with the smallest height, then the smallest width. */ 6882 SYNCTEX_INLINE static synctex_node_p _synctex_smallest_container_v2(synctex_node_p node, synctex_node_p other_node); 6883 6884 /* Returns the distance between the hit point hit point=(H,V) and the given node. */ 6885 6886 static int _synctex_point_node_distance_v2(synctex_point_p hitP, synctex_node_p node); 6887 6888 /* The closest container is the box that is the one closest to the given point. 6889 * The "visible" version takes into account the visible dimensions instead of the real ones given by TeX. */ 6890 static synctex_nd_s _synctex_eq_closest_child_v2(synctex_point_p hitP, synctex_node_p node); 6891 6892 #ifdef SYNCTEX_NOTHING 6893 #pragma mark - 6894 #pragma mark Queries 6895 #endif 6896 6897 struct synctex_iterator_t { 6898 synctex_node_p seed; 6899 synctex_node_p next; 6900 int count0; 6901 int count; 6902 }; 6903 6904 SYNCTEX_INLINE static synctex_iterator_p _synctex_iterator_new(synctex_node_p result, int count) 6905 { 6906 synctex_iterator_p iterator; 6907 if ((iterator = _synctex_malloc(sizeof(synctex_iterator_s)))) { 6908 iterator->seed = iterator->next = result; 6909 iterator->count0 = iterator->count = count; 6910 } 6911 return iterator; 6912 }; 6913 6914 void synctex_iterator_free(synctex_iterator_p iterator) 6915 { 6916 if (iterator) { 6917 synctex_node_free(iterator->seed); 6918 _synctex_free(iterator); 6919 } 6920 } 6921 synctex_bool_t synctex_iterator_has_next(synctex_iterator_p iterator) 6922 { 6923 return iterator ? iterator->count > 0 : 0; 6924 } 6925 int synctex_iterator_count(synctex_iterator_p iterator) 6926 { 6927 return iterator ? iterator->count : 0; 6928 } 6929 6930 /** 6931 * The next result of the iterator. 6932 * Internally, the iterator stores handles to nodes. 6933 * Externally, it returns the targets, 6934 * such that the caller only sees nodes. 6935 */ 6936 synctex_node_p synctex_iterator_next_result(synctex_iterator_p iterator) 6937 { 6938 if (iterator && iterator->count > 0) { 6939 synctex_node_p N = iterator->next; 6940 iterator->next = __synctex_tree_sibling(N); 6941 --iterator->count; 6942 return _synctex_tree_target(N); 6943 } 6944 return NULL; 6945 } 6946 int synctex_iterator_reset(synctex_iterator_p iterator) 6947 { 6948 if (iterator) { 6949 iterator->next = iterator->seed; 6950 return iterator->count = iterator->count0; 6951 } 6952 return 0; 6953 } 6954 6955 synctex_iterator_p synctex_iterator_new_edit(synctex_scanner_p scanner, int page, float h, float v) 6956 { 6957 if (scanner) { 6958 synctex_node_p sheet = NULL; 6959 synctex_point_s hit; 6960 synctex_node_p node = NULL; 6961 synctex_nd_lr_s nds = {{NULL, 0}, {NULL, 0}}; 6962 if (NULL == (scanner = synctex_scanner_parse(scanner)) || 0 >= scanner->unit) { /* scanner->unit must be >0 */ 6963 return NULL; 6964 } 6965 /* Find the proper sheet */ 6966 sheet = synctex_sheet(scanner, page); 6967 if (NULL == sheet) { 6968 return NULL; 6969 } 6970 /* Now sheet points to the sheet node with proper page number. */ 6971 /* Now that scanner has been initialized, we can convert 6972 * the given point to scanner integer coordinates */ 6973 hit = (synctex_point_s) {(h - scanner->x_offset) / scanner->unit, (v - scanner->y_offset) / scanner->unit}; 6974 /* At first, we browse all the horizontal boxes of the sheet 6975 * until we find one containing the hit point. */ 6976 if ((node = _synctex_tree_next_hbox(sheet))) { 6977 do { 6978 if (_synctex_point_in_box_v2(&hit, node)) { 6979 /* Maybe the hit point belongs to a contained vertical box. 6980 * This is the most likely situation. 6981 */ 6982 synctex_node_p next = node; 6983 #if defined(SYNCTEX_DEBUG) 6984 printf("--- We are lucky\n"); 6985 #endif 6986 /* This trick is for catching overlapping boxes */ 6987 while ((next = _synctex_tree_next_hbox(next))) { 6988 if (_synctex_point_in_box_v2(&hit, next)) { 6989 node = _synctex_smallest_container_v2(next, node); 6990 } 6991 } 6992 /* node is the smallest horizontal box that contains hit, 6993 * unless there is no hbox at all. 6994 */ 6995 node = _synctex_eq_deepest_container_v2(&hit, node); 6996 nds = _synctex_eq_get_closest_children_in_box_v2(&hit, node); 6997 end: 6998 if (nds.r.node && nds.l.node) { 6999 if ((_synctex_data_tag(nds.r.node) != _synctex_data_tag(nds.l.node)) || (_synctex_data_line(nds.r.node) != _synctex_data_line(nds.l.node)) || (_synctex_data_column(nds.r.node) != _synctex_data_column(nds.l.node))) { 7000 if (nds.l.distance > nds.r.distance) { 7001 node = nds.r.node; 7002 nds.r.node = nds.l.node; 7003 nds.l.node = node; 7004 } 7005 if ((node = _synctex_new_handle_with_target(nds.l.node))) { 7006 synctex_node_p other_handle; 7007 if ((other_handle = _synctex_new_handle_with_target(nds.r.node))) { 7008 _synctex_tree_set_sibling(node, other_handle); 7009 return _synctex_iterator_new(node, 2); 7010 } 7011 return _synctex_iterator_new(node, 1); 7012 } 7013 return NULL; 7014 } 7015 /* both nodes have the same input coordinates 7016 * We choose the one closest to the hit point */ 7017 if (nds.l.distance > nds.r.distance) { 7018 nds.l.node = nds.r.node; 7019 } 7020 nds.r.node = NULL; 7021 } else if (nds.r.node) { 7022 nds.l = nds.r; 7023 } else if (!nds.l.node) { 7024 nds.l.node = node; 7025 } 7026 if ((node = _synctex_new_handle_with_target(nds.l.node))) { 7027 return _synctex_iterator_new(node, 1); 7028 } 7029 return 0; 7030 } 7031 } while ((node = _synctex_tree_next_hbox(node))); 7032 /* All the horizontal boxes have been tested, 7033 * None of them contains the hit point. 7034 */ 7035 } 7036 /* We are not lucky, 7037 * we test absolutely all the node 7038 * to find the closest... */ 7039 if ((node = _synctex_tree_child(sheet))) { 7040 #if defined(SYNCTEX_DEBUG) 7041 printf("--- We are not lucky\n"); 7042 #endif 7043 nds.l = __synctex_closest_deep_child_v2(&hit, node); 7044 #if defined(SYNCTEX_DEBUG) 7045 printf("Edit query best: %i\n", nds.l.distance); 7046 #endif 7047 goto end; 7048 } 7049 } 7050 return NULL; 7051 } 7052 7053 /** 7054 * Loop the candidate friendly list to find the ones with the proper 7055 * tag and line. 7056 * Returns a tree of results targeting the found candidates. 7057 * At the top level each sibling has its own page number. 7058 * All the results with the same page number are linked by child/parent entry. 7059 * - parameter candidate: a friendly list of candidates 7060 */ 7061 static synctex_node_p _synctex_display_query_v2(synctex_node_p target, int tag, int line, synctex_bool_t exclude_box) 7062 { 7063 synctex_node_p first_handle = NULL; 7064 /* Search the first match */ 7065 if (target == NULL) { 7066 return first_handle; 7067 } 7068 do { 7069 int page; 7070 if ((exclude_box && _synctex_node_is_box(target)) || (tag != synctex_node_tag(target)) || (line != synctex_node_line(target))) { 7071 continue; 7072 } 7073 /* We found a first match, create 7074 * a result handle targeting that candidate. */ 7075 first_handle = _synctex_new_handle_with_target(target); 7076 if (first_handle == NULL) { 7077 return first_handle; 7078 } 7079 /* target is either a node, 7080 * or a proxy to some node, in which case, 7081 * the target's target belongs to a form, 7082 * not a sheet. */ 7083 page = synctex_node_page(target); 7084 /* Now create all the other results */ 7085 while ((target = _synctex_tree_friend(target))) { 7086 synctex_node_p result = NULL; 7087 if ((exclude_box && _synctex_node_is_box(target)) || (tag != synctex_node_tag(target)) || (line != synctex_node_line(target))) { 7088 continue; 7089 } 7090 /* Another match, same page number ? */ 7091 result = _synctex_new_handle_with_target(target); 7092 if (NULL == result) { 7093 return first_handle; 7094 } 7095 /* is it the same page number ? */ 7096 if (synctex_node_page(target) == page) { 7097 __synctex_tree_set_child(result, first_handle); 7098 first_handle = result; 7099 } else { 7100 /* We have 2 page numbers involved */ 7101 __synctex_tree_set_sibling(first_handle, result); 7102 while ((target = _synctex_tree_friend(target))) { 7103 synctex_node_p same_page_node; 7104 if ((exclude_box && _synctex_node_is_box(target)) || (tag != synctex_node_tag(target)) || (line != synctex_node_line(target))) { 7105 continue; 7106 } 7107 /* New match found, which page? */ 7108 result = _synctex_new_handle_with_target(target); 7109 if (NULL == result) { 7110 return first_handle; 7111 } 7112 same_page_node = first_handle; 7113 page = synctex_node_page(target); 7114 /* Find a result with the same page number */; 7115 do { 7116 if (_synctex_node_target_page(same_page_node) == page) { 7117 _synctex_tree_set_child(result, _synctex_tree_set_child(same_page_node, result)); 7118 } else if ((same_page_node = __synctex_tree_sibling(same_page_node))) { 7119 continue; 7120 } else { 7121 /* This is a new page number */ 7122 __synctex_tree_set_sibling(result, first_handle); 7123 first_handle = result; 7124 } 7125 break; 7126 } while (synctex_YES); 7127 } 7128 return first_handle; 7129 } 7130 } 7131 } while ((target = _synctex_tree_friend(target))); 7132 return first_handle; 7133 } 7134 synctex_iterator_p synctex_iterator_new_display(synctex_scanner_p scanner, const char *name, int line, int column, int page_hint) 7135 { 7136 (void)column; /* unused */ 7137 if (scanner) { 7138 int tag = synctex_scanner_get_tag(scanner, name); /* parse if necessary */ 7139 int max_line = 0; 7140 int line_offset = 1; 7141 int try_count = 100; 7142 synctex_node_p node = NULL; 7143 synctex_node_p result = NULL; 7144 if (tag == 0) { 7145 printf("SyncTeX Warning: No tag for %s\n", name); 7146 return NULL; 7147 } 7148 node = synctex_scanner_input_with_tag(scanner, tag); 7149 max_line = _synctex_data_line(node); 7150 /* node = NULL; */ 7151 if (line > max_line) { 7152 line = max_line; 7153 } 7154 while (try_count--) { 7155 if (line <= max_line) { 7156 /* This loop will only be performed once for advanced viewers */ 7157 synctex_node_p friend = _synctex_scanner_friend(scanner, tag + line); 7158 if ((node = friend)) { 7159 result = _synctex_display_query_v2(node, tag, line, synctex_YES); 7160 if (!result) { 7161 /* We did not find any matching boundary, retry including boxes */ 7162 node = friend; /* no need to test it again, already done */ 7163 result = _synctex_display_query_v2(node, tag, line, synctex_NO); 7164 } 7165 /* Now reverse the order to have nodes in display order, and then keep just a few nodes. 7166 * Order first the best node. */ 7167 /* The result is a tree. At the root level, all nodes 7168 * correspond to different page numbers. 7169 * Each node has a child which corresponds to the same 7170 * page number if relevant. 7171 * Then reorder the nodes to put first the one which fits best. 7172 * The idea is to count the number of nodes 7173 * with the same tag and line number in the parents 7174 * and choose the one with the biggest count. 7175 */ 7176 if (result) { 7177 /* navigate through siblings, 7178 then children */ 7179 int count = 1; 7180 synctex_node_p next_sibling = __synctex_tree_reset_sibling(result); 7181 int best_match = abs(page_hint - _synctex_node_target_page(result)); 7182 synctex_node_p sibling; 7183 int match; 7184 result = _synctex_vertically_sorted_v2(result); 7185 while ((sibling = next_sibling)) { 7186 /* What is next? Do not miss that step! */ 7187 next_sibling = __synctex_tree_reset_sibling(sibling); 7188 sibling = _synctex_vertically_sorted_v2(sibling); 7189 match = abs(page_hint - _synctex_node_target_page(sibling)); 7190 if (match < best_match) { 7191 /* Order this node first */ 7192 __synctex_tree_set_sibling(sibling, result); 7193 result = sibling; 7194 best_match = match; 7195 } else /*if (match>best_match)*/ { 7196 __synctex_tree_set_sibling(sibling, __synctex_tree_sibling(result)); 7197 __synctex_tree_set_sibling(result, sibling); 7198 } 7199 ++count; 7200 } 7201 /* Now order first the result closest to the page hint */ 7202 return _synctex_iterator_new(result, count); 7203 } 7204 } 7205 #if defined(__SYNCTEX_STRONG_DISPLAY_QUERY__) 7206 break; 7207 #else 7208 line += line_offset; 7209 line_offset = line_offset < 0 ? -(line_offset - 1) : -(line_offset + 1); 7210 if (line <= 0) { 7211 line += line_offset; 7212 line_offset = line_offset < 0 ? -(line_offset - 1) : -(line_offset + 1); 7213 } 7214 #endif 7215 } 7216 } 7217 } 7218 return NULL; 7219 } 7220 synctex_status_t synctex_display_query(synctex_scanner_p scanner, const char *name, int line, int column, int page_hint) 7221 { 7222 if (scanner) { 7223 synctex_iterator_free(scanner->iterator); 7224 scanner->iterator = synctex_iterator_new_display(scanner, name, line, column, page_hint); 7225 return synctex_iterator_count(scanner->iterator); 7226 } 7227 return SYNCTEX_STATUS_ERROR; 7228 } 7229 synctex_status_t synctex_edit_query(synctex_scanner_p scanner, int page, float h, float v) 7230 { 7231 if (scanner) { 7232 synctex_iterator_free(scanner->iterator); 7233 scanner->iterator = synctex_iterator_new_edit(scanner, page, h, v); 7234 return synctex_iterator_count(scanner->iterator); 7235 } 7236 return SYNCTEX_STATUS_ERROR; 7237 } 7238 /** 7239 * The next result of a query. 7240 */ 7241 synctex_node_p synctex_scanner_next_result(synctex_scanner_p scanner) 7242 { 7243 return scanner ? synctex_iterator_next_result(scanner->iterator) : NULL; 7244 } 7245 synctex_status_t synctex_scanner_reset_result(synctex_scanner_p scanner) 7246 { 7247 return scanner ? synctex_iterator_reset(scanner->iterator) : SYNCTEX_STATUS_ERROR; 7248 } 7249 7250 synctex_node_p synctex_node_target(synctex_node_p node) 7251 { 7252 return _synctex_tree_target(node); 7253 } 7254 7255 #ifdef SYNCTEX_NOTHING 7256 #pragma mark - 7257 #pragma mark Geometric utilities 7258 #endif 7259 7260 /** Rougly speaking, this is: 7261 * node's h coordinate - hit point's h coordinate. 7262 * If node is to the right of the hit point, then this distance is positive, 7263 * if node is to the left of the hit point, this distance is negative. 7264 * If the argument is a pdf form reference, then the child is used and returned instead. 7265 * Last Revision: Mon Apr 24 07:05:27 UTC 2017 7266 */ 7267 static synctex_nd_s _synctex_point_h_ordered_distance_v2(synctex_point_p hit, synctex_node_p node) 7268 { 7269 synctex_nd_s nd = {node, INT_MAX}; 7270 if (node) { 7271 int min, med, max, width; 7272 switch (synctex_node_type(node)) { 7273 /* The distance between a point and a box is special. 7274 * It is not the euclidian distance, nor something similar. 7275 * We have to take into account the particular layout, 7276 * and the box hierarchy. 7277 * Given a box, there are 9 regions delimited by the lines of the edges of the box. 7278 * The origin being at the top left corner of the page, 7279 * we also give names to the vertices of the box. 7280 * 7281 * 1 | 2 | 3 7282 * ---A---B---> 7283 * 4 | 5 | 6 7284 * ---C---D---> 7285 * 7 | 8 | 9 7286 * v v 7287 */ 7288 case synctex_node_type_vbox: 7289 case synctex_node_type_void_vbox: 7290 case synctex_node_type_void_hbox: 7291 /* getting the box bounds, taking into account negative width, height and depth. */ 7292 width = _synctex_data_width(node); 7293 min = _synctex_data_h(node); 7294 max = min + (width > 0 ? width : -width); 7295 /* We always have min <= max */ 7296 if (hit->h < min) { 7297 nd.distance = min - hit->h; /* regions 1+4+7, result is > 0 */ 7298 } else if (hit->h > max) { 7299 nd.distance = max - hit->h; /* regions 3+6+9, result is < 0 */ 7300 } else { 7301 nd.distance = 0; /* regions 2+5+8, inside the box, except for vertical coordinates */ 7302 } 7303 break; 7304 case synctex_node_type_proxy_vbox: 7305 /* getting the box bounds, taking into account negative width, height and depth. */ 7306 width = synctex_node_width(node); 7307 min = synctex_node_h(node); 7308 max = min + (width > 0 ? width : -width); 7309 /* We always have min <= max */ 7310 if (hit->h < min) { 7311 nd.distance = min - hit->h; /* regions 1+4+7, result is > 0 */ 7312 } else if (hit->h > max) { 7313 nd.distance = max - hit->h; /* regions 3+6+9, result is < 0 */ 7314 } else { 7315 nd.distance = 0; /* regions 2+5+8, inside the box, except for vertical coordinates */ 7316 } 7317 break; 7318 case synctex_node_type_hbox: 7319 case synctex_node_type_proxy_hbox: 7320 /* getting the box bounds, taking into account negative width, height and depth. */ 7321 width = synctex_node_hbox_width(node); 7322 min = synctex_node_hbox_h(node); 7323 max = min + (width > 0 ? width : -width); 7324 /* We always have min <= max */ 7325 if (hit->h < min) { 7326 nd.distance = min - hit->h; /* regions 1+4+7, result is > 0 */ 7327 } else if (hit->h > max) { 7328 nd.distance = max - hit->h; /* regions 3+6+9, result is < 0 */ 7329 } else { 7330 nd.distance = 0; /* regions 2+5+8, inside the box, except for vertical coordinates */ 7331 } 7332 break; 7333 case synctex_node_type_kern: 7334 /* IMPORTANT NOTICE: the location of the kern is recorded AFTER the move. 7335 * The distance to the kern is very special, 7336 * in general, there is no text material in the kern, 7337 * this is why we compute the offset relative to the closest edge of the kern.*/ 7338 max = _synctex_data_width(node); 7339 if (max < 0) { 7340 min = _synctex_data_h(node); 7341 max = min - max; 7342 } else { 7343 min = -max; 7344 max = _synctex_data_h(node); 7345 min += max; 7346 } 7347 med = (min + max) / 2; 7348 /* positive kern: '.' means text, '>' means kern offset 7349 * ............. 7350 * min>>>>med>>>>max 7351 * ............... 7352 * negative kern: '.' means text, '<' means kern offset 7353 * ............................ 7354 * min<<<<med<<<<max 7355 * ................................. 7356 * Actually, we do not take into account negative widths. 7357 * There is a problem for such situation when there is effectively overlapping text. 7358 * But this should be extremely rare. I guess that in that case, many different choices 7359 * could be made, one being in contradiction with the other. 7360 * It means that the best choice should be made according to the situation that occurs 7361 * most frequently. 7362 */ 7363 if (hit->h < min) { 7364 nd.distance = min - hit->h + 1; /* penalty to ensure other nodes are chosen first in case of overlapping ones */ 7365 } else if (hit->h > max) { 7366 nd.distance = max - hit->h - 1; /* same kind of penalty */ 7367 } else if (hit->h > med) { 7368 /* do things like if the node had 0 width and was placed at the max edge + 1*/ 7369 nd.distance = max - hit->h + 1; /* positive, the kern is to the right of the hit point */ 7370 } else { 7371 nd.distance = min - hit->h - 1; /* negative, the kern is to the left of the hit point */ 7372 } 7373 break; 7374 case synctex_node_type_rule: /* to do: special management */ 7375 case synctex_node_type_glue: 7376 case synctex_node_type_math: 7377 case synctex_node_type_boundary: 7378 case synctex_node_type_box_bdry: 7379 nd.distance = _synctex_data_h(node) - hit->h; 7380 break; 7381 case synctex_node_type_ref: 7382 nd.node = synctex_node_child(node); 7383 nd = _synctex_point_h_ordered_distance_v2(hit, nd.node); 7384 break; 7385 case synctex_node_type_proxy: 7386 case synctex_node_type_proxy_last: { 7387 /* shift the hit point to be relative to the proxy origin, 7388 * then compute the distance to the target 7389 */ 7390 synctex_point_s otherHit = *hit; 7391 otherHit.h -= _synctex_data_h(node); 7392 otherHit.v -= _synctex_data_v(node); 7393 nd.node = _synctex_tree_target(node); 7394 nd = _synctex_point_h_ordered_distance_v2(&otherHit, nd.node); 7395 nd.node = node; 7396 } 7397 default: 7398 break; 7399 } 7400 } 7401 return nd; 7402 } 7403 /** Rougly speaking, this is: 7404 * node's v coordinate - hit point's v coordinate. 7405 * If node is at the top of the hit point, then this distance is positive, 7406 * if node is at the bottom of the hit point, this distance is negative. 7407 */ 7408 static synctex_nd_s _synctex_point_v_ordered_distance_v2(synctex_point_p hit, synctex_node_p node) 7409 { 7410 synctex_nd_s nd = {node, INT_MAX}; 7411 int min, max, depth, height; 7412 switch (synctex_node_type(node)) { 7413 /* The distance between a point and a box is special. 7414 * It is not the euclidian distance, nor something similar. 7415 * We have to take into account the particular layout, 7416 * and the box hierarchy. 7417 * Given a box, there are 9 regions delimited by the lines of the edges of the box. 7418 * The origin being at the top left corner of the page, 7419 * we also give names to the vertices of the box. 7420 * 7421 * 1 | 2 | 3 7422 * ---A---B---> 7423 * 4 | 5 | 6 7424 * ---C---D---> 7425 * 7 | 8 | 9 7426 * v v 7427 */ 7428 case synctex_node_type_vbox: 7429 case synctex_node_type_void_vbox: 7430 case synctex_node_type_void_hbox: 7431 /* getting the box bounds, taking into account negative width, height and depth. */ 7432 min = synctex_node_v(node); 7433 max = min + _synctex_abs(_synctex_data_depth(node)); 7434 min -= _synctex_abs(_synctex_data_height(node)); 7435 /* We always have min <= max */ 7436 if (hit->v < min) { 7437 nd.distance = min - hit->v; /* regions 1+2+3, result is > 0 */ 7438 } else if (hit->v > max) { 7439 nd.distance = max - hit->v; /* regions 7+8+9, result is < 0 */ 7440 } else { 7441 nd.distance = 0; /* regions 4.5.6, inside the box, except for horizontal coordinates */ 7442 } 7443 break; 7444 case synctex_node_type_proxy_vbox: 7445 /* getting the box bounds, taking into account negative width, height and depth. */ 7446 min = synctex_node_v(node); 7447 max = min + _synctex_abs(synctex_node_depth(node)); 7448 min -= _synctex_abs(synctex_node_height(node)); 7449 /* We always have min <= max */ 7450 if (hit->v < min) { 7451 nd.distance = min - hit->v; /* regions 1+2+3, result is > 0 */ 7452 } else if (hit->v > max) { 7453 nd.distance = max - hit->v; /* regions 7+8+9, result is < 0 */ 7454 } else { 7455 nd.distance = 0; /* regions 4.5.6, inside the box, except for horizontal coordinates */ 7456 } 7457 break; 7458 case synctex_node_type_hbox: 7459 case synctex_node_type_proxy_hbox: 7460 /* getting the box bounds, taking into account negative height and depth. */ 7461 min = synctex_node_hbox_v(node); 7462 depth = synctex_node_hbox_depth(node); 7463 max = min + (depth > 0 ? depth : -depth); 7464 height = synctex_node_hbox_height(node); 7465 min -= (height > 0 ? height : -height); 7466 /* We always have min <= max */ 7467 if (hit->v < min) { 7468 nd.distance = min - hit->v; /* regions 1+2+3, result is > 0 */ 7469 } else if (hit->v > max) { 7470 nd.distance = max - hit->v; /* regions 7+8+9, result is < 0 */ 7471 } else { 7472 nd.distance = 0; /* regions 4.5.6, inside the box, except for horizontal coordinates */ 7473 } 7474 break; 7475 case synctex_node_type_rule: /* to do: special management */ 7476 case synctex_node_type_kern: 7477 case synctex_node_type_glue: 7478 case synctex_node_type_math: 7479 min = _synctex_data_v(node); 7480 max = min + _synctex_abs(_synctex_data_depth(_synctex_tree_parent(node))); 7481 min -= _synctex_abs(_synctex_data_height(_synctex_tree_parent(node))); 7482 /* We always have min <= max */ 7483 if (hit->v < min) { 7484 nd.distance = min - hit->v; /* regions 1+2+3, result is > 0 */ 7485 } else if (hit->v > max) { 7486 nd.distance = max - hit->v; /* regions 7+8+9, result is < 0 */ 7487 } else { 7488 nd.distance = 0; /* regions 4.5.6, inside the box, except for horizontal coordinates */ 7489 } 7490 break; 7491 case synctex_node_type_ref: 7492 nd.node = synctex_node_child(node); 7493 nd = _synctex_point_v_ordered_distance_v2(hit, nd.node); 7494 break; 7495 case synctex_node_type_proxy: 7496 case synctex_node_type_proxy_last: { 7497 synctex_point_s otherHit = *hit; 7498 otherHit.h -= _synctex_data_h(node); 7499 otherHit.v -= _synctex_data_v(node); 7500 nd.node = _synctex_tree_target(node); 7501 nd = _synctex_point_v_ordered_distance_v2(&otherHit, nd.node); 7502 nd.node = node; 7503 } 7504 default: 7505 break; 7506 } 7507 return nd; 7508 } 7509 /** 7510 * The best is the one with the smallest area. 7511 * The area is width*height where width and height may be big. 7512 * So there is a real risk of overflow if we stick with ints. 7513 */ 7514 SYNCTEX_INLINE static synctex_node_p _synctex_smallest_container_v2(synctex_node_p node, synctex_node_p other_node) 7515 { 7516 long total_height, other_total_height; 7517 unsigned long area, other_area; 7518 long width = synctex_node_hbox_width(node); 7519 long other_width = synctex_node_hbox_width(other_node); 7520 if (width < 0) { 7521 width = -width; 7522 } 7523 if (other_width < 0) { 7524 other_width = -other_width; 7525 } 7526 total_height = _synctex_abs(synctex_node_hbox_depth(node)) + _synctex_abs(synctex_node_hbox_height(node)); 7527 other_total_height = _synctex_abs(synctex_node_hbox_depth(other_node)) + _synctex_abs(synctex_node_hbox_height(other_node)); 7528 area = total_height * width; 7529 other_area = other_total_height * other_width; 7530 if (area < other_area) { 7531 return node; 7532 } 7533 if (area > other_area) { 7534 return other_node; 7535 } 7536 if (_synctex_abs(_synctex_data_width(node)) > _synctex_abs(_synctex_data_width(other_node))) { 7537 return node; 7538 } 7539 if (_synctex_abs(_synctex_data_width(node)) < _synctex_abs(_synctex_data_width(other_node))) { 7540 return other_node; 7541 } 7542 if (total_height < other_total_height) { 7543 return node; 7544 } 7545 if (total_height > other_total_height) { 7546 return other_node; 7547 } 7548 return node; 7549 } 7550 7551 SYNCTEX_INLINE static synctex_bool_t _synctex_point_in_box_v2(synctex_point_p hit, synctex_node_p node) 7552 { 7553 if (node) { 7554 if (0 == _synctex_point_h_ordered_distance_v2(hit, node).distance && 0 == _synctex_point_v_ordered_distance_v2(hit, node).distance) { 7555 return synctex_YES; 7556 } 7557 } 7558 return synctex_NO; 7559 } 7560 7561 static int _synctex_distance_to_box_v2(synctex_point_p hit, synctex_box_p box) 7562 { 7563 /* The distance between a point and a box is special. 7564 * It is not the euclidian distance, nor something similar. 7565 * We have to take into account the particular layout, 7566 * and the box hierarchy. 7567 * Given a box, there are 9 regions delimited by the lines of the edges of the box. 7568 * The origin being at the top left corner of the page, 7569 * we also give names to the vertices of the box. 7570 * 7571 * 1 | 2 | 3 7572 * ---A---B---> 7573 * 4 | 5 | 6 7574 * ---C---D---> 7575 * 7 | 8 | 9 7576 * v v 7577 * In each region, there is a different formula. 7578 * In the end we have a continuous distance which may not be a mathematical distance but who cares. */ 7579 if (hit->v < box->min.v) { 7580 /* Regions 1, 2 or 3 */ 7581 if (hit->h < box->min.h) { 7582 /* This is region 1. The distance to the box is the L1 distance PA. */ 7583 return box->min.v - hit->v + box->min.h - hit->h; /* Integer overflow? probability epsilon */ 7584 } else if (hit->h <= box->max.h) { 7585 /* This is region 2. The distance to the box is the geometrical distance to the top edge. */ 7586 return box->min.v - hit->v; 7587 } else { 7588 /* This is region 3. The distance to the box is the L1 distance PB. */ 7589 return box->min.v - hit->v + hit->h - box->max.h; 7590 } 7591 } else if (hit->v <= box->max.v) { 7592 /* Regions 4, 5 or 6 */ 7593 if (hit->h < box->min.h) { 7594 /* This is region 4. The distance to the box is the geometrical distance to the left edge. */ 7595 return box->min.h - hit->h; 7596 } else if (hit->h <= box->max.h) { 7597 /* This is region 5. We are inside the box. */ 7598 return 0; 7599 } else { 7600 /* This is region 6. The distance to the box is the geometrical distance to the right edge. */ 7601 return hit->h - box->max.h; 7602 } 7603 } else { 7604 /* Regions 7, 8 or 9 */ 7605 if (hit->h < box->min.h) { 7606 /* This is region 7. The distance to the box is the L1 distance PC. */ 7607 return hit->v - box->max.v + box->min.h - hit->h; 7608 } else if (hit->h <= box->max.h) { 7609 /* This is region 8. The distance to the box is the geometrical distance to the top edge. */ 7610 return hit->v - box->max.v; 7611 } else { 7612 /* This is region 9. The distance to the box is the L1 distance PD. */ 7613 return hit->v - box->max.v + hit->h - box->max.h; 7614 } 7615 } 7616 } 7617 7618 /** 7619 * The distance from the hit point to the node. 7620 */ 7621 static int _synctex_point_node_distance_v2(synctex_point_p hit, synctex_node_p node) 7622 { 7623 int d = INT_MAX; 7624 if (node) { 7625 synctex_box_s box = {{0, 0}, {0, 0}}; 7626 int dd = INT_MAX; 7627 switch (synctex_node_type(node)) { 7628 case synctex_node_type_vbox: 7629 box.min.h = _synctex_data_h(node); 7630 box.max.h = box.min.h + _synctex_abs(_synctex_data_width(node)); 7631 box.min.v = synctex_node_v(node); 7632 box.max.v = box.min.v + _synctex_abs(_synctex_data_depth(node)); 7633 box.min.v -= _synctex_abs(_synctex_data_height(node)); 7634 return _synctex_distance_to_box_v2(hit, &box); 7635 case synctex_node_type_proxy_vbox: 7636 box.min.h = synctex_node_h(node); 7637 box.max.h = box.min.h + _synctex_abs(synctex_node_width(node)); 7638 box.min.v = synctex_node_v(node); 7639 box.max.v = box.min.v + _synctex_abs(synctex_node_depth(node)); 7640 box.min.v -= _synctex_abs(synctex_node_height(node)); 7641 return _synctex_distance_to_box_v2(hit, &box); 7642 case synctex_node_type_hbox: 7643 case synctex_node_type_proxy_hbox: 7644 box.min.h = synctex_node_hbox_h(node); 7645 box.max.h = box.min.h + _synctex_abs(synctex_node_hbox_width(node)); 7646 box.min.v = synctex_node_hbox_v(node); 7647 box.max.v = box.min.v + _synctex_abs(synctex_node_hbox_depth(node)); 7648 box.min.v -= _synctex_abs(synctex_node_hbox_height(node)); 7649 return _synctex_distance_to_box_v2(hit, &box); 7650 case synctex_node_type_void_vbox: 7651 case synctex_node_type_void_hbox: 7652 /* best of distances from the left edge and right edge*/ 7653 box.min.h = _synctex_data_h(node); 7654 box.max.h = box.min.h; 7655 box.min.v = _synctex_data_v(node); 7656 box.max.v = box.min.v + _synctex_abs(_synctex_data_depth(node)); 7657 box.min.v -= _synctex_abs(_synctex_data_height(node)); 7658 d = _synctex_distance_to_box_v2(hit, &box); 7659 box.min.h = box.min.h + _synctex_abs(_synctex_data_width(node)); 7660 box.max.h = box.min.h; 7661 dd = _synctex_distance_to_box_v2(hit, &box); 7662 return d < dd ? d : dd; 7663 case synctex_node_type_kern: 7664 box.min.h = _synctex_data_h(node); 7665 box.max.h = box.min.h; 7666 box.max.v = _synctex_data_v(node); 7667 box.min.v = box.max.v - _synctex_abs(_synctex_data_height(_synctex_tree_parent(node))); 7668 d = _synctex_distance_to_box_v2(hit, &box); 7669 box.min.h -= _synctex_data_width(node); 7670 box.max.h = box.min.h; 7671 dd = _synctex_distance_to_box_v2(hit, &box); 7672 return d < dd ? d : dd; 7673 case synctex_node_type_glue: 7674 case synctex_node_type_math: 7675 case synctex_node_type_boundary: 7676 case synctex_node_type_box_bdry: 7677 box.min.h = _synctex_data_h(node); 7678 box.max.h = box.min.h; 7679 box.max.v = _synctex_data_v(node); 7680 box.min.v = box.max.v - _synctex_abs(_synctex_data_height(_synctex_tree_parent(node))); 7681 return _synctex_distance_to_box_v2(hit, &box); 7682 case synctex_node_type_proxy: 7683 case synctex_node_type_proxy_last: { 7684 synctex_point_s otherHit = *hit; 7685 otherHit.h -= _synctex_data_h(node); 7686 otherHit.v -= _synctex_data_v(node); 7687 return _synctex_point_node_distance_v2(&otherHit, _synctex_tree_target(node)); 7688 } 7689 default: 7690 break; 7691 } 7692 } 7693 return d; 7694 } 7695 static synctex_node_p _synctex_eq_deepest_container_v2(synctex_point_p hit, synctex_node_p node) 7696 { 7697 if (node) { 7698 /**/ 7699 synctex_node_p child; 7700 if ((child = synctex_node_child(node))) { 7701 /* Non void hbox or vbox, form ref or proxy */ 7702 /* We go deep first because some boxes have 0 dimensions 7703 * despite they do contain some black material. 7704 */ 7705 do { 7706 if ((_synctex_point_in_box_v2(hit, child))) { 7707 synctex_node_p deep = _synctex_eq_deepest_container_v2(hit, child); 7708 if (deep) { 7709 /* One of the children contains the hit. */ 7710 return deep; 7711 } 7712 } 7713 } while ((child = synctex_node_sibling(child))); 7714 /* is the hit point inside the box? */ 7715 if (synctex_node_type(node) == synctex_node_type_vbox || synctex_node_type(node) == synctex_node_type_proxy_vbox) { 7716 /* For vboxes we try to use some node inside. 7717 * Walk through the list of siblings until we find the closest one. 7718 * Only consider siblings with children inside. */ 7719 if ((child = _synctex_tree_child(node))) { 7720 synctex_nd_s best = SYNCTEX_ND_0; 7721 do { 7722 if (_synctex_tree_child(child)) { 7723 int d = _synctex_point_node_distance_v2(hit, child); 7724 if (d <= best.distance) { 7725 best = (synctex_nd_s) {child, d}; 7726 } 7727 } 7728 } while ((child = __synctex_tree_sibling(child))); 7729 if (best.node) { 7730 return best.node; 7731 } 7732 } 7733 } 7734 if (_synctex_point_in_box_v2(hit, node)) { 7735 return node; 7736 } 7737 } 7738 } 7739 return NULL; 7740 } 7741 static synctex_nd_s _synctex_eq_deepest_container_v3(synctex_point_p hit, synctex_node_p node) 7742 { 7743 if (node) { 7744 synctex_node_p child = NULL; 7745 if ((child = synctex_node_child(node))) { 7746 /* Non void hbox, vbox, box proxy or form ref */ 7747 /* We go deep first because some boxes have 0 dimensions 7748 * despite they do contain some black material. 7749 */ 7750 do { 7751 synctex_nd_s deep = _synctex_eq_deepest_container_v3(hit, child); 7752 if (deep.node) { 7753 /* One of the children contains the hit-> */ 7754 return deep; 7755 } 7756 } while ((child = synctex_node_sibling(child))); 7757 /* For vboxes we try to use some node inside. 7758 * Walk through the list of siblings until we find the closest one. 7759 * Only consider siblings with children inside. */ 7760 if (synctex_node_type(node) == synctex_node_type_vbox || synctex_node_type(node) == synctex_node_type_proxy_vbox) { 7761 if ((child = synctex_node_child(node))) { 7762 synctex_nd_s best = SYNCTEX_ND_0; 7763 do { 7764 if (synctex_node_child(child)) { 7765 int d = _synctex_point_node_distance_v2(hit, child); 7766 if (d < best.distance) { 7767 best = (synctex_nd_s) {child, d}; 7768 } 7769 } 7770 } while ((child = synctex_node_sibling(child))); 7771 if (best.node) { 7772 return best; 7773 } 7774 } 7775 } 7776 /* is the hit point inside the box? */ 7777 if (_synctex_point_in_box_v2(hit, node)) { 7778 return (synctex_nd_s) {node, 0}; 7779 } 7780 } 7781 } 7782 return SYNCTEX_ND_0; 7783 } 7784 7785 /* Compares the locations of the hit point with the locations of 7786 * the various nodes contained in the box. 7787 * As it is an horizontal box, we only compare horizontal coordinates. 7788 */ 7789 SYNCTEX_INLINE static synctex_nd_lr_s __synctex_eq_get_closest_children_in_hbox_v2(synctex_point_p hitP, synctex_node_p node) 7790 { 7791 synctex_nd_s childd = SYNCTEX_ND_0; 7792 synctex_nd_lr_s nds = {SYNCTEX_ND_0, SYNCTEX_ND_0}; 7793 if ((childd.node = synctex_node_child(node))) { 7794 synctex_nd_s nd = SYNCTEX_ND_0; 7795 do { 7796 childd = _synctex_point_h_ordered_distance_v2(hitP, childd.node); 7797 if (childd.distance > 0) { 7798 /* node is to the right of the hit point. 7799 * We compare node and the previously recorded one, through the recorded distance. 7800 * If the nodes have the same tag, prefer the one with the smallest line number, 7801 * if the nodes also have the same line number, prefer the one with the smallest column. */ 7802 if (nds.r.distance > childd.distance) { 7803 nds.r = childd; 7804 } else if (nds.r.distance == childd.distance && nds.r.node) { 7805 if (_synctex_data_tag(nds.r.node) == _synctex_data_tag(childd.node) && 7806 (_synctex_data_line(nds.r.node) > _synctex_data_line(childd.node) || (_synctex_data_line(nds.r.node) == _synctex_data_line(childd.node) && _synctex_data_column(nds.r.node) > _synctex_data_column(childd.node)))) { 7807 nds.r = childd; 7808 } 7809 } 7810 } else if (childd.distance == 0) { 7811 /* hit point is inside node. */ 7812 return _synctex_eq_get_closest_children_in_box_v2(hitP, childd.node); 7813 } else { /* here childd.distance < 0, the hit point is to the right of node */ 7814 childd.distance = -childd.distance; 7815 if (nds.l.distance > childd.distance) { 7816 nds.l = childd; 7817 } else if (nds.l.distance == childd.distance && nds.l.node) { 7818 if (_synctex_data_tag(nds.l.node) == _synctex_data_tag(childd.node) && 7819 (_synctex_data_line(nds.l.node) > _synctex_data_line(childd.node) || (_synctex_data_line(nds.l.node) == _synctex_data_line(childd.node) && _synctex_data_column(nds.l.node) > _synctex_data_column(childd.node)))) { 7820 nds.l = childd; 7821 } 7822 } 7823 } 7824 } while ((childd.node = synctex_node_sibling(childd.node))); 7825 if (nds.l.node) { 7826 /* the left node is new, try to narrow the result */ 7827 if ((nd = _synctex_eq_deepest_container_v3(hitP, nds.l.node)).node) { 7828 nds.l = nd; 7829 } 7830 if ((nd = __synctex_closest_deep_child_v2(hitP, nds.l.node)).node) { 7831 nds.l.node = nd.node; 7832 } 7833 } 7834 if (nds.r.node) { 7835 /* the right node is new, try to narrow the result */ 7836 if ((nd = _synctex_eq_deepest_container_v3(hitP, nds.r.node)).node) { 7837 nds.r = nd; 7838 } 7839 if ((nd = __synctex_closest_deep_child_v2(hitP, nds.r.node)).node) { 7840 nds.r.node = nd.node; 7841 } 7842 } 7843 } 7844 return nds; 7845 } 7846 7847 SYNCTEX_INLINE static synctex_nd_lr_s __synctex_eq_get_closest_children_in_vbox_v2(synctex_point_p hitP, synctex_node_p nodeP) 7848 { 7849 (void)nodeP; /* unused */ 7850 synctex_nd_lr_s nds = {SYNCTEX_ND_0, SYNCTEX_ND_0}; 7851 synctex_nd_s nd = SYNCTEX_ND_0; 7852 if ((nd.node = synctex_node_child(nd.node))) { 7853 do { 7854 nd = _synctex_point_v_ordered_distance_v2(hitP, nd.node); 7855 /* this is what makes the difference with the h version above */ 7856 if (nd.distance > 0) { 7857 /* node is to the top of the hit point (below because TeX is oriented from top to bottom. 7858 * We compare node and the previously recorded one, through the recorded distance. 7859 * If the nodes have the same tag, prefer the one with the smallest line number, 7860 * if the nodes also have the same line number, prefer the one with the smallest column. */ 7861 if (nds.r.distance > nd.distance) { 7862 nds.r = nd; 7863 } else if (nds.r.distance == nd.distance && nds.r.node) { 7864 if (_synctex_data_tag(nds.r.node) == _synctex_data_tag(nd.node) && 7865 (_synctex_data_line(nds.r.node) > _synctex_data_line(nd.node) || (_synctex_data_line(nds.r.node) == _synctex_data_line(nd.node) && _synctex_data_column(nds.r.node) > _synctex_data_column(nd.node)))) { 7866 nds.r = nd; 7867 } 7868 } 7869 } else if (nd.distance == 0) { 7870 nds.l = nd; 7871 } else { /* here nd < 0 */ 7872 nd.distance = -nd.distance; 7873 if (nds.l.distance > nd.distance) { 7874 nds.l = nd; 7875 } else if (nds.l.distance == nd.distance && nds.l.node) { 7876 if (_synctex_data_tag(nds.l.node) == _synctex_data_tag(nd.node) && 7877 (_synctex_data_line(nds.l.node) > _synctex_data_line(nd.node) || (_synctex_data_line(nds.l.node) == _synctex_data_line(nd.node) && _synctex_data_column(nds.l.node) > _synctex_data_column(nd.node)))) { 7878 nds.l = nd; 7879 } 7880 } 7881 } 7882 } while ((nd.node = synctex_node_sibling(nd.node))); 7883 if (nds.l.node) { 7884 if ((nd.node = _synctex_eq_deepest_container_v2(hitP, nds.l.node))) { 7885 nds.l.node = nd.node; 7886 } 7887 if ((nd = _synctex_eq_closest_child_v2(hitP, nds.l.node)).node) { 7888 nds.l.node = nd.node; 7889 } 7890 } 7891 if (nds.r.node) { 7892 if ((nd.node = _synctex_eq_deepest_container_v2(hitP, nds.r.node))) { 7893 nds.r.node = nd.node; 7894 } 7895 if ((nd = _synctex_eq_closest_child_v2(hitP, nds.r.node)).node) { 7896 nds.r.node = nd.node; 7897 } 7898 } 7899 } 7900 return nds; 7901 } 7902 7903 /** 7904 * Get the child closest to the hit point. 7905 * - parameter: hit point 7906 * - parameter: containing node 7907 * - returns: the child and the distance to the hit point. 7908 * SYNCTEX_ND_0 if the parameter node has no children. 7909 * - note: recursive call. 7910 */ 7911 static synctex_nd_s __synctex_closest_deep_child_v2(synctex_point_p hitP, synctex_node_p node) 7912 { 7913 synctex_nd_s best = SYNCTEX_ND_0; 7914 synctex_node_p child = NULL; 7915 if ((child = synctex_node_child(node))) { 7916 #if defined(SYNCTEX_DEBUG) 7917 printf("Closest deep child on box at line %i\n", SYNCTEX_LINEINDEX(node)); 7918 #endif 7919 do { 7920 #if defined SYNCTEX_DEBUG && SYNCTEX_DEBUG > 500 7921 synctex_node_display(child); 7922 #endif 7923 synctex_nd_s nd = SYNCTEX_ND_0; 7924 if (_synctex_node_is_box(child)) { 7925 nd = __synctex_closest_deep_child_v2(hitP, child); 7926 } else { 7927 nd = (synctex_nd_s) {child, _synctex_point_node_distance_v2(hitP, child)}; 7928 } 7929 if (nd.distance < best.distance || (nd.distance == best.distance && synctex_node_type(nd.node) != synctex_node_type_kern)) { 7930 #if defined(SYNCTEX_DEBUG) 7931 if (nd.node) { 7932 printf("New best %i<=%i line %i\n", nd.distance, best.distance, SYNCTEX_LINEINDEX(nd.node)); 7933 } 7934 #endif 7935 best = nd; 7936 } 7937 } while ((child = synctex_node_sibling(child))); 7938 #if defined(SYNCTEX_DEBUG) 7939 if (best.node) { 7940 printf("Found new best %i line %i\n", best.distance, SYNCTEX_LINEINDEX(best.node)); 7941 } 7942 #endif 7943 } 7944 return best; 7945 } 7946 7947 /** 7948 * Return the closest child. 7949 * - parameter: a pointer to the hit point, 7950 * - parameter: the container 7951 * - return: SYNCTEX_ND_0 if node has no child, 7952 * the __synctex_closest_deep_child_v2 otherwise. 7953 */ 7954 static synctex_nd_s _synctex_eq_closest_child_v2(synctex_point_p hitP, synctex_node_p node) 7955 { 7956 synctex_nd_s nd = SYNCTEX_ND_0; 7957 if (_synctex_node_is_box(node)) { 7958 nd = __synctex_closest_deep_child_v2(hitP, node); 7959 if (_synctex_node_is_box(nd.node)) { 7960 synctex_node_p child = NULL; 7961 if ((child = synctex_node_child(nd.node))) { 7962 synctex_nd_s best = {child, _synctex_point_node_distance_v2(hitP, child)}; 7963 while ((child = synctex_node_sibling(child))) { 7964 int d = _synctex_point_node_distance_v2(hitP, child); 7965 if (d < best.distance) { 7966 best = (synctex_nd_s) {child, d}; 7967 } else if (d == best.distance && synctex_node_type(child) != synctex_node_type_kern) { 7968 best.node = child; 7969 } 7970 } 7971 return best; 7972 } 7973 } 7974 return nd; 7975 } 7976 return SYNCTEX_ND_0; 7977 } 7978 SYNCTEX_INLINE static synctex_nd_lr_s _synctex_eq_get_closest_children_in_box_v2(synctex_point_p hitP, synctex_node_p node) 7979 { 7980 synctex_nd_lr_s nds = {SYNCTEX_ND_0, SYNCTEX_ND_0}; 7981 if (_synctex_tree_has_child(node)) { /* node != NULL */ 7982 if (node->class->type == synctex_node_type_hbox || node->class->type == synctex_node_type_proxy_hbox) { 7983 return __synctex_eq_get_closest_children_in_hbox_v2(hitP, node); 7984 } else { 7985 return __synctex_eq_get_closest_children_in_vbox_v2(hitP, node); 7986 } 7987 } 7988 return nds; 7989 } 7990 7991 #ifndef SYNCTEX_NO_UPDATER 7992 7993 #ifdef SYNCTEX_NOTHING 7994 #pragma mark - 7995 #pragma mark Updater 7996 #endif 7997 7998 typedef int (*synctex_print_f)(synctex_updater_p, const char *, ...); /* print formatted to either FILE * or gzFile */ 7999 typedef void (*synctex_close_f)(synctex_updater_p); /* close FILE * or gzFile */ 8000 8001 #define SYNCTEX_BITS_PER_BYTE 8 8002 8003 typedef union { 8004 gzFile as_gzFile; 8005 FILE *as_FILE_p; 8006 void *as_ptr; 8007 } syncex_file_u; 8008 8009 struct synctex_updater_t { 8010 syncex_file_u file; 8011 synctex_print_f print; 8012 synctex_close_f close; 8013 int length; /* the number of chars appended */ 8014 }; 8015 8016 static int _synctex_updater_print(synctex_updater_p updater, const char *format, ...) SYNCTEX_PRINTF_FORMAT(2, 3); 8017 static int _synctex_updater_print(synctex_updater_p updater, const char *format, ...) 8018 { 8019 int result = 0; 8020 if (updater) { 8021 va_list va; 8022 va_start(va, format); 8023 result = vfprintf(updater->file.as_FILE_p, format, va); 8024 va_end(va); 8025 } 8026 return result; 8027 } 8028 #if defined(_MSC_VER) || defined(__MINGW32__) 8029 #include <stdio.h> 8030 #include <stdlib.h> 8031 8032 static int vasprintf(char **ret, const char *format, va_list ap) 8033 { 8034 int len; 8035 len = _vsnprintf(NULL, 0, format, ap); 8036 if (len < 0) 8037 return -1; 8038 *ret = malloc(len + 1); 8039 if (!*ret) 8040 return -1; 8041 _vsnprintf(*ret, len + 1, format, ap); 8042 (*ret)[len] = '\0'; 8043 return len; 8044 } 8045 8046 #endif 8047 8048 /** 8049 * gzvprintf is not available until OSX 10.10 8050 */ 8051 static int _synctex_updater_print_gz(synctex_updater_p updater, const char *format, ...) SYNCTEX_PRINTF_FORMAT(2, 3); 8052 static int _synctex_updater_print_gz(synctex_updater_p updater, const char *format, ...) 8053 { 8054 int result = 0; 8055 if (updater) { 8056 char *buffer; 8057 va_list va; 8058 va_start(va, format); 8059 if (vasprintf(&buffer, format, va) < 0) { 8060 _synctex_error("Out of memory..."); 8061 } else if ((result = (int)strlen(buffer))) { 8062 result = gzwrite(updater->file.as_gzFile, buffer, (unsigned)result); 8063 } 8064 va_end(va); 8065 free(buffer); 8066 } 8067 return result; 8068 } 8069 8070 static void _synctex_updater_close(synctex_updater_p updater) 8071 { 8072 if (updater) { 8073 fclose(updater->file.as_FILE_p); 8074 } 8075 } 8076 8077 static void _synctex_updater_close_gz(synctex_updater_p updater) 8078 { 8079 if (updater) { 8080 gzclose(updater->file.as_gzFile); 8081 } 8082 } 8083 8084 synctex_updater_p synctex_updater_new_with_output_file(const char *output, const char *build_directory) 8085 { 8086 synctex_updater_p updater = NULL; 8087 const char *mode = NULL; 8088 synctex_open_s open; 8089 /* prepare the updater, the memory is the only one dynamically allocated */ 8090 updater = (synctex_updater_p)_synctex_malloc(sizeof(synctex_updater_s)); 8091 if (NULL == updater) { 8092 _synctex_error("! synctex_updater_new_with_file: malloc problem"); 8093 return NULL; 8094 } 8095 open = _synctex_open_v2(output, build_directory, 0, synctex_ADD_QUOTES); 8096 if (open.status < SYNCTEX_STATUS_OK) { 8097 open = _synctex_open_v2(output, build_directory, 0, synctex_DONT_ADD_QUOTES); 8098 if (open.status < SYNCTEX_STATUS_OK) { 8099 return_on_error: 8100 _synctex_free(updater); 8101 return updater = NULL; 8102 } 8103 } 8104 /* OK, the file exists, we close it and reopen it with the correct mode. 8105 * The receiver is now the owner of the "synctex" variable. */ 8106 gzclose(open.file); 8107 updater->file.as_ptr = NULL; 8108 mode = _synctex_get_io_mode_name(open.io_mode | synctex_io_append_mask); /* either "a" or "ab", depending on the file extension */ 8109 if (open.io_mode & synctex_io_gz_mask) { 8110 if (NULL == (updater->file.as_FILE_p = fopen(open.synctex, mode))) { 8111 no_write_error: 8112 _synctex_error("! synctex_updater_new_with_file: Can't append to %s", open.synctex); 8113 free(open.synctex); 8114 goto return_on_error; 8115 } 8116 updater->print = &_synctex_updater_print; 8117 updater->close = &_synctex_updater_close; 8118 } else { 8119 if (NULL == (updater->file.as_gzFile = gzopen(open.synctex, mode))) { 8120 goto no_write_error; 8121 } 8122 updater->print = &_synctex_updater_print_gz; 8123 updater->close = &_synctex_updater_close_gz; 8124 } 8125 printf("SyncTeX: updating %s...", open.synctex); 8126 _synctex_free(open.synctex); 8127 return updater; 8128 } 8129 8130 void synctex_updater_append_magnification(synctex_updater_p updater, char *magnification) 8131 { 8132 if (NULL == updater) { 8133 return; 8134 } 8135 if (magnification && strlen(magnification)) { 8136 updater->length += updater->print(updater, "Magnification:%s\n", magnification); 8137 } 8138 } 8139 8140 void synctex_updater_append_x_offset(synctex_updater_p updater, char *x_offset) 8141 { 8142 if (NULL == updater) { 8143 return; 8144 } 8145 if (x_offset && strlen(x_offset)) { 8146 updater->length += updater->print(updater, "X Offset:%s\n", x_offset); 8147 } 8148 } 8149 8150 void synctex_updater_append_y_offset(synctex_updater_p updater, char *y_offset) 8151 { 8152 if (NULL == updater) { 8153 return; 8154 } 8155 if (y_offset && strlen(y_offset)) { 8156 updater->length += updater->print(updater, "Y Offset:%s\n", y_offset); 8157 } 8158 } 8159 8160 void synctex_updater_free(synctex_updater_p updater) 8161 { 8162 if (NULL == updater) { 8163 return; 8164 } 8165 if (updater->length > 0) { 8166 updater->print(updater, "!%i\n", updater->length); 8167 } 8168 updater->close(updater); 8169 _synctex_free(updater); 8170 printf("... done.\n"); 8171 return; 8172 } 8173 #endif 8174 8175 #if defined(SYNCTEX_TESTING) 8176 #ifdef SYNCTEX_NOTHING 8177 #pragma mark - 8178 #pragma mark Testers 8179 #endif 8180 static int _synctex_input_copy_name(synctex_node_p input, char *name) 8181 { 8182 char *copy = _synctex_malloc(strlen(name) + 1); 8183 memcpy(copy, name, strlen(name) + 1); 8184 _synctex_data_set_name(input, copy); 8185 return 0; 8186 } 8187 int synctex_test_setup_scanner_sheets_421(synctex_scanner_p scanner) 8188 { 8189 int TC = 0; 8190 synctex_node_p sheet = synctex_node_new(scanner, synctex_node_type_sheet); 8191 _synctex_data_set_page(sheet, 4); 8192 SYNCTEX_TEST_BODY(TC, _synctex_data_page(sheet) == 4, ""); 8193 synctex_node_free(scanner->sheet); 8194 scanner->sheet = sheet; 8195 sheet = synctex_node_new(scanner, synctex_node_type_sheet); 8196 _synctex_data_set_page(sheet, 2); 8197 SYNCTEX_TEST_BODY(TC, _synctex_data_page(sheet) == 2, ""); 8198 __synctex_tree_set_sibling(sheet, scanner->sheet); 8199 scanner->sheet = sheet; 8200 sheet = synctex_node_new(scanner, synctex_node_type_sheet); 8201 _synctex_data_set_page(sheet, 1); 8202 SYNCTEX_TEST_BODY(TC, _synctex_data_page(sheet) == 1, ""); 8203 __synctex_tree_set_sibling(sheet, scanner->sheet); 8204 scanner->sheet = sheet; 8205 return TC; 8206 } 8207 int synctex_test_input(synctex_scanner_p scanner) 8208 { 8209 int TC = 0; 8210 synctex_node_p input = synctex_node_new(scanner, synctex_node_type_input); 8211 _synctex_data_set_tag(input, 421); 8212 SYNCTEX_TEST_BODY(TC, _synctex_data_tag(input) == 421, ""); 8213 _synctex_data_set_tag(input, 124); 8214 SYNCTEX_TEST_BODY(TC, _synctex_data_tag(input) == 124, ""); 8215 _synctex_data_set_line(input, 421); 8216 SYNCTEX_TEST_BODY(TC, _synctex_data_line(input) == 421, ""); 8217 _synctex_data_set_line(input, 214); 8218 SYNCTEX_TEST_BODY(TC, _synctex_data_line(input) == 214, ""); 8219 _synctex_data_set_line(input, 214); 8220 SYNCTEX_TEST_BODY(TC, _synctex_data_line(input) == 214, ""); 8221 _synctex_input_copy_name(input, "214"); 8222 SYNCTEX_TEST_BODY(TC, 0 == memcmp(_synctex_data_name(input), "214", 4), ""); 8223 _synctex_input_copy_name(input, "421421"); 8224 8225 SYNCTEX_TEST_BODY(TC, 0 == memcmp(_synctex_data_name(input), "421421", 4), ""); 8226 synctex_node_free(input); 8227 return TC; 8228 } 8229 int synctex_test_proxy(synctex_scanner_p scanner) 8230 { 8231 int TC = 0; 8232 synctex_node_p proxy = synctex_node_new(scanner, synctex_node_type_proxy); 8233 synctex_node_p target = synctex_node_new(scanner, synctex_node_type_rule); 8234 _synctex_tree_set_target(proxy, target); 8235 _synctex_data_set_tag(target, 421); 8236 SYNCTEX_TEST_BODY(TC, _synctex_data_tag(target) == 421, ""); 8237 SYNCTEX_TEST_BODY(TC, synctex_node_tag(target) == 421, ""); 8238 SYNCTEX_TEST_BODY(TC, synctex_node_tag(proxy) == 421, ""); 8239 synctex_node_free(proxy); 8240 synctex_node_free(target); 8241 return TC; 8242 } 8243 int synctex_test_handle(synctex_scanner_p scanner) 8244 { 8245 int TC = 0; 8246 synctex_node_p handle = synctex_node_new(scanner, synctex_node_type_handle); 8247 synctex_node_p proxy = synctex_node_new(scanner, synctex_node_type_proxy); 8248 synctex_node_p target = synctex_node_new(scanner, synctex_node_type_rule); 8249 _synctex_tree_set_target(handle, target); 8250 _synctex_data_set_tag(target, 421); 8251 SYNCTEX_TEST_BODY(TC, _synctex_data_tag(target) == 421, ""); 8252 SYNCTEX_TEST_BODY(TC, synctex_node_tag(target) == 421, ""); 8253 SYNCTEX_TEST_BODY(TC, synctex_node_tag(handle) == 421, ""); 8254 _synctex_data_set_line(target, 214); 8255 SYNCTEX_TEST_BODY(TC, _synctex_data_line(target) == 214, ""); 8256 SYNCTEX_TEST_BODY(TC, synctex_node_line(target) == 214, ""); 8257 SYNCTEX_TEST_BODY(TC, synctex_node_line(handle) == 214, ""); 8258 _synctex_data_set_column(target, 142); 8259 SYNCTEX_TEST_BODY(TC, _synctex_data_column(target) == 142, ""); 8260 SYNCTEX_TEST_BODY(TC, synctex_node_column(target) == 142, ""); 8261 SYNCTEX_TEST_BODY(TC, synctex_node_column(handle) == 142, ""); 8262 _synctex_tree_set_target(proxy, target); 8263 _synctex_tree_set_target(handle, proxy); 8264 _synctex_data_set_tag(target, 412); 8265 SYNCTEX_TEST_BODY(TC, _synctex_data_tag(target) == 412, ""); 8266 SYNCTEX_TEST_BODY(TC, synctex_node_tag(target) == 412, ""); 8267 SYNCTEX_TEST_BODY(TC, synctex_node_tag(handle) == 412, ""); 8268 _synctex_data_set_line(target, 124); 8269 SYNCTEX_TEST_BODY(TC, _synctex_data_line(target) == 124, ""); 8270 SYNCTEX_TEST_BODY(TC, synctex_node_line(target) == 124, ""); 8271 SYNCTEX_TEST_BODY(TC, synctex_node_line(handle) == 124, ""); 8272 _synctex_data_set_column(target, 241); 8273 SYNCTEX_TEST_BODY(TC, _synctex_data_column(target) == 241, ""); 8274 SYNCTEX_TEST_BODY(TC, synctex_node_column(target) == 241, ""); 8275 SYNCTEX_TEST_BODY(TC, synctex_node_column(handle) == 241, ""); 8276 synctex_node_free(handle); 8277 synctex_node_free(proxy); 8278 synctex_node_free(target); 8279 return TC; 8280 } 8281 int synctex_test_setup_scanner_input(synctex_scanner_p scanner) 8282 { 8283 int TC = 0; 8284 synctex_node_p input = synctex_node_new(scanner, synctex_node_type_input); 8285 _synctex_data_set_tag(input, 4); 8286 _synctex_input_copy_name(input, "21"); 8287 _synctex_data_set_line(input, 421); 8288 synctex_node_free(scanner->input); 8289 scanner->input = input; 8290 SYNCTEX_TEST_BODY(TC, _synctex_data_tag(input) == 4, ""); 8291 SYNCTEX_TEST_BODY(TC, strcmp(_synctex_data_name(input), "21") == 0, ""); 8292 SYNCTEX_TEST_BODY(TC, _synctex_data_line(input) == 421, ""); 8293 return TC; 8294 } 8295 int synctex_test_setup_nodes(synctex_scanner_p scanner, synctex_node_r nodes) 8296 { 8297 int TC = 0; 8298 int n; 8299 for (n = 0; n < synctex_node_number_of_types; ++n) { 8300 nodes[n] = synctex_node_new(scanner, n); 8301 SYNCTEX_TEST_BODY(TC, nodes[n] != NULL, ""); 8302 } 8303 return TC; 8304 } 8305 int synctex_test_teardown_nodes(synctex_scanner_p scanner, synctex_node_r nodes) 8306 { 8307 int n; 8308 for (n = 0; n < synctex_node_number_of_types; ++n) { 8309 synctex_node_free(nodes[n]); 8310 nodes[n] = NULL; 8311 } 8312 return 1; 8313 } 8314 int synctex_test_tree(synctex_scanner_p scanner) 8315 { 8316 int TC = 0; 8317 synctex_node_p nodes1[synctex_node_number_of_types]; 8318 synctex_node_p nodes2[synctex_node_number_of_types]; 8319 synctex_node_p nodes3[synctex_node_number_of_types]; 8320 int i, j; 8321 TC += synctex_test_setup_nodes(scanner, nodes1); 8322 TC += synctex_test_setup_nodes(scanner, nodes2); 8323 TC += synctex_test_setup_nodes(scanner, nodes3); 8324 /* Every node has a sibling */ 8325 for (i = 0; i < synctex_node_number_of_types; ++i) { 8326 for (j = 0; j < synctex_node_number_of_types; ++j) { 8327 _synctex_tree_set_sibling(nodes1[i], nodes2[i]); 8328 SYNCTEX_TEST_BODY(TC, nodes2[i] == synctex_node_sibling(nodes1[i]), ""); 8329 } 8330 } 8331 synctex_test_teardown_nodes(scanner, nodes3); 8332 synctex_test_teardown_nodes(scanner, nodes2); 8333 synctex_test_teardown_nodes(scanner, nodes1); 8334 return TC; 8335 } 8336 int synctex_test_page(synctex_scanner_p scanner) 8337 { 8338 int TC = synctex_test_setup_scanner_sheets_421(scanner); 8339 synctex_node_p sheet = scanner->sheet; 8340 synctex_node_p node = synctex_node_new(scanner, synctex_node_type_rule); 8341 _synctex_data_set_tag(node, 4); 8342 _synctex_data_set_line(node, 21); 8343 synctex_node_free(_synctex_node_set_child(sheet, node)); 8344 SYNCTEX_TEST_BODY(TC, synctex_node_page(node) == synctex_node_page(sheet), ""); 8345 return TC; 8346 } 8347 int synctex_test_display_query(synctex_scanner_p scanner) 8348 { 8349 int TC = synctex_test_setup_scanner_sheets_421(scanner); 8350 synctex_node_p sheet = scanner->sheet; 8351 synctex_node_p node = synctex_node_new(scanner, synctex_node_type_rule); 8352 _synctex_data_set_tag(node, 4); 8353 _synctex_data_set_line(node, 21); 8354 synctex_node_free(_synctex_node_set_child(sheet, node)); 8355 SYNCTEX_TEST_BODY(TC, node == synctex_node_child(sheet), ""); 8356 __synctex_node_make_friend_tlc(node); 8357 SYNCTEX_TEST_BODY(TC, _synctex_scanner_friend(scanner, 25) == node, ""); 8358 sheet = __synctex_tree_sibling(sheet); 8359 node = synctex_node_new(scanner, synctex_node_type_rule); 8360 _synctex_data_set_tag(node, 4); 8361 _synctex_data_set_line(node, 21); 8362 synctex_node_free(_synctex_node_set_child(sheet, node)); 8363 SYNCTEX_TEST_BODY(TC, node == synctex_node_child(sheet), ""); 8364 __synctex_node_make_friend_tlc(node); 8365 SYNCTEX_TEST_BODY(TC, _synctex_scanner_friend(scanner, 25) == node, ""); 8366 sheet = __synctex_tree_sibling(sheet); 8367 node = synctex_node_new(scanner, synctex_node_type_rule); 8368 _synctex_data_set_tag(node, 4); 8369 _synctex_data_set_line(node, 21); 8370 synctex_node_free(_synctex_node_set_child(sheet, node)); 8371 SYNCTEX_TEST_BODY(TC, node == synctex_node_child(sheet), ""); 8372 __synctex_node_make_friend_tlc(node); 8373 SYNCTEX_TEST_BODY(TC, (_synctex_scanner_friend(scanner, 25) == node), ""); 8374 synctex_test_setup_scanner_input(scanner); 8375 scanner->flags.has_parsed = synctex_YES; 8376 #if 1 8377 SYNCTEX_TEST_BODY(TC, (synctex_display_query(scanner, "21", 21, 4, -1) == 3), ""); 8378 #endif 8379 return TC; 8380 } 8381 typedef struct { 8382 int s; /* status */ 8383 char n[25]; /* name */ 8384 } synctex_test_sn_s; 8385 8386 synctex_test_sn_s synctex_test_tmp_sn(char *content) 8387 { 8388 synctex_test_sn_s sn = {0, "/tmp/test.XXXXXX.synctex"}; 8389 FILE *sfp; 8390 int fd = mkstemps(sn.n, 8); 8391 if (fd < 0) { 8392 fprintf(stderr, "%s: %s\n", sn.n, strerror(errno)); 8393 sn.s = -1; 8394 return sn; 8395 } 8396 if ((sfp = fdopen(fd, "w+")) == NULL) { 8397 unlink(sn.n); 8398 close(fd); 8399 fprintf(stderr, "%s: %s\n", sn.n, strerror(errno)); 8400 sn.s = -2; 8401 return sn; 8402 } 8403 sn.s = fputs(content, sfp); 8404 printf("temp:%s\n%i\n", sn.n, sn.s); 8405 fclose(sfp); 8406 if (sn.s == 0) { 8407 sn.s = -2; 8408 unlink(sn.n); 8409 } 8410 return sn; 8411 } 8412 int synctex_test_sheet_1() 8413 { 8414 int TC = 0; 8415 char *content = 8416 "SyncTeX Version:1 \n" /*00-19*/ 8417 "Input:1:./1.tex \n" /*20-39*/ 8418 "Output:pdf \n" /*40-59*/ 8419 "Magnification:100000000 \n" /*60-89*/ 8420 "Unit:1 \n" /*90-99*/ 8421 "X Offset:0 \n" /*00-19*/ 8422 "Y Offset:0 \n" /*20-39*/ 8423 "Content: \n" /*40-49*/ 8424 "{1 \n" /*50-59*/ 8425 "[1,10:20,350:330,330,0 \n" /*60-89*/ 8426 "] \n" /*90-99*/ 8427 "} \n" /*00-09*/ 8428 "Postamble:\n"; 8429 synctex_test_sn_s sn = synctex_test_tmp_sn(content); 8430 if (sn.s > 0) { 8431 synctex_scanner_p scanner = synctex_scanner_new_with_output_file(sn.n, NULL, synctex_YES); 8432 synctex_node_p node = synctex_scanner_handle(scanner); 8433 printf("Created nodes:\n"); 8434 while (node) { 8435 printf("%s\n", _synctex_node_abstract(node)); 8436 node = synctex_node_next(node); 8437 } 8438 synctex_scanner_free(scanner); 8439 unlink(sn.n); 8440 } else { 8441 ++TC; 8442 } 8443 return TC; 8444 } 8445 int synctex_test_sheet_2() 8446 { 8447 int TC = 0; 8448 char *content = 8449 "SyncTeX Version:1 \n" /*00-19*/ 8450 "Input:1:./1.tex \n" /*20-39*/ 8451 "Output:pdf \n" /*40-59*/ 8452 "Magnification:100000000 \n" /*60-89*/ 8453 "Unit:1 \n" /*90-99*/ 8454 "X Offset:0 \n" /*00-19*/ 8455 "Y Offset:0 \n" /*20-39*/ 8456 "Content: \n" /*40-49*/ 8457 "{1 \n" /*50-59*/ 8458 "(1,10:20,350:330,330,0 \n" /*60-89*/ 8459 ") \n" /*90-99*/ 8460 "} \n" /*00-09*/ 8461 "Postamble:\n"; 8462 synctex_test_sn_s sn = synctex_test_tmp_sn(content); 8463 if (sn.s > 0) { 8464 synctex_scanner_p scanner = synctex_scanner_new_with_output_file(sn.n, NULL, synctex_YES); 8465 synctex_node_p node = synctex_scanner_handle(scanner); 8466 printf("Created nodes:\n"); 8467 while (node) { 8468 printf("%s\n", _synctex_node_abstract(node)); 8469 node = _synctex_node_next(node); 8470 } 8471 TC += synctex_scanner_free(scanner); 8472 unlink(sn.n); 8473 } else { 8474 ++TC; 8475 } 8476 return TC; 8477 } 8478 int synctex_test_charindex() 8479 { 8480 int TC = 0; 8481 char *content = 8482 "SyncTeX Version:1 \n" /*00-19*/ 8483 "Input:1:./1.tex \n" /*20-39*/ 8484 "Output:pdf \n" /*40-59*/ 8485 "Magnification:100000000 \n" /*60-89*/ 8486 "Unit:1 \n" /*90-99*/ 8487 "X Offset:0 \n" /*00-19*/ 8488 "Y Offset:0 \n" /*20-39*/ 8489 "Content: \n" /*40-49*/ 8490 "{1 \n" /*50-59*/ 8491 "[1,10:20,350:330,330,0 \n" /*60-89*/ 8492 "(1,58:20,100:250,10,5 \n" /*90-119*/ 8493 "f1000:50,100 \n" /*20-39*/ 8494 ") \n" /*40-49*/ 8495 "] \n" /*50-59*/ 8496 "} \n" /*60-69*/ 8497 "Postamble:\n"; 8498 synctex_test_sn_s sn = synctex_test_tmp_sn(content); 8499 if (sn.s > 0) { 8500 synctex_scanner_p scanner = synctex_scanner_new_with_output_file(sn.n, NULL, synctex_YES); 8501 synctex_node_p node = synctex_scanner_handle(scanner); 8502 printf("Created nodes:\n"); 8503 while (node) { 8504 printf("%s\n", _synctex_node_abstract(node)); 8505 node = synctex_node_next(node); 8506 } 8507 TC += synctex_scanner_free(scanner); 8508 unlink(sn.n); 8509 } else { 8510 ++TC; 8511 } 8512 return TC; 8513 } 8514 int synctex_test_form() 8515 { 8516 int TC = 0; 8517 char *content = 8518 "SyncTeX Version:1 \n" /*00-19*/ 8519 "Input:1:./1.tex \n" /*20-39*/ 8520 "Output:pdf \n" /*40-59*/ 8521 "Magnification:100000000 \n" /*60-89*/ 8522 "Unit:1 \n" /*90-99*/ 8523 "X Offset:0 \n" /*00-19*/ 8524 "Y Offset:0 \n" /*20-39*/ 8525 "Content: \n" /*40-49*/ 8526 "{1 \n" /*50-59*/ 8527 "[1,10:20,350:330,330,0 \n" /*60-89*/ 8528 "(1,58:20,100:250,10,5 \n" /*90-119*/ 8529 "f1000:50,100 \n" /*20-39*/ 8530 ") \n" /*40-49*/ 8531 "] \n" /*50-59*/ 8532 "} \n" /*60-69*/ 8533 "<1000 \n" /*70-79*/ 8534 "(1,63:0,0:100,8,3 \n" /*80-99*/ 8535 ") \n" /*00-09*/ 8536 "> \n" /*10-19*/ 8537 "Postamble:\n"; 8538 synctex_test_sn_s sn = synctex_test_tmp_sn(content); 8539 if (sn.s > 0) { 8540 synctex_scanner_p scanner = synctex_scanner_new_with_output_file(sn.n, NULL, synctex_YES); 8541 synctex_node_p node = synctex_scanner_handle(scanner); 8542 while (node) { 8543 printf("%s\n", _synctex_node_abstract(node)); 8544 node = _synctex_node_next(node); 8545 } 8546 TC += synctex_scanner_free(scanner); 8547 unlink(sn.n); 8548 } else { 8549 ++TC; 8550 } 8551 return TC; 8552 } 8553 #endif