conf ファイルをプロパティリストとして読み込む

conf ファイルをプロパティリストとして読み込む

セクションのサポートについては心配していませんが、そうすると報奨金が支給されます :)

これまでのところ、次のような奇妙な出力が生成されます#2:

\begin{filecontents}{test}
\Property this property = some value
\Property k = v
\end{filecontents}
\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn

\cs_new:Npn \Property #1=#2^^M
  {
    1:#1\par
    2:#2\par
  }

\ExplSyntaxOff
\begin{document}
\input{test}
\end{document}

理想的には、次のような構文が望ましいです

\begin{filecontents*}{test.conf}
this property = some value
k = v

# bounty
[section]
property=value
\end{filecontents*}
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn

\begin{document}
\conf_load:Nn \l_tmpa_prop { test.conf }

% outputs {some value} (brace groups irrelevant)
\conf_get:Nn \l_tmpa_prop { this ~ property }

% bounty; outputs {value} (brace groups irrelevant)
\conf_get:Nnn \l_tmpa_prop { section } { property }

\end{document}

これを実現するにはどうすればよいでしょうか? インターフェース/命名の詳細は単なる提案であることに注意してください。

アイデア

(作業中のリスト)

  • ファイルを読み込み、各行にマクロをマッピングします。セクションはサポートされていません。
  • 読み物に必要なキャラクターをアクティブにし、闇の魔法を実践する

答え1

これがあなたの考えですか?

toplevelプロパティ リストを 1つ定義しsection、必要な plist を追加します。

\begin{filecontents*}{test.conf}
this property = some value
k = v

# bounty
[section]
property=value
\end{filecontents*}
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\confload}{m}
 {
  \allred_conf_load:n { #1 }
 }

\prop_new:N \g_allred_conf_toplevel_prop
\prop_new:N \g_allred_conf_section_prop
\tl_new:N \l__allred_level_tl
\ior_new:N \g_allred_read_conf_stream

\cs_new_protected:Npn \allred_conf_load:n #1
 {
  \group_begin:
  \tex_endlinechar:D \c_minus_one % Ugly! Complain with the team!
  \char_set_catcode_comment:n { `\# }
  \ior_open:Nn \g_allred_read_conf_stream { #1 }
  \tl_set:Nn \l__allred_level_tl { toplevel }
  \ior_map_inline:Nn \g_allread_read_conf_stream
   {
    \tl_if_blank:nF { ##1 }
     {
      \__allred_process_line:x { \tl_trim_spaces:n { ##1 } }
     }
   }
  \ior_close:N \g_allred_read_conf_stream { #1 }
  \group_end:
 }

\cs_new_protected:Npn \__allred_process_line:n #1
 {
  \str_case_x:nnF { \tl_item:nn { #1 } { 1 } }
   {
    { [ } { \__allred_process_newlevel:n { #1 } }
   }
   {
    \__allred_process_property:n { #1 }
   }
 }
\cs_generate_variant:Nn \__allred_process_line:n { x }

\cs_new_protected:Npn \__allred_process_newlevel:n #1
 {
  \__allred_process_newlevel:w #1
 }
\cs_new_protected:Npn \__allred_process_newlevel:w [ #1 ]
 {
  \tl_set:Nn \l__allred_level_tl { #1 }
 }
\cs_new_protected:Npn \__allred_process_property:n #1
 {
  \__allred_process_property_aux:www #1 ==\q_stop
 }
\cs_new_protected:Npn \__allred_process_property_aux:www #1 = #2 = #3 \q_stop
 {
  \prop_gput:cxx { g__allred_conf_ \l__allred_level_tl _prop }
   { \tl_trim_spaces:n { #1 } }
   { \tl_trim_spaces:n { #2 } }
 }
\cs_generate_variant:Nn \prop_gput:cnn { cxx }

\ExplSyntaxOff


\begin{document}
\confload{test.conf}

\ExplSyntaxOn
\prop_show:N \g__allred_conf_toplevel_prop
\prop_show:N \g__allred_conf_section_prop
\ExplSyntaxOff


\end{document}

これは端末の出力です

The property list \g__allred_conf_toplevel_prop contains the pairs (without
outer braces):
>  {this property}  =>  {some value}
>  {k}  =>  {v}.
<recently read> }

l.78 \prop_show:N \g__allred_conf_toplevel_prop

? 
The property list \g__allred_conf_section_prop contains the pairs (without
outer braces):
>  {property}  =>  {value}.
<recently read> }

l.79 \prop_show:N \g__allred_conf_section_prop

答え2

私のソリューションでは、expl3 や特別な LaTeX マクロは使用せず、TeX プリミティブのみを使用します。比較のためだけに使用します。このタスクのコーディングは 11 行目から始まります (最初の 10 行は OPmac からユニバーサル マクロとしてコピーされます)。

\bgroup \catcode`!=3 \catcode`?=3 % \replacestrings, \addto, \sxdef from OPmac
\gdef\replacestrings#1#2{%
   \long\def\tmp##1#1##2!{\ifx!##2!\addto\tmpb{##1}\else\addto\tmpb{##1#2}\tmp##2!\fi}%
   \edef\tmpb{\expandafter}\expandafter\tmp\tmpb?#1!%
   \def\tmp##1?{\def\tmpb{##1}}\expandafter\tmp\tmpb
}
\egroup
\long\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\sxdef#1{\expandafter\xdef\csname#1\endcsname}

% \readconf config_file 
\newread\infile
\def\readconf #1 {\bgroup \catcode`\#=14 \endlinechar=-1
   \def\sectionconf{global}\openin\infile=#1 \readconfA
}
\def\readconfA{\ifeof\infile \egroup \else
   \read\infile to\tmp 
   \expandafter\readconfB\tmp\par
   \expandafter \readconfA\fi
}
\def\readconfB#1\par{\ifx\par#1\par \else \readconfC#1\par \fi}
\def\readconfC#1#2\par{\ifx[#1\expandafter\readconfD \else\expandafter\readconfE\fi#1#2\par}
\def\readconfD[#1]#2\par{\def\sectionconf{#1}}
\def\readconfE#1\par{\def\tmpb{#1}\replacestrings{= }{=}\replacestrings{ =}{=}%
   \expandafter\readconfF\tmpb\par}
\def\readconfF#1=#2\par{\setkeyval{#1}{#2}}

\def\setkeyval#1#2{\expandafter\ifx\csname conf:\sectionconf\endcsname\relax
   \sxdef{conf:\sectionconf}{}\fi
   \sxdef{conf:\sectionconf}{\csname conf:\sectionconf\endcsname{#1}}%
   \sxdef{key:\sectionconf:#1}{#2}%
}

% \showconf[section]
\def\showconf[#1]{\def\sectionconf{#1}\message{SECTION [#1]:}%
   \expandafter\expandafter\expandafter \showconfA \csname conf:#1\endcsname \relax
}
\def\showconfA#1{\ifx\relax#1\else \showconfB{#1}\expandafter\showconfA\fi}
\def\showconfB#1{\message{{#1} => {\csname key:\sectionconf:#1\endcsname}}}

\readconf test.conf

\showconf [global]  % SECTION [global]: {this property} => {some value} {k} => {v}
\showconf [section] % SECTION [section]: {property} => {value}

\end

関連情報