summaryrefslogtreecommitdiff
path: root/macros/optex/base/ref-file.opm
blob: 7f9c619009e5d1a27a8913e6e3c262d2d788b860 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
%% This is part of the OpTeX project, see http://petr.olsak.net/optex

\_codedecl \openref {File for references <2021-07-19>} % preloaded in format

   \_doc --------------------------
   The \`\_inputref` macro is executed in `\everyjob`. It reads the
   `\jobname.ref` file, if it exists. After the file is read then it is removed
   and opened for writing.
   \_cod --------------------------

\_newwrite\_reffile

\_def\_inputref {%
  \_isfile{\_jobname.ref}\_iftrue
     \_input {\_jobname.ref}%
     \_edef\_prevrefhash{\_mdfive{\_jobname.ref}}%
     \_gfnotenum=0 \_lfnotenum=0 \_mnotenum=0
     \_openref
  \_fi
}

   \_doc --------------------------
   \`\_mdfive``{<file>}` expands to the MD5 hash of a given file.
   We use it to do consistency checking of the `.ref` file. First, we read the MD5 hash
   of `.ref` file from previous \TeX/ run before it is removed and opened for
   writing again in the \^`\_inputref` macro. The hash is saved to \`\_prevrefhash`.
   Second, we read the MD5 hash in the \^`\_byehook` macro again and if
   these hashes differ, warning that \"ref file has changed" is
   printed. Try running `optex op-demo` twice to see the effect.
   \_cod --------------------------

\_def\_mdfive#1{\_directlua{mdfive("#1")}}
\_def\_prevrefhash{}

   \_doc --------------------------
   If the `.ref` file does not exist, then it is not created by default. This means that if you
   process a document without any forward references then no `\jobname.ref`
   file is created (it would be unusable). The \^`\_wref` macro is a dummy in
   that case.
   \_cod --------------------------

\_def\_wrefrelax#1#2{}
\_let\_wref=\_wrefrelax

   \_doc ---------------------
   If a macro needs to create and use the `.ref` file, then such macro must
   first use \`\openref`. It creates the file and redefines
   \`\_wref` `\<macro>{<data>}` so that it
   saves the line `\<macro><data>` to the `.ref` file using the asynchronous
   `\write` primitive. Finally, `\_openref` destroys itself, because we
   don't need to open the file again.\nl
   `\_wref``<csname>{<params>}` in fact does `\write\_reffile{\string<csname><params>}`
   and similarly \`\_ewref``<csname>{<params>}` does
   `\write\_reffile{\string<csname><expanded-params>}`.
   \_cod ---------------------

