我正在为软件设计文档编写一个包。其中有一节涉及模块之间的软件接口,另一节描述每个模块。这里有一个模块使用的接口(函数和变量)的摘要,它们是使用包从上一节收集的collect
。
我创建了一些宏来创建接口(并收集所需的信息),并创建了其他宏来将收集到的信息放置到所需的位置,但编译文档时多次出现以下错误:
! You can't use a prefix with `\openin'.
<to be read again>
\openin
l.306 \insertprovidedinterfaces{SUP}
键入r
运行 pdfLaTeX 到最后,结果正是预期的,但我无法理解/摆脱这些消息。
有什么提示吗?
以下是 MWE:
\documentclass[a4paper, oneside, 10pt]{article}
\usepackage[english]{babel}
\usepackage[latin1]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\renewcommand*\familydefault{\sfdefault}
\usepackage[table, svgnames]{xcolor}
\usepackage{booktabs}
\usepackage{xparse}
\usepackage{xstring}
\usepackage{longtable}
\usepackage{collect}
\usepackage{tikz}%
\usepackage{hyperref}
%%
\colorlet{IFcolor}{Yellow!30!Blue!20}
\colorlet{IFVcolor}{Yellow!80!Blue!20}
%
% definitions of variables containing modules list, later used
% to avoid re-defining an already defined collection
% pfun -> provided functions
% nfun -> needed functions
% pvar -> provided variables
% nvar -> needed variables
\def\pfuncollectionlist{}
\def\nfuncollectionlist{}
\def\pvarcollectionlist{}
\def\nvarcollectionlist{}
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% environment for interfaces - functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Usage:
% param 1: Provider acronym
% param 2: name of function including ()
% param 3: comma-separated caller list
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\NewDocumentEnvironment{int-interface}{mmm}%
{%before
\phantomsection\label{iifprovided#1-#2}%
% provided function interfaces
\newpfuncollection{#1-provided-fun}%
\begin{collect} {#1-provided-fun}{}{}%
\item \hyperref[iifprovided#1-#2]{#1\_#2}
\end{collect}%
%
% needed function interfaces
\def\callers{#3}
\foreach \caller in \callers%
{%
\newnfuncollection{\caller-needed-fun}%
\begin{collect}{\caller-needed-fun}{}{}%
\item \hyperref[iifprovided#1-#2]{#1\_#2}%
\end{collect}%
}%
%
\small
\longtable[htbp]{>{\columncolor{IFcolor}}p{3.5cm}p{12cm}}\kill%\toprule
\endfirsthead
\multicolumn{2}{l}{\footnotesize\emph{Follows from previous page}} \\
\endhead
% normal foot
\multicolumn{2}{r}{\footnotesize\emph{Continue in the next page}} \\
\endfoot
% last foot
\bottomrule
\endlastfoot
%
% here the stationary contents
\toprule
Syntax & #1\_#2 \\
}%
{%
%after
Callers & #3 \\%
\endlongtable
}%
%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% environment for interfaces - variables
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Usage:
% param 1: Provider acronym
% param 2: name of variable
% param 3: comma-separated caller list, read access
% param 4: comma-separated caller list, write access
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\NewDocumentEnvironment{int-interface-var}{mmmm}%
{%before
\phantomsection\label{iifprovided#1-#2}%
% provided function interfaces
\newpvarcollection{#1-provided-var}%
\begin{collect}{#1-provided-var}{}{}%
\item \hyperref[iifprovided#1-#2]{#1\_#2}
\end{collect}%
%
%
% needed interfaces
% two consecutive \foreach are used to decide whether writing R, W or R/W
% first loop search for every read caller in writecaller list;
% if read caller is found in writecallers list,
% a 'R/W' is appended; elsewhere, it is 'only' R.
% Then similar thing is done starting from writecaller list:
% if actual writecaller is NOT found in readcaller list, it is marked only W;
% elsewhere nothing has to be done, because R/W has been already treated in
% previous loop (RW)
\def\callersreadlist{#3}
\def\callerswritelist{#4}
% detecting RW or R
\foreach \readcaller in \callersreadlist
{
\IfSubStr{\callerswritelist}{\readcaller}
{
\newnvarcollection{\readcaller-needed-var}%
\begin{collect}{\readcaller-needed-var}{}{}%
\item \hyperref[iifprovided#1-#2]{#1\_#2} [Read/Write]
\end{collect}%
}%
% else%
{%
\newnvarcollection{\readcaller-needed-var}%
\begin{collect}{\readcaller-needed-var}{}{}%
\item \hyperref[iifprovided#1-#2]{#1\_#2} [Read only]
\end{collect}%
}%
}
% detecting W
\foreach \writecaller in \callerswritelist
{
\IfSubStr{\callersreadlist}{\writecaller}
{
% if found, nothing to do
}%
% else%
{%
\newnvarcollection{\writecaller-needed-var}%
\begin{collect}{\writecaller-needed-var}{}{}%
\item \hyperref[iifprovided#1-#2]{#1\_#2} [Write only]
\end{collect}%
}%
}
%
% write longtable
\small
% didascalia ed etichetta
\longtable[htbp]{>{\columncolor{IFVcolor}}p{3.5cm}p{12cm}}\kill%\toprule
\endfirsthead
\multicolumn{2}{l}{\footnotesize\emph{Follows from previous page}} \\
\endhead
% piede normale
\multicolumn{2}{r}{\footnotesize\emph{Continue in the next page}} \\
\endfoot
% piede finale
\bottomrule
\endlastfoot
%
% here the stationary contents
\toprule
Syntax & #1\_#2 \\%
}%
{%
%after
% do the same search as before, to build list of read only, write only and read/write access modules
\def\callersreadlist{#3}%
\def\callerswritelist{#4}%
Accessed by: & %
\foreach\readcaller in \callersreadlist
{%
\IfSubStr{\callerswritelist}{\readcaller}%
{%
% if found
\readcaller{} \accessmode{rw}$\quad$%
}%
% else%
{%
\readcaller{} \accessmode{r}$\quad$%
}%
}%
%
%
\foreach\writecaller in \callerswritelist
{%
\IfSubStr{\callersreadlist}{\writecaller}%
{%
}%
% else%
{%
\writecaller{} \accessmode{w}$\quad$%
%
}%
}%
\\
\endlongtable
}%
%
%
%
%
%
\newcommand{\accessmode}[1]{%
(#1),
}%
%
\DeclareRobustCommand{\insertprovidedinterfaces}[1]{%
\paragraph{Function interfaces}
\IfSubStr{\pfuncollectionlist}{#1}{%
% Collection '#1-provided-fun' exists
\begin{itemize}
\includecollection{#1-provided-fun}%
\end{itemize}
}{%
None.
}%
\paragraph{Variable interfaces}
\IfSubStr{\pvarcollectionlist}{#1}{%
% Collection '#1-provided-var' exists
\begin{itemize}
\includecollection{#1-provided-var}%
\end{itemize}
}{%
None.
}%
}%
%
\DeclareRobustCommand{\insertneededinterfaces}[1]{%
\paragraph{Function interfaces}
\IfSubStr{\nfuncollectionlist}{#1}{%
% Collection '#1-needed-fun' esists
\begin{itemize}
\includecollection{#1-needed-fun}%
\end{itemize}
}{%
None.
}%
\paragraph{Variable interfaces}
\IfSubStr{\nvarcollectionlist}{#1}{%
% Collection '#1-needed-var' esists
\begin{itemize}
\includecollection{#1-needed-var}%
\end{itemize}
}{%
None.
}%
}%
%
\DeclareRobustCommand{\newpvarcollection}[1]{%
\IfSubStr{\pvarcollectionlist}{#1}{%
}{%
\xdef\pvarcollectionlist{\pvarcollectionlist{} #1}
\definecollection{#1}%
}%
}%
%
\DeclareRobustCommand{\newnvarcollection}[1]{%
\IfSubStr{\nvarcollectionlist}{#1}{%
}{%
\xdef\nvarcollectionlist{\nvarcollectionlist{} #1}
\definecollection{#1}%
}%
}%
%
\DeclareRobustCommand{\newpfuncollection}[1]{%
\IfSubStr{\pfuncollectionlist}{#1}{%
}{%
\xdef\pfuncollectionlist{\pfuncollectionlist{} #1}
\definecollection{#1}%
}%
}%
%
\DeclareRobustCommand{\newnfuncollection}[1]{%
\IfSubStr{\nfuncollectionlist}{#1}{%
}{%
\xdef\nfuncollectionlist{\nfuncollectionlist{} #1}
\definecollection{#1}%
}%
}%
%
\begin{document}
\section{Interfaces}
Here some software interfaces:
\begin{int-interface}{SUP}{eGetActualSystemStatus}{ICP}
Parameters & None \\
Return type & System status code. Codified value \\
Purpose & Obtain actual system status from \emph{SUP} \\
\end{int-interface}
%
\begin{int-interface}{SUP}{eSetOverrideRequest()}{SMB}
Parameters & Request code: ENTER, EXIT \\
Return type & Operation result. Codified value. \\
Purpose & To set an override request to \emph{SUP} \\
\end{int-interface}
%
\begin{int-interface-var}{HAL}{ausInputVoltageSamples}{SENS, I2C}{I2C, ICP}
Type & Buffer of 5 samples \\
Purpose & To store acquired input voltage samples\\
\end{int-interface-var}
%
\section{Modules description}
Some descriptive stuff\ldots
\subsection{SUP module}
Other descriptions\ldots
Here is a list of provided interfaces:
\insertprovidedinterfaces{SUP}
\subsection{HAL module}
Other descriptions\ldots
Here is a list of provided interfaces:
\insertprovidedinterfaces{HAL}
\end{document}
答案1
collect.sty
您可以修补似乎导致应用程序中出现错误的命令。这不应涉及 的其他用途collect
:
\makeatletter
\def\CE@ensure@opened#1{%
\@ifundefined{ifCE@@#1@open}{%
\PackageError{collect}{Collection `#1' has not been defined}{\@ehc}%
}{%
\csname ifCE@@#1@open\endcsname\else
\immediate\expandafter\openout\csname CE@@#1@out\endcsname=\jobname.#1\relax
\@ifundefined{CE@@#1@opentrue}{}{\global\csname CE@@#1@opentrue\endcsname}%
\fi
}%
}
\def\CE@ensure@closed#1{%
\@ifundefined{ifCE@@#1@open}{%
\PackageError{collect}{Collection `#1' has not been defined}{\@ehc}%
}{%
\csname ifCE@@#1@open\endcsname
\immediate\expandafter\closeout\csname CE@@#1@out\endcsname
\@ifundefined{CE@@#1@openfalse}{}{\global\csname CE@@#1@openfalse\endcsname}%
\fi
}%
}
\makeatother
代码应该放在序言中;您的 MWE 似乎运行时没有错误。
以下似乎是您的最小示例(相同的文档语法)的正确重新实现,没有使用collect
,但利用了expl3
。
\documentclass[a4paper, oneside, 10pt]{article}
\usepackage[english]{babel}
\usepackage[latin1]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\renewcommand*\familydefault{\sfdefault}
\usepackage[table, svgnames]{xcolor}
\usepackage{booktabs}
\usepackage{xparse}
\usepackage{longtable}
\usepackage{tikz}%
\usepackage{hyperref}
%%
\colorlet{IFcolor}{Yellow!30!Blue!20}
\colorlet{IFVcolor}{Yellow!80!Blue!20}
%
% definitions of variables containing modules list, later used
% to avoid re-defining an already defined collection
% pfun -> provided functions
% nfun -> needed functions
% pvar -> provided variables
% nvar -> needed variables
\ExplSyntaxOn
\clist_new:N \g_cbe_pfuncollectionlist_clist
\clist_new:N \g_cbe_nfuncollectionlist_clist
\clist_new:N \g_cbe_pvarcollectionlist_clist
\clist_new:N \g_cbe_nvarcollectionlist_clist
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% environment for interfaces - functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Usage:
% param 1: Provider acronym
% param 2: name of function including ()
% param 3: comma-separated caller list
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\NewDocumentEnvironment{int-interface}{mmm}
{
\cbe_int_interface_start:nnn {#1}{#2}{#3}
}
{
\cbe_int_interface_end:nnn {#1}{#2}{#3}
}
\cs_new_protected:Npn \cbe_int_interface_start:nnn #1 #2 #3
{
\phantomsection\label{iifprovided#1-#2}%
% provided function interfaces
\cbe_newpfuncollection:n { #1 }%
\cbe_collect:nn {#1-provided-fun}{\item \hyperref[iifprovided#1-#2]{#1\_#2}}
% needed function interfaces
\clist_map_inline:nn { #3 }
{
\cbe_newnfuncollection:n { ##1 }%
\cbe_collect:nn {##1-needed-fun}{\item \hyperref[iifprovided#1-#2]{#1\_#2}}
}
%
\small
\longtable[htbp]{>{\columncolor{IFcolor}}p{3.5cm}p{12cm}}\kill%\toprule
\endfirsthead
\multicolumn{2}{l}{\footnotesize\emph{Follows~from~previous~page}} \\
\endhead
% normal foot
\multicolumn{2}{r}{\footnotesize\emph{Continue~in~the~next~page}} \\
\endfoot
% last foot
\bottomrule
\endlastfoot
% here the stationary contents
\toprule
Syntax & #1\_#2 \\
}
\cs_new_protected:Npn \cbe_int_interface_end:nnn #1 #2 #3
{
Callers & #3 \\
\endlongtable
}
%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% environment for interfaces - variables
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Usage:
% param 1: Provider acronym
% param 2: name of variable
% param 3: comma-separated caller list, read access
% param 4: comma-separated caller list, write access
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\NewDocumentEnvironment{int-interface-var}{mmmm}
{
\cbe_int_interface_var_start:nnnn {#1}{#2}{#3}{#4}
}
{
\cbe_int_interface_var_end:nnnn {#1}{#2}{#3}{#4}
}
\cs_new_protected:Npn \cbe_int_interface_var_start:nnnn #1 #2 #3 #4
{
\phantomsection\label{iifprovided#1-#2}
% provided function interfaces
\cbe_newpvarcollection:n { #1 }
\cbe_collect:nn {#1-provided-var}{\item \hyperref[iifprovided#1-#2]{#1\_#2}}
% needed interfaces
% two consecutive \foreach are used to decide whether writing R, W or R/W
% first loop search for every read caller in writecaller list;
% if read caller is found in writecallers list,
% a 'R/W' is appended; elsewhere, it is 'only' R.
% Then similar thing is done starting from writecaller list:
% if actual writecaller is NOT found in readcaller list, it is marked only W;
% elsewhere nothing has to be done, because R/W has been already treated in
% previous loop (RW)
% detecting RW or R
\clist_map_inline:nn { #3 }
{
\clist_if_in:nnTF { #4 } { ##1 }
{
\cbe_newnvarcollection:n { ##1 }
\cbe_collect:nn { ##1-needed-var }{ \item \hyperref[iifprovided#1-#2]{#1\_#2} [Read/Write] }
}
{
\cbe_newnvarcollection:n { ##1 }
\cbe_collect:nn { ##1-needed-var }{ \item \hyperref[iifprovided#1-#2]{#1\_#2} [Read~Only] }
}
}
% detecting W
\clist_map_inline:nn { #4 }
{
\clist_if_in:nnF { #4 } { ##1 }
{
\cbe_newnvarcollection:n { ##1 }
\cbe_collect:nn { ##1-needed-var }{\item \hyperref[iifprovided#1-#2]{#1\_#2} [Write~only]}
}
}
% write longtable
\small
% didascalia ed etichetta
\longtable[htbp]{>{\columncolor{IFVcolor}}p{3.5cm}p{12cm}}\kill%\toprule
\endfirsthead
\multicolumn{2}{l}{\footnotesize\emph{Follows from previous page}} \\
\endhead
% piede normale
\multicolumn{2}{r}{\footnotesize\emph{Continue in the next page}} \\
\endfoot
% piede finale
\bottomrule
\endlastfoot
%
% here the stationary contents
\toprule
Syntax & #1\_#2 \\
}
\cs_new_protected:Npn \cbe_int_interface_var_end:nnnn #1 #2 #3 #4
{
% do the same search as before, to build list of read only, write only and read/write access modules
Accessed~by: &
\clist_map_inline:nn { #3 }
{
\clist_if_in:nnTF { #4 } { ##1 }
{
##1 ~ \cbe_accessmode:n { rw } \quad
}
{
##1 ~ \cbe_accessmode:n { r } \quad
}
}
\clist_map_inline:nn { #4 }
{
\clist_if_in:nnF { #3 } { ##1 }
{
##1 ~ \cbe_accessmode:n { w } \quad
}
}
\\
\endlongtable
}
%
\cs_new_protected:Npn \cbe_accessmode:n #1
{
(#1),
}
%
\NewDocumentCommand{\insertprovidedinterfaces}{m}
{
\paragraph{Function~interfaces}
\clist_if_in:NnTF \g_cbe_pfuncollectionlist_clist { #1 }
{
% Collection '#1-provided-fun' exists
\begin{itemize}
\cbe_includecollection:n {#1-provided-fun}
\end{itemize}
}
{
None.
}
\paragraph{Variable~interfaces}
\clist_if_in:NnTF \g_cbe_pvarcollectionlist_clist { #1 }
{
% Collection '#1-provided-var' exists
\begin{itemize}
\cbe_includecollection:n {#1-provided-var}
\end{itemize}
}
{
None.
}
}
%
\NewDocumentCommand{\insertneededinterfaces}{m}
{
\paragraph{Function interfaces}
\clist_if_in:NnTF \g_cbe_nfuncollectionlist_clist { #1 }
{
% Collection '#1-needed-fun' esists
\begin{itemize}
\cbe_includecollection:n {#1-needed-fun}
\end{itemize}
}
{
None.
}
\paragraph{Variable~interfaces}
\clist_if_in:NnTF \g_cbe_nvarcollectionlist_clist { #1 }
{
% Collection '#1-needed-var' esists
\begin{itemize}
\cbe_includecollection:n {#1-needed-var}%
\end{itemize}
}
{
None.
}
}
%
\cs_new_protected:Npn \cbe_newpvarcollection:n #1
{
\clist_if_in:NnF \g_cbe_pvarcollectionlist_clist { #1 }
{
\clist_gput_right:Nn \g_cbe_pvarcollectionlist_clist { #1 }
}
\cbe_newcollection:nn { #1 } { provided-var }
}
%
\cs_new_protected:Npn \cbe_newnvarcollection:n #1
{
\clist_if_in:NnF \g_cbe_nvarcollectionlist_clist { #1 }
{
\clist_gput_right:Nn \g_cbe_nvarcollectionlist_clist { #1 }
}
\cbe_newcollection:nn { #1 } { needed-var }
}
%
\cs_new_protected:Npn \cbe_newpfuncollection:n #1
{
\clist_if_in:NnF \g_cbe_pfuncollectionlist_clist { #1 }
{
\clist_gput_right:Nn \g_cbe_pfuncollectionlist_clist { #1 }
}
\cbe_newcollection:nn { #1 } { provided-fun }
}
%
\cs_new_protected:Npn \cbe_newnfuncollection:n #1
{
\clist_if_in:NnF \g_cbe_nfuncollectionlist_clist { #1 }
{
\clist_gput_right:Nn \g_cbe_nfuncollectionlist_clist { #1 }
}
\cbe_newcollection:nn { #1 } { needed-fun }
}
\cs_new_protected:Npn \cbe_newcollection:nn #1 #2
{
\tl_if_exist:cF { g_cbe_collection_#1-#2_tl }
{ \tl_new:c { g_cbe_collection_#1-#2_tl } }
}
\cs_new_protected:Npn \cbe_collect:nn #1 #2
{
\tl_gput_right:cn { g_cbe_collection_#1_tl } { #2 }
}
\cs_new_protected:Npn \cbe_includecollection:n #1
{
\tl_use:c { g_cbe_collection_#1_tl }
}
\ExplSyntaxOff
\begin{document}
\section{Interfaces}
Here some software interfaces:
\begin{int-interface}{SUP}{eGetActualSystemStatus}{ICP}
Parameters & None \\
Return type & System status code. Codified value \\
Purpose & Obtain actual system status from \emph{SUP} \\
\end{int-interface}
%
\begin{int-interface}{SUP}{eSetOverrideRequest()}{SMB}
Parameters & Request code: ENTER, EXIT \\
Return type & Operation result. Codified value. \\
Purpose & To set an override request to \emph{SUP} \\
\end{int-interface}
%
\begin{int-interface-var}{HAL}{ausInputVoltageSamples}{SENS, I2C}{I2C, ICP}
Type & Buffer of 5 samples \\
Purpose & To store acquired input voltage samples\\
\end{int-interface-var}
%
\section{Modules description}
Some descriptive stuff\ldots
\subsection{SUP module}
Other descriptions\ldots
Here is a list of provided interfaces:
\insertprovidedinterfaces{SUP}
\subsection{HAL module}
Other descriptions\ldots
Here is a list of provided interfaces:
\insertprovidedinterfaces{HAL}
\end{document}
我维护四个 clist 变量,用于检查接口是否已经存在,并将每个函数和变量描述添加到名为\g_cbe_<interface>-provided-fun_tl
、\g_cbe_<interface>-needed-fun_tl
、\g_cbe_<interface>-provided-var_tl
、的标记列表变量中\g_cbe_<interface>-needed-var_tl
,然后在\insertprovidedinterfaces{<interface>}
调用时使用该变量。
至少对于这个例子,我得到了和你相同的结果。
答案2
它是一个远的从最小示例,我不知道预期的输出应该是什么样的,但是
\DeclareRobustCommand{\insertprovidedinterfaces}[1]{%
\begingroup
\let\oldopenin\openin
\def\openin{\def\zzzz{}\oldopenin}
\paragraph{Function interfaces}
\IfSubStr{\pfuncollectionlist}{#1}{%
% Collection '#1-provided-fun' exists
\begin{itemize}
\includecollection{#1-provided-fun}%
\end{itemize}
}{%
None.
}%
\paragraph{Variable interfaces}
\IfSubStr{\pvarcollectionlist}{#1}{%
% Collection '#1-provided-var' exists
\begin{itemize}
\includecollection{#1-provided-var}%
\end{itemize}
}{%
None.
}%
\endgroup}%
\openin
使错误消失。可能它只是掩盖了代码中其他地方的错误使用。