diff options
Diffstat (limited to 'Build/source/texk/web2c/synctex/synctex_parser.c')
-rw-r--r-- | Build/source/texk/web2c/synctex/synctex_parser.c | 2602 |
1 files changed, 2602 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/synctex/synctex_parser.c b/Build/source/texk/web2c/synctex/synctex_parser.c new file mode 100644 index 00000000000..f68e32d99d7 --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex_parser.c @@ -0,0 +1,2602 @@ +/* +Copyright (c) 2008 jerome DOT laurens AT u-bourgogne DOT fr + +This file is part of the SyncTeX package. + +License: +-------- +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE + +Except as contained in this notice, the name of the copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written +authorization from the copyright holder. + +*/ + +#include "stddef.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "limits.h" +#include "time.h" +#include "math.h" +#include "errno.h" + +/* This custom malloc functions initializes to 0 the newly allocated memory. */ +void *_synctex_malloc(size_t size) { + void * ptr = malloc(size); + if(ptr) { + memset(ptr,0,size); + } + return (void *)ptr; +} + +/* The data is organized in a graph with multiple entries. + * The root object is a scanner, it is created with the contents on a synctex file. + * Each leaf of the tree is a synctex_node_t object. + * There are 3 subtrees, two of them sharing the same leaves. + * The first tree is the list of input records, where input file names are associated with tags. + * The second tree is the box tree as given by TeX when shipping pages out. + * First level objects are sheets, containing boxes, glues, kerns... + * The third tree allows to browse leaves according to tag and line. + */ + +#include "synctex_parser.h" + +/* each synctex node has a class */ +typedef struct __synctex_class_t _synctex_class_t; +typedef _synctex_class_t * synctex_class_t; + + +/* synctex_node_t is a pointer to a node + * _synctex_node is the target of the synctex_node_t 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. + */ +struct _synctex_node { + synctex_class_t class; + int * implementation; +}; + +/* 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. + */ +typedef synctex_node_t *(*_synctex_node_getter_t)(synctex_node_t); +typedef int *(*_synctex_int_getter_t)(synctex_node_t); + +struct __synctex_class_t { + synctex_scanner_t scanner; + int type; + synctex_node_t (*new)(synctex_scanner_t scanner); + void (*free)(synctex_node_t); + void (*log)(synctex_node_t); + void (*display)(synctex_node_t); + _synctex_node_getter_t parent; + _synctex_node_getter_t child; + _synctex_node_getter_t sibling; + _synctex_node_getter_t friend; + _synctex_int_getter_t info; +}; + +# pragma mark - +# pragma mark Abstract OBJECTS and METHODS + +/* These macros are shortcuts + * INFO(node) points to the first synctex integer data of node + * INFO(node)[index] is the information at index + */ +# define INFO(NODE) ((*((((NODE)->class))->info))(NODE)) + +/* This macro checks if a message can be sent. + */ +# define CAN_PERFORM(NODE,SELECTOR)\ + (NULL!=((((NODE)->class))->SELECTOR)) + +/* This macro is some kind of objc_msg_send. + * It takes care of sending the proper message if possible. + */ +# define MSG_SEND(NODE,SELECTOR) if(NODE && CAN_PERFORM(NODE,SELECTOR)) {\ + (*((((NODE)->class))->SELECTOR))(NODE);\ + } + +/* read only safe getter + */ +# define GET(NODE,SELECTOR)((NODE && CAN_PERFORM(NODE,SELECTOR))?GETTER(NODE,SELECTOR)[0]:(NULL)) + +/* read/write getter + */ +# define GETTER(NODE,SELECTOR)\ + ((synctex_node_t *)((*((((NODE)->class))->SELECTOR))(NODE))) + +# define FREE(NODE) MSG_SEND(NODE,free); + +/* Parent getter and setter + */ +# define PARENT(NODE) GET(NODE,parent) +# define SET_PARENT(NODE,NEW_PARENT) if(NODE && NEW_PARENT && CAN_PERFORM(NODE,parent)){\ + GETTER(NODE,parent)[0]=NEW_PARENT;\ + } + +/* Child getter and setter + */ +# define CHILD(NODE) GET(NODE,child) +# define SET_CHILD(NODE,NEW_CHILD) if(NODE && NEW_CHILD){\ + GETTER(NODE,child)[0]=NEW_CHILD;\ + GETTER(NEW_CHILD,parent)[0]=NODE;\ + } + +/* Sibling getter and setter + */ +# define SIBLING(NODE) GET(NODE,sibling) +# define SET_SIBLING(NODE,NEW_SIBLING) if(NODE && NEW_SIBLING) {\ + GETTER(NODE,sibling)[0]=NEW_SIBLING;\ + if(CAN_PERFORM(NEW_SIBLING,parent) && CAN_PERFORM(NODE,parent)) {\ + GETTER(NEW_SIBLING,parent)[0]=GETTER(NODE,parent)[0];\ + }\ + } +/* Friend getter and setter + */ +# define FRIEND(NODE) GET(NODE,friend) +# define SET_FRIEND(NODE,NEW_FRIEND) if(NODE && NEW_FRIEND){\ + GETTER(NODE,friend)[0]=NEW_FRIEND;\ + } + +/* A node is meant to own its child and sibling. + * It is not owned by its parent, unless it is its first child. + * This destructor is for all nodes. + */ +void _synctex_free_node(synctex_node_t node) { + if(node) { + (*((node->class)->sibling))(node); + FREE(SIBLING(node)); + FREE(CHILD(node)); + free(node); + } + return; +} + +/* A node is meant to own its child and sibling. + * It is not owned by its parent, unless it is its first child. + * This destructor is for nodes with no child. + */ +void _synctex_free_leaf(synctex_node_t node) { + if(node) { + FREE(SIBLING(node)); + free(node); + } + return; +} + +/* The synctex scanner is the root object. + * Is is initiated with the contents of a text file. + * The buffer_? are first used to parse the text. + */ +struct __synctex_scanner_t { + unsigned char * buffer_ptr; /* current location in the buffer */ + unsigned char * buffer_start; /* start of the buffer */ + unsigned char * buffer_end; /* end of the buffer */ + char * output; /* dvi or pdf, not yet used */ + int version; /* 1, not yet used */ + int pre_magnification; /* magnification from the synctex preamble */ + int pre_unit; /* unit from the synctex preamble */ + int pre_x_offset; /* X offste from the synctex preamble */ + int pre_y_offset; /* Y offset from the synctex preamble */ + int count; /* Number of records, from the synctex postamble */ + float unit; /* real unit, from synctex preamble or post scriptum */ + float x_offset; /* X offset, from synctex preamble or post scriptum */ + float y_offset; /* Y Offset, from synctex preamble or post scriptum */ + synctex_node_t sheet; /* The first sheet node */ + synctex_node_t input; /* The first input node */ + int number_of_lists; /* The number of friend lists */ + synctex_node_t * lists_of_friends;/* The friend lists */ + _synctex_class_t class[synctex_node_type_last]; /* The classes of the nodes of the scanner */ +}; + +/* PTR, START and END are convenient shortcuts + */ +# define PTR (scanner->buffer_ptr) +# define START (scanner->buffer_start) +# define END (scanner->buffer_end) + +# pragma mark - +# pragma mark OBJECTS, their creators and destructors. + +/* The sheet is a first level node. + * It has no parent (the parent is the scanner itself) + * Its sibling points to another sheet. + * Its child points to its first child, in general a box. + * A sheet node contains only one synctex information: the page. + * This is the 1 based page index as given by TeX. + */ +typedef struct { + synctex_class_t class; + int implementation[2+1];/* child, sibling + * PAGE */ +} synctex_sheet_t; + +/* The next macros is used to access the node info + * for example, the page of a sheet is stored in INFO(sheet)[PAGE] + */ +# define PAGE 0 + +/* This macro defines implementation offsets + */ +# define MAKE_GET(GETTER,OFFSET)\ +synctex_node_t * GETTER (synctex_node_t node) {\ + return node?(synctex_node_t *)((&((node)->implementation))+OFFSET):NULL;\ +} +MAKE_GET(_synctex_implementation_0,0) +MAKE_GET(_synctex_implementation_1,1) +MAKE_GET(_synctex_implementation_2,2) +MAKE_GET(_synctex_implementation_3,3) +MAKE_GET(_synctex_implementation_4,4) + +synctex_node_t _synctex_new_sheet(synctex_scanner_t scanner); +void _synctex_display_sheet(synctex_node_t sheet); +void _synctex_log_sheet(synctex_node_t sheet); + +static const _synctex_class_t synctex_class_sheet = { + NULL, /* No scanner yet */ + synctex_node_type_sheet, /* Node type */ + &_synctex_new_sheet, /* creator */ + &_synctex_free_node, /* destructor */ + &_synctex_log_sheet, /* log */ + &_synctex_display_sheet, /* display */ + NULL, /* No parent */ + &_synctex_implementation_0, /* child */ + &_synctex_implementation_1, /* sibling */ + NULL, /* No friend */ + (_synctex_int_getter_t)&_synctex_implementation_2 /* info */ +}; + +/* sheet node creator */ +synctex_node_t _synctex_new_sheet(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_sheet_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_sheet:(synctex_class_t)&synctex_class_sheet; + } + return node; +} + +/* A box node contains navigation and synctex information + * There are different kind of boxes. + * Only horizontal boxes are treated differently because of their visible size. + */ +typedef struct { + synctex_class_t class; + int implementation[4+3+5]; /* parent,child,sibling,friend, + * TAG,LINE,COLUMN, + * HORIZ,VERT,WIDTH,HEIGHT,DEPTH */ +} synctex_vert_box_node_t; + +# define TAG 0 +# define LINE (TAG+1) +# define COLUMN (LINE+1) +# define HORIZ (COLUMN+1) +# define VERT (HORIZ+1) +# define WIDTH (VERT+1) +# define HEIGHT (WIDTH+1) +# define DEPTH (HEIGHT+1) + +synctex_node_t _synctex_new_vbox(synctex_scanner_t scanner); +void _synctex_log_box(synctex_node_t sheet); +void _synctex_display_vbox(synctex_node_t node); + +/* These are static class objects, each scanner will make a copy of them and setup the scanner field. + */ +static const _synctex_class_t synctex_class_vbox = { + NULL, /* No scanner yet */ + synctex_node_type_vbox, /* Node type */ + &_synctex_new_vbox, /* creator */ + &_synctex_free_node, /* destructor */ + &_synctex_log_box, /* log */ + &_synctex_display_vbox, /* display */ + &_synctex_implementation_0, /* parent */ + &_synctex_implementation_1, /* child */ + &_synctex_implementation_2, /* sibling */ + &_synctex_implementation_3, /* friend */ + (_synctex_int_getter_t)&_synctex_implementation_4 +}; + +/* vertical box node creator */ +synctex_node_t _synctex_new_vbox(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_vert_box_node_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_vbox:(synctex_class_t)&synctex_class_vbox; + } + return node; +} + +/* Horizontal boxes must contain visible size, because 0 width does not mean emptiness */ +typedef struct { + synctex_class_t class; + int implementation[4+3+5+5]; /*parent,child,sibling,friend, + * TAG,LINE,COLUMN, + * HORIZ,VERT,WIDTH,HEIGHT,DEPTH, + * HORIZ_V,VERT_V,WIDTH_V,HEIGHT_V,DEPTH_V*/ +} synctex_horiz_box_node_t; + +# define HORIZ_V (DEPTH+1) +# define VERT_V (HORIZ_V+1) +# define WIDTH_V (VERT_V+1) +# define HEIGHT_V (WIDTH_V+1) +# define DEPTH_V (HEIGHT_V+1) + +synctex_node_t _synctex_new_hbox(synctex_scanner_t scanner); +void _synctex_display_hbox(synctex_node_t node); +void _synctex_log_horiz_box(synctex_node_t sheet); + + +static const _synctex_class_t synctex_class_hbox = { + NULL, /* No scanner yet */ + synctex_node_type_hbox, /* Node type */ + &_synctex_new_hbox, /* creator */ + &_synctex_free_node, /* destructor */ + &_synctex_log_horiz_box, /* log */ + &_synctex_display_hbox, /* display */ + &_synctex_implementation_0, /* parent */ + &_synctex_implementation_1, /* child */ + &_synctex_implementation_2, /* sibling */ + &_synctex_implementation_3, /* friend */ + (_synctex_int_getter_t)&_synctex_implementation_4 +}; + +/* horizontal box node creator */ +synctex_node_t _synctex_new_hbox(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_horiz_box_node_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_hbox:(synctex_class_t)&synctex_class_hbox; + } + return node; +} + +/* This void box node implementation is either horizontal or vertical + * It does not contain a child field. + */ +typedef struct { + synctex_class_t class; + int implementation[3+3+5]; /* parent,sibling,friend, + * TAG,LINE,COLUMN, + * HORIZ,VERT,WIDTH,HEIGHT,DEPTH*/ +} synctex_void_box_node_t; + +synctex_node_t _synctex_new_void_vbox(synctex_scanner_t scanner); +void _synctex_log_void_box(synctex_node_t sheet); +void _synctex_display_void_vbox(synctex_node_t node); + +static const _synctex_class_t synctex_class_void_vbox = { + NULL, /* No scanner yet */ + synctex_node_type_void_vbox,/* Node type */ + &_synctex_new_void_vbox, /* creator */ + &_synctex_free_node, /* destructor */ + &_synctex_log_void_box, /* log */ + &_synctex_display_void_vbox,/* display */ + &_synctex_implementation_0, /* parent */ + NULL, /* No child */ + &_synctex_implementation_1, /* sibling */ + &_synctex_implementation_2, /* friend */ + (_synctex_int_getter_t)&_synctex_implementation_3 +}; + +/* vertical void box node creator */ +synctex_node_t _synctex_new_void_vbox(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_void_box_node_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_void_vbox:(synctex_class_t)&synctex_class_void_vbox; + } + return node; +} + +synctex_node_t _synctex_new_void_hbox(synctex_scanner_t scanner); +void _synctex_display_void_hbox(synctex_node_t node); + +static const _synctex_class_t synctex_class_void_hbox = { + NULL, /* No scanner yet */ + synctex_node_type_void_hbox,/* Node type */ + &_synctex_new_void_hbox, /* creator */ + &_synctex_free_node, /* destructor */ + &_synctex_log_void_box, /* log */ + &_synctex_display_void_hbox,/* display */ + &_synctex_implementation_0, /* parent */ + NULL, /* No child */ + &_synctex_implementation_1, /* sibling */ + &_synctex_implementation_2, /* friend */ + (_synctex_int_getter_t)&_synctex_implementation_3 +}; + +/* horizontal void box node creator */ +synctex_node_t _synctex_new_void_hbox(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_void_box_node_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_void_hbox:(synctex_class_t)&synctex_class_void_hbox; + } + return node; +} + +/* The medium nodes correspond to kern, glue and math nodes. */ +typedef struct { + synctex_class_t class; + int implementation[3+3+3]; /* parent,sibling,friend, + * TAG,LINE,COLUMN, + * HORIZ,VERT,WIDTH */ +} synctex_medium_node_t; + +synctex_node_t _synctex_new_math(synctex_scanner_t scanner); +void _synctex_log_medium_node(synctex_node_t sheet); +void _synctex_display_math(synctex_node_t node); + +static const _synctex_class_t synctex_class_math = { + NULL, /* No scanner yet */ + synctex_node_type_math, /* Node type */ + &_synctex_new_math, /* creator */ + &_synctex_free_leaf, /* destructor */ + &_synctex_log_medium_node, /* log */ + &_synctex_display_math, /* display */ + &_synctex_implementation_0, /* parent */ + NULL, /* No child */ + &_synctex_implementation_1, /* sibling */ + &_synctex_implementation_2, /* friend */ + (_synctex_int_getter_t)&_synctex_implementation_3 +}; + +/* math node creator */ +synctex_node_t _synctex_new_math(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_medium_node_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_math:(synctex_class_t)&synctex_class_math; + } + return node; +} + +synctex_node_t _synctex_new_glue(synctex_scanner_t scanner); +void _synctex_display_glue(synctex_node_t node); + +static const _synctex_class_t synctex_class_glue = { + NULL, /* No scanner yet */ + synctex_node_type_glue, /* Node type */ + &_synctex_new_glue, /* creator */ + &_synctex_free_leaf, /* destructor */ + &_synctex_log_medium_node, /* log */ + &_synctex_display_glue, /* display */ + &_synctex_implementation_0, /* parent */ + NULL, /* No child */ + &_synctex_implementation_1, /* sibling */ + &_synctex_implementation_2, /* friend */ + (_synctex_int_getter_t)&_synctex_implementation_3 +}; +/* glue node creator */ +synctex_node_t _synctex_new_glue(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_medium_node_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_glue:(synctex_class_t)&synctex_class_glue; + } + return node; +} + +synctex_node_t _synctex_new_kern(synctex_scanner_t scanner); +void _synctex_display_kern(synctex_node_t node); + +static const _synctex_class_t synctex_class_kern = { + NULL, /* No scanner yet */ + synctex_node_type_kern, /* Node type */ + &_synctex_new_kern, /* creator */ + &_synctex_free_leaf, /* destructor */ + &_synctex_log_medium_node, /* log */ + &_synctex_display_kern, /* display */ + &_synctex_implementation_0, /* parent */ + NULL, /* No child */ + &_synctex_implementation_1, /* sibling */ + &_synctex_implementation_2, /* friend */ + (_synctex_int_getter_t)&_synctex_implementation_3 +}; + +/* kern node creator */ +synctex_node_t _synctex_new_kern(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_medium_node_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_kern:(synctex_class_t)&synctex_class_kern; + } + return node; +} + +/* Input nodes only know about their sibling, which is another input node. + * The synctex information is the TAG and NAME*/ +typedef struct { + synctex_class_t class; + int implementation[1+2]; /* sibling, + * TAG,NAME */ +} synctex_input_t; + +/* The TAG previously defined is also used here */ +# define NAME 1 + +synctex_node_t _synctex_new_input(synctex_scanner_t scanner); +void _synctex_display_input(synctex_node_t node); +void _synctex_log_input(synctex_node_t sheet); + +static const _synctex_class_t synctex_class_input = { + NULL, /* No scanner yet */ + synctex_node_type_input, /* Node type */ + &_synctex_new_input, /* creator */ + &_synctex_free_leaf, /* destructor */ + &_synctex_log_input, /* log */ + &_synctex_display_input, /* display */ + NULL, /* No parent */ + NULL, /* No child */ + &_synctex_implementation_0, /* sibling */ + NULL, /* No friend */ + (_synctex_int_getter_t)&_synctex_implementation_1 +}; + +synctex_node_t _synctex_new_input(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_input_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_input:(synctex_class_t)&synctex_class_input; + } + return node; +} + +#pragma mark - +#pragma mark Navigation +synctex_node_t synctex_node_parent(synctex_node_t node) +{ + return PARENT(node); +} +synctex_node_t synctex_node_sheet(synctex_node_t node) +{ + while(node && node->class->type != synctex_node_type_sheet) { + node = PARENT(node); + } + /* exit the while loop either when node is NULL or node is a sheet */ + return node; +} +synctex_node_t synctex_node_child(synctex_node_t node) +{ + return CHILD(node); +} +synctex_node_t synctex_node_sibling(synctex_node_t node) +{ + return SIBLING(node); +} +synctex_node_t synctex_node_next(synctex_node_t node) { + if(CHILD(node)) { + return CHILD(node); + } +sibling: + if(SIBLING(node)) { + return SIBLING(node); + } + if(node = PARENT(node)) { + if(node->class->type == synctex_node_type_sheet) {// EXC_BAD_ACCESS? + return NULL; + } + goto sibling; + } + return NULL; +} +#pragma mark - +#pragma mark CLASS + +/* Public node accessor: the type */ +synctex_node_type_t synctex_node_type(synctex_node_t node) { + if(node) { + return (((node)->class))->type; + } + return synctex_node_type_error; +} + +/* Public node accessor: the human readable type */ +const char * synctex_node_isa(synctex_node_t node) { +static const char * isa[synctex_node_type_last] = + {"Not a node","sheet","vbox","void vbox","hbox","void hbox","kern","glue","math","input"}; + return isa[synctex_node_type(node)]; +} + +# pragma mark - +# pragma mark LOG + +# define LOG(NODE) MSG_SEND(NODE,log) + +/* Public node logger */ +void synctex_node_log(synctex_node_t node) { + LOG(node); +} + +void _synctex_log_sheet(synctex_node_t sheet) { + if(sheet) { + printf("%s:%i\n",synctex_node_isa(sheet),INFO(sheet)[PAGE]); + printf("SELF:0x%x",sheet); + printf(" PARENT:0x%x",PARENT(sheet)); + printf(" CHILD:0x%x",CHILD(sheet)); + printf(" SIBLING:0x%x",SIBLING(sheet)); + printf(" FRIEND:0x%x\n",FRIEND(sheet)); + } +} + +void _synctex_log_medium_node(synctex_node_t node) { + printf("%s:%i,%i:%i,%i:%i\n", + synctex_node_isa(node), + INFO(node)[TAG], + INFO(node)[LINE], + INFO(node)[HORIZ], + INFO(node)[VERT], + INFO(node)[WIDTH]); + printf("SELF:0x%x",node); + printf(" PARENT:0x%x",PARENT(node)); + printf(" CHILD:0x%x",CHILD(node)); + printf(" SIBLING:0x%x",SIBLING(node)); + printf(" FRIEND:0x%x\n",FRIEND(node)); +} + +void _synctex_log_void_box(synctex_node_t node) { + int * info = INFO(node); + printf("%s",synctex_node_isa(node)); + printf(":%i",info[TAG]); + printf(",%i",info[LINE]); + printf(",%i",0); + printf(":%i",info[HORIZ]); + printf(",%i",info[VERT]); + printf(":%i",info[WIDTH]); + printf(",%i",info[HEIGHT]); + printf(",%i",info[DEPTH]); + printf("\nSELF:0x%x",node); + printf(" PARENT:0x%x",PARENT(node)); + printf(" CHILD:0x%x",CHILD(node)); + printf(" SIBLING:0x%x",SIBLING(node)); + printf(" FRIEND:0x%x\n",FRIEND(node)); +} + +void _synctex_log_box(synctex_node_t node) { + int * info = INFO(node); + printf("%s",synctex_node_isa(node)); + printf(":%i",info[TAG]); + printf(",%i",info[LINE]); + printf(",%i",0); + printf(":%i",info[HORIZ]); + printf(",%i",info[VERT]); + printf(":%i",info[WIDTH]); + printf(",%i",info[HEIGHT]); + printf(",%i",info[DEPTH]); + printf("\nSELF:0x%x",node); + printf(" PARENT:0x%x",PARENT(node)); + printf(" CHILD:0x%x",CHILD(node)); + printf(" SIBLING:0x%x",SIBLING(node)); + printf(" FRIEND:0x%x\n",FRIEND(node)); +} + +void _synctex_log_horiz_box(synctex_node_t node) { + int * info = INFO(node); + printf("%s",synctex_node_isa(node)); + printf(":%i",info[TAG]); + printf(",%i",info[LINE]); + printf(",%i",0); + printf(":%i",info[HORIZ]); + printf(",%i",info[VERT]); + printf(":%i",info[WIDTH]); + printf(",%i",info[HEIGHT]); + printf(",%i",info[DEPTH]); + printf(":%i",info[HORIZ_V]); + printf(",%i",info[VERT_V]); + printf(":%i",info[WIDTH_V]); + printf(",%i",info[HEIGHT_V]); + printf(",%i",info[DEPTH_V]); + printf("\nSELF:0x%x",node); + printf(" PARENT:0x%x",PARENT(node)); + printf(" CHILD:0x%x",CHILD(node)); + printf(" SIBLING:0x%x",SIBLING(node)); + printf(" FRIEND:0x%x\n",FRIEND(node)); +} + +void _synctex_log_input(synctex_node_t node) { + int * info = INFO(node); + printf("%s",synctex_node_isa(node)); + printf(":%i",info[TAG]); + printf(",%s",info[NAME]); + printf(" SIBLING:0x%x",SIBLING(node)); +} + +# define DISPLAY(NODE) MSG_SEND(NODE,display) + +void _synctex_display_sheet(synctex_node_t sheet) { + if(sheet) { + printf("....{%i\n",INFO(sheet)[PAGE]); + DISPLAY(CHILD(sheet)); + printf("....}\n"); + DISPLAY(SIBLING(sheet)); + } +} + +void _synctex_display_vbox(synctex_node_t node) { + printf("....[%i,%i:%i,%i:%i,%i,%i\n", + INFO(node)[TAG], + INFO(node)[LINE], + INFO(node)[HORIZ], + INFO(node)[VERT], + INFO(node)[WIDTH], + INFO(node)[HEIGHT], + INFO(node)[DEPTH]); + DISPLAY(CHILD(node)); + printf("....]\n"); + DISPLAY(SIBLING(node)); +} + +void _synctex_display_hbox(synctex_node_t node) { + printf("....(%i,%i:%i,%i:%i,%i,%i\n", + INFO(node)[TAG], + INFO(node)[LINE], + INFO(node)[HORIZ], + INFO(node)[VERT], + INFO(node)[WIDTH], + INFO(node)[HEIGHT], + INFO(node)[DEPTH]); + DISPLAY(CHILD(node)); + printf("....)\n"); + DISPLAY(SIBLING(node)); +} + +void _synctex_display_void_vbox(synctex_node_t node) { + printf("....v%i,%i;%i,%i:%i,%i,%i\n", + INFO(node)[TAG], + INFO(node)[LINE], + INFO(node)[HORIZ], + INFO(node)[VERT], + INFO(node)[WIDTH], + INFO(node)[HEIGHT], + INFO(node)[DEPTH]); + DISPLAY(SIBLING(node)); +} + +void _synctex_display_void_hbox(synctex_node_t node) { + printf("....h%i,%i:%i,%i:%i,%i,%i\n", + INFO(node)[TAG], + INFO(node)[LINE], + INFO(node)[HORIZ], + INFO(node)[VERT], + INFO(node)[WIDTH], + INFO(node)[HEIGHT], + INFO(node)[DEPTH]); + DISPLAY(SIBLING(node)); +} + +void _synctex_display_glue(synctex_node_t node) { + printf("....glue:%i,%i:%i,%i\n", + INFO(node)[TAG], + INFO(node)[LINE], + INFO(node)[HORIZ], + INFO(node)[VERT]); + DISPLAY(SIBLING(node)); +} + +void _synctex_display_math(synctex_node_t node) { + printf("....math:%i,%i:%i,%i\n", + INFO(node)[TAG], + INFO(node)[LINE], + INFO(node)[HORIZ], + INFO(node)[VERT]); + DISPLAY(SIBLING(node)); +} + +void _synctex_display_kern(synctex_node_t node) { + printf("....kern:%i,%i:%i,%i:%i\n", + INFO(node)[TAG], + INFO(node)[LINE], + INFO(node)[HORIZ], + INFO(node)[VERT], + INFO(node)[WIDTH]); + DISPLAY(SIBLING(node)); +} + +void _synctex_display_input(synctex_node_t node) { + printf("....Input:%i:%s\n", + INFO(node)[TAG], + INFO(node)[NAME]); + DISPLAY(SIBLING(node)); +} + +# pragma mark - +# pragma mark SCANNER + +#define SYNCTEX_NOERR 0 + +/* Used when parsing the synctex file. + * Advance to the next character starting a line. + * Actually, only \n is recognized as end of line marker. */ +int _synctex_next_line(synctex_scanner_t scanner) { + if(NULL == scanner) { + return -1; + } + while(PTR<END) { + if(*PTR == '\n') { + ++PTR; + return 0; + } + ++PTR; + } + return 1; +} + +/* Used when parsing the synctex file. + * Decode an integer. + * First file separators are skipped + */ +int _synctex_decode_int(synctex_scanner_t scanner, int* valueRef) { + if(NULL == scanner) return -1; + if(PTR>=END) return -1; + unsigned char * ptr = PTR; + if(*ptr==':' || *ptr==',') { + ++ptr; + } + unsigned char * end; + int result = (int)strtol((char *)ptr, (char **)&end, 10); + if(end>ptr) { + PTR = end; + if(valueRef) { + * valueRef = result; + } + return 0; + } + return -1; +} + +int _synctex_decode_string(synctex_scanner_t scanner, char ** valueRef) { + if(NULL == scanner || NULL == valueRef) return -1; + if(PTR>=END) return -1; + char * end = (char *)PTR; + while(end<(char *)END && *end != '\n') { + ++end; + } + size_t len = end - (char *)PTR; + if(* valueRef = malloc(len+1)) { + if(memcpy((*valueRef),(synctex_node_t)PTR,len)) { + (* valueRef)[len]='\0'; + PTR += len; + return 0; + } + free(* valueRef); + * valueRef = NULL; + } + return -1; +} + +/* Used when parsing the synctex file. + * Read an Input record. + */ +int _synctex_scan_input(synctex_scanner_t scanner) { + if(NULL == scanner) { + return -1; + } + if(0 == strncmp((char *)PTR,"Input:",6)) { + PTR += 6; + synctex_node_t input = _synctex_new_input(scanner); + if(_synctex_decode_int(scanner,INFO(input)+TAG) + || (++PTR,_synctex_decode_string(scanner,(char **)(INFO(input)+NAME))) + || _synctex_next_line(scanner)) { + FREE(input); + return -1; + } + SET_SIBLING(input,scanner->input) + scanner->input = input; + return 0; + } + return 1; +} + +/* Used when parsing the synctex file. + * Read the settings as part of the preamble. + */ +int _synctex_scan_settings(synctex_scanner_t scanner) { + if(NULL == scanner) { + return -1; + } + while(strncmp((char *)PTR,"Output:",7)) { + if(_synctex_next_line(scanner)) { + return -1; + } + } + PTR += 7; + if(_synctex_decode_string(scanner,&(scanner->output)) + || _synctex_next_line(scanner)) { + return -1; + } + while(strncmp((char *)PTR,"Magnification:",14)) { + if(_synctex_next_line(scanner)) { + return -1; + } + } + PTR += 14; + if(_synctex_decode_int(scanner,(int *)&(scanner->pre_magnification)) + || _synctex_next_line(scanner)) { + return -1; + } + while(strncmp((char *)PTR,"Unit:",5)) { + if(_synctex_next_line(scanner)) { + return -1; + } + } + PTR += 5; + if(_synctex_decode_int(scanner,(int *)&(scanner->pre_unit)) + || _synctex_next_line(scanner)) { + return -1; + } + while(strncmp((char *)PTR,"X Offset:",9)) { + if(_synctex_next_line(scanner)) { + return -1; + } + } + PTR += 9; + if(_synctex_decode_int(scanner,&(scanner->pre_x_offset)) + || _synctex_next_line(scanner)) { + return -1; + } + while(strncmp((char *)PTR,"Y Offset:",9)) { + if(_synctex_next_line(scanner)) { + return -1; + } + } + PTR += 9; + if(_synctex_decode_int(scanner,&(scanner->pre_y_offset)) + || _synctex_next_line(scanner)) { + return -1; + } + return 0; +} + +/* Used when parsing the synctex file. + * Read the preamplesss. + */ +int _synctex_scan_preamble(synctex_scanner_t scanner) { + if(NULL == scanner) { + return -1; + } + if(strncmp((char *)PTR,"SyncTeX Version:",1) + || ((PTR+=16),_synctex_decode_int(scanner,&(scanner->version))) + || _synctex_next_line(scanner)) { + return -1; + } + while(SYNCTEX_NOERR == _synctex_scan_input(scanner)) { + } + return _synctex_scan_settings(scanner); +} + +/* parse the post scriptum */ +#include "xlocale.h" +int _synctex_scan_post_scriptum(synctex_scanner_t scanner) { + while(strncmp((char *)PTR,"Post scriptum:",14)) { + if(_synctex_next_line(scanner)) { + return -1; + } + } + PTR += 14; + /* Scanning the information */ + /* initialize the offset with a fake value */ + scanner->x_offset = 6.027e23; + scanner->y_offset = scanner->x_offset; + /* By default, C programs start in the "C" locale + * But we are in a library, so we cannot assume that. */ + locale_t locale = newlocale(LC_ALL_MASK, NULL, NULL); + int status = 0; +next_record: + if(0 == strncmp((char *)PTR,"Magnification:",14)) { + PTR += 14; + if(PTR<END) { + scanner->unit = strtof_l((char *)PTR,(char **)&PTR,locale); +next_line: + status = _synctex_next_line(scanner); + if(status<0) { + freelocale(locale); + return -1; + } else if(0 == status) { + goto next_record; + } + } + freelocale(locale); + return 0; + } else if(0 == strncmp((char *)PTR,"X Offset:",9)) { + PTR += 9; + if(PTR<END) { + unsigned char * end = NULL; + float f = strtof_l((char *)PTR,(char **)&end,locale); + if(end>PTR) { + /* scan the x offset */ + //72/72.27/65536*16384+0.5; + PTR = end; + if(strncmp((char *)PTR,"in",2) == 0) { + f *= 72.27*65536; + } + else if(strncmp((char *)PTR,"cm",2) == 0) { + f *= 72.27*65536/2.54; + } + else if(strncmp((char *)PTR,"mm",2) == 0) { + f *= 72.27*65536/25.4; + } + else if(strncmp((char *)PTR,"pt",2) == 0) { + f *= 65536.0; + } + else if(strncmp((char *)PTR,"bp",2) == 0) { + f *= 72.27/72*65536; + } + else if(strncmp((char *)PTR,"pc",2) == 0) { + f *= 12.0*65536; + } + else if(strncmp((char *)PTR,"sp",2) == 0) { + f *= 1.0; + } + else if(strncmp((char *)PTR,"dd",2) == 0) { + f *= 1238.0/1157*65536; + } + else if(strncmp((char *)PTR,"cc",2) == 0) { + f *= 14856.0/1157*65536; + } + else if(strncmp((char *)PTR,"nd",2) == 0) { + f *= 685.0/642*65536; + } + else if(strncmp((char *)PTR,"nc",2) == 0) { + f *= 1370.0/107*65536; + } + else { + f *= 1.0; + PTR -= 2; + } + scanner->x_offset = f; + } + goto next_line; + } + freelocale(locale); + return 0; + } else if(0 == strncmp((char *)PTR,"Y Offset:",9)) { + PTR += 9; + if(PTR<END) { + unsigned char * end = NULL; + float f = strtof_l((char *)PTR,(char **)&end,locale); + if(end>PTR) { + /* scan the x offset */ + //72/72.27/65536*16384+0.5; + PTR = end; + if(strncmp((char *)PTR,"in",2) == 0) { + f *= 72.27*65536; + } + else if(strncmp((char *)PTR,"cm",2) == 0) { + f *= 72.27*65536/2.54; + } + else if(strncmp((char *)PTR,"mm",2) == 0) { + f *= 72.27*65536/25.4; + } + else if(strncmp((char *)PTR,"pt",2) == 0) { + f *= 65536.0; + } + else if(strncmp((char *)PTR,"bp",2) == 0) { + f *= 72.27/72*65536; + } + else if(strncmp((char *)PTR,"pc",2) == 0) { + f *= 12.0*65536; + } + else if(strncmp((char *)PTR,"sp",2) == 0) { + f *= 1.0; + } + else if(strncmp((char *)PTR,"dd",2) == 0) { + f *= 1238.0/1157*65536; + } + else if(strncmp((char *)PTR,"cc",2) == 0) { + f *= 14856.0/1157*65536; + } + else if(strncmp((char *)PTR,"nd",2) == 0) { + f *= 685.0/642*65536; + } + else if(strncmp((char *)PTR,"nc",2) == 0) { + f *= 1370.0/107*65536; + } + else { + f *= 1.0; + PTR -= 2; + } + scanner->y_offset = f; + } + goto next_line; + } + freelocale(locale); + return 0; + } + goto next_line; +} + +int _synctex_scan_postamble(synctex_scanner_t scanner) { + if(NULL == scanner) { + return -1; + } + if(strncmp((char *)PTR,"Postamble:",10) + || ((PTR += 10),_synctex_next_line(scanner))) { + return -1; + } + if(!strncmp((char *)PTR,"Count:",6)) { + PTR += 6; + if(_synctex_decode_int(scanner,&(scanner->count)) + || _synctex_next_line(scanner)) { + return -1; + } + } + while(_synctex_scan_post_scriptum(scanner)) { + if(_synctex_next_line(scanner)) { + return -1; + } + } + return 0; +} + +/* Horizontal boxes also have visible size. + * Visible size are bigger than real size. + * For example 0 width boxes may contain text. + * At creation time, the visible size is set to the values of the real size. + */ +int _synctex_setup_visible_box(synctex_node_t box) { + if(NULL == box || box->class->type != synctex_node_type_hbox) { + return -1; + } + int * info = INFO(box); + if(info) { + info[HORIZ_V] = info[HORIZ]; + info[VERT_V] = info[VERT]; + info[WIDTH_V] = info[WIDTH]; + info[HEIGHT_V] = info[HEIGHT]; + info[DEPTH_V] = info[DEPTH]; + return 0; + } + return -1; +} + +/* This method is sent to an horizontal box to setup the visible size + * Some box have 0 width but do contain text material. + * With this method, one can enlarge the box to contain the given point (h,v). + */ +int _synctex_horiz_box_setup_visible(synctex_node_t node,int h, int v) { + if(NULL == node || node->class->type != synctex_node_type_hbox) { + return -1; + } + int * itsINFO = INFO(node); + int itsBtm, itsTop; + if(itsINFO[WIDTH_V]<0) { + itsBtm = itsINFO[HORIZ_V]+itsINFO[WIDTH_V]; + itsTop = itsINFO[HORIZ_V]; + if(h<itsBtm) { + itsBtm -= h; + itsINFO[WIDTH_V] -= itsBtm; + } + if(h>itsTop) { + h -= itsTop; + itsINFO[WIDTH_V] -= h; + itsINFO[HORIZ_V] += h; + } + } else { + itsBtm = itsINFO[HORIZ_V]; + itsTop = itsINFO[HORIZ_V]+itsINFO[WIDTH_V]; + if(h<itsBtm) { + itsBtm -= h; + itsINFO[HORIZ_V] -= itsBtm; + itsINFO[WIDTH_V] += itsBtm; + } + if(h>itsTop) { + h -= itsTop; + itsINFO[WIDTH_V] += h; + } + } + return 0; +} + +/* Used when parsing the synctex file. + * The parent is a newly created sheet node that will hold the contents. + * Something is returned in case of error. + */ +int _synctex_scan_sheet(synctex_scanner_t scanner, synctex_node_t parent) { + if((NULL == scanner) || (NULL == parent))return -1; + synctex_node_t child = NULL; + synctex_node_t sibling = NULL; + int friend_index = 0; + int * info = NULL; + int curh, curv; +vertical_loop: + if(PTR<END) { + if(*PTR == '[') { + ++PTR; + if((child = _synctex_new_vbox(scanner)) && (info = INFO(child))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_decode_int(scanner,(int*)(info+HEIGHT)) + || _synctex_decode_int(scanner,(int*)(info+DEPTH)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_CHILD(parent,child); + parent = child; + child = NULL; + goto vertical_loop; + } else { + return -1; + } + } else if(*PTR == ']') { + ++PTR; + if(parent && parent->class->type == synctex_node_type_vbox) { + #define UPDATE_BOX_FRIEND(NODE)\ + friend_index = ((INFO(NODE))[TAG]+(INFO(NODE))[LINE])%(scanner->number_of_lists);\ + SET_FRIEND(NODE,(scanner->lists_of_friends)[friend_index]);\ + (scanner->lists_of_friends)[friend_index] = NODE; + if(NULL == CHILD(parent)) { + /* only void boxes are friends */ + UPDATE_BOX_FRIEND(parent); + } + child = parent; + parent = PARENT(child); + } else { + printf("Unexpected ]\n"); + } + if(_synctex_next_line(scanner)) { + return -1; + } + goto horizontal_loop; + } else if(*PTR == '(') { + ++PTR; + if((child = _synctex_new_hbox(scanner)) && (info = INFO(child))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_decode_int(scanner,(int*)(info+HEIGHT)) + || _synctex_decode_int(scanner,(int*)(info+DEPTH)) + || _synctex_setup_visible_box(child) + || _synctex_next_line(scanner)) { + return -1; + } + SET_CHILD(parent,child); + parent = child; + child = NULL; + goto vertical_loop; + } else { + return -1; + } + } else if(*PTR == ')') { + ++PTR; + if(parent && parent->class->type == synctex_node_type_hbox) { + if(NULL == child) { + UPDATE_BOX_FRIEND(parent); + } + child = parent; + parent = PARENT(child); + } else { + printf("Unexpected )\n"); + } + if(_synctex_next_line(scanner)) { + return -1; + } + goto horizontal_loop; + } else if(*PTR == 'v') { + ++PTR; + if((child = _synctex_new_void_vbox(scanner)) && (info = INFO(child))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_decode_int(scanner,(int*)(info+HEIGHT)) + || _synctex_decode_int(scanner,(int*)(info+DEPTH)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_CHILD(parent,child); + #define UPDATE_FRIEND(NODE)\ + friend_index = (info[TAG]+info[LINE])%(scanner->number_of_lists);\ + SET_FRIEND(NODE,(scanner->lists_of_friends)[friend_index]);\ + (scanner->lists_of_friends)[friend_index] = NODE; + UPDATE_FRIEND(child); + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == 'h') { + ++PTR; + if((child = _synctex_new_void_hbox(scanner)) && (info = INFO(child))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_decode_int(scanner,(int*)(info+HEIGHT)) + || _synctex_decode_int(scanner,(int*)(info+DEPTH)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_CHILD(parent,child); + UPDATE_FRIEND(child); + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child)+synctex_node_width(child),synctex_node_v(child)); + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == 'k') { + ++PTR; + if((child = _synctex_new_kern(scanner)) && (info = INFO(child))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_CHILD(parent,child); + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); + UPDATE_FRIEND(child); + if(!parent) { + printf("Child is:"); + synctex_node_log(child); + return -1; + } + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == 'x') { + ++PTR; + if(_synctex_decode_int(scanner,NULL) + || _synctex_decode_int(scanner,NULL) + || _synctex_decode_int(scanner,&curh) + || _synctex_decode_int(scanner,&curv) + || _synctex_next_line(scanner)) { + return -1; + } + _synctex_horiz_box_setup_visible(parent,curh,curv); + goto vertical_loop; + } else if(*PTR == 'g') { + ++PTR; + if((child = _synctex_new_glue(scanner)) && (info = INFO(child))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_CHILD(parent,child); + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); + UPDATE_FRIEND(child); + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == '$') { + ++PTR; + if((child = _synctex_new_math(scanner)) && (info = INFO(child))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_CHILD(parent,child); + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); + UPDATE_FRIEND(child); + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == '}') { + ++PTR; + if(!parent || parent->class->type != synctex_node_type_sheet + || _synctex_next_line(scanner)) { + return -1; + } + return 0; + } else if(*PTR == '!') { + ++PTR; + if(_synctex_next_line(scanner)) { + return -1; + } + goto vertical_loop; + } else { + printf("Ignored:<%c>\n",*PTR); + ++PTR; + if(_synctex_next_line(scanner)) { + return -1; + } + goto vertical_loop; + } + } else { + return -1; + } + synctex_bail(); +horizontal_loop: + if(PTR<END) { + if(*PTR == '[') { + ++PTR; + if((sibling = _synctex_new_vbox(scanner)) && (info = INFO(sibling))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_decode_int(scanner,(int*)(info+HEIGHT)) + || _synctex_decode_int(scanner,(int*)(info+DEPTH)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_SIBLING(child,sibling); + parent = sibling; + child = NULL; + goto vertical_loop; + } else { + return -1; + } + } else if(*PTR == ']') { + ++PTR; + if(parent && parent->class->type == synctex_node_type_vbox) { + if(NULL == child) { + UPDATE_BOX_FRIEND(parent); + } + child = parent; + parent = PARENT(child); + } else { + printf("Unexpected ]\n"); + } + if(_synctex_next_line(scanner)) { + return -1; + } + goto horizontal_loop; + } else if(*PTR == '(') { + ++PTR; + if((sibling = _synctex_new_hbox(scanner)) && (info = INFO(sibling))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_decode_int(scanner,(int*)(info+HEIGHT)) + || _synctex_decode_int(scanner,(int*)(info+DEPTH)) + || _synctex_setup_visible_box(sibling) + || _synctex_next_line(scanner)) { + return -1; + } + SET_SIBLING(child,sibling); + parent = sibling; + child = NULL; + goto vertical_loop; + } else { + return -1; + } + } else if(*PTR == ')') { + ++PTR; + if(parent && parent->class->type == synctex_node_type_hbox) { + if(NULL == child) { + UPDATE_BOX_FRIEND(parent); + } + child = parent; + parent = PARENT(child); + } else { + printf("Unexpected )\n"); + } + if(_synctex_next_line(scanner)) { + LOG(child); + return -1; + } + goto horizontal_loop; + } else if(*PTR == 'v') { + ++PTR; + if((sibling = _synctex_new_void_vbox(scanner)) && (info = INFO(sibling))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_decode_int(scanner,(int*)(info+HEIGHT)) + || _synctex_decode_int(scanner,(int*)(info+DEPTH)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_SIBLING(child,sibling); + UPDATE_FRIEND(sibling); + child = sibling; + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == 'h') { + ++PTR; + if((sibling = _synctex_new_void_hbox(scanner)) && (info = INFO(sibling))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_decode_int(scanner,(int*)(info+HEIGHT)) + || _synctex_decode_int(scanner,(int*)(info+DEPTH)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_SIBLING(child,sibling); + UPDATE_FRIEND(sibling); + child = sibling; + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child)+synctex_node_width(child),synctex_node_v(child)); + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == 'x') { + ++PTR; + if(_synctex_decode_int(scanner,NULL) + || _synctex_decode_int(scanner,NULL) + || _synctex_decode_int(scanner,&curh) + || _synctex_decode_int(scanner,&curv) + || _synctex_next_line(scanner)) { + return -1; + } + _synctex_horiz_box_setup_visible(parent,curh,curv); + goto horizontal_loop; + } else if(*PTR == 'k') { + ++PTR; + if((sibling = _synctex_new_kern(scanner)) && (info = INFO(sibling))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_SIBLING(child,sibling); + UPDATE_FRIEND(sibling); + child = sibling; + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == 'g') { + ++PTR; + if((sibling = _synctex_new_glue(scanner)) && (info = INFO(sibling))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_SIBLING(child,sibling); + UPDATE_FRIEND(sibling); + child = sibling; + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == '$') { + ++PTR; + if((sibling = _synctex_new_math(scanner)) && (info = INFO(sibling))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_SIBLING(child,sibling); + _synctex_horiz_box_setup_visible(parent,synctex_node_h(sibling),synctex_node_v(sibling)); + UPDATE_FRIEND(sibling); + child = sibling; + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == '}') { + ++PTR; + if(!parent || parent->class->type != synctex_node_type_sheet + || _synctex_next_line(scanner)) { + return -1; + } + return 0; + } else if(*PTR == '!') { + ++PTR; + if(_synctex_next_line(scanner)) { + return -1; + } + goto horizontal_loop; + } else { + printf("SyncTeX: Ignored record %c\n",*PTR); + if(_synctex_next_line(scanner)) { + return -1; + } + goto horizontal_loop; + } + } else { + return -1; + } +} + +/* Used when parsing the synctex file + */ +int _synctex_scan_content(synctex_scanner_t scanner) { + if(NULL == scanner) { + return -1; + } + /* set up the lists of friends */ + if(NULL == scanner->lists_of_friends) { + scanner->number_of_lists = 1024; + scanner->lists_of_friends = (synctex_node_t *)_synctex_malloc(scanner->number_of_lists*sizeof(synctex_node_t)); + if(NULL == scanner->lists_of_friends) { + printf("malloc:2\n"); + return -1; + } + } + /* Find where this section starts */ + while(strncmp((char *)PTR,"Content:",8)) { + if(_synctex_next_line(scanner)) { + return -1; + } + } + PTR += 8; + if(_synctex_next_line(scanner)) { + return -1; + } +next_sheet: + if(*PTR != '{') { + if(_synctex_scan_postamble(scanner)) { + if(_synctex_next_line(scanner)) { + return -1; + } + goto next_sheet; + } + return 0; + } + ++PTR; + /* Create a new sheet node */ + synctex_node_t sheet = _synctex_new_sheet(scanner); + if(_synctex_decode_int(scanner,INFO(sheet)+PAGE) + || _synctex_next_line(scanner)) { +bail: + FREE(sheet); + return -1; + } + if(_synctex_scan_sheet(scanner,sheet)) { + goto bail; + } + SET_SIBLING(sheet,scanner->sheet); + scanner->sheet = sheet; + while(SYNCTEX_NOERR == _synctex_scan_input(scanner)) { + } + goto next_sheet; +} + +/* Where the synctex scanner is created. + * name is the full path of the synctex file. */ +synctex_scanner_t synctex_scanner_new_with_contents_of_file(const char * name) { + synctex_scanner_t scanner = (synctex_scanner_t)_synctex_malloc(sizeof(_synctex_scanner_t)); + if(NULL == scanner) { + return NULL; + } + scanner->pre_magnification = 1000; + scanner->pre_unit = 8192; + scanner->pre_x_offset = scanner->pre_y_offset = 578; + scanner->class[synctex_node_type_sheet] = synctex_class_sheet; + (scanner->class[synctex_node_type_sheet]).scanner = scanner; + scanner->class[synctex_node_type_vbox] = synctex_class_vbox; + (scanner->class[synctex_node_type_vbox]).scanner = scanner; + scanner->class[synctex_node_type_void_vbox] = synctex_class_void_vbox; + (scanner->class[synctex_node_type_void_vbox]).scanner = scanner; + scanner->class[synctex_node_type_hbox] = synctex_class_hbox; + (scanner->class[synctex_node_type_hbox]).scanner = scanner; + scanner->class[synctex_node_type_void_hbox] = synctex_class_void_hbox; + (scanner->class[synctex_node_type_void_hbox]).scanner = scanner; + scanner->class[synctex_node_type_kern] = synctex_class_kern; + (scanner->class[synctex_node_type_kern]).scanner = scanner; + scanner->class[synctex_node_type_glue] = synctex_class_glue; + (scanner->class[synctex_node_type_glue]).scanner = scanner; + scanner->class[synctex_node_type_math] = synctex_class_math; + (scanner->class[synctex_node_type_math]).scanner = scanner; + scanner->class[synctex_node_type_input] = synctex_class_input; + (scanner->class[synctex_node_type_input]).scanner = scanner; + + FILE * F = fopen(name,"r"); + if(NULL == F) { + printf("SyncTeX: could not open %s, error %i\n",name,errno); +bail: + synctex_scanner_free(scanner); + return NULL; + } + if(fseek(F, 0, SEEK_END)) { + close(F); + goto bail; + } + size_t size = ftell(F); + rewind(F); + START = (unsigned char *)malloc(size+1); + if(NULL == START) { + printf("malloc error\n"); + close(F); + goto bail; + } + if(size != fread((void *)START, 1, size, F)) { +bailey: + close(F); + goto bail; + } + close(F); + START[size] = '\0'; /* ensure null termination */ + /* first read the beginning */ + END = START + size; + PTR = START; + if(_synctex_scan_preamble(scanner) + || _synctex_scan_content(scanner)) { + goto bailey; + } + free((void *)START); + START = PTR = END = NULL; + /* Everything is finished, final tuning */ + /* 1 pre_unit = (scanner->pre_unit)/65536 pt = (scanner->pre_unit)/65781.76 bp + * 1 pt = 65536 sp */ + if(scanner->pre_unit<=0) { + scanner->pre_unit = 8192; + } + if(scanner->pre_magnification<=0) { + scanner->pre_magnification = 1000; + } + if(scanner->unit <= 0) { + /* no post magnification */ + scanner->unit = scanner->pre_unit / 65781.76;/* 65781.76 or 65536.0*/ + } else { + /* post magnification */ + scanner->unit *= scanner->pre_unit / 65781.76; + } + scanner->unit *= scanner->pre_magnification / 1000.0; + if(scanner->x_offset > 6e23) { + /* no post offset */ + scanner->x_offset = scanner->pre_x_offset * (scanner->pre_unit / 65781.76); + scanner->y_offset = scanner->pre_y_offset * (scanner->pre_unit / 65781.76); + } else { + /* post offset */ + scanner->x_offset /= 65781.76; + scanner->y_offset /= 65781.76; + } + return scanner; +} + +/* The scanner destructor + */ +void synctex_scanner_free(synctex_scanner_t scanner) { + if(NULL == scanner) { + return; + } + FREE(scanner->sheet); + free(START); + free(scanner->output); + free(scanner->input); + free(scanner->lists_of_friends); + free(scanner); +} + +/* Scanner accessors. + */ +int synctex_scanner_pre_x_offset(synctex_scanner_t scanner){ + return scanner?scanner->pre_x_offset:0; +} +int synctex_scanner_pre_y_offset(synctex_scanner_t scanner){ + return scanner?scanner->pre_y_offset:0; +} +int synctex_scanner_x_offset(synctex_scanner_t scanner){ + return scanner?scanner->x_offset:0; +} +int synctex_scanner_y_offset(synctex_scanner_t scanner){ + return scanner?scanner->y_offset:0; +} +float synctex_scanner_magnification(synctex_scanner_t scanner){ + return scanner?scanner->unit:1; +} +void synctex_scanner_display(synctex_scanner_t scanner) { + if(NULL == scanner) { + return; + } + printf("The scanner:\noutput:%s\nversion:%i\n",scanner->output,scanner->version); + printf("pre_unit:%i\nx_offset:%i\nx_offset:%i\n",scanner->pre_unit,scanner->pre_x_offset,scanner->pre_y_offset); + printf("count:%i\npost_magnification:%f\npost_x_offset:%i\npost_x_offset:%i\n", + scanner->count,scanner->unit,scanner->x_offset,scanner->y_offset); + printf("The input:\n"); + DISPLAY(scanner->input); + if(scanner->count<1000) { + printf("The sheets:\n"); + DISPLAY(scanner->sheet); + printf("The friends:\n"); + if(scanner->lists_of_friends) { + int i = scanner->number_of_lists; + synctex_node_t node; + while(i--) { + printf("Friend index:%i\n",i); + node = (scanner->lists_of_friends)[i]; + while(node) { + printf("%s:%i,%i\n", + synctex_node_isa(node), + INFO(node)[TAG], + INFO(node)[LINE] + ); + node = FRIEND(node); + } + } + } + } else { + printf("Too many objects"); + } +} +/* Public*/ +const char * synctex_scanner_get_name(synctex_scanner_t scanner,int tag) { + if(NULL == scanner) { + return ""; + } + synctex_node_t input = scanner->input; + do { + if(tag == INFO(input)[TAG]) { + return (char *)(INFO(input)[NAME]); + } + } while(input = SIBLING(input)); + return 0; +} +int synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name) { + if(NULL == scanner) { + return 0; + } + synctex_node_t input = scanner->input; + do { + if((strlen(name) == strlen((char *)(INFO(input)[NAME]))) && + (0 == strncmp(name,(char *)(INFO(input)[NAME]),strlen(name)))) { + return INFO(input)[TAG]; + } + } while(input = SIBLING(input)); + return 0; +} +synctex_node_t synctex_scanner_input(synctex_scanner_t scanner) { + return scanner?scanner->input:NULL; +} +#pragma mark - +#pragma mark Public node attributes +float synctex_node_h(synctex_node_t node){ + if(!node) { + return 0; + } + return (float)INFO(node)[HORIZ]; +} +float synctex_node_v(synctex_node_t node){ + if(!node) { + return 0; + } + return (float)INFO(node)[VERT]; +} +float synctex_node_width(synctex_node_t node){ + if(!node) { + return 0; + } + return (float)INFO(node)[WIDTH]; +} +float synctex_node_box_h(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type != synctex_node_type_vbox) + && (node->class->type != synctex_node_type_void_vbox) + && (node->class->type != synctex_node_type_hbox) + && (node->class->type != synctex_node_type_void_hbox)) { + node = PARENT(node); + } + return (node->class->type == synctex_node_type_sheet)?0:(float)(INFO(node)[HORIZ]); +} +float synctex_node_box_v(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type != synctex_node_type_vbox) + && (node->class->type != synctex_node_type_void_vbox) + && (node->class->type != synctex_node_type_hbox) + && (node->class->type != synctex_node_type_void_hbox)) { + node = PARENT(node); + } + return (node->class->type == synctex_node_type_sheet)?0:(float)(INFO(node)[VERT]); +} +float synctex_node_box_width(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type != synctex_node_type_vbox) + && (node->class->type != synctex_node_type_void_vbox) + && (node->class->type != synctex_node_type_hbox) + && (node->class->type != synctex_node_type_void_hbox)) { + node = PARENT(node); + } + return (node->class->type == synctex_node_type_sheet)?0:(float)(INFO(node)[WIDTH]); +} +float synctex_node_box_height(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type != synctex_node_type_vbox) + && (node->class->type != synctex_node_type_void_vbox) + && (node->class->type != synctex_node_type_hbox) + && (node->class->type != synctex_node_type_void_hbox)) { + node = PARENT(node); + } + return (node->class->type == synctex_node_type_sheet)?0:(float)(INFO(node)[HEIGHT]); +} +float synctex_node_box_depth(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type != synctex_node_type_vbox) + && (node->class->type != synctex_node_type_void_vbox) + && (node->class->type != synctex_node_type_hbox) + && (node->class->type != synctex_node_type_void_hbox)) { + node = PARENT(node); + } + return (node->class->type == synctex_node_type_sheet)?0:(float)(INFO(node)[DEPTH]); +} +#pragma mark - +#pragma mark Public node visible attributes +float synctex_node_visible_h(synctex_node_t node){ + if(!node) { + return 0; + } + return INFO(node)[HORIZ]*node->class->scanner->unit+node->class->scanner->x_offset; +} +float synctex_node_visible_v(synctex_node_t node){ + if(!node) { + return 0; + } + return INFO(node)[VERT]*node->class->scanner->unit+node->class->scanner->y_offset; +} +float synctex_node_visible_width(synctex_node_t node){ + if(!node) { + return 0; + } + return INFO(node)[WIDTH]*node->class->scanner->unit; +} +float synctex_node_box_visible_h(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type == synctex_node_type_vbox) + || (node->class->type == synctex_node_type_void_hbox) + || (node->class->type == synctex_node_type_void_vbox)) { +result: + return INFO(node)[WIDTH]<0? + (INFO(node)[HORIZ]+INFO(node)[WIDTH])*node->class->scanner->unit+node->class->scanner->x_offset: + INFO(node)[HORIZ]*node->class->scanner->unit+node->class->scanner->x_offset; + } + if(node->class->type != synctex_node_type_hbox) { + node = PARENT(node); + } + if(node->class->type == synctex_node_type_sheet) { + return 0; + } + if(node->class->type == synctex_node_type_vbox) { + goto result; + } + return INFO(node)[WIDTH_V]<0? + (INFO(node)[HORIZ_V]+INFO(node)[WIDTH_V])*node->class->scanner->unit+node->class->scanner->x_offset: + INFO(node)[HORIZ_V]*node->class->scanner->unit+node->class->scanner->x_offset; +} +float synctex_node_box_visible_v(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type == synctex_node_type_vbox) + || (node->class->type == synctex_node_type_void_hbox) + || (node->class->type == synctex_node_type_void_vbox)) { +result: + return (float)(INFO(node)[VERT])*node->class->scanner->unit+node->class->scanner->y_offset; + } + if((node->class->type != synctex_node_type_vbox) + && (node->class->type != synctex_node_type_hbox)) { + node = PARENT(node); + } + if(node->class->type == synctex_node_type_sheet) { + return 0; + } + if(node->class->type == synctex_node_type_vbox) { + goto result; + } + return INFO(node)[VERT_V]*node->class->scanner->unit+node->class->scanner->y_offset; +} +float synctex_node_box_visible_width(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type == synctex_node_type_vbox) + || (node->class->type == synctex_node_type_void_hbox) + || (node->class->type == synctex_node_type_void_vbox)) { +result: + return INFO(node)[WIDTH]<0? + -INFO(node)[WIDTH]*node->class->scanner->unit: + INFO(node)[WIDTH]*node->class->scanner->unit; + } + if(node->class->type != synctex_node_type_hbox) { + node = PARENT(node); + } + if(node->class->type == synctex_node_type_sheet) { + return 0; + } + if(node->class->type == synctex_node_type_vbox) { + goto result; + } + return INFO(node)[WIDTH_V]<0? + -INFO(node)[WIDTH_V]*node->class->scanner->unit: + INFO(node)[WIDTH_V]*node->class->scanner->unit; +} +float synctex_node_box_visible_height(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type == synctex_node_type_vbox) + || (node->class->type == synctex_node_type_void_hbox) + || (node->class->type == synctex_node_type_void_vbox)) { +result: + return (float)(INFO(node)[HEIGHT])*node->class->scanner->unit; + } + if(node->class->type != synctex_node_type_hbox) { + node = PARENT(node); + } + if(node->class->type == synctex_node_type_sheet) { + return 0; + } + if(node->class->type == synctex_node_type_vbox) { + goto result; + } + return INFO(node)[HEIGHT_V]*node->class->scanner->unit; +} +float synctex_node_box_visible_depth(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type == synctex_node_type_vbox) + || (node->class->type == synctex_node_type_void_hbox) + || (node->class->type == synctex_node_type_void_vbox)) { +result: + return (float)(INFO(node)[DEPTH])*node->class->scanner->unit; + } + if(node->class->type != synctex_node_type_hbox) { + node = PARENT(node); + } + if(node->class->type == synctex_node_type_sheet) { + return 0; + } + if(node->class->type == synctex_node_type_vbox) { + goto result; + } + return INFO(node)[DEPTH_V]*node->class->scanner->unit; +} +#pragma mark - +#pragma mark Other public node attributes +int synctex_node_page(synctex_node_t node){ + if(!node) { + return -1; + } + synctex_node_t parent = PARENT(node); + while(parent) { + node = parent; + parent = PARENT(node); + } + if(node->class->type == synctex_node_type_sheet) { + return INFO(node)[PAGE]; + } + return -1; +} +int synctex_node_tag(synctex_node_t node) { + return node?INFO(node)[TAG]:-1; +} +int synctex_node_line(synctex_node_t node) { + return node?INFO(node)[LINE]:-1; +} +int synctex_node_column(synctex_node_t node) { + return -1; +} +#pragma mark - +#pragma mark Query + +synctex_node_t synctex_sheet_content(synctex_scanner_t scanner,int page) { + if(scanner) { + synctex_node_t sheet = scanner->sheet; + while(sheet) { + if(page == INFO(sheet)[PAGE]) { + return CHILD(sheet); + } + sheet = SIBLING(sheet); + } + } + return NULL; +} + +int synctex_display_query(synctex_scanner_t scanner,const char * name,int line,int column) { + int tag = synctex_scanner_get_tag(scanner,name); + if(tag == 0) { + printf("No tag for %s\n",name); + return -1; + } + free(START); + PTR = END = START = NULL; + size_t size = 0; + int friend_index = (tag+line)%(scanner->number_of_lists); + synctex_node_t node = (scanner->lists_of_friends)[friend_index]; + while(node) { + if((tag == INFO(node)[TAG]) && (line == INFO(node)[LINE])) { + if(PTR == END) { + size += 16; + END = realloc(START,size*sizeof(synctex_node_t *)); + PTR += END - START; + START = END; + END = START + size*sizeof(synctex_node_t *); + } + *(int *)PTR = (int)node; + PTR += sizeof(int); + } + node = FRIEND(node); + } + END = PTR; + PTR = NULL; + return END-START; +} + +int _synctex_node_is_box(synctex_node_t node) { + switch(synctex_node_type(node)) { + case synctex_node_type_hbox: + case synctex_node_type_void_hbox: + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + return -1; + } + return 0; +} + +int _synctex_point_in_visible_box(float h, float v, synctex_node_t node) { + if(_synctex_node_is_box(node)) { + v -= synctex_node_box_visible_v(node); + if((v<=-synctex_node_box_visible_height(node) + && v>=synctex_node_box_visible_depth(node)) + || (v>=-synctex_node_box_visible_height(node) + && v<= synctex_node_box_visible_depth(node))) { + h -= synctex_node_box_visible_h(node); + if((h<=0 && h>=synctex_node_box_visible_width(node)) + || (h>=0 && h<=synctex_node_box_visible_width(node))) { + return -1; + } + } + } + return 0; +} + +int synctex_edit_query(synctex_scanner_t scanner,int page,float h,float v) { + if(NULL == scanner) { + return 0; + } + free(START); + START = END = PTR = NULL; + synctex_node_t sheet = scanner->sheet; + while(INFO(sheet)[PAGE] != page) { + sheet = SIBLING(sheet); + } + if(NULL == sheet) { + return -1; + } + /* Now sheet points to the sheet node with proper page number */ + /* Declare memory storage, a buffer to hold found nodes */ + synctex_node_t * start = NULL; + synctex_node_t * end = NULL; + synctex_node_t * ptr = NULL; + size_t size = 0; + synctex_node_t node = CHILD(sheet); /* start with the child of the sheet */ + synctex_node_t next; +has_node_any_child: + if(next = CHILD(node)) { + /* node is a non void box */ + if(_synctex_point_in_visible_box(h,v,node)) { + /* we found a non void box containing the point */ + if(ptr == end) { + /* not enough room to store the result, add 16 more node records */ + size += 16; + end = realloc(start,size*sizeof(synctex_node_t)); + if(end == NULL) { + return -1; + } + ptr += end - start; + start = end; + end = start + size; + } + *ptr = node; + /* Does an included box also contain the hit point? + * If this is the case, ptr will be overriden later + * This is why we do not increment ptr yet. + * ptr will be incremented (registered) later if + * no enclosing box contains the hit point */ + } + node = next; + goto has_node_any_child; + } + /* node has no child */ +node_has_no_child: + if(_synctex_point_in_visible_box(h,v,node)) { + /* we found a void box containing the hit point */ + if(ptr == end) { + /* not enough room to store the result, add 16 more node records */ + size += 16; + end = realloc(start,size*sizeof(synctex_node_t)); + if(end == NULL) { + return -1; + } + ptr += end - start; + start = end; + end = start + size*sizeof(synctex_node_t); + } + *ptr = node; + /* Increment ptr to definitely register the node */ + ++ptr; + /* Ensure that it is the last node */ + *ptr = NULL; + } +next_sibling: + if(next = SIBLING(node)) { + node = next; + goto has_node_any_child; + } + /* This is the last node at this level + * The next step is the parent's sibling */ + next = PARENT(node); + if(ptr && *ptr == next) { + /* No included box does contain the point + * next was already tagged to contain the hit point + * but was not fully registered at that time, now we can increment ptr */ + ++ptr; + *ptr = NULL; + } else if(next == sheet) { +we_are_done: + end = ptr; + ptr = NULL; + /* Up to now, we have found a list of boxes enclosing the hit point. */ + if(end == start) { + /* No match found */ + return 0; + } + /* If there are many different boxes containing the hit point, put the smallest one front. + * This is in general the expected box in LaTeX picture environment. */ + ptr = start; + node = *ptr; + float best = synctex_node_box_visible_width(node); + float candidate; + synctex_node_t * best_node_ref = NULL; + while(node = *(++ptr)) { + candidate = synctex_node_box_visible_width(node); + if(candidate<best) { + best = candidate; + best_node_ref = ptr; + } + } + if(best_node_ref) { + node = *best_node_ref; + *best_node_ref = *start; + *start = node; + } + /* We do need to check children to find out the node closest to the hit point. + * Working with boxes is not very accurate because in general boxes are created asynchronously. + * The glue, kern, math are more appropriate for synchronization. */ + if(node = CHILD(*start)) { + best = INFINITY; + synctex_node_t best_node = NULL; + do { + switch((node->class)->type) { + default: + candidate = fabsf(synctex_node_visible_h(node)-h); + if(candidate<best) { + best = candidate; + best_node = node; + } + case synctex_node_type_hbox: + case synctex_node_type_vbox: + break; + } + } while(node = SIBLING(node)); + if(best_node) { + if(START = malloc(sizeof(synctex_node_t))) { + * (synctex_node_t *)START = best_node; + END = START + sizeof(synctex_node_t); + PTR = NULL; + free(start); + return (END-START)/sizeof(synctex_node_t); + } + } + } + START = (unsigned char *)start; + END = (unsigned char *)end; + PTR = NULL; + return (END-START)/sizeof(synctex_node_t); + } else if(NULL == next) { + /* What? a node with no parent? */ + printf("This is an error\n"); + goto we_are_done; + } + node = next; + goto next_sibling; +} + +synctex_node_t synctex_next_result(synctex_scanner_t scanner) { + if(NULL == PTR) { + PTR = START; + } else { + PTR+=sizeof(synctex_node_t); + } + if(PTR<END) { + return *(synctex_node_t*)PTR; + } else { + return NULL; + } +} + +int synctex_bail(void) { + printf("*** ERROR\n"); + return -1; +} +#pragma mark - +#pragma mark TESTS +/* This is not public, it is not up to date */ +synctex_scanner_t synctex_scanner_new_with_data(const void * bytes, unsigned int length) { + synctex_scanner_t scanner = (synctex_scanner_t)_synctex_malloc(sizeof(_synctex_scanner_t)); + if(NULL != scanner) { + START = (void *)bytes; + if(UINT_MAX-length<(int)(START)) { +bail: + free(scanner); + return NULL; + } + END = START+length; + scanner->pre_unit = 8192; + scanner->pre_x_offset = scanner->pre_y_offset = 578; + unsigned char the_char; + if(_synctex_scan_preamble(scanner)) { + goto bail; + } + do { + if(the_char == '{') { + if(_synctex_scan_content(scanner)) { + goto bail; + } + break; + } + } while(SYNCTEX_NOERR == _synctex_scan_next_line_header(scanner,&the_char)); + } + return scanner; +} + +int _synctex_scan_next_line_header(synctex_scanner_t scanner, unsigned char * valueRef) { + if(NULL == scanner || NULL == valueRef) return -1; + /* read until the next '\0' byte, return the following one */ + while(PTR<END) { + if(*PTR=='\0') { + if(++PTR<END) { + *valueRef = *(PTR++); + return 0; + } + } else { + ++PTR; + } + } + return -1; +} +int synctex_jump(synctex_scanner_t scanner) +{ + unsigned char the_char; + int n; + unsigned char * offset = END; + while(offset>scanner->buffer_start) { + if(*(--offset)) { + continue; + } + PTR = offset; + if(SYNCTEX_NOERR == _synctex_scan_next_line_header(scanner,&the_char)) { + if(the_char == '}') { + offset = PTR-1; +next: + if(SYNCTEX_NOERR == _synctex_decode_int(scanner,&n)) { + printf("}%i\n",n); + if(offset - n>START) { + offset -= n; + the_char = *offset; + if(the_char == '{') { + scanner->buffer_ptr=offset+1; + if(SYNCTEX_NOERR == _synctex_decode_int(scanner,&n)) { + printf("{%i\n",n); + if(offset - n>START) { + offset -= n; + the_char = *offset; + if(the_char == '}') { + PTR=offset+1; + goto next; + } else { + printf("This is not an '}', this is an %c\n", the_char); + } + } else { + printf("The start is reached %i\n",n); + } + } + } else { + printf("This is not an '{', this is an %c\n", the_char); + } + } else { + printf("ERROR: Too long %i\n",n); + } + } + break; + } + } + } + return 0; +} +int synctex_test(void) { + printf("sizeof(synctex_sheet_t):%i\n",sizeof(synctex_sheet_t)); + printf("sizeof(synctex_vert_box_node_t):%i\n",sizeof(synctex_vert_box_node_t)); + printf("sizeof(synctex_horiz_box_node_t):%i\n",sizeof(synctex_horiz_box_node_t)); + printf("sizeof(synctex_void_box_node_t):%i\n",sizeof(synctex_void_box_node_t)); + printf("sizeof(synctex_medium_node_t):%i\n",sizeof(synctex_medium_node_t)); + /* TESTING */ + synctex_node_t node; + synctex_node_t child; + synctex_node_t next; + #define TEST(LABEL,constructor)\ + printf("TESTING constructor:%s\n",LABEL);\ + node = constructor(NULL);\ + LOG(node);\ + FREE(node); + TEST(("_synctex_new_sheet"),_synctex_new_sheet); + TEST(("_synctex_new_vbox"),_synctex_new_vbox); + TEST(("_synctex_new_hbox"),_synctex_new_hbox); + TEST(("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST(("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST(("_synctex_new_math"),_synctex_new_math); + TEST(("_synctex_new_kern"),_synctex_new_kern); + TEST(("_synctex_new_glue"),_synctex_new_glue); + printf("...... ALL constructor tested\n\n\n\n"); + #undef TEST + #define TEST(PARENT_LABEL,PARENT_CONSTRUCTOR,CHILD_LABEL,CHILD_CONSTRUCTOR)\ + printf("TESTING parent:%s -> child:%s\n",PARENT_LABEL,CHILD_LABEL);\ + node = PARENT_CONSTRUCTOR(NULL);\ + child = CHILD_CONSTRUCTOR(NULL);\ + DISPLAY(node);\ + DISPLAY(child);\ + SET_CHILD(node,child);\ + DISPLAY(node);\ + DISPLAY(child);\ + if((CHILD(node) != child) || (node != PARENT(child))) {\ + return synctex_bail();\ + }\ + FREE(node); + TEST("_synctex_new_sheet",_synctex_new_sheet,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_sheet",_synctex_new_sheet,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_sheet",_synctex_new_sheet,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_sheet",_synctex_new_sheet,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_sheet",_synctex_new_sheet,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_sheet",_synctex_new_sheet,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_sheet",_synctex_new_sheet,("_synctex_new_glue"),_synctex_new_glue); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_glue"),_synctex_new_glue); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_glue"),_synctex_new_glue); +// TEST("_synctex_new_sheet","",_synctex_new_sheet,); +// TEST("","",,); + #undef TEST + #define TEST(CHILD_LABEL,CHILD_CONSTRUCTOR,SIBLING_LABEL,SIBLING_CONSTRUCTOR)\ + printf("TESTING child:%s -> next:%s\n",CHILD_LABEL,SIBLING_LABEL);\ + node = _synctex_new_sheet(NULL);\ + child = CHILD_CONSTRUCTOR(NULL);\ + next = SIBLING_CONSTRUCTOR(NULL);\ + DISPLAY(node);\ + DISPLAY(child);\ + DISPLAY(next);\ + SET_CHILD(node,child);\ + SET_SIBLING(child,next);\ + DISPLAY(node);\ + DISPLAY(child);\ + DISPLAY(next);\ + if((SIBLING(child) != next) || (node != PARENT(next))) {\ + return synctex_bail();\ + }\ + FREE(node); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_glue"),_synctex_new_glue); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_glue"),_synctex_new_glue); + TEST("_synctex_new_void_vbox",_synctex_new_void_vbox,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_void_vbox",_synctex_new_void_vbox,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_void_vbox",_synctex_new_void_vbox,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_void_vbox",_synctex_new_void_vbox,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_void_vbox",_synctex_new_void_vbox,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_void_vbox",_synctex_new_void_vbox,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_void_vbox",_synctex_new_void_vbox,("_synctex_new_glue"),_synctex_new_glue); + TEST("_synctex_new_void_hbox",_synctex_new_void_hbox,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_void_hbox",_synctex_new_void_hbox,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_void_hbox",_synctex_new_void_hbox,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_void_hbox",_synctex_new_void_hbox,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_void_hbox",_synctex_new_void_hbox,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_void_hbox",_synctex_new_void_hbox,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_void_hbox",_synctex_new_void_hbox,("_synctex_new_glue"),_synctex_new_glue); + TEST("_synctex_new_math",_synctex_new_math,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_math",_synctex_new_math,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_math",_synctex_new_math,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_math",_synctex_new_math,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_math",_synctex_new_math,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_math",_synctex_new_math,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_math",_synctex_new_math,("_synctex_new_glue"),_synctex_new_glue); + TEST("_synctex_new_kern",_synctex_new_kern,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_kern",_synctex_new_kern,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_kern",_synctex_new_kern,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_kern",_synctex_new_kern,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_kern",_synctex_new_kern,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_kern",_synctex_new_kern,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_kern",_synctex_new_kern,("_synctex_new_glue"),_synctex_new_glue); + TEST("_synctex_new_glue",_synctex_new_glue,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_glue",_synctex_new_glue,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_glue",_synctex_new_glue,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_glue",_synctex_new_glue,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_glue",_synctex_new_glue,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_glue",_synctex_new_glue,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_glue",_synctex_new_glue,("_synctex_new_glue"),_synctex_new_glue); + + return 0; + +} + |