diff options
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/utils/synctex.c')
-rw-r--r-- | Build/source/texk/web2c/luatexdir/utils/synctex.c | 1493 |
1 files changed, 1493 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/utils/synctex.c b/Build/source/texk/web2c/luatexdir/utils/synctex.c new file mode 100644 index 00000000000..459ef746d85 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/utils/synctex.c @@ -0,0 +1,1493 @@ +/* +Copyright (c) 2008 jerome DOT laurens AT u-bourgogne DOT fr + +This file is part of the SyncTeX package. + +License: +-------- +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE + +Except as contained in this notice, the name of the copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written +authorization from the copyright holder. + +Important notice: +----------------- +This file is named "synctex.c", it may or may not have a header counterpart +depending on its use. It aims to provide basic components useful for the +input/output synchronization technology for TeX. +The purpose of the implementation is threefold +- firstly, it defines a new input/output synchronization technology named + "synchronize texnology", "SyncTeX" or "synctex" +- secondly, it defines the naming convention and format of the auxiliary file + used by this technology +- thirdly, it defines the API of a controller and a controller, used in + particular by the pdfTeX and XeTeX programs to prepare synchronization. + +All these are up to a great extent de facto definitions, which means that they +are partly defined by the implementation itself. + +This technology was first designed for pdfTeX, an extension of TeX managing the +pdf output file format, but it can certainly be adapted to other programs built +from TeX as long as the extensions do not break too much the core design. +Moreover, the synchronize texnology only relies on code concept and not +implementation details, so it can be ported to other TeX systems. In order to +support SyncTeX, one can start reading the dedicated section in synctex.ch, +sync-pdftex.ch and sync-xetex.ch. Actually, support is provided for TeX, e-TeX, +pdfTeX and XeTeX. + +Other existing public synchronization technologies are defined by srcltx.sty - +also used by source specials - and pdfsync.sty. Like them, the synchronize +texnology is meant to be shared by various text editors, viewers and TeX +engines. A centralized reference and source of information is available in TeX-Live. + +Versioning: +----------- +As synctex is embedded into different TeX implementation, there is an independent +versionning system. +For TeX implementations, the actual version is: 1 +For .synctex file format, the actual version is SYNCTEX_VERSION below + +Please, do not remove these explanations. + +Acknowledgments: +---------------- +The author received useful remarks from the pdfTeX developers, especially Hahn The Thanh, +and significant help from XeTeX developer Jonathan Kew + +Nota Bene: +---------- +If you include or use a significant part of the synctex package into a software, +I would appreciate to be listed as contributor and see "SyncTeX" highlighted. + +Version 1 +Tue Jul 1 15:23:00 UTC 2008 + +*/ + +# define SYNCTEX_VERSION 1 + +# define SYNCTEX_DEBUG 0 + +/* Debugging: define the next macro to "return;" in order to disable the synctex code + * only suplemental function calls will be used. The compiler may optimize them. */ +# define SYNCTEX_RETURN_IF_DISABLED ; + +# define SYNCTEX_NOERR 0 + +# define EXTERN extern + +# ifdef xfree +# define SYNCTEX_FREE xfree +# else +# define SYNCTEX_FREE(x) free(x) +# endif + +#define ruleht rule_ht +#define ruledp rule_dp +#define rulewd rule_wd +#define zmem varmem +#define jobname job_name +#define totalpages total_pages +#define curinput cur_input +#define synctextagfield synctex_tag_field +#define namefield name_field + +#define gettexstring(a) xstrdup(makecstring(a)) +/*EXTERN char *gettexstring(int n);*/ + +/* the macros defined below do the same job than their almost eponym + * counterparts of *tex.web, the memory access is sometimes more direct + * because *tex.web won't share its own constants the main purpose is to + * maintain very few hook points into *tex.web in order both to ensure + * portability and not modifying to much the original code. see texmfmem.h + * and *tex.web for details, the synctex_ prefix prevents name conflicts, it + * is some kind of namespace +*/ +# warning These structures MUST be kept in synchronization with the main program +/* synctexoption is a global integer variable defined in *tex.web + * it is set to 1 by texmfmp.c if the command line has the '-synctex=1' + * option. */ +# define synctex_options synctexoption +# define SYNCTEX_NO_OPTION INT_MAX +/* if synctex_options is set to SYNCTEX_NO_OPTION, no command line option was provided. */ + +/* glue code: really define the main memory, + * this is exactly the same "mem" as in *tex.web. */ +# define mem zmem +/* glue code: synctexoffset is a global integer variable defined in *tex.web + * it is set to the offset where the primitive \synctex reads and writes its + * value. */ +# define SYNCTEX_VALUE zeqtb[synctexoffset].cint +/* if there were a mean to share the value of synctex_code between *tex.web + * and this file, it would be great. */ + +# define SYNCTEX_UNIT_FACTOR 1 +# define UNIT / synctex_ctxt.unit +/* UNIT is the scale. TeX coordinates are very accurate and client won't need + * that, at leat in a first step. 1.0 <-> 2^16 = 65536. + * The TeX unit is sp (scaled point) or pt/65536 which means that the scale + * factor to retrieve a bp unit (a postscript) is 72/72.27/65536 = + * 1/4096/16.06 = 1/8192/8.03 + * Here we use 1/SYNCTEX_UNIT_FACTOR as scale factor, then we can limit ourselves to + * integers. This default value assumes that TeX magnification factor is 1000. + * The real TeX magnification factor is used to fine tune the synctex context + * scale in the synctex_dot_open function. + * IMPORTANT: We can say that the natural unit of .synctex files is SYNCTEX_UNIT_FACTOR sp. + * To retrieve the proper bp unit, we'll have to divide by 8.03. To reduce + * rounding errors, we'll certainly have to add 0.5 for non negative integers + * and ±0.5 for negative integers. This trick is mainly to gain speed and + * size. A binary file would be more appropriate in that respect, but I guess + * that some clients like auctex would not like it very much. we cannot use + * "<<13" instead of "/SYNCTEX_UNIT_FACTOR" because the integers are signed and we do not + * want the sign bit to be propagated. The origin of the coordinates is at + * the top left corner of the page. For pdf mode, it is straightforward, but + * for dvi mode, we'll have to record the 1in offset in both directions, + * eventually modified by the magnification. +*/ + +/* WARNING: + The 9 definitions below must be in sync with their eponym declarations in + the proper synctex-*.ch* file. +*/ +# define synchronization_field_size 1 +/* The default value is 2, it is suitable for original TeX and alike, + * but it is too big for XeTeX. + * The tag and the line are just the two last words of the node. This is a + * very handy design but this is not strictly required by the concept. If + * really necessary, one can define other storage rules. + * XeTeX redefines synchronization_field_size, + * SYNCTEX_TAG_MODEL and SYNCTEX_LINE_MODEL + * All the default values are targeted to TeX or e-TeX. */ +# define SYNCTEX_TAG_MODEL(NODE,SIZE)\ + vinfo(NODE+SIZE-synchronization_field_size) +# define SYNCTEX_LINE_MODEL(NODE,SIZE)\ + vlink(NODE+SIZE-synchronization_field_size) +/* SYNCTEX_TAG_MODEL and SYNCTEX_LINE_MODEL are used to define + * SYNCTEX_TAG and SYNCTEX_LINE in a model independant way + * Both are tag and line accessors */ +/*# define box_node_size (7+synchronization_field_size)*/ +/* see: @d box_node_size=... + * There should be an automatic process here because these definitions + * are redundant. However, this process would certainly be overcomplicated + * (building then parsing the *tex.web file would be a pain) */ +# define width_offset 2 +/* see: @d width_offset=... */ +# define depth_offset 3 +/* see: @d depth_offset=... */ +# define height_offset 4 +/* see: @d height_offset=... */ + +/* Now define the local version of width(##), height(##) and depth(##) macros + These only depend on the 3 macros above. */ +# define SYNCTEX_TYPE(NODE) type(NODE) +/*# define rule_node 2*/ +/*# define glue_node 10*/ +/*# define kern_node 11*/ +# define SYNCTEX_SUBTYPE(NODE) subtype(NODE) +# define SYNCTEX_WIDTH(NODE) mem[NODE+width_offset].cint +# define SYNCTEX_DEPTH(NODE) mem[NODE+depth_offset].cint +# define SYNCTEX_HEIGHT(NODE) mem[NODE+height_offset].cint + +/* When an hlist ships out, it can contain many different kern/glue nodes with + * exactly the same sync tag and line. To reduce the size of the .synctex + * file, we only display a kern node sync info when either the sync tag or the + * line changes. Also, we try ro reduce the distance between the chosen nodes + * in order to improve accuracy. It means that we display information for + * consecutive nodes, as far as possible. This tricky part uses a "recorder", + * which is the address of the routine that knows how to write the + * synchronization info to the .synctex file. It also uses criteria to detect + * a change in the context, this is the macro SYNCTEX_CONTEXT_DID_CHANGE. The + * SYNCTEX_IGNORE macro is used to detect unproperly initialized nodes. See + * details in the implementation of the functions below. */ +# define SYNCTEX_IGNORE(NODE) SYNCTEX_IS_OFF || !SYNCTEX_VALUE || !SYNCTEX_FILE + +/* Some parts of the code may differ depending on the ouput mode, + * dvi or xdv vs pdf, in particular the management of magnification. + * The default is dvi mode. + * Also, if pdftex is used, the origin of the coordinates is at 0, not at 1in + * Default values are suitable for TeX */ +# define SYNCTEX_OUTPUT "dvi" +# define SYNCTEX_OFFSET_IS_PDF 0 + +# define SYNCTEX_YES (-1) +# define SYNCTEX_NO (0) +# define SYNCTEX_NO_ERROR (0) + +# include "luatexd.h" +# undef SYNCTEX_OFFSET_IS_PDF +# define SYNCTEX_OFFSET_IS_PDF (pdf_output_value>0) +# undef SYNCTEX_OUTPUT +# define SYNCTEX_OUTPUT ((pdf_output_value>0)?"pdf":"dvi") + +#define __SyncTeX__ 1 + +# if defined(__SyncTeX__) + +# include <stdio.h> +# include <stdarg.h> +# include "zlib.h" + +typedef void (*synctex_recorder_t)(halfword); /* recorders know how to record a node */ +typedef int (*synctex_fprintf_t)(void *, const char * , ...); /* print formatted to either FILE * or gzFile */ + +# define SYNCTEX_BITS_PER_BYTE 8 + +/* Here are all the local variables gathered in one "synchronization context" */ +static struct { + void *file; /* the foo.synctex or foo.synctex.gz I/O identifier */ + synctex_fprintf_t fprintf; /* either fprintf or gzprintf */ + char *busy_name; /* the real "foo.synctex(busy)" or "foo.synctex.gz(busy)" name */ + char *root_name; /* in general jobname.tex */ + integer count; /* The number of interesting records in "foo.synctex" */ + /* next concern the last sync record encountered */ + halfword node; /* the last synchronized node, must be set + * before the recorder */ + synctex_recorder_t recorder;/* the recorder of the node above, the + * routine that knows how to record the + * node to the .synctex file */ + integer tag, line; /* current tag and line */ + integer curh, curv; /* current point */ + integer magnification; /* The magnification as given by \mag */ + integer unit; /* The unit, defaults to 1, use 8192 to produce shorter but less accurate info */ + integer total_length; /* The total length of the bytes written since the last check point */ + struct _flags { + unsigned int option_read:1; /* Command line option read (in case of problem or at the end) */ + unsigned int off:1; /* Definitely turn off synctex, corresponds to cli option -synctex=0 */ + unsigned int no_gz:1; /* Whether zlib is used or not */ + unsigned int not_void:1; /* Whether it really contains synchronization material */ + unsigned int warn:1; /* One shot warning flag */ + unsigned int reserved:SYNCTEX_BITS_PER_BYTE*sizeof(int)-5; /* Align */ + } flags; +} synctex_ctxt = { +NULL, NULL, NULL, NULL, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, {0,0,0,0,0,0}}; + +#define SYNCTEX_FILE synctex_ctxt.file +#define SYNCTEX_IS_OFF (synctex_ctxt.flags.off) +#define SYNCTEX_NO_GZ (synctex_ctxt.flags.no_gz) +#define SYNCTEX_NOT_VOID (synctex_ctxt.flags.not_void) +#define SYNCTEX_WARNING_DISABLE (synctex_ctxt.flags.warn) +#define SYNCTEX_fprintf (*synctex_ctxt.fprintf) + +/* Initialize the options, synchronize the variables. + * This is sent by *tex.web before any TeX macro is used. + * */ +void synctex_init_command(void) +{ + /* This is a one shot function, any subsequent call is void */ + if (synctex_ctxt.flags.option_read) { + return; + } + if (SYNCTEX_NO_OPTION == synctex_options) { + /* No option given from the command line */ + SYNCTEX_VALUE = 0; + } else if (synctex_options == 0) { + /* -synctex=0 was given: SyncTeX must be definitely disabled, + * any subsequent \synctex=1 will have no effect at all */ + SYNCTEX_IS_OFF = SYNCTEX_YES; + SYNCTEX_VALUE = 0; + } else { + /* the command line options are not ignored */ + if(synctex_options < 0) { + SYNCTEX_NO_GZ = SYNCTEX_YES; + } + /* Initialize the content of the \synctex primitive */ + SYNCTEX_VALUE = synctex_options; + } + synctex_ctxt.flags.option_read = SYNCTEX_YES; + return; +} + +/* Free all memory used and close the file, + * It is sent locally when there is a problem with synctex output. */ +void synctex_abort(void) +{ + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctex_abort\n"); +#endif + if (SYNCTEX_FILE) { + if (SYNCTEX_NO_GZ) { + xfclose((FILE *)SYNCTEX_FILE, synctex_ctxt.busy_name); + } else { + gzclose((gzFile)SYNCTEX_FILE); + } + SYNCTEX_FREE(synctex_ctxt.busy_name); + synctex_ctxt.busy_name = NULL; + } + SYNCTEX_FREE(synctex_ctxt.root_name); + synctex_ctxt.root_name = NULL; + SYNCTEX_IS_OFF = SYNCTEX_YES; /* disable synctex */ +} + +static inline int synctex_record_preamble(void); +static inline int synctex_record_input(integer tag, char *name); + +static char *synctex_suffix = ".synctex"; +static char *synctex_suffix_gz = ".gz"; +static char *synctex_suffix_busy = "(busy)"; + +/* synctex_dot_open ensures that the foo.synctex file is open. + * In case of problem, it definitely disables synchronization. + * Now all the output synchronization info is gathered in only one file. + * It is possible to split this info into as many different output files as sheets + * plus 1 for the control but the overall benefits are not so clear. + * For example foo-i.synctex would contain input synchronization + * information for page i alone. +*/ +static void *synctex_dot_open(void) +{ + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nwarning: Synchronize DEBUG: synctex_dot_open\n"); + printf("\nwarning: SYNCTEX_VALUE=%0X\n", SYNCTEX_VALUE); + printf("\nwarning: synctex_options=%0X\n", synctex_options); +# endif + if (SYNCTEX_IS_OFF || !SYNCTEX_VALUE) { + return NULL; /* synchronization is disabled: do nothing */ + } + if (SYNCTEX_FILE) { + return SYNCTEX_FILE; /* synchronization is alerady enabled */ + } +#if SYNCTEX_DEBUG + printf("\nwarning: Synchronize DEBUG: synctex_dot_open 1\n"); +# endif + /* this is the first time we are asked to open the file + this part of code is executed only once: + either SYNCTEX_FILE is nonnegative or synchronization is + definitely disabled. */ + { + char *tmp = gettexstring(jobname); + /* jobname was set by the \jobname command on the *TeX side */ + char * the_busy_name = xmalloc(strlen(tmp) + strlen(synctex_suffix) + strlen(synctex_suffix_gz) + strlen(synctex_suffix_busy) + 1); + if(!the_busy_name) { + SYNCTEX_FREE(tmp); + synctex_abort(); + return NULL; + } + strcpy(the_busy_name, tmp); + SYNCTEX_FREE(tmp); + tmp = NULL; + strcat(the_busy_name, synctex_suffix); + /* Initialize SYNCTEX_NO_GZ with the content of \synctex to let the user choose the format. */ + SYNCTEX_NO_GZ = SYNCTEX_VALUE<0?SYNCTEX_YES:SYNCTEX_NO; + if (!SYNCTEX_NO_GZ) { + strcat(the_busy_name, synctex_suffix_gz); + } + strcat(the_busy_name, synctex_suffix_busy); + if (SYNCTEX_NO_GZ) { + SYNCTEX_FILE = xfopen(the_busy_name, FOPEN_WBIN_MODE); + synctex_ctxt.fprintf = (synctex_fprintf_t)(&fprintf); + } else { + SYNCTEX_FILE = gzopen(the_busy_name, FOPEN_WBIN_MODE); + synctex_ctxt.fprintf = (synctex_fprintf_t)(&gzprintf); + } +#if SYNCTEX_DEBUG + printf("\nwarning: Synchronize DEBUG: synctex_dot_open 2\n"); +#endif + if (SYNCTEX_FILE) { + if(SYNCTEX_NO_ERROR != synctex_record_preamble()) { + synctex_abort(); + return NULL; + } + /* Initialization of the context */ + synctex_ctxt.magnification = 1000; + synctex_ctxt.unit = SYNCTEX_UNIT_FACTOR; + /* synctex_ctxt.busy_name was NULL before, it now owns the_busy_name */ + synctex_ctxt.busy_name = the_busy_name; + the_busy_name = NULL; + /* print the preamble, this is an quite an UTF8 file */ + if (NULL != synctex_ctxt.root_name) { + synctex_record_input(1,synctex_ctxt.root_name); + SYNCTEX_FREE(synctex_ctxt.root_name); + synctex_ctxt.root_name = NULL; + } + synctex_ctxt.count = 0; +#if SYNCTEX_DEBUG + fprintf(stdout, + "\nwarning: Synchronize DEBUG: synctex_dot_open SYNCTEX AVAILABLE\n"); +#endif + } else { + /* no .synctex file available, so disable synchronization */ + SYNCTEX_IS_OFF = SYNCTEX_YES; + SYNCTEX_VALUE = 0; + printf("\nSyncTeX warning: no synchronization, problem with %s\n",the_busy_name); + /* and free the_busy_name */ + SYNCTEX_FREE(the_busy_name); + the_busy_name = NULL; +#if SYNCTEX_DEBUG + fprintf(stdout, + "\nwarning: Synchronize DEBUG: synctex_dot_open SYNCTEX DISABLED\n"); +#endif + } + } + return SYNCTEX_FILE; +} + +/* Each time TeX opens a file, it sends a synctexstartinput message and enters + * this function. Here, a new synchronization tag is created and stored in + * the synctex_tag_field of the TeX current input context. Each synchronized + * TeX node will record this tag instead of the file name. synctexstartinput + * writes the mapping synctag <-> file name to the .synctex (or .synctex.gz) file. A client + * will read the .synctex file and retrieve this mapping, it will be able to + * open the correct file just knowing its tag. If the same file is read + * multiple times, it might be associated to different tags. Synchronization + * controllers, either in viewers, editors or standalone should be prepared to + * handle this situation and take the appropriate action if they want to + * optimize memory. No two different files will have the same positive tag. + * It is not advisable to definitely store the file names here. If the file + * names ever have to be stored, it should definitely be done at the TeX level + * just like src-specials do, such that other components of the program can use + * it. This function does not make any difference between the files, it + * treats the same way .tex, .aux, .sty ... files, even if many of them do not + * contain any material meant to be typeset. +*/ +void synctex_start_input(void) +{ + static unsigned int synctex_tag_counter = 0; + + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nwarning: Synchronize DEBUG: synctexstartinput %i", + synctex_tag_counter); + printf("\nwarning: SYNCTEX_VALUE=%i", SYNCTEX_VALUE); + printf("\nwarning: synctex_options=%0X", synctex_options); +#endif + + if (SYNCTEX_IS_OFF) { + return; + } + /* synctex_tag_counter is a counter uniquely identifying the file actually + * open. Each time tex opens a new file, synctexstartinput will increment this + * counter */ + if (~synctex_tag_counter > 0) { + ++synctex_tag_counter; + } else { + /* we have reached the limit, subsequent files will be softly ignored + * this makes a lot of files... even in 32 bits + * Maybe we will limit this to 16bits and + * use the 16 other bits to store the column number */ + curinput.synctextagfield = 0; + return; + } + curinput.synctextagfield = synctex_tag_counter; /* -> *TeX.web */ + if (synctex_tag_counter == 1) { + /* this is the first file TeX ever opens, in general \jobname.tex we + * do not know yet if synchronization will ever be enabled so we have + * to store the file name, because we will need it later. + * This is necessary because \jobname can be different */ + synctex_ctxt.root_name = gettexstring(curinput.namefield); + /* we could initialize the unit field to 1 to avoid floating point exception + * when accidentaly dividing by the unit. + * This occurs when some SYNCTEX_IGNORE macro is not used. + * But this must not happen unexpectedly, so we leave the unit to 0 */ +#if SYNCTEX_DEBUG + printf("\nwarning: Synchronize DEBUG: synctexstartinput first END\n"); +# endif + return; + } + if (SYNCTEX_FILE || (SYNCTEX_VALUE && (SYNCTEX_NO_ERROR != synctex_dot_open()))) { + char *tmp = gettexstring(curinput.namefield); + synctex_record_input(curinput.synctextagfield,tmp); + SYNCTEX_FREE(tmp); + } +#if SYNCTEX_DEBUG + printf("\nwarning: Synchronize DEBUG: synctexstartinput END\n"); +# endif + return; +} + +/* All the synctex... functions below have the smallest set of parameters. It + * appears to be either the address of a node, or nothing at all. Using zmem, + * which is the place where all the nodes are stored, one can retrieve every + * information about a node. The other information is obtained through the + * global context variable. + */ + +static inline int synctex_record_postamble(void); + + +/* Free all memory used and close the file, + * sent by close_files_and_terminate in tex.web. + * synctexterminate() is called when the TeX run terminates. + * If synchronization was active, the working synctex file is moved to + * the final synctex file name. + * If synchronization was not active of if there is no output, + * the synctex file is removed if any. + * That way we can be sure that any synctex file is in sync with a tex run. + * However, it does not mean that it will be in sync with the pdf, especially + * when the output is dvi or xdv and the dvi (or xdv) to pdf driver has not been applied. + */ +void synctex_terminate(boolean log_opened) +{ + char *tmp = NULL; + char * the_real_syncname = NULL; + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexterminate\n"); +#endif + tmp = gettexstring(jobname); + the_real_syncname = xmalloc(strlen(tmp) + strlen(synctex_suffix) + strlen(synctex_suffix_gz) + 1); + if(!the_real_syncname) { + SYNCTEX_FREE(tmp); + synctex_abort(); + return; + } + strcpy(the_real_syncname, tmp); + strcat(the_real_syncname, synctex_suffix); + if (!SYNCTEX_NO_GZ) { + /* Remove any uncompressed synctex file, from a previous build. */ + remove(the_real_syncname); + strcat(the_real_syncname, synctex_suffix_gz); + } + /* allways remove the synctex output file before renaming it, windows requires it. */ + if(0 != remove(the_real_syncname) && errno == EACCES) { + fprintf(stderr,"SyncTeX: Can't remove %s (file is open or read only)\n",the_real_syncname); + } + if (SYNCTEX_FILE) { + if (SYNCTEX_NOT_VOID) { + synctex_record_postamble(); + /* close the synctex file*/ + if (SYNCTEX_NO_GZ) { + xfclose((FILE *)SYNCTEX_FILE, synctex_ctxt.busy_name); + } else { + gzclose((gzFile)SYNCTEX_FILE); + } + /* renaming the working synctex file */ + if(0 == rename(synctex_ctxt.busy_name,the_real_syncname)) { + if(log_opened) { + printf("\nSyncTeX written on %s",the_real_syncname); /* SyncTeX also refers to the contents */ + } + } else { + fprintf(stderr,"SyncTeX: Can't rename %s to %s\n",synctex_ctxt.busy_name,the_real_syncname); + remove(synctex_ctxt.busy_name); + } + } else { + /* close and remove the synctex file because there are no pages of output */ + if (SYNCTEX_NO_GZ) { + xfclose((FILE *)SYNCTEX_FILE, synctex_ctxt.busy_name); + } else { + gzclose((gzFile)SYNCTEX_FILE); + } + remove(synctex_ctxt.busy_name); + } + SYNCTEX_FILE = NULL; + } + if (SYNCTEX_NO_GZ) { + /* Remove any compressed synctex file, from a previous build. */ + strcat(the_real_syncname, synctex_suffix_gz); + remove(the_real_syncname); + } + SYNCTEX_FREE(synctex_ctxt.busy_name); + synctex_ctxt.busy_name = NULL; + SYNCTEX_FREE(the_real_syncname); + SYNCTEX_FREE(tmp); + synctex_abort(); +} + +static inline int synctex_record_content(void); +static inline int synctex_record_settings(void); +static inline int synctex_record_sheet(integer sheet); + +/* Recording the "{..." line. In *tex.web, use synctex_sheet(pdf_output) at + * the very beginning of the ship_out procedure. +*/ +void synctex_sheet(integer mag) +{ + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexsheet %i\n",mag); +#endif + if (SYNCTEX_IS_OFF) { + if(SYNCTEX_VALUE && !SYNCTEX_WARNING_DISABLE) { + SYNCTEX_WARNING_DISABLE = SYNCTEX_YES; + printf("\nSyncTeX warning: Synchronization was disabled from\nthe command line with -synctex=0\nChanging the value of \\synctex has no effect."); + } + return; + } + if (SYNCTEX_FILE || (SYNCTEX_VALUE && (SYNCTEX_NO_ERROR != synctex_dot_open()))) { + /* First possibility: the .synctex file is already open because SyncTeX was activated on the CLI + * or it was activated with the \synctex macro and the first page is already shipped out. + * Second possibility: tries to open the .synctex, useful if synchronization was enabled + * from the source file and not from the CLI. + * totalpages is defined in tex.web */ + if (totalpages == 0) { + /* Now it is time to properly set up the scale factor. */ + if(mag>0) { + synctex_ctxt.magnification = mag; + } + if(SYNCTEX_NO_ERROR != synctex_record_settings() + || SYNCTEX_NO_ERROR != synctex_record_content()) { + synctex_abort(); + return; + } + } + synctex_record_sheet(totalpages+1); + } +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexsheet END\n"); +#endif + return; +} + +static inline int synctex_record_teehs(integer sheet); + +/* Recording the "}..." line. In *tex.web, use synctex_teehs at + * the very end of the ship_out procedure. +*/ +void synctex_teehs(void) +{ + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexteehs\n"); +#endif + if (SYNCTEX_IS_OFF || !SYNCTEX_FILE ) { + return; + } + synctex_record_teehs(totalpages);/* not totalpages+1*/ +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexteehs END\n"); +#endif + return; +} + +static inline void synctex_record_vlist(halfword p); + +/* This message is sent when a vlist will be shipped out, more precisely at + * the beginning of the vliSYNCTEX_out procedure in *TeX.web. It will be balanced + * by a synctex_tsilv, sent at the end of the vliSYNCTEX_out procedure. p is the + * address of the vlist We assume that p is really a vlist node! */ +void synctex_vlist(halfword this_box) +{ + scaledpos pos; + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexhlist\n"); +#endif + if (SYNCTEX_IGNORE(this_box)) { + return; + } + synctex_ctxt.node = this_box; /* 0 to reset */ + synctex_ctxt.recorder = NULL; /* reset */ + synctex_ctxt.tag = SYNCTEX_TAG_MODEL(this_box,box_node_size); + synctex_ctxt.line = SYNCTEX_LINE_MODEL(this_box,box_node_size); + pos = synch_p_with_c(cur); + synctex_ctxt.curh = pos.h; + synctex_ctxt.curv = pos.v; + synctex_record_vlist(this_box); +} + +static inline void synctex_record_tsilv(halfword p); + +/* Recording a "f" line ending a vbox: this message is sent whenever a vlist + * has been shipped out. It is used to close the vlist nesting level. It is + * sent at the end of the vliSYNCTEX_out procedure in *TeX.web to balance a former + * synctex_vlist sent at the beginning of that procedure. */ +void synctex_tsilv(halfword this_box) +{ + scaledpos pos; + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctextsilv\n"); +#endif + if (SYNCTEX_IGNORE(this_box)) { + return; + } + /* Ignoring any pending info to be recorded */ + synctex_ctxt.node = this_box; /* 0 to reset */ + synctex_ctxt.tag = SYNCTEX_TAG_MODEL(this_box,box_node_size); + synctex_ctxt.line = SYNCTEX_LINE_MODEL(this_box,box_node_size); + pos = synch_p_with_c(cur); + synctex_ctxt.curh = pos.h; + synctex_ctxt.curv = pos.v; + synctex_ctxt.recorder = NULL; + synctex_record_tsilv(this_box); +} + +static inline void synctex_record_void_vlist(halfword p); + +/* This message is sent when a void vlist will be shipped out. + * There is no need to balance a void vlist. */ +void synctex_void_vlist(halfword p, halfword this_box) +{ + scaledpos pos; + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexvoidvlist\n"); +#endif + if (SYNCTEX_IGNORE(p)) { + return; + } + synctex_ctxt.node = p; /* reset */ + synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,box_node_size); + synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,box_node_size); + pos = synch_p_with_c(cur); + synctex_ctxt.curh = pos.h; + synctex_ctxt.curv = pos.v; + synctex_ctxt.recorder = NULL; /* reset */ + synctex_record_void_vlist(p); +} + +static inline void synctex_record_hlist(halfword p); + +/* This message is sent when an hlist will be shipped out, more precisely at + * the beginning of the hliSYNCTEX_out procedure in *TeX.web. It will be balanced + * by a synctex_tsilh, sent at the end of the hliSYNCTEX_out procedure. p is the + * address of the hlist We assume that p is really an hlist node! */ +void synctex_hlist(halfword this_box) +{ + scaledpos pos; + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexhlist\n"); +#endif + if (SYNCTEX_IGNORE(this_box)) { + return; + } + synctex_ctxt.node = this_box; /* 0 to reset */ + synctex_ctxt.tag = SYNCTEX_TAG_MODEL(this_box,box_node_size); + synctex_ctxt.line = SYNCTEX_LINE_MODEL(this_box,box_node_size); + pos = synch_p_with_c(cur); + synctex_ctxt.curh = pos.h; + synctex_ctxt.curv = pos.v; + synctex_ctxt.recorder = NULL; /* reset */ + synctex_record_hlist(this_box); +} + +static inline void synctex_record_tsilh(halfword p); + +/* Recording a ")" line ending an hbox this message is sent whenever an hlist + * has been shipped out it is used to close the hlist nesting level. It is + * sent at the end of the hliSYNCTEX_out procedure in *TeX.web to balance a former + * synctex_hlist sent at the beginning of that procedure. */ +void synctex_tsilh(halfword this_box) +{ + scaledpos pos; + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctextsilh\n"); +#endif + if (SYNCTEX_IGNORE(this_box)) { + return; + } + /* Ignoring any pending info to be recorded */ + synctex_ctxt.node = this_box; /* 0 to force next node to be recorded! */ + synctex_ctxt.tag = SYNCTEX_TAG_MODEL(this_box,box_node_size); + synctex_ctxt.line = SYNCTEX_LINE_MODEL(this_box,box_node_size); + pos = synch_p_with_c(cur); + synctex_ctxt.curh = pos.h; + synctex_ctxt.curv = pos.v; + synctex_ctxt.recorder = NULL; /* reset */ + synctex_record_tsilh(this_box); +} + +static inline void synctex_record_void_hlist(halfword p); + +/* This message is sent when a void hlist will be shipped out. + * There is no need to balance a void hlist. */ +void synctex_void_hlist(halfword p, halfword this_box) +{ + scaledpos pos; + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexvoidhlist\n"); +#endif + if (SYNCTEX_IGNORE(p)) { + return; + } + /* the sync context has changed */ + if (synctex_ctxt.recorder != NULL) { + /* but was not yet recorded */ + (*synctex_ctxt.recorder) (synctex_ctxt.node); + } + synctex_ctxt.node = p; /* 0 to reset */ + synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,box_node_size); + synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,box_node_size); + pos = synch_p_with_c(cur); + synctex_ctxt.curh = pos.h; + synctex_ctxt.curv = pos.v; + synctex_ctxt.recorder = NULL; /* reset */ + synctex_record_void_hlist(p); +} + +/* glue code: these only work with nodes of size medium_node_size */ +# define small_node_size 3 +/* see: @d small_node_size=2 {number of words to allocate for most node types} */ +# define medium_node_size (small_node_size+synchronization_field_size) +/* see: @d rule_node_size=4 */ +# /* define rule_node_size (4+synchronization_field_size)*/ + +/* IN THE SEQUEL, ALL NODE ARE medium_node_size'd, UNTIL THE CONTRARY IS MENTIONNED */ +# undef SYNCTEX_IGNORE +# define SYNCTEX_IGNORE(NODE) SYNCTEX_IS_OFF || !SYNCTEX_VALUE \ + || (0 >= SYNCTEX_TAG_MODEL(NODE,medium_node_size)) \ + || (0 >= SYNCTEX_LINE_MODEL(NODE,medium_node_size)) + +/* This macro will detect a change in the synchronization context. As long as + * the synchronization context remains the same, there is no need to write + * synchronization info: it would not help more. The synchronization context + * has changed when either the line number or the file tag has changed. */ +# define SYNCTEX_CONTEXT_DID_CHANGE(NODE) ((0 == synctex_ctxt.node)\ + || (SYNCTEX_TAG_MODEL(NODE,medium_node_size) != synctex_ctxt.tag)\ + || (SYNCTEX_LINE_MODEL(NODE,medium_node_size) != synctex_ctxt.line)) + +void synctex_math_recorder(halfword p); + +/* glue code this message is sent whenever an inline math node will ship out + See: @ @<Output the non-|char_node| |p| for... */ +void synctex_math(halfword p, halfword this_box) +{ + scaledpos pos; + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexmath\n"); +#endif + if (SYNCTEX_IGNORE(p)) { + return; + } + if ((synctex_ctxt.recorder != NULL) && SYNCTEX_CONTEXT_DID_CHANGE(p)) { + /* the sync context did change */ + (*synctex_ctxt.recorder) (synctex_ctxt.node); + } + synctex_ctxt.node = p; + synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,medium_node_size); + synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,medium_node_size); + pos = synch_p_with_c(cur); + synctex_ctxt.curh = pos.h; + synctex_ctxt.curv = pos.v; + synctex_ctxt.recorder = NULL;/* no need to record once more */ + synctex_math_recorder(p);/* always record synchronously */ +} + +static inline void synctex_record_glue(halfword p); +static inline void synctex_record_kern(halfword p); +static inline void synctex_record_rule(halfword p); + +/* this message is sent whenever an horizontal glue node or rule node ships out + See: move_past:... */ +# define SYNCTEX_IGNORE_RULE(NODE) SYNCTEX_IS_OFF || !SYNCTEX_VALUE \ + || (0 >= SYNCTEX_TAG_MODEL(NODE,rule_node_size)) \ + || (0 >= SYNCTEX_LINE_MODEL(NODE,rule_node_size)) +void synctex_horizontal_rule_or_glue(halfword p, halfword this_box) +{ + scaledpos pos; + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexglue\n"); +#endif + if (SYNCTEX_TYPE(p) == rule_node) { /* not medium_node_size so we can't use SYNCTEX_IGNORE */ + if (SYNCTEX_IGNORE_RULE(p)) { + return; + } + } + else { + if (SYNCTEX_IGNORE(p)) { + return; + } + } + synctex_ctxt.node = p; + pos = synch_p_with_c(cur); + synctex_ctxt.curh = pos.h; + synctex_ctxt.curv = pos.v; + synctex_ctxt.recorder = NULL; + switch(SYNCTEX_TYPE(p)) { + case rule_node: + synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,rule_node_size); + synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,rule_node_size); + synctex_record_rule(p);/* always record synchronously: maybe some text is outside the box */ + break; + case glue_node: + synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,medium_node_size); + synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,medium_node_size); + synctex_record_glue(p);/* always record synchronously: maybe some text is outside the box */ + break; + case kern_node: + synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,medium_node_size); + synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,medium_node_size); + synctex_record_kern(p);/* always record synchronously: maybe some text is outside the box */ + break; + default: + printf("\nSynchronize ERROR: unknown node type %i\n",SYNCTEX_TYPE(p)); + } +} + +void synctex_kern_recorder(halfword p); + +/* this message is sent whenever a kern node ships out + See: @ @<Output the non-|char_node| |p| for... */ +void synctex_kern(halfword p, halfword this_box) +{ + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexkern\n"); +#endif + if (SYNCTEX_IGNORE(p)) { + return; + } + if (SYNCTEX_CONTEXT_DID_CHANGE(p)) { + /* the sync context has changed */ + if (synctex_ctxt.recorder != NULL) { + /* but was not yet recorded */ + (*synctex_ctxt.recorder) (synctex_ctxt.node); + } + if(synctex_ctxt.node == this_box) { + /* first node in the list */ + synctex_ctxt.node = p; + synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,medium_node_size); + synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,medium_node_size); + synctex_ctxt.recorder = &synctex_kern_recorder; + } else { + synctex_ctxt.node = p; + synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,medium_node_size); + synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,medium_node_size); + synctex_ctxt.recorder = NULL; + /* always record when the context has just changed + * and when not the first node */ + synctex_kern_recorder(p); + } + } else { + /* just update the geometry and type (for future improvements) */ + synctex_ctxt.node = p; + synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,medium_node_size); + synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,medium_node_size); + synctex_ctxt.recorder = &synctex_kern_recorder; + } +} + +/* This last part is used as a tool to infer TeX behaviour, + * but not for direct synchronization. */ +# undef SYNCTEX_IGNORE +# define SYNCTEX_IGNORE(NODE) SYNCTEX_IS_OFF || !SYNCTEX_VALUE || !SYNCTEX_FILE \ + || (synctex_ctxt.count>2000) + +void synctex_char_recorder(halfword p); + +/* this message is sent whenever a char node ships out */ +void synctexchar(halfword p, halfword this_box) +{ + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexchar\n"); +#endif + if (SYNCTEX_IGNORE(p)) { + return; + } + if (synctex_ctxt.recorder != NULL) { + /* but was not yet recorded */ + (*synctex_ctxt.recorder) (synctex_ctxt.node); + } + synctex_ctxt.node = p; + synctex_ctxt.tag = 0; + synctex_ctxt.line = 0; + synctex_ctxt.recorder = NULL; + /* always record when the context has just changed */ + synctex_char_recorder(p); +} + +void synctex_node_recorder(halfword p); + +# undef SYNCTEX_IGNORE +# define SYNCTEX_IGNORE(NODE) (SYNCTEX_IS_OFF || !SYNCTEX_VALUE || !SYNCTEX_FILE) + +/* this message should be sent to record information + for a node of an unknown type */ +void synctexnode(halfword p, halfword this_box) +{ + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexnode\n"); +#endif + if (SYNCTEX_IGNORE(p)) { + return; + } + /* always record, not very usefull yet */ + synctex_node_recorder(p); +} + +/* this message should be sent to record information + synchronously for the current location */ +void synctex_current(void) +{ + scaledpos pos; + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexcurrent\n"); +#endif + if (SYNCTEX_IGNORE(nothing)) { + return; + } else { + pos = synch_p_with_c(cur); + size_t len = SYNCTEX_fprintf(SYNCTEX_FILE,"x%i,%i:%i,%i\n", + synctex_ctxt.tag,synctex_ctxt.line, + pos.h UNIT,pos.v UNIT); + if(len>0) { + synctex_ctxt.total_length += len; + return; + } + } + synctex_abort(); + return; +} + +#pragma mark - +#pragma mark Glue code Recorders + +/* Recording the settings */ +static inline int synctex_record_settings(void) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_settings\n"); +#endif + if(NULL == SYNCTEX_FILE) { + return SYNCTEX_NOERR; + } + if(SYNCTEX_FILE) { + size_t len = SYNCTEX_fprintf(SYNCTEX_FILE,"Output:%s\nMagnification:%i\nUnit:%i\nX Offset:%i\nY Offset:%i\n", + SYNCTEX_OUTPUT,synctex_ctxt.magnification,synctex_ctxt.unit, + ((SYNCTEX_OFFSET_IS_PDF != 0) ? 0 : 4736287 UNIT), + ((SYNCTEX_OFFSET_IS_PDF != 0) ? 0 : 4736287 UNIT)); + if(len>0) { + synctex_ctxt.total_length += len; + return SYNCTEX_NOERR; + } + } + synctex_abort(); + return -1; +} + +/* Recording a "SyncTeX..." line */ +static inline int synctex_record_preamble(void) +{ + size_t len = 0; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_preamble\n"); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,"SyncTeX Version:%i\n",SYNCTEX_VERSION); + if(len>0) { + synctex_ctxt.total_length = len; + return SYNCTEX_NOERR; + } + synctex_abort(); + return -1; +} + +/* Recording a "Input:..." line */ +static inline int synctex_record_input(integer tag, char *name) +{ + size_t len = 0; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_input\n"); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,"Input:%i:%s\n",tag,name); + if(len>0) { + synctex_ctxt.total_length += len; + return SYNCTEX_NOERR; + } + synctex_abort(); + return -1; +} + +/* Recording a "!..." line */ +static inline int synctex_record_anchor(void) +{ + size_t len = 0; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_anchor\n"); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,"!%i\n",synctex_ctxt.total_length); + if(len>0) { + synctex_ctxt.total_length = len; + ++synctex_ctxt.count; + return SYNCTEX_NOERR; + } + synctex_abort(); + return -1; +} + +/* Recording a "Content" line */ +static inline int synctex_record_content(void) +{ + size_t len = 0; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_content\n"); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,"Content:\n"); + if(len>0) { + synctex_ctxt.total_length += len; + return SYNCTEX_NOERR; + } + synctex_abort(); + return -1; +} + +/* Recording a "{..." line */ +static inline int synctex_record_sheet(integer sheet) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_sheet\n"); +#endif + if(SYNCTEX_NOERR == synctex_record_anchor()) { + size_t len = SYNCTEX_fprintf(SYNCTEX_FILE,"{%i\n",sheet); + if(len>0) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return SYNCTEX_NOERR; + } + } + synctex_abort(); + return -1; +} + +/* Recording a "}..." line */ +static inline int synctex_record_teehs(integer sheet) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_teehs\n"); +#endif + if(SYNCTEX_NOERR == synctex_record_anchor()) { + size_t len = SYNCTEX_fprintf(SYNCTEX_FILE,"}%i\n",sheet); + if(len>0) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return SYNCTEX_NOERR; + } + } + synctex_abort(); + return -1; +} + +/* Recording a "v..." line */ +static inline void synctex_record_void_vlist(halfword p) +{ + size_t len = 0; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_void_vlist\n"); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,"v%i,%i:%i,%i:%i,%i,%i\n", + SYNCTEX_TAG_MODEL(p,box_node_size), + SYNCTEX_LINE_MODEL(p,box_node_size), + synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT, + SYNCTEX_WIDTH(p) UNIT, + SYNCTEX_HEIGHT(p) UNIT, + SYNCTEX_DEPTH(p) UNIT); + if(len>0) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a "[..." line */ +static inline void synctex_record_vlist(halfword p) +{ + size_t len = 0; + SYNCTEX_NOT_VOID = SYNCTEX_YES; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_vlist\n"); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,"[%i,%i:%i,%i:%i,%i,%i\n", + SYNCTEX_TAG_MODEL(p,box_node_size), + SYNCTEX_LINE_MODEL(p,box_node_size), + synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT, + SYNCTEX_WIDTH(p) UNIT, + SYNCTEX_HEIGHT(p) UNIT, + SYNCTEX_DEPTH(p) UNIT); + if(len>0) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a "]..." line */ +static inline void synctex_record_tsilv(halfword p) +{ + size_t len = 0; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_tsilv\n"); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,"]\n"); + if(len>0) { + synctex_ctxt.total_length += len; + return; + } + synctex_abort(); + return; +} + +/* Recording a "h..." line */ +static inline void synctex_record_void_hlist(halfword p) +{ + size_t len = 0; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_void_hlist\n"); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,"h%i,%i:%i,%i:%i,%i,%i\n", + SYNCTEX_TAG_MODEL(p,box_node_size), + SYNCTEX_LINE_MODEL(p,box_node_size), + synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT, + SYNCTEX_WIDTH(p) UNIT, + SYNCTEX_HEIGHT(p) UNIT, + SYNCTEX_DEPTH(p) UNIT); + if(len>0) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a "(..." line */ +static inline void synctex_record_hlist(halfword p) +{ + size_t len = 0; + SYNCTEX_NOT_VOID = SYNCTEX_YES; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_hlist\n"); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,"(%i,%i:%i,%i:%i,%i,%i\n", + SYNCTEX_TAG_MODEL(p,box_node_size), + SYNCTEX_LINE_MODEL(p,box_node_size), + synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT, + SYNCTEX_WIDTH(p) UNIT, + SYNCTEX_HEIGHT(p) UNIT, + SYNCTEX_DEPTH(p) UNIT); + if(len>0) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a ")..." line */ +static inline void synctex_record_tsilh(halfword p) +{ + size_t len = 0; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_tsilh\n"); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,")\n"); + if(len>0) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a "Count..." line */ +static inline int synctex_record_count(void) { + size_t len = 0; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_count\n"); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,"Count:%i\n",synctex_ctxt.count); + if(len>0) { + synctex_ctxt.total_length += len; + return SYNCTEX_NOERR; + } + synctex_abort(); + return -1; +} + +/* Recording a "Postamble" section */ +static inline int synctex_record_postamble(void) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_postamble\n"); +#endif + if(SYNCTEX_NOERR == synctex_record_anchor()) { + size_t len = SYNCTEX_fprintf(SYNCTEX_FILE,"Postamble:\n"); + if(len>0) { + synctex_ctxt.total_length += len; + if(synctex_record_count() || synctex_record_anchor()) { + } else { + len = SYNCTEX_fprintf(SYNCTEX_FILE,"Post scriptum:\n"); + if(len>0) { + synctex_ctxt.total_length += len; + return SYNCTEX_NOERR; + } + } + } + } + synctex_abort(); + return -1; +} + +/* Recording a "g..." line */ +static inline void synctex_record_glue(halfword p) +{ + size_t len = 0; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_glue_recorder\n"); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,"g%i,%i:%i,%i\n", + SYNCTEX_TAG_MODEL(p,medium_node_size), + SYNCTEX_LINE_MODEL(p,medium_node_size), + synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT); + if(len>0) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a "k..." line */ +static inline void synctex_record_kern(halfword p) +{ + size_t len = 0; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_kern_recorder\n"); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,"k%i,%i:%i,%i:%i\n", + SYNCTEX_TAG_MODEL(p,medium_node_size), + SYNCTEX_LINE_MODEL(p,medium_node_size), + synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT, + SYNCTEX_WIDTH(p) UNIT); + if(len>0) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a "r..." line */ +static inline void synctex_record_rule(halfword p) +{ + size_t len = 0; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_tsilh\n"); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,"r%i,%i:%i,%i:%i,%i,%i\n", + SYNCTEX_TAG_MODEL(p,rule_node_size), + SYNCTEX_LINE_MODEL(p,rule_node_size), + synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT, + rulewd UNIT, + ruleht UNIT, + ruledp UNIT); + if(len>0) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + + +#pragma mark - +#pragma mark Recorders + +/* Recording a "$..." line */ +void synctex_math_recorder(halfword p) +{ + size_t len = 0; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_math_recorder\n"); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,"$%i,%i:%i,%i\n", + SYNCTEX_TAG_MODEL(p,medium_node_size), + SYNCTEX_LINE_MODEL(p,medium_node_size), + synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT); + if(len>0) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a "k..." line */ +void synctex_kern_recorder(halfword p) +{ + size_t len = 0; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_kern_recorder\n"); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,"k%i,%i:%i,%i:%i\n", + SYNCTEX_TAG_MODEL(p,medium_node_size), + SYNCTEX_LINE_MODEL(p,medium_node_size), + synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT, + SYNCTEX_WIDTH(p) UNIT); + if(len>0) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a "c..." line */ +void synctex_char_recorder(halfword p) +{ + size_t len = 0; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_char_recorder\n"); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,"c%i,%i\n", + synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT); + if(len>0) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a "?..." line, type, subtype and position */ +void synctex_node_recorder(halfword p) +{ + size_t len = 0; +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_node_recorder(0x%x)\n",p); +#endif + len = SYNCTEX_fprintf(SYNCTEX_FILE,"?%i,%i:%i,%i\n", + synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT, + mem[p].hh.b0,mem[p].hh.b1); + if(len>0) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +# else +# warning "SyncTeX is disabled" +# endif |