file-ini.mkvi /size: 7209 b    last modification: 2021-10-28 13:50
1%D \module
2%D   [       file=file-ini, % was supp-fil,
3%D        version=20110701, % 1995.10.10,
4%D          title=\CONTEXT\ File Macros,
5%D       subtitle=Helpers,
6%D           date=\currentdate,
7%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
8%C
9%C This module is part of the \CONTEXT\ macro||package and is
10%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
11%C details.
12
13%D \TEX\ operates on files, so one wouldn't wonder that there is a separate module
14%D for file commands. In \CONTEXT\ files are used for several purposes:
15%D
16%D \startitemize[packed]
17%D \item  general textual input
18%D \item  logging status information
19%D \item  saving registers, lists and references
20%D \item  buffering defered textual input
21%D \stopitemize
22%D
23%D When dealing with files we can load them as a whole, using the \type {\input}
24%D primitive or load them on a line||by||line basis, using \type {\read}. Writing is
25%D always done line by line, using \type {\write}.
26
27\writestatus{loading}{ConTeXt File Macros / Helpers}
28
29\registerctxluafile{file-ini}{}
30
31\unprotect
32
33%D \macros
34%D   {scratchread, scratchwrite}
35%D
36%D We define a scratch file for reading. Keep in mind that the number of files is
37%D limited to~16, so use this one when possible. We also define a scratch output
38%D file. In \MKIV\ and \LMTX\ we never use these file handles.
39
40\ifdefined\scratchread  \else \newread \scratchread  \fi
41\ifdefined\scratchwrite \else \newwrite\scratchwrite \fi
42
43%D Seldom needed:
44
45\def\openinputfile  #handle#name{\immediate\openin #handle={#name}\relax}
46\def\openoutputfile #handle#name{\immediate\openout#handle={#name}\relax}
47
48\def\closeinputfile #handle{\immediate\closein #handle\relax}
49\def\closeoutputfile#handle{\immediate\closeout#handle\relax}
50
51%D \macros
52%D   {writeln}
53%D
54%D This saves a few tokens:
55
56\def\writeln#handle{\write#handle{}}
57
58%D \macros
59%D   {pushendofline,popendofline}
60%D
61%D When we are loading files in the middle of the typesetting process, for instance
62%D when we load references, we have to be sure that the reading process does not
63%D generate so called 'spurious spaces'. This can be prevented by assigning the line
64%D ending character the \CATCODE\ comment. This is accomplished by
65%D
66%D \starttyping
67%D \pushendofline
68%D ... reading ...
69%D \popendofline
70%D \stoptyping
71
72\installsystemnamespace{eolstack}
73
74\newcount\c_system_files_eol_level
75
76\unexpanded\def\pushendofline
77  {\advance\c_system_files_eol_level\plusone
78   \expandafter\chardef\csname\??eolstack\number\c_system_files_eol_level\endcsname\catcode\endoflineasciicode
79   \catcode\endoflineasciicode\commentcatcode}
80
81\unexpanded\def\popendofline
82  {\catcode\endoflineasciicode\csname\??eolstack\number\c_system_files_eol_level\endcsname
83   \advance\c_system_files_eol_level\minusone}
84
85\unexpanded\def\restoreendofline
86  {\catcode\endoflineasciicode\endoflinecatcode}
87
88%D \macros
89%D   {startreadingfile,stopreadingfile}
90%D
91%D A low level capsule:
92
93\newcount\readingfilelevel       % no longer needed
94\newtoks \everystartreadingfile
95\newtoks \everystopreadingfile
96
97\unexpanded\def\startreadingfile% beter een every en \setnormalcatcodes
98  {\global\advance\readingfilelevel\plusone
99   \the\everystartreadingfile
100   \pushcatcodetable       % saveguard
101   \setcatcodetable\ctxcatcodes
102   \clf_pushregime}% temporarily this way
103
104\unexpanded\def\stopreadingfile
105  {\popcatcodetable      % saveguard
106   \clf_popregime % temporarily this way
107   \the\everystopreadingfile
108   \global\advance\readingfilelevel\minusone}
109
110%D \macros
111%D   {input, normalinput}
112%D
113%D Sometimes we run into troubles when \type {\input} wants to get expanded, e.g. in
114%D a \type {\write} (which happens in the metafun manual when we permit long MP
115%D lines). So, instead of fixing that, we go for a redefinition of \type {\input}.
116%D Of course it's better to use \type {\readfile} or \type {\processfile}.
117
118% \unexpanded\def\input{\normalinput}
119
120\def\inputgivenfile#name{\normalinput{#name}}
121
122%D \macros
123%D   {doifelsefile}
124%D
125%D The next alternative only looks if a file is present. No loading is done. This
126%D one obeys the standard \TEX\ lookup.
127%D
128%D \starttyping
129%D \doiffileelse {filename} {found} {not found}
130%D \stoptyping
131
132\unexpanded\def\doifelsefile     {\clf_doifelsefileexist}
133\unexpanded\def\doifelsepath     {\clf_doifelsepathexist}
134\unexpanded\def\doiffile    #name{\clf_doifelsefileexist{#name}\firstofoneargument\gobbleoneargument}
135\unexpanded\def\doifnotfile #name{\clf_doifelsefileexist{#name}\gobbleoneargument\firstofoneargument}
136
137\let\doiffileelse\doifelsefile
138\let\doifpathelse\doifelsepath
139
140\let\doifelsefileexists\doifelsefile
141\let\doifelsepathexists\doifelsepath
142
143\let\doiffileexistselse\doifelsefileexists
144\let\doifpathexistselse\doifelsepathexists
145
146%D \macros
147%D   {doifparentfileelse}
148%D
149%D \starttyping
150%D \doifparentfileelse{filename}{yes}{no}
151%D \stoptyping
152
153\ifdefined\outputfilename \else \def\outputfilename{\jobname} \fi
154
155\unexpanded\def\doifelseparentfile{\clf_doifelseparentfile}
156
157\let\doifparentfileelse\doifelseparentfile
158
159%D \macros
160%D   {splitfilename}
161%D
162%D \startbuffer
163%D \def\showfilesplit
164%D   {\bgroup \tttf
165%D      \hbox{(full: \splitofffull)}\space
166%D      \hbox{(path: \splitoffpath)}\space
167%D      \hbox{(base: \splitoffbase)}\space
168%D      \hbox{(name: \splitoffname)}\space
169%D      \hbox{(type: \splitofftype)}\space
170%D    \egroup}
171%D
172%D \splitfilename{c:/aa/bb/cc/dd.ee.ff} \showfilesplit \endgraf
173%D \splitfilename{c:/aa/bb/cc/dd.ee}    \showfilesplit \endgraf
174%D \splitfilename{c:/aa/bb/cc/dd}       \showfilesplit \endgraf
175%D
176%D \splitfilename{dd.ee.ff} \showfilesplit \endgraf
177%D \splitfilename{dd.ee}    \showfilesplit \endgraf
178%D \splitfilename{dd}       \showfilesplit \endgraf
179%D \stopbuffer
180%D
181%D \start \typebuffer \getbuffer \stop
182
183\newconstant\kindoffile % 0=normal 1=full path spec (or http) / set at the lua end
184
185\def\splitoffroot{.} \newconstant\splitoffkind
186
187\let\splitofffull\empty
188\let\splitoffpath\empty
189\let\splitoffbase\empty
190\let\splitoffname\empty
191\let\splitofftype\empty
192
193\unexpanded\def\splitfilename{\clf_splitfilename}
194
195%D \macros
196%D   {doonlyonce, doinputonce, doendinputonce}
197%D
198%D Especially macropackages need only be loaded once. Repetitive loading not only
199%D costs time, relocating registers often leads to abortion of the processing
200%D because \TEX's capacity is limited. One can prevent multiple execution and
201%D loading by using one of both:
202%D
203%D \starttyping
204%D \doonlyonce{actions}
205%D \doinputonce{filename}
206%D \doendinputonce{filename}
207%D \stoptyping
208%D
209%D This command obeys the standard method for locating files. We could move this
210%D function to the \LUA\ end.
211
212\installsystemnamespace {fileonce}
213
214\unexpanded\def\doonlyonce#whatever%
215  {\ifcsname\??fileonce#whatever\endcsname
216     \expandafter\gobbleoneargument
217   \else
218     \letgvalue{\??fileonce#whatever}\relax
219     \expandafter\firstofoneargument
220   \fi}
221
222\unexpanded\def\doinputonce#name%
223  {\doonlyonce{#name}{\doifelsefile{#name}{\inputgivenfile{#name}}\donothing}}
224
225\unexpanded\def\doendinputonce#name%
226  {\ifcsname\??fileonce#name\endcsname
227     \expandafter\endinput
228   \fi}
229
230\unexpanded\def\forgetdoingonce#whatever%
231  {\global\undefinevalue{\??fileonce#whatever}}
232
233\protect \endinput
234