1 /*
2  Copyright (c) 2008, 2009, 2010, 2011 jerome DOT laurens AT u-bourgogne DOT fr
3 
4  This file is part of the SyncTeX package.
5 
6  Latest Revision: Fri Apr 15 19:10:57 UTC 2011
7 
8  License:
9  --------
10  Permission is hereby granted, free of charge, to any person
11  obtaining a copy of this software and associated documentation
12  files (the "Software"), to deal in the Software without
13  restriction, including without limitation the rights to use,
14  copy, modify, merge, publish, distribute, sublicense, and/or sell
15  copies of the Software, and to permit persons to whom the
16  Software is furnished to do so, subject to the following
17  conditions:
18 
19  The above copyright notice and this permission notice shall be
20  included in all copies or substantial portions of the Software.
21 
22  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
24  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
29  OTHER DEALINGS IN THE SOFTWARE
30 
31  Except as contained in this notice, the name of the copyright holder
32  shall not be used in advertising or otherwise to promote the sale,
33  use or other dealings in this Software without prior written
34  authorization from the copyright holder.
35 
36  Important notice:
37  -----------------
38  This file is named "synctex.c", it may or may not have a header counterpart
39  depending on its use.  It aims to provide basic components useful for the
40  input/output synchronization technology for TeX.
41  The purpose of the implementation is threefold
42  - firstly, it defines a new input/output synchronization technology named
43  "synchronize texnology", "SyncTeX" or "synctex"
44  - secondly, it defines the naming convention and format of the auxiliary file
45  used by this technology
46  - thirdly, it defines the API of a controller and a controller, used in
47  particular by the pdfTeX and XeTeX programs to prepare synchronization.
48 
49  All these are up to a great extent de facto definitions, which means that they
50  are partly defined by the implementation itself.
51 
52  This technology was first designed for pdfTeX, an extension of TeX managing the
53  pdf output file format, but it can certainly be adapted to other programs built
54  from TeX as long as the extensions do not break too much the core design.
55  Moreover, the synchronize texnology only relies on code concept and not
56  implementation details, so it can be ported to other TeX systems.  In order to
57  support SyncTeX, one can start reading the dedicated section in synctex.ch,
58  sync-pdftex.ch and sync-xetex.ch. Actually, support is provided for TeX, e-TeX,
59  pdfTeX and XeTeX.
60 
61  Other existing public synchronization technologies are defined by srcltx.sty -
62  also used by source specials - and pdfsync.sty.  Like them, the synchronize
63  texnology is meant to be shared by various text editors, viewers and TeX
64  engines.  A centralized reference and source of information is available in TeX-Live.
65 
66  Versioning:
67  -----------
68  As synctex is embedded into different TeX implementation, there is an independent
69  versionning system.
70  For TeX implementations, the actual version is: 3
71  For .synctex file format, the actual version is SYNCTEX_VERSION below
72 
73  Please, do not remove these explanations.
74 
75  Acknowledgments:
76  ----------------
77  The author received useful remarks from the pdfTeX developers, especially Hahn The Thanh,
78  and significant help from XeTeX developer Jonathan Kew
79 
80  Nota Bene:
81  ----------
82  If you include or use a significant part of the synctex package into a software,
83  I would appreciate to be listed as contributor and see "SyncTeX" highlighted.
84 
85  History:
86  --------
87  Version 1.14
88  Fri Apr 15 19:10:57 UTC 2011
89  - taking output_directory into account
90  - Replaced FOPEN_WBIN_MODE by FOPEN_W_MODE when opening the text version of the .synctex file.
91  - Merging with LuaTeX's version of synctex.c
92 
93  Version 3
94  - very minor design change to take luatex into account
95  - typo fixed
96  - some size_t replaced by int
97  - very minor code design change to remove wrong xetex specific warnings
98 
99  Version 2
100  Fri Sep 19 14:55:31 UTC 2008
101  - support for file names containing spaces.
102  This is one thing that xetex and pdftex do not manage the same way.
103  When the input file name contains a space character ' ',
104  pdftex will automatically enclose this name between two quote characters '"',
105  making programs believe that these quotes are really part of the name.
106  xetex does nothing special.
107  For that reason, running the command line
108  xetex --synctex=-1 "my file.tex"
109  is producing the expected file named <my file.synctex>, (the '<' and '>' are not part of the name)
110  whereas running the command line
111  pdftex --synctex=-1 "my file.tex"
112  was producing the unexpected file named <"my file".synctex> where the two '"' chracters were part of the name.
113  Of course, that was breaking the typesetting mechanism when pdftex was involved.
114  To solve this problem, we prefer to rely on the output_file_name instead of the jobname.
115  In the case when no output_file_name is available, we use jobname and test if the file name
116  starts and ends with a quote character. Every synctex output file is removed because we consider
117  TeX encontered a problem.
118  There is some conditional coding.
119 
120  Version 1
121  Latest Revision: Wed Jul  1 08:15:44 UTC 2009
122 
123  */
124 
125 #   define SYNCTEX_VERSION 1
126 
127 #   define SYNCTEX_DEBUG 0
128 
129 /*  Debugging: define the next macro to "return;" in order to disable the synctex code
130  *  only suplemental function calls will be used. The compiler may optimize them. */
131 #   define SYNCTEX_RETURN_IF_DISABLED ;
132 
133 #   define SYNCTEX_NOERR 0
134 
135 #   define EXTERN extern
136 
137 #   ifdef xfree
138 #       define SYNCTEX_FREE xfree
139 #   else
140 #       define SYNCTEX_FREE(x) free(x)
141 #   endif
142 
143 /*  The header file SYNCTEX_ENGINE_H below is "synctex-tex.h" for TeX, ...
144  *  Some macros are defined and additional headers will be imported.
145  *  The macros below can be defined there, prior to their default definition given afterwards. */
146 #   include SYNCTEX_ENGINE_H
147 
148 /*  the macros defined below do the same job than their almost eponym
149  *  counterparts of *tex.web, the memory access is sometimes more direct
150  *  because *tex.web won't share its own constants the main purpose is to
151  *  maintain very few hook points into *tex.web in order both to ensure
152  *  portability and not modifying to much the original code.  see texmfmem.h
153  *  and *tex.web for details, the synctex_ prefix prevents name conflicts, it
154  *  is some kind of namespace
155  */
156 /*  synctexoption is a global integer variable defined in *tex.web
157  *  it is set to 1 by texmfmp.c if the command line has the '-synctex=1'
158  *  option.  */
159 #   if !defined(synctex_options)
160 #       define synctex_options synctexoption
161 #   endif
162 #   if !defined(SYNCTEX_NO_OPTION)
163 #       define SYNCTEX_NO_OPTION INT_MAX
164 #   endif
165 /*  if synctex_options is set to SYNCTEX_NO_OPTION, no command line option was provided.  */
166 
167 /*  glue code: really define the main memory,
168  *  this is exactly the same "mem" as in *tex.web.  */
169 #   if !defined(mem)
170 #       define mem zmem
171 #   endif
172 /*  glue code: synctexoffset is a global integer variable defined in *tex.web
173  *  it is set to the offset where the primitive \synctex reads and writes its
174  *  value.  */
175 #   if !defined(SYNCTEX_VALUE)
176 #       define SYNCTEX_VALUE zeqtb[synctexoffset].cint
177 #   endif
178 /*  if there were a mean to share the value of synctex_code between *tex.web
179  *  and this file, it would be great.  */
180 
181 /*  WARNING:
182  The 9 definitions below must be in sync with their eponym declarations in
183  the proper synctex-*.ch* file or equivalent.
184  Since version 1.14, the definitions are moved after the include directive above
185  and we adopted a conservative policy. The forthcoming definitions apply only if
186  when the macros are not already defined in SYNCTEX_ENGINE_H.
187  If the default values below do not fit with your requirements,
188  you can define them in the above mentionned header file.
189  */
190 #   if !defined(synchronization_field_size)
191 #       define synchronization_field_size 2
192 #   endif
193 /*  The default value is 2, it is suitable for original TeX and alike,
194  *  but it is too big for XeTeX.
195  *  The tag and the line are just the two last words of the node.  This is a
196  *  very handy design but this is not strictly required by the concept.  If
197  *  really necessary, one can define other storage rules.
198  *  XeTeX already defined synchronization_field_size,
199  *  SYNCTEX_TAG_MODEL and SYNCTEX_LINE_MODEL
200  *  All the default values are targeted to TeX or e-TeX.  */
201 #   if !defined(SYNCTEX_TAG_MODEL)
202 #       define SYNCTEX_TAG_MODEL(NODE,TYPE)\
203 mem[NODE+TYPE##_node_size-synchronization_field_size].cint
204 #   endif
205 #   if !defined(SYNCTEX_LINE_MODEL)
206 #       define SYNCTEX_LINE_MODEL(NODE,TYPE)\
207 mem[NODE+TYPE##_node_size-synchronization_field_size+1].cint
208 #   endif
209 /*  SYNCTEX_TAG_MODEL and SYNCTEX_LINE_MODEL are used to define
210  *  SYNCTEX_TAG and SYNCTEX_LINE in a model independant way
211  *  Both are tag and line accessors.
212  *  TYPE takes one of the prefixes in the ???_node_size definition below. */
213 /*  see: @d box_node_size=...
214  *  There should be an automatic process here because these definitions
215  *  are redundant. However, this process would certainly be overcomplicated
216  *  (building then parsing the *tex.web file would be a pain) */
217 #   if !defined(box_node_size)
218 #       define box_node_size (7+synchronization_field_size)
219 #   endif
220 /*  glue code: node sizes  */
221 #   if !defined(small_node_size)
222 #       define small_node_size 2
223 #   endif
224 /*  see: @d small_node_size=2 {number of words to allocate for most node types}  */
225 #   if !defined(medium_node_size)
226 #       define medium_node_size (small_node_size+synchronization_field_size)
227 #   endif
228 /*  see: @d rule_node_size=4  */
229 #   if !defined(rule_node_size)
230 #       define rule_node_size (4+synchronization_field_size)
231 #   endif
232 /*  see: luatex  */
233 #   if !defined(glue_node_size)
234 #       define glue_node_size medium_node_size
235 #   endif
236 #   if !defined(kern_node_size)
237 #       define kern_node_size medium_node_size
238 #   endif
239 #   if !defined(math_node_size)
240 #       define math_node_size medium_node_size
241 #   endif
242 #   if !defined(width_offset)
243 #       define width_offset 1
244 #   endif
245 /*  see: @d width_offset=...  */
246 #   if !defined( depth_offset)
247 #       define depth_offset 2
248 #   endif
249 /*  see: @d depth_offset=...  */
250 #   if !defined(height_offset)
251 #       define height_offset 3
252 #   endif
253 /*  see: @d height_offset=...  */
254 
255 /*  Now define the local version of width(##), height(##) and depth(##) macros
256  These only depend on the 3 macros above.  */
257 #   if !defined(SYNCTEX_TYPE)
258 #       define SYNCTEX_TYPE(NODE) mem[NODE].hh.b0
259 #   endif
260 #   if !defined(SYNCTEX_SUBTYPE)
261 #       define SYNCTEX_SUBTYPE(NODE) mem[NODE].hh.b1
262 #   endif
263 #   if !defined(SYNCTEX_WIDTH)
264 #       define SYNCTEX_WIDTH(NODE) mem[NODE+width_offset].cint
265 #   endif
266 #   if !defined(SYNCTEX_DEPTH)
267 #       define SYNCTEX_DEPTH(NODE) mem[NODE+depth_offset].cint
268 #   endif
269 #   if !defined(SYNCTEX_HEIGHT)
270 #       define SYNCTEX_HEIGHT(NODE) mem[NODE+height_offset].cint
271 #   endif
272 #   if !defined(rule_node)
273 #       define rule_node 2
274 #   endif
275 #   if !defined(glue_node)
276 #       define glue_node 10
277 #   endif
278 #   if !defined(kern_node)
279 #       define kern_node 11
280 #   endif
281 
282 /*  Some parts of the code may differ depending on the ouput mode,
283  *  dvi or xdv vs pdf, in particular the management of magnification.
284  *  The default is dvi mode.
285  *  Also, if pdftex is used, the origin of the coordinates is at 0, not at 1in
286  *  Default values are suitable for TeX  */
287 #   if !defined(SYNCTEX_OUTPUT)
288 #       define SYNCTEX_OUTPUT "dvi"
289 #   endif
290 #   if !defined(SYNCTEX_OFFSET_IS_PDF)
291 #       define SYNCTEX_OFFSET_IS_PDF 0
292 #   endif
293 
294 #if defined(_WIN32) && (defined(upTeX) || defined(eupTeX) || defined(XeTeX))
295 #define W32UPTEXSYNCTEX 1
296 #include <wchar.h>
297 static char *chgto_oem(char *src);
298 static int fsyscp_remove(char *name);
299 #define remove fsyscp_remove
300 #endif
301 
302 /*  This macro layer was added to take luatex into account as suggested by T. Hoekwater. */
303 #   if !defined(SYNCTEX_GET_JOB_NAME)
304 #       define SYNCTEX_GET_JOB_NAME() (gettexstring(jobname))
305 #   endif
306 #   if !defined(SYNCTEX_GET_LOG_NAME)
307 #       define SYNCTEX_GET_LOG_NAME() (gettexstring(texmflogname))
308 #   endif
309 #   if !defined(SYNCTEX_CURRENT_TAG)
310 #       define SYNCTEX_CURRENT_TAG (curinput.synctextagfield)
311 #   endif
312 #   if !defined(SYNCTEX_GET_CURRENT_NAME)
313 #       define SYNCTEX_GET_CURRENT_NAME() generic_synctex_get_current_name()
314 #   endif
315 #   if !defined(SYNCTEX_GET_TOTAL_PAGES)
316 #       define SYNCTEX_GET_TOTAL_PAGES() (totalpages)
317 #   endif
318 #   if !defined(SYNCTEX_CURH)
319 #       define SYNCTEX_CURH curh
320 #   endif
321 #   if !defined(SYNCTEX_CURV)
322 #       define SYNCTEX_CURV curv
323 #   endif
324 #   if !defined(SYNCTEX_RULE_WD)
325 #       define SYNCTEX_RULE_WD rulewd
326 #   endif
327 #   if !defined(SYNCTEX_RULE_HT)
328 #       define SYNCTEX_RULE_HT ruleht
329 #   endif
330 #   if !defined(SYNCTEX_RULE_DP)
331 #       define SYNCTEX_RULE_DP ruledp
332 #   endif
333 
334 /*  For non-GCC compilation.  */
335 #   if !defined(__GNUC__) || (__GNUC__ < 2)
336 #       define __attribute__(A)
337 #   endif
338 
339 #   include "synctex.h"
340 
341 #   define SYNCTEX_YES (1)
342 #   define SYNCTEX_NO  (0)
343 #   define SYNCTEX_NO_ERROR  (0)
344 
345 #   define SYNCTEX_UNIT_FACTOR 1
346 #   define UNIT / synctex_ctxt.unit
347 /*  UNIT is the scale. TeX coordinates are very accurate and client won't need
348  *  that, at leat in a first step.  1.0 <-> 2^16 = 65536.
349  *  The TeX unit is sp (scaled point) or pt/65536 which means that the scale
350  *  factor to retrieve a bp unit (a postscript) is 72/72.27/65536 =
351  *  1/4096/16.06 = 1/8192/8.03
352  *  Here we use 1/SYNCTEX_UNIT_FACTOR as scale factor, then we can limit ourselves to
353  *  integers. This default value assumes that TeX magnification factor is 1000.
354  *  The real TeX magnification factor is used to fine tune the synctex context
355  *  scale in the synctex_dot_open function.
356  *  IMPORTANT: We can say that the natural unit of .synctex files is SYNCTEX_UNIT_FACTOR sp.
357  *  To retrieve the proper bp unit, we'll have to divide by 8.03.  To reduce
358  *  rounding errors, we'll certainly have to add 0.5 for non negative integers
359  *  and �0.5 for negative integers.  This trick is mainly to gain speed and
360  *  size. A binary file would be more appropriate in that respect, but I guess
361  *  that some clients like auctex would not like it very much.  we cannot use
362  *  "<<13" instead of "/SYNCTEX_UNIT_FACTOR" because the integers are signed and we do not
363  *  want the sign bit to be propagated.  The origin of the coordinates is at
364  *  the top left corner of the page.  For pdf mode, it is straightforward, but
365  *  for dvi mode, we'll have to record the 1in offset in both directions,
366  *  eventually modified by the magnification.
367  */
368 
369 #   if defined(__SyncTeX__)
370 
371 #   include <stdio.h>
372 #   include <stdarg.h>
373 #   include "zlib.h"
374 
375 typedef void (*synctex_recorder_t) (halfword);  /* recorders know how to record a node */
376 typedef int (*synctex_fprintf_t) (void *, const char *, ...);   /* print formatted to either FILE * or gzFile */
377 
378 #   define SYNCTEX_BITS_PER_BYTE 8
379 
380 /*  Here are all the local variables gathered in one "synchronization context"  */
381 static struct {
382     void *file;                 /*  the foo.synctex or foo.synctex.gz I/O identifier  */
383     synctex_fprintf_t fprintf;  /*  either fprintf or gzprintf */
384     char *busy_name;            /*  the real "foo.synctex(busy)" or "foo.synctex.gz(busy)" name, with output_directory  */
385     char *root_name;            /*  in general jobname.tex  */
386     integer count;              /*  The number of interesting records in "foo.synctex"  */
387     /*  next concern the last sync record encountered  */
388     halfword node;              /*  the last synchronized node, must be set
389                                  *  before the recorder */
390     synctex_recorder_t recorder;/*  the recorder of the node above, the
391                                  *  routine that knows how to record the
392                                  *  node to the .synctex file */
393     integer tag, line;          /*  current tag and line  */
394     integer curh, curv;         /*  current point  */
395     integer magnification;      /*  The magnification as given by \mag */
396     integer unit;               /*  The unit, defaults to 1, use 8192 to produce shorter but less accurate info */
397     integer total_length;       /*  The total length of the bytes written since the last check point  */
398     struct _flags {
399         unsigned int option_read:1; /*  Command line option read (in case of problem or at the end) */
400         unsigned int off:1;         /*  Definitely turn off synctex, corresponds to cli option -synctex=0 */
401         unsigned int no_gz:1;       /*  Whether zlib is used or not */
402         unsigned int not_void:1;    /*  Whether it really contains synchronization material */
403         unsigned int warn:1;        /*  One shot warning flag */
404         unsigned int quoted:1;      /*  Whether the input file name was quoted by tex or not, for example "\"my input file.tex\"", unused by XeTeX */
405         unsigned int output_p:1;    /*  Whether the output_directory is used */
406         unsigned int reserved:SYNCTEX_BITS_PER_BYTE*sizeof(int)-7; /* Align */
407     } flags;
408 } synctex_ctxt = {
409     NULL, NULL, NULL, NULL, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, {0,0,0,0,0,0,0,0}};
410 
411 #   define SYNCTEX_FILE synctex_ctxt.file
412 #   define SYNCTEX_IS_OFF (synctex_ctxt.flags.off)
413 #   define SYNCTEX_NO_GZ (synctex_ctxt.flags.no_gz)
414 #   define SYNCTEX_NOT_VOID (synctex_ctxt.flags.not_void)
415 #   define SYNCTEX_WARNING_DISABLE (synctex_ctxt.flags.warn)
416 #   define SYNCTEX_fprintf (*synctex_ctxt.fprintf)
417 
418 /*  Initialize the options, synchronize the variables.
419  *  This is sent by *tex.web before any TeX macro is used.
420  *  */
synctexinitcommand(void)421 void synctexinitcommand(void)
422 {
423     /*  This is a one shot function, any subsequent call is void */
424     if (synctex_ctxt.flags.option_read) {
425         return;
426     }
427     if (SYNCTEX_NO_OPTION == synctex_options) {
428         /*  No option given from the command line  */
429         SYNCTEX_VALUE = 0;
430     } else if (synctex_options == 0) {
431         /*  -synctex=0 was given: SyncTeX must be definitely disabled,
432          *  any subsequent \synctex=1 will have no effect at all */
433         SYNCTEX_IS_OFF = SYNCTEX_YES;
434         SYNCTEX_VALUE = 0;
435     } else {
436         /*  the command line options are not ignored  */
437         if (synctex_options < 0) {
438             SYNCTEX_NO_GZ = SYNCTEX_YES;
439         }
440         /*  Initialize the content of the \synctex primitive */
441         SYNCTEX_VALUE = synctex_options;
442     }
443     synctex_ctxt.flags.option_read = SYNCTEX_YES;
444     return;
445 }
446 
447 /*  Free all memory used, close and remove the file if any,
448  *  It is sent locally when there is a problem with synctex output.
449  *  It is sent by pdftex when a fatal error occurred in pdftex.web. */
synctexabort(boolean log_opened)450 void synctexabort(boolean log_opened __attribute__ ((unused)))
451 {
452     SYNCTEX_RETURN_IF_DISABLED;
453 #   if SYNCTEX_DEBUG
454     printf("\nSynchronize DEBUG: synctex_abort\n");
455 #   endif
456     if (SYNCTEX_FILE) {
457         if (SYNCTEX_NO_GZ) {
458             xfclose((FILE *) SYNCTEX_FILE, synctex_ctxt.busy_name);
459         } else {
460             gzclose((gzFile) SYNCTEX_FILE);
461         }
462         SYNCTEX_FILE = NULL;
463         remove(synctex_ctxt.busy_name);
464         SYNCTEX_FREE(synctex_ctxt.busy_name);
465         synctex_ctxt.busy_name = NULL;
466     }
467     if (NULL != synctex_ctxt.root_name) {
468         SYNCTEX_FREE(synctex_ctxt.root_name);
469         synctex_ctxt.root_name = NULL;
470     }
471     SYNCTEX_IS_OFF = SYNCTEX_YES;      /* disable synctex */
472 }
473 
474 static inline int synctex_record_preamble(void);
475 static inline int synctex_record_input(integer tag, char *name);
476 
477 static const char *synctex_suffix = ".synctex";
478 static const char *synctex_suffix_gz = ".gz";
479 static const char *synctex_suffix_busy = "(busy)";
480 
481 /*  for DIR_SEP_STRING */
482 #   include <kpathsea/c-pathch.h>
483 /*  for kpse_absolute_p */
484 #   include <kpathsea/absolute.h>
485 
486 #ifdef W32UPTEXSYNCTEX
chgto_oem(char * src)487 static char *chgto_oem(char *src)
488 {
489   wchar_t *sw = NULL;
490   char    *dst = NULL;
491   static int f_codepage = 0;
492 
493   if(f_codepage == 0) {
494     f_codepage = AreFileApisANSI() ? GetACP() : GetOEMCP();
495   }
496 
497   if(f_codepage == file_system_codepage) {
498     dst = xstrdup(src);
499     return dst;
500   }
501 
502   sw = get_wstring_from_mbstring(file_system_codepage, src, sw);
503   dst = get_mbstring_from_wstring(f_codepage, sw, dst);
504   if(sw) free(sw);
505   return dst;
506 }
507 
fsyscp_gzopen(const char * path,const char * mode)508 static gzFile fsyscp_gzopen(const char *path, const char *mode)
509 {
510   gzFile  gzf;
511   wchar_t *pathw = NULL;
512   pathw = get_wstring_from_fsyscp(path, pathw);
513   gzf = gzopen_w(pathw, mode);
514   free(pathw);
515   return gzf;
516 }
517 
fsyscp_remove(char * s)518 static int fsyscp_remove(char *s)
519 {
520   wchar_t *sw = NULL;
521   int ret;
522   sw = get_wstring_from_fsyscp(s, sw);
523   ret = _wremove(sw);
524   if(sw) free(sw);
525   return ret;
526 }
527 
fsyscp_rename(char * s1,char * s2)528 static int fsyscp_rename(char *s1, char *s2)
529 {
530   wchar_t *sw1 = NULL, *sw2 = NULL;
531   int ret;
532 
533   sw1 = get_wstring_from_fsyscp(s1, sw1);
534   sw2 = get_wstring_from_fsyscp(s2, sw2);
535   ret = _wrename(sw1, sw2);
536   if(sw1) free(sw1);
537   if(sw2) free(sw2);
538   return ret;
539 }
540 
541 #undef fopen
542 #define fopen fsyscp_fopen
543 #define gzopen fsyscp_gzopen
544 #define rename fsyscp_rename
545 #endif
546 
547 /*  synctex_dot_open ensures that the foo.synctex file is open.
548  *  In case of problem, it definitely disables synchronization.
549  *  Now all the output synchronization info is gathered in only one file.
550  *  It is possible to split this info into as many different output files as sheets
551  *  plus 1 for the control but the overall benefits are not so clear.
552  *  For example foo-i.synctex would contain input synchronization
553  *  information for page i alone.
554  */
synctex_dot_open(void)555 static void *synctex_dot_open(void)
556 {
557     SYNCTEX_RETURN_IF_DISABLED;
558 #   if SYNCTEX_DEBUG
559     printf("\nwarning: Synchronize DEBUG: synctex_dot_open\n");
560     printf("\nwarning: SYNCTEX_VALUE=%0X\n", SYNCTEX_VALUE);
561     printf("\nwarning: synctex_options=%0X\n", synctex_options);
562 #   endif
563     if (SYNCTEX_IS_OFF || !SYNCTEX_VALUE) {
564         return NULL;            /*  synchronization is disabled: do nothing  */
565     }
566     if (SYNCTEX_FILE) {
567         return SYNCTEX_FILE;    /*  synchronization is already enabled  */
568     }
569 #   if SYNCTEX_DEBUG
570     printf("\nwarning: Synchronize DEBUG: synctex_dot_open 1\n");
571 #   endif
572     /*  this is the first time we are asked to open the file
573      this part of code is executed only once:
574      either SYNCTEX_FILE is nonnegative or synchronization is
575      definitely disabled. */
576     {
577         char *tmp = SYNCTEX_GET_JOB_NAME();
578         size_t len = strlen(tmp);
579         if (len>0) {
580             /*  jobname was set by the \jobname command on the *TeX side  */
581             char *the_busy_name = xmalloc((size_t)
582                                           ( len
583                                            + strlen(synctex_suffix)
584                                            + strlen(synctex_suffix_gz)
585                                            + strlen(synctex_suffix_busy)
586                                            + 1
587                                            + (output_directory?strlen(output_directory) + strlen(DIR_SEP_STRING):0)));
588             if (!the_busy_name) {
589                 SYNCTEX_FREE(tmp);
590                 tmp = NULL;
591                 synctexabort(0);
592                 return NULL;
593             }
594             /* Initialize the_busy_name to the void string */
595             the_busy_name[0] = (char)0;
596             /* If an output directory was specified, use it instead of cwd.  */
597             if (output_directory && !kpse_absolute_p(tmp, false)) {
598                 synctex_ctxt.flags.output_p = 1;
599                 strcat(the_busy_name, output_directory);
600                 strcat(the_busy_name, DIR_SEP_STRING);
601             }
602 #  if defined(XeTeX)
603             synctex_ctxt.flags.quoted = 0;
604             strcat(the_busy_name, tmp);
605 #  else
606             if (tmp[0] == '"' && tmp[len - 1] == '"') {
607                 /*  We are certainly on a pdftex like engine and the input file name did contain spaces inside.
608                  Quotes where added around that file name. We prefer to remove the quotes to have a human readable name.
609                  As of Fri Sep 19 14:00:01 UTC 2008, the file names containing quotes are not supported by pdfTeX
610                  nor SyncTeX. */
611                 synctex_ctxt.flags.quoted = 1;      /* we will have to add quotes around the file name in the log file. */
612                 tmp[len - 1] = (char)0;             /* Remove the trailing " in order not to copy it */
613                 strcat(the_busy_name, tmp + 1);     /* only copy what follows the leading " character */
614             } else {
615                 synctex_ctxt.flags.quoted = 0;
616                 strcat(the_busy_name, tmp);
617             }
618 #  endif
619             SYNCTEX_FREE(tmp);
620             tmp = NULL;
621             strcat(the_busy_name, synctex_suffix);
622             /*  Initialize SYNCTEX_NO_GZ with the content of \synctex to let the user choose the format. */
623             SYNCTEX_NO_GZ = SYNCTEX_VALUE < 0 ? SYNCTEX_YES : SYNCTEX_NO;
624             if (!SYNCTEX_NO_GZ) {
625                 strcat(the_busy_name, synctex_suffix_gz);
626             }
627             strcat(the_busy_name, synctex_suffix_busy);
628             if (SYNCTEX_NO_GZ) {
629                 SYNCTEX_FILE = fopen(the_busy_name, FOPEN_W_MODE);
630                 synctex_ctxt.fprintf = (synctex_fprintf_t) (&fprintf);
631             } else {
632                 SYNCTEX_FILE = gzopen(the_busy_name, FOPEN_WBIN_MODE);
633                 synctex_ctxt.fprintf = (synctex_fprintf_t) (&gzprintf);
634             }
635 #   if SYNCTEX_DEBUG
636             printf("\nwarning: Synchronize DEBUG: synctex_dot_open 2\n");
637 #   endif
638             if (SYNCTEX_FILE) {
639                 if (SYNCTEX_NO_ERROR == synctex_record_preamble()) {
640                     /*  Initialization of the context */
641                     synctex_ctxt.magnification = 1000;
642                     synctex_ctxt.unit = SYNCTEX_UNIT_FACTOR;
643                     /*  synctex_ctxt.busy_name was NULL before, it now owns the_busy_name */
644                     synctex_ctxt.busy_name = the_busy_name;
645                     the_busy_name = NULL;
646                     /*  print the preamble, this is quite an UTF8 file  */
647                     if (NULL != synctex_ctxt.root_name) {
648                         synctex_record_input(1, synctex_ctxt.root_name);
649                         SYNCTEX_FREE(synctex_ctxt.root_name);
650                         synctex_ctxt.root_name = NULL;
651                     }
652                     synctex_ctxt.count = 0;
653 #   if SYNCTEX_DEBUG
654                     fprintf(stdout,
655                             "\nwarning: Synchronize DEBUG: synctex_dot_open SYNCTEX AVAILABLE\n");
656 #   endif
657                     SYNCTEX_FREE(the_busy_name);
658                     the_busy_name = NULL;
659                     return SYNCTEX_FILE;
660                 } else {
661                     printf("\nSyncTeX warning: no synchronization, problem with %s\n",
662                            the_busy_name);
663                 }
664             }
665             SYNCTEX_FREE(the_busy_name);
666             the_busy_name = NULL;
667         } else {
668             printf("\nSyncTeX information: no synchronization with keyboard input\n");
669         }
670         /*  no .synctex file available, so disable synchronization  */
671         SYNCTEX_FREE(tmp);
672         tmp = NULL;
673         synctexabort(0);
674         return NULL;
675 #   if SYNCTEX_DEBUG
676         fprintf(stdout,
677                 "\nwarning: Synchronize DEBUG: synctex_dot_open SYNCTEX DISABLED\n");
678 #   endif
679     }
680     return SYNCTEX_FILE;
681 }
682 
683 /*  Each time TeX opens a file, it sends a synctexstartinput message and enters
684  *  this function.  Here, a new synchronization tag is created and stored in
685  *  the synctex_tag_field of the TeX current input context.  Each synchronized
686  *  TeX node will record this tag instead of the file name.  synctexstartinput
687  *  writes the mapping synctag <-> file name to the .synctex (or .synctex.gz) file.  A client
688  *  will read the .synctex file and retrieve this mapping, it will be able to
689  *  open the correct file just knowing its tag.  If the same file is read
690  *  multiple times, it might be associated to different tags.  Synchronization
691  *  controllers, either in viewers, editors or standalone should be prepared to
692  *  handle this situation and take the appropriate action if they want to
693  *  optimize memory.  No two different files will have the same positive tag.
694  *  It is not advisable to definitely store the file names here.  If the file
695  *  names ever have to be stored, it should definitely be done at the TeX level
696  *  just like src-specials do, such that other components of the program can use
697  *  it.  This function does not make any difference between the files, it
698  *  treats the same way .tex, .aux, .sty ... files, even if many of them do not
699  *  contain any material meant to be typeset.
700  */
synctexstartinput(void)701 void synctexstartinput(void)
702 {
703     static unsigned int synctex_tag_counter = 0;
704 
705     SYNCTEX_RETURN_IF_DISABLED;
706 #   if SYNCTEX_DEBUG
707     printf("\nwarning: Synchronize DEBUG: synctexstartinput %i",
708            synctex_tag_counter);
709     printf("\nwarning: SYNCTEX_VALUE=%i", SYNCTEX_VALUE);
710     printf("\nwarning: synctex_options=%0X", synctex_options);
711 #   endif
712 
713     if (SYNCTEX_IS_OFF) {
714         return;
715     }
716     /*  synctex_tag_counter is a counter uniquely identifying the file actually
717      *  open.  Each time tex opens a new file, synctexstartinput will increment this
718      *  counter  */
719     if (~synctex_tag_counter > 0) {
720         ++synctex_tag_counter;
721     } else {
722         /*  we have reached the limit, subsequent files will be softly ignored
723          *  this makes a lot of files... even in 32 bits
724          *  Maybe we will limit this to 16bits and
725          *  use the 16 other bits to store the column number */
726         SYNCTEX_CURRENT_TAG = 0;
727         return;
728     }
729     SYNCTEX_CURRENT_TAG = (int) synctex_tag_counter;     /*  -> *TeX.web  */
730     if (synctex_tag_counter == 1) {
731         /*  this is the first file TeX ever opens, in general \jobname.tex we
732          *  do not know yet if synchronization will ever be enabled so we have
733          *  to store the file name, because we will need it later.
734          *  This is necessary because \jobname can be different */
735 #ifdef W32UPTEXSYNCTEX
736         char *tmpa = SYNCTEX_GET_CURRENT_NAME();
737         synctex_ctxt.root_name = chgto_oem(tmpa);
738         free(tmpa);
739 #else
740         synctex_ctxt.root_name = SYNCTEX_GET_CURRENT_NAME();
741 #endif
742         if (!strlen(synctex_ctxt.root_name)) {
743             synctex_ctxt.root_name = xrealloc(synctex_ctxt.root_name, strlen("texput") + 1);
744             strcpy(synctex_ctxt.root_name, "texput");
745         }
746 #   if SYNCTEX_DEBUG
747         printf("\nwarning: Synchronize DEBUG: synctexstartinput first END\n");
748 #   endif
749         return;
750     }
751     if (SYNCTEX_FILE
752         || (SYNCTEX_NO_ERROR != synctex_dot_open())) {
753 #ifdef W32UPTEXSYNCTEX
754         char *tmpb = SYNCTEX_GET_CURRENT_NAME();
755         char *tmp = chgto_oem(tmpb);
756         free(tmpb);
757 #else
758         char *tmp = SYNCTEX_GET_CURRENT_NAME();
759 #endif
760         /* Always record the input, even if SYNCTEX_VALUE is 0 */
761         synctex_record_input(SYNCTEX_CURRENT_TAG,tmp);
762         SYNCTEX_FREE(tmp);
763     }
764 #   if SYNCTEX_DEBUG
765     printf("\nwarning: Synchronize DEBUG: synctexstartinput END\n");
766 #   endif
767     return;
768 }
769 
770 /*  All the synctex... functions below have the smallest set of parameters.  It
771  *  appears to be either the address of a node, or nothing at all.  Using zmem,
772  *  which is the place where all the nodes are stored, one can retrieve every
773  *  information about a node.  The other information is obtained through the
774  *  global context variable.
775  */
776 
777 static inline int synctex_record_postamble(void);
778 
779 
780 /*  Free all memory used and close the file,
781  *  sent by close_files_and_terminate in tex.web.
782  *  synctexterminate() is called when the TeX run terminates.
783  *  If synchronization was active, the working synctex file is moved to
784  *  the final synctex file name.
785  *  If synchronization was not active of if there is no output,
786  *  the synctex file is removed if any.
787  *  That way we can be sure that any synctex file is in sync with a tex run.
788  *  However, it does not mean that it will be in sync with the pdf, especially
789  *  when the output is dvi or xdv and the dvi (or xdv) to pdf driver has not been applied.
790  */
synctexterminate(boolean log_opened)791 void synctexterminate(boolean log_opened)
792 {
793     char *tmp = NULL;
794     char *the_real_syncname = NULL;
795     SYNCTEX_RETURN_IF_DISABLED;
796 #   if SYNCTEX_DEBUG
797     printf("\nSynchronize DEBUG: synctexterminate\n");
798 #   endif
799     if (log_opened && (tmp = SYNCTEX_GET_LOG_NAME())) {
800         /* In version 1, the jobname was used but it caused problems regarding spaces in file names. */
801         the_real_syncname = xmalloc((unsigned)
802                                     (strlen(tmp) + strlen(synctex_suffix) +
803                                      strlen(synctex_suffix_gz) + 1));
804         if (!the_real_syncname) {
805             SYNCTEX_FREE(tmp);
806             synctexabort(0);
807             return;
808         }
809         strcpy(the_real_syncname, tmp);
810         SYNCTEX_FREE(tmp);
811         tmp = NULL;
812         /* now remove the last path extension which is in general log */
813         tmp = the_real_syncname + strlen(the_real_syncname);
814         while (tmp > the_real_syncname) {
815             --tmp;
816             if (*tmp == '.') {
817                 *tmp = (char)0;    /* end the string here */
818                 break;
819             }
820         }
821         strcat(the_real_syncname, synctex_suffix);
822         if (!SYNCTEX_NO_GZ) {
823             /*  Remove any uncompressed synctex file, from a previous build. */
824             remove(the_real_syncname);
825             strcat(the_real_syncname, synctex_suffix_gz);
826         }
827         /* allways remove the synctex output file before renaming it, windows requires it. */
828         if (0 != remove(the_real_syncname) && errno == EACCES) {
829             fprintf(stderr,
830                     "SyncTeX: Can't remove %s (file is open or read only)\n",
831                     the_real_syncname);
832         }
833         if (SYNCTEX_FILE) {
834             if (SYNCTEX_NOT_VOID) {
835                 synctex_record_postamble();
836                 /* close the synctex file */
837                 if (SYNCTEX_NO_GZ) {
838                     xfclose((FILE *) SYNCTEX_FILE, synctex_ctxt.busy_name);
839                 } else {
840                     gzclose((gzFile) SYNCTEX_FILE);
841                 }
842                 SYNCTEX_FILE = NULL;
843                 /*  renaming the working synctex file */
844                 if (0 == rename(synctex_ctxt.busy_name, the_real_syncname)) {
845                     if (log_opened) {
846                         tmp = the_real_syncname;
847 #                       if SYNCTEX_DO_NOT_LOG_OUTPUT_DIRECTORY
848                         if (synctex_ctxt.flags.output_p) {
849                             tmp += strlen(output_directory) + strlen(DIR_SEP_STRING);
850                         }
851 #                       endif
852 #ifdef W32UPTEXSYNCTEX
853                         {
854                         char *stmp = chgto_oem(tmp);
855                         printf((synctex_ctxt.flags.quoted ? "\nSyncTeX written on \"%s\"" : "\nSyncTeX written on %s."),
856                                stmp);
857                         free(stmp);
858                         }
859 #else
860                         printf((synctex_ctxt.flags.quoted ? "\nSyncTeX written on \"%s\"" : "\nSyncTeX written on %s."),
861                                tmp);
862 #endif
863                         tmp = NULL;
864                     }
865                 } else {
866                     fprintf(stderr, "SyncTeX: Can't rename %s to %s\n",
867                             synctex_ctxt.busy_name, the_real_syncname);
868                     remove(synctex_ctxt.busy_name);
869                 }
870             } else {
871                 /* close and remove the synctex file because there are no pages of output */
872                 if (SYNCTEX_NO_GZ) {
873                     xfclose((FILE *) SYNCTEX_FILE, synctex_ctxt.busy_name);
874                 } else {
875                     gzclose((gzFile) SYNCTEX_FILE);
876                 }
877                 SYNCTEX_FILE = NULL;
878                 remove(synctex_ctxt.busy_name);
879             }
880         }
881         if (SYNCTEX_NO_GZ) {
882             /*  Remove any compressed synctex file, from a previous build. */
883             strcat(the_real_syncname, synctex_suffix_gz);
884             remove(the_real_syncname);
885         }
886     } else if ((tmp = SYNCTEX_GET_JOB_NAME())) {
887         size_t len = strlen(tmp);
888         /*  There was a problem with the output.
889          We just try to remove existing synctex output files
890          including the busy one. */
891         the_real_syncname = xmalloc((size_t)
892                                     (len + strlen(synctex_suffix)
893                                      + strlen(synctex_suffix_gz) + 1));
894         if (!the_real_syncname) {
895             SYNCTEX_FREE(tmp);
896             synctexabort(0);
897             return;
898         }
899 #   if defined(XeTeX)
900         strcpy(the_real_syncname, tmp);
901 #   else
902         if (len > 0 && tmp[0] == '"' && tmp[len - 1] == '"') {
903             /*  See above a similar situation. */
904             strcpy(the_real_syncname, tmp + 1); /* only copy what follows the leading " character */
905             len = strlen(the_real_syncname);
906             if ((len > 0) && (the_real_syncname[len - 1] == '"')) {
907                 the_real_syncname[len - 1] = '\0';
908             }
909         } else {
910             strcpy(the_real_syncname, tmp);
911         }
912 #   endif
913         SYNCTEX_FREE(tmp);
914         tmp = NULL;
915         strcat(the_real_syncname, synctex_suffix);
916         remove(the_real_syncname);
917         strcat(the_real_syncname, synctex_suffix_gz);
918         remove(the_real_syncname);
919         if (SYNCTEX_FILE) {
920             /* close the synctex file */
921             if (SYNCTEX_NO_GZ) {
922                 xfclose((FILE *) SYNCTEX_FILE, synctex_ctxt.busy_name);
923             } else {
924                 gzclose((gzFile) SYNCTEX_FILE);
925             }
926             SYNCTEX_FILE = NULL;
927             /*  removing the working synctex file */
928             remove(synctex_ctxt.busy_name);
929         }
930     }
931     SYNCTEX_FREE(synctex_ctxt.busy_name);
932     synctex_ctxt.busy_name = NULL;
933     SYNCTEX_FREE(the_real_syncname);
934     the_real_syncname = NULL;
935     synctexabort(0);
936 }
937 
938 static inline int synctex_record_content(void);
939 static inline int synctex_record_settings(void);
940 static inline int synctex_record_sheet(integer sheet);
941 
942 /*  Recording the "{..." line.  In *tex.web, use synctex_sheet(pdf_output) at
943  *  the very beginning of the ship_out procedure.
944  */
synctexsheet(integer mag)945 void synctexsheet(integer mag)
946 {
947     SYNCTEX_RETURN_IF_DISABLED;
948 #   if SYNCTEX_DEBUG
949     printf("\nSynchronize DEBUG: synctexsheet %i\n", mag);
950 #   endif
951     if (SYNCTEX_IS_OFF) {
952         if (SYNCTEX_VALUE && !SYNCTEX_WARNING_DISABLE) {
953             SYNCTEX_WARNING_DISABLE = SYNCTEX_YES;
954             printf
955             ("\nSyncTeX warning: Synchronization was disabled from\nthe command line with -synctex=0\nChanging the value of \\synctex has no effect.");
956         }
957         return;
958     }
959     if (SYNCTEX_FILE
960         || (SYNCTEX_VALUE && (SYNCTEX_NO_ERROR != synctex_dot_open()))) {
961         /*  First possibility: the .synctex file is already open because SyncTeX was activated on the CLI
962          *  or it was activated with the \synctex macro and the first page is already shipped out.
963          *  Second possibility: tries to open the .synctex, useful if synchronization was enabled
964          *  from the source file and not from the CLI. */
965         if (SYNCTEX_GET_TOTAL_PAGES() == 0) {
966             /*  Now it is time to properly set up the scale factor. */
967             if (mag > 0) {
968                 synctex_ctxt.magnification = mag;
969             }
970             if (SYNCTEX_NO_ERROR != synctex_record_settings()
971                 || SYNCTEX_NO_ERROR != synctex_record_content()) {
972                 synctexabort(0);
973                 return;
974             }
975         }
976         synctex_record_sheet(SYNCTEX_GET_TOTAL_PAGES()+1);
977     }
978 #   if SYNCTEX_DEBUG
979     printf("\nSynchronize DEBUG: synctexsheet END\n");
980 #   endif
981     return;
982 }
983 
984 static inline int synctex_record_teehs(integer sheet);
985 
986 /*  Recording the "}..." line.  In *tex.web, use synctex_teehs at
987  *  the very end of the ship_out procedure.
988  */
synctexteehs(void)989 void synctexteehs(void)
990 {
991     SYNCTEX_RETURN_IF_DISABLED;
992 #   if SYNCTEX_DEBUG
993     printf("\nSynchronize DEBUG: synctexteehs\n");
994 #   endif
995     if (SYNCTEX_IS_OFF || !SYNCTEX_FILE) {
996         return;
997     }
998     synctex_record_teehs(SYNCTEX_GET_TOTAL_PAGES());/* not SYNCTEX_GET_TOTAL_PAGES()+1*/
999 #   if SYNCTEX_DEBUG
1000     printf("\nSynchronize DEBUG: synctexteehs END\n");
1001 #   endif
1002     return;
1003 }
1004 
1005 static inline void synctex_record_vlist(halfword p);
1006 
1007 /*  When an hlist ships out, it can contain many different kern/glue nodes with
1008  *  exactly the same sync tag and line.  To reduce the size of the .synctex
1009  *  file, we only display a kern node sync info when either the sync tag or the
1010  *  line changes.  Also, we try ro reduce the distance between the chosen nodes
1011  *  in order to improve accuracy.  It means that we display information for
1012  *  consecutive nodes, as far as possible.  This tricky part uses a "recorder",
1013  *  which is the address of the routine that knows how to write the
1014  *  synchronization info to the .synctex file.  It also uses criteria to detect
1015  *  a change in the context, this is the macro SYNCTEX_???_CONTEXT_DID_CHANGE. The
1016  *  SYNCTEX_IGNORE macro is used to detect unproperly initialized nodes.  See
1017  *  details in the implementation of the functions below.  */
1018 #   define SYNCTEX_IGNORE(NODE) SYNCTEX_IS_OFF || !SYNCTEX_VALUE || !SYNCTEX_FILE
1019 
1020 
1021 /*  This message is sent when a vlist will be shipped out, more precisely at
1022  *  the beginning of the vlist_out procedure in *TeX.web.  It will be balanced
1023  *  by a synctex_tsilv, sent at the end of the vlist_out procedure.  p is the
1024  *  address of the vlist We assume that p is really a vlist node! */
synctexvlist(halfword this_box)1025 void synctexvlist(halfword this_box)
1026 {
1027     SYNCTEX_RETURN_IF_DISABLED;
1028 #   if SYNCTEX_DEBUG
1029     printf("\nSynchronize DEBUG: synctexhlist\n");
1030 #   endif
1031     if (SYNCTEX_IGNORE(this_box)) {
1032         return;
1033     }
1034     synctex_ctxt.node = this_box;   /*  0 to reset  */
1035     synctex_ctxt.recorder = NULL;   /*  reset  */
1036     synctex_ctxt.tag = SYNCTEX_TAG_MODEL(this_box,box);
1037     synctex_ctxt.line = SYNCTEX_LINE_MODEL(this_box,box);
1038     synctex_ctxt.curh = SYNCTEX_CURH;
1039     synctex_ctxt.curv = SYNCTEX_CURV;
1040     synctex_record_vlist(this_box);
1041 }
1042 
1043 static inline void synctex_record_tsilv(halfword p);
1044 
1045 /*  Recording a "f" line ending a vbox: this message is sent whenever a vlist
1046  *  has been shipped out. It is used to close the vlist nesting level. It is
1047  *  sent at the end of the vlist_out procedure in *TeX.web to balance a former
1048  *  synctex_vlist sent at the beginning of that procedure.    */
synctextsilv(halfword this_box)1049 void synctextsilv(halfword this_box)
1050 {
1051     SYNCTEX_RETURN_IF_DISABLED;
1052 #   if SYNCTEX_DEBUG
1053     printf("\nSynchronize DEBUG: synctextsilv\n");
1054 #   endif
1055     if (SYNCTEX_IGNORE(this_box)) {
1056         return;
1057     }
1058     /*  Ignoring any pending info to be recorded  */
1059     synctex_ctxt.node = this_box; /*  0 to reset  */
1060     synctex_ctxt.tag = SYNCTEX_TAG_MODEL(this_box,box);
1061     synctex_ctxt.line = SYNCTEX_LINE_MODEL(this_box,box);
1062     synctex_ctxt.curh = SYNCTEX_CURH;
1063     synctex_ctxt.curv = SYNCTEX_CURV;
1064     synctex_ctxt.recorder = NULL;
1065     synctex_record_tsilv(this_box);
1066 }
1067 
1068 static inline void synctex_record_void_vlist(halfword p);
1069 
1070 /*  This message is sent when a void vlist will be shipped out.
1071  *  There is no need to balance a void vlist.  */
synctexvoidvlist(halfword p,halfword this_box)1072 void synctexvoidvlist(halfword p, halfword this_box __attribute__ ((unused)))
1073 {
1074     SYNCTEX_RETURN_IF_DISABLED;
1075 #   if SYNCTEX_DEBUG
1076     printf("\nSynchronize DEBUG: synctexvoidvlist\n");
1077 #   endif
1078     if (SYNCTEX_IGNORE(p)) {
1079         return;
1080     }
1081     synctex_ctxt.node = p;          /*  reset  */
1082     synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,box);
1083     synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,box);
1084     synctex_ctxt.curh = SYNCTEX_CURH;
1085     synctex_ctxt.curv = SYNCTEX_CURV;
1086     synctex_ctxt.recorder = NULL;   /*  reset  */
1087     synctex_record_void_vlist(p);
1088 }
1089 
1090 static inline void synctex_record_hlist(halfword p);
1091 
1092 /*  This message is sent when an hlist will be shipped out, more precisely at
1093  *  the beginning of the hlist_out procedure in *TeX.web.  It will be balanced
1094  *  by a synctex_tsilh, sent at the end of the hlist_out procedure.  p is the
1095  *  address of the hlist We assume that p is really an hlist node! */
synctexhlist(halfword this_box)1096 void synctexhlist(halfword this_box)
1097 {
1098     SYNCTEX_RETURN_IF_DISABLED;
1099 #   if SYNCTEX_DEBUG
1100     printf("\nSynchronize DEBUG: synctexhlist\n");
1101 #   endif
1102     if (SYNCTEX_IGNORE(this_box)) {
1103         return;
1104     }
1105     synctex_ctxt.node = this_box;   /*  0 to reset  */
1106     synctex_ctxt.tag = SYNCTEX_TAG_MODEL(this_box,box);
1107     synctex_ctxt.line = SYNCTEX_LINE_MODEL(this_box,box);
1108     synctex_ctxt.curh = SYNCTEX_CURH;
1109     synctex_ctxt.curv = SYNCTEX_CURV;
1110     synctex_ctxt.recorder = NULL;   /*  reset  */
1111     synctex_record_hlist(this_box);
1112 }
1113 
1114 static inline void synctex_record_tsilh(halfword p);
1115 
1116 /*  Recording a ")" line ending an hbox this message is sent whenever an hlist
1117  *  has been shipped out it is used to close the hlist nesting level. It is
1118  *  sent at the end of the hlist_out procedure in *TeX.web to balance a former
1119  *  synctex_hlist sent at the beginning of that procedure.    */
synctextsilh(halfword this_box)1120 void synctextsilh(halfword this_box)
1121 {
1122     SYNCTEX_RETURN_IF_DISABLED;
1123 #   if SYNCTEX_DEBUG
1124     printf("\nSynchronize DEBUG: synctextsilh\n");
1125 #   endif
1126     if (SYNCTEX_IGNORE(this_box)) {
1127         return;
1128     }
1129     /*  Ignoring any pending info to be recorded  */
1130     synctex_ctxt.node = this_box;     /*  0 to force next node to be recorded!  */
1131     synctex_ctxt.tag = SYNCTEX_TAG_MODEL(this_box,box);
1132     synctex_ctxt.line = SYNCTEX_LINE_MODEL(this_box,box);
1133     synctex_ctxt.curh = SYNCTEX_CURH;
1134     synctex_ctxt.curv = SYNCTEX_CURV;
1135     synctex_ctxt.recorder = NULL;   /*  reset  */
1136     synctex_record_tsilh(this_box);
1137 }
1138 
1139 static inline void synctex_record_void_hlist(halfword p);
1140 
1141 /*  This message is sent when a void hlist will be shipped out.
1142  *  There is no need to balance a void hlist.  */
synctexvoidhlist(halfword p,halfword this_box)1143 void synctexvoidhlist(halfword p, halfword this_box __attribute__ ((unused)))
1144 {
1145     SYNCTEX_RETURN_IF_DISABLED;
1146 #   if SYNCTEX_DEBUG
1147     printf("\nSynchronize DEBUG: synctexvoidhlist\n");
1148 #   endif
1149     if (SYNCTEX_IGNORE(p)) {
1150         return;
1151     }
1152     /*  the sync context has changed  */
1153     if (synctex_ctxt.recorder != NULL) {
1154         /*  but was not yet recorded  */
1155         (*synctex_ctxt.recorder) (synctex_ctxt.node);
1156     }
1157     synctex_ctxt.node = p;          /*  0 to reset  */
1158     synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,box);
1159     synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,box);
1160     synctex_ctxt.curh = SYNCTEX_CURH;
1161     synctex_ctxt.curv = SYNCTEX_CURV;
1162     synctex_ctxt.recorder = NULL;   /*  reset  */
1163     synctex_record_void_hlist(p);
1164 }
1165 
1166 /* With LuaTeX we have to consider other node sizes than medium ones */
1167 #   define SYNCTEX_IGNORE_NODE(NODE,TYPE) SYNCTEX_IS_OFF || !SYNCTEX_VALUE \
1168 || (0 >= SYNCTEX_TAG_MODEL(NODE,TYPE)) \
1169 || (0 >= SYNCTEX_LINE_MODEL(NODE,TYPE))
1170 /*  This macro will detect a change in the synchronization context.  As long as
1171  *  the synchronization context remains the same, there is no need to write
1172  *  synchronization info: it would not help more.  The synchronization context
1173  *  has changed when either the line number or the file tag has changed.  */
1174 #   define SYNCTEX_CONTEXT_DID_CHANGE(NODE,TYPE) ((0 == synctex_ctxt.node)\
1175 || (SYNCTEX_TAG_MODEL(NODE,TYPE) != synctex_ctxt.tag)\
1176 || (SYNCTEX_LINE_MODEL(NODE,TYPE) != synctex_ctxt.line))
1177 
1178 void synctex_math_recorder(halfword p);
1179 
1180 /*  glue code, this message is sent whenever an inline math node will ship out
1181  See: @ @<Output the non-|char_node| |p| for...  */
synctexmath(halfword p,halfword this_box)1182 void synctexmath(halfword p, halfword this_box __attribute__ ((unused)))
1183 {
1184     SYNCTEX_RETURN_IF_DISABLED;
1185 #   if SYNCTEX_DEBUG
1186     printf("\nSynchronize DEBUG: synctexmath\n");
1187 #   endif
1188     if (SYNCTEX_IGNORE(p)) {
1189         return;
1190     }
1191     if ((synctex_ctxt.recorder != NULL) && SYNCTEX_CONTEXT_DID_CHANGE(p,math)) {
1192         /*  the sync context did change  */
1193         (*synctex_ctxt.recorder) (synctex_ctxt.node);
1194     }
1195     synctex_ctxt.node = p;
1196     synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,math);
1197     synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,math);
1198     synctex_ctxt.curh = SYNCTEX_CURH;
1199     synctex_ctxt.curv = SYNCTEX_CURV;
1200     synctex_ctxt.recorder = NULL;/*  no need to record once more  */
1201     synctex_math_recorder(p);/*  always record synchronously  */
1202 }
1203 
1204 static inline void synctex_record_glue(halfword p);
1205 static inline void synctex_record_kern(halfword p);
1206 static inline void synctex_record_rule(halfword p);
1207 
1208 /*  this message is sent whenever an horizontal glue node or rule node ships out
1209  See: move_past:...    */
1210 #   undef SYNCTEX_IGNORE
1211 #   define SYNCTEX_IGNORE(NODE,TYPE) SYNCTEX_IS_OFF || !SYNCTEX_VALUE \
1212 || (0 >= SYNCTEX_TAG_MODEL(NODE,TYPE)) \
1213 || (0 >= SYNCTEX_LINE_MODEL(NODE,TYPE))
synctexhorizontalruleorglue(halfword p,halfword this_box)1214 void synctexhorizontalruleorglue(halfword p, halfword this_box
1215                                  __attribute__ ((unused)))
1216 {
1217     SYNCTEX_RETURN_IF_DISABLED;
1218 #   if SYNCTEX_DEBUG
1219     printf("\nSynchronize DEBUG: synctexglue\n");
1220 #   endif
1221     switch (SYNCTEX_TYPE(p)) {
1222         case rule_node:
1223             if (SYNCTEX_IGNORE(p,rule)) {
1224                 return;
1225             }
1226             break;
1227         case glue_node:
1228             if (SYNCTEX_IGNORE(p,glue)) {
1229                 return;
1230             }
1231             break;
1232         case kern_node:
1233             if (SYNCTEX_IGNORE(p,kern)) {
1234                 return;
1235             }
1236             break;
1237         default:
1238             printf("\nSynchronize ERROR: unknown node type %i\n", SYNCTEX_TYPE(p));
1239     }
1240     synctex_ctxt.node = p;
1241     synctex_ctxt.curh = SYNCTEX_CURH;
1242     synctex_ctxt.curv = SYNCTEX_CURV;
1243     synctex_ctxt.recorder = NULL;
1244     switch (SYNCTEX_TYPE(p)) {
1245         case rule_node:
1246             synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,rule);
1247             synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,rule);
1248             synctex_record_rule(p); /*  always record synchronously: maybe some text is outside the box  */
1249             break;
1250         case glue_node:
1251             synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,glue);
1252             synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,glue);
1253             synctex_record_glue(p); /*  always record synchronously: maybe some text is outside the box  */
1254             break;
1255         case kern_node:
1256             synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,kern);
1257             synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,kern);
1258             synctex_record_kern(p); /*  always record synchronously: maybe some text is outside the box  */
1259             break;
1260         default:
1261             printf("\nSynchronize ERROR: unknown node type %i\n", SYNCTEX_TYPE(p));
1262     }
1263 }
1264 
1265 void synctex_kern_recorder(halfword p);
1266 
1267 /*  this message is sent whenever a kern node ships out
1268  See: @ @<Output the non-|char_node| |p| for...    */
synctexkern(halfword p,halfword this_box)1269 void synctexkern(halfword p, halfword this_box)
1270 {
1271     SYNCTEX_RETURN_IF_DISABLED;
1272 #   if SYNCTEX_DEBUG
1273     printf("\nSynchronize DEBUG: synctexkern\n");
1274 #   endif
1275     if (SYNCTEX_IGNORE(p,kern)) {
1276         return;
1277     }
1278     if (SYNCTEX_CONTEXT_DID_CHANGE(p,kern)) {
1279         /*  the sync context has changed  */
1280         if (synctex_ctxt.recorder != NULL) {
1281             /*  but was not yet recorded  */
1282             (*synctex_ctxt.recorder) (synctex_ctxt.node);
1283         }
1284         if (synctex_ctxt.node == this_box) {
1285             /* first node in the list */
1286             synctex_ctxt.node = p;
1287             synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,kern);
1288             synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,kern);
1289             synctex_ctxt.recorder = &synctex_kern_recorder;
1290         } else {
1291             synctex_ctxt.node = p;
1292             synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,kern);
1293             synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,kern);
1294             synctex_ctxt.recorder = NULL;
1295             /*  always record when the context has just changed
1296              *  and when not the first node  */
1297             synctex_kern_recorder(p);
1298         }
1299     } else {
1300         /*  just update the geometry and type (for future improvements)  */
1301         synctex_ctxt.node = p;
1302         synctex_ctxt.tag = SYNCTEX_TAG_MODEL(p,kern);
1303         synctex_ctxt.line = SYNCTEX_LINE_MODEL(p,kern);
1304         synctex_ctxt.recorder = &synctex_kern_recorder;
1305     }
1306 }
1307 
1308 /*  This last part is used as a tool to infer TeX behaviour,
1309  *  but not for direct synchronization. */
1310 #   undef SYNCTEX_IGNORE
1311 #   define SYNCTEX_IGNORE(NODE) SYNCTEX_IS_OFF || !SYNCTEX_VALUE || !SYNCTEX_FILE \
1312 || (synctex_ctxt.count>2000)
1313 
1314 void synctex_char_recorder(halfword p);
1315 
1316 /*  this message is sent whenever a char node ships out    */
synctexchar(halfword p,halfword this_box)1317 void synctexchar(halfword p, halfword this_box __attribute__ ((unused)))
1318 {
1319     SYNCTEX_RETURN_IF_DISABLED;
1320 #   if SYNCTEX_DEBUG
1321     printf("\nSynchronize DEBUG: synctexchar\n");
1322 #   endif
1323     if (SYNCTEX_IGNORE(p)) {
1324         return;
1325     }
1326     if (synctex_ctxt.recorder != NULL) {
1327         /*  but was not yet recorded  */
1328         (*synctex_ctxt.recorder) (synctex_ctxt.node);
1329     }
1330     synctex_ctxt.node = p;
1331     synctex_ctxt.tag = 0;
1332     synctex_ctxt.line = 0;
1333     synctex_ctxt.recorder = NULL;
1334     /*  always record when the context has just changed  */
1335     synctex_char_recorder(p);
1336 }
1337 
1338 void synctex_node_recorder(halfword p);
1339 
1340 #   undef SYNCTEX_IGNORE
1341 #   define SYNCTEX_IGNORE(NODE) (SYNCTEX_IS_OFF || !SYNCTEX_VALUE || !SYNCTEX_FILE)
1342 
1343 /*  this message should be sent to record information
1344  for a node of an unknown type    */
synctexnode(halfword p,halfword this_box)1345 void synctexnode(halfword p, halfword this_box __attribute__ ((unused)))
1346 {
1347     SYNCTEX_RETURN_IF_DISABLED;
1348 #   if SYNCTEX_DEBUG
1349     printf("\nSynchronize DEBUG: synctexnode\n");
1350 #   endif
1351     if (SYNCTEX_IGNORE(p)) {
1352         return;
1353     }
1354     /*  always record, not very usefull yet  */
1355     synctex_node_recorder(p);
1356 }
1357 
1358 /*  this message should be sent to record information
1359  synchronously for the current location    */
synctexcurrent(void)1360 void synctexcurrent(void)
1361 {
1362     SYNCTEX_RETURN_IF_DISABLED;
1363 #   if SYNCTEX_DEBUG
1364     printf("\nSynchronize DEBUG: synctexcurrent\n");
1365 #   endif
1366     if (SYNCTEX_IGNORE(nothing)) {
1367         return;
1368     } else {
1369         int len = SYNCTEX_fprintf(SYNCTEX_FILE, "x%i,%i:%i,%i\n",
1370                                   synctex_ctxt.tag,synctex_ctxt.line,
1371                                   SYNCTEX_CURH UNIT,SYNCTEX_CURV UNIT);
1372         if (len > 0) {
1373             synctex_ctxt.total_length += len;
1374             return;
1375         }
1376     }
1377     synctexabort(0);
1378     return;
1379 }
1380 
1381 /*  Recording the settings  */
synctex_record_settings(void)1382 static inline int synctex_record_settings(void)
1383 {
1384 #   if SYNCTEX_DEBUG > 999
1385     printf("\nSynchronize DEBUG: synctex_record_settings\n");
1386 #   endif
1387     if (NULL == SYNCTEX_FILE) {
1388         return SYNCTEX_NOERR;
1389     }
1390     if (SYNCTEX_FILE) {
1391         int len = SYNCTEX_fprintf(SYNCTEX_FILE, "Output:%s\nMagnification:%i\nUnit:%i\nX Offset:%i\nY Offset:%i\n",
1392                                   SYNCTEX_OUTPUT,synctex_ctxt.magnification,synctex_ctxt.unit,
1393                                   ((SYNCTEX_OFFSET_IS_PDF != 0) ? 0 : 4736287 UNIT),
1394                                   ((SYNCTEX_OFFSET_IS_PDF != 0) ? 0 : 4736287 UNIT));
1395         if (len > 0) {
1396             synctex_ctxt.total_length += len;
1397             return SYNCTEX_NOERR;
1398         }
1399     }
1400     synctexabort(0);
1401     return -1;
1402 }
1403 
1404 /*  Recording a "SyncTeX..." line  */
synctex_record_preamble(void)1405 static inline int synctex_record_preamble(void)
1406 {
1407     int len = 0;
1408 #   if SYNCTEX_DEBUG > 999
1409     printf("\nSynchronize DEBUG: synctex_record_preamble\n");
1410 #   endif
1411     len =
1412     SYNCTEX_fprintf(SYNCTEX_FILE, "SyncTeX Version:%i\n", SYNCTEX_VERSION);
1413     if (len > 0) {
1414         synctex_ctxt.total_length = len;
1415         return SYNCTEX_NOERR;
1416     }
1417     synctexabort(0);
1418     return -1;
1419 }
1420 
1421 /*  Recording a "Input:..." line  */
synctex_record_input(integer tag,char * name)1422 static inline int synctex_record_input(integer tag, char *name)
1423 {
1424     int len = 0;
1425 #   if SYNCTEX_DEBUG > 999
1426     printf("\nSynchronize DEBUG: synctex_record_input\n");
1427 #   endif
1428     len = SYNCTEX_fprintf(SYNCTEX_FILE, "Input:%i:%s\n", tag, name);
1429     if (len > 0) {
1430         synctex_ctxt.total_length += len;
1431         return SYNCTEX_NOERR;
1432     }
1433     synctexabort(0);
1434     return -1;
1435 }
1436 
1437 /*  Recording a "!..." line  */
synctex_record_anchor(void)1438 static inline int synctex_record_anchor(void)
1439 {
1440     int len = 0;
1441 #   if SYNCTEX_DEBUG > 999
1442     printf("\nSynchronize DEBUG: synctex_record_anchor\n");
1443 #   endif
1444     len = SYNCTEX_fprintf(SYNCTEX_FILE, "!%i\n", synctex_ctxt.total_length);
1445     if (len > 0) {
1446         synctex_ctxt.total_length = len;
1447         ++synctex_ctxt.count;
1448         return SYNCTEX_NOERR;
1449     }
1450     synctexabort(0);
1451     return -1;
1452 }
1453 
1454 /*  Recording a "Content" line  */
synctex_record_content(void)1455 static inline int synctex_record_content(void)
1456 {
1457     int len = 0;
1458 #   if SYNCTEX_DEBUG > 999
1459     printf("\nSynchronize DEBUG: synctex_record_content\n");
1460 #   endif
1461     len = SYNCTEX_fprintf(SYNCTEX_FILE, "Content:\n");
1462     if (len > 0) {
1463         synctex_ctxt.total_length += len;
1464         return SYNCTEX_NOERR;
1465     }
1466     synctexabort(0);
1467     return -1;
1468 }
1469 
1470 /*  Recording a "{..." line  */
synctex_record_sheet(integer sheet)1471 static inline int synctex_record_sheet(integer sheet)
1472 {
1473 #   if SYNCTEX_DEBUG > 999
1474     printf("\nSynchronize DEBUG: synctex_record_sheet\n");
1475 #   endif
1476     if (SYNCTEX_NOERR == synctex_record_anchor()) {
1477         int len = SYNCTEX_fprintf(SYNCTEX_FILE, "{%i\n", sheet);
1478         if (len > 0) {
1479             synctex_ctxt.total_length += len;
1480             ++synctex_ctxt.count;
1481             return SYNCTEX_NOERR;
1482         }
1483     }
1484     synctexabort(0);
1485     return -1;
1486 }
1487 
1488 /*  Recording a "}..." line  */
synctex_record_teehs(integer sheet)1489 static inline int synctex_record_teehs(integer sheet)
1490 {
1491 #   if SYNCTEX_DEBUG > 999
1492     printf("\nSynchronize DEBUG: synctex_record_teehs\n");
1493 #   endif
1494     if (SYNCTEX_NOERR == synctex_record_anchor()) {
1495         int len = SYNCTEX_fprintf(SYNCTEX_FILE, "}%i\n", sheet);
1496         if (len > 0) {
1497             synctex_ctxt.total_length += len;
1498             ++synctex_ctxt.count;
1499             return SYNCTEX_NOERR;
1500         }
1501     }
1502     synctexabort(0);
1503     return -1;
1504 }
1505 
1506 /*  Recording a "v..." line  */
synctex_record_void_vlist(halfword p)1507 static inline void synctex_record_void_vlist(halfword p)
1508 {
1509     int len = 0;
1510 #   if SYNCTEX_DEBUG > 999
1511     printf("\nSynchronize DEBUG: synctex_record_void_vlist\n");
1512 #   endif
1513     len = SYNCTEX_fprintf(SYNCTEX_FILE, "v%i,%i:%i,%i:%i,%i,%i\n",
1514                           SYNCTEX_TAG_MODEL(p,box),
1515                           SYNCTEX_LINE_MODEL(p,box),
1516                           synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT,
1517                           SYNCTEX_WIDTH(p) UNIT,
1518                           SYNCTEX_HEIGHT(p) UNIT,
1519                           SYNCTEX_DEPTH(p) UNIT);
1520     if (len > 0) {
1521         synctex_ctxt.total_length += len;
1522         ++synctex_ctxt.count;
1523         return;
1524     }
1525     synctexabort(0);
1526     return;
1527 }
1528 
1529 /*  Recording a "[..." line  */
synctex_record_vlist(halfword p)1530 static inline void synctex_record_vlist(halfword p)
1531 {
1532     int len = 0;
1533     SYNCTEX_NOT_VOID = SYNCTEX_YES;
1534 #   if SYNCTEX_DEBUG > 999
1535     printf("\nSynchronize DEBUG: synctex_record_vlist\n");
1536 #   endif
1537     len = SYNCTEX_fprintf(SYNCTEX_FILE, "[%i,%i:%i,%i:%i,%i,%i\n",
1538                           SYNCTEX_TAG_MODEL(p,box),
1539                           SYNCTEX_LINE_MODEL(p,box),
1540                           synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT,
1541                           SYNCTEX_WIDTH(p) UNIT,
1542                           SYNCTEX_HEIGHT(p) UNIT,
1543                           SYNCTEX_DEPTH(p) UNIT);
1544     if (len > 0) {
1545         synctex_ctxt.total_length += len;
1546         ++synctex_ctxt.count;
1547         return;
1548     }
1549     synctexabort(0);
1550     return;
1551 }
1552 
1553 /*  Recording a "]..." line  */
synctex_record_tsilv(halfword p)1554 static inline void synctex_record_tsilv(halfword p __attribute__ ((unused)))
1555 {
1556     int len = 0;
1557 #   if SYNCTEX_DEBUG > 999
1558     printf("\nSynchronize DEBUG: synctex_record_tsilv\n");
1559 #   endif
1560     len = SYNCTEX_fprintf(SYNCTEX_FILE, "]\n");
1561     if (len > 0) {
1562         synctex_ctxt.total_length += len;
1563         return;
1564     }
1565     synctexabort(0);
1566     return;
1567 }
1568 
1569 /*  Recording a "h..." line  */
synctex_record_void_hlist(halfword p)1570 static inline void synctex_record_void_hlist(halfword p)
1571 {
1572     int len = 0;
1573 #   if SYNCTEX_DEBUG > 999
1574     printf("\nSynchronize DEBUG: synctex_record_void_hlist\n");
1575 #   endif
1576     len = SYNCTEX_fprintf(SYNCTEX_FILE, "h%i,%i:%i,%i:%i,%i,%i\n",
1577                           SYNCTEX_TAG_MODEL(p,box),
1578                           SYNCTEX_LINE_MODEL(p,box),
1579                           synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT,
1580                           SYNCTEX_WIDTH(p) UNIT,
1581                           SYNCTEX_HEIGHT(p) UNIT,
1582                           SYNCTEX_DEPTH(p) UNIT);
1583     if (len > 0) {
1584         synctex_ctxt.total_length += len;
1585         ++synctex_ctxt.count;
1586         return;
1587     }
1588     synctexabort(0);
1589     return;
1590 }
1591 
1592 /*  Recording a "(..." line  */
synctex_record_hlist(halfword p)1593 static inline void synctex_record_hlist(halfword p)
1594 {
1595     int len = 0;
1596     SYNCTEX_NOT_VOID = SYNCTEX_YES;
1597 #   if SYNCTEX_DEBUG > 999
1598     printf("\nSynchronize DEBUG: synctex_record_hlist\n");
1599 #   endif
1600     len = SYNCTEX_fprintf(SYNCTEX_FILE, "(%i,%i:%i,%i:%i,%i,%i\n",
1601                           SYNCTEX_TAG_MODEL(p,box),
1602                           SYNCTEX_LINE_MODEL(p,box),
1603                           synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT,
1604                           SYNCTEX_WIDTH(p) UNIT,
1605                           SYNCTEX_HEIGHT(p) UNIT,
1606                           SYNCTEX_DEPTH(p) UNIT);
1607     if (len > 0) {
1608         synctex_ctxt.total_length += len;
1609         ++synctex_ctxt.count;
1610         return;
1611     }
1612     synctexabort(0);
1613     return;
1614 }
1615 
1616 /*  Recording a ")..." line  */
synctex_record_tsilh(halfword p)1617 static inline void synctex_record_tsilh(halfword p __attribute__ ((unused)))
1618 {
1619     int len = 0;
1620 #   if SYNCTEX_DEBUG > 999
1621     printf("\nSynchronize DEBUG: synctex_record_tsilh\n");
1622 #   endif
1623     len = SYNCTEX_fprintf(SYNCTEX_FILE, ")\n");
1624     if (len > 0) {
1625         synctex_ctxt.total_length += len;
1626         ++synctex_ctxt.count;
1627         return;
1628     }
1629     synctexabort(0);
1630     return;
1631 }
1632 
1633 /*  Recording a "Count..." line  */
synctex_record_count(void)1634 static inline int synctex_record_count(void)
1635 {
1636     int len = 0;
1637 #   if SYNCTEX_DEBUG > 999
1638     printf("\nSynchronize DEBUG: synctex_record_count\n");
1639 #   endif
1640     len = SYNCTEX_fprintf(SYNCTEX_FILE, "Count:%i\n", synctex_ctxt.count);
1641     if (len > 0) {
1642         synctex_ctxt.total_length += len;
1643         return SYNCTEX_NOERR;
1644     }
1645     synctexabort(0);
1646     return -1;
1647 }
1648 
1649 /*  Recording a "Postamble" section  */
synctex_record_postamble(void)1650 static inline int synctex_record_postamble(void)
1651 {
1652 #   if SYNCTEX_DEBUG > 999
1653     printf("\nSynchronize DEBUG: synctex_record_postamble\n");
1654 #   endif
1655     if (SYNCTEX_NOERR == synctex_record_anchor()) {
1656         int len = SYNCTEX_fprintf(SYNCTEX_FILE, "Postamble:\n");
1657         if (len > 0) {
1658             synctex_ctxt.total_length += len;
1659             if (synctex_record_count() || synctex_record_anchor()) {
1660             } else {
1661                 len = SYNCTEX_fprintf(SYNCTEX_FILE, "Post scriptum:\n");
1662                 if (len > 0) {
1663                     synctex_ctxt.total_length += len;
1664                     return SYNCTEX_NOERR;
1665                 }
1666             }
1667         }
1668     }
1669     synctexabort(0);
1670     return -1;
1671 }
1672 
1673 /*  Recording a "g..." line  */
synctex_record_glue(halfword p)1674 static inline void synctex_record_glue(halfword p)
1675 {
1676     int len = 0;
1677 #   if SYNCTEX_DEBUG > 999
1678     printf("\nSynchronize DEBUG: synctex_glue_recorder\n");
1679 #   endif
1680     len = SYNCTEX_fprintf(SYNCTEX_FILE, "g%i,%i:%i,%i\n",
1681                           SYNCTEX_TAG_MODEL(p,glue),
1682                           SYNCTEX_LINE_MODEL(p,glue),
1683                           synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT);
1684     if (len > 0) {
1685         synctex_ctxt.total_length += len;
1686         ++synctex_ctxt.count;
1687         return;
1688     }
1689     synctexabort(0);
1690     return;
1691 }
1692 
1693 /*  Recording a "k..." line  */
synctex_record_kern(halfword p)1694 static inline void synctex_record_kern(halfword p)
1695 {
1696     int len = 0;
1697 #   if SYNCTEX_DEBUG > 999
1698     printf("\nSynchronize DEBUG: synctex_kern_recorder\n");
1699 #   endif
1700     len = SYNCTEX_fprintf(SYNCTEX_FILE, "k%i,%i:%i,%i:%i\n",
1701                           SYNCTEX_TAG_MODEL(p,glue),
1702                           SYNCTEX_LINE_MODEL(p,glue),
1703                           synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT,
1704                           SYNCTEX_WIDTH(p) UNIT);
1705     if (len > 0) {
1706         synctex_ctxt.total_length += len;
1707         ++synctex_ctxt.count;
1708         return;
1709     }
1710     synctexabort(0);
1711     return;
1712 }
1713 
1714 /*  Recording a "r..." line  */
synctex_record_rule(halfword p)1715 static inline void synctex_record_rule(halfword p)
1716 {
1717     int len = 0;
1718 #   if SYNCTEX_DEBUG > 999
1719     printf("\nSynchronize DEBUG: synctex_record_tsilh\n");
1720 #   endif
1721     len = SYNCTEX_fprintf(SYNCTEX_FILE, "r%i,%i:%i,%i:%i,%i,%i\n",
1722                           SYNCTEX_TAG_MODEL(p,rule),
1723                           SYNCTEX_LINE_MODEL(p,rule),
1724                           synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT,
1725                           SYNCTEX_RULE_WD UNIT, SYNCTEX_RULE_HT UNIT, SYNCTEX_RULE_DP UNIT);
1726     if (len > 0) {
1727         synctex_ctxt.total_length += len;
1728         ++synctex_ctxt.count;
1729         return;
1730     }
1731     synctexabort(0);
1732     return;
1733 }
1734 
1735 /*  Recording a "$..." line  */
synctex_math_recorder(halfword p)1736 void synctex_math_recorder(halfword p)
1737 {
1738     int len = 0;
1739 #   if SYNCTEX_DEBUG > 999
1740     printf("\nSynchronize DEBUG: synctex_math_recorder\n");
1741 #   endif
1742     len = SYNCTEX_fprintf(SYNCTEX_FILE, "$%i,%i:%i,%i\n",
1743                           SYNCTEX_TAG_MODEL(p, math),
1744                           SYNCTEX_LINE_MODEL(p, math),
1745                           synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT);
1746     if (len > 0) {
1747         synctex_ctxt.total_length += len;
1748         ++synctex_ctxt.count;
1749         return;
1750     }
1751     synctexabort(0);
1752     return;
1753 }
1754 
1755 /*  Recording a "k..." line  */
synctex_kern_recorder(halfword p)1756 void synctex_kern_recorder(halfword p)
1757 {
1758     int len = 0;
1759 #   if SYNCTEX_DEBUG > 999
1760     printf("\nSynchronize DEBUG: synctex_kern_recorder\n");
1761 #   endif
1762     len = SYNCTEX_fprintf(SYNCTEX_FILE, "k%i,%i:%i,%i:%i\n",
1763                           SYNCTEX_TAG_MODEL(p, kern),
1764                           SYNCTEX_LINE_MODEL(p, kern),
1765                           synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT,
1766                           SYNCTEX_WIDTH(p) UNIT);
1767     if (len > 0) {
1768         synctex_ctxt.total_length += len;
1769         ++synctex_ctxt.count;
1770         return;
1771     }
1772     synctexabort(0);
1773     return;
1774 }
1775 
1776 /*  Recording a "c..." line  */
synctex_char_recorder(halfword p)1777 void synctex_char_recorder(halfword p __attribute__ ((unused)))
1778 {
1779     int len = 0;
1780 #   if SYNCTEX_DEBUG > 999
1781     printf("\nSynchronize DEBUG: synctex_char_recorder\n");
1782 #   endif
1783     len = SYNCTEX_fprintf(SYNCTEX_FILE, "c%i,%i\n",
1784                           synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT);
1785     if (len > 0) {
1786         synctex_ctxt.total_length += len;
1787         ++synctex_ctxt.count;
1788         return;
1789     }
1790     synctexabort(0);
1791     return;
1792 }
1793 
1794 /*  Recording a "?..." line, type, subtype and position  */
synctex_node_recorder(halfword p)1795 void synctex_node_recorder(halfword p)
1796 {
1797     int len = 0;
1798 #   if SYNCTEX_DEBUG > 999
1799     printf("\nSynchronize DEBUG: synctex_node_recorder(0x%x)\n", p);
1800 #   endif
1801     len = SYNCTEX_fprintf(SYNCTEX_FILE, "?%i,%i:%i,%i\n",
1802                           synctex_ctxt.curh UNIT, synctex_ctxt.curv UNIT,
1803                           SYNCTEX_TYPE(p), SYNCTEX_SUBTYPE(p));
1804     if (len > 0) {
1805         synctex_ctxt.total_length += len;
1806         ++synctex_ctxt.count;
1807         return;
1808     }
1809     synctexabort(0);
1810     return;
1811 }
1812 #   endif
1813