%D \module %D [ file=file-ini, % was supp-fil, %D version=20110701, % 1995.10.10, %D title=\CONTEXT\ File Macros, %D subtitle=Helpers, %D date=\currentdate, %D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. %D \TEX\ operates on files, so one wouldn't wonder that there is a separate module %D for file commands. In \CONTEXT\ files are used for several purposes: %D %D \startitemize[packed] %D \item general textual input %D \item logging status information %D \item saving registers, lists and references %D \item buffering defered textual input %D \stopitemize %D %D When dealing with files we can load them as a whole, using the \type {\input} %D primitive or load them on a line||by||line basis, using \type {\read}. Writing is %D always done line by line, using \type {\write}. \writestatus{loading}{ConTeXt File Macros / Helpers} \registerctxluafile{file-ini}{} \unprotect %D \macros %D {scratchread, scratchwrite} %D %D We define a scratch file for reading. Keep in mind that the number of files is %D limited to~16, so use this one when possible. We also define a scratch output %D file. In \MKIV\ and \LMTX\ we never use these file handles. \ifdefined\scratchread \else \newread \scratchread \fi \ifdefined\scratchwrite \else \newwrite\scratchwrite \fi %D Seldom needed: \def\openinputfile #handle#name{\immediate\openin #handle={#name}\relax} \def\openoutputfile #handle#name{\immediate\openout#handle={#name}\relax} \def\closeinputfile #handle{\immediate\closein #handle\relax} \def\closeoutputfile#handle{\immediate\closeout#handle\relax} %D \macros %D {writeln} %D %D This saves a few tokens: \def\writeln#handle{\write#handle{}} %D \macros %D {pushendofline,popendofline} %D %D When we are loading files in the middle of the typesetting process, for instance %D when we load references, we have to be sure that the reading process does not %D generate so called 'spurious spaces'. This can be prevented by assigning the line %D ending character the \CATCODE\ comment. This is accomplished by %D %D \starttyping %D \pushendofline %D ... reading ... %D \popendofline %D \stoptyping \installsystemnamespace{eolstack} \newcount\c_system_files_eol_level \unexpanded\def\pushendofline {\advance\c_system_files_eol_level\plusone \expandafter\chardef\csname\??eolstack\number\c_system_files_eol_level\endcsname\catcode\endoflineasciicode \catcode\endoflineasciicode\commentcatcode} \unexpanded\def\popendofline {\catcode\endoflineasciicode\csname\??eolstack\number\c_system_files_eol_level\endcsname \advance\c_system_files_eol_level\minusone} \unexpanded\def\restoreendofline {\catcode\endoflineasciicode\endoflinecatcode} %D \macros %D {startreadingfile,stopreadingfile} %D %D A low level capsule: \newcount\readingfilelevel % no longer needed \newtoks \everystartreadingfile \newtoks \everystopreadingfile \unexpanded\def\startreadingfile% beter een every en \setnormalcatcodes {\global\advance\readingfilelevel\plusone \the\everystartreadingfile \pushcatcodetable % saveguard \setcatcodetable\ctxcatcodes \clf_pushregime}% temporarily this way \unexpanded\def\stopreadingfile {\popcatcodetable % saveguard \clf_popregime % temporarily this way \the\everystopreadingfile \global\advance\readingfilelevel\minusone} %D \macros %D {input, normalinput} %D %D Sometimes we run into troubles when \type {\input} wants to get expanded, e.g. in %D a \type {\write} (which happens in the metafun manual when we permit long MP %D lines). So, instead of fixing that, we go for a redefinition of \type {\input}. %D Of course it's better to use \type {\readfile} or \type {\processfile}. \unexpanded\def\input{\normalinput} \def\inputgivenfile#name{\normalinput{#name}} %D \macros %D {doifelsefile} %D %D The next alternative only looks if a file is present. No loading is done. This %D one obeys the standard \TEX\ lookup. %D %D \starttyping %D \doiffileelse {filename} {found} {not found} %D \stoptyping \unexpanded\def\doifelsefile {\clf_doifelsefileexist} \unexpanded\def\doifelsepath {\clf_doifelsepathexist} \unexpanded\def\doiffile #name{\clf_doifelsefileexist{#name}\firstofoneargument\gobbleoneargument} \unexpanded\def\doifnotfile #name{\clf_doifelsefileexist{#name}\gobbleoneargument\firstofoneargument} \let\doiffileelse\doifelsefile \let\doifpathelse\doifelsepath \let\doifelsefileexists\doifelsefile \let\doifelsepathexists\doifelsepath \let\doiffileexistselse\doifelsefileexists \let\doifpathexistselse\doifelsepathexists %D \macros %D {doifparentfileelse} %D %D \starttyping %D \doifparentfileelse{filename}{yes}{no} %D \stoptyping \ifdefined\outputfilename \else \def\outputfilename{\jobname} \fi \unexpanded\def\doifelseparentfile{\clf_doifelseparentfile} \let\doifparentfileelse\doifelseparentfile %D \macros %D {splitfilename} %D %D \startbuffer %D \def\showfilesplit %D {\bgroup \tttf %D \hbox{(full: \splitofffull)}\space %D \hbox{(path: \splitoffpath)}\space %D \hbox{(base: \splitoffbase)}\space %D \hbox{(name: \splitoffname)}\space %D \hbox{(type: \splitofftype)}\space %D \egroup} %D %D \splitfilename{c:/aa/bb/cc/dd.ee.ff} \showfilesplit \endgraf %D \splitfilename{c:/aa/bb/cc/dd.ee} \showfilesplit \endgraf %D \splitfilename{c:/aa/bb/cc/dd} \showfilesplit \endgraf %D %D \splitfilename{dd.ee.ff} \showfilesplit \endgraf %D \splitfilename{dd.ee} \showfilesplit \endgraf %D \splitfilename{dd} \showfilesplit \endgraf %D \stopbuffer %D %D \start \typebuffer \getbuffer \stop \newconstant\kindoffile % 0=normal 1=full path spec (or http) / set at the lua end \def\splitoffroot{.} \newconstant\splitoffkind \let\splitofffull\empty \let\splitoffpath\empty \let\splitoffbase\empty \let\splitoffname\empty \let\splitofftype\empty \unexpanded\def\splitfilename{\clf_splitfilename} %D \macros %D {doonlyonce, doinputonce, doendinputonce} %D %D Especially macropackages need only be loaded once. Repetitive loading not only %D costs time, relocating registers often leads to abortion of the processing %D because \TEX's capacity is limited. One can prevent multiple execution and %D loading by using one of both: %D %D \starttyping %D \doonlyonce{actions} %D \doinputonce{filename} %D \doendinputonce{filename} %D \stoptyping %D %D This command obeys the standard method for locating files. We could move this %D function to the \LUA\ end. \installsystemnamespace {fileonce} \unexpanded\def\doonlyonce#whatever% {\ifcsname\??fileonce#whatever\endcsname \expandafter\gobbleoneargument \else \letgvalue{\??fileonce#whatever}\relax \expandafter\firstofoneargument \fi} \unexpanded\def\doinputonce#name% {\doonlyonce{#name}{\doifelsefile{#name}{\inputgivenfile{#name}}\donothing}} \unexpanded\def\doendinputonce#name% {\ifcsname\??fileonce#name\endcsname \expandafter\endinput \fi} \unexpanded\def\forgetdoingonce#whatever% {\global\undefinevalue{\??fileonce#whatever}} \protect \endinput