diff options
author | Jonathan Kew <jfkthame@googlemail.com> | 2008-04-25 14:48:35 +0000 |
---|---|---|
committer | Jonathan Kew <jfkthame@googlemail.com> | 2008-04-25 14:48:35 +0000 |
commit | 12ed7b16e1915c6d5c3453f1bce9b4802de10882 (patch) | |
tree | 073ce924de3ed0c18b7656f8009d41dfa961fb85 /Build/source/texk/web2c/synctex | |
parent | 6ad0c2572b39216cefd820842002f54e65f96ce7 (diff) |
XeTeX update (from svn r.655), incl new SyncTeX
git-svn-id: svn://tug.org/texlive/trunk@7643 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/synctex')
31 files changed, 7469 insertions, 1244 deletions
diff --git a/Build/source/texk/web2c/synctex/INSTALL b/Build/source/texk/web2c/synctex/INSTALL new file mode 100644 index 00000000000..f7456ac1b02 --- /dev/null +++ b/Build/source/texk/web2c/synctex/INSTALL @@ -0,0 +1,96 @@ +# 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. +# + +How to INSTALL synctex support in web2c. + +First you need a recent convert tool (as of march 2008) + +Modify your .mk file to mimic what was done for pdftex + +In synctex.mk +------------- +### SyncTeX support in pdftex +# list of change files +synctex-pdftex_ch_srcs_mem_only = \ + $(synctex_dir)/synctex-mem.ch0 \ + $(synctex_dir)/synctex-mem.ch1 \ + $(synctex_dir)/synctex-e-mem.ch0 \ + $(synctex_dir)/synctex-e-mem.ch1 +synctex-pdftex_ch_srcs_on = \ + $(synctex-pdftex_ch_srcs_mem_only) \ + $(synctex_dir)/synctex-rec.ch0 \ + $(synctex_dir)/synctex-rec.ch1 \ + $(synctex_dir)/synctex-e-rec.ch0 \ + $(synctex_dir)/synctex-e-rec.ch1 \ + $(synctex_dir)/synctex-pdf-rec.ch2 +synctex-pdftex_ch_srcs_off = +# The C sources and headers +synctex-pdftex_o = synctex-pdf.o +synctex-pdf.h: $(synctex_dir)/synctex.h + cat $(synctex_dir)/synctex.h >$@ +synctex-pdftex.h: $(synctex_dir)/$@ + cat $(synctex_dir)/$@ >$@ +synctex-pdf.c: pdftexd.h $(synctex_dir)/synctex.c synctex-pdftex.h + sed s/TEX-OR-MF-OR-MP/pdftex/ $(synctex_dir)/synctex.c >$@ +synctex_pdftexd_on = \ + if test -z "`grep __SyncTeX__ pdftexd.h`";\ + then\ + $(synctex_all_texd);\ + sed -f synctex_sed_command.txt pdftexd.h > synctex_pdftexd.h;\ + mv synctex_pdftexd.h pdftexd.h;\ + rm -f synctex_sed_command.txt;\ + fi +synctex_pdftexd_off = +# switchers: _on to enable full synctex support, _off to completely disable synctex, _mem_only to only implement memory management. +synctex-pdftex_ch_srcs = $(synctex-pdftex_ch_srcs_on) +# _on to enable -synctex command line option, _off to disable +synctex_pdftexd = $(synctex_pdftexd_on) + +In pdftex.mk +------------ +# The C sources. +pdftex_c = pdftexini.c pdftex0.c pdftex1.c pdftex2.c pdftex3.c +pdftex_o = pdftexini.o pdftex0.o pdftex1.o pdftex2.o pdftex3.o pdftexextra.o loadpdftexpool.o $(synctex-pdftex_o) + +# C file dependencies. +$(pdftex_c) pdftexcoerce.h pdftexd.h: pdftex.p $(web2c_texmf) $(srcdir)/$(pdftexdir)/pdftex.defines $(srcdir)/$(pdftexdir)/pdftex.h + $(web2c) pdftex + $(synctex_pdftexd) + +# Sources for pdftex.ch: +pdftex_ch_srcs = $(srcdir)/$(pdftexdir)/pdftex.web \ + $(srcdir)/$(pdftexdir)/tex.ch0 \ + $(srcdir)/tex.ch \ + $(synctex-pdftex_ch_srcs) \ + $(srcdir)/$(pdftexdir)/pdftex.ch + diff --git a/Build/source/texk/web2c/synctex/Makefile b/Build/source/texk/web2c/synctex/Makefile new file mode 100644 index 00000000000..3b692b99f42 --- /dev/null +++ b/Build/source/texk/web2c/synctex/Makefile @@ -0,0 +1,174 @@ +# 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: +# ------- +# make some tests + +srcdir = .. + +prepare: + if ! test -d tests;\ + then\ + mkdir -p tests;\ + fi + +tests: prepare + cd tests;\ + make all +force: + +clean: + rm -Rf tests + +tests_dir: + -mkdir -p tests + +texch1:prepare + tie -m tests/tex1.web ../tex.web ../tex.ch + +texch2:texch1 + tie -m tests/tex2.web tests/tex1.web ../synctex/synctex.ch0 + +texch3:texch2 + tie -m tests/tex3.web tests/tex2.web ../synctex/synctex.ch1 + +texch: texch3 + +etexch01:tests_dir + tie -m tests/etex01.web ../tex.web ../etexdir/tex.ch0 + +etexch02:etexch01 + tie -m tests/etex02.web tests/etex01.web ../tex.ch + +etexch03:etexch02 + tie -m tests/etex03.web tests/etex02.web ../etexdir/tex.ch1 + +etexch04:etexch03 + tie -m tests/etex04.web tests/etex03.web ../etexdir/tex.ech + +etexch05:etexch04 + tie -m tests/etex05.web tests/etex04.web ../synctex/synctex.ch0 + +etexch06:etexch05 + tie -m tests/etex06.web tests/etex05.web ../synctex/synctex.ch1 + +etexch0:etexch06 + +etexch1:tests_dir + tie -m tests/etex1.web ../tex.web ../etexdir/etex.ch + +etexch2:etexch1 + tie -m tests/etex2.web tests/etex1.web ../synctex/synctex.ch0 + +etexch3:etexch2 + tie -m tests/etex3.web tests/etex2.web ../synctex/synctex.ch1 + +etexch4:etexch3 + tie -m tests/etex4.web tests/etex3.web ../synctex/synctex-e.ch0 + +etexch5:etexch4 + tie -m tests/etex5.web tests/etex4.web ../synctex/synctex-e.ch1 + +etexch:etexch5 + echo "DONE" + +etexch-11:tests_dir etex.web + tie -m tests/etex-11.web tests/etex.web ../synctex/synctex.ch0 + +etexch-12:etexch-11 + tie -m tests/etex-12.web tests/etex-11.web ../synctex/synctex.ch1 + +etexch-13:etexch-12 + tie -m tests/etex-13.web tests/etex-12.web ../synctex/synctex-e.ch0 + +etexch-14:etexch-13 + tie -m tests/etex-14.web tests/etex-13.web ../synctex/synctex-e.ch1 + +etexch-1:etexch-14 + echo "DONE" + +# Generation of the web and ch file. +# Sources for etex.web: +etex_web_srcs = $(srcdir)/tex.web \ + $(srcdir)/etexdir/etex.ch \ + $(srcdir)/etexdir/etex.fix +# Sources for etex.ch: +etex_ch_srcs = etex.web \ + $(srcdir)/etexdir/tex.ch0 \ + $(srcdir)/tex.ch \ + $(srcdir)/etexdir/tex.ch1 \ + $(srcdir)/etexdir/tex.ech +# Rules: +etex.web: prepare $(etex_web_srcs) + tie -m tests/etex.web $(etex_web_srcs) +etex.ch: prepare $(etex_ch_srcs) + tie -c tests/etex.ch $(etex_ch_srcs) + +xetex_web_srcs = $(srcdir)/tex.web \ + $(srcdir)/etexdir/etex.ch \ + $(srcdir)/etexdir/tex.ch0 \ + $(srcdir)/tex.ch \ + $(srcdir)/etexdir/tex.ch1 \ + $(srcdir)/etexdir/tex.ech \ + ../synctex/synctex.ch0 \ + ../synctex/synctex-e.ch0 \ + ../synctex/synctex-xetex.ch1 \ + $(srcdir)/xetexdir/xetex.ch + +xetex.web: prepare $(xetex_web_srcs) + tie -m tests/xetex.web $(xetex_web_srcs) + +xetex1: xetex.web + tie -m tests/xetex1.web tests/xetex.web ../synctex/synctex.ch0 + +xetex2:xetex1 + tie -m tests/xetex2.web tests/xetex1.web ../synctex/synctex-e.ch0 + +xetex3:xetex2 + tie -m tests/xetex3.web tests/xetex2.web ../synctex/synctex-xetex.ch1 + +xetex:xetex3 + echo "DONE" + +pdftex1: prepare + pwd + ls + tie -m tests/pdftex-1.web ../pdftexdir/pdftex.web ../pdftexdir/tex.ch0 + +pdftex2: prepare + tie -m tests/pdftex-2.web tests/pdftex-1.web ../tex.ch + +pdftex3: prepare + tie -m tests/pdftex-3.web tests/pdftex-2.web ../pdftexdir/pdftex.ch + +pdftex:pdftex3 diff --git a/Build/source/texk/web2c/synctex/Makefile.in b/Build/source/texk/web2c/synctex/Makefile.in new file mode 100644 index 00000000000..07e94a694ee --- /dev/null +++ b/Build/source/texk/web2c/synctex/Makefile.in @@ -0,0 +1,76 @@ +# 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: +# ------- +# make some tests +# various test for synctex consistency +srcdir=../.. + +# first part: web consistency + +webs_dir: + -mkdir -p webs + +clean::webs_clean + rm -Rf webs + +texch1:webs_dir + tie -m webs/tex1.web ../../tex.web ../../tex.ch + +texch2:texch1 + tie -m webs/tex2.web webs/tex1.web ../../synctex/synctex.ch0 + +texch3:texch2 + tie -m webs/tex3.web webs/tex2.web ../../synctex/synctex.ch1 + +texch: texch3 + +etexch1:webs_dir + tie -m webs/etex1.web ../../tex.web ../../etexdir/tex.ch0 + +etexch2:etexch1 + tie -m webs/etex2.web webs/etex1.web ../../tex.ch + +etexch3:etexch2 + tie -m webs/etex3.web webs/etex2.web ../../etexdir/tex.ch1 + +etexch4:etexch3 + tie -m webs/etex4.web webs/etex3.web ../../etexdir/tex.ech + +etexch5:etexch4 + tie -m webs/etex5.web webs/etex4.web ../../synctex/synctex.ch0 + +etexch6:etexch5 + tie -m webs/etex6.web webs/etex5.web ../../synctex/synctex.ch1 + +etexch:etexch6 diff --git a/Build/source/texk/web2c/synctex/README.txt b/Build/source/texk/web2c/synctex/README.txt new file mode 100644 index 00000000000..a599b6e57fa --- /dev/null +++ b/Build/source/texk/web2c/synctex/README.txt @@ -0,0 +1,163 @@ +# 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. +# + +This file gives the .synctex file specifications. + +SyncTeX output file specifications, Version 2, Lun 31 mar 2008 13:50:31 UTC +=========================================================================== +This is an EBNF file specification extended by ICU regex patterns +(enclosed between 2 '/'s) + +The whole synctex file is made of various records gathered into four different sections: + +<synctex file> ::= <preamble> <contents> <postamble> <post scriptum> + +Each record is a sequence of text characters following an end of record mark or starting the file, +and ending with an end of record mark. +The first characters of a record will determine the type of the record. + +<end of record mark> ::= /\n/ +<end of record> ::= /[^\n]*/<end of record mark> + +The preamble: +------------- + +<preamble> ::= <control record> <input record>* <informations> <forthcoming records> + +<control record> ::= /SyncTeX Version:/<version><end of record mark> +<SyncTeX> ::= +<version> ::= /1/ + +<input record> ::= /Input:/<tag information><end of record mark> +<tag information> ::= <tag>/:/<file name><end of record mark> +<tag> ::= <integer> +<file name> ::= /[^<end of record mark>]*/ +This is used to give a shortcut to filenames. + +<informations> ::= <output record>? <magnification record>? <unit record>? <x offset record>? <y offset record>? + +<output record> ::= /Output:/<output><end of record mark> +<output> ::= /dvi|pdf|xdv|[0-9a-zA-Z]*/ + +<magnification record> ::= /Magnification:/<magnification><end of record> +<magnification> ::= <integer> +This is the TeX magnification. + +<unit record> ::= /Unit:<unit><end of record>/ +<unit> ::= <integer> +The SyncTeX unit is <unit> scaled point, 1 in general, 8192 when not given. + +<x offset record> ::= /X Offset:/<x offset><end of record> +<x offset> ::= <integer> +<y offset record> ::= /Y Offset:/<y offset><end of record> +<y offset> ::= <integer> +The offset or the origin of the system of coordinates from the top left point of the page. +This defaults to 1in for both the vertical and horizontal offsets. +Both offsets are given in this section in scaled point unit. + +<forthcoming records>: The preamble, like any other section may contain in the future any other kind of record, +except the one starting the next section. In order to ensure some forwards compatibility, +parsers should anticipate and parse unknown records: an unexpected record should be silently ignored by the parser. +This means that this format is somehow open an more types of records can be added without breaking existing software. + +The preamble ends when a record is found that fits the following section. + +The contents: +------------- +<contents> ::= <contents record><sheet(1)><i line>*<sheet(2)><i line>*...<sheet(N)><i line>* + +<contents record>::=/Contents:/<byte offset><end of record>/ +<offset> ::= <byte offset> +<sheet(n)> ::= <sheet(n) start><v content>*<sheet end> +<sheet(n) start> ::= /{/<byte offset>/:/<the integer n><end of record>/ +<sheet end> ::= /}/<byte offset><end of record> + +<box content> ::= <vbox section>|<hbox section>|<void vbox record>|<void hbox record> +<vbox section> ::= (<vbox start record><vbox content>*<vbox stop record>)|<box content>* +<hbox content> ::= <glue record>|<kern record>|<math record>|<box content> +<hbox section> ::= <hbox start record><box content>*<hbox stop record> + +<void vbox record> ::= /v/<link>/:/<point>/:/<size><end of record> +<void hbox record> ::= /h/<link>/:/<point>/:/<size><end of record> +<size> ::= <W>/,/<H>/,/<D> +<W> ::= <integer> +<H> ::= <integer> +<D> ::= <integer> +<link> ::= <tag>/,/<line>(/,/<column>)? +<line> ::= <integer> +<column> ::= <integer> + +<current record> ::= /x/<link>/:/<point><end of record> +<kern record> ::= /k/<link>/:/<point>/:/<W><end of record> +<glue record> ::= /g/<link>/:/<point><end of record> +<math record> ::= /$/<link>/:/<point><end of record> + +The byte offset is an implicit anchor to navigate the synctex file from sheet to sheet. + +The postamble: +-------------- +The postamble closes the file +If there is no postamble, it means that the typesetting process did not end correctly. +<postamble> ::= <postamble record><number of objects record> + +<postamble record> ::= /Postamble:/<byte offset><end of record> +<number of objects record> ::= /Count:/<integer><end of record> + +The post scriptum: +------------------ +The post scriptum contains material possibly added by 3rd parties. +It allows to append some transformation (shift and magnify). +Typically, one applies a dvi to pdf filter with offset options and magnification, +then he appends the same options to the synctex file, for example + + dvipdfmx -m 0.486 -x 9472573sp -y 13.3dd source.dvi + echo "X Offset:9472573" >> source.synctex + echo "Y Offset:13.3dd" >> source.synctex + echo "Magnification:0.486" >> source.synctex + + +<post scriptum> ::= (<magnification line>|<x offset line>|<y offset line>)* +<magnification line> ::= /Magnification:/<post magnification><end of line mark> +<post magnification> ::= <unsigned decimal float> +<x offset line> ::= /X Offset:/<post x offset><end of line mark> +<post x offset> ::= <sign><unsigned decimal float><offset unit> +<y offset> ::= <x offset> +<sign> ::= /(+|-)?/ +<offset unit> ::= /(in|cm|mm|pt|bp|pc|sp|dd|cc|nd|nc)?/ +<end of line mark> ::= /[\n\r]*/ +<y offset line> ::= /Y Offset:/<post y offset><end of line mark> +<post y offset> ::= <sign><unsigned decimal float><offset unit> + +This second information will override the offset and magnification previously available in the preamble section. +All the numbers are encoded using the decimal representation with "C" locale. + diff --git a/Build/source/texk/web2c/synctex/man1/synctex.1 b/Build/source/texk/web2c/synctex/man1/synctex.1 new file mode 100644 index 00000000000..57a9a432f16 --- /dev/null +++ b/Build/source/texk/web2c/synctex/man1/synctex.1 @@ -0,0 +1,27 @@ +.Dd 27/03/08 \" DATE +.Dt synctex 1 \" Program name and manual section number +.Th synctex 1 +.Sh NAME +.Nm synctex +.Nd command line client tool to support the Synchronize TeXnology available in recent TeX engines. +.Sh SYNOPSIS +.TP +.Nm +\fIcommand\fP [\fIoptions\fP] [\fIargs\fP] +.Sh OVERVIEW +The Synchronization TeXnology is a new feature of recent TeX engines. +It allows to synchronize between input and output, +which means to navigate from the source document to the typeset material +and vice versa. +.Pp +Run `synctex help' to access the built-in tool documentation. +.Sh SEE ALSO +.\" List links in ascending order by section, alphabetically within a section. +.\" Please do not reference files that do not exist without filing a bug report +.Xr synctex 5 +.Xr tex 1 +.Sh AUTHOR +The Synchronize TeXnology is essentially due to Jerome Laurens, +with useful suggestions by some well known actors of the TeX world. +.\" .Sh BUGS \" Document known, unremedied bugs +.\" .Sh HISTORY \" Document history if command behaves in a unique manner
\ No newline at end of file diff --git a/Build/source/texk/web2c/synctex/man5/synctex.5 b/Build/source/texk/web2c/synctex/man5/synctex.5 new file mode 100644 index 00000000000..9ae2b634a42 --- /dev/null +++ b/Build/source/texk/web2c/synctex/man5/synctex.5 @@ -0,0 +1,314 @@ +.Dd August 30, 2006 +.Dt SYNCTEX 5 +.Os "Independant" +.\" +.\" +.Sh NAME +.Nm synctex +.Nd Synchronize TeXnology help file +.\" +.\" +.Sh DESCRIPTION +Synchronize TeXnology help file +.Pq synctexs +are text files that help input/output synchronization during document preparation with the TeX typesetting system. +.Sh BASICS +The structure of this file should not be considered public, in the sense that no one should need to parse its contents, except the synctex command line utility, and the synctex_parser library. +Unless it is absolutely not avoidable, access to the contents of the synctex file should only be made through requests made to the synctex command line utility. +.\" +.Sh STRUCTURE +The element structure of a synctex file is a list of text line records as follows. +.Sq \&* , +.Sq \&+ , +and +.Sq \&? +have their usual EBNF meanings: +.Sq \&* +means zero or more, +.Sq \&+ +means one or more, and +.Sq \&? +means zero or one +.Pq i.e., optional . +.Pp +.Bl -item -offset indent +.\" +.It +.Li <SyncTeX> ::= +.Pq The whole contents in 4 sections +.Bl -item -offset indent +.It +.Li <Preamble> +.It +.Li <Content> +.It +.Li <Postamble> +.It +.Li <Post Scriptum> +.El +.\" +.El +.Pp +Each section starts with the first occurrence of a sectioning line, and ends with the next section, if any. +In the following definitions, we do not mention the section ending condition. +.Sh The preamble +.Bl -item -offset indent +.\" +.It +.Li <Preamble> ::= +.Bl -item -offset indent +.It +.Li Qq SyncTeX Version: +<Version Number> <EOL> +.It +.Li <Input Line>* +.It +.Li ( +.Qq Magnification: +<TeX magnification> <EOL>)* +.It +.Li ( +.Qq Unit: +<unit in scaled point> <EOL>)* +.It +.Li ( +.Qq X Offset: +<horizontal offset in scaled point> <EOL>)* +.It +.Li ( +.Qq Y Offset: +<vertical offset in scaled point> <EOL>)* +.El +.It +.Li <Input Line> ::= +.Qq Input: +<tag> +.Qq \&: +<File Name> <EOL> +.\" +.El +.Sh The content +.Bl -item -offset indent +.It +.Li <Content> ::= +.Bl -item -offset indent +.It +.Li <byte offset record> +.It +.Li Qq Content: +<EOL> +.It +.Li <sheet(1)> +.It +.Li <Input Line>* +.It +.Li <sheet(2)> +.It +.Li <Input Line>* +.It +.Li ... +.It +.Li <sheet(N)> +.It +.Li <Input Line>* +.El +.It +.Li <byte offset record> ::= +.Qq \&! +<byte offset> <end of record> +.Pp +.El +.Pp +.Bl -item -offset indent +.It +.Li <sheet(n)> ::= +.Bl -item -offset indent +.It +.Li <byte offset record> +.It +.Li Qq \&{ +<the integer n> <end of record>/ +.It +.Li <box content>* +.It +.Li <byte offset record> +.It +.Li Qq \&} +<the integer n> <end of record> +.El +.El +.Pp +The <box content> describes what is inside a box. +It is either a vertical or horizontal box, +with some records related to glue, kern or math nodes. +.Bl -item -offset indent +.It +.Li <box content> ::= +.Bl -item -offset indent +.It +.Li <vbox section>|<hbox section> +.It +.Li |<void vbox record>|<void hbox record> +.It +.Li |<current record>|<glue record>|<kern record>|<math record> +.El +.It +.Li <vbox section> ::= +.Bl -item -offset indent +.It +.Li Qq \&[ +<link> +.Qq \&: +<point> +.Qq \&: +<size> <end of record> +.It +.Li <box content>* +.It +.Li Qq \&] +<end of record> +.El +.It +.Li <hbox section> ::= +.Bl -item -offset indent +.It +.Li Qq \&( +<link> +.Qq \&: +<point> +.Qq \&: +<size> <end of record> +.It +.Li <box content>* +.It +.Li Qq \&) +<end of record> +.El +.El +.Pp +Void boxes: +.Bl -item -offset indent +.It +.Li <void vbox record> ::= +.Qq v +<link> +.Qq \&: +<point> +.Qq \&: +<size> <end of record> +.It +.Li <void hbox record> ::= +.Qq h +<link> +.Qq \&: +<point> +.Qq \&: +<size> <end of record> +.It +.Li <size> ::= <Width> +.Qq \&, +<Height> +.Qq \&, +<Depth> +.It +.Li <Width> ::= <integer> +.It +.Li <Height> ::= <integer> +.It +.Li <Depth> ::= <integer> +.It +.Li <link> ::= <tag> +.Qq \&, +<line>( +.Qq \&, +<column>)? +.It +.Li <line> ::= <integer> +.It +.Li <column> ::= <integer> +.El +.Pp +The forthcoming records are basic one liners. +.Bl -item -offset indent +.It +.Li <current record> ::= +.Qq x +<link> +.Qq \&: +<point> <end of record> +.It +.Li <kern record> ::= +.Qq k +<link> +.Qq \&: +<point> +.Qq \&: +<Width> <end of record> +.It +.Li <glue record> ::= +.Qq g +<link> +.Qq \&: +<point> <end of record> +.It +.Li <math record> ::= +.Qq $ +<link> +.Qq \&: +<point> <end of record> +.El +.Pp +.\" .Sx underline, .Dq double quotes, .Pq enclosed in parenthesis +.Sh The postamble +The postamble closes the file +If there is no postamble, it means that the typesetting process did not end correctly. +.Bl -item -offset indent +.\" +.It +.Li <Postamble>::= +.Bl -item -offset indent +.It +.Li <byte offset record> +.It +.Li Qq Count: +<Number fo records> <EOL> +.El +.Sh The post scriptum +The post scriptum contains material possibly added by 3rd parties. +It allows to append some transformation (shift and magnify). +Typically, one applies a dvi to pdf filter with offset options and magnification, +then he appends the same options to the synctex file, for example +.Bd -offset indent + synctex update -o foo.pdf -m 0.486 -x 9472573sp -y 13.3dd source.dvi +.Ed +.Bl -item -offset indent +.\" +.It +.Li <Post Scriptum>::= +.\" +.Bl -item -offset indent +.It +.Li <byte offset record> +.It +.Li Qq Post Scriptum: +<EOL> +.It +.Li Qq Magnification: +<number> <EOL> +.Pq Set additional magnification +.It +.Li Qq X Offset: +<dimension> <EOL> +.Pq Set horizontal offset +.It +.Li Qq Y Offset: +<dimension> <EOL> +.Pq Set vertical offset +.El +This second information will override the offset and magnification previously available in the preamble section. +All the numbers are encoded using the decimal representation with "C" locale. +.Sh USAGE +.Pp +The <current record> is used to compute the visible size of hbox's. +The byte offset is an implicit anchor to navigate the synctex file from sheet to sheet. +. diff --git a/Build/source/texk/web2c/synctex/synctex-e-mem.ch0 b/Build/source/texk/web2c/synctex/synctex-e-mem.ch0 new file mode 100644 index 00000000000..d36577c7bfb --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex-e-mem.ch0 @@ -0,0 +1,164 @@ +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 etex.ch l.3852 + 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 + begin free_node(LR_temp,medium_node_size); p:=head; + {{\sl SyncTeX}: |LR_temp| is a math node} + while link(p)<>tail do p:=link(p); + free_node(tail,medium_node_size); link(p):=null; tail:=p; goto done; + end; +@z + +@x etex.ch l.3976 +@<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 Sync\TeX}: p is a |math_node|} +@z + +@x etex.ch l.4036 +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; + end; +@z + +@x etex.ch l.4088 +@<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 Sync\TeX}: p is a |kern_node|} +link(t):=q; width(t):=rule_wd; edge_dist(t):=-cur_h-rule_wd; goto done; +end +@z + +@x etex.ch l.4137 + 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 Sync\TeX}: 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 Sync\TeX}: proper size for glue} + glue_ptr(r):=glue_ptr(p); leader_ptr(r):=null; + end; +@z + +@x etex.ch l.4234 +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 Sync\TeX}: 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 Sync\TeX} 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 Sync\TeX}: no more "goto found", and proper node size} + goto done; + end; + type(p):=kern_node; + {{\sl Sync\TeX} 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 Sync\TeX} node size watch point: |math_node| size == |kern_node| size} + end; + end +@z diff --git a/Build/source/texk/web2c/synctex/synctex-e-mem.ch1 b/Build/source/texk/web2c/synctex/synctex-e-mem.ch1 new file mode 100644 index 00000000000..67e11212f63 --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex-e-mem.ch1 @@ -0,0 +1,53 @@ +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 synctex-mem.ch0 l.147 +@d REMOVE ME IF synctex_code is properly defined +@y +@z + +@x etex.ch l.514 +@d int_pars=etex_int_pars {total number of integer parameters} +@y +@d synctex_code=etex_int_pars +@d int_pars=synctex_code+1 {total number of integer parameters} +@z diff --git a/Build/source/texk/web2c/synctex/synctex-e-rec.ch0 b/Build/source/texk/web2c/synctex/synctex-e-rec.ch0 new file mode 100644 index 00000000000..098d42c98f6 --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex-e-rec.ch0 @@ -0,0 +1,141 @@ +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: +------- +Description forthcoming + +@x srcdir/etex.ch l.536 +@/@<Cases for |print_param|@>@/ +othercases print("[unknown integer parameter!]") +@y +@/@<synctex case for |print_param|@>@/ +@/@<Cases for |print_param|@>@/ +othercases print("[unknown integer parameter!]") +@z + +@x etex.ch l.1568 +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 Sync\TeX} information@>; + cur_h:=cur_h+width(p); +end; +math_node: begin + @<Record |math_node| {\sl Sync\TeX} information@>; + @<Handle a math node in |hlist_out|@>; +end; +@z + +@x etex.ch l.3965 +@<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 + +@x etex.ch l.4126 + 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 Sync\TeX} 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 + +@x synctex-e-mem.ch0 l.100 + glue_node: begin r:=get_node(medium_node_size); add_glue_ref(glue_ptr(p)); + {{\sl Sync\TeX}: proper size for glue} + glue_ptr(r):=glue_ptr(p); leader_ptr(r):=null; + end; +@y + glue_node: begin r:=get_node(medium_node_size); add_glue_ref(glue_ptr(p)); + {{\sl Sync\TeX}: proper size for glue} + @<Copy the glue {\sl Sync\TeX} information@>; + glue_ptr(r):=glue_ptr(p); leader_ptr(r):=null; + end; +@z + +@x etex.ch l.4459 +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 Sync\TeX} information@>; +end +@z + +@x synctex-mem.ch0 l.236 +@ @<Put each...@>= +primitive("synctex",assign_int,int_base+synctex_code);@/ +@!@:synctex_}{\.{\\synctex} primitive@> +@y +@ @<Put each...@>= +primitive("synctex",assign_int,int_base+synctex_code);@/ +@!@:synctex_}{\.{\\synctex} primitive@> + +@ @<synctex case for |print_param|@>= +synctex_code: print_esc("synctex"); +@z + +@x synctex-act.ch0 l.267 +@ @<Prepare terminal input {\sl Sync\TeX} information@>= +synctex_tag:=0; +@y +@ @<Prepare terminal input {\sl Sync\TeX} information@>= +synctex_tag:=0; + +@ @<Prepare pseudo file {\sl Sync\TeX} information@>= +synctex_tag:=0; +@z diff --git a/Build/source/texk/web2c/synctex/synctex-e-rec.ch1 b/Build/source/texk/web2c/synctex/synctex-e-rec.ch1 new file mode 100644 index 00000000000..c1c4e813010 --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex-e-rec.ch1 @@ -0,0 +1,41 @@ +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. + +@x +MISSING IMPLEMENTATION: 0 synctag for medium sized node at mem[p] +@y +mem[p+medium_node_size-synctex_field_size].int:=0; {{\sl Sync\TeX}: do nothing, it is too late} +@z diff --git a/Build/source/texk/web2c/synctex/synctex-etex.h b/Build/source/texk/web2c/synctex/synctex-etex.h new file mode 100644 index 00000000000..7e51d9c18e9 --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex-etex.h @@ -0,0 +1,38 @@ +/* +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. + +*/ + +# warning SyncTeX for eTeX + +# include "etexd.h" diff --git a/Build/source/texk/web2c/synctex/synctex-mem.ch0 b/Build/source/texk/web2c/synctex/synctex-mem.ch0 new file mode 100644 index 00000000000..5b8cf19e99e --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex-mem.ch0 @@ -0,0 +1,263 @@ +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: +------- + +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 tex.web l.2888 +@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_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 tex.web l.2935 +@d rule_node_size=4 {number of words to allocate for a rule node} +@@y +@d rule_node_size=4+synctex_field_size {number of words to allocate for a rule node} +@@z + +@x tex.web l.2976 +@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 tex.web l.3081 +@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; +subtype(p):=s; width(p):=w; new_math:=p; +end; +@z + +@x tex.web l.3176 +@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; +@z + +@x tex.web l.3189 +@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; +@z + + +@x tex.web l.3227 +@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; +@z + + +@x tex.web l.3925: free nodes with proper size + 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); + goto done; + end; + kern_node,math_node:begin + free_node(p, medium_node_size); + goto done; + end; + penalty_node: do_nothing; +@z + +@x tex.web l.4009: +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)); + 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; + r:=get_node(words); +end; +penalty_node: begin r:=get_node(small_node_size); + words:=small_node_size; + end; +@z + +@x tex.web l.4903 +@d pretolerance_code=0 {badness tolerance before hyphenation} +@y +@d REMOVE ME IF synctex_code is properly defined + +@d pretolerance_code=0 {badness tolerance before hyphenation} +@z + +@x tex.web l.5022 +@d error_context_lines==int_par(error_context_lines_code) +@y +@d error_context_lines==int_par(error_context_lines_code) +@# +@d synctex == int_par(synctex_code) +@z + +@x tex.web l.6422 +@!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 tex.web l.6452 +@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 Sync\TeX} tag of the current file} +@z + +@x tex.web l. 14182 + 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; + end; + end +@z + +@x +@* \[54] System-dependent changes. +@y +@* \[54/SyncTeX] The {\sl Synchronize \TeX nology}. +This section is devoted to the {\sl Synchronize \TeX nology} +- or simply {\sl Sync\TeX} - 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 \TeX nology} is tagged +with the ``{\sl synctex}'' key word. Any code extract where {\sl Sync\TeX} 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 Sync\TeX} is gathered in this section, +except the definitions. + +@ 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 Sync\TeX}} related options, and the {\sl Sync\TeX} 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@> + +@ In order to give the {\sl Sync\TeX} 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; + +@ Synchronization is achieved with the help of an auxiliary file... +@^synctex@> +@^synchronization@> + +@* \[54] System-dependent changes. +@z diff --git a/Build/source/texk/web2c/synctex/synctex-mem.ch1 b/Build/source/texk/web2c/synctex/synctex-mem.ch1 new file mode 100644 index 00000000000..dd31da119ce --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex-mem.ch1 @@ -0,0 +1,44 @@ +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 synctex support. +It implements the memory management for TeX like engines. +It must apply after synctex-mem.ch0 + +@x tex.web l.2888 + synctex-mem.ch0 +@d synctex_field_size=MISSING IMPLEMENTATION +@y +@d synctex_field_size=2 {Declare the {\sl Sync\TeX} field size to store the {\sl Sync\TeX} information: + 2 integers for file tag and line} +@z diff --git a/Build/source/texk/web2c/synctex/synctex-mem.ch2 b/Build/source/texk/web2c/synctex/synctex-mem.ch2 new file mode 100644 index 00000000000..ef883eec3ab --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex-mem.ch2 @@ -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 contains TeX changes for synctex support. +It implements the memory management for TeX like engines. +It must apply after synctex-mem.ch? and synctex-act.ch? + +@x tex.web l.4903 + synctex-mem.ch0 +@d REMOVE ME IF synctex_code is properly defined +@y +@z + +@x tex.web l.4960 + tex.ch +@d int_pars=web2c_int_pars {total number of integer parameters} +@y +@d synctex_code=web2c_int_pars +@d int_pars=synctex_code+1 {total number of \TeX's integer parameters} +@z diff --git a/Build/source/texk/web2c/synctex/synctex-pdf-rec.ch2 b/Build/source/texk/web2c/synctex/synctex-pdf-rec.ch2 new file mode 100644 index 00000000000..d6cb5793594 --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex-pdf-rec.ch2 @@ -0,0 +1,161 @@ +% +% Copyright (c) 1996-2007 Han The Thanh, <thanh@pdftex.org> +% +% This file is part of pdfTeX. +% +% pdfTeX is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 2 of the License, or +% (at your option) any later version. +% +% pdfTeX is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License along with +% pdfTeX; if not, write to the Free Software Foundation, Inc., 51 Franklin +% Street, Fifth Floor, Boston, MA 02110-1301 USA. +% +% These are synctex specific additions to pdftex. +% This change file is meant to override previous changes made by synctex.ch +% + +Fix +@x pdftex.web l.14497 +margin_kern_node, +kern_node: begin + @<Record |kern_node| {\sl Sync\TeX} information@>; + cur_h:=cur_h+width(p); +end; +@y +margin_kern_node:cur_h:=cur_h+width(p); +kern_node: begin + @<Record |kern_node| {\sl Sync\TeX} information@>; + cur_h:=cur_h+width(p); +end; +@z + +@x pdftex.web l.18358 +while p<>null do + @<Output node |p| for |pdf_hlist_out| and move to the next node, + maintaining the condition |cur_v=base_line|@>; +@y +@<Start hlist {\sl Sync\TeX} information record@>; +while p<>null do + @<Output node |p| for |pdf_hlist_out| and move to the next node, + maintaining the condition |cur_v=base_line|@>; +@<Finish hlist {\sl Sync\TeX} information record@>; +@z + +@x pdftex.web l.18382 + p:=link(p); + until not is_char_node(p); +@y + p:=link(p); + until not is_char_node(p); + @<Record current point {\sl Sync\TeX} information@>; +@z + +@x pdftex.web l.18395 +margin_kern_node, +kern_node:cur_h:=cur_h+width(p); +math_node: @<Handle a math node in |hlist_out|@>; +@y +margin_kern_node:cur_h:=cur_h+width(p); +kern_node: begin + @<Record |kern_node| {\sl Sync\TeX} information@>; + cur_h:=cur_h+width(p); +end; +math_node: begin + @<Record |math_node| {\sl Sync\TeX} information@>; + @<Handle a math node in |hlist_out|@>; +end; +@z + +@x pdftex.web l.18405 +move_past: cur_h:=cur_h+rule_wd; +@y +move_past: begin + cur_h:=cur_h+rule_wd; + @<Record horizontal |rule_node| or |glue_node| {\sl Sync\TeX} information@>; +end; +@z + +@x pdftex.web l.18409 +@ @<(\pdfTeX) Output a box in an hlist@>= +if list_ptr(p)=null then cur_h:=cur_h+width(p) +@y +@ @<(\pdfTeX) Output a box in an hlist@>= +if list_ptr(p)=null then + if type(p)=vlist_node then begin + @<Record void vlist {\sl Sync\TeX} information@> + cur_h:=cur_h+width(p) + end + else begin + @<Record void hlist {\sl Sync\TeX} information@> + cur_h:=cur_h+width(p); + end +@z + +@x pdftex.web l.18509 +left_edge:=cur_h; cur_v:=cur_v-height(this_box); top_edge:=cur_v; +@y +left_edge:=cur_h; +@<Start vlist {\sl Sync\TeX} information record@>; +cur_v:=cur_v-height(this_box); top_edge:=cur_v; +@z + +@x pdftex.web l.18511 +while p<>null do + @<Output node |p| for |pdf_vlist_out| and move to the next node, + maintaining the condition |cur_h=left_edge|@>; +@y +while p<>null do + @<Output node |p| for |pdf_vlist_out| and move to the next node, + maintaining the condition |cur_h=left_edge|@>; +@<Finish vlist {\sl Sync\TeX} information record@>; +@z + +@x pdftex.web l.18545 +@ @<(\pdfTeX) Output a box in a vlist@>= +if list_ptr(p)=null then cur_v:=cur_v+height(p)+depth(p) +@y +@ @<(\pdfTeX) Output a box in a vlist@>= +if list_ptr(p)=null then begin + cur_v:=cur_v+height(p); + if type(p)=vlist_node then begin + @<Record void vlist {\sl Sync\TeX} information@>; + end + else begin + @<Record void hlist {\sl Sync\TeX} information@>; + end; + cur_v:=cur_v+depth(p); +end +@z + +@x pdftex.web l.18668 +pdf_last_resources: integer; {pointer to most recently generated Resources object} +begin if tracing_output>0 then +@y +pdf_last_resources: integer; {pointer to most recently generated Resources object} +begin @<Start sheet {\sl Sync\TeX} information record@>; +begin if tracing_output>0 then +@z + +@x pdftex.web l.18699 +@<Flush the box from memory, showing statistics if requested@>; +end; +@y +@<Flush the box from memory, showing statistics if requested@>; +end; +@<Finish sheet {\sl Sync\TeX} information record@>; +end; +@z + +@x +synctex_sheet(mag); +@y +pdf_output_value:=pdf_output; {{\sl Sync\TeX}: we assume that |pdf_output| is properly set up} +synctex_sheet(mag); +@z diff --git a/Build/source/texk/web2c/synctex/synctex-pdftex.h b/Build/source/texk/web2c/synctex/synctex-pdftex.h new file mode 100644 index 00000000000..be4004eef0f --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex-pdftex.h @@ -0,0 +1,46 @@ +/* +Copyright (c) 2008 jerome DOT laurens AT u-bourgogne DOT fr + +This file is part of the SyncTeX package. + +License: +-------- +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE + +Except as contained in this notice, the name of the copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written +authorization from the copyright holder. + +*/ + +# include "pdftexd.h" + +/* We observe pdfoutputvalue in order to determine whether output mode is + * pdf or dvi. + * We will assume that pdf_output_value equals pdf_output before entering + * the synctex_sheet function below. */ +# undef SYNCTEX_OFFSET_IS_PDF +# define SYNCTEX_OFFSET_IS_PDF (pdfoutputvalue>0) +# undef SYNCTEX_OUTPUT +# define SYNCTEX_OUTPUT ((pdfoutputvalue>0)?"pdf":"dvi") + diff --git a/Build/source/texk/web2c/synctex/synctex-rec.ch0 b/Build/source/texk/web2c/synctex/synctex-rec.ch0 new file mode 100644 index 00000000000..8868214409c --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex-rec.ch0 @@ -0,0 +1,397 @@ +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: +------- + +@x tex.web l.2707 +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 Sync\TeX} information@>; +get_node:=r; +exit:end; +@z + +@x tex.web l.3993: Copy +@ @<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 Sync\TeX} information@>; +@z + +@x tex.web l.4009: after synctex-mem.ch0 +glue_node: begin r:=get_node(medium_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: +begin + words:=medium_node_size; + r:=get_node(words); +end; +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)); + @<Copy the glue {\sl Sync\TeX} 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 Sync\TeX}: do not copy the {\sl Sync\TeX} information} + r:=get_node(words); +end; +penalty_node: begin r:=get_node(small_node_size); + words:=small_node_size; + end; +@z + +@x tex.web l.7045 +name:=0; {|terminal_input| is now |true|} +end; +@y +name:=0; {|terminal_input| is now |true|} +@<Prepare terminal input {\sl Sync\TeX} information@>; +end; +@z + +@x tex.web l.10375 +@<Read the first line of the new file@>; +@y +@<Prepare new file {\sl Sync\TeX} information@>; +@<Read the first line of the new file@>; +@z + +@x tex.web l.12332 +while p<>null do @<Output node |p| for |hlist_out| and move to the next node, + maintaining the condition |cur_v=base_line|@>; +@y +@<Start hlist {\sl Sync\TeX} 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 Sync\TeX} information record@>; +@z + +@x tex.web l.12354 + until not is_char_node(p); + dvi_h:=cur_h; +@y + until not is_char_node(p); + dvi_h:=cur_h; + @<Record current point {\sl Sync\TeX} information@>; +@z + +@x tex.web l.12384 +move_past: cur_h:=cur_h+rule_wd; +@y +move_past: begin + cur_h:=cur_h+rule_wd; + @<Record horizontal |rule_node| or |glue_node| {\sl Sync\TeX} information@>; +end; +@z + +@x tex.web l.12388 +@ @<Output a box in an hlist@>= +if list_ptr(p)=null then cur_h:=cur_h+width(p) +@y +@ @<Output a box in an hlist@>= +if list_ptr(p)=null then begin + if type(p)=vlist_node then begin + @<Record void vlist {\sl Sync\TeX} information@> + cur_h:=cur_h+width(p); + end + else begin + @<Record void hlist {\sl Sync\TeX} information@> + end; + cur_h:=cur_h+width(p); +end +@z + +@x tex.web l.12527 +save_loc:=dvi_offset+dvi_ptr; left_edge:=cur_h; cur_v:=cur_v-height(this_box); +@y +save_loc:=dvi_offset+dvi_ptr; left_edge:=cur_h; +@<Start vlist {\sl Sync\TeX} information record@>; +cur_v:=cur_v-height(this_box); +@z + +@x tex.web l.12529 +while p<>null do @<Output node |p| for |vlist_out| and move to the next node, + maintaining the condition |cur_h=left_edge|@>; +@y +while p<>null do @<Output node |p| for |vlist_out| and move to the next node, + maintaining the condition |cur_h=left_edge|@>; +@<Finish vlist {\sl Sync\TeX} information record@>; +@z + +@x tex.web l.12563 +@<Output a box in a vlist@>= +if list_ptr(p)=null then cur_v:=cur_v+height(p)+depth(p) +@y +@<Output a box in a vlist@>= +if list_ptr(p)=null then begin + cur_v:=cur_v+height(p); + if type(p)=vlist_node then begin + @<Record void vlist {\sl Sync\TeX} information@>; + end + else begin + @<Record void hlist {\sl Sync\TeX} information@>; + end; + cur_v:=cur_v+depth(p); +end +@z + +@x tex.web l.12663 +@!old_setting:0..max_selector; {saved |selector| setting} +begin if tracing_output>0 then +@y +@!old_setting:0..max_selector; {saved |selector| setting} +begin @<Start sheet {\sl Sync\TeX} information record@> +begin if tracing_output>0 then +@z + +@x tex.web l.12686 +@<Flush the box from memory, showing statistics if requested@>; +end; +@y +@<Flush the box from memory, showing statistics if requested@>; +end; +@<Finish sheet {\sl Sync\TeX} information record@>; +end; +@z + +@x tex.web l.17880 +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 tex.web l.19326 +@<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 Sync\TeX} watch point: box(|page_head|) size >= |glue_node| size} +@z + +@x tex.web l.20181 +temp_ptr:=lig_stack; lig_stack:=link(temp_ptr); +free_node(temp_ptr,small_node_size); +@y +temp_ptr:=lig_stack; lig_stack:=link(temp_ptr); +free_node(temp_ptr,small_node_size); {{\sl Sync\TeX} watch point: proper size!} +@z + +@x +history:=spotless; {ready to go!} +@y +synctex:=synctexoption; {{\sl Sync\TeX}: read command-line option if given} +history:=spotless; {ready to go!} +@z + +@x tex.web l.24288 +begin @<Finish the extensions@>; +@y +begin @<Finish the extensions@>; +@<Terminate {\sl Sync\TeX} information recording@> +@z + +@x tex.web + synctex-mem.ch0 +@ Synchronization is achieved with the help of an auxiliary file... +@y +@ 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 Sync\TeX} controller implemented +in the external |synctex.c| file will store geometrical information. +This {\sl Sync\TeX} controller will take care of every technical details +concerning the {\sl Sync\TeX} 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 Sync\TeX\ information}. +It consists of a unique file name identifier, the {\sl Sync\TeX\ 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 Sync\TeX}, +we call them {\sl synchronized nodes}. +Synchronized nodes store the {\sl Sync\TeX} information in their last two words: +the first one contains a {\sl Sync\TeX\ 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 Sync\TeX} 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 Sync\TeX} 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 Sync\TeX} 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 Sync\TeX} 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 Sync\TeX} controller with +a |synctex_start_input| message. +This controller will create a new {\sl Sync\TeX} 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 Sync\TeX} information@>= +synctex_start_input; {Give control to the {\sl Sync\TeX} controller} + +@ @<Prepare terminal input {\sl Sync\TeX} information@>= +synctex_tag:=0; + +@ @<Terminate {\sl Sync\TeX} information recording@>= +synctex_terminate; {Let the {\sl Sync\TeX} controller close its files.} + +@ 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 Sync\TeX}, +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 Sync\TeX} controller. +The argument is either the box or the node currently shipped out. +The vertical boxes are not recorded, but the code is available for clients. + +@ @<Start sheet {\sl Sync\TeX} information record@>= +synctex_sheet(mag); + +@ @<Finish sheet {\sl Sync\TeX} information record@>= +synctex_teehs; + +@ @<Start vlist {\sl Sync\TeX} information record@>= +synctex_vlist(this_box); + +@ @<Finish vlist {\sl Sync\TeX} information record@>= +synctex_tsilv(this_box); + +@ @<Record void vlist {\sl Sync\TeX} information@>= +synctex_void_vlist(p,this_box); + +@ @<Start hlist {\sl Sync\TeX} information record@>= +synctex_hlist(this_box); + +@ @<Finish hlist {\sl Sync\TeX} information record@>= +synctex_tsilh(this_box); + +@ @<Record void hlist {\sl Sync\TeX} information@>= +synctex_void_hlist(p,this_box); + +@ @<Record current point {\sl Sync\TeX} information@>= +synctex_current; + +@ @<Record horizontal |rule_node| or |glue_node| {\sl Sync\TeX} information@>= +synctex_horizontal_rule_or_glue(p,this_box); + +@ @<Record |kern_node| {\sl Sync\TeX} information@>= +synctex_kern(p,this_box); + +@ @<Record |math_node| {\sl Sync\TeX} information@>= +synctex_math(p,this_box); + +@ When making a copy of a synchronized node, we might also have to duplicate +the {\sl Sync\TeX} 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 Sync\TeX} information they received at creation time. + +@ @<Copy the box {\sl Sync\TeX} information@>= +MISSING IMPLEMENTATION: copy the synctex information for box node at mem[r] from node at mem[p] + +@ @<Copy the glue {\sl Sync\TeX} information@>= +MISSING IMPLEMENTATION: copy the synctex information for glue node at mem[r] from node at mem[p] + +@ {\sl Nota Bene:} +The {\sl Sync\TeX} 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 Sync\TeX} 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 Sync\TeX} 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 Sync\TeX} information''. +Then all the remaining code should be just harmless. +The resulting program would behave exactly the same as if absolutely no {\sl Sync\TeX} +related code was there, including memory management. +Of course, all this assumes that {\sl Sync\TeX} is turned off from the command line. +@z
\ No newline at end of file diff --git a/Build/source/texk/web2c/synctex/synctex-rec.ch1 b/Build/source/texk/web2c/synctex/synctex-rec.ch1 new file mode 100644 index 00000000000..e52ef773ba9 --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex-rec.ch1 @@ -0,0 +1,64 @@ +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 synctex support. +It implements the memory management for TeX like engines. +It must apply after synctex-mem.ch0 + +@x + MISSING IMPLEMENTATION: 0 synctag for medium sized node at mem[t] +@y + mem[t+medium_node_size-synctex_field_size].int:=0; {{\sl Sync\TeX}: do nothing, it is too late} +@z + +@x + MISSING IMPLEMENTATION: update the synctex information for node at mem[r] with size s +@y + mem[r+s-synctex_field_size].int:=synctex_tag; + mem[r+s-synctex_field_size+1].int:=line; +@z + +@x +MISSING IMPLEMENTATION: copy the synctex information for box node at mem[r] from node at mem[p] +@y +mem[r+box_node_size-synctex_field_size].int:=mem[p+box_node_size-synctex_field_size].int; +mem[r+box_node_size-synctex_field_size+1].int:=mem[p+box_node_size-synctex_field_size+1].int; +@z + +@x +MISSING IMPLEMENTATION: copy the synctex information for glue node at mem[r] from node at mem[p] +@y +mem[r+medium_node_size-synctex_field_size].int:=mem[p+medium_node_size-synctex_field_size].int; +mem[r+medium_node_size-synctex_field_size+1].int:=mem[p+medium_node_size-synctex_field_size+1].int; +@z diff --git a/Build/source/texk/web2c/synctex/synctex-rec.ch2 b/Build/source/texk/web2c/synctex/synctex-rec.ch2 new file mode 100644 index 00000000000..d4ddb9f894d --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex-rec.ch2 @@ -0,0 +1,51 @@ +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 synctex support. +It implements the memory management for TeX like engines. +It must apply after synctex-mem.ch? and synctex-act.ch? + +@x tex.web l.12378 +kern_node,math_node:cur_h:=cur_h+width(p); +@y +kern_node: begin + @<Record |kern_node| {\sl Sync\TeX} information@>; + cur_h:=cur_h+width(p); +end; +math_node: begin + @<Record |math_node| {\sl Sync\TeX} information@>; + cur_h:=cur_h+width(p); +end; +@z + diff --git a/Build/source/texk/web2c/synctex/synctex-tex.h b/Build/source/texk/web2c/synctex/synctex-tex.h new file mode 100644 index 00000000000..d8573268b59 --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex-tex.h @@ -0,0 +1,38 @@ +/* +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. + +*/ + +# warning SyncTeX for TeX + +# include "texd.h" diff --git a/Build/source/texk/web2c/synctex/synctex-xe-mem.ch2 b/Build/source/texk/web2c/synctex/synctex-xe-mem.ch2 new file mode 100644 index 00000000000..1213ba0999d --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex-xe-mem.ch2 @@ -0,0 +1,44 @@ +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 SyncTeX support. +It implements the memory management for XeTeX like engines. +It must apply after synctex.ch0 and synctex-e.ch1 + +@x +@d synctex_field_size=MISSING IMPLEMENTATION +@y +@d synctex_field_size=1 {Declare the {\sl Sync\TeX} field size to store the {\sl Sync\TeX} information: + we will put file tag and line into lh and rh fields of one word} +@z diff --git a/Build/source/texk/web2c/synctex/synctex-xe-rec.ch2 b/Build/source/texk/web2c/synctex/synctex-xe-rec.ch2 new file mode 100644 index 00000000000..282d7c4d864 --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex-xe-rec.ch2 @@ -0,0 +1,70 @@ +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 SyncTeX support. +It implements the memory management for XeTeX like engines. +It must apply after synctex.ch0 and synctex-e.ch1 + +@x + MISSING IMPLEMENTATION: 0 synctag for medium sized node at mem[t] +@y + mem[t+medium_node_size-synctex_field_size].hh.lh:=0; {{\sl Sync\TeX}: do nothing, it is too late} +@z + +@x +MISSING IMPLEMENTATION: 0 synctag for medium sized node at mem[p] +@y +mem[p+medium_node_size-synctex_field_size].hh.lh:=0; {{\sl Sync\TeX}: do nothing, it is too late} +@z + +@x + MISSING IMPLEMENTATION: update the synctex information for node at mem[r] with size s +@y + mem[r+s-synctex_field_size].hh.lh := synctex_tag; + mem[r+s-synctex_field_size].hh.rh := line; +@z + +@x +MISSING IMPLEMENTATION: copy the synctex information for box node at mem[r] from node at mem[p] +@y +mem[r+box_node_size-synctex_field_size].hh.lh:=mem[p+box_node_size-synctex_field_size].hh.lh; +mem[r+box_node_size-synctex_field_size].hh.rh:=mem[p+box_node_size-synctex_field_size].hh.rh; +@z + +@x +MISSING IMPLEMENTATION: copy the synctex information for glue node at mem[r] from node at mem[p] +@y +mem[r+medium_node_size-synctex_field_size].hh.lh:=mem[p+medium_node_size-synctex_field_size].hh.lh; +mem[r+medium_node_size-synctex_field_size].hh.rh:=mem[p+medium_node_size-synctex_field_size].hh.rh; +@z diff --git a/Build/source/texk/web2c/synctex/synctex-xetex.h b/Build/source/texk/web2c/synctex/synctex-xetex.h new file mode 100644 index 00000000000..f0c32fad6f4 --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex-xetex.h @@ -0,0 +1,58 @@ +/* +Copyright (c) 2008 jerome DOT laurens AT u-bourgogne DOT fr + +This file is part of the SyncTeX package. + +License: +-------- +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE + +Except as contained in this notice, the name of the copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written +authorization from the copyright holder. +*/ + +# include "xetexd.h" +/* this will define XeTeX, which we can use in later conditionals */ + +# include <xetexdir/xetexextra.h> + +/* We observe nopdfoutput in order to determine whether output mode is + * pdf or xdv. */ +# undef SYNCTEX_OUTPUT +# define SYNCTEX_OUTPUT (nopdfoutput!=0?"xdv":"pdf") + +/* WARNING: + The definition below must be in sync with their eponym declarations in synctex-xetex.ch1 +*/ +# undef synchronization_field_size +# define synchronization_field_size 1 + +/* 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. */ +# undef SYNCTEX_TAG_MODEL +# define SYNCTEX_TAG_MODEL(NODE,SIZE)\ + mem[NODE+SIZE-synchronization_field_size].hh.lhfield +# undef SYNCTEX_LINE_MODEL +# define SYNCTEX_LINE_MODEL(NODE,SIZE)\ + mem[NODE+SIZE-synchronization_field_size].hh.rh diff --git a/Build/source/texk/web2c/synctex/synctex.c b/Build/source/texk/web2c/synctex/synctex.c index 8f1e5a72aca..f32eaa94836 100644 --- a/Build/source/texk/web2c/synctex/synctex.c +++ b/Build/source/texk/web2c/synctex/synctex.c @@ -72,77 +72,27 @@ 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 +# define SYNCTEX_DEBUG 0 -# ifdef pdfTeX -# undef pdfTeX -# endif +# define SYNCTEX_GZ 1 -# include "pdftexd.h" +/* 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 ; -# undef SYNCTEX_ENGINE -# define SYNCTEX_ENGINE SYNCTEX_ENGINE_PDFTEX +# define SYNCTEX_NOERR 0 -/* 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) +# define EXTERN extern -# endif /* defined XETEX_* */ +# ifdef xfree +# define SYNCTEX_FREE xfree +# else +# define SYNCTEX_FREE(x) free(x) +# endif -# 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}; +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 @@ -152,94 +102,275 @@ NULL, NULL, NULL, 0, 0, NULL, 0, 0, 0, 0}; * 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 +# 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 +# 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 +# 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 +# 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 +# define SYNCTEX_IS_ENABLED 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 2 +/* 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)\ + mem[NODE+SIZE-synchronization_field_size].cint +# define SYNCTEX_LINE_MODEL(NODE,SIZE)\ + mem[NODE+SIZE-synchronization_field_size+1].cint +/* 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 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 3 macros above. */ +# define SYNCTEX_TYPE(NODE) mem[NODE].hh.b0 +# define rule_node 2 +# define glue_node 10 +# define kern_node 11 +# define SYNCTEX_SUBTYPE(NODE) mem[NODE].hh.b1 +# 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) (0 != (synctex_options & SYNCTEX_DISABLED_MASK) ) \ + || (SYNCTEX_IS_ENABLED == 0) \ + || (st_FILE == 0) + +/* 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 + +#include "synctex-TEX-OR-MF-OR-MP.h" + +# if defined(__SyncTeX__) + +# include <stdio.h> +# include <stdarg.h> + +#if SYNCTEX_GZ +# include "zlib.h" +# define FPRINTF gzprintf +#else +# define FPRINTF fprintf +#endif + +/* Here are all the local variables gathered in one "synchronization context" */ +static struct { +#if SYNCTEX_GZ + gzFile file; /* the foo.synctex I/O identifier */ +#else + FILE *file; /* the foo.synctex I/O identifier */ +#endif + char *name; /* the real "foo.synctex" 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 */ + void (*recorder) (halfword);/* 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 8192, fixed */ + integer total_length; /* The total length of the bytes written since the last check point */ +} synctex_ctxt = { +NULL, NULL, NULL, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0}; + +#define st_FILE synctex_ctxt.file + +/* Free all memory used and close the file, + * sent by close_files_and_terminate in tex.web + * It is also 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 (NULL != st_FILE) { +#if SYNCTEX_GZ + gzclose(st_FILE); +#else + xfclose(st_FILE, synctex_ctxt.name); +#endif + SYNCTEX_FREE(synctex_ctxt.name); + synctex_ctxt.name = NULL; + } + SYNCTEX_FREE(synctex_ctxt.root_name); + synctex_ctxt.root_name = NULL; + synctex_options = SYNCTEX_DISABLED_MASK; /* disable synctex */ +} + +static inline int synctex_record_preamble(void); +static inline int synctex_record_input(integer tag, char *name); + +#if SYNCTEX_GZ +static char *synctex_suffix = ".synctex.gz"; +#else +static char *synctex_suffix = ".synctex"; +#endif +static char *synctex_working = "(working)"; + /* 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. + * 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. + * 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)) { +#if SYNCTEX_DISABLED + return NULL; +#endif +#if SYNCTEX_DEBUG + printf("\nwarning: Synchronize DEBUG: synctex_dot_open\n"); + printf("\nwarning: SYNCTEX_IS_ENABLED=%0X\n", SYNCTEX_IS_ENABLED); + printf("\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) { +#if SYNCTEX_DEBUG + printf("\nwarning: Synchronize DEBUG: synctex_dot_open 1\n"); +# endif + if (NULL == st_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 + either st_FILE is nonnegative or synchronization is definitely disabled. */ - static char *suffix = ".synctex"; - /* jobname was set by the \jobname command on the *TeX side */ + /* 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); + char *the_syncname = xmalloc(strlen(tmp) + strlen(synctex_suffix) + strlen(synctex_working) + 1); + if(NULL == the_syncname) { + SYNCTEX_FREE(tmp); + synctex_abort(); + return NULL; + } 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_FREE(tmp); + strcat(the_syncname, synctex_suffix); + strcat(the_syncname, synctex_working); +#if SYNCTEX_GZ + st_FILE = gzopen(the_syncname, FOPEN_WBIN_MODE); +#else + st_FILE = xfopen(the_syncname, FOPEN_WBIN_MODE); +#endif +#if SYNCTEX_DEBUG + printf("\nwarning: Synchronize DEBUG: synctex_dot_open 2\n"); +#endif + if (NULL != st_FILE) { + if(synctex_record_preamble()) { + synctex_abort(); + return NULL; + } + /* Initialization of the context */ + synctex_ctxt.magnification = 1000; + synctex_ctxt.unit = SYNCTEX_UNIT_FACTOR; /* 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); + /* print the preamble, this is an quite an UTF8 file */ if (NULL != synctex_ctxt.root_name) { - fprintf(synctex_ctxt.file, "i:1:%s\n", synctex_ctxt.root_name); - xfree(synctex_ctxt.root_name); + synctex_record_input(1,synctex_ctxt.root_name); + SYNCTEX_FREE(synctex_ctxt.root_name); synctex_ctxt.root_name = NULL; } -# if SYNCTEX_DEBUG + synctex_ctxt.count = 0; +#if SYNCTEX_DEBUG fprintf(stdout, "\nwarning: Synchronize DEBUG: synctex_dot_open SYNCTEX AVAILABLE\n"); -# endif +#endif } else { /* no .synctex file available, so disable synchronization */ - SYNCTEX_OPTIONS = SYNCTEX_DISABLED_MASK; + synctex_options = SYNCTEX_DISABLED_MASK; /* and free the_syncname */ - xfree(the_syncname); + SYNCTEX_FREE(the_syncname); the_syncname = NULL; -# if SYNCTEX_DEBUG +#if SYNCTEX_DEBUG fprintf(stdout, "\nwarning: Synchronize DEBUG: synctex_dot_open SYNCTEX DISABLED\n"); -# endif +#endif } } - return synctex_ctxt.file; + return st_FILE; } /* Each time TeX opens a file, it sends a syncstartinput message and enters @@ -264,40 +395,42 @@ void synctexstartinput(void) { static unsigned int synctex_tag_counter = 0; -# if SYNCTEX_DEBUG - fprintf(stdout, "\nwarning: Synchronize DEBUG: synctexstartinput %i\n", + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nwarning: Synchronize DEBUG: synctexstartinput %i", 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", + printf("\nwarning: SYNCTEX_IS_ENABLED=%i", SYNCTEX_IS_ENABLED); + printf("\nwarning: synctex_options=%0X", synctex_options); + printf("\nwarning: SYNCTEX_DISABLED_MASK=%0X", SYNCTEX_DISABLED_MASK); -# endif +#endif - if (0 != (SYNCTEX_OPTIONS & SYNCTEX_DISABLED_MASK)) { - /* this is where we disable synchronization -synchronization=-1 */ + if (0 != (synctex_options & SYNCTEX_DISABLED_MASK)) { + /* this is where we disable synchronization -synctex=-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 + * 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 */ + * 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; } - - if (0 == (SYNCTEX_OPTIONS & SYNCTEX_IGNORE_CLI_MASK)) { + 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; + SYNCTEX_IS_ENABLED = synctex_options>SYNCTEX_IS_ENABLED? + 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 */ + * 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 @@ -305,355 +438,928 @@ void synctexstartinput(void) * 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); + /* 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 ((NULL != synctex_ctxt.file) - || ((SYNCTEX_IS_ENABLED && synctex_dot_open()) != 0)) { + if ((NULL != st_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); + synctex_record_input(curinput.synctextagfield,tmp); + SYNCTEX_FREE(tmp); } -# if SYNCTEX_DEBUG - fprintf(stdout, "\nwarning: Synchronize DEBUG: synctexstartinput END\n"); -# endif +#if SYNCTEX_DEBUG + printf("\nwarning: Synchronize DEBUG: synctexstartinput END\n"); +# endif return; } +static inline int synctex_record_postamble(void); + +/* Free all memory used and close the file, + * sent by close_files_and_terminate in tex.web. */ + /* 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 +/* 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, the synctex file is removed is 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 synctexterminate(void) +{ + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexterminate\n"); +#endif + char *tmp = gettexstring(jobname); + char * the_real_syncname = xmalloc(strlen(tmp) + strlen(synctex_suffix) + 1); + if(NULL == the_real_syncname) { + SYNCTEX_FREE(tmp); + synctex_abort(); + return; + } + strcpy(the_real_syncname, tmp); + strcat(the_real_syncname, synctex_suffix); + remove(the_real_syncname); + if (NULL != st_FILE) { + if (totalpages > 0) { + synctex_record_postamble(); + } + /* renaming the working synctex file */ + char *the_working_syncname = xmalloc(strlen(the_real_syncname) + strlen(synctex_working) + 1); + if(NULL != the_working_syncname) { + strcpy(the_working_syncname, the_real_syncname); + strcat(the_working_syncname, synctex_working); + rename(the_working_syncname,the_real_syncname); + SYNCTEX_FREE(the_working_syncname); + } + } + 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 synctexsheet(integer mag) { -# if SYNCTEX_DEBUG - fprintf(stdout, "\nSynchronize DEBUG: synctexsheet %i\n",mag); -# endif - if (0 != (SYNCTEX_OPTIONS & SYNCTEX_DISABLED_MASK)) { + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexsheet %i\n",mag); +#endif + if (0 != (synctex_options & SYNCTEX_DISABLED_MASK)) { return; } - if ((synctex_ctxt.file != NULL) + if ((st_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. */ + * pdf starts exactly from the top left corner. */ if(mag>0) { - synctex_ctxt.scale = 8192000/mag; + synctex_ctxt.magnification = 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 + if(synctex_record_settings() || synctex_record_content()) { + synctex_abort(); + return; + } } - fprintf(synctex_ctxt.file, "s:%ld\n", (long int) totalpages + 1); - ++synctex_ctxt.count; + synctex_record_sheet(totalpages+1); } -# if SYNCTEX_DEBUG - fprintf(stdout, "\nSynchronize DEBUG: synctexsheet END\n"); -# endif +#if SYNCTEX_DEBUG + printf("\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. -*/ +static inline int synctex_record_teehs(integer sheet); -/* WARNING: - The 5 definitions below must be in sync with their eponym declarations in *tex.web +/* Recording the "}..." line. In *tex.web, use synctex_sheet(mag) at + * the very beginning of the ship_out procedure. */ -# 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=... */ +void synctexteehs(void) +{ + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexteehs\n"); +#endif + if ((0 != (synctex_options & SYNCTEX_DISABLED_MASK)) || (st_FILE == NULL) ) { + return; + } + synctex_record_teehs(totalpages);/* not totalpages+1*/ +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexteehs END\n"); +#endif + return; +} -/* 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 +#define SYNCTEX_DEBUG_SAVINGS /*if(NULL!=synctex_ctxt.recorder){\ + FPRINTF(st_FILE, "SAVED ");\ + (*synctex_ctxt.recorder) (synctex_ctxt.node);}*/ + +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 vlist_out procedure in *TeX.web. It will be balanced + * by a synctex_tsilv, sent at the end of the vlist_out procedure. p is the + * address of the vlist We assume that p is really a vlist node! */ +void synctexvlist(halfword this_box) +{ + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexhlist\n"); #endif + if (SYNCTEX_IGNORE(this_box)) { + return; + } + SYNCTEX_DEBUG_SAVINGS; + 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); + synctex_ctxt.curh = curh; + synctex_ctxt.curv = curv; + synctex_record_vlist(this_box); +} -/* 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) +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 vlist_out procedure in *TeX.web to balance a former + * synctex_vlist sent at the beginning of that procedure. */ +void synctextsilv(halfword this_box) +{ + 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); + synctex_ctxt.curh = curh; + synctex_ctxt.curv = curv; + synctex_ctxt.recorder = NULL; + synctex_record_tsilv(this_box); +} -/* Recording a "h:..." line */ -void synctex_hlist_recorder(halfword p) +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 synctexvoidvlist(halfword p, halfword this_box) { - 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; + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexvoidvlist\n"); +#endif + if (SYNCTEX_IGNORE(p)) { + return; + } + SYNCTEX_DEBUG_SAVINGS; + 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); + synctex_ctxt.curh = curh; + synctex_ctxt.curv = curv; + 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 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) +void synctexhlist(halfword this_box) { -# if SYNCTEX_DEBUG - fprintf(stdout, "\nSynchronize DEBUG: synctexhlist\n"); -# endif - if (SYNCTEX_IGNORE(p)) { + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexhlist\n"); +#endif + if (SYNCTEX_IGNORE(this_box)) { return; } - synctex_ctxt.p = 0; /* reset */ + SYNCTEX_DEBUG_SAVINGS; + 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); + synctex_ctxt.curh = curh; + synctex_ctxt.curv = curv; synctex_ctxt.recorder = NULL; /* reset */ - synctex_hlist_recorder(p); + synctex_record_hlist(this_box); } -/* Recording a "e" line ending an hbox this message is sent whenever an hlist +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 hlist_out procedure in *TeX.web to balance a former * synctex_hlist sent at the beginning of that procedure. */ -void synctextsilh(halfword p) +void synctextsilh(halfword this_box) { -# if SYNCTEX_DEBUG - fprintf(stdout, "\nSynchronize DEBUG: synctextsilh\n"); -# endif - if (SYNCTEX_IGNORE(p)) { + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctextsilh\n"); +#endif + if (SYNCTEX_IGNORE(this_box)) { 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; + SYNCTEX_DEBUG_SAVINGS; + /* 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); + synctex_ctxt.curh = curh; + synctex_ctxt.curv = curv; + 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 synctexvoidhlist(halfword p, halfword this_box) +{ + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexvoidhlist\n"); +#endif + if (SYNCTEX_IGNORE(p)) { + return; } - fputs("e\n", synctex_ctxt.file); + SYNCTEX_DEBUG_SAVINGS; + /* 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); + synctex_ctxt.curh = curh; + synctex_ctxt.curv = curv; + synctex_ctxt.recorder = NULL; /* reset */ + synctex_record_void_hlist(p); } -# 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 +# 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 +# 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) (0 != (synctex_options & SYNCTEX_DISABLED_MASK) ) \ + || (0 == SYNCTEX_IS_ENABLED) \ + || (0 >= SYNCTEX_TAG_MODEL(NODE,medium_node_size)) \ + || (0 >= SYNCTEX_LINE_MODEL(NODE,medium_node_size)) \ + || (0 == st_FILE) /* 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))) +# 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)) -/* 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; -} +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 synctexmath(halfword p) +void synctexmath(halfword p, halfword this_box) { -# if SYNCTEX_DEBUG - fprintf(stdout, "\nSynchronize DEBUG: synctexmath\n"); -# endif + 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) { + SYNCTEX_DEBUG_SAVINGS; + if ((synctex_ctxt.recorder != NULL) && SYNCTEX_CONTEXT_DID_CHANGE(p)) { /* the sync context did change */ - (*synctex_ctxt.recorder) (synctex_ctxt.p); + (*synctex_ctxt.recorder) (synctex_ctxt.node); } - synctex_ctxt.h = curh; - synctex_ctxt.v = curv; - synctex_ctxt.p = p; + 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.curh = curh; + synctex_ctxt.curv = curv; synctex_ctxt.recorder = NULL;/* no need to record once more */ - synctex_math_recorder(p);/* always record */ + synctex_math_recorder(p);/* always record synchronously */ } -/* Recording a "g:..." line */ -void synctex_glue_recorder(halfword p) +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:... */ +void synctexhorizontalruleorglue(halfword p, halfword this_box) { - 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; + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexglue\n"); +#endif + if (SYNCTEX_IGNORE(p)) { + return; + } + synctex_ctxt.node = p; + synctex_ctxt.curh = curh; + synctex_ctxt.curv = curv; + 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)); + } } -/* this message is sent whenever a glue node ships out +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 synctexglue(halfword p) +void synctexkern(halfword p, halfword this_box) { -# if SYNCTEX_DEBUG - fprintf(stdout, "\nSynchronize DEBUG: synctexglue\n"); -# endif + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexkern\n"); +#endif if (SYNCTEX_IGNORE(p)) { return; } - if (SYNCTEX_CONTEXT_DID_CHANGE) { + 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.p); + (*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); } - 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 { + SYNCTEX_DEBUG_SAVINGS; /* 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; + 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; } } -/* Recording a "k:..." line */ -void synctex_kern_recorder(halfword p) +/* This last part is used as a tool to infer TeX behaviour, + * but not for direct synchronization. */ +# undef SYNCTEX_IGNORE +# define SYNCTEX_IGNORE(NODE) (0 != (synctex_options & SYNCTEX_DISABLED_MASK) ) \ + || (0 == SYNCTEX_IS_ENABLED) \ + || (NULL == st_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) { - 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; + 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); } -/* this message is sent whenever a kern node ships out - See: @ @<Output the non-|char_node| |p| for... */ -void synctexkern(halfword p) +void synctex_node_recorder(halfword p); + +# undef SYNCTEX_IGNORE +# define SYNCTEX_IGNORE(NODE) (0 != (synctex_options & SYNCTEX_DISABLED_MASK) \ + || (0 == SYNCTEX_IS_ENABLED) \ + || (NULL == st_FILE)) +/* this message should be sent to record information + for a node of an unknown type */ +void synctexnode(halfword p, halfword this_box) { -# if SYNCTEX_DEBUG - fprintf(stdout, "\nSynchronize DEBUG: synctexkern\n"); -# endif - if (SYNCTEX_IGNORE(p)) { + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexnode\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; + /* always record, not very usefull yet */ + synctex_node_recorder(p); +} + +/* this message should be sent to record information + synchronously for the current location */ +void synctexcurrent(void) +{ + SYNCTEX_RETURN_IF_DISABLED; +#if SYNCTEX_DEBUG + printf("\nSynchronize DEBUG: synctexcurrent\n"); +#endif + if (SYNCTEX_IGNORE(nothing)) { + return; } + size_t len = FPRINTF(st_FILE,"x%i,%i:%i,%i\n", + synctex_ctxt.tag,synctex_ctxt.line, + curh UNIT,curv UNIT); + if(len) { + synctex_ctxt.total_length += len; + return; + } + synctex_abort(); + return; } -/* Free all memory used and close the file, sent by utils.c */ -void synctex_terminate(void) +#pragma mark - +#pragma mark Glue code Recorders + +/* Recording the settings */ +static inline int synctex_record_settings(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); +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_settings\n"); +#endif + if(NULL == st_FILE) { + return 0; } - xfree(synctex_ctxt.root_name); + if(st_FILE) { + size_t len = FPRINTF(st_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) { + synctex_ctxt.total_length += len; + return 0; + } + } + synctex_abort(); + return -1; +} + +/* Recording a "SyncTeX..." line */ +static inline int synctex_record_preamble(void) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_preamble\n"); +#endif + size_t len = FPRINTF(st_FILE,"SyncTeX Version:%i\n",SYNCTEX_VERSION); + if(len) { + synctex_ctxt.total_length = len; + return 0; + } + synctex_abort(); + return -1; +} + +/* Recording a "Input:..." line */ +static inline int synctex_record_input(integer tag, char *name) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_input\n"); +#endif + size_t len = FPRINTF(st_FILE,"Input:%i:%s\n",tag,name); + if(len) { + synctex_ctxt.total_length += len; + return 0; + } + synctex_abort(); + return -1; +} + +/* Recording a "!..." line */ +static inline int synctex_record_anchor(void) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_anchor\n"); +#endif + size_t len = FPRINTF(st_FILE,"!%i\n",synctex_ctxt.total_length); + if(len) { + synctex_ctxt.total_length = len; + ++synctex_ctxt.count; + return 0; + } + synctex_abort(); + return -1; +} + +/* Recording a "Content" line */ +static inline int synctex_record_content(void) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_content\n"); +#endif + size_t len = FPRINTF(st_FILE,"Content:\n"); + if(len) { + synctex_ctxt.total_length += len; + return 0; + } + 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 = FPRINTF(st_FILE,"{%i\n",sheet); + if(len) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return 0; + } + } + 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 = FPRINTF(st_FILE,"}%i\n",sheet); + if(len) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return 0; + } + } + synctex_abort(); + return -1; +} + +/* Recording a "v..." line */ +static inline void synctex_record_void_vlist(halfword p) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_void_vlist\n"); +#endif + size_t len = FPRINTF(st_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) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a "[..." line */ +static inline void synctex_record_vlist(halfword p) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_vlist\n"); +#endif + size_t len = FPRINTF(st_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) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a "]..." line */ +static inline void synctex_record_tsilv(halfword p) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_tsilv\n"); +#endif + size_t len = FPRINTF(st_FILE,"]\n"); + if(len) { + synctex_ctxt.total_length += len; + return; + } + synctex_abort(); + return; +} + +/* Recording a "h..." line */ +static inline void synctex_record_void_hlist(halfword p) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_void_hlist\n"); +#endif + size_t len = FPRINTF(st_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) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a "(..." line */ +static inline void synctex_record_hlist(halfword p) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_hlist\n"); +#endif + size_t len = FPRINTF(st_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) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a ")..." line */ +static inline void synctex_record_tsilh(halfword p) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_tsilh\n"); +#endif + size_t len = FPRINTF(st_FILE,")\n"); + if(len) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a "Count..." line */ +static inline int synctex_record_count(void) { +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_count\n"); +#endif + size_t len = FPRINTF(st_FILE,"Count:%i\n",synctex_ctxt.count); + if(len) { + synctex_ctxt.total_length += len; + return 0; + } + 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 = FPRINTF(st_FILE,"Postamble:\n"); + if(len) { + synctex_ctxt.total_length += len; + if(synctex_record_count() || synctex_record_anchor()) { + } else { + len = FPRINTF(st_FILE,"Post scriptum:\n"); + if(len) { + synctex_ctxt.total_length += len; + return 0; + } + } + } + } + synctex_abort(); + return -1; +} + +/* Recording a "g..." line */ +static inline void synctex_record_glue(halfword p) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_glue_recorder\n"); +#endif + size_t len = FPRINTF(st_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) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a "k..." line */ +static inline void synctex_record_kern(halfword p) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_kern_recorder\n"); +#endif + size_t len = FPRINTF(st_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) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a "r..." line */ +static inline void synctex_record_rule(halfword p) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_record_tsilh\n"); +#endif + size_t len = FPRINTF(st_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) { + 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) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_math_recorder\n"); +#endif + size_t len = FPRINTF(st_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) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a "k..." line */ +void synctex_kern_recorder(halfword p) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_kern_recorder\n"); +#endif + size_t len = FPRINTF(st_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) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +/* Recording a "c..." line */ +void synctex_char_recorder(halfword p) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_char_recorder\n"); +#endif + size_t len = FPRINTF(st_FILE,"c%i,%i\n", + synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT); + if(len) { + 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) +{ +#if SYNCTEX_DEBUG > 999 + printf("\nSynchronize DEBUG: synctex_node_recorder(0x%x)\n",p); +#endif + size_t len = FPRINTF(st_FILE,"?%i,%i:%i,%i\n", + synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT, + mem[p].hh.b0,mem[p].hh.b1); + if(len) { + synctex_ctxt.total_length += len; + ++synctex_ctxt.count; + return; + } + synctex_abort(); + return; +} + +# else +# warning "SyncTeX is disabled" +# endif diff --git a/Build/source/texk/web2c/synctex/synctex.ch b/Build/source/texk/web2c/synctex/synctex.ch deleted file mode 100644 index 835a0ea777a..00000000000 --- a/Build/source/texk/web2c/synctex/synctex.ch +++ /dev/null @@ -1,860 +0,0 @@ -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); {append a single character} -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); {append a single character} -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 index 357c77f5e8a..8fb9c592169 100644 --- a/Build/source/texk/web2c/synctex/synctex.defines +++ b/Build/source/texk/web2c/synctex/synctex.defines @@ -34,16 +34,28 @@ authorization from the copyright holder. Notice: ------- This file is an interface to the synctex system for web2c. +It declares the public functions API of synctex.c. +It is always embedded as common definitions when convert'ing +from web to c (See the convert shell script). } -{ functions from the synctex controller in synctex.h } +{ functions from the synctex controller in synctex.c } @define procedure synctexstartinput; +@define procedure synctexterminate; @define procedure synctexsheet(); +@define procedure synctexteehs; +@define procedure synctexvlist(); +@define procedure synctextsilv(); +@define procedure synctexvoidvlist(); @define procedure synctexhlist(); @define procedure synctextsilh(); +@define procedure synctexvoidhlist(); @define procedure synctexmath(); @define procedure synctexkern(); -@define procedure synctexglue(); +@define procedure synctexchar(); +@define procedure synctexnode(); +@define procedure synctexcurrent; +@define procedure synctexhorizontalruleorglue(); { 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 index 98fcc29664f..10996392877 100644 --- a/Build/source/texk/web2c/synctex/synctex.h +++ b/Build/source/texk/web2c/synctex/synctex.h @@ -25,37 +25,72 @@ OTHER DEALINGS IN THE SOFTWARE */ -# ifndef __SYNCTEX_HEADER__ -# define __SYNCTEX_HEADER__ +# 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 +/* Send this message to clean memory. */ +extern void synctexterminate(void); + +/* Recording the "{..." line. In *tex.web, use synctex_sheet(pdf_output) at * the very beginning of the ship_out procedure. */ -extern void synctexsheet(integer pdf_output); +extern void synctexsheet(integer mag); + +/* Recording the "}..." line. In *tex.web, use synctex_teehs at + * the very end of the ship_out procedure. +*/ +extern void synctexteehs(void); + +/* This message is sent when a vlist will be shipped out, more precisely at + * the beginning of the vlist_out procedure in *TeX.web. It will be balanced + * by a synctex_tsilv, sent at the end of the vlist_out procedure. p is the + * address of the vlist We assume that p is really a vlist node! */ +extern void synctexvlist(halfword this_box); + +/* 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 vlist_out procedure in *TeX.web to balance a former + * synctex_vlist sent at the beginning of that procedure. */ +extern void synctextsilv(halfword this_box); + +/* This message is sent when a void vlist will be shipped out. + * There is no need to balance a void vlist. */ +extern void synctexvoidvlist(halfword p, halfword this_box); /* 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); +extern void synctexhlist(halfword this_box); /* 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); +extern void synctextsilh(halfword this_box); + +/* This message is sent when a void hlist will be shipped out. + * There is no need to balance a void hlist. */ +extern void synctexvoidhlist(halfword p, halfword this_box); /* Send this message whenever an inline math node will ship out. */ -extern void synctexmath(halfword p); +extern void synctexmath(halfword p, halfword this_box); -/* Send this message whenever a glue node will ship out. */ -extern void synctexglue(halfword p); +/* Send this message whenever an horizontal rule or glue node will ship out. */ +extern void synctexhorizontalruleorglue(halfword p, halfword this_box); /* Send this message whenever a kern node will ship out. */ -extern void synctexkern(halfword p); +extern void synctexkern(halfword p, halfword this_box); -/* Send this message to clean memory. */ -extern void synctex_terminate(void); +/* this message is sent whenever a char node ships out */ +extern void synctexchar(halfword p, halfword this_box); + +/* this message should be sent to record information + for a node of an unknown type */ +extern void synctexnode(halfword p, halfword this_box); + +/* For debugging purpose only */ +extern void synctexcurrent(void); -# endif
\ No newline at end of file +# 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 index 5d77fddd5f3..8d33f360f51 100644 --- a/Build/source/texk/web2c/synctex/synctex.mk +++ b/Build/source/texk/web2c/synctex/synctex.mk @@ -35,16 +35,168 @@ # Makefile fragment for synctex. # It is included in web2c/Makefile.in +synctex_dir = $(srcdir)/synctex + +synctex_all_texd = \ + echo "Enabling SyncTeX Support.";\ + echo "s/\#include \"texmfmp.h\"/\#define __SyncTeX__\\" > synctex_sed_command.txt;\ + echo "\#include \"texmfmp.h\"/" >> synctex_sed_command.txt + +### SyncTeX support in tex +# list of change files +synctex-tex_ch_srcs_mem_only = \ + $(synctex_dir)/synctex-mem.ch0 \ + $(synctex_dir)/synctex-mem.ch1 \ + $(synctex_dir)/synctex-mem.ch2 +synctex-tex_ch_srcs_on = \ + $(synctex-tex_ch_srcs_mem_only) \ + $(synctex_dir)/synctex-rec.ch0 \ + $(synctex_dir)/synctex-rec.ch1 \ + $(synctex_dir)/synctex-rec.ch2 +synctex-tex_ch_srcs_off = +synctex-tex.ch:tie tex.ch $(synctex-tex_ch_srcs) + $(TIE) -c synctex-tex.ch $(srcdir)/tex.web $(synctex-tex_ch_srcs) # 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 >$@ +synctex-tex_o = synctex.o +synctex.h: $(synctex_dir)/synctex.h + cat $(synctex_dir)/synctex.h >$@ +synctex-tex.h: $(synctex_dir)/$@ + cat $(synctex_dir)/$@ >$@ +synctex.c: texd.h $(synctex_dir)/synctex.c synctex-tex.h + sed s/TEX-OR-MF-OR-MP/tex/ $(synctex_dir)/synctex.c >$@ +synctex_texd_on = \ + if test -z "`grep __SyncTeX__ texd.h`";\ + then\ + $(synctex_all_texd);\ + sed -f synctex_sed_command.txt texd.h > synctex_texd.h;\ + mv synctex_texd.h texd.h;\ + rm -f synctex_sed_command.txt;\ + fi +synctex_texd_off = +# switchers: _on to enable full synctex support, _off to completely disable synctex, _mem_only to only implement memory management. +synctex-tex_ch_srcs = \ + $(srcdir)/tex.ch \ + $(synctex-tex_ch_srcs_on) +# _on to enable -synctex command line option, _off to disable +synctex_texd = $(synctex_texd_on) + +### SyncTeX support in etex +# list of change files +synctex-etex_ch_srcs_mem_only = \ + $(synctex_dir)/synctex-mem.ch0 \ + $(synctex_dir)/synctex-mem.ch1 \ + $(synctex_dir)/synctex-e-mem.ch0 \ + $(synctex_dir)/synctex-e-mem.ch1 +synctex-etex_ch_srcs_on = \ + $(synctex-etex_ch_srcs_mem_only) \ + $(synctex_dir)/synctex-rec.ch0 \ + $(synctex_dir)/synctex-rec.ch1 \ + $(synctex_dir)/synctex-e-rec.ch0 \ + $(synctex_dir)/synctex-e-rec.ch1 +synctex-etex_ch_srcs_off = +# The C sources and headers +synctex-etex_o = synctex-e.o +synctex-e.h: $(synctex_dir)/synctex.h + cat $(synctex_dir)/synctex.h >$@ +synctex-etex.h: $(synctex_dir)/$@ + cat $(synctex_dir)/$@ >$@ +synctex-e.c: etexd.h $(synctex_dir)/synctex.c synctex-etex.h + sed s/TEX-OR-MF-OR-MP/etex/ $(synctex_dir)/synctex.c >$@ +synctex_etexd_on = \ + if test -z "`grep __SyncTeX__ etexd.h`";\ + then\ + $(synctex_all_texd);\ + sed -f synctex_sed_command.txt etexd.h > synctex_etexd.h;\ + mv synctex_etexd.h etexd.h;\ + rm -f synctex_sed_command.txt;\ + fi +synctex_etexd_off = +# switchers: _on to enable full synctex support, _off to completely disable synctex, _mem_only to only implement memory management. +synctex-etex_ch_srcs = $(synctex-etex_ch_srcs_on) +# _on to enable -synctex command line option, _off to disable +synctex_etexd = $(synctex_etexd_on) + +### SyncTeX support in pdftex +# list of change files +synctex-pdftex_ch_srcs_mem_only = \ + $(synctex_dir)/synctex-mem.ch0 \ + $(synctex_dir)/synctex-mem.ch1 \ + $(synctex_dir)/synctex-e-mem.ch0 \ + $(synctex_dir)/synctex-e-mem.ch1 +synctex-pdftex_ch_srcs_on = \ + $(synctex-pdftex_ch_srcs_mem_only) \ + $(synctex_dir)/synctex-rec.ch0 \ + $(synctex_dir)/synctex-rec.ch1 \ + $(synctex_dir)/synctex-e-rec.ch0 \ + $(synctex_dir)/synctex-e-rec.ch1 \ + $(synctex_dir)/synctex-pdf-rec.ch2 +synctex-pdftex_ch_srcs_off = +# The C sources and headers +synctex-pdftex_o = synctex-pdf.o +synctex-pdf.h: $(synctex_dir)/synctex.h + cat $(synctex_dir)/synctex.h >$@ +synctex-pdftex.h: $(synctex_dir)/$@ + cat $(synctex_dir)/$@ >$@ +synctex-pdf.c: pdftexd.h $(synctex_dir)/synctex.c synctex-pdftex.h + sed s/TEX-OR-MF-OR-MP/pdftex/ $(synctex_dir)/synctex.c >$@ +synctex_pdftexd_on = \ + if test -z "`grep __SyncTeX__ pdftexd.h`";\ + then\ + $(synctex_all_texd);\ + sed -f synctex_sed_command.txt pdftexd.h > synctex_pdftexd.h;\ + mv synctex_pdftexd.h pdftexd.h;\ + rm -f synctex_sed_command.txt;\ + fi +synctex_pdftexd_off = +# switchers: _on to enable full synctex support, _off to completely disable synctex, _mem_only to only implement memory management. +synctex-pdftex_ch_srcs = $(synctex-pdftex_ch_srcs_on) +# _on to enable -synctex command line option, _off to disable +synctex_pdftexd = $(synctex_pdftexd_on) + +### SyncTeX support in xetex +# list of change files +synctex-xetex_ch_srcs_mem_only = \ + $(synctex_dir)/synctex-mem.ch0 \ + $(synctex_dir)/synctex-e-mem.ch0 \ + $(synctex_dir)/synctex-e-mem.ch1 \ + $(synctex_dir)/synctex-xe-mem.ch2 +synctex-xetex_ch_srcs_on = \ + $(synctex-xetex_ch_srcs_mem_only) \ + $(synctex_dir)/synctex-rec.ch0 \ + $(synctex_dir)/synctex-e-rec.ch0 \ + $(synctex_dir)/synctex-xe-rec.ch2 +synctex-xetex_ch_srcs_off = +# The C sources and headers +synctex-xetex_o = synctex-xe.o +synctex-xe.h: $(synctex_dir)/synctex.h + cat $(synctex_dir)/synctex.h >$@ +synctex-xetex.h: $(synctex_dir)/$@ + cat $(synctex_dir)/$@ >$@ +synctex-xe.c: xetexd.h $(synctex_dir)/synctex.c synctex-xetex.h + sed s/TEX-OR-MF-OR-MP/xetex/ $(synctex_dir)/synctex.c >$@ +synctex_xetexd_on = \ + if test -z "`grep __SyncTeX__ xetexd.h`";\ + then\ + $(synctex_all_texd);\ + sed -f synctex_sed_command.txt xetexd.h > synctex_xetexd.h;\ + mv synctex_xetexd.h xetexd.h;\ + rm -f synctex_sed_command.txt;\ + fi +synctex_xetexd_off = +# switchers: _on to enable full synctex support, _off to completely disable synctex, _mem_only to only implement memory management. +synctex-xetex_ch_srcs = $(synctex-xetex_ch_srcs_on) +# _on to enable -synctex command line option, _off to disable +synctex_xetexd = $(synctex_xetexd_on) + +# the synctex tool, this is not yet implemented +synctex_parser.c synctex_parser.h synctex_main.c: + cat $(synctex_dir)/$@ >$@ +synctex:synctex_main.o synctex_parser.o + $(link_command) synctex_main.o synctex_parser.o # Cleaning up. clean:: synctex-clean synctex-clean: - -rm synctex.o synctex.h synctex.c + -rm -f synctex-* # end of synctex.mk diff --git a/Build/source/texk/web2c/synctex/synctex_main.c b/Build/source/texk/web2c/synctex/synctex_main.c new file mode 100644 index 00000000000..655f559bfe9 --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex_main.c @@ -0,0 +1,792 @@ +/* +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_main.c". +This is the command line interface to the synctex_parser.c. +*/ + +# include <stdlib.h> +# include <stdio.h> +# include <string.h> +# include <stdarg.h> +# include "synctex_parser.h" + +int main(int argc, char *argv[]); + +void synctex_help(char * error,...); +void synctex_help_view(char * error,...); +void synctex_help_edit(char * error,...); + +int synctex_view(int argc, char *argv[]); +int synctex_edit(int argc, char *argv[]); +int synctex_update(int argc, char *argv[]); + +int main(int argc, char *argv[]) +{ + int arg_index = 1; + if(arg_index<argc) { + if(0==strcmp("help",argv[arg_index])) { + if(++arg_index<argc) { + if(0==strcmp("view",argv[arg_index])) { + synctex_help_view(NULL); + return 0; + } else if(0==strcmp("edit",argv[arg_index])) { + synctex_help_edit(NULL); + return 0; + } + } + synctex_help(NULL); + return 0; + } else if(0==strcmp("view",argv[arg_index])) { + return synctex_view(argc-arg_index-1,argv+arg_index+1); + } else if(0==strcmp("edit",argv[arg_index])) { + return synctex_edit(argc-arg_index-1,argv+arg_index+1); + } else if(0==strcmp("update",argv[arg_index])) { + return synctex_update(argc-arg_index-1,argv+arg_index+1); + } + } + synctex_help("Missing options"); + return 0; +} + +void synctex_usage(char * error,va_list ap) { + if(error) { + fprintf(stderr,"SyncTeX ERROR: "); + vfprintf(stderr,error,ap); + fprintf(stderr,"%s\n"); + } + fprintf((error?stderr:stdout), + "usage: synctex <subcommand> [options] [args]\n" + "Synchronize TeXnology command-line client, version 0.1\n\n" + "The Synchronization TeXnology by Jérôme Laurens is a new feature of recent TeX engines.\n" + "It allows to synchronize between input and output, which means to\n" + "navigate from the source document to the typeset material and vice versa.\n\n" + ); + return; +} + +void synctex_help(char * error,...) { + va_list v; + va_start(v, error); + synctex_usage(error, v); + va_end(v); + fprintf((error?stderr:stdout), + "Available subcommands:\n" + " view to perform forwards synchronization\n" + " edit to perform backwards synchronization\n" + " update to update a synctex file after a dvi/xdv to pdf filter\n" + " help this help\n\n" + "Type 'synctex help <subcommand>' for help on a specific subcommand.\n" + "Type 'synctex --version' to see the program version number.\n\n" + ); + return; +} + +void synctex_help_view(char * error,...) { + va_list v; + va_start(v, error); + synctex_usage(error, v); + va_end(v); + fprintf((error?stderr:stdout), + "synctex view: forwards synchronization,\n" + "command sent by the editor to view the output corresponding to the position under the mouse\n" + "\n" + "usage: synctex view -i line:column:input -o output [-x viewer-command] [-h before/offset:middle/after]\n" + "\n" + "-i line:column:input\n" + " specify the line, column and input file.\n" + " The line and column are 1 based integers,\n" + " they allow to identify every character in a file.\n" + " column is the offset of a character relative to the containing line.\n" + " Pass 0 if this information is not relevant.\n" + " input is either the name of the main source file or an included document.\n" + " It must be the very name as understood by TeX.\n" + " \n" + "-o output\n" + " is the full path of the output file (with any relevant path extension).\n" + " \n" + "-x viewer-command\n" + " Normally the synctex tool outputs its result to the stdout.\n" + " It is possible to launch an external tool with the result.\n" + " The viewer-command is a printf like format string with numbered specifiers.\n" + " %{output} is the name of the main document, without path extension.\n" + " %{page} is the 0 based page number, %{page+1} is the 1 based page number.\n" + " To synchronize by point, %{x} is the x coordinate, %{y} is the y coordinate,\n" + " both in dots and relative to the top left corner of the page.\n" + " To synchronize by box,\n" + " %{h} is the horizontal coordinate of the origin of the enclosing box,\n" + " %{v} is the vertical coordinate of the origin of the enclosing box,\n" + " both in dots and relative to the upper left corner of the page.\n" + " They may be different from the preceding pair of coordinates.\n" + " %{width} is the width, %{height} is the height of the enclosing box.\n" + " The latter dimension is naturally counted from bottom to top.\n" + " There is no notion of depth for such a box.\n" + " To synchronize by content, %{before} is the word before,\n" + " %{offset} is the offset, %{middle} is the middle word, and %{after} is the word after.\n" + "\n" + " If no viewer command is provided, the content of the SYNCTEX_VIEWER environment variable is used instead.\n" + "\n" + "-h before/offset:middle/after\n" + " This hint allows a forwards synchronization by contents.\n" + " Instead of giving a character offset in a line, you can give full words.\n" + " A full word is a sequence of characters (excepting '/').\n" + " You will choose full words in the source document that will certainly appear unaltered in the output.\n" + " The middle word contains the character under the mouse at position offset.\n" + " before is a full word preceding middle and after is following it.\n" + " The before or after word can be missing, they are then considered as void strings.\n" + " \n" + ); + return; +} + +/* "usage: synctex view -i line:column:input -o output [-x viewer-command] [-h before/offset:middle/after]\n" */ +int synctex_view(int argc, char *argv[]) { + int arg_index = 0; + int line = -1; + int column = 0; + char * input = NULL; + char * viewer = NULL; + char * before = NULL; + int offset = 0; + char * middle = NULL; + char * after = NULL; + char * output = NULL; + /* required */ + if((arg_index>=argc) || strcmp("-i",argv[arg_index]) || (++arg_index>=argc)) { + synctex_help_view("Missing -i required argument"); + return -1; + } + char * start = argv[arg_index]; + char * end = NULL; + line = strtol(start,&end,10); + if(end>start && strlen(end)>0 && *end==':') { + start = end+1; + column = strtol(start,&end,10); + if(end == start || column < 0) { + column = 0; + } + if(strlen(end)>1 && *end==':') { + input = end+1; + goto scan_output; + } + } + synctex_help_view("Bad -i argument"); + return -1; +scan_output: + if((++arg_index>=argc) || strcmp("-o",argv[arg_index]) || (++arg_index>=argc)) { + synctex_help_view("Missing -o required argument"); + return -1; + } + output = argv[arg_index]; + /* now scan the optional arguments */ + if(++arg_index<argc) { + if(0 == strcmp("-x",argv[arg_index])) { + if(++arg_index<argc) { + if(strcmp("-",argv[arg_index])) { + /* next option does not start with '-', this is a command */ + viewer = argv[arg_index]; + if(++arg_index<argc) { + goto option_hint; + } else { + goto proceed; + } + } else { + /* retrieve the environment variable */ + viewer = getenv("SYNCTEX_VIEWER"); + goto option_hint; + } + } else { + viewer = getenv("SYNCTEX_VIEWER"); + goto proceed; + } + } +option_hint: + if(0 == strcmp("-h",argv[arg_index]) && ++arg_index<argc) { + /* modify the argument */; + after = strstr(argv[arg_index],"/"); + if(NULL != after) { + before = argv[arg_index]; + *after = '\0'; + ++after; + offset = strtol(after,&middle,10); + if(middle>after && offset>=0 && strlen(middle)>2) { + after = strstr(++middle,"/"); + if(NULL != after) { + *after = '\0'; + if(offset<strlen(middle)) { + ++after; + goto proceed; + } + } + } + } + synctex_help_view("Bad hint"); + return -1; + } + } + /* Now proceed, ignore any other argument */ + synctex_scanner_t scanner = NULL; + char * synctex = NULL; + size_t size = 0; +proceed: +#if SYNCTEX_DEBUG + printf("line:%i\n",line); + printf("column:%i\n",column); + printf("input:%s\n",input); + printf("viewer:%s\n",viewer); + printf("before:%s\n",before); + printf("offset:%i\n",offset); + printf("middle:%s\n",middle); + printf("after:%s\n",after); + printf("output:%s\n",output); + printf("cwd:%s\n",getcwd(NULL,0)); +#endif + size = strlen(output)+9; + synctex = (char *)malloc(size); + if(NULL == synctex) { + synctex_help_view("No more memory"); + return -1; + } + if(0 == strlcpy(synctex,output,size)) { + synctex_help_view("Copy problem"); + return -1; + } + char * ptr = synctex; + char * where = NULL; + /* remove the path extension of the last path component. */ +# define SYNCTEX_PATH_COMPONENTS_SEPARATOR "/" + if(where = strstr(ptr,SYNCTEX_PATH_COMPONENTS_SEPARATOR)) { + do { + ptr = where; + } while(where = strstr(ptr+1,SYNCTEX_PATH_COMPONENTS_SEPARATOR)); + } +# define SYNCTEX_PATH_EXTENSION_SEPARATOR "." + if(where = strstr(ptr,SYNCTEX_PATH_EXTENSION_SEPARATOR)) { + do { + ptr = where; + } while(where = strstr(ptr+1,SYNCTEX_PATH_EXTENSION_SEPARATOR)); + *ptr = '\0'; + } + if(0 == strlcat(synctex,".synctex",size)){ + synctex_help_view("Concatenation problem"); + return -1; + } + size = 0; + scanner = synctex_scanner_new_with_contents_of_file(synctex); + free(synctex); + synctex = NULL; + if(scanner && synctex_display_query(scanner,input,line,column)) { + synctex_node_t node = NULL; + if(node = synctex_next_result(scanner)) { + /* filtering the command */ + if(viewer && strlen(viewer)) { + /* Replace %{ by &{, then remove all unescaped '%'*/ + char * where = NULL; + while(where = strstr(viewer,"%{")) { + *where = '&'; + } + where = viewer; + while(where = strstr(viewer,"%")) { + if(strlen(++where)) { + if(*where == '%') { + ++where; + } else { + *(where-1)='&'; + } + } + } + char * dictionary [] = { + "&{output}","%1$s", + "&{page}","%2$i", + "&{page+1}","%3$i", + "&{x}","%4$f", + "&{y}","%5$f", + "&{h}","%6$f", + "&{v}","%7$f", + "&{width}","%8$f", + "&{height}","%9$f", + "&{before}","%10$s", + "&{offset}","%11$i", + "&{middle}","%12$s", + "&{after}","%13$s"}; + int i = 26; + while(i>0) { + char * value = dictionary[--i]; + char * key = dictionary[--i]; +find_a_key: + where = strstr(viewer,key); + if(where) { + memcpy(where,value,strlen(value)); + memmove(where+strlen(value),where+strlen(key),strlen(where)-strlen(key)+1); + goto find_a_key; + } + } + size = strlen(viewer)+3*sizeof(int)+6*sizeof(float)+4*(65536)+1; + char * buffer = malloc(size); + if(NULL == buffer) { + synctex_help_view("No memory available"); + return -1; + } + if(size-1<=snprintf(buffer,size,viewer, + "<main output>", + synctex_node_page(node)-1, + synctex_node_page(node), + synctex_node_h(node), + synctex_node_v(node), + synctex_node_box_visible_h(node), + synctex_node_box_visible_v(node)+synctex_node_box_visible_depth(node), + synctex_node_box_visible_width(node), + synctex_node_box_visible_height(node)+synctex_node_box_visible_depth(node), + (before?before:""), + offset, + (middle?middle:""), + (after?after:""))) { + /* Not all the characters were printed*/ + free(buffer); + buffer= NULL; + synctex_help_view("Problem with\n%s\n",viewer); + return -1; + } + printf("SyncTeX: Executing\n%s\n",buffer); + int status = system(buffer); + free(buffer); + buffer = NULL; + return status; + } else { + /* just print out the results */ + puts("SyncTeX result begin\n"); + do { + printf( "Output:%s\n" + "Page:%i\n" + "x:%f\n" + "y:%f\n" + "h:%f\n" + "v:%f\n" + "W:%f\n" + "H:%f\n" + "before:%s\n" + "offset:%i\n" + "middle:%s\n" + "after:%s\n", + output, + synctex_node_sheet(node), + synctex_node_h(node), + synctex_node_v(node), + synctex_node_box_h(node), + synctex_node_box_v(node)+synctex_node_box_depth(node), + synctex_node_box_width(node), + synctex_node_box_height(node)+synctex_node_box_depth(node), + (before?before:""), + offset, + (middle?middle:""), + (after?after:"")); + } while(node = synctex_next_result(scanner)); + puts("SyncTeX result end\n"); + } + } + } + return 0; +} + +void synctex_help_edit(char * error,...) { + va_list v; + va_start(v, error); + synctex_usage(error, v); + va_end(v); + fputs( + "synctex edit: backwards synchronization,\n" + "command sent by the viewer to edit the source corresponding to the position under the mouse\n\n" + "\n" + "usage: synctex edit -o page:x:y:file [-x editor-command] [-h offset:context]\n" + "\n" + "-o page:x:y:file\n" + " specify the page and coordinates of the point under the mouse.\n" + " page is 1 based.\n" + " Coordinates x and y are counted from the top left corner of the page.\n" + " Their unit is the big point (72 dpi).\n" + " \n" + " file is the full path of a tex file (including the synctex path extension)\n" + " \n" + "-x editor-command\n" + " Normally the synctex tool outputs its result to the stdout.\n" + " It is possible to execute an external tool with the result.\n" + " The editor-command is a printf like format string with following specifiers.\n" + " They will be replaced by their value before the command is executed.\n" + " %{output} is the full path of the output document, with no extension.\n" + " %{input} is the name of the input document.\n" + " %{line} is the 0 based line number. %{line+1} is the 1 based line number.\n" + " %{column} is the 0 based column number or -1. %{column+1} is the 1 based column number or -1.\n" + " %{offset} is the 0 based offset and %{context} is the context of the hint.\n" + " \n" + " If no editor command is provided, the content of the SYNCTEX_EDITOR environment variable is used instead.\n" + " \n" + "-h offset:context\n" + " This hint allows a backwards synchronization by contents.\n" + " You give a context including the character at the mouse location, and\n" + " the offset of this character relative to the beginning of this bunch of text.\n" + " \n", + (error?stderr:stdout) + ); + return; +} + +/* "usage: synctex edit -o page:x:y:output [-x editor-command] [-h offset:context]\n" */ +int synctex_edit(int argc, char *argv[]) { + int arg_index = 0; + int page = -1; + float x = 0; + float y = 0; + char * output = NULL; + char * editor = NULL; + int offset = 0; + char * context = NULL; + /* required */ + if((arg_index>=argc) || strcmp("-o",argv[arg_index]) || (++arg_index>=argc)) { + synctex_help_view("Missing -o required argument"); + return -1; + } + char * start = argv[arg_index]; + char * end = NULL; + page = strtol(start,&end,10); + if(end>start && strlen(end)>1 && *end==':') { + start = end+1; + x = strtof(start,&end); + if(end>start && strlen(end)>1 && *end==':') { + y = strtof(start,&end); + if(end>start && strlen(end)>1 && *end==':') { + output = ++end; + goto scan_execute; + } + } + } + synctex_help_edit("Bad -o argument"); + return -1; +scan_execute: + /* now scan the optional arguments */ + if(++arg_index<argc) { + if(0 == strcmp("-x",argv[arg_index])) { + if(++arg_index<argc) { + if(strcmp("-",argv[arg_index])) { + /* next option does not start with '-', this is a command */ + editor = argv[arg_index]; + if(++arg_index<argc) { + goto option_hint; + } else { + goto proceed; + } + } else { + /* retrieve the environment variable */ + editor = getenv("SYNCTEX_EDITOR"); + goto option_hint; + } + } else { + editor = getenv("SYNCTEX_EDITOR"); + goto proceed; + } + } +option_hint: + if(0 == strcmp("-h",argv[arg_index]) && ++arg_index<argc) { + + start = argv[arg_index]; + end = NULL; + offset = strtol(start,&end,10); + if(end>start && strlen(end)>1 && *end==':') { + context = end+1; + goto proceed; + } + synctex_help_edit("Bad -h argument"); + return -1; + } + } + synctex_scanner_t scanner = NULL; + char * synctex = NULL; + size_t size = 0; +proceed: +#if SYNCTEX_DEBUG + printf("page:%i\n",page); + printf("x:%f\n",x); + printf("y:%f\n",y); + printf("output:%s\n",output); + printf("editor:%s\n",editor); + printf("offset:%i\n",offset); + printf("context:%s\n",context); + printf("cwd:%s\n",getcwd(NULL,0)); +#endif + size = strlen(output)+9; + synctex = (char *)malloc(size); + if(NULL == synctex) { + synctex_help_edit("No more memory"); + return -1; + } + if(0 == strlcpy(synctex,output,size)) { + synctex_help_edit("Copy problem"); + return -1; + } + char * ptr = synctex; + char * where = NULL; + /* remove the path extension of the last path component. */ + if(where = strstr(ptr,SYNCTEX_PATH_COMPONENTS_SEPARATOR)) { + do { + ptr = where; + } while(where = strstr(ptr+1,SYNCTEX_PATH_COMPONENTS_SEPARATOR)); + } + if(where = strstr(ptr,SYNCTEX_PATH_EXTENSION_SEPARATOR)) { + do { + ptr = where; + } while(where = strstr(ptr+1,SYNCTEX_PATH_EXTENSION_SEPARATOR)); + *ptr = '\0'; + } + if(0 == strlcat(synctex,".synctex",size)){ + synctex_help_edit("Concatenation problem"); + return -1; + } + size = 0; + scanner = synctex_scanner_new_with_contents_of_file(synctex); + free(synctex); + synctex = NULL; + if(scanner && synctex_edit_query(scanner,page,x,y)) { + synctex_node_t node = NULL; + char * input = NULL; + if((node = synctex_next_result(scanner)) + && (input = (char *)synctex_scanner_get_name(scanner,synctex_node_tag(node)))) { + /* filtering the command */ + if(strlen(editor)) { + /* Replace %{ by &{, then remove all unescaped '%'*/ + while(where = strstr(editor,"%{")) { + *where = '&'; + } + where = editor; + while(where = strstr(editor,"%")) { + if(strlen(++where)) { + if(*where == '%') { + ++where; + } else { + *(where-1)='&'; + } + } + } + char * dictionary [] = { + "&{output}","%1$s", + "&{input}","%2$s", + "&{line}","%3$i", + "&{column}","%4$i", + "&{offset}","%5$i", + "&{context}","%6$s"}; + int i = 12; + while(i>0) { + char * value = dictionary[--i]; + char * key = dictionary[--i]; +find_a_key: + where = strstr(editor,key); + if(where) { + memcpy(where,value,strlen(value)); + memmove(where+strlen(value),where+strlen(key),strlen(where)-strlen(key)+1); + goto find_a_key; + } + } + size = strlen(editor)+3*sizeof(int)+6*sizeof(float)+4*(65536)+1; + char * buffer = malloc(size); + if(NULL == buffer) { + printf("SyncTeX ERROR: No memory available\n",editor); + return -1; + } + if(size-1<=snprintf(buffer,size,editor, + output, + input, + synctex_node_line(node), + synctex_node_column(node), + offset, + (context?context:""))) { + /* Not all the characters were printed*/ + free(buffer); + buffer= NULL; + printf("SyncTeX ERROR: Problem with\n%s\n",editor); + return -1; + } + printf("SyncTeX: Executing\n%s\n",buffer); + int status = system(buffer); + free(buffer); + buffer = NULL; + return status; + } else { + /* just print out the results */ + puts("SyncTeX result begin\n"); + do { + printf( "Output:%s\n" + "Input:%s\n" + "Line:%f\n" + "Column:%s\n" + "Offset:%i\n" + "Context:%s\n", + output, + input, + synctex_node_line(node), + synctex_node_column(node), + offset, + (context?context:"")); + } while(node = synctex_next_result(scanner)); + puts("SyncTeX result end\n"); + } + } + } + return 0; +} + +void synctex_help_update(char * error,...) { + va_list v; + va_start(v, error); + synctex_usage(error, v); + va_end(v); + fputs( + "synctex update: up to date synctex file,\n" + "Use this command to update the synctex file once a dvi/xdv to pdf filter is applied.\n\n" + "\n" + "usage: synctex update -o output [-m number] [-x dimension] [-y dimension]\n" + "\n" + "-o output is the file to which the filter applies.\n" + "-m number Set additional magnification\n" + "-x dimension Set horizontal offset\n" + "-y dimension Set vertical offset\n" + "In general, these are exactly the options provided to the dvi/xdv to pdf filter.\n", + (error?stderr:stdout) + ); + return; +} + +/* "usage: synctex update -o output [-m number] [-x dimension] [-y dim output\n" */ +int synctex_update(int argc, char *argv[]) { + int arg_index = 0; + if(arg_index>=argc) { + synctex_help_update("Bad update command"); + return -1; + } + char * magnification = NULL; + char * x = NULL; + char * y = NULL; + char * output = NULL; + /* required */ + if((arg_index>=argc) || strcmp("-o",argv[arg_index]) || (++arg_index>=argc)) { + synctex_help_update("Missing -o required argument"); + return -1; + } + output = argv[arg_index]; + if(++arg_index>=argc) { + return 0; + } +next_argument: + if(0 == strcmp("-m",argv[arg_index])) { + if(++arg_index>=argc) { + synctex_help_update("Missing magnification"); + return -1; + } + magnification = argv[arg_index]; +prepare_next_argument: + if(++arg_index<argc) { + goto next_argument; + } + } else if(0 == strcmp("-x",argv[arg_index])) { + if(++arg_index>=argc) { + synctex_help_update("Missing x offset"); + return -1; + } + x = argv[arg_index]; + goto prepare_next_argument; + } else if(0 == strcmp("-y",argv[arg_index])) { + if(++arg_index>=argc) { + synctex_help_update("Missing y offset"); + return -1; + } + y = argv[arg_index]; + goto prepare_next_argument; + } + /* Arguments parsed */ + size_t size = strlen(output)+9; + char * synctex = (char *)malloc(size); + if(NULL == synctex) { + synctex_help_update("No more memory"); + return -1; + } + if(0 == strlcpy(synctex,output,size)) { + synctex_help_update("Copy problem"); + return -1; + } + if(NULL == x + && NULL == y + && NULL == magnification) { + /* Nothing to update */ + printf("SyncTeX: Nothing to update\n"); + return 0; + } + char * ptr = synctex; + char * where = NULL; + /* remove the path extension of the last path component. */ + if(where = strstr(ptr,SYNCTEX_PATH_COMPONENTS_SEPARATOR)) { + do { + ptr = where; + } while(where = strstr(ptr+1,SYNCTEX_PATH_COMPONENTS_SEPARATOR)); + } + if(where = strstr(ptr,SYNCTEX_PATH_EXTENSION_SEPARATOR)) { + do { + ptr = where; + } while(where = strstr(ptr+1,SYNCTEX_PATH_EXTENSION_SEPARATOR)); + *ptr = '\0'; + } + if(0 == strlcat(synctex,".synctex",size)){ + synctex_help_update("Concatenation problem"); + return -1; + } + FILE * F = fopen(synctex,"a"); + if(NULL == F) { + synctex_help_update("No file at: %s",synctex); + return -1; + } + printf("SyncTeX: updating %s...",synctex); + int len = 0; + if(magnification) { + len += fprintf(F,"Magnification:%s\n",magnification); + } + if(x) { + len += fprintf(F,"X Offset:%s\n",x); + } + if(y) { + len += fprintf(F,"Y Offset:%s\n",y); + } + if(len) { + fprintf(F,"!%i\n",len); + } + fclose(F); + printf(" done\n"); + return 0; +} diff --git a/Build/source/texk/web2c/synctex/synctex_parser.c b/Build/source/texk/web2c/synctex/synctex_parser.c new file mode 100644 index 00000000000..f68e32d99d7 --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex_parser.c @@ -0,0 +1,2602 @@ +/* +Copyright (c) 2008 jerome DOT laurens AT u-bourgogne DOT fr + +This file is part of the SyncTeX package. + +License: +-------- +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE + +Except as contained in this notice, the name of the copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written +authorization from the copyright holder. + +*/ + +#include "stddef.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "limits.h" +#include "time.h" +#include "math.h" +#include "errno.h" + +/* This custom malloc functions initializes to 0 the newly allocated memory. */ +void *_synctex_malloc(size_t size) { + void * ptr = malloc(size); + if(ptr) { + memset(ptr,0,size); + } + return (void *)ptr; +} + +/* The data is organized in a graph with multiple entries. + * The root object is a scanner, it is created with the contents on a synctex file. + * Each leaf of the tree is a synctex_node_t object. + * There are 3 subtrees, two of them sharing the same leaves. + * The first tree is the list of input records, where input file names are associated with tags. + * The second tree is the box tree as given by TeX when shipping pages out. + * First level objects are sheets, containing boxes, glues, kerns... + * The third tree allows to browse leaves according to tag and line. + */ + +#include "synctex_parser.h" + +/* each synctex node has a class */ +typedef struct __synctex_class_t _synctex_class_t; +typedef _synctex_class_t * synctex_class_t; + + +/* synctex_node_t is a pointer to a node + * _synctex_node is the target of the synctex_node_t pointer + * It is a pseudo object oriented program. + * class is a pointer to the class object the node belongs to. + * implementation is meant to contain the private data of the node + * basically, there are 2 kinds of information: navigation information and + * synctex information. Both will depend on the type of the node, + * thus different nodes will have different private data. + * There is no inheritancy overhead. + */ +struct _synctex_node { + synctex_class_t class; + int * implementation; +}; + +/* Each node of the tree, except the scanner itself belongs to a class. + * The class object is just a struct declaring the owning scanner + * This is a pointer to the scanner as root of the tree. + * The type is used to identify the kind of node. + * The class declares pointers to a creator and a destructor method. + * The log and display fields are used to log and display the node. + * display will also display the child, sibling and parent sibling. + * parent, child and sibling are used to navigate the tree, + * from TeX box hierarchy point of view. + * The friend field points to a method which allows to navigate from friend to friend. + * A friend is a node with very close tag and line numbers. + * Finally, the info field point to a method giving the private node info offset. + */ +typedef synctex_node_t *(*_synctex_node_getter_t)(synctex_node_t); +typedef int *(*_synctex_int_getter_t)(synctex_node_t); + +struct __synctex_class_t { + synctex_scanner_t scanner; + int type; + synctex_node_t (*new)(synctex_scanner_t scanner); + void (*free)(synctex_node_t); + void (*log)(synctex_node_t); + void (*display)(synctex_node_t); + _synctex_node_getter_t parent; + _synctex_node_getter_t child; + _synctex_node_getter_t sibling; + _synctex_node_getter_t friend; + _synctex_int_getter_t info; +}; + +# pragma mark - +# pragma mark Abstract OBJECTS and METHODS + +/* These macros are shortcuts + * INFO(node) points to the first synctex integer data of node + * INFO(node)[index] is the information at index + */ +# define INFO(NODE) ((*((((NODE)->class))->info))(NODE)) + +/* This macro checks if a message can be sent. + */ +# define CAN_PERFORM(NODE,SELECTOR)\ + (NULL!=((((NODE)->class))->SELECTOR)) + +/* This macro is some kind of objc_msg_send. + * It takes care of sending the proper message if possible. + */ +# define MSG_SEND(NODE,SELECTOR) if(NODE && CAN_PERFORM(NODE,SELECTOR)) {\ + (*((((NODE)->class))->SELECTOR))(NODE);\ + } + +/* read only safe getter + */ +# define GET(NODE,SELECTOR)((NODE && CAN_PERFORM(NODE,SELECTOR))?GETTER(NODE,SELECTOR)[0]:(NULL)) + +/* read/write getter + */ +# define GETTER(NODE,SELECTOR)\ + ((synctex_node_t *)((*((((NODE)->class))->SELECTOR))(NODE))) + +# define FREE(NODE) MSG_SEND(NODE,free); + +/* Parent getter and setter + */ +# define PARENT(NODE) GET(NODE,parent) +# define SET_PARENT(NODE,NEW_PARENT) if(NODE && NEW_PARENT && CAN_PERFORM(NODE,parent)){\ + GETTER(NODE,parent)[0]=NEW_PARENT;\ + } + +/* Child getter and setter + */ +# define CHILD(NODE) GET(NODE,child) +# define SET_CHILD(NODE,NEW_CHILD) if(NODE && NEW_CHILD){\ + GETTER(NODE,child)[0]=NEW_CHILD;\ + GETTER(NEW_CHILD,parent)[0]=NODE;\ + } + +/* Sibling getter and setter + */ +# define SIBLING(NODE) GET(NODE,sibling) +# define SET_SIBLING(NODE,NEW_SIBLING) if(NODE && NEW_SIBLING) {\ + GETTER(NODE,sibling)[0]=NEW_SIBLING;\ + if(CAN_PERFORM(NEW_SIBLING,parent) && CAN_PERFORM(NODE,parent)) {\ + GETTER(NEW_SIBLING,parent)[0]=GETTER(NODE,parent)[0];\ + }\ + } +/* Friend getter and setter + */ +# define FRIEND(NODE) GET(NODE,friend) +# define SET_FRIEND(NODE,NEW_FRIEND) if(NODE && NEW_FRIEND){\ + GETTER(NODE,friend)[0]=NEW_FRIEND;\ + } + +/* A node is meant to own its child and sibling. + * It is not owned by its parent, unless it is its first child. + * This destructor is for all nodes. + */ +void _synctex_free_node(synctex_node_t node) { + if(node) { + (*((node->class)->sibling))(node); + FREE(SIBLING(node)); + FREE(CHILD(node)); + free(node); + } + return; +} + +/* A node is meant to own its child and sibling. + * It is not owned by its parent, unless it is its first child. + * This destructor is for nodes with no child. + */ +void _synctex_free_leaf(synctex_node_t node) { + if(node) { + FREE(SIBLING(node)); + free(node); + } + return; +} + +/* The synctex scanner is the root object. + * Is is initiated with the contents of a text file. + * The buffer_? are first used to parse the text. + */ +struct __synctex_scanner_t { + unsigned char * buffer_ptr; /* current location in the buffer */ + unsigned char * buffer_start; /* start of the buffer */ + unsigned char * buffer_end; /* end of the buffer */ + char * output; /* dvi or pdf, not yet used */ + int version; /* 1, not yet used */ + int pre_magnification; /* magnification from the synctex preamble */ + int pre_unit; /* unit from the synctex preamble */ + int pre_x_offset; /* X offste from the synctex preamble */ + int pre_y_offset; /* Y offset from the synctex preamble */ + int count; /* Number of records, from the synctex postamble */ + float unit; /* real unit, from synctex preamble or post scriptum */ + float x_offset; /* X offset, from synctex preamble or post scriptum */ + float y_offset; /* Y Offset, from synctex preamble or post scriptum */ + synctex_node_t sheet; /* The first sheet node */ + synctex_node_t input; /* The first input node */ + int number_of_lists; /* The number of friend lists */ + synctex_node_t * lists_of_friends;/* The friend lists */ + _synctex_class_t class[synctex_node_type_last]; /* The classes of the nodes of the scanner */ +}; + +/* PTR, START and END are convenient shortcuts + */ +# define PTR (scanner->buffer_ptr) +# define START (scanner->buffer_start) +# define END (scanner->buffer_end) + +# pragma mark - +# pragma mark OBJECTS, their creators and destructors. + +/* The sheet is a first level node. + * It has no parent (the parent is the scanner itself) + * Its sibling points to another sheet. + * Its child points to its first child, in general a box. + * A sheet node contains only one synctex information: the page. + * This is the 1 based page index as given by TeX. + */ +typedef struct { + synctex_class_t class; + int implementation[2+1];/* child, sibling + * PAGE */ +} synctex_sheet_t; + +/* The next macros is used to access the node info + * for example, the page of a sheet is stored in INFO(sheet)[PAGE] + */ +# define PAGE 0 + +/* This macro defines implementation offsets + */ +# define MAKE_GET(GETTER,OFFSET)\ +synctex_node_t * GETTER (synctex_node_t node) {\ + return node?(synctex_node_t *)((&((node)->implementation))+OFFSET):NULL;\ +} +MAKE_GET(_synctex_implementation_0,0) +MAKE_GET(_synctex_implementation_1,1) +MAKE_GET(_synctex_implementation_2,2) +MAKE_GET(_synctex_implementation_3,3) +MAKE_GET(_synctex_implementation_4,4) + +synctex_node_t _synctex_new_sheet(synctex_scanner_t scanner); +void _synctex_display_sheet(synctex_node_t sheet); +void _synctex_log_sheet(synctex_node_t sheet); + +static const _synctex_class_t synctex_class_sheet = { + NULL, /* No scanner yet */ + synctex_node_type_sheet, /* Node type */ + &_synctex_new_sheet, /* creator */ + &_synctex_free_node, /* destructor */ + &_synctex_log_sheet, /* log */ + &_synctex_display_sheet, /* display */ + NULL, /* No parent */ + &_synctex_implementation_0, /* child */ + &_synctex_implementation_1, /* sibling */ + NULL, /* No friend */ + (_synctex_int_getter_t)&_synctex_implementation_2 /* info */ +}; + +/* sheet node creator */ +synctex_node_t _synctex_new_sheet(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_sheet_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_sheet:(synctex_class_t)&synctex_class_sheet; + } + return node; +} + +/* A box node contains navigation and synctex information + * There are different kind of boxes. + * Only horizontal boxes are treated differently because of their visible size. + */ +typedef struct { + synctex_class_t class; + int implementation[4+3+5]; /* parent,child,sibling,friend, + * TAG,LINE,COLUMN, + * HORIZ,VERT,WIDTH,HEIGHT,DEPTH */ +} synctex_vert_box_node_t; + +# define TAG 0 +# define LINE (TAG+1) +# define COLUMN (LINE+1) +# define HORIZ (COLUMN+1) +# define VERT (HORIZ+1) +# define WIDTH (VERT+1) +# define HEIGHT (WIDTH+1) +# define DEPTH (HEIGHT+1) + +synctex_node_t _synctex_new_vbox(synctex_scanner_t scanner); +void _synctex_log_box(synctex_node_t sheet); +void _synctex_display_vbox(synctex_node_t node); + +/* These are static class objects, each scanner will make a copy of them and setup the scanner field. + */ +static const _synctex_class_t synctex_class_vbox = { + NULL, /* No scanner yet */ + synctex_node_type_vbox, /* Node type */ + &_synctex_new_vbox, /* creator */ + &_synctex_free_node, /* destructor */ + &_synctex_log_box, /* log */ + &_synctex_display_vbox, /* display */ + &_synctex_implementation_0, /* parent */ + &_synctex_implementation_1, /* child */ + &_synctex_implementation_2, /* sibling */ + &_synctex_implementation_3, /* friend */ + (_synctex_int_getter_t)&_synctex_implementation_4 +}; + +/* vertical box node creator */ +synctex_node_t _synctex_new_vbox(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_vert_box_node_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_vbox:(synctex_class_t)&synctex_class_vbox; + } + return node; +} + +/* Horizontal boxes must contain visible size, because 0 width does not mean emptiness */ +typedef struct { + synctex_class_t class; + int implementation[4+3+5+5]; /*parent,child,sibling,friend, + * TAG,LINE,COLUMN, + * HORIZ,VERT,WIDTH,HEIGHT,DEPTH, + * HORIZ_V,VERT_V,WIDTH_V,HEIGHT_V,DEPTH_V*/ +} synctex_horiz_box_node_t; + +# define HORIZ_V (DEPTH+1) +# define VERT_V (HORIZ_V+1) +# define WIDTH_V (VERT_V+1) +# define HEIGHT_V (WIDTH_V+1) +# define DEPTH_V (HEIGHT_V+1) + +synctex_node_t _synctex_new_hbox(synctex_scanner_t scanner); +void _synctex_display_hbox(synctex_node_t node); +void _synctex_log_horiz_box(synctex_node_t sheet); + + +static const _synctex_class_t synctex_class_hbox = { + NULL, /* No scanner yet */ + synctex_node_type_hbox, /* Node type */ + &_synctex_new_hbox, /* creator */ + &_synctex_free_node, /* destructor */ + &_synctex_log_horiz_box, /* log */ + &_synctex_display_hbox, /* display */ + &_synctex_implementation_0, /* parent */ + &_synctex_implementation_1, /* child */ + &_synctex_implementation_2, /* sibling */ + &_synctex_implementation_3, /* friend */ + (_synctex_int_getter_t)&_synctex_implementation_4 +}; + +/* horizontal box node creator */ +synctex_node_t _synctex_new_hbox(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_horiz_box_node_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_hbox:(synctex_class_t)&synctex_class_hbox; + } + return node; +} + +/* This void box node implementation is either horizontal or vertical + * It does not contain a child field. + */ +typedef struct { + synctex_class_t class; + int implementation[3+3+5]; /* parent,sibling,friend, + * TAG,LINE,COLUMN, + * HORIZ,VERT,WIDTH,HEIGHT,DEPTH*/ +} synctex_void_box_node_t; + +synctex_node_t _synctex_new_void_vbox(synctex_scanner_t scanner); +void _synctex_log_void_box(synctex_node_t sheet); +void _synctex_display_void_vbox(synctex_node_t node); + +static const _synctex_class_t synctex_class_void_vbox = { + NULL, /* No scanner yet */ + synctex_node_type_void_vbox,/* Node type */ + &_synctex_new_void_vbox, /* creator */ + &_synctex_free_node, /* destructor */ + &_synctex_log_void_box, /* log */ + &_synctex_display_void_vbox,/* display */ + &_synctex_implementation_0, /* parent */ + NULL, /* No child */ + &_synctex_implementation_1, /* sibling */ + &_synctex_implementation_2, /* friend */ + (_synctex_int_getter_t)&_synctex_implementation_3 +}; + +/* vertical void box node creator */ +synctex_node_t _synctex_new_void_vbox(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_void_box_node_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_void_vbox:(synctex_class_t)&synctex_class_void_vbox; + } + return node; +} + +synctex_node_t _synctex_new_void_hbox(synctex_scanner_t scanner); +void _synctex_display_void_hbox(synctex_node_t node); + +static const _synctex_class_t synctex_class_void_hbox = { + NULL, /* No scanner yet */ + synctex_node_type_void_hbox,/* Node type */ + &_synctex_new_void_hbox, /* creator */ + &_synctex_free_node, /* destructor */ + &_synctex_log_void_box, /* log */ + &_synctex_display_void_hbox,/* display */ + &_synctex_implementation_0, /* parent */ + NULL, /* No child */ + &_synctex_implementation_1, /* sibling */ + &_synctex_implementation_2, /* friend */ + (_synctex_int_getter_t)&_synctex_implementation_3 +}; + +/* horizontal void box node creator */ +synctex_node_t _synctex_new_void_hbox(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_void_box_node_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_void_hbox:(synctex_class_t)&synctex_class_void_hbox; + } + return node; +} + +/* The medium nodes correspond to kern, glue and math nodes. */ +typedef struct { + synctex_class_t class; + int implementation[3+3+3]; /* parent,sibling,friend, + * TAG,LINE,COLUMN, + * HORIZ,VERT,WIDTH */ +} synctex_medium_node_t; + +synctex_node_t _synctex_new_math(synctex_scanner_t scanner); +void _synctex_log_medium_node(synctex_node_t sheet); +void _synctex_display_math(synctex_node_t node); + +static const _synctex_class_t synctex_class_math = { + NULL, /* No scanner yet */ + synctex_node_type_math, /* Node type */ + &_synctex_new_math, /* creator */ + &_synctex_free_leaf, /* destructor */ + &_synctex_log_medium_node, /* log */ + &_synctex_display_math, /* display */ + &_synctex_implementation_0, /* parent */ + NULL, /* No child */ + &_synctex_implementation_1, /* sibling */ + &_synctex_implementation_2, /* friend */ + (_synctex_int_getter_t)&_synctex_implementation_3 +}; + +/* math node creator */ +synctex_node_t _synctex_new_math(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_medium_node_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_math:(synctex_class_t)&synctex_class_math; + } + return node; +} + +synctex_node_t _synctex_new_glue(synctex_scanner_t scanner); +void _synctex_display_glue(synctex_node_t node); + +static const _synctex_class_t synctex_class_glue = { + NULL, /* No scanner yet */ + synctex_node_type_glue, /* Node type */ + &_synctex_new_glue, /* creator */ + &_synctex_free_leaf, /* destructor */ + &_synctex_log_medium_node, /* log */ + &_synctex_display_glue, /* display */ + &_synctex_implementation_0, /* parent */ + NULL, /* No child */ + &_synctex_implementation_1, /* sibling */ + &_synctex_implementation_2, /* friend */ + (_synctex_int_getter_t)&_synctex_implementation_3 +}; +/* glue node creator */ +synctex_node_t _synctex_new_glue(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_medium_node_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_glue:(synctex_class_t)&synctex_class_glue; + } + return node; +} + +synctex_node_t _synctex_new_kern(synctex_scanner_t scanner); +void _synctex_display_kern(synctex_node_t node); + +static const _synctex_class_t synctex_class_kern = { + NULL, /* No scanner yet */ + synctex_node_type_kern, /* Node type */ + &_synctex_new_kern, /* creator */ + &_synctex_free_leaf, /* destructor */ + &_synctex_log_medium_node, /* log */ + &_synctex_display_kern, /* display */ + &_synctex_implementation_0, /* parent */ + NULL, /* No child */ + &_synctex_implementation_1, /* sibling */ + &_synctex_implementation_2, /* friend */ + (_synctex_int_getter_t)&_synctex_implementation_3 +}; + +/* kern node creator */ +synctex_node_t _synctex_new_kern(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_medium_node_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_kern:(synctex_class_t)&synctex_class_kern; + } + return node; +} + +/* Input nodes only know about their sibling, which is another input node. + * The synctex information is the TAG and NAME*/ +typedef struct { + synctex_class_t class; + int implementation[1+2]; /* sibling, + * TAG,NAME */ +} synctex_input_t; + +/* The TAG previously defined is also used here */ +# define NAME 1 + +synctex_node_t _synctex_new_input(synctex_scanner_t scanner); +void _synctex_display_input(synctex_node_t node); +void _synctex_log_input(synctex_node_t sheet); + +static const _synctex_class_t synctex_class_input = { + NULL, /* No scanner yet */ + synctex_node_type_input, /* Node type */ + &_synctex_new_input, /* creator */ + &_synctex_free_leaf, /* destructor */ + &_synctex_log_input, /* log */ + &_synctex_display_input, /* display */ + NULL, /* No parent */ + NULL, /* No child */ + &_synctex_implementation_0, /* sibling */ + NULL, /* No friend */ + (_synctex_int_getter_t)&_synctex_implementation_1 +}; + +synctex_node_t _synctex_new_input(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_input_t)); + if(node) { + node->class = scanner?scanner->class+synctex_node_type_input:(synctex_class_t)&synctex_class_input; + } + return node; +} + +#pragma mark - +#pragma mark Navigation +synctex_node_t synctex_node_parent(synctex_node_t node) +{ + return PARENT(node); +} +synctex_node_t synctex_node_sheet(synctex_node_t node) +{ + while(node && node->class->type != synctex_node_type_sheet) { + node = PARENT(node); + } + /* exit the while loop either when node is NULL or node is a sheet */ + return node; +} +synctex_node_t synctex_node_child(synctex_node_t node) +{ + return CHILD(node); +} +synctex_node_t synctex_node_sibling(synctex_node_t node) +{ + return SIBLING(node); +} +synctex_node_t synctex_node_next(synctex_node_t node) { + if(CHILD(node)) { + return CHILD(node); + } +sibling: + if(SIBLING(node)) { + return SIBLING(node); + } + if(node = PARENT(node)) { + if(node->class->type == synctex_node_type_sheet) {// EXC_BAD_ACCESS? + return NULL; + } + goto sibling; + } + return NULL; +} +#pragma mark - +#pragma mark CLASS + +/* Public node accessor: the type */ +synctex_node_type_t synctex_node_type(synctex_node_t node) { + if(node) { + return (((node)->class))->type; + } + return synctex_node_type_error; +} + +/* Public node accessor: the human readable type */ +const char * synctex_node_isa(synctex_node_t node) { +static const char * isa[synctex_node_type_last] = + {"Not a node","sheet","vbox","void vbox","hbox","void hbox","kern","glue","math","input"}; + return isa[synctex_node_type(node)]; +} + +# pragma mark - +# pragma mark LOG + +# define LOG(NODE) MSG_SEND(NODE,log) + +/* Public node logger */ +void synctex_node_log(synctex_node_t node) { + LOG(node); +} + +void _synctex_log_sheet(synctex_node_t sheet) { + if(sheet) { + printf("%s:%i\n",synctex_node_isa(sheet),INFO(sheet)[PAGE]); + printf("SELF:0x%x",sheet); + printf(" PARENT:0x%x",PARENT(sheet)); + printf(" CHILD:0x%x",CHILD(sheet)); + printf(" SIBLING:0x%x",SIBLING(sheet)); + printf(" FRIEND:0x%x\n",FRIEND(sheet)); + } +} + +void _synctex_log_medium_node(synctex_node_t node) { + printf("%s:%i,%i:%i,%i:%i\n", + synctex_node_isa(node), + INFO(node)[TAG], + INFO(node)[LINE], + INFO(node)[HORIZ], + INFO(node)[VERT], + INFO(node)[WIDTH]); + printf("SELF:0x%x",node); + printf(" PARENT:0x%x",PARENT(node)); + printf(" CHILD:0x%x",CHILD(node)); + printf(" SIBLING:0x%x",SIBLING(node)); + printf(" FRIEND:0x%x\n",FRIEND(node)); +} + +void _synctex_log_void_box(synctex_node_t node) { + int * info = INFO(node); + printf("%s",synctex_node_isa(node)); + printf(":%i",info[TAG]); + printf(",%i",info[LINE]); + printf(",%i",0); + printf(":%i",info[HORIZ]); + printf(",%i",info[VERT]); + printf(":%i",info[WIDTH]); + printf(",%i",info[HEIGHT]); + printf(",%i",info[DEPTH]); + printf("\nSELF:0x%x",node); + printf(" PARENT:0x%x",PARENT(node)); + printf(" CHILD:0x%x",CHILD(node)); + printf(" SIBLING:0x%x",SIBLING(node)); + printf(" FRIEND:0x%x\n",FRIEND(node)); +} + +void _synctex_log_box(synctex_node_t node) { + int * info = INFO(node); + printf("%s",synctex_node_isa(node)); + printf(":%i",info[TAG]); + printf(",%i",info[LINE]); + printf(",%i",0); + printf(":%i",info[HORIZ]); + printf(",%i",info[VERT]); + printf(":%i",info[WIDTH]); + printf(",%i",info[HEIGHT]); + printf(",%i",info[DEPTH]); + printf("\nSELF:0x%x",node); + printf(" PARENT:0x%x",PARENT(node)); + printf(" CHILD:0x%x",CHILD(node)); + printf(" SIBLING:0x%x",SIBLING(node)); + printf(" FRIEND:0x%x\n",FRIEND(node)); +} + +void _synctex_log_horiz_box(synctex_node_t node) { + int * info = INFO(node); + printf("%s",synctex_node_isa(node)); + printf(":%i",info[TAG]); + printf(",%i",info[LINE]); + printf(",%i",0); + printf(":%i",info[HORIZ]); + printf(",%i",info[VERT]); + printf(":%i",info[WIDTH]); + printf(",%i",info[HEIGHT]); + printf(",%i",info[DEPTH]); + printf(":%i",info[HORIZ_V]); + printf(",%i",info[VERT_V]); + printf(":%i",info[WIDTH_V]); + printf(",%i",info[HEIGHT_V]); + printf(",%i",info[DEPTH_V]); + printf("\nSELF:0x%x",node); + printf(" PARENT:0x%x",PARENT(node)); + printf(" CHILD:0x%x",CHILD(node)); + printf(" SIBLING:0x%x",SIBLING(node)); + printf(" FRIEND:0x%x\n",FRIEND(node)); +} + +void _synctex_log_input(synctex_node_t node) { + int * info = INFO(node); + printf("%s",synctex_node_isa(node)); + printf(":%i",info[TAG]); + printf(",%s",info[NAME]); + printf(" SIBLING:0x%x",SIBLING(node)); +} + +# define DISPLAY(NODE) MSG_SEND(NODE,display) + +void _synctex_display_sheet(synctex_node_t sheet) { + if(sheet) { + printf("....{%i\n",INFO(sheet)[PAGE]); + DISPLAY(CHILD(sheet)); + printf("....}\n"); + DISPLAY(SIBLING(sheet)); + } +} + +void _synctex_display_vbox(synctex_node_t node) { + printf("....[%i,%i:%i,%i:%i,%i,%i\n", + INFO(node)[TAG], + INFO(node)[LINE], + INFO(node)[HORIZ], + INFO(node)[VERT], + INFO(node)[WIDTH], + INFO(node)[HEIGHT], + INFO(node)[DEPTH]); + DISPLAY(CHILD(node)); + printf("....]\n"); + DISPLAY(SIBLING(node)); +} + +void _synctex_display_hbox(synctex_node_t node) { + printf("....(%i,%i:%i,%i:%i,%i,%i\n", + INFO(node)[TAG], + INFO(node)[LINE], + INFO(node)[HORIZ], + INFO(node)[VERT], + INFO(node)[WIDTH], + INFO(node)[HEIGHT], + INFO(node)[DEPTH]); + DISPLAY(CHILD(node)); + printf("....)\n"); + DISPLAY(SIBLING(node)); +} + +void _synctex_display_void_vbox(synctex_node_t node) { + printf("....v%i,%i;%i,%i:%i,%i,%i\n", + INFO(node)[TAG], + INFO(node)[LINE], + INFO(node)[HORIZ], + INFO(node)[VERT], + INFO(node)[WIDTH], + INFO(node)[HEIGHT], + INFO(node)[DEPTH]); + DISPLAY(SIBLING(node)); +} + +void _synctex_display_void_hbox(synctex_node_t node) { + printf("....h%i,%i:%i,%i:%i,%i,%i\n", + INFO(node)[TAG], + INFO(node)[LINE], + INFO(node)[HORIZ], + INFO(node)[VERT], + INFO(node)[WIDTH], + INFO(node)[HEIGHT], + INFO(node)[DEPTH]); + DISPLAY(SIBLING(node)); +} + +void _synctex_display_glue(synctex_node_t node) { + printf("....glue:%i,%i:%i,%i\n", + INFO(node)[TAG], + INFO(node)[LINE], + INFO(node)[HORIZ], + INFO(node)[VERT]); + DISPLAY(SIBLING(node)); +} + +void _synctex_display_math(synctex_node_t node) { + printf("....math:%i,%i:%i,%i\n", + INFO(node)[TAG], + INFO(node)[LINE], + INFO(node)[HORIZ], + INFO(node)[VERT]); + DISPLAY(SIBLING(node)); +} + +void _synctex_display_kern(synctex_node_t node) { + printf("....kern:%i,%i:%i,%i:%i\n", + INFO(node)[TAG], + INFO(node)[LINE], + INFO(node)[HORIZ], + INFO(node)[VERT], + INFO(node)[WIDTH]); + DISPLAY(SIBLING(node)); +} + +void _synctex_display_input(synctex_node_t node) { + printf("....Input:%i:%s\n", + INFO(node)[TAG], + INFO(node)[NAME]); + DISPLAY(SIBLING(node)); +} + +# pragma mark - +# pragma mark SCANNER + +#define SYNCTEX_NOERR 0 + +/* Used when parsing the synctex file. + * Advance to the next character starting a line. + * Actually, only \n is recognized as end of line marker. */ +int _synctex_next_line(synctex_scanner_t scanner) { + if(NULL == scanner) { + return -1; + } + while(PTR<END) { + if(*PTR == '\n') { + ++PTR; + return 0; + } + ++PTR; + } + return 1; +} + +/* Used when parsing the synctex file. + * Decode an integer. + * First file separators are skipped + */ +int _synctex_decode_int(synctex_scanner_t scanner, int* valueRef) { + if(NULL == scanner) return -1; + if(PTR>=END) return -1; + unsigned char * ptr = PTR; + if(*ptr==':' || *ptr==',') { + ++ptr; + } + unsigned char * end; + int result = (int)strtol((char *)ptr, (char **)&end, 10); + if(end>ptr) { + PTR = end; + if(valueRef) { + * valueRef = result; + } + return 0; + } + return -1; +} + +int _synctex_decode_string(synctex_scanner_t scanner, char ** valueRef) { + if(NULL == scanner || NULL == valueRef) return -1; + if(PTR>=END) return -1; + char * end = (char *)PTR; + while(end<(char *)END && *end != '\n') { + ++end; + } + size_t len = end - (char *)PTR; + if(* valueRef = malloc(len+1)) { + if(memcpy((*valueRef),(synctex_node_t)PTR,len)) { + (* valueRef)[len]='\0'; + PTR += len; + return 0; + } + free(* valueRef); + * valueRef = NULL; + } + return -1; +} + +/* Used when parsing the synctex file. + * Read an Input record. + */ +int _synctex_scan_input(synctex_scanner_t scanner) { + if(NULL == scanner) { + return -1; + } + if(0 == strncmp((char *)PTR,"Input:",6)) { + PTR += 6; + synctex_node_t input = _synctex_new_input(scanner); + if(_synctex_decode_int(scanner,INFO(input)+TAG) + || (++PTR,_synctex_decode_string(scanner,(char **)(INFO(input)+NAME))) + || _synctex_next_line(scanner)) { + FREE(input); + return -1; + } + SET_SIBLING(input,scanner->input) + scanner->input = input; + return 0; + } + return 1; +} + +/* Used when parsing the synctex file. + * Read the settings as part of the preamble. + */ +int _synctex_scan_settings(synctex_scanner_t scanner) { + if(NULL == scanner) { + return -1; + } + while(strncmp((char *)PTR,"Output:",7)) { + if(_synctex_next_line(scanner)) { + return -1; + } + } + PTR += 7; + if(_synctex_decode_string(scanner,&(scanner->output)) + || _synctex_next_line(scanner)) { + return -1; + } + while(strncmp((char *)PTR,"Magnification:",14)) { + if(_synctex_next_line(scanner)) { + return -1; + } + } + PTR += 14; + if(_synctex_decode_int(scanner,(int *)&(scanner->pre_magnification)) + || _synctex_next_line(scanner)) { + return -1; + } + while(strncmp((char *)PTR,"Unit:",5)) { + if(_synctex_next_line(scanner)) { + return -1; + } + } + PTR += 5; + if(_synctex_decode_int(scanner,(int *)&(scanner->pre_unit)) + || _synctex_next_line(scanner)) { + return -1; + } + while(strncmp((char *)PTR,"X Offset:",9)) { + if(_synctex_next_line(scanner)) { + return -1; + } + } + PTR += 9; + if(_synctex_decode_int(scanner,&(scanner->pre_x_offset)) + || _synctex_next_line(scanner)) { + return -1; + } + while(strncmp((char *)PTR,"Y Offset:",9)) { + if(_synctex_next_line(scanner)) { + return -1; + } + } + PTR += 9; + if(_synctex_decode_int(scanner,&(scanner->pre_y_offset)) + || _synctex_next_line(scanner)) { + return -1; + } + return 0; +} + +/* Used when parsing the synctex file. + * Read the preamplesss. + */ +int _synctex_scan_preamble(synctex_scanner_t scanner) { + if(NULL == scanner) { + return -1; + } + if(strncmp((char *)PTR,"SyncTeX Version:",1) + || ((PTR+=16),_synctex_decode_int(scanner,&(scanner->version))) + || _synctex_next_line(scanner)) { + return -1; + } + while(SYNCTEX_NOERR == _synctex_scan_input(scanner)) { + } + return _synctex_scan_settings(scanner); +} + +/* parse the post scriptum */ +#include "xlocale.h" +int _synctex_scan_post_scriptum(synctex_scanner_t scanner) { + while(strncmp((char *)PTR,"Post scriptum:",14)) { + if(_synctex_next_line(scanner)) { + return -1; + } + } + PTR += 14; + /* Scanning the information */ + /* initialize the offset with a fake value */ + scanner->x_offset = 6.027e23; + scanner->y_offset = scanner->x_offset; + /* By default, C programs start in the "C" locale + * But we are in a library, so we cannot assume that. */ + locale_t locale = newlocale(LC_ALL_MASK, NULL, NULL); + int status = 0; +next_record: + if(0 == strncmp((char *)PTR,"Magnification:",14)) { + PTR += 14; + if(PTR<END) { + scanner->unit = strtof_l((char *)PTR,(char **)&PTR,locale); +next_line: + status = _synctex_next_line(scanner); + if(status<0) { + freelocale(locale); + return -1; + } else if(0 == status) { + goto next_record; + } + } + freelocale(locale); + return 0; + } else if(0 == strncmp((char *)PTR,"X Offset:",9)) { + PTR += 9; + if(PTR<END) { + unsigned char * end = NULL; + float f = strtof_l((char *)PTR,(char **)&end,locale); + if(end>PTR) { + /* scan the x offset */ + //72/72.27/65536*16384+0.5; + PTR = end; + if(strncmp((char *)PTR,"in",2) == 0) { + f *= 72.27*65536; + } + else if(strncmp((char *)PTR,"cm",2) == 0) { + f *= 72.27*65536/2.54; + } + else if(strncmp((char *)PTR,"mm",2) == 0) { + f *= 72.27*65536/25.4; + } + else if(strncmp((char *)PTR,"pt",2) == 0) { + f *= 65536.0; + } + else if(strncmp((char *)PTR,"bp",2) == 0) { + f *= 72.27/72*65536; + } + else if(strncmp((char *)PTR,"pc",2) == 0) { + f *= 12.0*65536; + } + else if(strncmp((char *)PTR,"sp",2) == 0) { + f *= 1.0; + } + else if(strncmp((char *)PTR,"dd",2) == 0) { + f *= 1238.0/1157*65536; + } + else if(strncmp((char *)PTR,"cc",2) == 0) { + f *= 14856.0/1157*65536; + } + else if(strncmp((char *)PTR,"nd",2) == 0) { + f *= 685.0/642*65536; + } + else if(strncmp((char *)PTR,"nc",2) == 0) { + f *= 1370.0/107*65536; + } + else { + f *= 1.0; + PTR -= 2; + } + scanner->x_offset = f; + } + goto next_line; + } + freelocale(locale); + return 0; + } else if(0 == strncmp((char *)PTR,"Y Offset:",9)) { + PTR += 9; + if(PTR<END) { + unsigned char * end = NULL; + float f = strtof_l((char *)PTR,(char **)&end,locale); + if(end>PTR) { + /* scan the x offset */ + //72/72.27/65536*16384+0.5; + PTR = end; + if(strncmp((char *)PTR,"in",2) == 0) { + f *= 72.27*65536; + } + else if(strncmp((char *)PTR,"cm",2) == 0) { + f *= 72.27*65536/2.54; + } + else if(strncmp((char *)PTR,"mm",2) == 0) { + f *= 72.27*65536/25.4; + } + else if(strncmp((char *)PTR,"pt",2) == 0) { + f *= 65536.0; + } + else if(strncmp((char *)PTR,"bp",2) == 0) { + f *= 72.27/72*65536; + } + else if(strncmp((char *)PTR,"pc",2) == 0) { + f *= 12.0*65536; + } + else if(strncmp((char *)PTR,"sp",2) == 0) { + f *= 1.0; + } + else if(strncmp((char *)PTR,"dd",2) == 0) { + f *= 1238.0/1157*65536; + } + else if(strncmp((char *)PTR,"cc",2) == 0) { + f *= 14856.0/1157*65536; + } + else if(strncmp((char *)PTR,"nd",2) == 0) { + f *= 685.0/642*65536; + } + else if(strncmp((char *)PTR,"nc",2) == 0) { + f *= 1370.0/107*65536; + } + else { + f *= 1.0; + PTR -= 2; + } + scanner->y_offset = f; + } + goto next_line; + } + freelocale(locale); + return 0; + } + goto next_line; +} + +int _synctex_scan_postamble(synctex_scanner_t scanner) { + if(NULL == scanner) { + return -1; + } + if(strncmp((char *)PTR,"Postamble:",10) + || ((PTR += 10),_synctex_next_line(scanner))) { + return -1; + } + if(!strncmp((char *)PTR,"Count:",6)) { + PTR += 6; + if(_synctex_decode_int(scanner,&(scanner->count)) + || _synctex_next_line(scanner)) { + return -1; + } + } + while(_synctex_scan_post_scriptum(scanner)) { + if(_synctex_next_line(scanner)) { + return -1; + } + } + return 0; +} + +/* Horizontal boxes also have visible size. + * Visible size are bigger than real size. + * For example 0 width boxes may contain text. + * At creation time, the visible size is set to the values of the real size. + */ +int _synctex_setup_visible_box(synctex_node_t box) { + if(NULL == box || box->class->type != synctex_node_type_hbox) { + return -1; + } + int * info = INFO(box); + if(info) { + info[HORIZ_V] = info[HORIZ]; + info[VERT_V] = info[VERT]; + info[WIDTH_V] = info[WIDTH]; + info[HEIGHT_V] = info[HEIGHT]; + info[DEPTH_V] = info[DEPTH]; + return 0; + } + return -1; +} + +/* This method is sent to an horizontal box to setup the visible size + * Some box have 0 width but do contain text material. + * With this method, one can enlarge the box to contain the given point (h,v). + */ +int _synctex_horiz_box_setup_visible(synctex_node_t node,int h, int v) { + if(NULL == node || node->class->type != synctex_node_type_hbox) { + return -1; + } + int * itsINFO = INFO(node); + int itsBtm, itsTop; + if(itsINFO[WIDTH_V]<0) { + itsBtm = itsINFO[HORIZ_V]+itsINFO[WIDTH_V]; + itsTop = itsINFO[HORIZ_V]; + if(h<itsBtm) { + itsBtm -= h; + itsINFO[WIDTH_V] -= itsBtm; + } + if(h>itsTop) { + h -= itsTop; + itsINFO[WIDTH_V] -= h; + itsINFO[HORIZ_V] += h; + } + } else { + itsBtm = itsINFO[HORIZ_V]; + itsTop = itsINFO[HORIZ_V]+itsINFO[WIDTH_V]; + if(h<itsBtm) { + itsBtm -= h; + itsINFO[HORIZ_V] -= itsBtm; + itsINFO[WIDTH_V] += itsBtm; + } + if(h>itsTop) { + h -= itsTop; + itsINFO[WIDTH_V] += h; + } + } + return 0; +} + +/* Used when parsing the synctex file. + * The parent is a newly created sheet node that will hold the contents. + * Something is returned in case of error. + */ +int _synctex_scan_sheet(synctex_scanner_t scanner, synctex_node_t parent) { + if((NULL == scanner) || (NULL == parent))return -1; + synctex_node_t child = NULL; + synctex_node_t sibling = NULL; + int friend_index = 0; + int * info = NULL; + int curh, curv; +vertical_loop: + if(PTR<END) { + if(*PTR == '[') { + ++PTR; + if((child = _synctex_new_vbox(scanner)) && (info = INFO(child))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_decode_int(scanner,(int*)(info+HEIGHT)) + || _synctex_decode_int(scanner,(int*)(info+DEPTH)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_CHILD(parent,child); + parent = child; + child = NULL; + goto vertical_loop; + } else { + return -1; + } + } else if(*PTR == ']') { + ++PTR; + if(parent && parent->class->type == synctex_node_type_vbox) { + #define UPDATE_BOX_FRIEND(NODE)\ + friend_index = ((INFO(NODE))[TAG]+(INFO(NODE))[LINE])%(scanner->number_of_lists);\ + SET_FRIEND(NODE,(scanner->lists_of_friends)[friend_index]);\ + (scanner->lists_of_friends)[friend_index] = NODE; + if(NULL == CHILD(parent)) { + /* only void boxes are friends */ + UPDATE_BOX_FRIEND(parent); + } + child = parent; + parent = PARENT(child); + } else { + printf("Unexpected ]\n"); + } + if(_synctex_next_line(scanner)) { + return -1; + } + goto horizontal_loop; + } else if(*PTR == '(') { + ++PTR; + if((child = _synctex_new_hbox(scanner)) && (info = INFO(child))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_decode_int(scanner,(int*)(info+HEIGHT)) + || _synctex_decode_int(scanner,(int*)(info+DEPTH)) + || _synctex_setup_visible_box(child) + || _synctex_next_line(scanner)) { + return -1; + } + SET_CHILD(parent,child); + parent = child; + child = NULL; + goto vertical_loop; + } else { + return -1; + } + } else if(*PTR == ')') { + ++PTR; + if(parent && parent->class->type == synctex_node_type_hbox) { + if(NULL == child) { + UPDATE_BOX_FRIEND(parent); + } + child = parent; + parent = PARENT(child); + } else { + printf("Unexpected )\n"); + } + if(_synctex_next_line(scanner)) { + return -1; + } + goto horizontal_loop; + } else if(*PTR == 'v') { + ++PTR; + if((child = _synctex_new_void_vbox(scanner)) && (info = INFO(child))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_decode_int(scanner,(int*)(info+HEIGHT)) + || _synctex_decode_int(scanner,(int*)(info+DEPTH)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_CHILD(parent,child); + #define UPDATE_FRIEND(NODE)\ + friend_index = (info[TAG]+info[LINE])%(scanner->number_of_lists);\ + SET_FRIEND(NODE,(scanner->lists_of_friends)[friend_index]);\ + (scanner->lists_of_friends)[friend_index] = NODE; + UPDATE_FRIEND(child); + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == 'h') { + ++PTR; + if((child = _synctex_new_void_hbox(scanner)) && (info = INFO(child))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_decode_int(scanner,(int*)(info+HEIGHT)) + || _synctex_decode_int(scanner,(int*)(info+DEPTH)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_CHILD(parent,child); + UPDATE_FRIEND(child); + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child)+synctex_node_width(child),synctex_node_v(child)); + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == 'k') { + ++PTR; + if((child = _synctex_new_kern(scanner)) && (info = INFO(child))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_CHILD(parent,child); + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); + UPDATE_FRIEND(child); + if(!parent) { + printf("Child is:"); + synctex_node_log(child); + return -1; + } + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == 'x') { + ++PTR; + if(_synctex_decode_int(scanner,NULL) + || _synctex_decode_int(scanner,NULL) + || _synctex_decode_int(scanner,&curh) + || _synctex_decode_int(scanner,&curv) + || _synctex_next_line(scanner)) { + return -1; + } + _synctex_horiz_box_setup_visible(parent,curh,curv); + goto vertical_loop; + } else if(*PTR == 'g') { + ++PTR; + if((child = _synctex_new_glue(scanner)) && (info = INFO(child))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_CHILD(parent,child); + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); + UPDATE_FRIEND(child); + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == '$') { + ++PTR; + if((child = _synctex_new_math(scanner)) && (info = INFO(child))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_CHILD(parent,child); + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); + UPDATE_FRIEND(child); + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == '}') { + ++PTR; + if(!parent || parent->class->type != synctex_node_type_sheet + || _synctex_next_line(scanner)) { + return -1; + } + return 0; + } else if(*PTR == '!') { + ++PTR; + if(_synctex_next_line(scanner)) { + return -1; + } + goto vertical_loop; + } else { + printf("Ignored:<%c>\n",*PTR); + ++PTR; + if(_synctex_next_line(scanner)) { + return -1; + } + goto vertical_loop; + } + } else { + return -1; + } + synctex_bail(); +horizontal_loop: + if(PTR<END) { + if(*PTR == '[') { + ++PTR; + if((sibling = _synctex_new_vbox(scanner)) && (info = INFO(sibling))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_decode_int(scanner,(int*)(info+HEIGHT)) + || _synctex_decode_int(scanner,(int*)(info+DEPTH)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_SIBLING(child,sibling); + parent = sibling; + child = NULL; + goto vertical_loop; + } else { + return -1; + } + } else if(*PTR == ']') { + ++PTR; + if(parent && parent->class->type == synctex_node_type_vbox) { + if(NULL == child) { + UPDATE_BOX_FRIEND(parent); + } + child = parent; + parent = PARENT(child); + } else { + printf("Unexpected ]\n"); + } + if(_synctex_next_line(scanner)) { + return -1; + } + goto horizontal_loop; + } else if(*PTR == '(') { + ++PTR; + if((sibling = _synctex_new_hbox(scanner)) && (info = INFO(sibling))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_decode_int(scanner,(int*)(info+HEIGHT)) + || _synctex_decode_int(scanner,(int*)(info+DEPTH)) + || _synctex_setup_visible_box(sibling) + || _synctex_next_line(scanner)) { + return -1; + } + SET_SIBLING(child,sibling); + parent = sibling; + child = NULL; + goto vertical_loop; + } else { + return -1; + } + } else if(*PTR == ')') { + ++PTR; + if(parent && parent->class->type == synctex_node_type_hbox) { + if(NULL == child) { + UPDATE_BOX_FRIEND(parent); + } + child = parent; + parent = PARENT(child); + } else { + printf("Unexpected )\n"); + } + if(_synctex_next_line(scanner)) { + LOG(child); + return -1; + } + goto horizontal_loop; + } else if(*PTR == 'v') { + ++PTR; + if((sibling = _synctex_new_void_vbox(scanner)) && (info = INFO(sibling))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_decode_int(scanner,(int*)(info+HEIGHT)) + || _synctex_decode_int(scanner,(int*)(info+DEPTH)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_SIBLING(child,sibling); + UPDATE_FRIEND(sibling); + child = sibling; + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == 'h') { + ++PTR; + if((sibling = _synctex_new_void_hbox(scanner)) && (info = INFO(sibling))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_decode_int(scanner,(int*)(info+HEIGHT)) + || _synctex_decode_int(scanner,(int*)(info+DEPTH)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_SIBLING(child,sibling); + UPDATE_FRIEND(sibling); + child = sibling; + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child)+synctex_node_width(child),synctex_node_v(child)); + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == 'x') { + ++PTR; + if(_synctex_decode_int(scanner,NULL) + || _synctex_decode_int(scanner,NULL) + || _synctex_decode_int(scanner,&curh) + || _synctex_decode_int(scanner,&curv) + || _synctex_next_line(scanner)) { + return -1; + } + _synctex_horiz_box_setup_visible(parent,curh,curv); + goto horizontal_loop; + } else if(*PTR == 'k') { + ++PTR; + if((sibling = _synctex_new_kern(scanner)) && (info = INFO(sibling))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_decode_int(scanner,(int*)(info+WIDTH)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_SIBLING(child,sibling); + UPDATE_FRIEND(sibling); + child = sibling; + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == 'g') { + ++PTR; + if((sibling = _synctex_new_glue(scanner)) && (info = INFO(sibling))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_SIBLING(child,sibling); + UPDATE_FRIEND(sibling); + child = sibling; + _synctex_horiz_box_setup_visible(parent,synctex_node_h(child),synctex_node_v(child)); + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == '$') { + ++PTR; + if((sibling = _synctex_new_math(scanner)) && (info = INFO(sibling))) { + if(_synctex_decode_int(scanner,(int*)(info+TAG)) + || _synctex_decode_int(scanner,(int*)(info+LINE)) + || _synctex_decode_int(scanner,(int*)(info+HORIZ)) + || _synctex_decode_int(scanner,(int*)(info+VERT)) + || _synctex_next_line(scanner)) { + return -1; + } + SET_SIBLING(child,sibling); + _synctex_horiz_box_setup_visible(parent,synctex_node_h(sibling),synctex_node_v(sibling)); + UPDATE_FRIEND(sibling); + child = sibling; + goto horizontal_loop; + } else { + return -1; + } + } else if(*PTR == '}') { + ++PTR; + if(!parent || parent->class->type != synctex_node_type_sheet + || _synctex_next_line(scanner)) { + return -1; + } + return 0; + } else if(*PTR == '!') { + ++PTR; + if(_synctex_next_line(scanner)) { + return -1; + } + goto horizontal_loop; + } else { + printf("SyncTeX: Ignored record %c\n",*PTR); + if(_synctex_next_line(scanner)) { + return -1; + } + goto horizontal_loop; + } + } else { + return -1; + } +} + +/* Used when parsing the synctex file + */ +int _synctex_scan_content(synctex_scanner_t scanner) { + if(NULL == scanner) { + return -1; + } + /* set up the lists of friends */ + if(NULL == scanner->lists_of_friends) { + scanner->number_of_lists = 1024; + scanner->lists_of_friends = (synctex_node_t *)_synctex_malloc(scanner->number_of_lists*sizeof(synctex_node_t)); + if(NULL == scanner->lists_of_friends) { + printf("malloc:2\n"); + return -1; + } + } + /* Find where this section starts */ + while(strncmp((char *)PTR,"Content:",8)) { + if(_synctex_next_line(scanner)) { + return -1; + } + } + PTR += 8; + if(_synctex_next_line(scanner)) { + return -1; + } +next_sheet: + if(*PTR != '{') { + if(_synctex_scan_postamble(scanner)) { + if(_synctex_next_line(scanner)) { + return -1; + } + goto next_sheet; + } + return 0; + } + ++PTR; + /* Create a new sheet node */ + synctex_node_t sheet = _synctex_new_sheet(scanner); + if(_synctex_decode_int(scanner,INFO(sheet)+PAGE) + || _synctex_next_line(scanner)) { +bail: + FREE(sheet); + return -1; + } + if(_synctex_scan_sheet(scanner,sheet)) { + goto bail; + } + SET_SIBLING(sheet,scanner->sheet); + scanner->sheet = sheet; + while(SYNCTEX_NOERR == _synctex_scan_input(scanner)) { + } + goto next_sheet; +} + +/* Where the synctex scanner is created. + * name is the full path of the synctex file. */ +synctex_scanner_t synctex_scanner_new_with_contents_of_file(const char * name) { + synctex_scanner_t scanner = (synctex_scanner_t)_synctex_malloc(sizeof(_synctex_scanner_t)); + if(NULL == scanner) { + return NULL; + } + scanner->pre_magnification = 1000; + scanner->pre_unit = 8192; + scanner->pre_x_offset = scanner->pre_y_offset = 578; + scanner->class[synctex_node_type_sheet] = synctex_class_sheet; + (scanner->class[synctex_node_type_sheet]).scanner = scanner; + scanner->class[synctex_node_type_vbox] = synctex_class_vbox; + (scanner->class[synctex_node_type_vbox]).scanner = scanner; + scanner->class[synctex_node_type_void_vbox] = synctex_class_void_vbox; + (scanner->class[synctex_node_type_void_vbox]).scanner = scanner; + scanner->class[synctex_node_type_hbox] = synctex_class_hbox; + (scanner->class[synctex_node_type_hbox]).scanner = scanner; + scanner->class[synctex_node_type_void_hbox] = synctex_class_void_hbox; + (scanner->class[synctex_node_type_void_hbox]).scanner = scanner; + scanner->class[synctex_node_type_kern] = synctex_class_kern; + (scanner->class[synctex_node_type_kern]).scanner = scanner; + scanner->class[synctex_node_type_glue] = synctex_class_glue; + (scanner->class[synctex_node_type_glue]).scanner = scanner; + scanner->class[synctex_node_type_math] = synctex_class_math; + (scanner->class[synctex_node_type_math]).scanner = scanner; + scanner->class[synctex_node_type_input] = synctex_class_input; + (scanner->class[synctex_node_type_input]).scanner = scanner; + + FILE * F = fopen(name,"r"); + if(NULL == F) { + printf("SyncTeX: could not open %s, error %i\n",name,errno); +bail: + synctex_scanner_free(scanner); + return NULL; + } + if(fseek(F, 0, SEEK_END)) { + close(F); + goto bail; + } + size_t size = ftell(F); + rewind(F); + START = (unsigned char *)malloc(size+1); + if(NULL == START) { + printf("malloc error\n"); + close(F); + goto bail; + } + if(size != fread((void *)START, 1, size, F)) { +bailey: + close(F); + goto bail; + } + close(F); + START[size] = '\0'; /* ensure null termination */ + /* first read the beginning */ + END = START + size; + PTR = START; + if(_synctex_scan_preamble(scanner) + || _synctex_scan_content(scanner)) { + goto bailey; + } + free((void *)START); + START = PTR = END = NULL; + /* Everything is finished, final tuning */ + /* 1 pre_unit = (scanner->pre_unit)/65536 pt = (scanner->pre_unit)/65781.76 bp + * 1 pt = 65536 sp */ + if(scanner->pre_unit<=0) { + scanner->pre_unit = 8192; + } + if(scanner->pre_magnification<=0) { + scanner->pre_magnification = 1000; + } + if(scanner->unit <= 0) { + /* no post magnification */ + scanner->unit = scanner->pre_unit / 65781.76;/* 65781.76 or 65536.0*/ + } else { + /* post magnification */ + scanner->unit *= scanner->pre_unit / 65781.76; + } + scanner->unit *= scanner->pre_magnification / 1000.0; + if(scanner->x_offset > 6e23) { + /* no post offset */ + scanner->x_offset = scanner->pre_x_offset * (scanner->pre_unit / 65781.76); + scanner->y_offset = scanner->pre_y_offset * (scanner->pre_unit / 65781.76); + } else { + /* post offset */ + scanner->x_offset /= 65781.76; + scanner->y_offset /= 65781.76; + } + return scanner; +} + +/* The scanner destructor + */ +void synctex_scanner_free(synctex_scanner_t scanner) { + if(NULL == scanner) { + return; + } + FREE(scanner->sheet); + free(START); + free(scanner->output); + free(scanner->input); + free(scanner->lists_of_friends); + free(scanner); +} + +/* Scanner accessors. + */ +int synctex_scanner_pre_x_offset(synctex_scanner_t scanner){ + return scanner?scanner->pre_x_offset:0; +} +int synctex_scanner_pre_y_offset(synctex_scanner_t scanner){ + return scanner?scanner->pre_y_offset:0; +} +int synctex_scanner_x_offset(synctex_scanner_t scanner){ + return scanner?scanner->x_offset:0; +} +int synctex_scanner_y_offset(synctex_scanner_t scanner){ + return scanner?scanner->y_offset:0; +} +float synctex_scanner_magnification(synctex_scanner_t scanner){ + return scanner?scanner->unit:1; +} +void synctex_scanner_display(synctex_scanner_t scanner) { + if(NULL == scanner) { + return; + } + printf("The scanner:\noutput:%s\nversion:%i\n",scanner->output,scanner->version); + printf("pre_unit:%i\nx_offset:%i\nx_offset:%i\n",scanner->pre_unit,scanner->pre_x_offset,scanner->pre_y_offset); + printf("count:%i\npost_magnification:%f\npost_x_offset:%i\npost_x_offset:%i\n", + scanner->count,scanner->unit,scanner->x_offset,scanner->y_offset); + printf("The input:\n"); + DISPLAY(scanner->input); + if(scanner->count<1000) { + printf("The sheets:\n"); + DISPLAY(scanner->sheet); + printf("The friends:\n"); + if(scanner->lists_of_friends) { + int i = scanner->number_of_lists; + synctex_node_t node; + while(i--) { + printf("Friend index:%i\n",i); + node = (scanner->lists_of_friends)[i]; + while(node) { + printf("%s:%i,%i\n", + synctex_node_isa(node), + INFO(node)[TAG], + INFO(node)[LINE] + ); + node = FRIEND(node); + } + } + } + } else { + printf("Too many objects"); + } +} +/* Public*/ +const char * synctex_scanner_get_name(synctex_scanner_t scanner,int tag) { + if(NULL == scanner) { + return ""; + } + synctex_node_t input = scanner->input; + do { + if(tag == INFO(input)[TAG]) { + return (char *)(INFO(input)[NAME]); + } + } while(input = SIBLING(input)); + return 0; +} +int synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name) { + if(NULL == scanner) { + return 0; + } + synctex_node_t input = scanner->input; + do { + if((strlen(name) == strlen((char *)(INFO(input)[NAME]))) && + (0 == strncmp(name,(char *)(INFO(input)[NAME]),strlen(name)))) { + return INFO(input)[TAG]; + } + } while(input = SIBLING(input)); + return 0; +} +synctex_node_t synctex_scanner_input(synctex_scanner_t scanner) { + return scanner?scanner->input:NULL; +} +#pragma mark - +#pragma mark Public node attributes +float synctex_node_h(synctex_node_t node){ + if(!node) { + return 0; + } + return (float)INFO(node)[HORIZ]; +} +float synctex_node_v(synctex_node_t node){ + if(!node) { + return 0; + } + return (float)INFO(node)[VERT]; +} +float synctex_node_width(synctex_node_t node){ + if(!node) { + return 0; + } + return (float)INFO(node)[WIDTH]; +} +float synctex_node_box_h(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type != synctex_node_type_vbox) + && (node->class->type != synctex_node_type_void_vbox) + && (node->class->type != synctex_node_type_hbox) + && (node->class->type != synctex_node_type_void_hbox)) { + node = PARENT(node); + } + return (node->class->type == synctex_node_type_sheet)?0:(float)(INFO(node)[HORIZ]); +} +float synctex_node_box_v(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type != synctex_node_type_vbox) + && (node->class->type != synctex_node_type_void_vbox) + && (node->class->type != synctex_node_type_hbox) + && (node->class->type != synctex_node_type_void_hbox)) { + node = PARENT(node); + } + return (node->class->type == synctex_node_type_sheet)?0:(float)(INFO(node)[VERT]); +} +float synctex_node_box_width(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type != synctex_node_type_vbox) + && (node->class->type != synctex_node_type_void_vbox) + && (node->class->type != synctex_node_type_hbox) + && (node->class->type != synctex_node_type_void_hbox)) { + node = PARENT(node); + } + return (node->class->type == synctex_node_type_sheet)?0:(float)(INFO(node)[WIDTH]); +} +float synctex_node_box_height(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type != synctex_node_type_vbox) + && (node->class->type != synctex_node_type_void_vbox) + && (node->class->type != synctex_node_type_hbox) + && (node->class->type != synctex_node_type_void_hbox)) { + node = PARENT(node); + } + return (node->class->type == synctex_node_type_sheet)?0:(float)(INFO(node)[HEIGHT]); +} +float synctex_node_box_depth(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type != synctex_node_type_vbox) + && (node->class->type != synctex_node_type_void_vbox) + && (node->class->type != synctex_node_type_hbox) + && (node->class->type != synctex_node_type_void_hbox)) { + node = PARENT(node); + } + return (node->class->type == synctex_node_type_sheet)?0:(float)(INFO(node)[DEPTH]); +} +#pragma mark - +#pragma mark Public node visible attributes +float synctex_node_visible_h(synctex_node_t node){ + if(!node) { + return 0; + } + return INFO(node)[HORIZ]*node->class->scanner->unit+node->class->scanner->x_offset; +} +float synctex_node_visible_v(synctex_node_t node){ + if(!node) { + return 0; + } + return INFO(node)[VERT]*node->class->scanner->unit+node->class->scanner->y_offset; +} +float synctex_node_visible_width(synctex_node_t node){ + if(!node) { + return 0; + } + return INFO(node)[WIDTH]*node->class->scanner->unit; +} +float synctex_node_box_visible_h(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type == synctex_node_type_vbox) + || (node->class->type == synctex_node_type_void_hbox) + || (node->class->type == synctex_node_type_void_vbox)) { +result: + return INFO(node)[WIDTH]<0? + (INFO(node)[HORIZ]+INFO(node)[WIDTH])*node->class->scanner->unit+node->class->scanner->x_offset: + INFO(node)[HORIZ]*node->class->scanner->unit+node->class->scanner->x_offset; + } + if(node->class->type != synctex_node_type_hbox) { + node = PARENT(node); + } + if(node->class->type == synctex_node_type_sheet) { + return 0; + } + if(node->class->type == synctex_node_type_vbox) { + goto result; + } + return INFO(node)[WIDTH_V]<0? + (INFO(node)[HORIZ_V]+INFO(node)[WIDTH_V])*node->class->scanner->unit+node->class->scanner->x_offset: + INFO(node)[HORIZ_V]*node->class->scanner->unit+node->class->scanner->x_offset; +} +float synctex_node_box_visible_v(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type == synctex_node_type_vbox) + || (node->class->type == synctex_node_type_void_hbox) + || (node->class->type == synctex_node_type_void_vbox)) { +result: + return (float)(INFO(node)[VERT])*node->class->scanner->unit+node->class->scanner->y_offset; + } + if((node->class->type != synctex_node_type_vbox) + && (node->class->type != synctex_node_type_hbox)) { + node = PARENT(node); + } + if(node->class->type == synctex_node_type_sheet) { + return 0; + } + if(node->class->type == synctex_node_type_vbox) { + goto result; + } + return INFO(node)[VERT_V]*node->class->scanner->unit+node->class->scanner->y_offset; +} +float synctex_node_box_visible_width(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type == synctex_node_type_vbox) + || (node->class->type == synctex_node_type_void_hbox) + || (node->class->type == synctex_node_type_void_vbox)) { +result: + return INFO(node)[WIDTH]<0? + -INFO(node)[WIDTH]*node->class->scanner->unit: + INFO(node)[WIDTH]*node->class->scanner->unit; + } + if(node->class->type != synctex_node_type_hbox) { + node = PARENT(node); + } + if(node->class->type == synctex_node_type_sheet) { + return 0; + } + if(node->class->type == synctex_node_type_vbox) { + goto result; + } + return INFO(node)[WIDTH_V]<0? + -INFO(node)[WIDTH_V]*node->class->scanner->unit: + INFO(node)[WIDTH_V]*node->class->scanner->unit; +} +float synctex_node_box_visible_height(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type == synctex_node_type_vbox) + || (node->class->type == synctex_node_type_void_hbox) + || (node->class->type == synctex_node_type_void_vbox)) { +result: + return (float)(INFO(node)[HEIGHT])*node->class->scanner->unit; + } + if(node->class->type != synctex_node_type_hbox) { + node = PARENT(node); + } + if(node->class->type == synctex_node_type_sheet) { + return 0; + } + if(node->class->type == synctex_node_type_vbox) { + goto result; + } + return INFO(node)[HEIGHT_V]*node->class->scanner->unit; +} +float synctex_node_box_visible_depth(synctex_node_t node){ + if(!node) { + return 0; + } + if((node->class->type == synctex_node_type_vbox) + || (node->class->type == synctex_node_type_void_hbox) + || (node->class->type == synctex_node_type_void_vbox)) { +result: + return (float)(INFO(node)[DEPTH])*node->class->scanner->unit; + } + if(node->class->type != synctex_node_type_hbox) { + node = PARENT(node); + } + if(node->class->type == synctex_node_type_sheet) { + return 0; + } + if(node->class->type == synctex_node_type_vbox) { + goto result; + } + return INFO(node)[DEPTH_V]*node->class->scanner->unit; +} +#pragma mark - +#pragma mark Other public node attributes +int synctex_node_page(synctex_node_t node){ + if(!node) { + return -1; + } + synctex_node_t parent = PARENT(node); + while(parent) { + node = parent; + parent = PARENT(node); + } + if(node->class->type == synctex_node_type_sheet) { + return INFO(node)[PAGE]; + } + return -1; +} +int synctex_node_tag(synctex_node_t node) { + return node?INFO(node)[TAG]:-1; +} +int synctex_node_line(synctex_node_t node) { + return node?INFO(node)[LINE]:-1; +} +int synctex_node_column(synctex_node_t node) { + return -1; +} +#pragma mark - +#pragma mark Query + +synctex_node_t synctex_sheet_content(synctex_scanner_t scanner,int page) { + if(scanner) { + synctex_node_t sheet = scanner->sheet; + while(sheet) { + if(page == INFO(sheet)[PAGE]) { + return CHILD(sheet); + } + sheet = SIBLING(sheet); + } + } + return NULL; +} + +int synctex_display_query(synctex_scanner_t scanner,const char * name,int line,int column) { + int tag = synctex_scanner_get_tag(scanner,name); + if(tag == 0) { + printf("No tag for %s\n",name); + return -1; + } + free(START); + PTR = END = START = NULL; + size_t size = 0; + int friend_index = (tag+line)%(scanner->number_of_lists); + synctex_node_t node = (scanner->lists_of_friends)[friend_index]; + while(node) { + if((tag == INFO(node)[TAG]) && (line == INFO(node)[LINE])) { + if(PTR == END) { + size += 16; + END = realloc(START,size*sizeof(synctex_node_t *)); + PTR += END - START; + START = END; + END = START + size*sizeof(synctex_node_t *); + } + *(int *)PTR = (int)node; + PTR += sizeof(int); + } + node = FRIEND(node); + } + END = PTR; + PTR = NULL; + return END-START; +} + +int _synctex_node_is_box(synctex_node_t node) { + switch(synctex_node_type(node)) { + case synctex_node_type_hbox: + case synctex_node_type_void_hbox: + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + return -1; + } + return 0; +} + +int _synctex_point_in_visible_box(float h, float v, synctex_node_t node) { + if(_synctex_node_is_box(node)) { + v -= synctex_node_box_visible_v(node); + if((v<=-synctex_node_box_visible_height(node) + && v>=synctex_node_box_visible_depth(node)) + || (v>=-synctex_node_box_visible_height(node) + && v<= synctex_node_box_visible_depth(node))) { + h -= synctex_node_box_visible_h(node); + if((h<=0 && h>=synctex_node_box_visible_width(node)) + || (h>=0 && h<=synctex_node_box_visible_width(node))) { + return -1; + } + } + } + return 0; +} + +int synctex_edit_query(synctex_scanner_t scanner,int page,float h,float v) { + if(NULL == scanner) { + return 0; + } + free(START); + START = END = PTR = NULL; + synctex_node_t sheet = scanner->sheet; + while(INFO(sheet)[PAGE] != page) { + sheet = SIBLING(sheet); + } + if(NULL == sheet) { + return -1; + } + /* Now sheet points to the sheet node with proper page number */ + /* Declare memory storage, a buffer to hold found nodes */ + synctex_node_t * start = NULL; + synctex_node_t * end = NULL; + synctex_node_t * ptr = NULL; + size_t size = 0; + synctex_node_t node = CHILD(sheet); /* start with the child of the sheet */ + synctex_node_t next; +has_node_any_child: + if(next = CHILD(node)) { + /* node is a non void box */ + if(_synctex_point_in_visible_box(h,v,node)) { + /* we found a non void box containing the point */ + if(ptr == end) { + /* not enough room to store the result, add 16 more node records */ + size += 16; + end = realloc(start,size*sizeof(synctex_node_t)); + if(end == NULL) { + return -1; + } + ptr += end - start; + start = end; + end = start + size; + } + *ptr = node; + /* Does an included box also contain the hit point? + * If this is the case, ptr will be overriden later + * This is why we do not increment ptr yet. + * ptr will be incremented (registered) later if + * no enclosing box contains the hit point */ + } + node = next; + goto has_node_any_child; + } + /* node has no child */ +node_has_no_child: + if(_synctex_point_in_visible_box(h,v,node)) { + /* we found a void box containing the hit point */ + if(ptr == end) { + /* not enough room to store the result, add 16 more node records */ + size += 16; + end = realloc(start,size*sizeof(synctex_node_t)); + if(end == NULL) { + return -1; + } + ptr += end - start; + start = end; + end = start + size*sizeof(synctex_node_t); + } + *ptr = node; + /* Increment ptr to definitely register the node */ + ++ptr; + /* Ensure that it is the last node */ + *ptr = NULL; + } +next_sibling: + if(next = SIBLING(node)) { + node = next; + goto has_node_any_child; + } + /* This is the last node at this level + * The next step is the parent's sibling */ + next = PARENT(node); + if(ptr && *ptr == next) { + /* No included box does contain the point + * next was already tagged to contain the hit point + * but was not fully registered at that time, now we can increment ptr */ + ++ptr; + *ptr = NULL; + } else if(next == sheet) { +we_are_done: + end = ptr; + ptr = NULL; + /* Up to now, we have found a list of boxes enclosing the hit point. */ + if(end == start) { + /* No match found */ + return 0; + } + /* If there are many different boxes containing the hit point, put the smallest one front. + * This is in general the expected box in LaTeX picture environment. */ + ptr = start; + node = *ptr; + float best = synctex_node_box_visible_width(node); + float candidate; + synctex_node_t * best_node_ref = NULL; + while(node = *(++ptr)) { + candidate = synctex_node_box_visible_width(node); + if(candidate<best) { + best = candidate; + best_node_ref = ptr; + } + } + if(best_node_ref) { + node = *best_node_ref; + *best_node_ref = *start; + *start = node; + } + /* We do need to check children to find out the node closest to the hit point. + * Working with boxes is not very accurate because in general boxes are created asynchronously. + * The glue, kern, math are more appropriate for synchronization. */ + if(node = CHILD(*start)) { + best = INFINITY; + synctex_node_t best_node = NULL; + do { + switch((node->class)->type) { + default: + candidate = fabsf(synctex_node_visible_h(node)-h); + if(candidate<best) { + best = candidate; + best_node = node; + } + case synctex_node_type_hbox: + case synctex_node_type_vbox: + break; + } + } while(node = SIBLING(node)); + if(best_node) { + if(START = malloc(sizeof(synctex_node_t))) { + * (synctex_node_t *)START = best_node; + END = START + sizeof(synctex_node_t); + PTR = NULL; + free(start); + return (END-START)/sizeof(synctex_node_t); + } + } + } + START = (unsigned char *)start; + END = (unsigned char *)end; + PTR = NULL; + return (END-START)/sizeof(synctex_node_t); + } else if(NULL == next) { + /* What? a node with no parent? */ + printf("This is an error\n"); + goto we_are_done; + } + node = next; + goto next_sibling; +} + +synctex_node_t synctex_next_result(synctex_scanner_t scanner) { + if(NULL == PTR) { + PTR = START; + } else { + PTR+=sizeof(synctex_node_t); + } + if(PTR<END) { + return *(synctex_node_t*)PTR; + } else { + return NULL; + } +} + +int synctex_bail(void) { + printf("*** ERROR\n"); + return -1; +} +#pragma mark - +#pragma mark TESTS +/* This is not public, it is not up to date */ +synctex_scanner_t synctex_scanner_new_with_data(const void * bytes, unsigned int length) { + synctex_scanner_t scanner = (synctex_scanner_t)_synctex_malloc(sizeof(_synctex_scanner_t)); + if(NULL != scanner) { + START = (void *)bytes; + if(UINT_MAX-length<(int)(START)) { +bail: + free(scanner); + return NULL; + } + END = START+length; + scanner->pre_unit = 8192; + scanner->pre_x_offset = scanner->pre_y_offset = 578; + unsigned char the_char; + if(_synctex_scan_preamble(scanner)) { + goto bail; + } + do { + if(the_char == '{') { + if(_synctex_scan_content(scanner)) { + goto bail; + } + break; + } + } while(SYNCTEX_NOERR == _synctex_scan_next_line_header(scanner,&the_char)); + } + return scanner; +} + +int _synctex_scan_next_line_header(synctex_scanner_t scanner, unsigned char * valueRef) { + if(NULL == scanner || NULL == valueRef) return -1; + /* read until the next '\0' byte, return the following one */ + while(PTR<END) { + if(*PTR=='\0') { + if(++PTR<END) { + *valueRef = *(PTR++); + return 0; + } + } else { + ++PTR; + } + } + return -1; +} +int synctex_jump(synctex_scanner_t scanner) +{ + unsigned char the_char; + int n; + unsigned char * offset = END; + while(offset>scanner->buffer_start) { + if(*(--offset)) { + continue; + } + PTR = offset; + if(SYNCTEX_NOERR == _synctex_scan_next_line_header(scanner,&the_char)) { + if(the_char == '}') { + offset = PTR-1; +next: + if(SYNCTEX_NOERR == _synctex_decode_int(scanner,&n)) { + printf("}%i\n",n); + if(offset - n>START) { + offset -= n; + the_char = *offset; + if(the_char == '{') { + scanner->buffer_ptr=offset+1; + if(SYNCTEX_NOERR == _synctex_decode_int(scanner,&n)) { + printf("{%i\n",n); + if(offset - n>START) { + offset -= n; + the_char = *offset; + if(the_char == '}') { + PTR=offset+1; + goto next; + } else { + printf("This is not an '}', this is an %c\n", the_char); + } + } else { + printf("The start is reached %i\n",n); + } + } + } else { + printf("This is not an '{', this is an %c\n", the_char); + } + } else { + printf("ERROR: Too long %i\n",n); + } + } + break; + } + } + } + return 0; +} +int synctex_test(void) { + printf("sizeof(synctex_sheet_t):%i\n",sizeof(synctex_sheet_t)); + printf("sizeof(synctex_vert_box_node_t):%i\n",sizeof(synctex_vert_box_node_t)); + printf("sizeof(synctex_horiz_box_node_t):%i\n",sizeof(synctex_horiz_box_node_t)); + printf("sizeof(synctex_void_box_node_t):%i\n",sizeof(synctex_void_box_node_t)); + printf("sizeof(synctex_medium_node_t):%i\n",sizeof(synctex_medium_node_t)); + /* TESTING */ + synctex_node_t node; + synctex_node_t child; + synctex_node_t next; + #define TEST(LABEL,constructor)\ + printf("TESTING constructor:%s\n",LABEL);\ + node = constructor(NULL);\ + LOG(node);\ + FREE(node); + TEST(("_synctex_new_sheet"),_synctex_new_sheet); + TEST(("_synctex_new_vbox"),_synctex_new_vbox); + TEST(("_synctex_new_hbox"),_synctex_new_hbox); + TEST(("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST(("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST(("_synctex_new_math"),_synctex_new_math); + TEST(("_synctex_new_kern"),_synctex_new_kern); + TEST(("_synctex_new_glue"),_synctex_new_glue); + printf("...... ALL constructor tested\n\n\n\n"); + #undef TEST + #define TEST(PARENT_LABEL,PARENT_CONSTRUCTOR,CHILD_LABEL,CHILD_CONSTRUCTOR)\ + printf("TESTING parent:%s -> child:%s\n",PARENT_LABEL,CHILD_LABEL);\ + node = PARENT_CONSTRUCTOR(NULL);\ + child = CHILD_CONSTRUCTOR(NULL);\ + DISPLAY(node);\ + DISPLAY(child);\ + SET_CHILD(node,child);\ + DISPLAY(node);\ + DISPLAY(child);\ + if((CHILD(node) != child) || (node != PARENT(child))) {\ + return synctex_bail();\ + }\ + FREE(node); + TEST("_synctex_new_sheet",_synctex_new_sheet,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_sheet",_synctex_new_sheet,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_sheet",_synctex_new_sheet,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_sheet",_synctex_new_sheet,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_sheet",_synctex_new_sheet,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_sheet",_synctex_new_sheet,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_sheet",_synctex_new_sheet,("_synctex_new_glue"),_synctex_new_glue); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_glue"),_synctex_new_glue); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_glue"),_synctex_new_glue); +// TEST("_synctex_new_sheet","",_synctex_new_sheet,); +// TEST("","",,); + #undef TEST + #define TEST(CHILD_LABEL,CHILD_CONSTRUCTOR,SIBLING_LABEL,SIBLING_CONSTRUCTOR)\ + printf("TESTING child:%s -> next:%s\n",CHILD_LABEL,SIBLING_LABEL);\ + node = _synctex_new_sheet(NULL);\ + child = CHILD_CONSTRUCTOR(NULL);\ + next = SIBLING_CONSTRUCTOR(NULL);\ + DISPLAY(node);\ + DISPLAY(child);\ + DISPLAY(next);\ + SET_CHILD(node,child);\ + SET_SIBLING(child,next);\ + DISPLAY(node);\ + DISPLAY(child);\ + DISPLAY(next);\ + if((SIBLING(child) != next) || (node != PARENT(next))) {\ + return synctex_bail();\ + }\ + FREE(node); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_vbox",_synctex_new_vbox,("_synctex_new_glue"),_synctex_new_glue); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_hbox",_synctex_new_hbox,("_synctex_new_glue"),_synctex_new_glue); + TEST("_synctex_new_void_vbox",_synctex_new_void_vbox,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_void_vbox",_synctex_new_void_vbox,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_void_vbox",_synctex_new_void_vbox,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_void_vbox",_synctex_new_void_vbox,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_void_vbox",_synctex_new_void_vbox,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_void_vbox",_synctex_new_void_vbox,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_void_vbox",_synctex_new_void_vbox,("_synctex_new_glue"),_synctex_new_glue); + TEST("_synctex_new_void_hbox",_synctex_new_void_hbox,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_void_hbox",_synctex_new_void_hbox,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_void_hbox",_synctex_new_void_hbox,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_void_hbox",_synctex_new_void_hbox,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_void_hbox",_synctex_new_void_hbox,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_void_hbox",_synctex_new_void_hbox,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_void_hbox",_synctex_new_void_hbox,("_synctex_new_glue"),_synctex_new_glue); + TEST("_synctex_new_math",_synctex_new_math,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_math",_synctex_new_math,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_math",_synctex_new_math,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_math",_synctex_new_math,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_math",_synctex_new_math,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_math",_synctex_new_math,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_math",_synctex_new_math,("_synctex_new_glue"),_synctex_new_glue); + TEST("_synctex_new_kern",_synctex_new_kern,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_kern",_synctex_new_kern,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_kern",_synctex_new_kern,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_kern",_synctex_new_kern,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_kern",_synctex_new_kern,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_kern",_synctex_new_kern,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_kern",_synctex_new_kern,("_synctex_new_glue"),_synctex_new_glue); + TEST("_synctex_new_glue",_synctex_new_glue,("_synctex_new_vbox"),_synctex_new_vbox); + TEST("_synctex_new_glue",_synctex_new_glue,("_synctex_new_hbox"),_synctex_new_hbox); + TEST("_synctex_new_glue",_synctex_new_glue,("_synctex_new_void_vbox"),_synctex_new_void_vbox); + TEST("_synctex_new_glue",_synctex_new_glue,("_synctex_new_void_hbox"),_synctex_new_void_hbox); + TEST("_synctex_new_glue",_synctex_new_glue,("_synctex_new_math"),_synctex_new_math); + TEST("_synctex_new_glue",_synctex_new_glue,("_synctex_new_kern"),_synctex_new_kern); + TEST("_synctex_new_glue",_synctex_new_glue,("_synctex_new_glue"),_synctex_new_glue); + + return 0; + +} + diff --git a/Build/source/texk/web2c/synctex/synctex_parser.h b/Build/source/texk/web2c/synctex/synctex_parser.h new file mode 100644 index 00000000000..e0bce6523a6 --- /dev/null +++ b/Build/source/texk/web2c/synctex/synctex_parser.h @@ -0,0 +1,214 @@ +/* +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. + +*/ + +#ifndef __SYNCTEX_PARSER__ +# define __SYNCTEX_PARSER__ + +/* synctex_node_t is the type for all synctex nodes */ +typedef struct _synctex_node * synctex_node_t; + +/* The main synctex object is a scanner + * Its implementation is considered private + */ +typedef struct __synctex_scanner_t _synctex_scanner_t; +typedef _synctex_scanner_t * synctex_scanner_t; + +/* This is the designated method to create a new synctex scanner object. + * name is the full path of the synctex file to be parsed. + * NULL is returned in case of an error. + */ +synctex_scanner_t synctex_scanner_new_with_contents_of_file(const char * name); + +/* This is the designated method to delete a synctex scanner object. + */ +void synctex_scanner_free(synctex_scanner_t scanner); + +/* Display all the information contains in the scanner object. + * If the records are too numerous, they are not displayed. + */ +void synctex_scanner_display(synctex_scanner_t scanner); + +/* The x and y offset of the origin. The magnification + These are used by pdf viewers that want to display the real box size. + For example, getting the horizontal coordinate of a node would require + synctex_node_box_h(node)*synctex_scanner_magnification(scanner)+synctex_scanner_x_offset(scanner) + Getting its width would simply require + synctex_node_box_width(node)*synctex_scanner_magnification(scanner) + */ +int synctex_scanner_x_offset(synctex_scanner_t scanner); +int synctex_scanner_y_offset(synctex_scanner_t scanner); +float synctex_scanner_magnification(synctex_scanner_t scanner); + +/* Managing the input file names. + * Given a tag, synctex_scanner_get_name will return the corresponding file name. + * Conversely, given a file name, synctex_scanner_get_tag will retur, the corresponding tag. + * Finally, synctex_scanner_input is the first input node of the scanner. + * To browse all the input node, use a loop like + * + * while(input_node=synctex_node_sibling(input_node)) { + * blah + * } + */ +const char * synctex_scanner_get_name(synctex_scanner_t scanner,int tag); +int synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name); +synctex_node_t synctex_scanner_input(synctex_scanner_t scanner); + +/* Browsing the nodes + * parent, child and sibling are standard names for tree nodes. + * The parent is one level higher, the child is one level deeper, + * and the sibling is at the same level. + * The sheet of a node is the first ancestor pf type sheet. + * A node and its sibling have the same parent. + * A node is the parent of its child. + * A node is either the child of its parent, + * or belongs to the sibling chain of its parent's child. + * The next node is either the child, the sibling or the parent's sibling, + * unless the parent is a sheet. + * This allows to navigate through all the nodes of a given sheet node: + * + * synctex_node_t node = sheet; + * while(node = synctex_node_next(node)) { + * // do something with node + * } + * + * With synctex_sheet_content, you can retrieve the sheet node at index page. + * whereas synctex_node_sheet allows to retrieve the sheet containing a given node. + */ +synctex_node_t synctex_node_parent(synctex_node_t node); +synctex_node_t synctex_node_sheet(synctex_node_t node); +synctex_node_t synctex_node_child(synctex_node_t node); +synctex_node_t synctex_node_sibling(synctex_node_t node); +synctex_node_t synctex_node_next(synctex_node_t node); +synctex_node_t synctex_sheet_content(synctex_scanner_t scanner,int page); + +/* These are the types of the synctex nodes */ +typedef enum { + synctex_node_type_error = 0, + synctex_node_type_sheet, + synctex_node_type_vbox, + synctex_node_type_void_vbox, + synctex_node_type_hbox, + synctex_node_type_void_hbox, + synctex_node_type_kern, + synctex_node_type_glue, + synctex_node_type_math, + synctex_node_type_input, + synctex_node_type_last +} synctex_node_type_t; + +/* synctex_node_type gives the type of a given node, + * synctex_node_isa gives the same information as a human readable text. */ +synctex_node_type_t synctex_node_type(synctex_node_t node); +const char * synctex_node_isa(synctex_node_t node); + +/* This is primarily used for debugging purpose */ +void synctex_node_log(synctex_node_t node); + +/* Given a node, access to its tag, line and column. + * The latter is not yet fully supported. + */ +int synctex_node_tag(synctex_node_t node); +int synctex_node_line(synctex_node_t node); +int synctex_node_column(synctex_node_t node); + +/* This is the page where the node appears. + * This is a 1 based indes as given by TeX. + */ +int synctex_node_page(synctex_node_t node); + +/* For quite all nodes, horizontal, vertical coordinates, and width. + */ +float synctex_node_h(synctex_node_t node); +float synctex_node_v(synctex_node_t node); +float synctex_node_width(synctex_node_t node); + +/* For all nodes, dimensions of the enclosing box. + * A box is enclosing itself.*/ +float synctex_node_box_h(synctex_node_t node); +float synctex_node_box_v(synctex_node_t node); +float synctex_node_box_width(synctex_node_t node); +float synctex_node_box_height(synctex_node_t node); +float synctex_node_box_depth(synctex_node_t node); + +/* For quite all nodes, horizontal, vertical coordinates, and width. + * The visible dimensions are bigger than real ones to compensate 0 width boxes. + * A box is enclosing itself. + */ +float synctex_node_visible_h(synctex_node_t node); +float synctex_node_visible_v(synctex_node_t node); +float synctex_node_visible_width(synctex_node_t node); +/* For all nodes, visible dimensions of the enclosing box. + * A box is enclosing itself. + * The visible dimensions are bigger than real ones to compensate 0 width boxes. + */ +float synctex_node_box_visible_h(synctex_node_t node); +float synctex_node_box_visible_v(synctex_node_t node); +float synctex_node_box_visible_width(synctex_node_t node); +float synctex_node_box_visible_height(synctex_node_t node); +float synctex_node_box_visible_depth(synctex_node_t node); + +/* The main entry points. + * Given the file name, a line and a column number, synctex_display_query returns the number of nodes + * satisfying the contrain. Use code like + * + * if(synctex_display_query(scanner,name,line,column)>0) { + * synctex_node_t node; + * while(node = synctex_next_result(scanner)) { + * // do something with node + * ... + * } + * } + * + * Given the page and the position, synctex_edit_query returns the number of nodes + * satisfying the contrain. Use code like + * + * if(synctex_display_query(scanner,page,h,v)>0) { + * synctex_node_t node; + * while(node = synctex_next_result(scanner)) { + * // do something with node + * ... + * } + * } + * + * page is 1 based + * h and v are counted relative to the top left corner of the page. + * If one of this function returns a non positive integer, + * it means that an error occurred. + */ +int synctex_display_query(synctex_scanner_t scanner,const char * name,int line,int column); +int synctex_edit_query(synctex_scanner_t scanner,int page,float h,float v); +synctex_node_t synctex_next_result(synctex_scanner_t scanner); + +#endif
\ No newline at end of file |