sinc with TL 36732
[luatex.git] / source / texk / web2c / synctexdir / synctex.c
blobc01e4480245da6e9a9f4d4c25f8d87ada8437658
1 /*
2 Copyright (c) 2008, 2009, 2010, 2011 jerome DOT laurens AT u-bourgogne DOT fr
4 This file is part of the SyncTeX package.
6 Latest Revision: Fri Apr 15 19:10:57 UTC 2011
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:
19 The above copyright notice and this permission notice shall be
20 included in all copies or substantial portions of the Software.
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
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.
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.
49 All these are up to a great extent de facto definitions, which means that they
50 are partly defined by the implementation itself.
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.
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.
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
73 Please, do not remove these explanations.
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
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.
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
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
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.
120 Version 1
121 Latest Revision: Wed Jul 1 08:15:44 UTC 2009
125 # define SYNCTEX_VERSION 1
127 # define SYNCTEX_DEBUG 0
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 ;
133 # define SYNCTEX_NOERR 0
135 # define EXTERN extern
137 # ifdef xfree
138 # define SYNCTEX_FREE xfree
139 # else
140 # define SYNCTEX_FREE(x) free(x)
141 # endif
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
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
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. */
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. */
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.
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=... */
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
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
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
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
334 /* For non-GCC compilation. */
335 # if !defined(__GNUC__) || (__GNUC__ < 2)
336 # define __attribute__(A)
337 # endif
339 # include "synctex.h"
341 # define SYNCTEX_YES (1)
342 # define SYNCTEX_NO (0)
343 # define SYNCTEX_NO_ERROR (0)
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.
369 # if defined(__SyncTeX__)
371 # include <stdio.h>
372 # include <stdarg.h>
373 # include "zlib.h"
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 */
378 # define SYNCTEX_BITS_PER_BYTE 8
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}};
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)
418 /* Initialize the options, synchronize the variables.
419 * This is sent by *tex.web before any TeX macro is used.
420 * */
421 void synctexinitcommand(void)
423 /* This is a one shot function, any subsequent call is void */
424 if (synctex_ctxt.flags.option_read) {
425 return;
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;
440 /* Initialize the content of the \synctex primitive */
441 SYNCTEX_VALUE = synctex_options;
443 synctex_ctxt.flags.option_read = SYNCTEX_YES;
444 return;
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. */
450 void synctexabort(boolean log_opened __attribute__ ((unused)))
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);
462 SYNCTEX_FILE = NULL;
463 remove(synctex_ctxt.busy_name);
464 SYNCTEX_FREE(synctex_ctxt.busy_name);
465 synctex_ctxt.busy_name = NULL;
467 if (NULL != synctex_ctxt.root_name) {
468 SYNCTEX_FREE(synctex_ctxt.root_name);
469 synctex_ctxt.root_name = NULL;
471 SYNCTEX_IS_OFF = SYNCTEX_YES; /* disable synctex */
474 static inline int synctex_record_preamble(void);
475 static inline int synctex_record_input(integer tag, char *name);
477 static const char *synctex_suffix = ".synctex";
478 static const char *synctex_suffix_gz = ".gz";
479 static const char *synctex_suffix_busy = "(busy)";
481 /* for DIR_SEP_STRING */
482 # include <kpathsea/c-pathch.h>
483 /* for kpse_absolute_p */
484 # include <kpathsea/absolute.h>
486 #ifdef W32UPTEXSYNCTEX
487 static char *chgto_oem(char *src)
489 wchar_t *sw = NULL;
490 char *dst = NULL;
491 static int f_codepage = 0;
493 if(f_codepage == 0) {
494 f_codepage = AreFileApisANSI() ? GetACP() : GetOEMCP();
497 if(f_codepage == file_system_codepage) {
498 dst = xstrdup(src);
499 return dst;
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;
508 static gzFile fsyscp_gzopen(const char *path, const char *mode)
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;
518 static int fsyscp_remove(char *s)
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;
528 static int fsyscp_rename(char *s1, char *s2)
530 wchar_t *sw1 = NULL, *sw2 = NULL;
531 int ret;
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;
541 #undef fopen
542 #define fopen fsyscp_fopen
543 #define gzopen fsyscp_gzopen
544 #define rename fsyscp_rename
545 #endif
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.
555 static void *synctex_dot_open(void)
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 */
566 if (SYNCTEX_FILE) {
567 return SYNCTEX_FILE; /* synchronization is already enabled */
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. */
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)
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;
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);
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);
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);
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);
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;
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);
665 SYNCTEX_FREE(the_busy_name);
666 the_busy_name = NULL;
667 } else {
668 printf("\nSyncTeX information: no synchronization with keyboard input\n");
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
680 return SYNCTEX_FILE;
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.
701 void synctexstartinput(void)
703 static unsigned int synctex_tag_counter = 0;
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
713 if (SYNCTEX_IS_OFF) {
714 return;
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;
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");
746 # if SYNCTEX_DEBUG
747 printf("\nwarning: Synchronize DEBUG: synctexstartinput first END\n");
748 # endif
749 return;
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);
764 # if SYNCTEX_DEBUG
765 printf("\nwarning: Synchronize DEBUG: synctexstartinput END\n");
766 # endif
767 return;
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.
777 static inline int synctex_record_postamble(void);
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.
791 void synctexterminate(boolean log_opened)
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;
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;
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);
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);
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);
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);
851 # endif
852 #ifdef W32UPTEXSYNCTEX
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);
859 #else
860 printf((synctex_ctxt.flags.quoted ? "\nSyncTeX written on \"%s\"" : "\nSyncTeX written on %s."),
861 tmp);
862 #endif
863 tmp = NULL;
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);
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);
877 SYNCTEX_FILE = NULL;
878 remove(synctex_ctxt.busy_name);
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);
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;
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';
909 } else {
910 strcpy(the_real_syncname, tmp);
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);
926 SYNCTEX_FILE = NULL;
927 /* removing the working synctex file */
928 remove(synctex_ctxt.busy_name);
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);
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);
942 /* Recording the "{..." line. In *tex.web, use synctex_sheet(pdf_output) at
943 * the very beginning of the ship_out procedure.
945 void synctexsheet(integer mag)
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.");
957 return;
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;
970 if (SYNCTEX_NO_ERROR != synctex_record_settings()
971 || SYNCTEX_NO_ERROR != synctex_record_content()) {
972 synctexabort(0);
973 return;
976 synctex_record_sheet(SYNCTEX_GET_TOTAL_PAGES()+1);
978 # if SYNCTEX_DEBUG
979 printf("\nSynchronize DEBUG: synctexsheet END\n");
980 # endif
981 return;
984 static inline int synctex_record_teehs(integer sheet);
986 /* Recording the "}..." line. In *tex.web, use synctex_teehs at
987 * the very end of the ship_out procedure.
989 void synctexteehs(void)
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;
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;
1005 static inline void synctex_record_vlist(halfword p);
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
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! */
1025 void synctexvlist(halfword this_box)
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;
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);
1043 static inline void synctex_record_tsilv(halfword p);
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. */
1049 void synctextsilv(halfword this_box)
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;
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);
1068 static inline void synctex_record_void_vlist(halfword p);
1070 /* This message is sent when a void vlist will be shipped out.
1071 * There is no need to balance a void vlist. */
1072 void synctexvoidvlist(halfword p, halfword this_box __attribute__ ((unused)))
1074 SYNCTEX_RETURN_IF_DISABLED;
1075 # if SYNCTEX_DEBUG
1076 printf("\nSynchronize DEBUG: synctexvoidvlist\n");
1077 # endif
1078 if (SYNCTEX_IGNORE(p)) {
1079 return;
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);
1090 static inline void synctex_record_hlist(halfword p);
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! */
1096 void synctexhlist(halfword this_box)
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;
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);
1114 static inline void synctex_record_tsilh(halfword p);
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. */
1120 void synctextsilh(halfword this_box)
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;
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);
1139 static inline void synctex_record_void_hlist(halfword p);
1141 /* This message is sent when a void hlist will be shipped out.
1142 * There is no need to balance a void hlist. */
1143 void synctexvoidhlist(halfword p, halfword this_box __attribute__ ((unused)))
1145 SYNCTEX_RETURN_IF_DISABLED;
1146 # if SYNCTEX_DEBUG
1147 printf("\nSynchronize DEBUG: synctexvoidhlist\n");
1148 # endif
1149 if (SYNCTEX_IGNORE(p)) {
1150 return;
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);
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);
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))
1178 void synctex_math_recorder(halfword p);
1180 /* glue code, this message is sent whenever an inline math node will ship out
1181 See: @ @<Output the non-|char_node| |p| for... */
1182 void synctexmath(halfword p, halfword this_box __attribute__ ((unused)))
1184 SYNCTEX_RETURN_IF_DISABLED;
1185 # if SYNCTEX_DEBUG
1186 printf("\nSynchronize DEBUG: synctexmath\n");
1187 # endif
1188 if (SYNCTEX_IGNORE(p)) {
1189 return;
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);
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 */
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);
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))
1214 void synctexhorizontalruleorglue(halfword p, halfword this_box
1215 __attribute__ ((unused)))
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;
1226 break;
1227 case glue_node:
1228 if (SYNCTEX_IGNORE(p,glue)) {
1229 return;
1231 break;
1232 case kern_node:
1233 if (SYNCTEX_IGNORE(p,kern)) {
1234 return;
1236 break;
1237 default:
1238 printf("\nSynchronize ERROR: unknown node type %i\n", SYNCTEX_TYPE(p));
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));
1265 void synctex_kern_recorder(halfword p);
1267 /* this message is sent whenever a kern node ships out
1268 See: @ @<Output the non-|char_node| |p| for... */
1269 void synctexkern(halfword p, halfword this_box)
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;
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);
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);
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;
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)
1314 void synctex_char_recorder(halfword p);
1316 /* this message is sent whenever a char node ships out */
1317 void synctexchar(halfword p, halfword this_box __attribute__ ((unused)))
1319 SYNCTEX_RETURN_IF_DISABLED;
1320 # if SYNCTEX_DEBUG
1321 printf("\nSynchronize DEBUG: synctexchar\n");
1322 # endif
1323 if (SYNCTEX_IGNORE(p)) {
1324 return;
1326 if (synctex_ctxt.recorder != NULL) {
1327 /* but was not yet recorded */
1328 (*synctex_ctxt.recorder) (synctex_ctxt.node);
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);
1338 void synctex_node_recorder(halfword p);
1340 # undef SYNCTEX_IGNORE
1341 # define SYNCTEX_IGNORE(NODE) (SYNCTEX_IS_OFF || !SYNCTEX_VALUE || !SYNCTEX_FILE)
1343 /* this message should be sent to record information
1344 for a node of an unknown type */
1345 void synctexnode(halfword p, halfword this_box __attribute__ ((unused)))
1347 SYNCTEX_RETURN_IF_DISABLED;
1348 # if SYNCTEX_DEBUG
1349 printf("\nSynchronize DEBUG: synctexnode\n");
1350 # endif
1351 if (SYNCTEX_IGNORE(p)) {
1352 return;
1354 /* always record, not very usefull yet */
1355 synctex_node_recorder(p);
1358 /* this message should be sent to record information
1359 synchronously for the current location */
1360 void synctexcurrent(void)
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;
1377 synctexabort(0);
1378 return;
1381 /* Recording the settings */
1382 static inline int synctex_record_settings(void)
1384 # if SYNCTEX_DEBUG > 999
1385 printf("\nSynchronize DEBUG: synctex_record_settings\n");
1386 # endif
1387 if (NULL == SYNCTEX_FILE) {
1388 return SYNCTEX_NOERR;
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;
1400 synctexabort(0);
1401 return -1;
1404 /* Recording a "SyncTeX..." line */
1405 static inline int synctex_record_preamble(void)
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;
1417 synctexabort(0);
1418 return -1;
1421 /* Recording a "Input:..." line */
1422 static inline int synctex_record_input(integer tag, char *name)
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;
1433 synctexabort(0);
1434 return -1;
1437 /* Recording a "!..." line */
1438 static inline int synctex_record_anchor(void)
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;
1450 synctexabort(0);
1451 return -1;
1454 /* Recording a "Content" line */
1455 static inline int synctex_record_content(void)
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;
1466 synctexabort(0);
1467 return -1;
1470 /* Recording a "{..." line */
1471 static inline int synctex_record_sheet(integer sheet)
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;
1484 synctexabort(0);
1485 return -1;
1488 /* Recording a "}..." line */
1489 static inline int synctex_record_teehs(integer sheet)
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;
1502 synctexabort(0);
1503 return -1;
1506 /* Recording a "v..." line */
1507 static inline void synctex_record_void_vlist(halfword p)
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;
1525 synctexabort(0);
1526 return;
1529 /* Recording a "[..." line */
1530 static inline void synctex_record_vlist(halfword p)
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;
1549 synctexabort(0);
1550 return;
1553 /* Recording a "]..." line */
1554 static inline void synctex_record_tsilv(halfword p __attribute__ ((unused)))
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;
1565 synctexabort(0);
1566 return;
1569 /* Recording a "h..." line */
1570 static inline void synctex_record_void_hlist(halfword p)
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;
1588 synctexabort(0);
1589 return;
1592 /* Recording a "(..." line */
1593 static inline void synctex_record_hlist(halfword p)
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;
1612 synctexabort(0);
1613 return;
1616 /* Recording a ")..." line */
1617 static inline void synctex_record_tsilh(halfword p __attribute__ ((unused)))
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;
1629 synctexabort(0);
1630 return;
1633 /* Recording a "Count..." line */
1634 static inline int synctex_record_count(void)
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;
1645 synctexabort(0);
1646 return -1;
1649 /* Recording a "Postamble" section */
1650 static inline int synctex_record_postamble(void)
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;
1669 synctexabort(0);
1670 return -1;
1673 /* Recording a "g..." line */
1674 static inline void synctex_record_glue(halfword p)
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;
1689 synctexabort(0);
1690 return;
1693 /* Recording a "k..." line */
1694 static inline void synctex_record_kern(halfword p)
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;
1710 synctexabort(0);
1711 return;
1714 /* Recording a "r..." line */
1715 static inline void synctex_record_rule(halfword p)
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;
1731 synctexabort(0);
1732 return;
1735 /* Recording a "$..." line */
1736 void synctex_math_recorder(halfword p)
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;
1751 synctexabort(0);
1752 return;
1755 /* Recording a "k..." line */
1756 void synctex_kern_recorder(halfword p)
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;
1772 synctexabort(0);
1773 return;
1776 /* Recording a "c..." line */
1777 void synctex_char_recorder(halfword p __attribute__ ((unused)))
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;
1790 synctexabort(0);
1791 return;
1794 /* Recording a "?..." line, type, subtype and position */
1795 void synctex_node_recorder(halfword p)
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;
1809 synctexabort(0);
1810 return;
1812 # endif