\_def\_openref {%
   \_immediate\_openout\_reffile="\_jobname.ref"\_relax
   \_gdef\_wref ##1##2{\_write\_reffile{\_bslash\_csstring##1##2}}%
   \_immediate\_write\_reffile {\_pcent\_pcent\_space OpTeX <\_optexversion> - REF file}%
   \_immediate\_wref \Xrefversion{{\_REFversion}}%
   \_ifx\_refdecldata\_empty \_else \_refdeclwrite \_fi
   \_gdef\_openref{}%
}
\_def\_ewref #1#2{\_edef\_ewrefA{#2}\_ea\_wref\_ea#1\_ea{\_ewrefA}}
\_def\openref{\_openref}

   \_doc ----------------------
   We are using the convention that the macros used in `.ref` file are named
   `\_X<foo>`.
   We don't want to read `.ref` files from old, incompatible versions of
   \OpTeX/ (and OPmac). This is ensured by using a version number and the
   \`\Xrefversion` macro at the beginning of the `.ref` file:
   \begtt \catcode`\<=13
   \Xrefversion{<version>}
   \endtt
   The macro checks the version compatibility.
   Because OPmac does not understand `\_Xrefversion` we use
   `\Xrefversion` (with a different number of `<version>` than OPmac) here.
   The result: OPmac skips `.ref` files produced by \OpTeX/ and vice
   versa.
   \_cod ----------------------

\_def\_REFversion{6} % current version of .ref files in OpTeX
\_def\_Xrefversion#1{\_ifnum #1=\_REFversion\_relax \_else \_endinput \_fi}
\_public \Xrefversion ; % we want to ignore .ref files generated by OPmac

   \_doc -----------------------
   You cannot define your own `.ref` macros before `.ref` file is read
   because it is read in `\everyjob`. But you can define such macros by using
   \`\refdecl``{<definitions of your ref macros>}`.
   This command writes `<definitions of your ref macros>` to the
   `.ref` file. Then the next lines written to the  `.ref` file can include
   your macros.
   An example from CTUstyle2:
   \begtt
   \refdecl{%
      \def\totlist{} \def\toflist{}^^J
      \def\Xtab#1#2#3{\addto\totlist{\totline{#1}{#2}{#3}}}^^J
      \def\Xfig#1#2#3{\addto\toflist{\tofline{#1}{#2}{#3}}}
   }
   \endtt
   We must read `<definitions of your ref macros>` while `#` has the catcode 12,
   because we don't want to duplicate each `#` in the `.ref` file.\nl
   `\refdecl` appends its data to the \`\_refdecldata` macro. It is
   pushed to the `.ref` file immediatelly only if the file is opened
   already. Otherwise we are waiting to `\openref` because we don't want
   to open the `.ref` file if it is unnecessary.
   \_cod \_fin -----------------

\_def\_refdecldata{}
\_def\_refdecl{\_bgroup \_catcode`\#=12 \_catcode`\\=12 \_catcode`\ =12 \_refdeclA}
\_def\_refdeclA#1{\_egroup
   \_ifx\_refdecldata\_empty\_else \_global\_addto\_refdecldata{^^J}\_fi
   \_global\_addto\_refdecldata{#1}%
   \_ifx\_openref\_empty \_refdeclwrite \_fi
}
\_def\_refdeclwrite{%
   \_immediate\_write\_reffile{\_pcent\_space \_string\refdecl:^^J\_detokenize\_ea{\_refdecldata}}%
   \_gdef\_refdecldata{}%
}
\_public \refdecl ;

\_endcode % ================================================

A so called `.ref` (`\jobname.ref`) file is used to store data that will be
needed in the next \TeX/ run (information about references, TOC lines, etc.).
If it exists it is read by `\everyjob`, when processing of the document starts,
but it is not created at all if the document doesn't need any forward
references. Here are the typical contents of a `.ref` file:

\begtt \catcode`\<=13
\Xrefversion{<ref-version>}
\_Xpage{<gpageno>}{<pageno>}
\_Xtoc{<level>}{<type>}{<text>}{}<title>
\_Xlabel{<label>}{<text>}
\_Xlabel{<label>}{<text>}
...
\_Xpage{<gpageno>}{<pageno>}
\_Xlabel{<label>}{<text>}
...
\endtt

\begitems
* \^`\_Xpage` corresponds to the beginning of a page. <gpageno> is an internal
page number, globally numbered from one. `<pageno>` is the page number
(`\the\pageno`) used in pagination (they may differ).

* \^`\_Xtoc` corresponds to a chapter, section or subsection title on a page.
`<title>` is the title of the chapter (`<level>`=1, `<type>`=`chap`), section
(`<level>`=2, `<type>`=`sec`) or subsection (`<level>`=3, `<type>`=`secc`).

* \^`\_Xlabel` corresponds to a labelled object on a page. `<label>` is the
label provided by the user in \^`\label[<label>]`, while `<text>` is the text
which should be used for the reference (section or table number, for example
`2.3.14`).
\enditems


\_endinput

History:
2021-07-19  \openrefA merged to \openref
2021-07-18  ref file consistency checking added
2021-04-13  \Xrefversion incremented (6), new format of \_Xbib
2021-02-05  \_ewref introduced
2020-02-14  released