diff options
-rw-r--r-- | Build/source/texk/web2c/synctex/synctex.c | 659 | ||||
-rw-r--r-- | Build/source/texk/web2c/synctex/synctex.ch | 860 | ||||
-rw-r--r-- | Build/source/texk/web2c/synctex/synctex.defines | 49 | ||||
-rw-r--r-- | Build/source/texk/web2c/synctex/synctex.h | 61 | ||||
-rw-r--r-- | Build/source/texk/web2c/synctex/synctex.mk | 50 |
5 files changed, 1679 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/synctex/synctex.c b/Build/source/texk/web2c/synctex/synctex.c new file mode 100644 index 00000000000..8f1e5a72aca --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex.c @@ -0,0 +1,659 @@ +/* +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. + +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 on +CTAN, in directory support/synctex. + +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. + +*/ + +# define SYNCTEX_DEBUG 0 + +extern char *gettexstring(int n); + +# define EXTERN extern + +# define SYNCTEX_VERSION 1 + +/* Some parts of the code may differ depending on the TeX engine. + * Here are the possible switches: */ +# define SYNCTEX_ENGINE_TEX 0 +# define SYNCTEX_ENGINE_PDFTEX 1 +/* Default engine (suitable for xetex): */ +# define SYNCTEX_ENGINE SYNCTEX_ENGINE_TEX + +/* Other 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 not pdf mode. */ +# define SYNCTEX_IS_PDF 0 + +# if defined(XETEX_MAC) || defined(XETEX_OTHER) + +# include <stdio.h> + +# include "xetexd.h" + /* this will define XeTeX, which we can use in later conditionals */ + +# include <xetexdir/xetexextra.h> + +# define MAX(a, b) ((a) > (b) ? (a) : (b)) +# define xfree(x) do { if (x) free(x); } while (0) + +# else + +# ifdef pdfTeX +# undef pdfTeX +# endif + +# include "pdftexd.h" + +# undef SYNCTEX_ENGINE +# define SYNCTEX_ENGINE SYNCTEX_ENGINE_PDFTEX + +/* We observe pdfoutputvalue in order to determine whether output mode is pdf. + * We will assume that pdf_output_value equals pdf_output before entering + * the synctex_sheet function below. */ +# undef SYNCTEX_IS_PDF +# define SYNCTEX_IS_PDF (pdfoutputvalue>0) + +# endif /* defined XETEX_* */ + +# if defined(pdfTeX) || defined(XeTeX) || defined(__SyncTeX__) + +/* Here are all the local variables gathered in one "synchronization context" */ +static struct { + FILE *file; /* the foo.synctex I/O identifier */ + char *name; /* the real "foo.synctex" name */ + char *root_name; /* in general jobname.tex */ + integer count; /* The number of records in "foo.synctex" */ + /* next concern the last sync record encountered */ + halfword p; /* the last synchronized node, must be set + * before the recorder */ + void (*recorder) (halfword p); /* the recorder of the node above, the + * routine that knows how to record the + * node to the .synctex file */ + integer h, v; /* the last sync record coordinates */ + integer offset; /* the offset of the origin / the topleft of + * the page in both directions */ + integer scale; /* Some magnification factor to define UNIT */ +} synctex_ctxt = { +NULL, NULL, NULL, 0, 0, NULL, 0, 0, 0, 0}; + +/* 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 '-synchronize=1' + * option. */ +# define SYNCTEX_OPTIONS synctexoption +# define SYNCTEX_DISABLED_MASK 0x80000000 +/* if the SYNCTEX_DISABLED_MASK bit of SYNCTEX_OPTIONS is set, the + * synchronization is definitely disabled. */ +# define SYNCTEX_IGNORE_CLI_MASK 0x40000000 +/* if the SYNCTEX_IGNORE_CLI_MASK bit of SYNCTEX_OPTIONS is set, the option + * given from the command line is ignored. */ + +/* 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_IS_ENABLED zeqtb[synctexoffset].cint +/* if there were a mean to share the value of synctex_code between pdftex.web + * and this file, it would be great. */ + +/* synctex_dot_open ensures that the foo.synctex file is open. + * In case of problem, it definitely disables synchronization. + * Now all the 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 FILE *synctex_dot_open(void) +{ +# if SYNCTEX_DEBUG + fprintf(stdout, "\nwarning: Synchronize DEBUG: synctex_dot_open\n"); + fprintf(stdout, "\nwarning: SYNCTEX_IS_ENABLED=%0X\n", SYNCTEX_IS_ENABLED); + fprintf(stdout, "\nwarning: SYNCTEX_OPTIONS=%0X\n", SYNCTEX_OPTIONS); +# endif + if (0 != (SYNCTEX_OPTIONS & SYNCTEX_DISABLED_MASK)) { + return 0; /* synchronization is definitely disabled: do nothing */ + } +# if SYNCTEX_DEBUG + fprintf(stdout, "\nwarning: Synchronize DEBUG: synctex_dot_open 1\n"); +# endif + if (NULL == synctex_ctxt.file) { + /* this is the first time we are asked to open the file + this part of code is executed only once: + either synctex_ctxt.file is nonnegative or synchronization is + definitely disabled. */ + static char *suffix = ".synctex"; + /* jobname was set by the \jobname command on the *TeX side */ + char *tmp = gettexstring(jobname); + /* jobname was set by the \jobname command on the *TeX side */ + char *the_syncname = xmalloc(strlen(tmp) + strlen(suffix) + 1); + strcpy(the_syncname, tmp); + xfree(tmp); + strcat(the_syncname, suffix); + synctex_ctxt.file = xfopen(the_syncname, FOPEN_W_MODE); +# if SYNCTEX_DEBUG + fprintf(stdout, "\nwarning: Synchronize DEBUG: synctex_dot_open 2\n"); +# endif + if (NULL != synctex_ctxt.file) { + /* synctex_ctxt.name was NULL before, it now owns the_syncname */ + synctex_ctxt.name = the_syncname; + /* print the preamble, this is an UTF8 file */ + fprintf(synctex_ctxt.file, "SyncTeX\nversion:%d\n", + SYNCTEX_VERSION); + if (NULL != synctex_ctxt.root_name) { + fprintf(synctex_ctxt.file, "i:1:%s\n", synctex_ctxt.root_name); + xfree(synctex_ctxt.root_name); + synctex_ctxt.root_name = NULL; + } +# if SYNCTEX_DEBUG + fprintf(stdout, + "\nwarning: Synchronize DEBUG: synctex_dot_open SYNCTEX AVAILABLE\n"); +# endif + } else { + /* no .synctex file available, so disable synchronization */ + SYNCTEX_OPTIONS = SYNCTEX_DISABLED_MASK; + /* and free the_syncname */ + xfree(the_syncname); + the_syncname = NULL; +# if SYNCTEX_DEBUG + fprintf(stdout, + "\nwarning: Synchronize DEBUG: synctex_dot_open SYNCTEX DISABLED\n"); +# endif + } + } + return synctex_ctxt.file; +} + +/* Each time TeX opens a file, it sends a syncstartinput 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. syncstartinput + * writes the mapping synctag <-> file name to the .synctex 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 + * controller, either in viewers, editors or standalone should be prepared to + * handle this situation and take the appropriate action of 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 synctexstartinput(void) +{ + static unsigned int synctex_tag_counter = 0; + +# if SYNCTEX_DEBUG + fprintf(stdout, "\nwarning: Synchronize DEBUG: synctexstartinput %i\n", + synctex_tag_counter); + fprintf(stdout, "\nwarning: SYNCTEX_IS_ENABLED=%i\n", SYNCTEX_IS_ENABLED); + fprintf(stdout, "\nwarning: SYNCTEX_OPTIONS=%0X\n", SYNCTEX_OPTIONS); + fprintf(stdout, "\nwarning: SYNCTEX_DISABLED_MASK=%0X\n", + SYNCTEX_DISABLED_MASK); +# endif + + if (0 != (SYNCTEX_OPTIONS & SYNCTEX_DISABLED_MASK)) { + /* this is where we disable synchronization -synchronization=-1 */ + return; + } + /* synctex_tag_counter is a counter uniquely identifying the file actually + * open each time tex opens a new file, syncstartinput 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 */ + curinput.synctextagfield = 0; + return; + } + + if (0 == (SYNCTEX_OPTIONS & SYNCTEX_IGNORE_CLI_MASK)) { + /* the command line options are not ignored */ + SYNCTEX_IS_ENABLED = MAX(SYNCTEX_OPTIONS, SYNCTEX_IS_ENABLED); + SYNCTEX_OPTIONS |= SYNCTEX_IGNORE_CLI_MASK; + /* the command line options will be ignored from now on. Every + * subsequent call of syncstartinput won't get there SYNCTEX_OPTIONS + * is now the list of option flags */ + } + + 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 + * certainly not necessary due to \jobname */ + synctex_ctxt.root_name = gettexstring(curinput.namefield); + return; + } + if ((NULL != synctex_ctxt.file) + || ((SYNCTEX_IS_ENABLED && synctex_dot_open()) != 0)) { + char *tmp = gettexstring(curinput.namefield); + fprintf(synctex_ctxt.file,"i:%u:%s\n",curinput.synctextagfield,tmp); + xfree(tmp); + } +# if SYNCTEX_DEBUG + fprintf(stdout, "\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. +*/ + +/* Recording the "s:..." line. In *tex.web, use synctex_sheet(pdf_output) at + * the very beginning of the ship_out procedure. +*/ +void synctexsheet(integer mag) +{ +# if SYNCTEX_DEBUG + fprintf(stdout, "\nSynchronize DEBUG: synctexsheet %i\n",mag); +# endif + if (0 != (SYNCTEX_OPTIONS & SYNCTEX_DISABLED_MASK)) { + return; + } + if ((synctex_ctxt.file != NULL) + || ((SYNCTEX_IS_ENABLED != 0) && (synctex_dot_open() != 0))) { + /* 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 */ + synctex_ctxt.count = 0; + if (totalpages == 0) { + if (SYNCTEX_IS_PDF != 0) { + fprintf(synctex_ctxt.file, ">:pdf\n"); + } + /* Now it is time to properly set up the scale factor. + * Depending on the output mode + * dvi and pdf, don't start from the same origin. + * dvi starts at (1in,1in) from the top left corner + * pdf starts exactly from the top left corner. + * mag is a global TeX variable. */ + if(mag>0) { + synctex_ctxt.scale = 8192000/mag; + } + else { + synctex_ctxt.scale = 8192; + } + fprintf(synctex_ctxt.file, "z:%ld\n", ((SYNCTEX_IS_PDF != 0) ? 0 : 578)); +# if SYNCTEX_DEBUG + fprintf(stdout, "\nSynchronize DEBUG: synctex_ctxt.scale:%u\n",synctex_ctxt.scale); +# endif + } + fprintf(synctex_ctxt.file, "s:%ld\n", (long int) totalpages + 1); + ++synctex_ctxt.count; + } +# if SYNCTEX_DEBUG + fprintf(stdout, "\nSynchronize DEBUG: synctexsheet END\n"); +# endif + return; +} + +# define UNIT / synctex_ctxt.scale +/* 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/8192 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 8192 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 "/8192" 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 5 definitions below must be in sync with their eponym declarations in *tex.web +*/ +# ifdef XeTeX +# define synchronization_field_size 1 +# else +# define synchronization_field_size 2 +# endif + +# define box_node_size (7+synchronization_field_size) +/* see: @d box_node_size=... */ +# define width_offset 1 +/* see: @d width_offset=... */ +# define depth_offset 2 +/* see: @d depth_offset=... */ +# define height_offset 3 +/* see: @d height_offset=... */ + +/* Now define the local version of width(##), height(##) and depth(##) macros + These only depend on the macros above. */ +# 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 + +# ifdef XeTeX +/* in XeTeX, "halfword" fields are at least 32 bits, so we'll use those for + * tag and line so that the sync field size is only one memory_word. */ +# define SYNCTEX_TAG(NODE) mem[NODE+box_node_size-1].hh.lhfield +# define SYNCTEX_LINE(NODE) mem[NODE+box_node_size-1].hh.rh +# else +/* 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. */ +# define SYNCTEX_TAG(NODE) mem[NODE+box_node_size-2].cint +# define SYNCTEX_LINE(NODE) mem[NODE+box_node_size-1].cint +#endif + +/* When an hlist ships out, it can contain many different kern 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) (0 != (SYNCTEX_OPTIONS & SYNCTEX_DISABLED_MASK) ) \ + || (SYNCTEX_IS_ENABLED == 0) \ + || (synctex_ctxt.file == 0) + +/* Recording a "h:..." line */ +void synctex_hlist_recorder(halfword p) +{ + fprintf(synctex_ctxt.file, "h:%u:%u(%i,%i,%i,%i,%i)\n", + SYNCTEX_TAG(p), SYNCTEX_LINE(p), + curh UNIT, + curv UNIT, + SYNCTEX_WIDTH(p) UNIT, + SYNCTEX_HEIGHT(p) UNIT, + SYNCTEX_DEPTH(p) UNIT); + ++synctex_ctxt.count; +} + +/* This message is sent when an hlist will be shipped out, more precisely at + * the beginning of the hlist_out procedure in *TeX.web. It will be balanced + * by a synctex_tsilh, sent at the end of the hlist_out procedure. p is the + * address of the hlist We assume that p is really an hlist node! */ +void synctexhlist(halfword p) +{ +# if SYNCTEX_DEBUG + fprintf(stdout, "\nSynchronize DEBUG: synctexhlist\n"); +# endif + if (SYNCTEX_IGNORE(p)) { + return; + } + synctex_ctxt.p = 0; /* reset */ + synctex_ctxt.recorder = NULL; /* reset */ + synctex_hlist_recorder(p); +} + +/* Recording a "e" 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 hlist_out procedure in *TeX.web to balance a former + * synctex_hlist sent at the beginning of that procedure. */ +void synctextsilh(halfword p) +{ +# if SYNCTEX_DEBUG + fprintf(stdout, "\nSynchronize DEBUG: synctextsilh\n"); +# endif + if (SYNCTEX_IGNORE(p)) { + return; + } + /* is there a pending info to be recorded */ + if (NULL != synctex_ctxt.recorder) { + /* synctex_ctxt node is set and must be recorded as last node */ + (*synctex_ctxt.recorder) (synctex_ctxt.p); + synctex_ctxt.p = 0; /* force next node to be recorded! */ + synctex_ctxt.recorder = NULL; + } + fputs("e\n", synctex_ctxt.file); +} + +# undef SYNCTEX_IGNORE +# define SYNCTEX_IGNORE(NODE) (0 != (SYNCTEX_OPTIONS & SYNCTEX_DISABLED_MASK) ) \ + || (0 == SYNCTEX_IS_ENABLED) \ + || (0 >= SYNCTEX_TAG(NODE)) \ + || (0 >= SYNCTEX_LINE(NODE)) \ + || (0 == synctex_ctxt.file) +# undef SYNCTEX_TAG +# undef SYNCTEX_LINE +/* glue code: these only work with nodes of size medium_node_size */ +# define small_node_size 2 +/* 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) +# ifdef XeTeX +# define SYNCTEX_TAG(NODE) mem[NODE+medium_node_size-1].hh.lhfield +# define SYNCTEX_LINE(NODE) mem[NODE+medium_node_size-1].hh.rh +# else +# define SYNCTEX_TAG(NODE) mem[NODE+medium_node_size-2].cint +# define SYNCTEX_LINE(NODE) mem[NODE+medium_node_size-1].cint +# endif + +/* 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 ((0 == synctex_ctxt.p)\ + || (SYNCTEX_TAG(p) != SYNCTEX_TAG(synctex_ctxt.p))\ + || (SYNCTEX_LINE(p) != SYNCTEX_LINE(synctex_ctxt.p))) + +/* Recording a "$:..." line */ +void synctex_math_recorder(halfword p) +{ + fprintf(synctex_ctxt.file, "$:%u:%u(%i,%i)\n", + SYNCTEX_TAG(p), SYNCTEX_LINE(p), + synctex_ctxt.h UNIT, + synctex_ctxt.v UNIT); + ++synctex_ctxt.count; +} + +/* glue code this message is sent whenever an inline math node will ship out + See: @ @<Output the non-|char_node| |p| for... */ +void synctexmath(halfword p) +{ +# if SYNCTEX_DEBUG + fprintf(stdout, "\nSynchronize DEBUG: synctexmath\n"); +# endif + if (SYNCTEX_IGNORE(p)) { + return; + } + if ((synctex_ctxt.recorder != NULL) && SYNCTEX_CONTEXT_DID_CHANGE) { + /* the sync context did change */ + (*synctex_ctxt.recorder) (synctex_ctxt.p); + } + synctex_ctxt.h = curh; + synctex_ctxt.v = curv; + synctex_ctxt.p = p; + synctex_ctxt.recorder = NULL;/* no need to record once more */ + synctex_math_recorder(p);/* always record */ +} + +/* Recording a "g:..." line */ +void synctex_glue_recorder(halfword p) +{ + fprintf(synctex_ctxt.file, "g:%u:%u(%i,%i)\n", + SYNCTEX_TAG(p), SYNCTEX_LINE(p), + synctex_ctxt.h UNIT, + synctex_ctxt.v UNIT); + ++synctex_ctxt.count; +} + +/* this message is sent whenever a glue node ships out + See: @ @<Output the non-|char_node| |p| for... */ +void synctexglue(halfword p) +{ +# if SYNCTEX_DEBUG + fprintf(stdout, "\nSynchronize DEBUG: synctexglue\n"); +# endif + if (SYNCTEX_IGNORE(p)) { + return; + } + if (SYNCTEX_CONTEXT_DID_CHANGE) { + /* the sync context has changed */ + if (synctex_ctxt.recorder != NULL) { + /* but was not yet recorded */ + (*synctex_ctxt.recorder) (synctex_ctxt.p); + } + synctex_ctxt.h = curh; + synctex_ctxt.v = curv; + synctex_ctxt.p = p; + synctex_ctxt.recorder = NULL; + /* always record when the context has just changed */ + synctex_glue_recorder(p); + } else { + /* just update the geometry and type (for future improvements) */ + synctex_ctxt.h = curh; + synctex_ctxt.v = curv; + synctex_ctxt.p = p; + synctex_ctxt.recorder = &synctex_glue_recorder; + } +} + +/* Recording a "k:..." line */ +void synctex_kern_recorder(halfword p) +{ + fprintf(synctex_ctxt.file, "k:%u:%u(%i,%i,%i)\n", + SYNCTEX_TAG(p), SYNCTEX_LINE(p), + synctex_ctxt.h UNIT, + synctex_ctxt.v UNIT, + SYNCTEX_WIDTH(p) UNIT); + ++synctex_ctxt.count; +} + +/* this message is sent whenever a kern node ships out + See: @ @<Output the non-|char_node| |p| for... */ +void synctexkern(halfword p) +{ +# if SYNCTEX_DEBUG + fprintf(stdout, "\nSynchronize DEBUG: synctexkern\n"); +# endif + if (SYNCTEX_IGNORE(p)) { + return; + } + if (SYNCTEX_CONTEXT_DID_CHANGE || (SYNCTEX_WIDTH(p)<0)) { + /* the sync context has changed */ + if (synctex_ctxt.recorder != NULL) { + /* but was not yet recorded */ + (*synctex_ctxt.recorder) (synctex_ctxt.p); + } + synctex_ctxt.h = curh; + synctex_ctxt.v = curv; + synctex_ctxt.p = p; + synctex_ctxt.recorder = NULL; + /* always record when the context has just changed */ + synctex_kern_recorder(p); + } else { + /* just update the geometry and type (for future improvements) */ + synctex_ctxt.h = curh; + synctex_ctxt.v = curv; + synctex_ctxt.p = p; + synctex_ctxt.recorder = &synctex_kern_recorder; + } +} + +/* Free all memory used and close the file, sent by utils.c */ +void synctex_terminate(void) +{ +# if SYNCTEX_DEBUG + fprintf(stdout, "\nSynchronize DEBUG: synctex_terminate\n"); +# endif + if (synctex_ctxt.file != NULL) { + fprintf(synctex_ctxt.file, "#:%u\n",synctex_ctxt.count); + xfclose(synctex_ctxt.file, synctex_ctxt.name); + xfree(synctex_ctxt.name); + } + xfree(synctex_ctxt.root_name); +} + +#endif diff --git a/Build/source/texk/web2c/synctex/synctex.ch b/Build/source/texk/web2c/synctex/synctex.ch new file mode 100644 index 00000000000..cd207ffe55f --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex.ch @@ -0,0 +1,860 @@ +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. + +Notice: +------- +This file contains TeX changes for core synctex support. +It is missing some implementation details that are deferred to either +sync-pdftex.ch or sync-xetex.ch +synctex.ch is based on tex.web after the eTeX changes have been applied. +So it might not apply as is to pdftex.web due to some typographical changes. +In the building process, one may have to apply some suitable tex.ch0 first. +See pdftexdir for details. + +@x +found: link(r):=null; {this node is now nonempty} +@!stat var_used:=var_used+s; {maintain usage statistics} +tats@;@/ +get_node:=r; +exit:end; +@y +found: link(r):=null; {this node is now nonempty} +@!stat var_used:=var_used+s; {maintain usage statistics} +tats@;@/ +@<Initialize bigger nodes with {\sl synctex} information@>; +get_node:=r; +exit:end; +@z + +The |synctex_field_size| depends on the TeX implementation. +pdfTeX uses 2 additional words whereas XeTeX will only use one, +because it naturally has bigger words of memory. +@x +@d hlist_node=0 {|type| of hlist nodes} +@d box_node_size=7 {number of words to allocate for a box node} +@y +@d synctex_engine_pdftex=0 +@d synctex_engine_xetex=1 +@d synctex_field_size=MISSING IMPLEMENTATION + +@d hlist_node=0 {|type| of hlist nodes} +@d box_node_size=7+synctex_field_size {number of words to allocate for a box node} +@z + +@x +@d small_node_size=2 {number of words to allocate for most node types} +@y +@d small_node_size=2 {number of words to allocate for most node types} +@d medium_node_size=small_node_size+synctex_field_size {number of words to + allocate for synchronized node types like math, kern and glue nodes} +@z + +@x +@p function new_math(@!w:scaled;@!s:small_number):pointer; +var p:pointer; {the new node} +begin p:=get_node(small_node_size); type(p):=math_node; +subtype(p):=s; width(p):=w; new_math:=p; +end; +@y +@p function new_math(@!w:scaled;@!s:small_number):pointer; +var p:pointer; {the new node} +begin p:=get_node(medium_node_size); type(p):=math_node; + {{\sl synctex} node size watch point: proper size} +subtype(p):=s; width(p):=w; new_math:=p; +end; +@z + +@x +@p function new_param_glue(@!n:small_number):pointer; +var p:pointer; {the new node} +@!q:pointer; {the glue specification} +begin p:=get_node(small_node_size); type(p):=glue_node; subtype(p):=n+1; +@y +@p function new_param_glue(@!n:small_number):pointer; +var p:pointer; {the new node} +@!q:pointer; {the glue specification} +begin p:=get_node(medium_node_size); type(p):=glue_node; subtype(p):=n+1; + {{\sl synctex} watch point: proper size} +@z + + +@x +@p function new_glue(@!q:pointer):pointer; +var p:pointer; {the new node} +begin p:=get_node(small_node_size); type(p):=glue_node; subtype(p):=normal; +@y +@p function new_glue(@!q:pointer):pointer; +var p:pointer; {the new node} +begin p:=get_node(medium_node_size); type(p):=glue_node; subtype(p):=normal; + {{\sl synctex} watch point: proper size} +@z + + +@x +@p function new_kern(@!w:scaled):pointer; +var p:pointer; {the new node} +begin p:=get_node(small_node_size); type(p):=kern_node; +@y +@p function new_kern(@!w:scaled):pointer; +var p:pointer; {the new node} +begin p:=get_node(medium_node_size); type(p):=kern_node; + {{\sl synctex} whatch point: proper |kern_node| size} +@z + + +@x + glue_node: begin fast_delete_glue_ref(glue_ptr(p)); + if leader_ptr(p)<>null then flush_node_list(leader_ptr(p)); + end; + kern_node,math_node,penalty_node: do_nothing; +@y + glue_node: begin fast_delete_glue_ref(glue_ptr(p)); + if leader_ptr(p)<>null then flush_node_list(leader_ptr(p)); + free_node(p, medium_node_size); {{\sl synctex} watch point: proper size} + goto done; + end; + kern_node,math_node:begin + free_node(p, medium_node_size); {{\sl synctex} watch point: proper size} + goto done; + end; + penalty_node: do_nothing; +@z + + +@x +@ @<Case statement to copy...@>= +case type(p) of +hlist_node,vlist_node,unset_node: begin r:=get_node(box_node_size); +@y +@ @<Case statement to copy...@>= +case type(p) of +hlist_node,vlist_node,unset_node: begin r:=get_node(box_node_size); + @<Copy the box {\sl synctex} information@>; +@z + + +@x +glue_node: begin r:=get_node(small_node_size); add_glue_ref(glue_ptr(p)); + glue_ptr(r):=glue_ptr(p); leader_ptr(r):=copy_node_list(leader_ptr(p)); + end; +kern_node,math_node,penalty_node: begin r:=get_node(small_node_size); + words:=small_node_size; + end; +@y +glue_node: begin r:=get_node(medium_node_size); add_glue_ref(glue_ptr(p)); + {{\sl synctex} node size watch point: proper size} + @<Copy the glue {\sl synctex} information@>; + glue_ptr(r):=glue_ptr(p); leader_ptr(r):=copy_node_list(leader_ptr(p)); + end; +kern_node,math_node: +begin + words:=medium_node_size; + {{\sl synctex}: proper size, do not copy the {\sl synctex} information} + r:=get_node(words); +end; +penalty_node: begin r:=get_node(small_node_size); + words:=small_node_size; + end; +@z + +next change is etex based +@x +@d etex_int_pars=eTeX_state_code+eTeX_states {total number of \eTeX's integer parameters} +@# +@d int_pars=etex_int_pars {total number of integer parameters} +@y +@d etex_int_pars=eTeX_state_code+eTeX_states {total number of \eTeX's integer parameters} +@# +@d synctex_code=etex_int_pars {{\sl synctex}: for the \.{\\synctex} macro} +@d synctex_int_pars=synctex_code+1 {total number of \TeX's integer parameters} +@# +@d int_pars=synctex_int_pars {total number of integer parameters} +@z + +next change is etex based +@x +@d tracing_assigns==int_par(tracing_assigns_code) +@y +@d synctex == int_par(synctex_code) +@# +@d tracing_assigns==int_par(tracing_assigns_code) +@z + +next change is etex based +@x +@/@<Cases for |print_param|@>@/ +othercases print("[unknown integer parameter!]") +endcases; +@y +@/@<synctex case for |print_param|@>@/ +@/@<Cases for |print_param|@>@/ +othercases print("[unknown integer parameter!]") +endcases; +@z + +@x +@!in_state_record = record + @!state_field, @!index_field: quarterword; + @!start_field,@!loc_field, @!limit_field, @!name_field: halfword; + end; +@y +@!in_state_record = record + @!state_field, @!index_field: quarterword; + @!start_field,@!loc_field, @!limit_field, @!name_field: halfword; + @!synctex_tag_field: integer; {stack the tag of the current file} + end; +@z + +@x +@d name==cur_input.name_field {name of the current file} +@y +@d name==cur_input.name_field {name of the current file} +@d synctex_tag==cur_input.synctex_tag_field {{\sl synctex} tag of the current file} +@z + + +@x +name:=0; {|terminal_input| is now |true|} +end; +@y +name:=0; {|terminal_input| is now |true|} +@<Prepare terminal input {\sl synctex} information@>; +end; +@z + + +@x +@<Read the first line of the new file@>; +end; +@y +@<Prepare new file {\sl synctex} information@>; +@<Read the first line of the new file@>; +end; +@z + +next change is etex based +@x +@<Initialize |hlist_out| for mixed direction typesetting@>; +left_edge:=cur_h; +while p<>null do @<Output node |p| for |hlist_out| and move to the next node, + maintaining the condition |cur_v=base_line|@>; +@<Finish |hlist_out| for mixed direction typesetting@>; +@y +@<Initialize |hlist_out| for mixed direction typesetting@>; +left_edge:=cur_h; +@<Start hlist {\sl synctex} information record@>; +while p<>null do @<Output node |p| for |hlist_out| and move to the next node, + maintaining the condition |cur_v=base_line|@>; +@<Finish hlist {\sl synctex} information record@>; +@<Finish |hlist_out| for mixed direction typesetting@>; +@z + +@x +whatsit_node: @<Output the whatsit node |p| in an hlist@>; +glue_node: @<Move right or output leaders@>; +@y +whatsit_node: @<Output the whatsit node |p| in an hlist@>; +glue_node: begin + @<Record |glue_node| {\sl synctex} information@> + @<Move right or output leaders@>; +end; +@z + +next change is etex based +@x +kern_node:cur_h:=cur_h+width(p); +math_node: @<Handle a math node in |hlist_out|@>; +@y +kern_node: begin + @<Record |kern_node| {\sl synctex} information@>; + cur_h:=cur_h+width(p); +end; +math_node: begin + @<Record |math_node| {\sl synctex} information@>; + @<Handle a math node in |hlist_out|@>; +end; +@z + +@x +@!old_setting:0..max_selector; {saved |selector| setting} +begin if tracing_output>0 then + begin print_nl(""); print_ln; + print("Completed box being shipped out"); +@.Completed box...@> +@y +@!old_setting:0..max_selector; {saved |selector| setting} +begin +@<Record sheet {\sl synctex} information@> +if tracing_output>0 then + begin print_nl(""); print_ln; + print("Completed box being shipped out"); +@.Completed box...@> +@z + +@x + if r<>null then if link(r)=null then if not is_char_node(r) then + if type(r)=kern_node then {unneeded italic correction} + begin free_node(r,small_node_size); link(q):=null; + end; + end +@y + if r<>null then if link(r)=null then if not is_char_node(r) then + if type(r)=kern_node then {unneeded italic correction} + begin free_node(r,medium_node_size); link(q):=null; {{\sl synctex}: r is a |kern_node|} + end; + end +@z + + +@x + p:=lig_stack; lig_stack:=link(p); free_node(p,small_node_size); +@y + p:=lig_stack; lig_stack:=link(p); + free_node(p,small_node_size); {{\sl synctex} node size watch point: proper size!} +@z + +@x +if w<>0 then + begin link(t):=new_kern(w); t:=link(t); w:=0; + end; +@y +if w<>0 then + begin link(t):=new_kern(w); t:=link(t); w:=0; + MISSING IMPLEMENTATION: 0 synctag for medium sized node at mem[t] + end; +@z + +@x +@<Initialize the special list...@>= +type(page_head):=glue_node; subtype(page_head):=normal; +@y +@<Initialize the special list...@>= +type(page_head):=glue_node; subtype(page_head):=normal; + {{\sl synctex} watch point: box(|page_head|) size >= |glue_node| size} +@z + +@x +@<Move the cursor past a pseudo-ligature...@>= +main_p:=lig_ptr(lig_stack); +if main_p>null then tail_append(main_p); +temp_ptr:=lig_stack; lig_stack:=link(temp_ptr); +free_node(temp_ptr,small_node_size); +@y +@<Move the cursor past a pseudo-ligature...@>= +main_p:=lig_ptr(lig_stack); +if main_p>null then tail_append(main_p); +temp_ptr:=lig_stack; lig_stack:=link(temp_ptr); +free_node(temp_ptr,small_node_size); {{\sl synctex} node size watch point: proper size!} +@z + +next change is etex based +@x + if subtype(p)<a_leaders then + begin type(p):=kern_node; width(p):=rule_wd; + end +@y + if subtype(p)<a_leaders then + begin type(p):=kern_node; width(p):=rule_wd; + {{\sl synctex} node size watch point: |glue_node| size == |kern_node| size} + end +@z + +next change is etex based +@x + if (type(tail)=math_node)and(subtype(tail)=begin_M_code) then + begin free_node(LR_temp,small_node_size); p:=head; + while link(p)<>tail do p:=link(p); + free_node(tail,small_node_size); link(p):=null; tail:=p; goto done; + end; +@y + if (type(tail)=math_node)and(subtype(tail)=begin_M_code) then + begin free_node(LR_temp,small_node_size); p:=head; + while link(p)<>tail do p:=link(p); + free_node(tail,medium_node_size); link(p):=null; tail:=p; goto done; + {{\sl synctex} node size watch point: proper size for |math_node|} + end; +@z + +next change is etex based +@x +@ @<Adjust \(t)the LR stack for the |hp...@>= +if end_LR(p) then + if info(LR_ptr)=end_LR_type(p) then pop_LR + else begin incr(LR_problems); type(p):=kern_node; subtype(p):=explicit; + end +else push_LR(p) +@y +@ @<Adjust \(t)the LR stack for the |hp...@>= +if end_LR(p) then + if info(LR_ptr)=end_LR_type(p) then pop_LR + else begin incr(LR_problems); type(p):=kern_node; subtype(p):=explicit; + {{\sl synctex} node size watch point: |math_node| size == |kern_node| size} + end +else push_LR(p) +@z + +next change is etex based +@x + if LR_dir(p)<>cur_dir then + @<Reverse an hlist segment and |goto reswitch|@>; + end; +type(p):=kern_node; +end +@y + if LR_dir(p)<>cur_dir then + @<Reverse an hlist segment and |goto reswitch|@>; + end; +type(p):=kern_node; + {{\sl synctex} node size watch point: |math_node| size == |kern_node| size} +end +@z + +next change is etex based +@x +@<Reverse the complete hlist...@>= +begin save_h:=cur_h; temp_ptr:=p; p:=new_kern(0); link(prev_p):=p; +@y +@<Reverse the complete hlist...@>= +begin save_h:=cur_h; temp_ptr:=p; p:=new_kern(0); +MISSING IMPLEMENTATION: 0 synctag for medium sized node at mem[p] +link(prev_p):=p; +@z + +next change is etex based +@x +@<Reverse an hlist segment...@>= +begin save_h:=cur_h; temp_ptr:=link(p); rule_wd:=width(p); +free_node(p,small_node_size); +@y +@<Reverse an hlist segment...@>= +begin save_h:=cur_h; temp_ptr:=link(p); rule_wd:=width(p); +free_node(p,medium_node_size); {{\sl synctex}: p is a |math_node|} +@z + +next change is etex based +@x +if type(p)=kern_node then if (rule_wd=0)or(l=null) then + begin free_node(p,small_node_size); p:=l; + end; +@y +if type(p)=kern_node then if (rule_wd=0)or(l=null) then + begin free_node(p,medium_node_size); p:=l; + {{\sl synctex} node size watch: proper size for |kern_node|} + end; +@z + +next change is etex based +@x +math_node: begin rule_wd:=width(p); +if end_LR(p) then + if info(LR_ptr)<>end_LR_type(p) then + begin type(p):=kern_node; incr(LR_problems); + end + else begin pop_LR; + if n>min_halfword then + begin decr(n); decr(subtype(p)); {change |after| into |before|} + end + else begin type(p):=kern_node; + if m>min_halfword then decr(m) + else @<Finish the reversed hlist segment and |goto done|@>; + end; +@y +math_node: begin rule_wd:=width(p); +if end_LR(p) then + if info(LR_ptr)<>end_LR_type(p) then + begin type(p):=kern_node; incr(LR_problems); + {{\sl synctex} node size watch point: |math_node| size == |kern_node| size} + end + else begin pop_LR; + if n>min_halfword then + begin decr(n); decr(subtype(p)); {change |after| into |before|} + end + else begin type(p):=kern_node; + {{\sl synctex} node size watch point: |math_node| size == |kern_node| size} + if m>min_halfword then decr(m) + else @<Finish the reversed hlist segment and |goto done|@>; + end; +@z + +next change is etex based +@x + if (n>min_halfword)or(LR_dir(p)<>cur_dir) then + begin incr(n); incr(subtype(p)); {change |before| into |after|} + end + else begin type(p):=kern_node; incr(m); + end; + end; +end; +@y + if (n>min_halfword)or(LR_dir(p)<>cur_dir) then + begin incr(n); incr(subtype(p)); {change |before| into |after|} + end + else begin type(p):=kern_node; incr(m); + {{\sl synctex} node size watch point: |math_node| size == |kern_node| size} + end; + end; +end; +@z + + +next change is etex based +@x +@<Finish the reversed...@>= +begin free_node(p,small_node_size); +link(t):=q; width(t):=rule_wd; edge_dist(t):=-cur_h-rule_wd; goto done; +end +@y +@<Finish the reversed...@>= +begin free_node(p,medium_node_size); {{\sl synctex}: p is a |kern_node|} +link(t):=q; width(t):=rule_wd; edge_dist(t):=-cur_h-rule_wd; goto done; +end +@z + +next change is etex based +@x + if is_char_node(p) then r:=get_avail + else case type(p) of + hlist_node,vlist_node: begin r:=get_node(box_node_size); + mem[r+6]:=mem[p+6]; mem[r+5]:=mem[p+5]; {copy the last two words} + words:=5; list_ptr(r):=null; {this affects |mem[r+5]|} + end; +@y + if is_char_node(p) then r:=get_avail + else case type(p) of + hlist_node,vlist_node: begin r:=get_node(box_node_size); + @<Copy the box {\sl synctex} information@>; + mem[r+6]:=mem[p+6]; mem[r+5]:=mem[p+5]; {copy the last two words} + words:=5; list_ptr(r):=null; {this affects |mem[r+5]|} + end; +@z + +next change is etex based +@x + kern_node,math_node: begin r:=get_node(small_node_size); + words:=small_node_size; + end; + glue_node: begin r:=get_node(small_node_size); add_glue_ref(glue_ptr(p)); + glue_ptr(r):=glue_ptr(p); leader_ptr(r):=null; + end; +@y + kern_node,math_node: begin + words:=medium_node_size; {{\sl synctex}: proper size for math and kern} + r:=get_node(words); + end; + glue_node: begin r:=get_node(medium_node_size); add_glue_ref(glue_ptr(p)); + {{\sl synctex}: proper size for glue} + @<Copy the glue {\sl synctex} information@>; + glue_ptr(r):=glue_ptr(p); leader_ptr(r):=null; + end; +@z + +next change is etex based +@x +found:width(t):=width(p); link(t):=q; free_node(p,small_node_size); +done:link(temp_head):=l; +end; + +@ @<Adjust \(t)the LR stack for the |j...@>= +if end_LR(p) then + if info(LR_ptr)<>end_LR_type(p) then + begin type(p):=kern_node; incr(LR_problems); + end + else begin pop_LR; + if n>min_halfword then + begin decr(n); decr(subtype(p)); {change |after| into |before|} + end + else begin if m>min_halfword then decr(m)@+else goto found; + type(p):=kern_node; + end; + end +else begin push_LR(p); + if (n>min_halfword)or(LR_dir(p)<>cur_dir) then + begin incr(n); incr(subtype(p)); {change |before| into |after|} + end + else begin type(p):=kern_node; incr(m); + end; + end +@y +found:width(t):=width(p); link(t):=q; free_node(p,small_node_size); + {{\sl synctex}: Unused label, see below} +done:link(temp_head):=l; +end; + +@ @<Adjust \(t)the LR stack for the |j...@>= +if end_LR(p) then + if info(LR_ptr)<>end_LR_type(p) then + begin type(p):=kern_node; incr(LR_problems); + {{\sl synctex} node size watch point: |math_node| size == |kern_node| size} + end + else begin pop_LR; + if n>min_halfword then + begin decr(n); decr(subtype(p)); {change |after| into |before|} + end + else begin if m>min_halfword then decr(m)@+else begin + width(t):=width(p); link(t):=q; free_node(p,medium_node_size); + {{\sl synctex}: no more "goto found", and proper node size} + goto done; + end; + type(p):=kern_node; + {{\sl synctex} node size watch point: |math_node| size == |kern_node| size} + end; + end +else begin push_LR(p); + if (n>min_halfword)or(LR_dir(p)<>cur_dir) then + begin incr(n); incr(subtype(p)); {change |before| into |after|} + end + else begin type(p):=kern_node; incr(m); + {{\sl synctex} node size watch point: |math_node| size == |kern_node| size} + end; + end +@z + +next change is etex based +@x +if tracing_scan_tokens>0 then + begin if term_offset>max_print_line-3 then print_ln + else if (term_offset>0)or(file_offset>0) then print_char(" "); + name:=19; print("( "); incr(open_parens); update_terminal; + end +else name:=18 +@y +if tracing_scan_tokens>0 then + begin if term_offset>max_print_line-3 then print_ln + else if (term_offset>0)or(file_offset>0) then print_char(" "); + name:=19; print("( "); incr(open_parens); update_terminal; + end +else begin + name:=18; + @<Prepare pseudo file {\sl synctex} information@>; +end +@z + +@x +@* \[54] System-dependent changes. +This section should be replaced, if necessary, by any special +modifications of the program +@y +@* \[53b] The {\sl synchronize texnology}. +This section is devoted to the {\sl synchronize texnology} +- or simply {\sl synctex} - used to synchronize between input and output. +This section explains how synchronization basics are implemented. +Before we enter into more technical details, +let us recall in a few words what is synchronization. + +\TeX\ typesetting system clearly separates the input and the output material, +and synchronization will provide a new link between both that can help +text editors and viewers to work together. +More precisely, forwards synchronization is the ability, +given a location in the input source file, +to find what is the corresponding place in the output. +Backwards synchronization just performs the opposite: +given a location in the output, +retrieve the corresponding material in the input source file. + +For better code management and maintainance, we adopt a naming convention. +Throughout this program, code related to the {\sl synchronize texnology} is tagged +with the {\sl synctex} key word. Any code extract where {\sl synctex} plays +its part, either explicitly or implicitly, (should) contain the string {\sl synctex}. +This naming convention also holds for external files. +Moreover, all the code related to {\sl synctex} is gathered in this section, +except the definitions. + +Synchronization is achieved with the help of an auxiliary file named +`\.{{\sl jobname}.synctex}' ({\sl jobname} is the contents of the +\.{\\jobname} macro), where a {\sl synctex} controller implemented +in the external |synctex.c| file will store geometrical information. +This {\sl synctex} controller will take care of every technical details +concerning the {\sl synctex} file, we will only focus on the messages +the controller will receive from the \TeX\ program. + +The most accurate synchronization information should allow to map +any character of the input source file to the corresponding location +in the output, if relevant. +Ideally, the synchronization information of the input material consists of +the file name, the line and column numbers of every character. +The synchronization information in the output is simply the page number and +either point coordinates, or box dimensions and position. +The problem is that the mapping between these informations is only known at +ship out time, which means that we must keep track of the input +synchronization information until the pages ship out. + +As \TeX\ only knows about file names and line numbers, +but forgets the column numbers, we only consider a +restricted input synchronization information called {\sl synctex information}. +It consists of a unique file name identifier, the {\sl synctex file tag}, +and the line number. + +Keeping track of such information, +should be different whether characters or nodes are involved. +Actually, only certain nodes are involved in {\sl synctex}, +we call them {\sl synchronized nodes}. +Synchronized nodes store the {\sl synctex} information in their last two words: +the first one contains a {\sl synctex file tag} uniquely identifying +the input file, and the second one contains the current line number, +as returned by the \.{\\inputlineno} primitive. +The |synctex_field_size| macro contains the necessary size to store +the {\sl synctex} information in a node. + +When declaring the size of a new node, it is recommanded to use the following +convention: if the node is synchronized, use a definition similar to +|my_synchronized_node_size|={\sl xxx}+|synctex_field_size|. +Moreover, one should expect that the {\sl synctex} information is always stored +in the last two words of a synchronized node. + +@ By default, every node with a sufficiently big size is initialized +at creation time in the |get_node| routine with the current +{\sl synctex} information, whether or not the node is synchronized. +One purpose is to set this information very early in order to minimize code +dependencies, including forthcoming extensions. +Another purpose is to avoid the assumption that every node type has a dedicated getter, +where initialization should take place. Actually, it appears that some nodes are created +using directly the |get_node| routine and not the dedicated constructor. +And finally, initializing the node at only one place is less error prone. + +@ @<Initialize bigger nodes with {\sl synctex} information@>= +if s>=medium_node_size then +begin + MISSING IMPLEMENTATION: update the synctex information for node at mem[r] with size s +end; + +@ Instead of storing the input file name, it is better to store just an identifier. +Each time \TeX\ opens a new file, it notifies the {\sl synctex} controller with +a |synctex_start_input| message. +This controller will create a new {\sl synctex} file tag and +will update the current input state record accordingly. +If the input comes from the terminal or a pseudo file, the |synctex_tag| is set to 0. +It results in automatically disabling synchronization for material +input from the terminal or pseudo files. + +@ @<Prepare new file {\sl synctex} information@>= +synctex_start_input; {Give control to the {\sl synctex} controller} + +@ @<Prepare terminal input {\sl synctex} information@>= +synctex_tag:=0; + +@ @<Prepare pseudo file {\sl synctex} information@>= +synctex_tag:=0; + +@ Synchronized nodes are boxes, math, kern and glue nodes. +Other nodes should be synchronized too, in particular math noads. +\TeX\ assumes that math, kern and glue nodes have the same size, +this is why both are synchronized. +{\sl In fine}, only horizontal lists are really used in {\sl synctex}, +but all box nodes are considered the same with respect to synchronization, +because a box node type is allowed to change at execution time. + +The next sections are the various messages sent to the {\sl synctex} controller. +The argument is either the box or the node currently shipped out. + +@ @<Start hlist {\sl synctex} information record@>= +synctex_hlist(this_box); + +@ @<Finish hlist {\sl synctex} information record@>= +synctex_tsilh(this_box); + +@ @<Record |glue_node| {\sl synctex} information@>= +synctex_glue(p); + +@ @<Record |kern_node| {\sl synctex} information@>= +synctex_kern(p); + +@ @<Record |math_node| {\sl synctex} information@>= +synctex_math(p); + +@ @<Record sheet {\sl synctex} information@>= +synctex_sheet(mag); + +@ When making a copy of a synchronized node, we might also have to duplicate +the {\sl synctex} information by copying the two last words. +This is the case for a |box_node| and for a |glue_node|, +but not for a |math_node| nor a |kern_node|. These last two nodes always keep +the {\sl synctex} information they received at creation time. + +@ @<Copy the box {\sl synctex} information@>= +MISSING IMPLEMENTATION: copy the synctex information for box node at mem[r] from node at mem[p] + +@ @<Copy the glue {\sl synctex} information@>= +MISSING IMPLEMENTATION: copy the synctex information for glue node at mem[r] from node at mem[p] + +@ Enabling synchronization should be performed from the command line, +|synctexoption| is used for that purpose. +This global integer variable is declared here but it is not used here. +This is just a placeholder where the command line controller will put +the {\sl {\sl synctex}} related options, and the {\sl synctex} controller will read them. + +@ @<Glob...@>= +@!synctexoption:integer; + +@ A convenient primitive is provided: +\.{\\synctex=1} in the input source file enables synchronization whereas +\.{\\synctex=0} disables it. +Its memory address is |synctex_code|. + +@ @<Put each...@>= +primitive("synctex",assign_int,int_base+synctex_code);@/ +@!@:synctex_}{\.{\\synctex} primitive@> + +@ @<synctex case for |print_param|@>= +synctex_code: print_esc("synctex"); + +@ In order to give the {\sl synctex} controller read and write access to +the contents of the \.{\\synctex} primitive, we declare |synctexoffset|, +such that |mem[synctexoffset]| and \.{\\synctex} correpond to +the same memory storage. |synctexoffset| is initialized to +the correct value when quite everything is initialized. + +@ @<Glob...@>= +@!synctexoffset:integer; {holds the true value of |synctex_code|} + +@ @<Initialize whatever...@>= +synctexoffset:=int_base+synctex_code; + +@ {\sl Nota Bene:} +The {\sl synctex} code is very close to the memory model. +It is not connected to any other part of the code, +except for memory management. It is possible to neutralize the {\sl synctex} code +rather simply. The first step is to define a null |synctex_field_size|. +The second step is to comment out the code in ``Initialize bigger nodes...'' and every +``Copy ... {\sl synctex} information''. +The last step will be to comment out the |synctex_tag_field| related code in the +definition of |synctex_tag| and the various ``Prepare ... {\sl synctex} information''. +Then all the remaining code should be just harmless. +The resulting program would behave exactly the same as if absolutely no {\sl synctex} +related code was there, including memory management. +Of course, all this assumes that {\sl synctex} is turned off from the command line. +@^synctex@> +@^synchronization@> + +@* \[54] System-dependent changes. +This section should be replaced, if necessary, by any special +modifications of the program +@z diff --git a/Build/source/texk/web2c/synctex/synctex.defines b/Build/source/texk/web2c/synctex/synctex.defines new file mode 100644 index 00000000000..357c77f5e8a --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex.defines @@ -0,0 +1,49 @@ +{ +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. + +Notice: +------- +This file is an interface to the synctex system for web2c. +} + +{ functions from the synctex controller in synctex.h } +@define procedure synctexstartinput; +@define procedure synctexsheet(); +@define procedure synctexhlist(); +@define procedure synctextsilh(); +@define procedure synctexmath(); +@define procedure synctexkern(); +@define procedure synctexglue(); + +{ end of synctex.defines } +{ vim: set syntax=web : } diff --git a/Build/source/texk/web2c/synctex/synctex.h b/Build/source/texk/web2c/synctex/synctex.h new file mode 100644 index 00000000000..98fcc29664f --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex.h @@ -0,0 +1,61 @@ +/* synctex.h + +This file is part of the SyncTeX package. + +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 + +*/ + +# ifndef __SYNCTEX_HEADER__ +# define __SYNCTEX_HEADER__ + +/* Send this message when starting a new input. */ +extern void synctexstartinput(void); + +/* Recording the "s:..." line. In *tex.web, use synctex_sheet(pdf_output) at + * the very beginning of the ship_out procedure. +*/ +extern void synctexsheet(integer pdf_output); + +/* Send this message when an hlist will be shipped out, more precisely at + * the beginning of the hlist_out procedure in *TeX.web. It must be balanced + * by a synctex_tsilh, sent at the end of the hlist_out procedure. p is the + * address of the hlist. */ +extern void synctexhlist(halfword p); + +/* Sent this message at the end of the hlist_out procedure in *TeX.web + * to balance a former synctex_hlist. */ +extern void synctextsilh(halfword p); + +/* Send this message whenever an inline math node will ship out. */ +extern void synctexmath(halfword p); + +/* Send this message whenever a glue node will ship out. */ +extern void synctexglue(halfword p); + +/* Send this message whenever a kern node will ship out. */ +extern void synctexkern(halfword p); + +/* Send this message to clean memory. */ +extern void synctex_terminate(void); + +# endif
\ No newline at end of file diff --git a/Build/source/texk/web2c/synctex/synctex.mk b/Build/source/texk/web2c/synctex/synctex.mk new file mode 100644 index 00000000000..5d77fddd5f3 --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex.mk @@ -0,0 +1,50 @@ +# 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. +# +# Notice: +# ------- +# Makefile fragment for synctex. +# It is included in web2c/Makefile.in + +# The C sources and headers +synctex_o = synctex.o +synctex.h: $(top_srcdir)/synctex/synctex.h + cat $(top_srcdir)/synctex/synctex.h >$@ +synctex.c: synctex.h $(top_srcdir)/synctex/synctex.c + cat $(top_srcdir)/synctex/synctex.c >$@ + +# Cleaning up. +clean:: synctex-clean +synctex-clean: + -rm synctex.o synctex.h synctex.c + +# end of synctex.mk |