diff options
Diffstat (limited to 'Build/source/texk/web2c/synctexdir/synctex_parser.c')
-rw-r--r-- | Build/source/texk/web2c/synctexdir/synctex_parser.c | 2950 |
1 files changed, 1713 insertions, 1237 deletions
diff --git a/Build/source/texk/web2c/synctexdir/synctex_parser.c b/Build/source/texk/web2c/synctexdir/synctex_parser.c index 1e99f2cf1ec..327ca37abef 100644 --- a/Build/source/texk/web2c/synctexdir/synctex_parser.c +++ b/Build/source/texk/web2c/synctexdir/synctex_parser.c @@ -1,8 +1,13 @@ /* -Copyright (c) 2008 jerome DOT laurens AT u-bourgogne DOT fr +Copyright (c) 2008, 2009 jerome DOT laurens AT u-bourgogne DOT fr This file is part of the SyncTeX package. +Version: 1.6 +See synctex_parser_readme.txt for more details + +Latest Revision: Wed Jul 1 11:18:18 UTC 2009 + License: -------- Permission is hereby granted, free of charge, to any person @@ -59,39 +64,22 @@ Thu Jun 19 09:39:21 UTC 2008 # define HAVE_LOCALE_H 1 # define HAVE_SETLOCALE 1 # if defined(_MSC_VER) -# define inline __inline +# define SYNCTEX_INLINE __inline +# else +# define SYNCTEX_INLINE inline # endif # endif -#include "stddef.h" -#include "stdio.h" -#include "stdlib.h" -#include "string.h" -#include "limits.h" -#include "time.h" -#include "math.h" -#include "errno.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <limits.h> #if defined(HAVE_LOCALE_H) #include <locale.h> #endif -void *_synctex_malloc(size_t size); - -/* This custom malloc functions initializes to 0 the newly allocated memory. */ -void *_synctex_malloc(size_t size) { - void * ptr = malloc(size); - if(ptr) { -/* In Visual C, bzero is not available */ -#ifdef _MSC_VER - memset(ptr,0, size); -#else - bzero(ptr,size); -#endif - } - 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. @@ -103,8 +91,9 @@ void *_synctex_malloc(size_t size) { */ #include "synctex_parser.h" +#include <synctex_parser_utils.h> -/* each synctex node has a class */ +/* each synctex node has a class */ typedef struct __synctex_class_t _synctex_class_t; typedef _synctex_class_t * synctex_class_t; @@ -214,17 +203,20 @@ struct __synctex_class_t { SYNCTEX_GETTER(NEW_SIBLING,parent)[0]=SYNCTEX_GETTER(NODE,parent)[0];\ }\ } -/* Friend getter and setter +/* Friend getter and setter. A friend is a kern, math, glue or void box node which tag and line numbers are similar. + * This is a first filter on the nodes that avoids testing all of them. + * Friends are used mainly in forward synchronization aka from source to output. */ # define SYNCTEX_FRIEND(NODE) SYNCTEX_GET(NODE,friend) # define SYNCTEX_SET_FRIEND(NODE,NEW_FRIEND) if(NODE && NEW_FRIEND){\ SYNCTEX_GETTER(NODE,friend)[0]=NEW_FRIEND;\ } -/* Next box getter and setter +/* Next box getter and setter. The box tree can be traversed from one horizontal boxes to the other. + * Navigation starts with the deeper boxes. */ -# define SYNCTEX_NEXT_BOX(NODE) SYNCTEX_GET(NODE,next_box) -# define SYNCTEX_SET_NEXT_BOX(NODE,NEXT_BOX) if(NODE && NEXT_BOX){\ +# define SYNCTEX_NEXT_HORIZ_BOX(NODE) SYNCTEX_GET(NODE,next_box) +# define SYNCTEX_SET_NEXT_HORIZ_BOX(NODE,NEXT_BOX) if(NODE && NEXT_BOX){\ SYNCTEX_GETTER(NODE,next_box)[0]=NEXT_BOX;\ } @@ -256,35 +248,42 @@ void _synctex_free_leaf(synctex_node_t node) { } return; } - -#include <zlib.h> +# ifdef __SYNCTEX_WORK__ +# include "/usr/include/zlib.h" +# else +# include <zlib.h> +# endif /* The synctex scanner is the root object. * Is is initialized with the contents of a text file or a gzipped file. * The buffer_? are first used to parse the text. */ struct __synctex_scanner_t { - gzFile file; /* The (possibly compressed) file */ - unsigned char * buffer_cur; /* current location in the buffer */ - unsigned char * buffer_start; /* start of the buffer */ - unsigned char * buffer_end; /* end of the buffer */ - char * output_fmt; /* dvi or pdf, not yet used */ - char * output; /* the output name used to create the scanner */ - char * synctex; /* the .synctex or .synctex.gz name used to create the scanner */ - 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, its siblings are the other sheet nodes */ - synctex_node_t input; /* The first input node, its siblings are the other input nodes */ - int number_of_lists; /* The number of friend lists */ - synctex_node_t * lists_of_friends;/* The friend lists */ - _synctex_class_t class[synctex_node_number_of_types]; /* The classes of the nodes of the scanner */ + gzFile file; /* The (possibly compressed) file */ + unsigned char * buffer_cur; /* current location in the buffer */ + unsigned char * buffer_start; /* start of the buffer */ + unsigned char * buffer_end; /* end of the buffer */ + char * output_fmt; /* dvi or pdf, not yet used */ + char * output; /* the output name used to create the scanner */ + char * synctex; /* the .synctex or .synctex.gz name used to create the scanner */ + int version; /* 1, not yet used */ + struct { + unsigned has_parsed:1; /* Whether the scanner has parsed its underlying synctex file. */ + unsigned reserved:sizeof(unsigned)-1; /* alignment */ + } flags; + 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, its siblings are the other sheet nodes */ + synctex_node_t input; /* The first input node, its siblings are the other input nodes */ + int number_of_lists; /* The number of friend lists */ + synctex_node_t * lists_of_friends;/* The friend lists */ + _synctex_class_t class[synctex_node_number_of_types]; /* The classes of the nodes of the scanner */ }; /* SYNCTEX_CUR, SYNCTEX_START and SYNCTEX_END are convenient shortcuts @@ -337,8 +336,8 @@ SYNCTEX_MAKE_GET(_synctex_implementation_5,5) typedef struct { synctex_class_t class; - synctex_info_t implementation[3+SYNCTEX_PAGE_IDX+1];/* child, sibling, next box, - * SYNCTEX_PAGE_IDX */ + synctex_info_t implementation[3+SYNCTEX_PAGE_IDX+1];/* child, sibling, next box, + * SYNCTEX_PAGE_IDX */ } synctex_sheet_t; synctex_node_t _synctex_new_sheet(synctex_scanner_t scanner); @@ -346,18 +345,18 @@ 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_implementation_2, /* Next box */ - (_synctex_info_getter_t)&_synctex_implementation_3 /* info */ + 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_implementation_2, /* Next box */ + (_synctex_info_getter_t)&_synctex_implementation_3 /* info */ }; /* sheet node creator */ @@ -390,12 +389,15 @@ synctex_node_t _synctex_new_sheet(synctex_scanner_t scanner) { # define SYNCTEX_WIDTH(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_WIDTH_IDX].INT # define SYNCTEX_HEIGHT(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HEIGHT_IDX].INT # define SYNCTEX_DEPTH(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_DEPTH_IDX].INT +# define SYNCTEX_ABS_WIDTH(NODE) ((SYNCTEX_WIDTH(NODE)>0?SYNCTEX_WIDTH(NODE):-SYNCTEX_WIDTH(NODE))) +# define SYNCTEX_ABS_HEIGHT(NODE) ((SYNCTEX_HEIGHT(NODE)>0?SYNCTEX_HEIGHT(NODE):-SYNCTEX_HEIGHT(NODE))) +# define SYNCTEX_ABS_DEPTH(NODE) ((SYNCTEX_DEPTH(NODE)>0?SYNCTEX_DEPTH(NODE):-SYNCTEX_DEPTH(NODE))) typedef struct { synctex_class_t class; - synctex_info_t implementation[5+SYNCTEX_DEPTH_IDX+1]; /* parent,child,sibling,friend,next box, - * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN, - * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH */ + synctex_info_t implementation[5+SYNCTEX_DEPTH_IDX+1]; /* parent,child,sibling,friend,next box, + * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN, + * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH */ } synctex_vert_box_node_t; synctex_node_t _synctex_new_vbox(synctex_scanner_t scanner); @@ -405,17 +407,17 @@ 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_implementation_4, /* next box */ + 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_implementation_4, /* next box */ (_synctex_info_getter_t)&_synctex_implementation_5 }; @@ -439,14 +441,17 @@ synctex_node_t _synctex_new_vbox(synctex_scanner_t scanner) { # define SYNCTEX_WIDTH_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_WIDTH_V_IDX].INT # define SYNCTEX_HEIGHT_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HEIGHT_V_IDX].INT # define SYNCTEX_DEPTH_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_DEPTH_V_IDX].INT +# define SYNCTEX_ABS_WIDTH_V(NODE) ((SYNCTEX_WIDTH_V(NODE)>0?SYNCTEX_WIDTH_V(NODE):-SYNCTEX_WIDTH_V(NODE))) +# define SYNCTEX_ABS_HEIGHT_V(NODE) ((SYNCTEX_HEIGHT_V(NODE)>0?SYNCTEX_HEIGHT_V(NODE):-SYNCTEX_HEIGHT_V(NODE))) +# define SYNCTEX_ABS_DEPTH_V(NODE) ((SYNCTEX_DEPTH_V(NODE)>0?SYNCTEX_DEPTH_V(NODE):-SYNCTEX_DEPTH_V(NODE))) /* Horizontal boxes must contain visible size, because 0 width does not mean emptiness */ typedef struct { synctex_class_t class; synctex_info_t implementation[5+SYNCTEX_DEPTH_V_IDX+1]; /*parent,child,sibling,friend,next box, - * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN, - * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH, - * SYNCTEX_HORIZ_V,SYNCTEX_VERT_V,SYNCTEX_WIDTH_V,SYNCTEX_HEIGHT_V,SYNCTEX_DEPTH_V*/ + * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN, + * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH, + * SYNCTEX_HORIZ_V,SYNCTEX_VERT_V,SYNCTEX_WIDTH_V,SYNCTEX_HEIGHT_V,SYNCTEX_DEPTH_V*/ } synctex_horiz_box_node_t; synctex_node_t _synctex_new_hbox(synctex_scanner_t scanner); @@ -455,17 +460,17 @@ 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_implementation_4, /* next box */ + 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_implementation_4, /* next box */ (_synctex_info_getter_t)&_synctex_implementation_5 }; @@ -483,9 +488,9 @@ synctex_node_t _synctex_new_hbox(synctex_scanner_t scanner) { */ typedef struct { synctex_class_t class; - synctex_info_t implementation[3+SYNCTEX_DEPTH_IDX+1]; /* parent,sibling,friend, - * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN, - * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH*/ + synctex_info_t implementation[3+SYNCTEX_DEPTH_IDX+1]; /* parent,sibling,friend, + * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN, + * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH*/ } synctex_void_box_node_t; synctex_node_t _synctex_new_void_vbox(synctex_scanner_t scanner); @@ -493,17 +498,17 @@ 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 */ - NULL, /* No next box */ + 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 */ + NULL, /* No next box */ (_synctex_info_getter_t)&_synctex_implementation_3 }; @@ -520,17 +525,17 @@ 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 */ - NULL, /* No next box */ + 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 */ + NULL, /* No next box */ (_synctex_info_getter_t)&_synctex_implementation_3 }; @@ -543,34 +548,43 @@ synctex_node_t _synctex_new_void_hbox(synctex_scanner_t scanner) { return node; } -/* The medium nodes correspond to kern, glue and math nodes. */ +/* The medium nodes correspond to kern, glue, penalty and math nodes. */ typedef struct { synctex_class_t class; - synctex_info_t implementation[3+SYNCTEX_WIDTH_IDX+1]; /* parent,sibling,friend, - * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN, - * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH */ + synctex_info_t implementation[3+SYNCTEX_WIDTH_IDX+1]; /* parent,sibling,friend, + * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN, + * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH */ } synctex_medium_node_t; +#define SYNCTEX_IS_BOX(NODE)\ + ((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)) + +#define SYNCTEX_HAS_CHILDREN(NODE) (NODE && SYNCTEX_CHILD(NODE)) + +void _synctex_log_medium_node(synctex_node_t node); + +/* math node creator */ 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 */ - NULL, /* No next box */ + 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 */ + NULL, /* No next box */ (_synctex_info_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) { @@ -579,24 +593,60 @@ synctex_node_t _synctex_new_math(synctex_scanner_t scanner) { return node; } +/* kern node creator */ +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 */ + NULL, /* No next box */ + (_synctex_info_getter_t)&_synctex_implementation_3 +}; + +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; +} + +/* The small nodes correspond to glue and boundary nodes. */ +typedef struct { + synctex_class_t class; + synctex_info_t implementation[3+SYNCTEX_VERT_IDX+1]; /* parent,sibling,friend, + * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN, + * SYNCTEX_HORIZ,SYNCTEX_VERT */ +} synctex_small_node_t; + +void _synctex_log_small_node(synctex_node_t node); +/* glue node creator */ 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 */ - NULL, /* No next box */ + 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 */ + NULL, /* No next box */ (_synctex_info_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) { @@ -605,29 +655,29 @@ synctex_node_t _synctex_new_glue(synctex_scanner_t scanner) { 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 */ - NULL, /* No next box */ +/* boundary node creator */ +synctex_node_t _synctex_new_boundary(synctex_scanner_t scanner); +void _synctex_display_boundary(synctex_node_t node); + +static const _synctex_class_t synctex_class_boundary = { + NULL, /* No scanner yet */ + synctex_node_type_boundary, /* Node type */ + &_synctex_new_boundary, /* creator */ + &_synctex_free_leaf, /* destructor */ + &_synctex_log_small_node, /* log */ + &_synctex_display_boundary, /* display */ + &_synctex_implementation_0, /* parent */ + NULL, /* No child */ + &_synctex_implementation_1, /* sibling */ + &_synctex_implementation_2, /* friend */ + NULL, /* No next box */ (_synctex_info_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)); +synctex_node_t _synctex_new_boundary(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_small_node_t)); if(node) { - node->class = scanner?scanner->class+synctex_node_type_kern:(synctex_class_t)&synctex_class_kern; + node->class = scanner?scanner->class+synctex_node_type_boundary:(synctex_class_t)&synctex_class_boundary; } return node; } @@ -639,8 +689,8 @@ synctex_node_t _synctex_new_kern(synctex_scanner_t scanner) { * The synctex information is the SYNCTEX_TAG and SYNCTEX_NAME*/ typedef struct { synctex_class_t class; - synctex_info_t implementation[1+SYNCTEX_NAME_IDX+1]; /* sibling, - * SYNCTEX_TAG,SYNCTEX_NAME */ + synctex_info_t implementation[1+SYNCTEX_NAME_IDX+1]; /* sibling, + * SYNCTEX_TAG,SYNCTEX_NAME */ } synctex_input_t; synctex_node_t _synctex_new_input(synctex_scanner_t scanner); @@ -649,17 +699,17 @@ 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_input, /* destructor */ - &_synctex_log_input, /* log */ - &_synctex_display_input, /* display */ - NULL, /* No parent */ - NULL, /* No child */ - &_synctex_implementation_0, /* sibling */ - NULL, /* No friend */ - NULL, /* No next box */ + NULL, /* No scanner yet */ + synctex_node_type_input, /* Node type */ + &_synctex_new_input, /* creator */ + &_synctex_free_input, /* destructor */ + &_synctex_log_input, /* log */ + &_synctex_display_input, /* display */ + NULL, /* No parent */ + NULL, /* No child */ + &_synctex_implementation_0, /* sibling */ + NULL, /* No friend */ + NULL, /* No next box */ (_synctex_info_getter_t)&_synctex_implementation_1 }; @@ -690,7 +740,7 @@ synctex_node_t synctex_node_sheet(synctex_node_t node) while(node && node->class->type != synctex_node_type_sheet) { node = SYNCTEX_PARENT(node); } - /* exit the while loop either when node is NULL or node is a sheet */ + /* 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) @@ -709,8 +759,8 @@ sibling: if(SYNCTEX_SIBLING(node)) { return SYNCTEX_SIBLING(node); } - if((node = SYNCTEX_PARENT(node)) != NULL) { - if(node->class->type == synctex_node_type_sheet) {/* EXC_BAD_ACCESS? */ + if((node = SYNCTEX_PARENT(node))) { + if(node->class->type == synctex_node_type_sheet) {/* EXC_BAD_ACCESS? */ return NULL; } goto sibling; @@ -733,7 +783,7 @@ synctex_node_type_t synctex_node_type(synctex_node_t node) { /* Public node accessor: the human readable type */ const char * synctex_node_isa(synctex_node_t node) { static const char * isa[synctex_node_number_of_types] = - {"Not a node","sheet","vbox","void vbox","hbox","non void hbox","void hbox","kern","glue","math","input"}; + {"Not a node","input","sheet","vbox","void vbox","hbox","void hbox","kern","glue","math","boundary"}; return isa[synctex_node_type(node)]; } @@ -755,17 +805,38 @@ void synctex_node_display(synctex_node_t node) { SYNCTEX_DISPLAY(node); } +void _synctex_display_input(synctex_node_t node) { + printf("....Input:%i:%s\n", + SYNCTEX_TAG(node), + SYNCTEX_NAME(node)); + SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node)); +} + void _synctex_log_sheet(synctex_node_t sheet) { if(sheet) { printf("%s:%i\n",synctex_node_isa(sheet),SYNCTEX_PAGE(sheet)); - printf("SELF:%p",sheet); - printf(" SYNCTEX_PARENT:%p",SYNCTEX_PARENT(sheet)); - printf(" SYNCTEX_CHILD:%p",SYNCTEX_CHILD(sheet)); - printf(" SYNCTEX_SIBLING:%p",SYNCTEX_SIBLING(sheet)); - printf(" SYNCTEX_FRIEND:%p\n",SYNCTEX_FRIEND(sheet)); + printf("SELF:%p",(void *)sheet); + printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(sheet)); + printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(sheet)); + printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(sheet)); + printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(sheet)); } } +void _synctex_log_small_node(synctex_node_t node) { + printf("%s:%i,%i:%i,%i\n", + synctex_node_isa(node), + SYNCTEX_TAG(node), + SYNCTEX_LINE(node), + SYNCTEX_HORIZ(node), + SYNCTEX_VERT(node)); + printf("SELF:%p",(void *)node); + printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node)); + printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node)); + printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node)); + printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node)); +} + void _synctex_log_medium_node(synctex_node_t node) { printf("%s:%i,%i:%i,%i:%i\n", synctex_node_isa(node), @@ -774,11 +845,11 @@ void _synctex_log_medium_node(synctex_node_t node) { SYNCTEX_HORIZ(node), SYNCTEX_VERT(node), SYNCTEX_WIDTH(node)); - printf("SELF:%p",node); - printf(" SYNCTEX_PARENT:%p",SYNCTEX_PARENT(node)); - printf(" SYNCTEX_CHILD:%p",SYNCTEX_CHILD(node)); - printf(" SYNCTEX_SIBLING:%p",SYNCTEX_SIBLING(node)); - printf(" SYNCTEX_FRIEND:%p\n",SYNCTEX_FRIEND(node)); + printf("SELF:%p",(void *)node); + printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node)); + printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node)); + printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node)); + printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node)); } void _synctex_log_void_box(synctex_node_t node) { @@ -791,11 +862,11 @@ void _synctex_log_void_box(synctex_node_t node) { printf(":%i",SYNCTEX_WIDTH(node)); printf(",%i",SYNCTEX_HEIGHT(node)); printf(",%i",SYNCTEX_DEPTH(node)); - printf("\nSELF:%p",node); - printf(" SYNCTEX_PARENT:%p",SYNCTEX_PARENT(node)); - printf(" SYNCTEX_CHILD:%p",SYNCTEX_CHILD(node)); - printf(" SYNCTEX_SIBLING:%p",SYNCTEX_SIBLING(node)); - printf(" SYNCTEX_FRIEND:%p\n",SYNCTEX_FRIEND(node)); + printf("\nSELF:%p",(void *)node); + printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node)); + printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node)); + printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node)); + printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node)); } void _synctex_log_box(synctex_node_t node) { @@ -808,11 +879,11 @@ void _synctex_log_box(synctex_node_t node) { printf(":%i",SYNCTEX_WIDTH(node)); printf(",%i",SYNCTEX_HEIGHT(node)); printf(",%i",SYNCTEX_DEPTH(node)); - printf("\nSELF:%p",node); - printf(" SYNCTEX_PARENT:%p",SYNCTEX_PARENT(node)); - printf(" SYNCTEX_CHILD:%p",SYNCTEX_CHILD(node)); - printf(" SYNCTEX_SIBLING:%p",SYNCTEX_SIBLING(node)); - printf(" SYNCTEX_FRIEND:%p\n",SYNCTEX_FRIEND(node)); + printf("\nSELF:%p",(void *)node); + printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node)); + printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node)); + printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node)); + printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node)); } void _synctex_log_horiz_box(synctex_node_t node) { @@ -825,23 +896,23 @@ void _synctex_log_horiz_box(synctex_node_t node) { printf(":%i",SYNCTEX_WIDTH(node)); printf(",%i",SYNCTEX_HEIGHT(node)); printf(",%i",SYNCTEX_DEPTH(node)); - printf(":%i",SYNCTEX_HORIZ_V(node)); + printf("/%i",SYNCTEX_HORIZ_V(node)); printf(",%i",SYNCTEX_VERT_V(node)); printf(":%i",SYNCTEX_WIDTH_V(node)); printf(",%i",SYNCTEX_HEIGHT_V(node)); printf(",%i",SYNCTEX_DEPTH_V(node)); - printf("\nSELF:%p",node); - printf(" SYNCTEX_PARENT:%p",SYNCTEX_PARENT(node)); - printf(" SYNCTEX_CHILD:%p",SYNCTEX_CHILD(node)); - printf(" SYNCTEX_SIBLING:%p",SYNCTEX_SIBLING(node)); - printf(" SYNCTEX_FRIEND:%p\n",SYNCTEX_FRIEND(node)); + printf("\nSELF:%p",(void *)node); + printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node)); + printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node)); + printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node)); + printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node)); } void _synctex_log_input(synctex_node_t node) { printf("%s",synctex_node_isa(node)); printf(":%i",SYNCTEX_TAG(node)); printf(",%s",SYNCTEX_NAME(node)); - printf(" SYNCTEX_SIBLING:%p",SYNCTEX_SIBLING(node)); + printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node)); } void _synctex_display_sheet(synctex_node_t sheet) { @@ -933,10 +1004,12 @@ void _synctex_display_kern(synctex_node_t node) { SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node)); } -void _synctex_display_input(synctex_node_t node) { - printf("....Input:%i:%s\n", +void _synctex_display_boundary(synctex_node_t node) { + printf("....boundary:%i,%i:%i,%i\n", SYNCTEX_TAG(node), - SYNCTEX_NAME(node)); + SYNCTEX_LINE(node), + SYNCTEX_HORIZ(node), + SYNCTEX_VERT(node)); SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node)); } @@ -968,7 +1041,7 @@ typedef int synctex_status_t; /* Parameter error: */ # define SYNCTEX_STATUS_BAD_ARGUMENT -2 -# define SYNCTEX_FILE scanner->file +# define SYNCTEX_FILE (scanner->file) /* Actually, the minimum buffer size is driven by integer and float parsing. * ±0.123456789e123 @@ -976,55 +1049,14 @@ typedef int synctex_status_t; # define SYNCTEX_BUFFER_MIN_SIZE 16 # define SYNCTEX_BUFFER_SIZE 32768 -#include <stdarg.h> - -inline static int _synctex_error(char * reason,...) { - va_list arg; - int result; - result = fprintf(stderr,"SyncTeX ERROR: "); - va_start (arg, reason); - result += vfprintf(stderr, reason, arg); - va_end (arg); - result = fprintf(stderr,"\n"); - return result; -} - # ifdef SYNCTEX_NOTHING # pragma mark - # pragma mark Prototypes # endif -void _synctex_free_node(synctex_node_t node); -void _synctex_free_leaf(synctex_node_t node); -synctex_node_t _synctex_new_sheet(synctex_scanner_t scanner); -synctex_node_t _synctex_new_vbox(synctex_scanner_t scanner); -synctex_node_t _synctex_new_hbox(synctex_scanner_t scanner); -synctex_node_t _synctex_new_void_vbox(synctex_scanner_t scanner); -synctex_node_t _synctex_new_void_hbox(synctex_scanner_t scanner); -synctex_node_t _synctex_new_math(synctex_scanner_t scanner); -synctex_node_t _synctex_new_glue(synctex_scanner_t scanner); -synctex_node_t _synctex_new_kern(synctex_scanner_t scanner); -synctex_node_t _synctex_new_input(synctex_scanner_t scanner); -void _synctex_free_input(synctex_node_t node); -synctex_node_t synctex_node_next(synctex_node_t node); -synctex_node_type_t synctex_node_type(synctex_node_t node); -const char * synctex_node_isa(synctex_node_t node); -void synctex_node_log(synctex_node_t node); -void _synctex_log_sheet(synctex_node_t sheet); -void _synctex_log_medium_node(synctex_node_t node); void _synctex_log_void_box(synctex_node_t node); void _synctex_log_box(synctex_node_t node); void _synctex_log_horiz_box(synctex_node_t node); void _synctex_log_input(synctex_node_t node); -void _synctex_display_sheet(synctex_node_t sheet); -void _synctex_display_vbox(synctex_node_t node); -void _synctex_display_hbox(synctex_node_t node); -void _synctex_display_void_vbox(synctex_node_t node); -void _synctex_display_void_hbox(synctex_node_t node); -void _synctex_display_glue(synctex_node_t node); -void _synctex_display_math(synctex_node_t node); -void _synctex_display_kern(synctex_node_t node); -void _synctex_display_input(synctex_node_t node); -inline static int _synctex_error(char * reason,...); synctex_status_t _synctex_buffer_get_available_size(synctex_scanner_t scanner, size_t * size_ptr); synctex_status_t _synctex_next_line(synctex_scanner_t scanner); synctex_status_t _synctex_match_string(synctex_scanner_t scanner, const char * the_string); @@ -1039,47 +1071,11 @@ synctex_status_t _synctex_setup_visible_box(synctex_node_t box); synctex_status_t _synctex_horiz_box_setup_visible(synctex_node_t node,int h, int v); synctex_status_t _synctex_scan_sheet(synctex_scanner_t scanner, synctex_node_t parent); synctex_status_t _synctex_scan_content(synctex_scanner_t scanner); -void synctex_strip_last_path_extension(char * string); -synctex_scanner_t synctex_scanner_new_with_output_file(const char * output); -synctex_scanner_t synctex_scanner_new_with_contents_of_file(const char * name); -void synctex_scanner_free(synctex_scanner_t scanner); int synctex_scanner_pre_x_offset(synctex_scanner_t scanner); int synctex_scanner_pre_y_offset(synctex_scanner_t scanner); -int synctex_scanner_x_offset(synctex_scanner_t scanner); -int synctex_scanner_y_offset(synctex_scanner_t scanner); -float synctex_scanner_magnification(synctex_scanner_t scanner); -void synctex_scanner_display(synctex_scanner_t scanner); -const char * synctex_scanner_get_name(synctex_scanner_t scanner,int tag); -int synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name); -synctex_node_t synctex_scanner_input(synctex_scanner_t scanner); const char * synctex_scanner_get_output_fmt(synctex_scanner_t scanner); -const char * synctex_scanner_get_output(synctex_scanner_t scanner); -float synctex_node_h(synctex_node_t node); -float synctex_node_v(synctex_node_t node); -float synctex_node_width(synctex_node_t node); -float synctex_node_box_h(synctex_node_t node); -float synctex_node_box_v(synctex_node_t node); -float synctex_node_box_width(synctex_node_t node); -float synctex_node_box_height(synctex_node_t node); -float synctex_node_box_depth(synctex_node_t node); -float synctex_node_visible_h(synctex_node_t node); -float synctex_node_visible_v(synctex_node_t node); -float synctex_node_visible_width(synctex_node_t node); -float synctex_node_box_visible_h(synctex_node_t node); -float synctex_node_box_visible_v(synctex_node_t node); -float synctex_node_box_visible_width(synctex_node_t node); -float synctex_node_box_visible_height(synctex_node_t node); -float synctex_node_box_visible_depth(synctex_node_t node); -int synctex_node_page(synctex_node_t node); -int synctex_node_tag(synctex_node_t node); -int synctex_node_line(synctex_node_t node); -int synctex_node_column(synctex_node_t node); -synctex_node_t synctex_sheet_content(synctex_scanner_t scanner,int page); -int synctex_display_query(synctex_scanner_t scanner,const char * name,int line,int column); int _synctex_node_is_box(synctex_node_t node); -int synctex_edit_query(synctex_scanner_t scanner,int page,float h,float v); -synctex_node_t synctex_next_result(synctex_scanner_t scanner); -int synctex_bail(void); +int _synctex_bail(void); /* Try to ensure that the buffer contains at least size bytes. * Passing a huge size argument means the whole buffer length. @@ -1089,7 +1085,7 @@ int synctex_bail(void); * The value returned in size_ptr is the number of bytes now available in the buffer. * This is a nonnegative integer, it may take the value 0. * It is the responsibility of the caller to test whether this size is conforming to its needs. - * Negative values may returned in case of error, actually + * Negative values may return in case of error, actually * when there was an error reading the synctex file. */ synctex_status_t _synctex_buffer_get_available_size(synctex_scanner_t scanner, size_t * size_ptr) { size_t available = 0; @@ -1100,36 +1096,43 @@ synctex_status_t _synctex_buffer_get_available_size(synctex_scanner_t scanner, s if(size>SYNCTEX_BUFFER_SIZE){ size = SYNCTEX_BUFFER_SIZE; } - available = SYNCTEX_END - SYNCTEX_CUR; /* available is the number of unparsed chars in the buffer */ + available = SYNCTEX_END - SYNCTEX_CUR; /* available is the number of unparsed chars in the buffer */ if(size<=available) { - /* There are already sufficiently many characters in the buffer */ + /* There are already sufficiently many characters in the buffer */ size = available; return SYNCTEX_STATUS_OK; } if(SYNCTEX_FILE) { - /* Copy the remaining part of the buffer to the beginning, - * then read the next part of the file */ - int read = 0; + /* Copy the remaining part of the buffer to the beginning, + * then read the next part of the file */ + int already_read = 0; if(available) { memmove(SYNCTEX_START, SYNCTEX_CUR, available); } - SYNCTEX_CUR = SYNCTEX_START + available; /* the next character after the move, will change. */ - /* Fill the buffer up to its end */ - read = gzread(SYNCTEX_FILE,(void *)SYNCTEX_CUR,SYNCTEX_BUFFER_SIZE - available); - if(read>0) { - /* We assume that 0<read<=SYNCTEX_BUFFER_SIZE - available, such that - * SYNCTEX_CUR + read = SYNCTEX_START + available + read <= SYNCTEX_START + SYNCTEX_BUFFER_SIZE */ - SYNCTEX_END = SYNCTEX_CUR + read; + SYNCTEX_CUR = SYNCTEX_START + available; /* the next character after the move, will change. */ + /* Fill the buffer up to its end */ + already_read = gzread(SYNCTEX_FILE,(void *)SYNCTEX_CUR,SYNCTEX_BUFFER_SIZE - available); + if(already_read>0) { + /* We assume that 0<already_read<=SYNCTEX_BUFFER_SIZE - available, such that + * SYNCTEX_CUR + already_read = SYNCTEX_START + available + already_read <= SYNCTEX_START + SYNCTEX_BUFFER_SIZE */ + SYNCTEX_END = SYNCTEX_CUR + already_read; /* If the end of the file was reached, all the required SYNCTEX_BUFFER_SIZE - available * may not be filled with values from the file. - * In that case, the buffer should stop properly after read characters. */ + * In that case, the buffer should stop properly after already_read characters. */ * SYNCTEX_END = '\0'; SYNCTEX_CUR = SYNCTEX_START; - size = SYNCTEX_END - SYNCTEX_CUR; /* == old available + read*/ - return SYNCTEX_STATUS_OK; /* May be available is less than size, the caller will have to test. */ - } else if(read<0) { - /*There is an error */ - _synctex_error("gzread error (1:%i)",read); + size = SYNCTEX_END - SYNCTEX_CUR; /* == old available + already_read*/ + return SYNCTEX_STATUS_OK; /* May be available is less than size, the caller will have to test. */ + } else if(0>already_read) { + /* There is an error in zlib */ + int errnum = 0; + const char * error_string = gzerror(SYNCTEX_FILE, &errnum); + if(Z_ERRNO == errnum) { + /* There is an error in zlib caused by the file system */ + _synctex_error("gzread error from the file system (%i)",errno); + } else { + _synctex_error("gzread error (%i:%i,%s)",already_read,errnum,error_string); + } return SYNCTEX_STATUS_ERROR; } else { /* Nothing was read, we are at the end of the file. */ @@ -1137,13 +1140,13 @@ synctex_status_t _synctex_buffer_get_available_size(synctex_scanner_t scanner, s SYNCTEX_FILE = NULL; SYNCTEX_END = SYNCTEX_CUR; SYNCTEX_CUR = SYNCTEX_START; - * SYNCTEX_END = '\0';/* Terminate the string properly.*/ + * SYNCTEX_END = '\0';/* Terminate the string properly.*/ size = SYNCTEX_END - SYNCTEX_CUR; - return SYNCTEX_STATUS_EOF; /* there might be a bit of text left */ + return SYNCTEX_STATUS_EOF; /* there might be a bit of text left */ } - /* At this point, the function has already returned from above */ + /* At this point, the function has already returned from above */ } - /* We cannot enlarge the buffer because the end of the file was reached. */ + /* We cannot enlarge the buffer because the end of the file was reached. */ size = available; return SYNCTEX_STATUS_EOF; # undef size @@ -1194,14 +1197,14 @@ infinite_loop: * As side effect, the buffer state may have changed if the given argument string can't fit into the buffer. */ synctex_status_t _synctex_match_string(synctex_scanner_t scanner, const char * the_string) { - size_t tested_len = 0; /* the number of characters at the beginning of the_string that match */ - size_t remaining_len = 0; /* the number of remaining characters of the_string that should match */ + size_t tested_len = 0; /* the number of characters at the beginning of the_string that match */ + size_t remaining_len = 0; /* the number of remaining characters of the_string that should match */ size_t available = 0; synctex_status_t status = 0; if(NULL == scanner || NULL == the_string) { return SYNCTEX_STATUS_BAD_ARGUMENT; } - remaining_len = strlen(the_string); /* All the_string should match */ + remaining_len = strlen(the_string); /* All the_string should match */ if(0 == remaining_len) { return SYNCTEX_STATUS_BAD_ARGUMENT; } @@ -1233,9 +1236,9 @@ return_OK: /* update the remaining length and the parsed length. */ remaining_len -= available; tested_len += available; - SYNCTEX_CUR += available; /* We validate the tested characters. */ + SYNCTEX_CUR += available; /* We validate the tested characters. */ if(0 == remaining_len) { - /* Nothing left to test, we have found the given string, we return the length. */ + /* Nothing left to test, we have found the given string, we return the length. */ return tested_len; } /* We also have to record the current state of the file cursor because @@ -1246,7 +1249,7 @@ return_OK: * can be safely discarded. */ offset = gztell(SYNCTEX_FILE); /* offset now corresponds to the first character of the file that was not buffered. */ - available = SYNCTEX_CUR - SYNCTEX_START; /* available can be used as temporary placeholder. */ + available = SYNCTEX_CUR - SYNCTEX_START; /* available can be used as temporary placeholder. */ /* available now corresponds to the number of chars that where already buffered and * that match the head of the_string. If in fine the_string does not match, all these chars must be recovered * because the buffer contents is completely replaced by _synctex_buffer_get_available_size. @@ -1260,14 +1263,14 @@ more_characters: available = remaining_len; status = _synctex_buffer_get_available_size(scanner,&available); if(status<SYNCTEX_STATUS_EOF) { - return status; /* This is an error, no need to go further. */ + return status; /* This is an error, no need to go further. */ } if(available==0) { - /* Missing characters: recover the initial state of the file and return. */ + /* Missing characters: recover the initial state of the file and return. */ return_NOT_OK: if(offset != gzseek(SYNCTEX_FILE,offset,SEEK_SET)) { /* This is a critical error, we could not recover the previous state. */ - fprintf(stderr,"SyncTeX critical ERROR: can't seek file\n"); + _synctex_error("can't seek file"); return SYNCTEX_STATUS_ERROR; } /* Next time we are asked to fill the buffer, @@ -1278,7 +1281,7 @@ return_NOT_OK: if(available<remaining_len) { /* We'll have to loop one more time. */ if(strncmp((char *)SYNCTEX_CUR,the_string,available)) { - /* This is not the expected string, recover the previous state and return. */ + /* This is not the expected string, recover the previous state and return. */ goto return_NOT_OK; } /* Advance the_string to the first untested character. */ @@ -1286,21 +1289,21 @@ return_NOT_OK: /* update the remaining length and the parsed length. */ remaining_len -= available; tested_len += available; - SYNCTEX_CUR += available; /* We validate the tested characters. */ + SYNCTEX_CUR += available; /* We validate the tested characters. */ if(0 == remaining_len) { - /* Nothing left to test, we have found the given string. */ + /* Nothing left to test, we have found the given string. */ return SYNCTEX_STATUS_OK; } goto more_characters; } /* This is the last step. */ if(strncmp((char *)SYNCTEX_CUR,the_string,remaining_len)) { - /* This is not the expected string, recover the previous state and return. */ + /* This is not the expected string, recover the previous state and return. */ goto return_NOT_OK; } goto return_OK; } else { - /* The buffer can't contain the given string argument, and the EOF was reached */ + /* The buffer can't contain the given string argument, and the EOF was reached */ return SYNCTEX_STATUS_EOF; } } @@ -1327,17 +1330,17 @@ synctex_status_t _synctex_decode_int(synctex_scanner_t scanner, int* value_ref) available = SYNCTEX_BUFFER_MIN_SIZE; status = _synctex_buffer_get_available_size(scanner, &available); if(status<SYNCTEX_STATUS_EOF) { - return status;/* Forward error. */ + return status;/* Forward error. */ } if(available==0) { - return SYNCTEX_STATUS_EOF;/* it is the end of file. */ + return SYNCTEX_STATUS_EOF;/* it is the end of file. */ } ptr = SYNCTEX_CUR; if(*ptr==':' || *ptr==',') { ++ptr; --available; if(available==0) { - return SYNCTEX_STATUS_NOT_OK;/* It is not possible to scan an int */ + return SYNCTEX_STATUS_NOT_OK;/* It is not possible to scan an int */ } } result = (int)strtol((char *)ptr, (char **)&end, 10); @@ -1346,9 +1349,9 @@ synctex_status_t _synctex_decode_int(synctex_scanner_t scanner, int* value_ref) if(value_ref) { * value_ref = result; } - return SYNCTEX_STATUS_OK;/* Successfully scanned an int */ + return SYNCTEX_STATUS_OK;/* Successfully scanned an int */ } - return SYNCTEX_STATUS_NOT_OK;/* Could not scan an int */ + return SYNCTEX_STATUS_NOT_OK;/* Could not scan an int */ } /* The purpose of this function is to read a string. @@ -1372,13 +1375,13 @@ synctex_status_t _synctex_decode_string(synctex_scanner_t scanner, char ** value unsigned char * end = NULL; size_t current_size = 0; size_t new_size = 0; - size_t len = 0;/* The number of bytes to copy */ + size_t len = 0;/* The number of bytes to copy */ size_t available = 0; synctex_status_t status = 0; if(NULL == scanner || NULL == value_ref) { return SYNCTEX_STATUS_BAD_ARGUMENT; } - /* The buffer must at least contain one character: the '\n' end of line marker */ + /* The buffer must at least contain one character: the '\n' end of line marker */ if(SYNCTEX_CUR>=SYNCTEX_END) { available = 1; status = _synctex_buffer_get_available_size(scanner,&available); @@ -1389,16 +1392,16 @@ synctex_status_t _synctex_decode_string(synctex_scanner_t scanner, char ** value return SYNCTEX_STATUS_EOF; } } - /* Now we are sure that there is at least one available character, either because - * SYNCTEX_CUR was already < SYNCTEX_END, or because the buffer has been properly filled. */ - /* end will point to the next unparsed '\n' character in the file, when mapped to the buffer. */ + /* Now we are sure that there is at least one available character, either because + * SYNCTEX_CUR was already < SYNCTEX_END, or because the buffer has been properly filled. */ + /* end will point to the next unparsed '\n' character in the file, when mapped to the buffer. */ end = SYNCTEX_CUR; - * value_ref = NULL;/* Initialize, it will be realloc'ed */ - /* We scan all the characters up to the next '\n' */ + * value_ref = NULL;/* Initialize, it will be realloc'ed */ + /* We scan all the characters up to the next '\n' */ next_character: if(end<SYNCTEX_END) { if(*end == '\n') { - /* OK, we found where to stop */ + /* OK, we found where to stop */ len = end - SYNCTEX_CUR; if(current_size>UINT_MAX-len-1) { /* But we have reached the limit: we do not have current_size+len+1>UINT_MAX. @@ -1412,8 +1415,8 @@ next_character: * where we have assumed that len<UINT_MAX */ if((* value_ref = realloc(* value_ref,new_size+1)) != NULL) { if(memcpy((*value_ref)+current_size,SYNCTEX_CUR,len)) { - (* value_ref)[new_size]='\0'; /* Terminate the string */ - SYNCTEX_CUR += len;/* Advance to the terminating '\n' */ + (* value_ref)[new_size]='\0'; /* Terminate the string */ + SYNCTEX_CUR += len;/* Advance to the terminating '\n' */ return SYNCTEX_STATUS_OK; } free(* value_ref); @@ -1428,7 +1431,7 @@ next_character: goto next_character; } } else { - /* end == SYNCTEX_END */ + /* end == SYNCTEX_END */ len = SYNCTEX_END - SYNCTEX_CUR; if(current_size>UINT_MAX-len-1) { /* We have reached the limit. */ @@ -1438,8 +1441,8 @@ next_character: new_size = current_size+len; if((* value_ref = realloc(* value_ref,new_size+1)) != NULL) { if(memcpy((*value_ref)+current_size,SYNCTEX_CUR,len)) { - (* value_ref)[new_size]='\0'; /* Terminate the string */ - SYNCTEX_CUR = SYNCTEX_END;/* Advance the cursor to the end of the bufer */ + (* value_ref)[new_size]='\0'; /* Terminate the string */ + SYNCTEX_CUR = SYNCTEX_END;/* Advance the cursor to the end of the bufer */ return SYNCTEX_STATUS_OK; } free(* value_ref); @@ -1447,7 +1450,7 @@ next_character: _synctex_error("could not copy memory (2)."); return SYNCTEX_STATUS_ERROR; } - /* Huge memory problem */ + /* Huge memory problem */ _synctex_error("could not allocate memory (2)."); return SYNCTEX_STATUS_ERROR; } @@ -1501,7 +1504,7 @@ synctex_status_t _synctex_scan_input(synctex_scanner_t scanner) { /* Prepend this input node to the input linked list of the scanner */ SYNCTEX_SET_SIBLING(input,scanner->input); scanner->input = input; - return _synctex_next_line(scanner);/* read the line termination character, if any */ + return _synctex_next_line(scanner);/* read the line termination character, if any */ /* Now, set up the path */ } @@ -1533,7 +1536,7 @@ not_found: } goto not_found; } - /* A line is found, scan the value */ + /* A line is found, scan the value */ return (*decoder)(scanner,value_ref); } @@ -1705,19 +1708,19 @@ post_scriptum_not_found: if(status<SYNCTEX_STATUS_EOF) { return status; } else if(status<SYNCTEX_STATUS_OK) { - return SYNCTEX_STATUS_OK;/* The EOF is found, we have properly scanned the file */ + return SYNCTEX_STATUS_OK;/* The EOF is found, we have properly scanned the file */ } goto post_scriptum_not_found; } - /* We found the name, advance to the next line. */ + /* We found the name, advance to the next line. */ next_line: status = _synctex_next_line(scanner); if(status<SYNCTEX_STATUS_EOF) { return status; } else if(status<SYNCTEX_STATUS_OK) { - return SYNCTEX_STATUS_OK;/* The EOF is found, we have properly scanned the file */ + return SYNCTEX_STATUS_OK;/* The EOF is found, we have properly scanned the file */ } - /* Scanning the information */ + /* Scanning the information */ status = _synctex_match_string(scanner,"Magnification:"); if(status == SYNCTEX_STATUS_OK ) { #ifdef HAVE_SETLOCALE @@ -1741,7 +1744,7 @@ next_line: if(status<SYNCTEX_STATUS_EOF){ report_record_problem: _synctex_error("Problem reading the Post Scriptum records"); - return status; /* echo the error. */ + return status; /* echo the error. */ } status = _synctex_match_string(scanner,"X Offset:"); if(status == SYNCTEX_STATUS_OK) { @@ -1789,9 +1792,9 @@ count_again: } status = _synctex_scan_named(scanner,"Count:",&(scanner->count),(synctex_decoder_t)&_synctex_decode_int); if(status < SYNCTEX_STATUS_EOF) { - return status; /* forward the error */ - } else if(status < SYNCTEX_STATUS_OK) { /* No Count record found */ - status = _synctex_next_line(scanner); /* Advance one more line */ + return status; /* forward the error */ + } else if(status < SYNCTEX_STATUS_OK) { /* No Count record found */ + status = _synctex_next_line(scanner); /* Advance one more line */ if(status<SYNCTEX_STATUS_OK) { return status; } @@ -1807,21 +1810,21 @@ count_again: * At creation time, the visible size is set to the values of the real size. */ synctex_status_t _synctex_setup_visible_box(synctex_node_t box) { - if(NULL == box - || (box->class->type != synctex_node_type_hbox - && box->class->type != synctex_node_type_hbox_non_void - && box->class->type != synctex_node_type_vbox)) { - return SYNCTEX_STATUS_BAD_ARGUMENT; - } - if(SYNCTEX_INFO(box) != NULL) { - SYNCTEX_HORIZ_V(box) = SYNCTEX_HORIZ(box); - SYNCTEX_VERT_V(box) = SYNCTEX_VERT(box); - SYNCTEX_WIDTH_V(box) = SYNCTEX_WIDTH(box); - SYNCTEX_HEIGHT_V(box) = SYNCTEX_HEIGHT(box); - SYNCTEX_DEPTH_V(box) = SYNCTEX_DEPTH(box); - return SYNCTEX_STATUS_OK; + if(box) { + switch(box->class->type) { + case synctex_node_type_hbox: + if(SYNCTEX_INFO(box) != NULL) { + SYNCTEX_HORIZ_V(box) = SYNCTEX_HORIZ(box); + SYNCTEX_VERT_V(box) = SYNCTEX_VERT(box); + SYNCTEX_WIDTH_V(box) = SYNCTEX_WIDTH(box); + SYNCTEX_HEIGHT_V(box) = SYNCTEX_HEIGHT(box); + SYNCTEX_DEPTH_V(box) = SYNCTEX_DEPTH(box); + return SYNCTEX_STATUS_OK; + } + return SYNCTEX_STATUS_ERROR; + } } - return SYNCTEX_STATUS_ERROR; + return SYNCTEX_STATUS_BAD_ARGUMENT; } /* This method is sent to an horizontal box to setup the visible size @@ -1833,40 +1836,31 @@ synctex_status_t _synctex_horiz_box_setup_visible(synctex_node_t node,int h, int # pragma unused(v) # endif int itsBtm, itsTop; - if(NULL == node || (node->class->type != synctex_node_type_hbox - && node->class->type != synctex_node_type_hbox_non_void)) { + if(NULL == node || node->class->type != synctex_node_type_hbox) { return SYNCTEX_STATUS_BAD_ARGUMENT; } if(SYNCTEX_WIDTH_V(node)<0) { - itsBtm = SYNCTEX_HORIZ_V(node)+SYNCTEX_WIDTH_V(node); - itsTop = SYNCTEX_HORIZ_V(node); + itsBtm = SYNCTEX_HORIZ_V(node); + itsTop = SYNCTEX_HORIZ_V(node)-SYNCTEX_WIDTH_V(node); if(h<itsBtm) { - itsBtm -= h; - SYNCTEX_WIDTH_V(node) -= itsBtm; - } - if(h>itsTop) { - h -= itsTop; - SYNCTEX_WIDTH_V(node) -= h; - SYNCTEX_HORIZ_V(node) += h; + SYNCTEX_HORIZ_V(node) = h; + SYNCTEX_WIDTH_V(node) = SYNCTEX_HORIZ_V(node) - itsTop; + } else if(h>itsTop) { + SYNCTEX_WIDTH_V(node) = SYNCTEX_HORIZ_V(node) - h; } } else { itsBtm = SYNCTEX_HORIZ_V(node); itsTop = SYNCTEX_HORIZ_V(node)+SYNCTEX_WIDTH_V(node); if(h<itsBtm) { - itsBtm -= h; - SYNCTEX_HORIZ_V(node) -= itsBtm; - SYNCTEX_WIDTH_V(node) += itsBtm; - } - if(h>itsTop) { - h -= itsTop; - SYNCTEX_WIDTH_V(node) += h; + SYNCTEX_HORIZ_V(node) = h; + SYNCTEX_WIDTH_V(node) = itsTop - SYNCTEX_HORIZ_V(node); + } else if(h>itsTop) { + SYNCTEX_WIDTH_V(node) = h - SYNCTEX_HORIZ_V(node); } } return SYNCTEX_STATUS_OK; } -int synctex_bail(void); - /* Used when parsing the synctex file. * The sheet argument is a newly created sheet node that will hold the contents. * Something is returned in case of error. @@ -1878,13 +1872,12 @@ synctex_status_t _synctex_scan_sheet(synctex_scanner_t scanner, synctex_node_t s synctex_node_t box = sheet; int friend_index = 0; synctex_info_t * info = NULL; - int curh, curv; synctex_status_t status = 0; size_t available = 0; if((NULL == scanner) || (NULL == sheet)) { return SYNCTEX_STATUS_BAD_ARGUMENT; } - /* We MUST start with a box, so at this level, the unique possibility is '[', '(' or "}". */ + /* We MUST start with a box, so at this level, the unique possibility is '[', '(' or "}". */ prepare_loop: if(SYNCTEX_CUR<SYNCTEX_END) { if(*SYNCTEX_CUR == '[') { @@ -1900,7 +1893,7 @@ scan_vbox: || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX) - || (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK)) { + || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { _synctex_error("Bad vbox record."); #define SYNCTEX_RETURN(STATUS) return STATUS; SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); @@ -1908,7 +1901,7 @@ scan_vbox: SYNCTEX_SET_CHILD(parent,child); parent = child; child = NULL; - goto vertical_loop; + goto child_loop;/* next created node will be a child */ } else { _synctex_error("Can't create vbox record."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); @@ -1925,14 +1918,16 @@ scan_hbox: || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX) || _synctex_setup_visible_box(child)<SYNCTEX_STATUS_OK - || (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK)) { + || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { _synctex_error("Bad hbox record."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child)); + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child)); SYNCTEX_SET_CHILD(parent,child); parent = child; child = NULL; - goto vertical_loop; + goto child_loop;/* next created node will be a child */ } else { _synctex_error("Can't create hbox record."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); @@ -1941,7 +1936,7 @@ scan_hbox: scan_teehs: ++SYNCTEX_CUR; if(NULL == parent || parent->class->type != synctex_node_type_sheet - || (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK)) { + || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { _synctex_error("Unexpected end of sheet."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } @@ -1955,7 +1950,7 @@ scan_anchor: } goto prepare_loop; } else { - /* _synctex_error("Ignored record %c\n",*SYNCTEX_CUR); */ + /* _synctex_error("Ignored record %c\n",*SYNCTEX_CUR); */ ++SYNCTEX_CUR; if(_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { _synctex_error("Unexpected end."); @@ -1973,12 +1968,15 @@ scan_anchor: goto prepare_loop; } } - synctex_bail(); -vertical_loop: + _synctex_bail(); +/* The child loop means that we go do one level, when we just created a box node, + * the next node created is a child of this box. */ +child_loop: if(SYNCTEX_CUR<SYNCTEX_END) { if(*SYNCTEX_CUR == '[') { goto scan_vbox; } else if(*SYNCTEX_CUR == ']') { +scan_xobv: ++SYNCTEX_CUR; if(NULL != parent && parent->class->type == synctex_node_type_vbox) { #define SYNCTEX_UPDATE_BOX_FRIEND(NODE)\ @@ -1986,7 +1984,7 @@ vertical_loop: SYNCTEX_SET_FRIEND(NODE,(scanner->lists_of_friends)[friend_index]);\ (scanner->lists_of_friends)[friend_index] = NODE; if(NULL == SYNCTEX_CHILD(parent)) { - /* only void boxes are friends */ + /* only void boxes are friends */ SYNCTEX_UPDATE_BOX_FRIEND(parent); } child = parent; @@ -1998,20 +1996,21 @@ vertical_loop: _synctex_error("Uncomplete sheet."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } - goto horizontal_loop; + goto sibling_loop; } else if(*SYNCTEX_CUR == '(') { goto scan_hbox; } else if(*SYNCTEX_CUR == ')') { +scan_xobh: ++SYNCTEX_CUR; - if(NULL != parent && (parent->class->type == synctex_node_type_hbox - || parent->class->type == synctex_node_type_hbox_non_void)) { + if((parent) && parent->class->type == synctex_node_type_hbox) { if(NULL == child) { + /* Only boxes with no children are friends, + * boxes with children are indirectly friends through one of their descendants. */ SYNCTEX_UPDATE_BOX_FRIEND(parent); } - if(parent->class->type == synctex_node_type_hbox_non_void) { - SYNCTEX_SET_NEXT_BOX(box,parent); - box = parent; - } + /* setting the next horizontal box at the end ensures that a child is recorded before any of its ancestors. */ + SYNCTEX_SET_NEXT_HORIZ_BOX(box,parent); + box = parent; child = parent; parent = SYNCTEX_PARENT(child); } else { @@ -2021,7 +2020,7 @@ vertical_loop: _synctex_error("Uncomplete sheet."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } - goto horizontal_loop; + goto sibling_loop; } else if(*SYNCTEX_CUR == 'v') { ++SYNCTEX_CUR; if(NULL != (child = _synctex_new_void_vbox(scanner)) @@ -2033,7 +2032,7 @@ vertical_loop: || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX) - || (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK)) { + || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { _synctex_error("Bad void vbox record."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } @@ -2043,7 +2042,7 @@ vertical_loop: SYNCTEX_SET_FRIEND(NODE,(scanner->lists_of_friends)[friend_index]);\ (scanner->lists_of_friends)[friend_index] = NODE; SYNCTEX_UPDATE_FRIEND(child); - goto horizontal_loop; + goto sibling_loop; } else { _synctex_error("Can't create vbox record."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); @@ -2059,15 +2058,15 @@ vertical_loop: || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX) - || (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK)) { + || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { _synctex_error("Bad void hbox record."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } SYNCTEX_SET_CHILD(parent,child); SYNCTEX_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; + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child)); + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child)); + goto sibling_loop; } else { _synctex_error("Can't create void hbox record."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); @@ -2081,40 +2080,19 @@ vertical_loop: || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX) - || (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK)) { + || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { _synctex_error("Bad kern record."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } SYNCTEX_SET_CHILD(parent,child); - _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); - #define SYNCTEX_HBOX_SET_NON_VOID(NODE)\ - if(NODE->class->type == synctex_node_type_hbox) {\ - NODE->class->type = synctex_node_type_hbox_non_void;\ - } - SYNCTEX_HBOX_SET_NON_VOID(parent); SYNCTEX_UPDATE_FRIEND(child); - if(NULL == parent) { - _synctex_error("Missing parent for Child"); - synctex_node_log(child); - SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); - } - goto horizontal_loop; + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child)); + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)-SYNCTEX_WIDTH(child),SYNCTEX_VERT(child)); + goto sibling_loop; } else { _synctex_error("Can't create kern record."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } - } else if(*SYNCTEX_CUR == 'x') { - ++SYNCTEX_CUR; - if(_synctex_decode_int(scanner,NULL)<SYNCTEX_STATUS_OK - || _synctex_decode_int(scanner,NULL)<SYNCTEX_STATUS_OK - || _synctex_decode_int(scanner,&curh)<SYNCTEX_STATUS_OK - || _synctex_decode_int(scanner,&curv)<SYNCTEX_STATUS_OK - || (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK)) { - _synctex_error("Bad x record."); - SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); - } - _synctex_horiz_box_setup_visible(parent,curh,curv); - goto vertical_loop; } else if(*SYNCTEX_CUR == 'g') { ++SYNCTEX_CUR; if(NULL != (child = _synctex_new_glue(scanner)) @@ -2123,15 +2101,14 @@ vertical_loop: || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX) - || (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK)) { + || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { _synctex_error("Bad glue record."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } SYNCTEX_SET_CHILD(parent,child); - SYNCTEX_HBOX_SET_NON_VOID(parent); - _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child)); SYNCTEX_UPDATE_FRIEND(child); - goto horizontal_loop; + goto sibling_loop; } else { _synctex_error("Can't create glue record."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); @@ -2144,15 +2121,34 @@ vertical_loop: || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX) - || (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK)) { + || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { _synctex_error("Bad math record."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } SYNCTEX_SET_CHILD(parent,child); - SYNCTEX_HBOX_SET_NON_VOID(parent); - _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child)); SYNCTEX_UPDATE_FRIEND(child); - goto horizontal_loop; + goto sibling_loop; + } else { + _synctex_error("Can't create math record."); + SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); + } + } else if(*SYNCTEX_CUR == 'x') { + ++SYNCTEX_CUR; + if(NULL != (child = _synctex_new_boundary(scanner)) + && NULL != (info = SYNCTEX_INFO(child))) { + if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX) + || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX) + || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX) + || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX) + || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { + _synctex_error("Bad boundary record."); + SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); + } + SYNCTEX_SET_CHILD(parent,child); + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child)); + SYNCTEX_UPDATE_FRIEND(child); + goto sibling_loop; } else { _synctex_error("Can't create math record."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); @@ -2162,13 +2158,13 @@ vertical_loop: } else if(*SYNCTEX_CUR == '!') { goto scan_anchor; } else { - /* _synctex_error("Ignored record %c\n",*SYNCTEX_CUR); */ + /* _synctex_error("Ignored record %c\n",*SYNCTEX_CUR); */ ++SYNCTEX_CUR; if(_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { _synctex_error("Unexpected end."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } - goto vertical_loop; + goto child_loop; } } else { available = 1; @@ -2177,11 +2173,13 @@ vertical_loop: _synctex_error("Uncomplete sheet(0)"); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } else { - goto vertical_loop; + goto child_loop; } } - synctex_bail(); -horizontal_loop: + _synctex_bail(); +/* The vertical loop means that we are on the same level, for example when we just ended a box. + * If a node is created now, it will be a sibling of the current node, sharing the same parent. */ +sibling_loop: if(SYNCTEX_CUR<SYNCTEX_END) { if(*SYNCTEX_CUR == '[') { ++SYNCTEX_CUR; @@ -2194,34 +2192,20 @@ horizontal_loop: || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX) - || (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK)) { + || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { _synctex_error("Bad vbox record (2)."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } SYNCTEX_SET_SIBLING(child,sibling); parent = sibling; child = NULL; - goto vertical_loop; + goto child_loop; } else { _synctex_error("Can't create vbox record (2)."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } } else if(*SYNCTEX_CUR == ']') { - ++SYNCTEX_CUR; - if(NULL != parent && parent->class->type == synctex_node_type_vbox) { - if(NULL == child) { - SYNCTEX_UPDATE_BOX_FRIEND(parent); - } - child = parent; - parent = SYNCTEX_PARENT(child); - } else { - _synctex_error("Unexpected end of vbox record (2), ignored."); - } - if(_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { - _synctex_error("Unexpected end of file (2)."); - SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); - } - goto horizontal_loop; + goto scan_xobv; } else if(*SYNCTEX_CUR == '(') { ++SYNCTEX_CUR; if(NULL != (sibling = _synctex_new_hbox(scanner)) && @@ -2234,39 +2218,23 @@ horizontal_loop: || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX) || _synctex_setup_visible_box(sibling)<SYNCTEX_STATUS_OK - || (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK)) { + || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { _synctex_error("Bad hbox record (2)."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } SYNCTEX_SET_SIBLING(child,sibling); - parent = sibling; + child = sibling; + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child)); + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child)); + parent = child; child = NULL; - goto vertical_loop; + goto child_loop; } else { _synctex_error("Can't create hbox record (2)."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } } else if(*SYNCTEX_CUR == ')') { - ++SYNCTEX_CUR; - if(NULL != parent &&(parent->class->type == synctex_node_type_hbox - ||parent->class->type == synctex_node_type_hbox_non_void)) { - if(NULL == child) { - SYNCTEX_UPDATE_BOX_FRIEND(parent); - } - if(parent->class->type == synctex_node_type_hbox_non_void) { - SYNCTEX_SET_NEXT_BOX(box,parent); - box = parent; - } - child = parent; - parent = SYNCTEX_PARENT(child); - } else { - _synctex_error("Unexpected end of hbox record (2)."); - } - if(_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { - _synctex_error("Unexpected end of file (2,')')."); - SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); - } - goto horizontal_loop; + goto scan_xobh; } else if(*SYNCTEX_CUR == 'v') { ++SYNCTEX_CUR; if(NULL != (sibling = _synctex_new_void_vbox(scanner)) && @@ -2278,14 +2246,14 @@ horizontal_loop: || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX) - || (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK)) { + || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { _synctex_error("Bad void vbox record (2)."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } SYNCTEX_SET_SIBLING(child,sibling); - SYNCTEX_UPDATE_FRIEND(sibling); child = sibling; - goto horizontal_loop; + SYNCTEX_UPDATE_FRIEND(child); + goto sibling_loop; } else { _synctex_error("can't create void vbox record (2)."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); @@ -2301,32 +2269,20 @@ horizontal_loop: || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX) - || (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK)) { + || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { _synctex_error("Bad void hbox record (2)."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } SYNCTEX_SET_SIBLING(child,sibling); - SYNCTEX_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; + SYNCTEX_UPDATE_FRIEND(child); + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child)); + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)+SYNCTEX_ABS_WIDTH(child),SYNCTEX_VERT(child)); + goto sibling_loop; } else { _synctex_error("can't create void hbox record (2)."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } - } else if(*SYNCTEX_CUR == 'x') { - ++SYNCTEX_CUR; - if(_synctex_decode_int(scanner,NULL)<SYNCTEX_STATUS_OK - || _synctex_decode_int(scanner,NULL)<SYNCTEX_STATUS_OK - || _synctex_decode_int(scanner,&curh)<SYNCTEX_STATUS_OK - || _synctex_decode_int(scanner,&curv)<SYNCTEX_STATUS_OK - || (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK)) { - _synctex_error("Bad x record (2)."); - SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); - } - _synctex_horiz_box_setup_visible(parent,curh,curv); - goto horizontal_loop; } else if(*SYNCTEX_CUR == 'k') { ++SYNCTEX_CUR; if(NULL != (sibling = _synctex_new_kern(scanner)) @@ -2336,16 +2292,16 @@ horizontal_loop: || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX) - || (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK)) { + || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { _synctex_error("Bad kern record (2)."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } SYNCTEX_SET_SIBLING(child,sibling); - SYNCTEX_UPDATE_FRIEND(sibling); child = sibling; - _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); - SYNCTEX_HBOX_SET_NON_VOID(parent); - goto horizontal_loop; + SYNCTEX_UPDATE_FRIEND(child); + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child)); + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child)-SYNCTEX_WIDTH(child),SYNCTEX_VERT(child)); + goto sibling_loop; } else { _synctex_error("Can't create kern record (2)."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); @@ -2358,16 +2314,15 @@ horizontal_loop: || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX) - || (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK)) { + || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { _synctex_error("Bad glue record (2)."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } SYNCTEX_SET_SIBLING(child,sibling); - SYNCTEX_UPDATE_FRIEND(sibling); child = sibling; - _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); - SYNCTEX_HBOX_SET_NON_VOID(parent); - goto horizontal_loop; + SYNCTEX_UPDATE_FRIEND(child); + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child)); + goto sibling_loop; } else { _synctex_error("Can't create glue record (2)."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); @@ -2380,20 +2335,40 @@ horizontal_loop: || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX) || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX) - || (_synctex_next_line(scanner)<SYNCTEX_STATUS_OK)) { + || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { _synctex_error("Bad math record (2)."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } SYNCTEX_SET_SIBLING(child,sibling); - _synctex_horiz_box_setup_visible(parent,synctex_node_h(sibling),synctex_node_v(sibling)); - SYNCTEX_UPDATE_FRIEND(sibling); child = sibling; - SYNCTEX_HBOX_SET_NON_VOID(parent); - goto horizontal_loop; + SYNCTEX_UPDATE_FRIEND(child); + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child)); + goto sibling_loop; } else { _synctex_error("Can't create math record (2)."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } + } else if(*SYNCTEX_CUR == 'x') { + ++SYNCTEX_CUR; + if(NULL != (sibling = _synctex_new_boundary(scanner)) + && NULL != (info = SYNCTEX_INFO(sibling))) { + if(SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX) + || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX) + || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX) + || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX) + || _synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { + _synctex_error("Bad boundary record (2)."); + SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); + } + SYNCTEX_SET_SIBLING(child,sibling); + child = sibling; + SYNCTEX_UPDATE_FRIEND(child); + _synctex_horiz_box_setup_visible(parent,SYNCTEX_HORIZ(child),SYNCTEX_VERT(child)); + goto sibling_loop; + } else { + _synctex_error("Can't create boundary record (2)."); + SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); + } } else if(*SYNCTEX_CUR == '}') { goto scan_teehs; } else if(*SYNCTEX_CUR == '!') { @@ -2402,20 +2377,20 @@ horizontal_loop: _synctex_error("Missing anchor (2)."); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } - goto horizontal_loop; + goto sibling_loop; } else { ++SYNCTEX_CUR; /* _synctex_error("Ignored record %c(2)\n",*SYNCTEX_CUR); */ if(_synctex_next_line(scanner)<SYNCTEX_STATUS_OK) { SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); } - goto horizontal_loop; + goto sibling_loop; } } else { available = 1; status = _synctex_buffer_get_available_size(scanner,&available); if(status<SYNCTEX_STATUS_OK && available>0){ - goto horizontal_loop; + goto sibling_loop; } else { _synctex_error("Uncomplete sheet(2)"); SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); @@ -2432,7 +2407,7 @@ synctex_status_t _synctex_scan_content(synctex_scanner_t scanner) { if(NULL == scanner) { return SYNCTEX_STATUS_BAD_ARGUMENT; } - /* set up the lists of friends */ + /* 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)); @@ -2441,7 +2416,7 @@ synctex_status_t _synctex_scan_content(synctex_scanner_t scanner) { return SYNCTEX_STATUS_ERROR; } } - /* Find where this section starts */ + /* Find where this section starts */ content_not_found: status = _synctex_match_string(scanner,"Content:"); if(status<SYNCTEX_STATUS_EOF) { @@ -2472,7 +2447,7 @@ next_sheet: return SYNCTEX_STATUS_OK; } ++SYNCTEX_CUR; - /* Create a new sheet node */ + /* Create a new sheet node */ sheet = _synctex_new_sheet(scanner); status = _synctex_decode_int(scanner,&(SYNCTEX_PAGE(sheet))); if(status<SYNCTEX_STATUS_OK) { @@ -2494,7 +2469,7 @@ bail: SYNCTEX_SET_SIBLING(sheet,scanner->sheet); scanner->sheet = sheet; sheet = NULL; - /* Now read the list of Inputs between 2 sheets. */ + /* Now read the list of Inputs between 2 sheets. */ do { status = _synctex_scan_input(scanner); if(status<SYNCTEX_STATUS_EOF) { @@ -2506,119 +2481,251 @@ bail: goto next_sheet; } -/* These are the possible extensions of the synctex file */ -static const char * synctex_suffix = ".synctex"; -static const char * synctex_suffix_gz = ".gz"; - -/* strip the last extension of the given string */ -void synctex_strip_last_path_extension(char * string) { - if(NULL != string){ - char * last_component = NULL; - char * last_extension = NULL; - char * next = NULL; - /* first we find the last path component */ - if(NULL == (last_component = strstr(string,"/"))){ - last_component = string; - } else { - ++last_component; - while(NULL != (next = strstr(last_component,"/"))){ - last_component = next+1; - } - } - /* then we find the last path extension */ - if(NULL != (last_extension = strstr(last_component,"."))){ - ++last_extension; - while(NULL != (next = strstr(last_extension,"."))){ - last_extension = next+1; - } - --last_extension;/* back to the "."*/ - if(last_extension>last_component){/* filter out paths like ....my/dir/.hidden"*/ - last_extension[0] = '\0'; - } - } - } -} - -synctex_scanner_t synctex_scanner_new_with_contents_of_file(const char * name); - -/* Where the synctex scanner is created. - * output is the full or relative path of the uncompressed or compressed synctex file. - * On error, NULL is returned. - * This can be due to allocation error, or an internal inconsistency (bad SYNCTEX_BUFFER_SIZE). */ -synctex_scanner_t synctex_scanner_new_with_output_file(const char * output) { - synctex_scanner_t scanner = NULL; +/* Where the synctex scanner is created. */ +synctex_scanner_t synctex_scanner_new_with_output_file(const char * output, const char * build_directory, int parse) { + gzFile file = NULL; char * synctex = NULL; - size_t size = 0; + synctex_scanner_t scanner = NULL; + synctex_io_mode_t io_mode = synctex_io_mode_read; /* Here we assume that int are smaller than void * */ if(sizeof(int)>sizeof(void*)) { - fputs("SyncTeX INTERNAL INCONSISTENCY: int's are unexpectedly bigger than pointers, bailing out.",stderr); + _synctex_error("INTERNAL INCONSISTENCY: int's are unexpectedly bigger than pointers, bailing out."); return NULL; } - /* now create the synctex file name */ - size = strlen(output)+strlen(synctex_suffix)+strlen(synctex_suffix_gz)+1; - synctex = (char *)malloc(size); - if(NULL == synctex) { - fprintf(stderr,"! synctex_scanner_new_with_output_file: Memory problem (1)\n"); + /* We ensure that SYNCTEX_BUFFER_SIZE < UINT_MAX, I don't know if it makes sense... */ + if(SYNCTEX_BUFFER_SIZE >= UINT_MAX) { + _synctex_error("SyncTeX BUG: Internal inconsistency, bad SYNCTEX_BUFFER_SIZE (1)"); return NULL; } - /* we have reserved for synctex enough memory to copy output and both suffices, - * including the terminating character */ - if(synctex != strcpy(synctex,output)) { - fprintf(stderr,"! synctex_scanner_new_with_output_file: Copy problem\n"); -return_on_error: - free(synctex); + /* for integers: */ + if(SYNCTEX_BUFFER_SIZE < SYNCTEX_BUFFER_MIN_SIZE) { + _synctex_error("SyncTeX BUG: Internal inconsistency, bad SYNCTEX_BUFFER_SIZE (2)"); return NULL; } - /* remove the last path extension if any */ - synctex_strip_last_path_extension(synctex); - if(synctex != strcat(synctex,synctex_suffix)){ - fprintf(stderr,"! synctex_scanner_new_with_output_file: Concatenation problem (can't add suffix '%s')\n",synctex_suffix); - goto return_on_error; + /* now open the synctex file */ + if(_synctex_open(output,build_directory,&synctex,&file,synctex_NO,&io_mode) || !file) { + if(_synctex_open(output,build_directory,&synctex,&file,synctex_YES,&io_mode) || !file) { + return NULL; + } } - scanner = synctex_scanner_new_with_contents_of_file(synctex); + scanner = (synctex_scanner_t)_synctex_malloc(sizeof(_synctex_scanner_t)); if(NULL == scanner) { - if(synctex != strcat(synctex,synctex_suffix_gz)){ - fprintf(stderr,"! synctex_scanner_new_with_output_file: Concatenation problem (can't add suffix '%s')\n",synctex_suffix_gz); - goto return_on_error; - } - scanner = synctex_scanner_new_with_contents_of_file(synctex); - if(NULL == scanner) { - goto return_on_error; - } + _synctex_error("SyncTeX: malloc problem"); + free(synctex); + gzclose(file); + return NULL; } - /* make a private copy of output for the scanner */ + /* make a private copy of output for the scanner */ if(NULL == (scanner->output = (char *)malloc(strlen(output)+1))){ - fputs("! synctex_scanner_new_with_output_file: Memory problem (2), scanner's output is not reliable.",stderr); + _synctex_error("! synctex_scanner_new_with_output_file: Memory problem (2), scanner's output is not reliable."); } else if(scanner->output != strcpy(scanner->output,output)) { - fputs("! synctex_scanner_new_with_output_file: Copy problem, scanner's output is not reliable.\n",stderr); + _synctex_error("! synctex_scanner_new_with_output_file: Copy problem, scanner's output is not reliable."); } - scanner->synctex = synctex;/* Now the scanner owns synctex */ - return scanner; + scanner->synctex = synctex;/* Now the scanner owns synctex */ + SYNCTEX_FILE = file; + return parse? synctex_scanner_parse(scanner):scanner; } -/* Where the synctex scanner is created. - * name is the full path of the uncompressed or compressed synctex file. - * It is not the designated initializer because the scanner's core_path field is not initialized here. - * On error, NULL is returned. - * This can be due to allocation error, or an internal inconsistency (bad SYNCTEX_BUFFER_SIZE). */ -synctex_scanner_t synctex_scanner_new_with_contents_of_file(const char * name) { - synctex_scanner_t scanner = NULL; - synctex_status_t status = 0; - /* We ensure that SYNCTEX_BUFFER_SIZE < UINT_MAX, I don't know if it makes sense... */ - if(SYNCTEX_BUFFER_SIZE >= UINT_MAX) { - fprintf(stderr,"SyncTeX BUG: Internal inconsistency, bad SYNCTEX_BUFFER_SIZE (1)"); - return NULL; +int __synctex_open(const char * output, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_modeRef); + +/* This functions opens the file at the "output" given location. + * It manages the problem of quoted filenames that appear with pdftex an filenames containing the space character. + * In TeXLive 2008, the synctex file created with pdftex did contain unexpected quotes. + * This function will remove them if possible. + * 0 on success, non 0 on error. */ +int __synctex_open(const char * output, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_modeRef) { +# define synctex_name (*synctex_name_ref) +# define the_file (*file_ref) +# define io_mode (*io_modeRef) + if(synctex_name_ref && file_ref) { + char * quoteless = NULL; + const char * mode = synctex_io_modes[io_mode]; + size_t size = 0; + /* now create the synctex file name */ + size = strlen(output)+strlen(synctex_suffix)+strlen(synctex_suffix_gz)+1; + synctex_name = (char *)malloc(size); + if(NULL == synctex_name) { + _synctex_error("! __synctex_open: Memory problem (1)\n"); + return 1; + } + /* we have reserved for synctex enough memory to copy output, both suffices and 2 quotes, + * including the terminating character. size is free now. */ + if(synctex_name != strcpy(synctex_name,output)) { + _synctex_error("! __synctex_open: Copy problem\n"); +return_on_error: + free(synctex_name); + synctex_name = NULL;/* Don't forget to reinitialize. */ + the_file = NULL; /* Here as well */ + free(quoteless); + return 2; + } + /* remove the last path extension if any */ + _synctex_strip_last_path_extension(synctex_name); + if(!strlen(synctex_name)) { + goto return_on_error; + } + /* now insert quotes. */ + if(add_quotes) { + char * quoted = NULL; + if(_synctex_copy_with_quoting_last_path_component(synctex_name,"ed,size) || (NULL == quoted)) { + /* There was an error or quoting does not make sense: */ + goto return_on_error; + } + quoteless = synctex_name; + synctex_name = quoted; + } + /* Now add the first path extension. */ + if(synctex_name != strcat(synctex_name,synctex_suffix)){ + _synctex_error("! __synctex_open: Concatenation problem (can't add suffix '%s')\n",synctex_suffix); + goto return_on_error; + } + /* To quoteless as well. */ + if(quoteless && (quoteless != strcat(quoteless,synctex_suffix))){ + free(quoteless); + quoteless = NULL; + } + if(NULL == (the_file = gzopen(synctex_name,mode))) { + /* Could not open this file */ + if(errno != ENOENT) { + /* The file does exist, this is a lower lever error, I can't do anything. */ + _synctex_error("SyncTeX: could not open %s, error %i\n",synctex_name,errno); + goto return_on_error; + } + /* Try the compressed version */ + if(synctex_name != strcat(synctex_name,synctex_suffix_gz)){ + _synctex_error("! __synctex_open: Concatenation problem (can't add suffix '%s')\n",synctex_suffix_gz); + goto return_on_error; + } + ++io_mode; + mode = synctex_io_modes[io_mode]; /* the file is a compressed and is a binary file, this caused errors on Windows */ + /* To quoteless as well. */ + if(quoteless && (quoteless != strcat(quoteless,synctex_suffix_gz))){ + free(quoteless); + quoteless = NULL; + } + if(NULL == (the_file = gzopen(synctex_name,mode))) { + /* Could not open this file */ + if(errno != ENOENT) { + /* The file does exist, this is a lower lever error, I can't do anything. */ + _synctex_error("SyncTeX: could not open %s, error %i\n",synctex_name,errno); + } + goto return_on_error; + } + } + /* At this point, the file is properly open. + * If we are in the add_quotes mode, we change the file name by removing the quotes. */ + if(quoteless) { + gzclose(the_file); + if(rename(synctex_name,quoteless)) { + _synctex_error("SyncTeX: could not rename %s to %s, error %i\n",synctex_name,quoteless,errno); + /* Reopen the file. */ + if(NULL == (the_file = gzopen(synctex_name,mode))) { + /* Could not open this file */ + if(errno != ENOENT) { + /* The file does exist, this is a lower lever error, I can't do anything. */ + _synctex_error("SyncTeX: could not open again %s, error %i\n",synctex_name,errno); + } + goto return_on_error; + } + } else { + if(NULL == (the_file = gzopen(quoteless,mode))) { + /* Could not open this file */ + if(errno != ENOENT) { + /* The file does exist, this is a lower lever error, I can't do anything. */ + _synctex_error("SyncTeX: could not open renamed %s, error %i\n",quoteless,errno); + } + goto return_on_error; + } + /* The quote free file name should replace the old one:*/ + free(synctex_name); + synctex_name = quoteless; + quoteless = NULL; + } + } + return 0; } - /* for integers: */ - if(SYNCTEX_BUFFER_SIZE < SYNCTEX_BUFFER_MIN_SIZE) { - fprintf(stderr,"SyncTeX BUG: Internal inconsistency, bad SYNCTEX_BUFFER_SIZE (2)"); - return NULL; + return 3; /* Bad parameter. */ +# undef synctex_name +# undef the_file +# undef io_mode +} + +int _synctex_open(const char * output, const char * build_directory, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_modeRef); + +/* Opens the ouput file, taking into account the eventual build_directory. + * 0 on success, non 0 on error. */ +int _synctex_open(const char * output, const char * build_directory, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_modeRef) { +# define synctex_name (*synctex_name_ref) +# define the_file (*file_ref) + int result = __synctex_open(output,synctex_name_ref,file_ref,add_quotes,io_modeRef); + if((result || !*file_ref) && build_directory && strlen(build_directory)) { + char * build_output, *lpc; + size_t size; + synctex_bool_t is_absolute; + build_output = NULL; + lpc = _synctex_last_path_component(output); + size = strlen(build_directory)+strlen(lpc)+2; + is_absolute = _synctex_path_is_absolute(build_directory); + if(!is_absolute) { + size += strlen(output); + } + if((build_output = (char *)malloc(size))) { + if(is_absolute) { + build_output[0] = '\0'; + } else { + if(build_output != strcpy(build_output,output)) { + return -4; + } + *(lpc+(build_output-output))='\0'; + } + if(build_output == strcat(build_output,build_directory)) { + /* Append a path separator if necessary. */ + if(!SYNCTEX_IS_PATH_SEPARATOR(build_output[strlen(build_directory)-1])) { + if(build_output != strcat(build_output,"/")) { + return -2; + } + } + /* Append the last path component of the output. */ + if(build_output != strcat(build_output,lpc)) { + return -3; + } + return __synctex_open(build_output,synctex_name_ref,file_ref,add_quotes,io_modeRef); + } + } + return -1; } - scanner = (synctex_scanner_t)_synctex_malloc(sizeof(_synctex_scanner_t)); + return result; +# undef synctex_name +# undef the_file +} + +/* The scanner destructor + */ +void synctex_scanner_free(synctex_scanner_t scanner) { if(NULL == scanner) { - fprintf(stderr,"SyncTeX: malloc problem"); - return NULL; + return; } + if(SYNCTEX_FILE) { + gzclose(SYNCTEX_FILE); + SYNCTEX_FILE = NULL; + } + SYNCTEX_FREE(scanner->sheet); + SYNCTEX_FREE(scanner->input); + free(SYNCTEX_START); + free(scanner->output_fmt); + free(scanner->output); + free(scanner->synctex); + free(scanner->lists_of_friends); + free(scanner); +} + +/* Where the synctex scanner parses the contents of the file. */ +synctex_scanner_t synctex_scanner_parse(synctex_scanner_t scanner) { + synctex_status_t status = 0; + if(!scanner || scanner->flags.has_parsed) { + return scanner; + } + scanner->flags.has_parsed=1; scanner->pre_magnification = 1000; scanner->pre_unit = 8192; scanner->pre_x_offset = scanner->pre_y_offset = 578; @@ -2626,6 +2733,8 @@ synctex_scanner_t synctex_scanner_new_with_contents_of_file(const char * name) { * If there is a post scriptum section, this value will be overriden by the real life value */ scanner->x_offset = scanner->y_offset = 6.027e23f; scanner->class[synctex_node_type_sheet] = synctex_class_sheet; + scanner->class[synctex_node_type_input] = synctex_class_input; + (scanner->class[synctex_node_type_input]).scanner = scanner; (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; @@ -2633,8 +2742,6 @@ synctex_scanner_t synctex_scanner_new_with_contents_of_file(const char * name) { (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_hbox_non_void] = synctex_class_hbox; - (scanner->class[synctex_node_type_hbox_non_void]).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; @@ -2643,48 +2750,39 @@ synctex_scanner_t synctex_scanner_new_with_contents_of_file(const char * name) { (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; - SYNCTEX_FILE = gzopen(name,"r"); - if(NULL == SYNCTEX_FILE) { - if(errno != ENOENT) { - fprintf(stderr,"SyncTeX: could not open %s, error %i\n",name,errno); - } -bail: + scanner->class[synctex_node_type_boundary] = synctex_class_boundary; + (scanner->class[synctex_node_type_boundary]).scanner = scanner; + SYNCTEX_START = (unsigned char *)malloc(SYNCTEX_BUFFER_SIZE+1); /* one more character for null termination */ + if(NULL == SYNCTEX_START) { + _synctex_error("SyncTeX: malloc error"); synctex_scanner_free(scanner); return NULL; } - SYNCTEX_START = (unsigned char *)malloc(SYNCTEX_BUFFER_SIZE+1); /* one more character for null termination */ - if(NULL == SYNCTEX_START) { - fprintf(stderr,"SyncTeX: malloc error"); - gzclose(SYNCTEX_FILE); - goto bail; - } SYNCTEX_END = SYNCTEX_START+SYNCTEX_BUFFER_SIZE; - /* SYNCTEX_END always points to a null terminating character. - * Maybe there is another null terminating character between SYNCTEX_CUR and SYNCTEX_END-1. - * At least, we are sure that SYNCTEX_CUR points to a string covering a valid part of the memory. */ - * SYNCTEX_END = '\0'; + /* SYNCTEX_END always points to a null terminating character. + * Maybe there is another null terminating character between SYNCTEX_CUR and SYNCTEX_END-1. + * At least, we are sure that SYNCTEX_CUR points to a string covering a valid part of the memory. */ + *SYNCTEX_END = '\0'; SYNCTEX_CUR = SYNCTEX_END; status = _synctex_scan_preamble(scanner); if(status<SYNCTEX_STATUS_OK) { - fprintf(stderr,"SyncTeX Error: Bad preamble\n"); + _synctex_error("SyncTeX Error: Bad preamble\n"); bailey: - gzclose(SYNCTEX_FILE); - goto bail; + synctex_scanner_free(scanner); + return NULL; } status = _synctex_scan_content(scanner); if(status<SYNCTEX_STATUS_OK) { - fprintf(stderr,"SyncTeX Error: Bad content\n"); + _synctex_error("SyncTeX Error: Bad content\n"); goto bailey; } - /* Everything is finished, free the buffer, close he file */ + /* Everything is finished, free the buffer, close the file */ free((void *)SYNCTEX_START); SYNCTEX_START = SYNCTEX_CUR = SYNCTEX_END = NULL; gzclose(SYNCTEX_FILE); SYNCTEX_FILE = NULL; - /* Final tuning: set the default values for various parameters */ - /* 1 pre_unit = (scanner->pre_unit)/65536 pt = (scanner->pre_unit)/65781.76 bp + /* Final tuning: set the default values for various parameters */ + /* 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; @@ -2693,19 +2791,19 @@ bailey: scanner->pre_magnification = 1000; } if(scanner->unit <= 0) { - /* no post magnification */ - scanner->unit = scanner->pre_unit / 65781.76;/* 65781.76 or 65536.0*/ + /* no post magnification */ + scanner->unit = scanner->pre_unit / 65781.76;/* 65781.76 or 65536.0*/ } else { - /* post magnification */ + /* post magnification */ scanner->unit *= scanner->pre_unit / 65781.76; } scanner->unit *= scanner->pre_magnification / 1000.0; if(scanner->x_offset > 6e23) { - /* no post offset */ + /* 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 */ + /* post offset */ scanner->x_offset /= 65781.76f; scanner->y_offset /= 65781.76f; } @@ -2713,22 +2811,6 @@ bailey: #undef SYNCTEX_FILE } -/* The scanner destructor - */ -void synctex_scanner_free(synctex_scanner_t scanner) { - if(NULL == scanner) { - return; - } - SYNCTEX_FREE(scanner->sheet); - SYNCTEX_FREE(scanner->input); - free(SYNCTEX_START); - free(scanner->output_fmt); - free(scanner->output); - free(scanner->synctex); - free(scanner->lists_of_friends); - free(scanner); -} - /* Scanner accessors. */ int synctex_scanner_pre_x_offset(synctex_scanner_t scanner){ @@ -2794,20 +2876,69 @@ const char * synctex_scanner_get_name(synctex_scanner_t scanner,int tag) { } while((input = SYNCTEX_SIBLING(input)) != NULL); return NULL; } -int synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name) { + +int _synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name); +int _synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name) { synctex_node_t input = NULL; if(NULL == scanner) { return 0; } input = scanner->input; do { - if((strlen(name) == strlen((SYNCTEX_NAME(input)))) && - (0 == strncmp(name,(SYNCTEX_NAME(input)),strlen(name)))) { + if(_synctex_is_equivalent_file_name(name,(SYNCTEX_NAME(input)))) { return SYNCTEX_TAG(input); } } while((input = SYNCTEX_SIBLING(input)) != NULL); return 0; } + +int synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name) { + size_t char_index = strlen(name); + if((scanner = synctex_scanner_parse(scanner)) && (0 < char_index)) { + /* the name is not void */ + char_index -= 1; + if(!SYNCTEX_IS_PATH_SEPARATOR(name[char_index])) { + /* the last character of name is not a path separator */ + int result = _synctex_scanner_get_tag(scanner,name); + if(result) { + return result; + } else { + /* the given name was not the one known by TeX + * try a name relative to the enclosing directory of the scanner->output file */ + const char * relative = name; + const char * ptr = scanner->output; + while((strlen(relative) > 0) && (strlen(ptr) > 0) && (*relative == *ptr)) + { + relative += 1; + ptr += 1; + } + /* Find the last path separator before relative */ + while(relative > name) { + if(SYNCTEX_IS_PATH_SEPARATOR(*(relative-1))) { + break; + } + relative -= 1; + } + if((relative > name) && (result = _synctex_scanner_get_tag(scanner,relative))) { + return result; + } + if(SYNCTEX_IS_PATH_SEPARATOR(name[0])) { + /* No tag found for the given absolute name, + * Try each relative path starting from the shortest one */ + while(0<char_index) { + char_index -= 1; + if(SYNCTEX_IS_PATH_SEPARATOR(name[char_index]) + && (result = _synctex_scanner_get_tag(scanner,name+char_index+1))) { + return result; + } + } + } + } + return result; + } + } + return 0; +} synctex_node_t synctex_scanner_input(synctex_scanner_t scanner) { return scanner?scanner->input:NULL; } @@ -2824,88 +2955,88 @@ const char * synctex_scanner_get_synctex(synctex_scanner_t scanner) { # pragma mark - # pragma mark Public node attributes # endif -float synctex_node_h(synctex_node_t node){ +int synctex_node_h(synctex_node_t node){ if(!node) { return 0; } - return (float)SYNCTEX_HORIZ(node); + return SYNCTEX_HORIZ(node); } -float synctex_node_v(synctex_node_t node){ +int synctex_node_v(synctex_node_t node){ if(!node) { return 0; } - return (float)SYNCTEX_VERT(node); + return SYNCTEX_VERT(node); } -float synctex_node_width(synctex_node_t node){ +int synctex_node_width(synctex_node_t node){ if(!node) { return 0; } - return (float)SYNCTEX_WIDTH(node); + return SYNCTEX_WIDTH(node); } -float synctex_node_box_h(synctex_node_t node){ +int 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_hbox_non_void) - && (node->class->type != synctex_node_type_void_hbox)) { - node = SYNCTEX_PARENT(node); + if(SYNCTEX_IS_BOX(node)) { +result: + return SYNCTEX_HORIZ(node); + } + if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { + goto result; } - return (node->class->type == synctex_node_type_sheet)?0:(float)(SYNCTEX_HORIZ(node)); + return 0; } -float synctex_node_box_v(synctex_node_t node){ +int 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_hbox_non_void) - && (node->class->type != synctex_node_type_void_hbox)) { - node = SYNCTEX_PARENT(node); + if(SYNCTEX_IS_BOX(node)) { +result: + return SYNCTEX_VERT(node); + } + if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { + goto result; } - return (node->class->type == synctex_node_type_sheet)?0:(float)(SYNCTEX_VERT(node)); + return 0; } -float synctex_node_box_width(synctex_node_t node){ +int 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_hbox_non_void) - && (node->class->type != synctex_node_type_void_hbox)) { - node = SYNCTEX_PARENT(node); + if(SYNCTEX_IS_BOX(node)) { +result: + return SYNCTEX_WIDTH(node); + } + if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { + goto result; } - return (node->class->type == synctex_node_type_sheet)?0:(float)(SYNCTEX_WIDTH(node)); + return 0; } -float synctex_node_box_height(synctex_node_t node){ +int 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_hbox_non_void) - && (node->class->type != synctex_node_type_void_hbox)) { - node = SYNCTEX_PARENT(node); + if(SYNCTEX_IS_BOX(node)) { +result: + return SYNCTEX_HEIGHT(node); } - return (node->class->type == synctex_node_type_sheet)?0:(float)(SYNCTEX_HEIGHT(node)); + if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { + goto result; + } + return 0; } -float synctex_node_box_depth(synctex_node_t node){ +int 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_hbox_non_void) - && (node->class->type != synctex_node_type_void_hbox)) { - node = SYNCTEX_PARENT(node); + if(SYNCTEX_IS_BOX(node)) { +result: + return SYNCTEX_DEPTH(node); } - return (node->class->type == synctex_node_type_sheet)?0:(float)(SYNCTEX_DEPTH(node)); + if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { + goto result; + } + return 0; } # ifdef SYNCTEX_NOTHING # pragma mark - @@ -2933,119 +3064,91 @@ 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)) { + switch(node->class->type) { + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + case synctex_node_type_void_hbox: + return SYNCTEX_HORIZ(node)*node->class->scanner->unit+node->class->scanner->x_offset; + case synctex_node_type_hbox: result: - return SYNCTEX_WIDTH(node)<0? - (SYNCTEX_HORIZ(node)+SYNCTEX_WIDTH(node))*node->class->scanner->unit+node->class->scanner->x_offset: - SYNCTEX_HORIZ(node)*node->class->scanner->unit+node->class->scanner->x_offset; - } - if(node->class->type != synctex_node_type_hbox - && node->class->type != synctex_node_type_hbox_non_void) { - node = SYNCTEX_PARENT(node); + return SYNCTEX_HORIZ_V(node)*node->class->scanner->unit+node->class->scanner->x_offset; } - if(node->class->type == synctex_node_type_sheet) { - return 0; - } - if(node->class->type == synctex_node_type_vbox) { + if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { goto result; } - return SYNCTEX_INFO(node)[SYNCTEX_WIDTH_V_IDX].INT<0? - (SYNCTEX_INFO(node)[SYNCTEX_HORIZ_V_IDX].INT+SYNCTEX_INFO(node)[SYNCTEX_WIDTH_V_IDX].INT)*node->class->scanner->unit+node->class->scanner->x_offset: - SYNCTEX_INFO(node)[SYNCTEX_HORIZ_V_IDX].INT*node->class->scanner->unit+node->class->scanner->x_offset; + return 0; } 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)) { + switch(node->class->type) { + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + case synctex_node_type_void_hbox: + return SYNCTEX_VERT(node)*node->class->scanner->unit+node->class->scanner->x_offset; + case synctex_node_type_hbox: result: - return (float)(SYNCTEX_VERT(node))*node->class->scanner->unit+node->class->scanner->y_offset; - } - if(node->class->type != synctex_node_type_hbox - && node->class->type != synctex_node_type_hbox_non_void) { - node = SYNCTEX_PARENT(node); + return SYNCTEX_VERT_V(node)*node->class->scanner->unit+node->class->scanner->x_offset; } - if(node->class->type == synctex_node_type_sheet) { - return 0; - } - if(node->class->type == synctex_node_type_vbox) { + if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { goto result; } - return SYNCTEX_INFO(node)[SYNCTEX_VERT_V_IDX].INT*node->class->scanner->unit+node->class->scanner->y_offset; + return 0; } 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)) { + switch(node->class->type) { + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + case synctex_node_type_void_hbox: + return SYNCTEX_WIDTH(node)*node->class->scanner->unit; + case synctex_node_type_hbox: result: - return SYNCTEX_WIDTH(node)<0? - -SYNCTEX_WIDTH(node)*node->class->scanner->unit: - SYNCTEX_WIDTH(node)*node->class->scanner->unit; + return SYNCTEX_WIDTH_V(node)*node->class->scanner->unit; } - if(node->class->type != synctex_node_type_hbox - && node->class->type != synctex_node_type_hbox_non_void) { - node = SYNCTEX_PARENT(node); - } - if(node->class->type == synctex_node_type_sheet) { - return 0; - } - if(node->class->type == synctex_node_type_vbox) { + if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { goto result; } - return SYNCTEX_INFO(node)[SYNCTEX_WIDTH_V_IDX].INT<0? - -SYNCTEX_INFO(node)[SYNCTEX_WIDTH_V_IDX].INT*node->class->scanner->unit: - SYNCTEX_INFO(node)[SYNCTEX_WIDTH_V_IDX].INT*node->class->scanner->unit; + return 0; } 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)) { + switch(node->class->type) { + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + case synctex_node_type_void_hbox: + return SYNCTEX_HEIGHT(node)*node->class->scanner->unit; + case synctex_node_type_hbox: result: - return (float)(SYNCTEX_HEIGHT(node))*node->class->scanner->unit; + return SYNCTEX_HEIGHT_V(node)*node->class->scanner->unit; } - if(node->class->type != synctex_node_type_hbox - && node->class->type != synctex_node_type_hbox_non_void) { - node = SYNCTEX_PARENT(node); - } - if(node->class->type == synctex_node_type_sheet) { - return 0; - } - if(node->class->type == synctex_node_type_vbox) { + if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { goto result; } - return SYNCTEX_INFO(node)[SYNCTEX_HEIGHT_V_IDX].INT*node->class->scanner->unit; + return 0; } 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)) { + switch(node->class->type) { + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + case synctex_node_type_void_hbox: + return SYNCTEX_DEPTH(node)*node->class->scanner->unit; + case synctex_node_type_hbox: result: - return (float)(SYNCTEX_DEPTH(node))*node->class->scanner->unit; + return SYNCTEX_DEPTH_V(node)*node->class->scanner->unit; } - if(node->class->type != synctex_node_type_hbox - && node->class->type != synctex_node_type_hbox_non_void) { - node = SYNCTEX_PARENT(node); - } - if(node->class->type == synctex_node_type_sheet) { - return 0; - } - if(node->class->type == synctex_node_type_vbox) { + if((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { goto result; } - return SYNCTEX_INFO(node)[SYNCTEX_DEPTH_V_IDX].INT*node->class->scanner->unit; + return 0; } # ifdef SYNCTEX_NOTHING # pragma mark - @@ -3081,7 +3184,7 @@ int synctex_node_column(synctex_node_t node) { } # ifdef SYNCTEX_NOTHING # pragma mark - -# pragma mark Query +# pragma mark Sheet # endif synctex_node_t synctex_sheet_content(synctex_scanner_t scanner,int page) { @@ -3102,10 +3205,6 @@ synctex_node_t synctex_sheet_content(synctex_scanner_t scanner,int page) { # pragma mark Query # endif -int synctex_display_query(synctex_scanner_t scanner,const char * name,int line,int column); -int synctex_edit_query(synctex_scanner_t scanner,int page,float h,float v); -synctex_node_t synctex_next_result(synctex_scanner_t scanner); - int synctex_display_query(synctex_scanner_t scanner,const char * name,int line,int column) { # ifdef __DARWIN_UNIX03 # pragma unused(column) @@ -3113,6 +3212,7 @@ int synctex_display_query(synctex_scanner_t scanner,const char * name,int line,i int tag = synctex_scanner_get_tag(scanner,name); size_t size = 0; int friend_index = 0; + int max_line = 0; synctex_node_t node = NULL; if(tag == 0) { printf("SyncTeX Warning: No tag for %s\n",name); @@ -3120,430 +3220,838 @@ int synctex_display_query(synctex_scanner_t scanner,const char * name,int line,i } free(SYNCTEX_START); SYNCTEX_CUR = SYNCTEX_END = SYNCTEX_START = NULL; - friend_index = (tag+line)%(scanner->number_of_lists); - node = (scanner->lists_of_friends)[friend_index]; - while(node) { - if((tag == SYNCTEX_TAG(node)) && (line == SYNCTEX_LINE(node))) { - if(SYNCTEX_CUR == SYNCTEX_END) { - size += 16; - SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *)); - SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START; - SYNCTEX_START = SYNCTEX_END; - SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *); - } - *(synctex_node_t *)SYNCTEX_CUR = node; - SYNCTEX_CUR += sizeof(synctex_node_t); - } - node = SYNCTEX_FRIEND(node); - } - SYNCTEX_END = SYNCTEX_CUR; - SYNCTEX_CUR = NULL; - return SYNCTEX_END-SYNCTEX_START; -} - -inline static synctex_node_t _synctex_best_child_node(synctex_node_t node,int H,int V, int * distanceRef); -inline static synctex_node_t _synctex_best_child_node(synctex_node_t node,int H,int V, int * distanceRef) { - if(NULL != distanceRef) { - synctex_node_t child = NULL; - switch((node->class)->type) { - case synctex_node_type_hbox_non_void: - if((child = SYNCTEX_CHILD(node))) { - synctex_node_t result = NULL; - do { - synctex_node_t candidate = NULL; - if((candidate = _synctex_best_child_node(child,H,V,distanceRef))) { - if(0 == *distanceRef) { - /* We can't do better */ - return candidate; - } - result = candidate; - } - } while((child = SYNCTEX_SIBLING(child))); - return result; - } else { - /* this is an error if this box does not contain children. */ - fprintf(stderr, - "SyncTeX internal inconsistency: we should not get there (synctex_best_child_node:%i), please report bug to the SyncTeX maintainer\n", - (node->class)->type); - return NULL; + max_line = line < INT_MAX-scanner->number_of_lists ? line+scanner->number_of_lists:INT_MAX; + while(line<max_line) { + /* This loop will only be performed once for advanced viewers */ + friend_index = (tag+line)%(scanner->number_of_lists); + if((node = (scanner->lists_of_friends)[friend_index])) { + do { + if((synctex_node_type(node)>=synctex_node_type_boundary) + && (tag == SYNCTEX_TAG(node)) + && (line == SYNCTEX_LINE(node))) { + if(SYNCTEX_CUR == SYNCTEX_END) { + size += 16; + SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *)); + SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START; + SYNCTEX_START = SYNCTEX_END; + SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *); + } + *(synctex_node_t *)SYNCTEX_CUR = node; + SYNCTEX_CUR += sizeof(synctex_node_t); } - case synctex_node_type_hbox: - case synctex_node_type_vbox: - /* This is a box that contains children but no kern, math or glue nodes. */ - if((child = SYNCTEX_CHILD(node))) { - synctex_node_t result = NULL; + } while((node = SYNCTEX_FRIEND(node))); + if(SYNCTEX_START == NULL) { + /* We did not find any matching boundary, retry with glue or kern */ + node = (scanner->lists_of_friends)[friend_index];/* no need to test it again, already done */ + do { + if((synctex_node_type(node)>=synctex_node_type_kern) + && (tag == SYNCTEX_TAG(node)) + && (line == SYNCTEX_LINE(node))) { + if(SYNCTEX_CUR == SYNCTEX_END) { + size += 16; + SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *)); + SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START; + SYNCTEX_START = SYNCTEX_END; + SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *); + } + *(synctex_node_t *)SYNCTEX_CUR = node; + SYNCTEX_CUR += sizeof(synctex_node_t); + } + } while((node = SYNCTEX_FRIEND(node))); + if(SYNCTEX_START == NULL) { + /* We did not find any matching glue or kern, retry with boxes */ + node = (scanner->lists_of_friends)[friend_index];/* no need to test it again, already done */ do { - synctex_node_t candidate = NULL; - if((candidate = _synctex_best_child_node(child,H,V,distanceRef))) { - if(0 == *distanceRef) { - /* We can't do better */ - return candidate; - } - result = candidate; - } - } while((child = SYNCTEX_SIBLING(child))); - return result; - } else { - /* If the hit point is inside the box, we must return a node inside the box */ - int min = SYNCTEX_HORIZ_V(node); - int max = min+SYNCTEX_WIDTH_V(node); - if(min<=H && H<=max) { - min = SYNCTEX_VERT_V(node); - max = min + SYNCTEX_DEPTH_V(node); - min -= SYNCTEX_HEIGHT_V(node); - if(min<=V && V<=max) { - /* The hit point and the result are in the same box, we can't do better */ - *distanceRef = 0;/* no one else will ever try to do better */ - return node; + if((tag == SYNCTEX_TAG(node)) + && (line == SYNCTEX_LINE(node))) { + if(SYNCTEX_CUR == SYNCTEX_END) { + size += 16; + SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *)); + SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START; + SYNCTEX_START = SYNCTEX_END; + SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *); + } + *(synctex_node_t *)SYNCTEX_CUR = node; + SYNCTEX_CUR += sizeof(synctex_node_t); } - } - return NULL; + } while((node = SYNCTEX_FRIEND(node))); } - case synctex_node_type_void_hbox: - case synctex_node_type_void_vbox: - /* Both boxes does not contain any material, they only contribute to SyncTeX by their line number. */ - return NULL; - default: + } + SYNCTEX_END = SYNCTEX_CUR; + /* Now reverse the order to have nodes in display order, and keep just a few nodes */ + if((SYNCTEX_START) && (SYNCTEX_END)) { - int i = SYNCTEX_HORIZ(node); - int distance = i>H?i-H:H-i; - i = SYNCTEX_VERT(node); - distance += i>V?i-V:V-i; - if(distance<*distanceRef) { - *distanceRef = distance; - return node; + synctex_node_t * start_ref = (synctex_node_t *)SYNCTEX_START; + synctex_node_t * end_ref = (synctex_node_t *)SYNCTEX_END; + end_ref -= 1; + while(start_ref < end_ref) { + node = *start_ref; + *start_ref = *end_ref; + *end_ref = node; + start_ref += 1; + end_ref -= 1; + } + /* Basically, we keep the first node for each parent. + * More precisely, we keep only nodes that are not descendants of + * their predecessor's parent. */ + start_ref = (synctex_node_t *)SYNCTEX_START; + end_ref = (synctex_node_t *)SYNCTEX_START; + next_end: + end_ref += 1; /* we allways have start_ref<= end_ref*/ + if(end_ref < (synctex_node_t *)SYNCTEX_END) { + node = *end_ref; + while((node = SYNCTEX_PARENT(node))) { + if(SYNCTEX_PARENT(*start_ref) == node) { + goto next_end; + } + } + start_ref += 1; + *start_ref = *end_ref; + goto next_end; } - return NULL; + start_ref += 1; + SYNCTEX_END = (unsigned char *)start_ref; } - } + SYNCTEX_CUR = NULL; + return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t); + } +# if defined(__SYNCTEX_STRONG_DISPLAY_QUERY__) + break; +# else + ++line; +# endif } - return NULL; + return 0; } -/* The best container is the deeper box that contains the given point. - * We traverse the node tree in a deep first manner and stop as soon as a resutl is found. */ -inline static synctex_node_t _synctex_best_container(synctex_node_t node,int H,int V); -inline static synctex_node_t _synctex_best_container(synctex_node_t node,int H,int V) { - int min, max; - synctex_node_t child = NULL; - synctex_node_t result = NULL; - switch(node->class->type) { - case synctex_node_type_hbox: - case synctex_node_type_vbox: - case synctex_node_type_hbox_non_void: - max = SYNCTEX_WIDTH_V(node); - if(max<0) { - min = max; - max = SYNCTEX_HORIZ_V(node); - min += max; - } else { - min = SYNCTEX_HORIZ_V(node); - max += min; - } - if(min<=H && H<=max) { - child = node; - while((child = SYNCTEX_CHILD(child))) { - if((result = _synctex_best_container(child,H,V))) { - return result; - } - } - min = SYNCTEX_VERT_V(node); - max = min + SYNCTEX_DEPTH_V(node); - min -= SYNCTEX_HEIGHT_V(node); - if(min<=V && V<=max) { - /* The hit point and the result are in the same box, we can't do better */ - return node; - } - } +synctex_node_t synctex_next_result(synctex_scanner_t scanner) { + if(NULL == SYNCTEX_CUR) { + SYNCTEX_CUR = SYNCTEX_START; + } else { + SYNCTEX_CUR+=sizeof(synctex_node_t); + } + if(SYNCTEX_CUR<SYNCTEX_END) { + return *(synctex_node_t*)SYNCTEX_CUR; + } else { + return NULL; } - return NULL; } +/* This struct records a point in TeX coordinates.*/ +typedef struct { + int h; + int v; +} synctex_point_t; + +/* This struct records distances, the left one is positive or 0 and the right one is negative or 0. + * When comparing the locations of 2 different graphical objects on the page, we will have to also record the + * horizontal distance as signed to keep track of the typesetting order.*/ +typedef struct { + int left; + int right; +} synctex_distances_t; + +typedef struct { + synctex_point_t left; + synctex_point_t right; +} synctex_offsets_t; + + +typedef struct { + synctex_node_t left; + synctex_node_t right; +} synctex_node_set_t; + +/* The smallest container between two has the smallest width or height. + * This comparison is used when there are 2 overlapping boxes that contain the hit point. + * For ConTeXt, the problem appears at each page. + * The chosen box is the one with the smallest height, then the smallest width. */ +SYNCTEX_INLINE static synctex_node_t _synctex_smallest_container(synctex_node_t node, synctex_node_t other_node); + +/* Returns the distance between the hit point hitPoint=(H,V) and the given node. */ +synctex_bool_t _synctex_point_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible); +int _synctex_node_distance_to_point(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible); + +/* The best container is the deeper box that contains the hit point (H,V). + * _synctex_eq_deepest_container starts with node whereas + * _synctex_box_child_deepest starts with node's children, if any + * if node is not a box, or a void box, NULL is returned. + * We traverse the node tree in a deep first manner and stop as soon as a result is found. */ +static synctex_node_t _synctex_eq_deepest_container(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible); + +/* Once a best container is found, the closest children are the closest nodes to the left or right of the hit point. + * Only horizontal and vertical offsets are used to compare the positions of the nodes. */ +SYNCTEX_INLINE static int _synctex_eq_get_closest_children_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef, synctex_bool_t visible); + +/* The closest container is the box that is the one closest to the given point. + * The "visible" version takes into account the visible dimensions instead of the real ones given by TeX. */ +SYNCTEX_INLINE static synctex_node_t _synctex_eq_closest_child(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible); + +#define SYNCTEX_MASK_LEFT 1 +#define SYNCTEX_MASK_RIGHT 2 + int synctex_edit_query(synctex_scanner_t scanner,int page,float h,float v) { synctex_node_t sheet = NULL; - synctex_node_t node = NULL; - synctex_node_t best_node = NULL; - synctex_node_t best_container = NULL; - int H,V; - int minH,maxH,minV,maxV; - int best_distance,distance; - if(NULL == scanner || 0 == scanner->unit) { + synctex_node_t node = NULL; /* placeholder */ + synctex_node_t other_node = NULL; /* placeholder */ + synctex_point_t hitPoint = {0,0}; /* placeholder */ + synctex_node_set_t bestNodes = {NULL,NULL}; /* holds the best node */ + synctex_distances_t bestDistances = {INT_MAX,INT_MAX}; + synctex_node_t bestContainer = NULL; /* placeholder */ + if(NULL == (scanner = synctex_scanner_parse(scanner)) || 0 >= scanner->unit) {/* scanner->unit must be >0 */ return 0; } - /* Convert the given point to scanner integer coordinates */ - H = (h-scanner->x_offset)/scanner->unit; - V = (v-scanner->y_offset)/scanner->unit; + /* Convert the given point to scanner integer coordinates */ + hitPoint.h = (h-scanner->x_offset)/scanner->unit; + hitPoint.v = (v-scanner->y_offset)/scanner->unit; /* We will store in the scanner's buffer the result of the query. */ free(SYNCTEX_START); SYNCTEX_START = SYNCTEX_END = SYNCTEX_CUR = NULL; - /* Find the proper sheet */ + /* Find the proper sheet */ sheet = scanner->sheet; - while(sheet != NULL && SYNCTEX_PAGE(sheet) != page) { + while((sheet) && SYNCTEX_PAGE(sheet) != page) { sheet = SYNCTEX_SIBLING(sheet); } if(NULL == sheet) { return -1; } - /* Now sheet points to the sheet node with proper page number */ - /* try to find the box closest to the hit point (H,V) */ - /* We initialize the values with the next box of the sheet. */ - node = SYNCTEX_NEXT_BOX(sheet); - if(NULL == node) { - /* This is a very weird situation where there are no kern, math or glue nodes. - * Ignore this, for the moment. */ - return 0; - } - /* The distance between a point and a box is special. - * It is not the euclidian distance, nor something similar. - * We have to take into account the particular layout, - * and the box hierarchy. - * Given a box, there are 9 regions delimited by the lines of the edges of the box. - * The origin being at the top left corner of the page, - * we also give names to the vertices of the box. - * - * 1 | 2 | 3 - * ---A---B---> - * 4 | 5 | 6 - * ---C---D---> - * 7 | 8 | 9 - * v v - * In each region, there is a different formula. - * In the end we have a continuous distance which may not be a mathematical distance but who cares. */ - /* In order to gain speed, we have made a linked list of all the box nodes that contain either kern, glue or math node. - * These kind of boxes are expected to represent the vast majority of boxes. - * It was created while parsing the sheet content, and the boxes are ordered from deeper to lower. */ - /* min? and max? are the coordinates of the box. */ -next_box: - /* getting the box bounds, taking into account negative widths. */ - maxH = SYNCTEX_WIDTH_V(node); - if(maxH<0) { - minH = maxH; - maxH = SYNCTEX_HORIZ_V(node); - minH += maxH; - } else { - minH = SYNCTEX_HORIZ_V(node); - maxH += minH; - } - minV = SYNCTEX_VERT_V(node); - maxV = minV + SYNCTEX_DEPTH_V(node); - minV -= SYNCTEX_HEIGHT_V(node); - /* In what region is the point P=(H,V) ? */ - if(V<minV) { - if(H<minH) { - /* This is region 1. The distance to the box is the L1 distance PA. */ - best_distance = minV - V + minH - H;/* Integer overflow? probability epsilon */ - } else if(H<=maxH) { - /* This is region 2. The distance to the box is the geometrical distance to the top edge. */ - best_distance = minV - V; - } else { - /* This is region 3. The distance to the box is the L1 distance PB. */ - best_distance = minV - V + H - maxH; - } - } else if(V<=maxV) { - if(H<minH) { - /* This is region 4. The distance to the box is the geometrical distance to the left edge. */ - best_distance = minH - H; - } else if(H<=maxH) { - /* This is region 4. We are inside the box. */ - best_distance = 0; - } else { - /* This is region 6. The distance to the box is the geometrical distance to the right edge. */ - best_distance = H - maxH; - } - } else { - if(H<minH) { - /* This is region 7. The distance to the box is the L1 distance PC. */ - best_distance = V - maxV + minH - H; - } else if(H<=maxH) { - /* This is region 8. The distance to the box is the geometrical distance to the top edge. */ - best_distance = V - maxV; - } else { - /* This is region 9. The distance to the box is the L1 distance PD. */ - best_distance = V - maxV + H - maxH; - } - } - best_node = node; - /* Is best_node a box containing the hit point? */ - if(best_distance==0) { - if((best_container = _synctex_best_container(best_node,H,V)) && (best_container != best_node)) { - /* We have found a box that contains the hit point, as a descendant of best_node. - * best_container is a box that contains no kern, math and glue nodes, - * otherwise, it would be located in the linked list of such boxes, before its ancestor best_node - * and it would have been laready caught. - * In mathematical formulas, there are such boxes because there is not enough material to add glue or kern. */ - if((SYNCTEX_START = malloc(sizeof(synctex_node_t)))) { - * (synctex_node_t *)SYNCTEX_START = best_container; - SYNCTEX_END = SYNCTEX_START + sizeof(synctex_node_t); - SYNCTEX_CUR = NULL; - return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t); - } else { + /* Now sheet points to the sheet node with proper page number */ + /* Here is how we work: + * At first we do not consider the visible box dimensions. This will cover the most frequent cases. + * Then we try with the visible box dimensions. + * We try to find a non void box containing the hit point. + * We browse all the horizontal boxes until we find one containing the hit point. */ + if((node = SYNCTEX_NEXT_HORIZ_BOX(sheet))) { + do { + if(_synctex_point_in_box(hitPoint,node,synctex_YES)) { + /* Maybe the hitPoint belongs to a contained vertical box. */ +end: + /* This trick is for catching overlapping boxes */ + if((other_node = SYNCTEX_NEXT_HORIZ_BOX(node))) { + do { + if(_synctex_point_in_box(hitPoint,other_node,synctex_YES)) { + node = _synctex_smallest_container(other_node,node); + } + } while((other_node = SYNCTEX_NEXT_HORIZ_BOX(other_node))); + } + if((bestContainer = _synctex_eq_deepest_container(hitPoint,node,synctex_YES))) { + node = bestContainer; + } + _synctex_eq_get_closest_children_in_box(hitPoint,node,&bestNodes,&bestDistances,synctex_YES); + if(bestNodes.right && bestNodes.left) { + if((SYNCTEX_TAG(bestNodes.right)!=SYNCTEX_TAG(bestNodes.left)) + || (SYNCTEX_LINE(bestNodes.right)!=SYNCTEX_LINE(bestNodes.left)) + || (SYNCTEX_COLUMN(bestNodes.right)!=SYNCTEX_COLUMN(bestNodes.left))) { + if((SYNCTEX_START = malloc(2*sizeof(synctex_node_t)))) { + if(bestDistances.left>bestDistances.right) { + ((synctex_node_t *)SYNCTEX_START)[0] = bestNodes.right; + ((synctex_node_t *)SYNCTEX_START)[1] = bestNodes.left; + } else { + ((synctex_node_t *)SYNCTEX_START)[0] = bestNodes.left; + ((synctex_node_t *)SYNCTEX_START)[1] = bestNodes.right; + } + SYNCTEX_END = SYNCTEX_START + 2*sizeof(synctex_node_t); + SYNCTEX_CUR = NULL; + return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t); + } + return SYNCTEX_STATUS_ERROR; + } + /* both nodes have the same input coordinates + * We choose the one closest to the hit point */ + if(bestDistances.left>bestDistances.right) { + bestNodes.left = bestNodes.right; + } + bestNodes.right = NULL; + } else if(bestNodes.right) { + bestNodes.left = bestNodes.right; + } else if(!bestNodes.left){ + bestNodes.left = node; + } + if((SYNCTEX_START = malloc(sizeof(synctex_node_t)))) { + * (synctex_node_t *)SYNCTEX_START = bestNodes.left; + SYNCTEX_END = SYNCTEX_START + sizeof(synctex_node_t); + SYNCTEX_CUR = NULL; + return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t); + } return SYNCTEX_STATUS_ERROR; } + } while ((node = SYNCTEX_NEXT_HORIZ_BOX(node))); + } + /* We are not lucky */ + if((node = SYNCTEX_CHILD(sheet))) { + goto end; + } + return 0; +} + +# ifdef SYNCTEX_NOTHING +# pragma mark - +# pragma mark Utilities +# endif + +int _synctex_bail(void) { + _synctex_error("SyncTeX ERROR\n"); + return -1; +} +/* Rougly speaking, this is: + * node's h coordinate - hitPoint's h coordinate. + * If node is to the right of the hit point, then this distance is positive, + * if node is to the left of the hit point, this distance is negative.*/ +int _synctex_point_h_distance(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible); +int _synctex_point_h_distance(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) { + if(node) { + int min,med,max; + switch(node->class->type) { + /* The distance between a point and a box is special. + * It is not the euclidian distance, nor something similar. + * We have to take into account the particular layout, + * and the box hierarchy. + * Given a box, there are 9 regions delimited by the lines of the edges of the box. + * The origin being at the top left corner of the page, + * we also give names to the vertices of the box. + * + * 1 | 2 | 3 + * ---A---B---> + * 4 | 5 | 6 + * ---C---D---> + * 7 | 8 | 9 + * v v + */ + case synctex_node_type_hbox: + /* getting the box bounds, taking into account negative width, height and depth. */ + min = visible?SYNCTEX_HORIZ_V(node):SYNCTEX_HORIZ(node); + max = min + (visible?SYNCTEX_ABS_WIDTH_V(node):SYNCTEX_ABS_WIDTH(node)); + /* We allways have min <= max */ + if(hitPoint.h<min) { + return min - hitPoint.h; /* regions 1+4+7, result is > 0 */ + } else if (hitPoint.h>max) { + return max - hitPoint.h; /* regions 3+6+9, result is < 0 */ + } else { + return 0; /* regions 2+5+8, inside the box, except for vertical coordinates */ + } + break; + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + case synctex_node_type_void_hbox: + /* getting the box bounds, taking into account negative width, height and depth. + * For these boxes, no visible dimension available */ + min = SYNCTEX_HORIZ(node); + max = min + SYNCTEX_ABS_WIDTH(node); + /* We allways have min <= max */ + if(hitPoint.h<min) { + return min - hitPoint.h; /* regions 1+4+7, result is > 0 */ + } else if (hitPoint.h>max) { + return max - hitPoint.h; /* regions 3+6+9, result is < 0 */ + } else { + return 0; /* regions 2+5+8, inside the box, except for vertical coordinates */ + } + break; + case synctex_node_type_kern: + /* IMPORTANT NOTICE: the location of the kern is recorded AFTER the move. + * The distance to the kern is very special, + * in general, there is no text material in the kern, + * this is why we compute the offset relative to the closest edge of the kern.*/ + max = SYNCTEX_WIDTH(node); + if(max<0) { + min = SYNCTEX_HORIZ(node); + max = min - max; + } else { + min = -max; + max = SYNCTEX_HORIZ(node); + min += max; + } + med = (min+max)/2; + /* positive kern: '.' means text, '>' means kern offset + * ............. + * min>>>>med>>>>max + * ............... + * negative kern: '.' means text, '<' means kern offset + * ............................ + * min<<<<med<<<<max + * ................................. + * Actually, we do not take into account negative widths. + * There is a problem for such situation when there is efectively overlapping text. + * But this should be extremely rare. I guess that in that case, many different choices + * could be made, one being in contradiction of the other. + * It means that the best choice should be made according to the situation that occurs + * most frequently. + */ + if(hitPoint.h<min) { + return min - hitPoint.h + 1; /* penalty to ensure other nodes are chosen first in case of overlapping ones */ + } else if (hitPoint.h>max) { + return max - hitPoint.h - 1; /* same kind of penalty */ + } else if (hitPoint.h>med) { + /* do things like if the node had 0 width and was placed at the max edge + 1*/ + return max - hitPoint.h + 1; /* positive, the kern is to the right of the hitPoint */ + } else { + return min - hitPoint.h - 1; /* negative, the kern is to the left of the hitPoint */ + } + case synctex_node_type_glue: + case synctex_node_type_math: + return SYNCTEX_HORIZ(node) - hitPoint.h; } - /* Then we try to find what is the best child node inside the box best_node, - * which means the node closest to the hit point.*/ - distance = INT_MAX; - if(node = _synctex_best_child_node(best_node,H,V,&distance)) { - if((SYNCTEX_START = malloc(sizeof(synctex_node_t)))) { - * (synctex_node_t *)SYNCTEX_START = node; - SYNCTEX_END = SYNCTEX_START + sizeof(synctex_node_t); - SYNCTEX_CUR = NULL; - return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t); - } else { - return SYNCTEX_STATUS_ERROR; - } + } + return INT_MAX;/* We always assume that the node is faraway to the right*/ +} +/* Rougly speaking, this is: + * node's v coordinate - hitPoint's v coordinate. + * If node is at the top of the hit point, then this distance is positive, + * if node is at the bottom of the hit point, this distance is negative.*/ +int _synctex_point_v_distance(synctex_point_t hitPoint, synctex_node_t node,synctex_bool_t visible); +int _synctex_point_v_distance(synctex_point_t hitPoint, synctex_node_t node,synctex_bool_t visible) { +# ifdef __DARWIN_UNIX03 +# pragma unused(visible) +# endif + if(node) { + int min,max; + switch(node->class->type) { + /* The distance between a point and a box is special. + * It is not the euclidian distance, nor something similar. + * We have to take into account the particular layout, + * and the box hierarchy. + * Given a box, there are 9 regions delimited by the lines of the edges of the box. + * The origin being at the top left corner of the page, + * we also give names to the vertices of the box. + * + * 1 | 2 | 3 + * ---A---B---> + * 4 | 5 | 6 + * ---C---D---> + * 7 | 8 | 9 + * v v + */ + case synctex_node_type_hbox: + /* getting the box bounds, taking into account negative width, height and depth. */ + min = SYNCTEX_VERT_V(node); + max = min + SYNCTEX_ABS_DEPTH_V(node); + min -= SYNCTEX_ABS_HEIGHT_V(node); + /* We allways have min <= max */ + if(hitPoint.v<min) { + return min - hitPoint.v; /* regions 1+2+3, result is > 0 */ + } else if (hitPoint.v>max) { + return max - hitPoint.v; /* regions 7+8+9, result is < 0 */ + } else { + return 0; /* regions 4.5.6, inside the box, except for horizontal coordinates */ + } + break; + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + case synctex_node_type_void_hbox: + /* getting the box bounds, taking into account negative width, height and depth. */ + min = SYNCTEX_VERT(node); + max = min + SYNCTEX_ABS_DEPTH(node); + min -= SYNCTEX_ABS_HEIGHT(node); + /* We allways have min <= max */ + if(hitPoint.v<min) { + return min - hitPoint.v; /* regions 1+2+3, result is > 0 */ + } else if (hitPoint.v>max) { + return max - hitPoint.v; /* regions 7+8+9, result is < 0 */ + } else { + return 0; /* regions 4.5.6, inside the box, except for horizontal coordinates */ + } + break; + case synctex_node_type_kern: + case synctex_node_type_glue: + case synctex_node_type_math: + return SYNCTEX_VERT(node) - hitPoint.v; } - /* We could not find a best node closest to the hit point. - * This is unreachable code because all the boxes here are non void boxes. */ - if((node = SYNCTEX_NEXT_BOX(best_node))) { - goto next_box; - } else { - return 0; - } - } - node = best_node; - /* Now we have best_distance>0 - * We continue through the non void box list until we find the box closest to the hit point */ - while(node = SYNCTEX_NEXT_BOX(node)) { - maxH = SYNCTEX_WIDTH_V(node); - if(maxH<0) { - minH = maxH; - maxH = SYNCTEX_HORIZ_V(node); - minH += maxH; - } else { - minH = SYNCTEX_HORIZ_V(node); - maxH += minH; - } - minV = SYNCTEX_VERT_V(node); - maxV = minV + SYNCTEX_DEPTH_V(node); - minV -= SYNCTEX_HEIGHT_V(node); - if(V<minV) { - if(H<minH) { - /* This is region 1. The distance to the box is the L1 distance PA. */ - distance = minV - V + minH - H;/* Integer overflow? probability epsilon */ - } else if(H<=maxH) { - /* This is region 2. The distance to the box is the geometrical distance to the top edge. */ - distance = minV - V; - } else { - /* This is region 3. The distance to the box is the L1 distance PB. */ - distance = minV - V + H - maxH; - } - } else if(V<=maxV) { - if(H<minH) { - /* This is region 4. The distance to the box is the geometrical distance to the left edge. */ - distance = minH - H; - } else if(H<=maxH) { - /* This is region 4. We are inside the box. */ - distance = 0; - } else { - /* This is region 6. The distance to the box is the geometrical distance to the right edge. */ - distance = H - maxH; - } - } else { - if(H<minH) { - /* This is region 7. The distance to the box is the L1 distance PC. */ - distance = V - maxV + minH - H; - } else if(H<=maxH) { - /* This is region 8. The distance to the box is the geometrical distance to the top edge. */ - distance = V - maxV; - } else { - /* This is region 9. The distance to the box is the L1 distance PD. */ - distance = V - maxV + H - maxH; - } + } + return INT_MAX;/* We always assume that the node is faraway to the top*/ +} + +SYNCTEX_INLINE static synctex_node_t _synctex_smallest_container(synctex_node_t node, synctex_node_t other_node) { + float height, other_height; + if(SYNCTEX_WIDTH(node)<SYNCTEX_WIDTH(other_node)) { + return node; + } + if(SYNCTEX_WIDTH(node)>SYNCTEX_WIDTH(other_node)) { + return other_node; + } + height = SYNCTEX_ABS_DEPTH(node) + SYNCTEX_ABS_HEIGHT(node); + other_height = SYNCTEX_ABS_DEPTH(other_node) + SYNCTEX_ABS_HEIGHT(other_node); + if(height<other_height) { + return node; + } + if(height>other_height) { + return other_node; + } + return node; +} + +synctex_bool_t _synctex_point_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) { + if(node) { + if(0 == _synctex_point_h_distance(hitPoint,node,visible) + && 0 == _synctex_point_v_distance(hitPoint,node,visible)) { + return synctex_YES; } - if(distance>0) { - /* This box does not contain the hit point */ - if(distance<best_distance) { - /* but it is closer */ - best_distance = distance; - best_node = node; - } - } else { - /* This box contains the hit point */ - best_node = node; - /* Is ther a better container, that was not a non void box?*/ - if((best_container = _synctex_best_container(node,H,V)) && (best_container != best_node)) { - /* the answer is yes */ - if((SYNCTEX_START = malloc(sizeof(synctex_node_t)))) { - * (synctex_node_t *)SYNCTEX_START = best_container; - SYNCTEX_END = SYNCTEX_START + sizeof(synctex_node_t); - SYNCTEX_CUR = NULL; - return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t); + } + return synctex_NO; +} + +int _synctex_node_distance_to_point(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) { +# ifdef __DARWIN_UNIX03 +# pragma unused(visible) +# endif + int result = INT_MAX; /* when the distance is meaning less (sheet, input...) */ + if(node) { + int minH,maxH,minV,maxV; + switch(node->class->type) { + /* The distance between a point and a box is special. + * It is not the euclidian distance, nor something similar. + * We have to take into account the particular layout, + * and the box hierarchy. + * Given a box, there are 9 regions delimited by the lines of the edges of the box. + * The origin being at the top left corner of the page, + * we also give names to the vertices of the box. + * + * 1 | 2 | 3 + * ---A---B---> + * 4 | 5 | 6 + * ---C---D---> + * 7 | 8 | 9 + * v v + * In each region, there is a different formula. + * In the end we have a continuous distance which may not be a mathematical distance but who cares. */ + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + case synctex_node_type_hbox: + case synctex_node_type_void_hbox: + /* getting the box bounds, taking into account negative widths. */ + minH = SYNCTEX_HORIZ(node); + maxH = minH + SYNCTEX_ABS_WIDTH(node); + minV = SYNCTEX_VERT(node); + maxV = minV + SYNCTEX_ABS_DEPTH(node); + minV -= SYNCTEX_ABS_HEIGHT(node); + /* In what region is the point hitPoint=(H,V) ? */ + if(hitPoint.v<minV) { + if(hitPoint.h<minH) { + /* This is region 1. The distance to the box is the L1 distance PA. */ + result = minV - hitPoint.v + minH - hitPoint.h;/* Integer overflow? probability epsilon */ + } else if(hitPoint.h<=maxH) { + /* This is region 2. The distance to the box is the geometrical distance to the top edge. */ + result = minV - hitPoint.v; + } else { + /* This is region 3. The distance to the box is the L1 distance PB. */ + result = minV - hitPoint.v + hitPoint.h - maxH; + } + } else if(hitPoint.v<=maxV) { + if(hitPoint.h<minH) { + /* This is region 4. The distance to the box is the geometrical distance to the left edge. */ + result = minH - hitPoint.h; + } else if(hitPoint.h<=maxH) { + /* This is region 4. We are inside the box. */ + result = 0; + } else { + /* This is region 6. The distance to the box is the geometrical distance to the right edge. */ + result = hitPoint.h - maxH; + } } else { - return SYNCTEX_STATUS_ERROR; + if(hitPoint.h<minH) { + /* This is region 7. The distance to the box is the L1 distance PC. */ + result = hitPoint.v - maxV + minH - hitPoint.h; + } else if(hitPoint.h<=maxH) { + /* This is region 8. The distance to the box is the geometrical distance to the top edge. */ + result = hitPoint.v - maxV; + } else { + /* This is region 9. The distance to the box is the L1 distance PD. */ + result = hitPoint.v - maxV + hitPoint.h - maxH; + } } - } - /* the best_node is also the best_container, just find the closest child node. */ - distance = INT_MAX; - if(best_node = _synctex_best_child_node(best_node,H,V,&distance)) { - if((SYNCTEX_START = malloc(sizeof(synctex_node_t)))) { - * (synctex_node_t *)SYNCTEX_START = best_node; - SYNCTEX_END = SYNCTEX_START + sizeof(synctex_node_t); - SYNCTEX_CUR = NULL; - return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t); + break; + case synctex_node_type_kern: + maxH = SYNCTEX_WIDTH(node); + if(maxH<0) { + minH = SYNCTEX_HORIZ(node); + maxH = minH - maxH; + } else { + minH = -maxH; + maxH = SYNCTEX_HORIZ(node); + minH += maxH; + } + minV = SYNCTEX_VERT(node); + if(hitPoint.h<minH) { + if(hitPoint.v>minV) { + result = hitPoint.v - minV + minH - hitPoint.h; + } else { + result = minV - hitPoint.v + minH - hitPoint.h; + } + } else if (hitPoint.h>maxH) { + if(hitPoint.v>minV) { + result = hitPoint.v - minV + hitPoint.h - maxH; + } else { + result = minV - hitPoint.v + hitPoint.h - maxH; + } + } else if(hitPoint.v>minV) { + result = hitPoint.v - minV; + } else { + result = minV - hitPoint.v; + } + break; + case synctex_node_type_glue: + case synctex_node_type_math: + minH = SYNCTEX_HORIZ(node); + minV = SYNCTEX_VERT(node); + if(hitPoint.h<minH) { + if(hitPoint.v>minV) { + result = hitPoint.v - minV + minH - hitPoint.h; + } else { + result = minV - hitPoint.v + minH - hitPoint.h; + } + } else if(hitPoint.v>minV) { + result = hitPoint.v - minV + hitPoint.h - minH; } else { - return SYNCTEX_STATUS_ERROR; + result = minV - hitPoint.v + hitPoint.h - minH; + } + break; + } + } + return result; +} + +static synctex_node_t _synctex_eq_deepest_container(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible) { + if(node) { + synctex_node_t result = NULL; + synctex_node_t child = NULL; + switch(node->class->type) { + case synctex_node_type_vbox: + case synctex_node_type_hbox: + /* test the deep nodes first */ + if((child = SYNCTEX_CHILD(node))) { + do { + if((result = _synctex_eq_deepest_container(hitPoint,child,visible))) { + return result; + } + } while((child = SYNCTEX_SIBLING(child))); + } + /* is the hit point inside the box? */ + if(_synctex_point_in_box(hitPoint,node,visible)) { + if(node && (node->class->type == synctex_node_type_vbox) && (child = SYNCTEX_CHILD(node))) { + int bestDistance = INT_MAX; + do { + if(SYNCTEX_CHILD(child)) { + int distance = _synctex_node_distance_to_point(hitPoint,child,visible); + if(distance < bestDistance) { + bestDistance = distance; + node = child; + } + } + } while((child = SYNCTEX_SIBLING(child))); + } + return node; + } + } + } + return NULL; +} + +/* Compares the locations of the hitPoint with the locations of the various nodes contained in the box. + * As it is an horizontal box, we only compare horizontal coordinates. */ +SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_hbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef, synctex_bool_t visible); +SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_hbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef, synctex_bool_t visible) { + int result = 0; + if((node = SYNCTEX_CHILD(node))) { + do { + int off7 = _synctex_point_h_distance(hitPoint,node,visible); + if(off7 > 0) { + /* node is to the right of the hit point. + * We compare node and the previously recorded one, through the recorded distance. + * If the nodes have the same tag, prefer the one with the smallest line number, + * if the nodes also have the same line number, prefer the one with the smallest column. */ + if(bestDistancesRef->right > off7) { + bestDistancesRef->right = off7; + bestNodesRef->right = node; + result |= SYNCTEX_MASK_RIGHT; + } else if(bestDistancesRef->right == off7 && bestNodesRef->right) { + if(SYNCTEX_TAG(bestNodesRef->right) == SYNCTEX_TAG(node) + && (SYNCTEX_LINE(bestNodesRef->right) > SYNCTEX_LINE(node) + || (SYNCTEX_LINE(bestNodesRef->right) == SYNCTEX_LINE(node) + && SYNCTEX_COLUMN(bestNodesRef->right) > SYNCTEX_COLUMN(node)))) { + bestNodesRef->right = node; + result |= SYNCTEX_MASK_RIGHT; + } + } + } else if(off7 == 0) { + bestDistancesRef->left = bestDistancesRef->right = 0; + bestNodesRef->left = node; + bestNodesRef->right = NULL; + result |= SYNCTEX_MASK_LEFT; + } else { /* here off7 < 0 */ + off7 = -off7; + if(bestDistancesRef->left > off7) { + bestDistancesRef->left = off7; + bestNodesRef->left = node; + result |= SYNCTEX_MASK_LEFT; + } else if(bestDistancesRef->left == off7 && bestNodesRef->left) { + if(SYNCTEX_TAG(bestNodesRef->left) == SYNCTEX_TAG(node) + && (SYNCTEX_LINE(bestNodesRef->left) > SYNCTEX_LINE(node) + || (SYNCTEX_LINE(bestNodesRef->left) == SYNCTEX_LINE(node) + && SYNCTEX_COLUMN(bestNodesRef->left) > SYNCTEX_COLUMN(node)))) { + bestNodesRef->left = node; + result |= SYNCTEX_MASK_LEFT; + } } } - /* We should have stopped here because _synctex_best_child_node always returns something for non void boxes. */ - } - } - /* Bad luck, no non void box does contain the hit point, we have to work harder. - * We start from the top (the sheet's child) and try to find a box that contains the hit point. - * It is a bit long but it should occur only seldomly. */ - if((node = SYNCTEX_CHILD(sheet)) && (best_container = _synctex_best_container(node,H,V)) && (best_container != best_node)) { - /* in fact, we always have best_container != best_node, because the former contains the hit point, but not the latter. - * At that point, we are sure that the distance between the hit point and the best_node is positive. */ - if((SYNCTEX_START = malloc(sizeof(synctex_node_t)))) { - * (synctex_node_t *)SYNCTEX_START = best_container; - SYNCTEX_END = SYNCTEX_START + sizeof(synctex_node_t); - SYNCTEX_CUR = NULL; - return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t); - } else { - return SYNCTEX_STATUS_ERROR; + } while((node = SYNCTEX_SIBLING(node))); + if(result & SYNCTEX_MASK_LEFT) { + /* the left node is new, try to narrow the result */ + if((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->left,visible))) { + bestNodesRef->left = node; + } + if((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->left,visible))) { + bestNodesRef->left = node; + } + } + if(result & SYNCTEX_MASK_RIGHT) { + /* the right node is new, try to narrow the result */ + if((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->right,visible))) { + bestNodesRef->right = node; + } + if((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->right,visible))) { + bestNodesRef->right = node; + } } } - /* Last chance, return the best_node or its best child. */ - if(best_node) { - distance = INT_MAX; - if((node = _synctex_best_child_node(best_node,H,V,&distance))) { - best_node = node; + return result; +} +SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_vbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef,synctex_bool_t visible); +SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_vbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef,synctex_bool_t visible) { + int result = 0; + if((node = SYNCTEX_CHILD(node))) { + do { + int off7 = _synctex_point_v_distance(hitPoint,node,visible);/* this is what makes the difference with the h version above */ + if(off7 > 0) { + /* node is to the top of the hit point (below because TeX is oriented from top to bottom. + * We compare node and the previously recorded one, through the recorded distance. + * If the nodes have the same tag, prefer the one with the smallest line number, + * if the nodes also have the same line number, prefer the one with the smallest column. */ + if(bestDistancesRef->right > off7) { + bestDistancesRef->right = off7; + bestNodesRef->right = node; + result |= SYNCTEX_MASK_RIGHT; + } else if(bestDistancesRef->right == off7 && bestNodesRef->right) { + if(SYNCTEX_TAG(bestNodesRef->right) == SYNCTEX_TAG(node) + && (SYNCTEX_LINE(bestNodesRef->right) > SYNCTEX_LINE(node) + || (SYNCTEX_LINE(bestNodesRef->right) == SYNCTEX_LINE(node) + && SYNCTEX_COLUMN(bestNodesRef->right) > SYNCTEX_COLUMN(node)))) { + bestNodesRef->right = node; + result |= SYNCTEX_MASK_RIGHT; + } + } + } else if(off7 == 0) { + bestDistancesRef->left = bestDistancesRef->right = 0; + bestNodesRef->left = node; + bestNodesRef->right = NULL; + result |= SYNCTEX_MASK_LEFT; + } else { /* here off7 < 0 */ + off7 = -off7; + if(bestDistancesRef->left > off7) { + bestDistancesRef->left = off7; + bestNodesRef->left = node; + result |= SYNCTEX_MASK_LEFT; + } else if(bestDistancesRef->left == off7 && bestNodesRef->left) { + if(SYNCTEX_TAG(bestNodesRef->left) == SYNCTEX_TAG(node) + && (SYNCTEX_LINE(bestNodesRef->left) > SYNCTEX_LINE(node) + || (SYNCTEX_LINE(bestNodesRef->left) == SYNCTEX_LINE(node) + && SYNCTEX_COLUMN(bestNodesRef->left) > SYNCTEX_COLUMN(node)))) { + bestNodesRef->left = node; + result |= SYNCTEX_MASK_LEFT; + } + } + } + } while((node = SYNCTEX_SIBLING(node))); + if(result & SYNCTEX_MASK_LEFT) { + /* the left node is new, try to narrow the result */ + if((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->left,visible))) { + bestNodesRef->left = node; + } + if((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->left,visible))) { + bestNodesRef->left = node; + } } - if((SYNCTEX_START = malloc(sizeof(synctex_node_t)))) { - * (synctex_node_t *)SYNCTEX_START = best_node; - SYNCTEX_END = SYNCTEX_START + sizeof(synctex_node_t); - SYNCTEX_CUR = NULL; - return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t); - } else { - return SYNCTEX_STATUS_ERROR; + if(result & SYNCTEX_MASK_RIGHT) { + /* the right node is new, try to narrow the result */ + if((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->right,visible))) { + bestNodesRef->right = node; + } + if((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->right,visible))) { + bestNodesRef->right = node; + } + } + } + return result; +} +SYNCTEX_INLINE static int _synctex_eq_get_closest_children_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef,synctex_bool_t visible) { + if(node) { + switch(node->class->type) { + case synctex_node_type_hbox: + return __synctex_eq_get_closest_children_in_hbox(hitPoint, node, bestNodesRef, bestDistancesRef,visible); + case synctex_node_type_vbox: + return __synctex_eq_get_closest_children_in_vbox(hitPoint, node, bestNodesRef, bestDistancesRef,visible); } } return 0; } -synctex_node_t synctex_next_result(synctex_scanner_t scanner) { - if(NULL == SYNCTEX_CUR) { - SYNCTEX_CUR = SYNCTEX_START; - } else { - SYNCTEX_CUR+=sizeof(synctex_node_t); - } - if(SYNCTEX_CUR<SYNCTEX_END) { - return *(synctex_node_t*)SYNCTEX_CUR; - } else { - return NULL; +SYNCTEX_INLINE static synctex_node_t __synctex_eq_closest_child(synctex_point_t hitPoint, synctex_node_t node,int* distanceRef, synctex_bool_t visible); +SYNCTEX_INLINE static synctex_node_t __synctex_eq_closest_child(synctex_point_t hitPoint, synctex_node_t node,int* distanceRef, synctex_bool_t visible) { + synctex_node_t best_node = NULL; + if((node = SYNCTEX_CHILD(node))) { + do { + int distance = _synctex_node_distance_to_point(hitPoint,node,visible); + synctex_node_t candidate = NULL; + if(distance<=*distanceRef) { + *distanceRef = distance; + best_node = node; + } + switch(node->class->type) { + case synctex_node_type_vbox: + case synctex_node_type_hbox: + if((candidate = __synctex_eq_closest_child(hitPoint,node,distanceRef,visible))) { + best_node = candidate; + } + } + } while((node = SYNCTEX_SIBLING(node))); } + return best_node; } - -int synctex_bail(void) { - fprintf(stderr,"SyncTeX ERROR\n"); - return -1; +SYNCTEX_INLINE static synctex_node_t _synctex_eq_closest_child(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible) { + if(node) { + switch(node->class->type) { + case synctex_node_type_hbox: + case synctex_node_type_vbox: + { + int best_distance = INT_MAX; + synctex_node_t best_node = __synctex_eq_closest_child(hitPoint,node,&best_distance,visible); + if((best_node)) { + synctex_node_t child = NULL; + switch(best_node->class->type) { + case synctex_node_type_vbox: + case synctex_node_type_hbox: + if((child = SYNCTEX_CHILD(best_node))) { + best_distance = _synctex_node_distance_to_point(hitPoint,child,visible); + while((child = SYNCTEX_SIBLING(child))) { + int distance = _synctex_node_distance_to_point(hitPoint,child,visible); + if(distance<=best_distance) { + best_distance = distance; + best_node = child; + } + } + } + } + } + return best_node; + } + } + } + return NULL; } # ifdef SYNCTEX_NOTHING -# pragma mark ===== updater +# pragma mark - +# pragma mark Updater # endif -typedef int (*synctex_fprintf_t)(void *, const char * , ...); /* print formatted to either FILE * or gzFile */ +typedef int (*synctex_fprintf_t)(void *, const char * , ...); /* print formatted to either FILE * or gzFile */ # define SYNCTEX_BITS_PER_BYTE 8 @@ -3553,86 +4061,56 @@ struct __synctex_updater_t { int length; /* the number of chars appended */ struct _flags { unsigned int no_gz:1; /* Whether zlib is used or not */ - unsigned int reserved:SYNCTEX_BITS_PER_BYTE*sizeof(int)-1; /* Align */ + unsigned int reserved:SYNCTEX_BITS_PER_BYTE*sizeof(int)-1; /* Align */ } flags; }; # define SYNCTEX_FILE updater->file # define SYNCTEX_NO_GZ ((updater->flags).no_gz) # define SYNCTEX_fprintf (*(updater->fprintf)) -# define SYNCTEX_YES (-1) -# define SYNCTEX_NO (0) - -synctex_updater_t synctex_updater_new_with_output_file(const char * output); -void synctex_updater_append_magnification(synctex_updater_t updater, char * magnification); -void synctex_updater_append_x_offset(synctex_updater_t updater, char * x_offset); -void synctex_updater_append_y_offset(synctex_updater_t updater, char * y_offset); -void synctex_updater_free(synctex_updater_t updater); -synctex_updater_t synctex_updater_new_with_output_file(const char * output){ +synctex_updater_t synctex_updater_new_with_output_file(const char * output, const char * build_directory) { synctex_updater_t updater = NULL; char * synctex = NULL; size_t size = 0; - /* prepare the updater */ + synctex_io_mode_t io_mode = synctex_io_mode_read; + const char * mode; + /* prepare the updater */ updater = (synctex_updater_t)_synctex_malloc(sizeof(synctex_updater_t)); if(NULL == updater) { - fprintf(stderr,"! synctex_updater_new_with_file: malloc problem"); + _synctex_error("! synctex_updater_new_with_file: malloc problem"); return NULL; } - size = strlen(output)+strlen(synctex_suffix)+strlen(synctex_suffix_gz)+1; - synctex = (char *)malloc(size); - if(NULL == synctex) { - fprintf(stderr,"! synctex_updater_new_with_output_file: Memory problem (1)\n"); -return_on_error1: + if(_synctex_open(output,build_directory,&synctex,&SYNCTEX_FILE,synctex_NO,&io_mode) + && _synctex_open(output,build_directory,&synctex,&SYNCTEX_FILE,synctex_YES,&io_mode)) { +return_on_error: free(updater); return NULL; } - /* we have reserved for synctex enough memory to copy output and both suffices, - * including the terminating character */ - if(synctex != strcpy(synctex,output)) { - fprintf(stderr,"! synctex_updater_new_with_output_file: Copy problem\n"); -return_on_error2: - free(synctex); - goto return_on_error1; - } - /* remove the last path extension if any */ - synctex_strip_last_path_extension(synctex); - /* append the synctex suffix */ - if(synctex != strcat(synctex,synctex_suffix)){ - fprintf(stderr,"! synctex_scanner_new_with_output_file: Concatenation problem (can't add suffix '%s')\n",synctex_suffix); - goto return_on_error2; - } - if(NULL != (SYNCTEX_FILE = fopen(synctex,"r"))){ - /* OK, the file exists */ - fclose(SYNCTEX_FILE); - if(NULL == (SYNCTEX_FILE = (void *)fopen(synctex,"a"))) { + /* OK, the file exists */ + gzclose(SYNCTEX_FILE); + SYNCTEX_FILE = NULL; + SYNCTEX_NO_GZ = io_mode%2?synctex_NO:synctex_YES; + mode = synctex_io_modes[io_mode+synctex_io_mode_append];/* either "a" or "ab", depending on the file extension */ + if(SYNCTEX_NO_GZ) { + if(NULL == (SYNCTEX_FILE = (void *)fopen(synctex,mode))) { no_write_error: - fprintf(stderr,"! synctex_updater_new_with_file: Can't append to %s",synctex); - goto return_on_error2; + _synctex_error("! synctex_updater_new_with_file: Can't append to %s",synctex); + free(synctex); + goto return_on_error; } - SYNCTEX_NO_GZ = SYNCTEX_YES; updater->fprintf = (synctex_fprintf_t)(&fprintf); -return_updater: - printf("SyncTeX: updating %s...",synctex); - free(synctex); - return updater; - } - /* append the gz suffix */ - if(synctex != strcat(synctex,synctex_suffix_gz)){ - fprintf(stderr,"! synctex_scanner_new_with_output_file: Concatenation problem (can't add suffix '%s')\n",synctex_suffix_gz); - goto return_on_error2; - } - if(NULL != (SYNCTEX_FILE = gzopen(synctex,"r"))){ - gzclose(SYNCTEX_FILE); - if(NULL == (SYNCTEX_FILE = gzopen(synctex,"a"))) { + } else { + if(NULL == (SYNCTEX_FILE = (void *)gzopen(synctex,mode))) { goto no_write_error; } - SYNCTEX_NO_GZ = SYNCTEX_NO; updater->fprintf = (synctex_fprintf_t)(&gzprintf); - goto return_updater; } - goto return_on_error2; + printf("SyncTeX: updating %s...",synctex); + free(synctex); + return updater; } + void synctex_updater_append_magnification(synctex_updater_t updater, char * magnification){ if(NULL==updater) { return; @@ -3676,5 +4154,3 @@ void synctex_updater_free(synctex_updater_t updater){ printf("... done.\n"); return; } - - |