/* SPDX-FileCopyrightText: 2008-2017 jerome DOT laurens AT u-bourgogne DOT fr SPDX-License-Identifier: X11 This file is part of the __SyncTeX__ package. [//]: # (Latest Revision: Fri Jul 14 16:20:41 UTC 2017) [//]: # (Version: 1.19) See `synctex_parser_readme.md` for more details */ #include "synctex_parser.h" #include "synctex_parser_utils.h" #ifndef __SYNCTEX_PARSER_PRIVATE__ #define __SYNCTEX_PARSER_PRIVATE__ #ifdef __cplusplus extern "C" { #endif /* Reminder that the argument must not be NULL */ typedef synctex_node_p synctex_non_null_node_p; /* Each node of the tree, except the scanner itself belongs to a class. * The class object is just a struct declaring the owning scanner * This is a pointer to the scanner as root of the tree. * The type is used to identify the kind of node. * The class declares pointers to a creator and a destructor method. * The log and display fields are used to log and display the node. * display will also display the child, sibling and parent sibling. * parent, child and sibling are used to navigate the tree, * from TeX box hierarchy point of view. * The friend field points to a method which allows to navigate from friend to friend. * A friend is a node with very close tag and line numbers. * Finally, the info field point to a method giving the private node info offset. */ /** * These are the masks for the synctex node types. * int's are 32 bits at least. */ enum { synctex_shift_root, synctex_shift_no_root, synctex_shift_void, synctex_shift_no_void, synctex_shift_box, synctex_shift_no_box, synctex_shift_proxy, synctex_shift_no_proxy, synctex_shift_h, synctex_shift_v }; enum { synctex_mask_root = 1, synctex_mask_no_root = synctex_mask_root << 1, synctex_mask_void = synctex_mask_no_root << 1, synctex_mask_no_void = synctex_mask_void << 1, synctex_mask_box = synctex_mask_no_void << 1, synctex_mask_no_box = synctex_mask_box << 1, synctex_mask_proxy = synctex_mask_no_box << 1, synctex_mask_no_proxy = synctex_mask_proxy << 1, synctex_mask_h = synctex_mask_no_proxy << 1, synctex_mask_v = synctex_mask_h << 1, }; enum { synctex_mask_non_void_hbox = synctex_mask_no_void | synctex_mask_box | synctex_mask_h, synctex_mask_non_void_vbox = synctex_mask_no_void | synctex_mask_box | synctex_mask_v }; typedef enum { synctex_node_mask_sf = synctex_mask_root | synctex_mask_no_void | synctex_mask_no_box | synctex_mask_no_proxy, synctex_node_mask_vbox = synctex_mask_no_root | synctex_mask_no_void | synctex_mask_box | synctex_mask_no_proxy | synctex_mask_v, synctex_node_mask_hbox = synctex_mask_no_root | synctex_mask_no_void | synctex_mask_box | synctex_mask_no_proxy | synctex_mask_h, synctex_node_mask_void_vbox = synctex_mask_no_root | synctex_mask_void | synctex_mask_box | synctex_mask_no_proxy | synctex_mask_v, synctex_node_mask_void_hbox = synctex_mask_no_root | synctex_mask_void | synctex_mask_box | synctex_mask_no_proxy | synctex_mask_h, synctex_node_mask_vbox_proxy = synctex_mask_no_root | synctex_mask_no_void | synctex_mask_box | synctex_mask_proxy | synctex_mask_v, synctex_node_mask_hbox_proxy = synctex_mask_no_root | synctex_mask_no_void | synctex_mask_box | synctex_mask_proxy | synctex_mask_h, synctex_node_mask_nvnn = synctex_mask_no_root | synctex_mask_void | synctex_mask_no_box | synctex_mask_no_proxy, synctex_node_mask_input = synctex_mask_root | synctex_mask_void | synctex_mask_no_box | synctex_mask_no_proxy, synctex_node_mask_proxy = synctex_mask_no_root | synctex_mask_void | synctex_mask_no_box | synctex_mask_proxy } synctex_node_mask_t; enum { /* input */ synctex_tree_sibling_idx = 0, synctex_tree_s_input_max = 1, /* All */ synctex_tree_s_parent_idx = 1, synctex_tree_sp_child_idx = 2, synctex_tree_spc_friend_idx = 3, synctex_tree_spcf_last_idx = 4, synctex_tree_spcfl_vbox_max = 5, /* hbox supplement */ synctex_tree_spcfl_next_hbox_idx = 5, synctex_tree_spcfln_hbox_max = 6, /* hbox proxy supplement */ synctex_tree_spcfln_target_idx = 6, synctex_tree_spcflnt_proxy_hbox_max = 7, /* vbox proxy supplement */ synctex_tree_spcfl_target_idx = 5, synctex_tree_spcflt_proxy_vbox_max = 6, /* spf supplement*/ synctex_tree_sp_friend_idx = 2, synctex_tree_spf_max = 3, /* box boundary supplement */ synctex_tree_spf_arg_sibling_idx = 3, synctex_tree_spfa_max = 4, /* proxy supplement */ synctex_tree_spf_target_idx = 3, synctex_tree_spft_proxy_max = 4, /* last proxy supplement */ synctex_tree_spfa_target_idx = 4, synctex_tree_spfat_proxy_last_max = 5, /* sheet supplement */ synctex_tree_s_child_idx = 1, synctex_tree_sc_next_hbox_idx = 2, synctex_tree_scn_sheet_max = 3, /* form supplement */ synctex_tree_sc_target_idx = 2, synctex_tree_sct_form_max = 3, /* spct */ synctex_tree_spc_target_idx = 3, synctex_tree_spct_handle_max = 4, }; enum { /* input */ synctex_data_input_tag_idx = 0, synctex_data_input_line_idx = 1, synctex_data_input_name_idx = 2, synctex_data_input_tln_max = 3, /* sheet */ synctex_data_sheet_page_idx = 0, synctex_data_p_sheet_max = 1, /* form */ synctex_data_form_tag_idx = 0, synctex_data_t_form_max = 1, /* tlchv */ synctex_data_tag_idx = 0, synctex_data_line_idx = 1, synctex_data_column_idx = 2, synctex_data_h_idx = 3, synctex_data_v_idx = 4, synctex_data_tlchv_max = 5, /* tlchvw */ synctex_data_width_idx = 5, synctex_data_tlchvw_max = 6, /* box */ synctex_data_height_idx = 6, synctex_data_depth_idx = 7, synctex_data_box_max = 8, /* hbox supplement */ synctex_data_mean_line_idx = 8, synctex_data_weight_idx = 9, synctex_data_h_V_idx = 10, synctex_data_v_V_idx = 11, synctex_data_width_V_idx = 12, synctex_data_height_V_idx = 13, synctex_data_depth_V_idx = 14, synctex_data_hbox_max = 15, /* ref */ synctex_data_ref_tag_idx = 0, synctex_data_ref_h_idx = 1, synctex_data_ref_v_idx = 2, synctex_data_ref_thv_max = 3, /* proxy */ synctex_data_proxy_h_idx = 0, synctex_data_proxy_v_idx = 1, synctex_data_proxy_hv_max = 2, }; /* each synctex node has a class */ typedef struct synctex_class_t synctex_class_s; typedef synctex_class_s *synctex_class_p; /* synctex_node_p is a pointer to a node * synctex_node_s is the target of the synctex_node_p pointer * It is a pseudo object oriented program. * class is a pointer to the class object the node belongs to. * implementation is meant to contain the private data of the node * basically, there are 2 kinds of information: navigation information and * synctex information. Both will depend on the type of the node, * thus different nodes will have different private data. * There is no inheritancy overhead. */ typedef union { synctex_node_p as_node; int as_integer; char *as_string; void *as_pointer; } synctex_data_u; typedef synctex_data_u *synctex_data_p; #if defined(SYNCTEX_USE_CHARINDEX) typedef unsigned int synctex_charindex_t; synctex_charindex_t synctex_node_charindex(synctex_node_p node); typedef synctex_charindex_t synctex_lineindex_t; synctex_lineindex_t synctex_node_lineindex(synctex_node_p node); synctex_node_p synctex_scanner_handle(synctex_scanner_p scanner); #define SYNCTEX_DECLARE_CHARINDEX \ synctex_charindex_t char_index; \ synctex_lineindex_t line_index; #define SYNCTEX_DECLARE_CHAR_OFFSET synctex_charindex_t charindex_offset; #else #define SYNCTEX_DECLARE_CHARINDEX #define SYNCTEX_DECLARE_CHAR_OFFSET #endif struct synctex_node_t { SYNCTEX_DECLARE_CHARINDEX synctex_class_p class; #ifdef DEBUG synctex_data_u data[22]; #else synctex_data_u data[1]; #endif }; typedef synctex_node_p *synctex_node_r; typedef struct { int h; int v; } synctex_point_s; typedef synctex_point_s *synctex_point_p; typedef struct { synctex_point_s min; /* top left */ synctex_point_s max; /* bottom right */ } synctex_box_s; typedef synctex_box_s *synctex_box_p; /** * These are the types of the synctex nodes. * No need to use them but the compiler needs them here. * There are 3 kinds of nodes. * - primary nodes * - proxies * - handles * Primary nodes are created at parse time * of the synctex file. * Proxies are used to support pdf forms. * The ref primary nodes are replaced by a tree * of proxy nodes which duplicate the tree of primary * nodes available in the referred form. * Roughly speaking, the primary nodes of the form * know what to display, the proxy nodes know where. * Handles are used in queries. They point to either * primary nodes or proxies. */ typedef enum { synctex_node_type_none = 0, synctex_node_type_input, synctex_node_type_sheet, synctex_node_type_form, synctex_node_type_ref, synctex_node_type_vbox, synctex_node_type_void_vbox, synctex_node_type_hbox, synctex_node_type_void_hbox, synctex_node_type_kern, synctex_node_type_glue, synctex_node_type_rule, synctex_node_type_math, synctex_node_type_boundary, synctex_node_type_box_bdry, synctex_node_type_proxy, synctex_node_type_proxy_last, synctex_node_type_proxy_vbox, synctex_node_type_proxy_hbox, synctex_node_type_handle, synctex_node_number_of_types } synctex_node_type_t; /* synctex_node_type gives the type of a given node, * synctex_node_isa gives the same information as a human readable text. */ synctex_node_type_t synctex_node_type(synctex_node_p node); const char *synctex_node_isa(synctex_node_p node); synctex_node_type_t synctex_node_target_type(synctex_node_p node); synctex_node_type_t synctex_node_type(synctex_node_p node); const char *synctex_node_isa(synctex_node_p node); void synctex_node_log(synctex_node_p node); void synctex_node_display(synctex_node_p node); /* Given a node, access to the location in the synctex file where it is defined. */ int synctex_node_form_tag(synctex_node_p node); int synctex_node_mean_line(synctex_node_p node); int synctex_node_weight(synctex_node_p node); int synctex_node_child_count(synctex_node_p node); int synctex_node_h(synctex_node_p node); int synctex_node_v(synctex_node_p node); int synctex_node_width(synctex_node_p node); int synctex_node_box_h(synctex_node_p node); int synctex_node_box_v(synctex_node_p node); int synctex_node_box_width(synctex_node_p node); int synctex_node_box_height(synctex_node_p node); int synctex_node_box_depth(synctex_node_p node); int synctex_node_hbox_h(synctex_node_p node); int synctex_node_hbox_v(synctex_node_p node); int synctex_node_hbox_width(synctex_node_p node); int synctex_node_hbox_height(synctex_node_p node); int synctex_node_hbox_depth(synctex_node_p node); synctex_scanner_p synctex_scanner_new(); synctex_node_p synctex_node_new(synctex_scanner_p scanner, synctex_node_type_t type); /** * Scanner display switcher getter. * If the switcher is 0, synctex_node_display is disabled. * If the switcher is <0, synctex_node_display has no limit. * If the switcher is >0, only the first switcher (as number) nodes are displayed. * - parameter: a scanner * - returns: an integer */ int synctex_scanner_display_switcher(synctex_scanner_p scanR); void synctex_scanner_set_display_switcher(synctex_scanner_p scanR, int switcher); /** * Iterator is the structure used to traverse * the answer to client queries. * First answers are the best matches, according * to criteria explained below. * Next answers are not ordered. * Objects are handles to nodes in the synctex node tree starting at scanner. */ typedef struct synctex_iterator_t synctex_iterator_s; typedef synctex_iterator_s *synctex_iterator_p; /** * Designated creator for a display query, id est, * forward navigation from source to output. * Returns NULL if the query has no answer. * Code example: * synctex_iterator_p iterator = NULL; * if ((iterator = synctex_iterator_new_display(...)) { * synctex_node_p node = NULL; * while((node = synctex_iterator_next_result(iterator))) { * do something with node... * } */ synctex_iterator_p synctex_iterator_new_display(synctex_scanner_p scanner, const char *name, int line, int column, int page_hint); /** * Designated creator for an edit query, id est, * backward navigation from output to source. * Code example: * synctex_iterator_p iterator = NULL; * if ((iterator = synctex_iterator_new_edit(...)) { * synctex_node_p node = NULL; * while((node = synctex_iterator_next_result(iterator))) { * do something with node... * } */ synctex_iterator_p synctex_iterator_new_edit(synctex_scanner_p scanner, int page, float h, float v); /** * Free all the resources. * - argument iterator: the object to free... * You should free the iterator before the scanner * owning the nodes it iterates with. */ void synctex_iterator_free(synctex_iterator_p iterator); /** * Whether the iterator actually points to an object. * - argument iterator: the object to iterate on... */ synctex_bool_t synctex_iterator_has_next(synctex_iterator_p iterator); /** * Returns the pointed object and advance the cursor * to the next object. Returns NULL and does nothing * if the end has already been reached. * - argument iterator: the object to iterate on... */ synctex_node_p synctex_iterator_next_result(synctex_iterator_p iterator); /** * Reset the cursor position to the first result. * - argument iterator: the object to iterate on... */ int synctex_iterator_reset(synctex_iterator_p iterator); /** * The number of objects left for traversal. * - argument iterator: the object to iterate on... */ int synctex_iterator_count(synctex_iterator_p iterator); /** * The target of the node, either a handle or a proxy. */ synctex_node_p synctex_node_target(synctex_node_p node); #ifndef SYNCTEX_NO_UPDATER /* The main synctex updater object. * This object is used to append information to the synctex file. * Its implementation is considered private. * It is used by the synctex command line tool to take into account modifications * that could occur while postprocessing files by dvipdf like filters. */ typedef struct synctex_updater_t synctex_updater_s; typedef synctex_updater_s *synctex_updater_p; /* Designated initializer. * Once you are done with your whole job, * free the updater */ synctex_updater_p synctex_updater_new_with_output_file(const char *output, const char *directory); /* Use the next functions to append records to the synctex file, * no consistency tests made on the arguments */ void synctex_updater_append_magnification(synctex_updater_p updater, char *magnification); void synctex_updater_append_x_offset(synctex_updater_p updater, char *x_offset); void synctex_updater_append_y_offset(synctex_updater_p updater, char *y_offset); /* You MUST free the updater, once everything is properly appended */ void synctex_updater_free(synctex_updater_p updater); #endif #if defined(SYNCTEX_DEBUG) #include "assert.h" #define SYNCTEX_ASSERT assert #else #define SYNCTEX_ASSERT(UNUSED) #endif #if defined(SYNCTEX_TESTING) #warning TESTING IS PROHIBITED #if __clang__ #define __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wformat-extra-args\"") #define __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS _Pragma("clang diagnostic pop") #else #define __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS #define __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS #endif #define SYNCTEX_TEST_BODY(counter, condition, desc, ...) \ do { \ __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \ if (!(condition)) { \ ++counter; \ printf("**** Test failed: %s\nfile %s\nfunction %s\nline %i\n", #condition, __FILE__, __FUNCTION__, __LINE__); \ printf((desc), ##__VA_ARGS__); \ } \ __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \ } while (0) #define SYNCTEX_TEST_PARAMETER(counter, condition) SYNCTEX_TEST_BODY(counter, (condition), "Invalid parameter not satisfying: %s", #condition) int synctex_test_input(synctex_scanner_p scanner); int synctex_test_proxy(synctex_scanner_p scanner); int synctex_test_tree(synctex_scanner_p scanner); int synctex_test_page(synctex_scanner_p scanner); int synctex_test_handle(synctex_scanner_p scanner); int synctex_test_display_query(synctex_scanner_p scanner); int synctex_test_charindex(); int synctex_test_sheet_1(); int synctex_test_sheet_2(); int synctex_test_sheet_3(); int synctex_test_form(); #endif #ifdef __cplusplus } #endif #endif