Lendo um arquivo conf como uma lista de propriedades

Lendo um arquivo conf como uma lista de propriedades

Não estou preocupado em apoiar seções, embora uma recompensa fosse dada por isso :)

Aqui está o que tenho até agora, mas produz resultados estranhos para #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}

Idealmente, eu gostaria de ter uma sintaxe como

\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}

Como pode ser isto alcançado? Devo observar que os detalhes da interface/nomeação são apenas uma sugestão.

Ideias

(uma lista de trabalho em andamento)

  • Lendo o arquivo e mapeando uma macro em cada linha; não suporta seções
  • Tornando ativos os personagens necessários para a leitura e praticando magia negra

Responder1

É isso que você tem em mente?

Eu defino uma toplevellista de propriedades e sectionuma; adicione as listas que você precisa.

\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}

Esta é a saída no terminal

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

Responder2

Minha solução não usa expl3, nem macros especiais de látex, apenas primitivas TeX. Apenas para comparação. A codificação desta tarefa começa na linha 11 (as primeiras dez linhas são copiadas como macros universais do 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

informação relacionada