summaryrefslogtreecommitdiff
path: root/macros/generic/olsak-misc/scancsv.tex
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/generic/olsak-misc/scancsv.tex
Initial commit
Diffstat (limited to 'macros/generic/olsak-misc/scancsv.tex')
-rw-r--r--macros/generic/olsak-misc/scancsv.tex242
1 files changed, 242 insertions, 0 deletions
diff --git a/macros/generic/olsak-misc/scancsv.tex b/macros/generic/olsak-misc/scancsv.tex
new file mode 100644
index 0000000000..aa1ce26825
--- /dev/null
+++ b/macros/generic/olsak-misc/scancsv.tex
@@ -0,0 +1,242 @@
+% scancsv. tex
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% 26. 2. 2005 Petr Olsak
+
+% This is a macro for processing the CSV format in plain TeX.
+%
+% The input file is assumed in the form:
+%
+% "header1";"header2";"header3"; ... "header-n"
+% "text 1,1";"text 1,2";"text 1,3"; ... "text 1,n"
+% "text 2,1";"text 2,2";"text 2,3"; ... "text 2,n"
+% "text 3,1";"text 3,2";"text 3,3"; ... "text 3,n"
+% ...
+%
+% You can process such a file by
+%
+% \input scancsv.tex
+% \def\lineaction{...}
+% \scanbase soubor
+%
+% The separator " can be omited in a arbitrary header or item text.
+% I.e. the following format is scanned without problems:
+%
+% "firstname";"lastname";number;RC
+% "Ferdinand";"Mravenec";1;000111/2244
+% "Josef";"Vykutal";2;444333/2211
+%
+% The macro reads the headers and then reads next lines repeatedly.
+% The full expanable macro \e is ready after the line is read.
+% More exactly \e[header] expands to the appropriate item body.
+% The \lineaction macro is processed after each line is read.
+% It is supposed that \lineaction is defined by user.
+%
+% Next line of the table is read after \lineaction, the \e macros have
+% a new meaning (items from this next line) and the \lineaction is executed
+% again. This is repeated until last line of the input table is reached.
+% Moreower, the \linenum register is available, where the number of the
+% last scanned line is stored.
+
+% Example:
+%
+% \input scancsv
+%
+% \newcount \mylines
+% \def\bb #1 #2/{\hbox to#1{#2\hss}}
+%
+% \def\printaction{\global\advance\mylines by1 %% \scanabase works
+% \hbox{% %% in the TeX group
+% \bb 2em \the\numline./
+% \bb 26em \e[subject]/
+% \bb 10em \e[lastname] \e[firstname]/
+% \bb 3em \hfill\e[pay2002]/
+% \bb 3em \hfill\e[pay2001]/}
+% }
+% \def\lineaction{\if K\e[member_type]% Institutional members
+% \printaction
+% \else \if G\e[member_type]% High school
+% \printaction
+% \fi\fi % I am printing Institutional mambers and high schools only
+% }
+% \scanbase database1
+% \scanbase database2
+% {\it Number of printed lines: \the\mylines}.
+% \end
+%
+% If the \lineaction macro isn't defined by user then scanbase used
+% its own (default) macro which prints all items from one line
+% into the one paragraph in comprimend form (you can try this).
+%
+% The \scanbase macro opens the TeX group then runs \beginhook
+% then reads headers, then reads the lines ans processes \linecation
+% repeatedly, then runs \endhook and finally closes the group.
+% Default values for \beginhook and \endhook is \relax but user
+% can define something else.
+%
+% The user can redefine the \separator and \obklopeni (surrounding char)
+% after \input scanbase if there are used another characters than semicolon
+% and " in the input file.
+
+\def\separator{;} % separator mezi polozkami
+\def\obklopeni{"} % nepovinne "obklopeni" polozky
+
+\newcount\colnum \newcount\numline
+
+\catcode`\^^X=13 \def^^X{}
+
+\def\scanheader{\futurelet \nextchar \doheader}
+
+\def\doheader {\expandafter\ifx \obklopeni\nextchar \expandafter \maskheader
+ \else \expandafter \nomaskheader \fi}
+
+\def\runheader{\advance\colnum by1
+ \expandafter \ifx \csname e:\itemdata\endcsname \relax
+ \expandafter \edef \csname c:\the\colnum\endcsname{\itemdata}%
+ \expandafter \def \csname e:\itemdata\endcsname {}%
+ \else
+ \expandafter \edef \csname c:\the\colnum\endcsname{\itemdata:\the\colnum}%
+ \fi
+ \futurelet \nextchar \testnextchar
+}
+\def\testnextchar{\ifx\nextchar^^X\let\next=\ignorethirdline
+ \else \let\next=\scanheader
+ \fi \next
+}
+
+\def\ignorethirdline ^^X{\edef\maxcolumn{\the\colnum}\runfirstitem}
+
+\def\runfirstitem #1^^X{\def\tmp{#1}%
+ \ifx\tmp\empty \expandafter\endinput \fi
+ \ifx\tmp\stopmark
+ \else \colnum=0
+ \edef\tmp{\noexpand\scanitem #1\separator\noexpand^^X}\expandafter\tmp
+ \fi}
+\def\scanitem {\futurelet \nextchar \doitem}
+
+\def\doitem {\expandafter \ifx \obklopeni\nextchar \expandafter \maskitem
+ \else \expandafter \nomaskitem \fi}
+
+\def\runitem {\advance\colnum by1
+ \expandafter\edef\csname e:\csname c:\the\colnum\endcsname\endcsname{\itemdata}%
+ \futurelet \nextchar \testnextitem
+}
+\def\testnextitem{\ifx\nextchar^^X\let\next=\runline
+ \else \let\next=\scanitem
+ \fi \next
+}
+\def\runline ^^X{\advance\numline by1
+ \lineaction
+ \futurelet \nextchar \runfirstitem
+}
+\def\e [#1]{\expandafter\ifx \csname e:#1\endcsname \relax
+ \message{Warning: the #1 column is not defined in header.}%
+ \else \csname e:#1\endcsname \fi
+}
+
+\def\printall{\colnum = 0
+ \noindent \hangindent=\parindent \raggedright
+ \loop
+ \advance\colnum by1
+ {\seventt \ignorespaces \csname c:\the\colnum\endcsname:}\penalty0
+ \csname e:\csname c:\the\colnum\endcsname\endcsname
+ \ifnum\colnum < \maxcolumn , \repeat
+ .\par
+}
+\let\lineaction=\printall
+
+\def\scanbase #1 {\begingroup \endlinechar=`\^^X
+ \edef\maskauvo{\obklopeni####1\obklopeni\separator}
+ \edef\maskaneuvo{####1\separator}
+ \expandafter\def \expandafter\maskheader \maskauvo {\def\itemdata{##1}\runheader}
+ \expandafter\def \expandafter\nomaskheader \maskaneuvo {\def\itemdata{##1}\runheader}
+ \expandafter\def \expandafter\maskitem \maskauvo {\def\itemdata{##1}\runitem}
+ \expandafter\def \expandafter\nomaskitem \maskaneuvo {\def\itemdata{##1}\runitem}
+ \edef\scanfirstline ##1^^X{\noexpand\scanheader##1\separator\noexpand^^X}
+ \def\do##1{\catcode`##1=12 }\dospecials
+ \catcode`\ =10 \beginhook
+ \expandafter \scanfirstline \input #1 \relax^^X\endhook \endgroup}
+\def\stopmark{\relax}
+
+\let\beginhook=\relax \let\endhook=\relax
+
+\endinput
+
+% Makro na zpracovani databasovych vystupu ve formatu CSV pro plain.
+%
+% Srovnejte tez makro scanbase.tex
+%
+% Nacitane soubory se predpokladaji ve tvaru:
+%
+% "zahlavi1";"zahlavi2";"zahlavi3"; ... "zahlavi-n"
+% "text 1,1";"text 1,2";"text 1,3"; ... "text 1,n"
+% "text 2,1";"text 2,2";"text 2,3"; ... "text 2,n"
+% "text 3,1";"text 3,2";"text 3,3"; ... "text 3,n"
+% ...
+%
+% Na takovy soubor je mozno po
+%
+% \input scancsv.tex
+%
+% aplikovat makro \scanbase takto:
+%
+% \scanbase soubor
+%
+% Obklopujici znak " muze u libovolneho zahlavi nebo polozky
+% chybet. Tj. je korektni treba i takovy zapis dat:
+%
+% "jmeno";"prijmeni";cislo;RC
+% "Ferdinand";"Mravenec";1;000111/2244
+% "Josef";"Vykutal";2;444333/2211
+%
+% Makro nacte zahlavi a zacne cist jednotlive radky. Po precteni
+% kazdeho radku je obsah polozky pripraven v expanznim makru
+% \e. Presneji \e[zahlavi] expanduje na text odpovidajici polozky.
+% V teto situaci \scanbase spusti makro \lineaction, ktere si muze
+% uzivatel definovat jak chce.
+%
+% Po ukonceni makra \lineaction cte scanbase dalsi radek tabulky, naplni
+% znovu expanzni makra \e texty polozek z tohoto radku a spusti znovu
+% \lineaction. To se opakuje tak dlouho, dokud neni ukonceno cteni
+% tabulky. Navic je makru \lineaction k dispozici registr \numline
+% obsahujici cislo prave precteneho radku.
+%
+% Priklad pouziti:
+%
+% \input scancsv
+%
+% \newcount \mylines
+% \def\bb #1 #2/{\hbox to#1{#2\hss}}
+%
+% \def\printaction{\global\advance\mylines by1 %% \scanabase pracuje
+% \hbox{% %% uvnitr skupiny!
+% \bb 2em \the\numline./
+% \bb 26em \e[nazev]/
+% \bb 10em \e[prijmeni] \e[jmeno]/
+% \bb 3em \hfill\e[kc2002]/
+% \bb 3em \hfill\e[kc2001]/}
+% }
+% \def\lineaction{\if K\e[typ_clenstvi]% Kolektivni clenove
+% \printaction
+% \else \if G\e[typ_clenstvi]% Gymnazia
+% \printaction
+% \fi\fi % tisknu jen kolektivni cleny a gymnazia
+% }
+% \scanbase database1
+% \scanbase database2
+% {\it Number of printed lines: \the\mylines}.
+% \end
+%
+% Pokud neni uzivatelem definovano makro \lineaction, pouzije
+% scanbase sve vlastni (defaultni) makro, ktere vytiskne vsechny polozky
+% jednoho radku do odstavce ve velmi zhustenem tvaru (vyzkousejte si).
+%
+% Kazde \scanbase vstupuje do skupiny, pak spusti \beginhook,
+% pak cte hlavicku a jednotlive radky, jak bylo receno vyse,
+% pak spusti \endhook a nakonec vyleze ze skupiny.
+% Sekvence \beginhook a \endhook muze predefinovat uzivatel, defaltne maji
+% hodnotu \relax
+%
+% Uzivatel muze po nacteni \input scanbase predefinovat makra \separator
+% a \obklopeni (viz nize), pokud jsou v datech polozky a zahlavi
+% oddeleny jinymi znaky nez strednik a symbol palce.
+