% scanbase. tex
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 26. 10. 2002                     Petr Olsak

%  This is a macro for processing the mysql outputs in plain TeX
%  The input is supposed in the format:
%
%
%  arbitrary text before table
%  it is ignored 
%  +------------+------------+----------------------------+
%  |   header1  |   header2  |  header3 ...               |
%  +------------+------------+----------------------------+
%  |   text 1,1 |   text 1,2 |  text 1,3 ...              |
%  |   text 2,1 |   text 2,2 |  text 2,3 ...              |
%  |   text 3,1 |   text 3,2 |  text 3,3 ...              |
%  |   ...      |   ...      |           ...              |
%  +------------+------------+----------------------------+
%
%  You can process such file by
%
%  \input scanbase.tex
%  \def\lineaction{...}
%  \scanbase file
%
%  The macro reads the headres first and then reads the lines 
%  with the text. The contents of each item can be accessed 
%  by full expanable macro \e after each line is read. More preciselly, 
%  \e[header] expands to the body of the appropriate item.
%  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 scanbase
%
%  \newcount \mylines
%  \def\bb #1 #2/{\hbox to#1{#2\hss}}
%
%  \def\printaction{\global\advance\mylines by1 %% \scanabase works 
%     \hbox{%                                   %% inside 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.

\newcount\colnum \newcount\numline
\font\seventt=cstt10 at7pt

\catcode`\^^X=13 \def^^X{}

\def\scanfirstline #1-+^^X|{\scanheader}

\def\scanheader #1 |{\advance\colnum by1
  \expandafter \ifx \csname e:#1\endcsname \relax
     \expandafter \def \csname c:\the\colnum\endcsname{#1}%
     \expandafter \def \csname e:#1\endcsname {}%
  \else
     \expandafter \edef \csname c:\the\colnum\endcsname{#1:\the\colnum}%
  \fi
  \futurelet \nextchar \testnextchar
}
\def\testnextchar{\ifx\nextchar^^X\let\next=\ignorethirdline
  \else \let\next=\scanheader 
  \fi \next
}
\def\ignorethirdline ^^X+-#1-+^^X{\edef\maxcolumn{\the\colnum}\runfirstitem}

\def\runfirstitem|{\colnum=0 \runitem}

\def\runitem #1 |{\advance\colnum by1
  \def\tmp{#1}%
  \ifx\tmp\empty \else
     \expandafter \ignorefirstspace \tmp^^X%
  \fi
  \expandafter\edef\csname e:\csname c:\the\colnum\endcsname\endcsname{\tmp}%
  \futurelet \nextchar \testnextitem
}  
\expandafter \def \expandafter \ignorefirstspace \space#1^^X{\def\tmp{#1}}

\def\testnextitem{\ifx\nextchar^^X\let\next=\runline
  \else \let\next=\runitem
  \fi \next
}
\def\runline ^^X{\advance\numline by1
  \lineaction
  \futurelet \nextchar \testnextline
}
\def\testnextline{\ifx\nextchar+\let\next=\endgame
  \else \let\next=\runfirstitem
  \fi \next
}
\def\endgame+-#1-+^^X{\endinput}

\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
  \def\do##1{\catcode`##1=12 }\dospecials
  \catcode`\ =10 \beginhook
  \expandafter \scanfirstline \input #1 \endhook \endgroup}

\let\beginhook=\relax \let\endhook=\relax

\endinput


%  Makro na zpracovani databasovych vystupu z mysql pro plain
%  Nacitane soubory se predpokladaji ve tvaru:
%
%
%  libovolny text pred tabulkou, 
%  ktery bude ignorovan
%  +------------+------------+----------------------------+
%  |   zahlavi1 |   zahlavi2 |  zahlavi3 ...              |
%  +------------+------------+----------------------------+
%  |   text 1,1 |   text 1,2 |  text 1,3 ...              |
%  |   text 2,1 |   text 2,2 |  text 2,3 ...              |
%  |   text 3,1 |   text 3,2 |  text 3,3 ...              |
%  |   ...      |   ...      |           ...              |
%  +------------+------------+----------------------------+
%
%  Na takovy soubor je mozno po
%
%  \input scanbase.tex
%
%  aplikovat makro \scanbase takto:
%
%  \scanbase soubor
%
%  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 scanbase
%
%  \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
