%% 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{optex.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 immediately 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