%Article 19302 of comp.text.tex:
%Path: sifon!newsflash.concordia.ca!utcsri!rpi!batcomputer!munnari.oz.au!metro!grivel!neumann.une.edu.au!zhuhan
%From: zhuhan@neumann.une.edu.au (Z Jiang)
%Newsgroups: comp.text.tex
%Subject: A robust solution? (was:Skipping blocks in a
%Message-ID: <2155@grivel.une.edu.au>
%Date: 8 Oct 93 00:14:49 GMT
%Sender: usenet@grivel.une.edu.au
%Organization: University of New England, Armidale, Australia
%Lines: 460
%Nntp-Posting-Host: neumann.une.edu.au
%
%A lot a suggestions have been posted recently for a macro that
%comments out blocks of text in TeX or LaTeX or anyTeX.
%
%I have come up with also one solution. In my opinion. This is quite
%robust. The method is that you use
%   \begincomment{password}
%     < any text !>
%   \endcomment
%Then <any text!> will be ignored. If you are careful, then you would
%have already asked that what if <anytext!> contains '\endcomment'?
%This is then solved by using a nonempty 'password'.  In other words,
%if the password is nonempty, then the password instead of \endcomment
%is used to end the <any text>.
%
%The main idea is that \begincomment{password} sets chars 1-128 to
%catcode 11 or so, so that all legal characters are 'letters'. Then
%it looks at the token stream to find if there is the 'password'.
%If it does find it, then quit the comment.
%
%Good point:
%  You can comment out *arbitrarily* number of lines, without hitting
%  TeX capacity. It also print out the number of lines you skipped.
%
%Inconvenience:
%  The potion after \endcomment or 'password' in the line containing
%  such word is also commented out. So it is best \endcomment takes
%  up an entire line. However a warning  will be issued and the ignored
%  portion be written into your log file, should you put something other
%  than spaces after  \endcomment on the same line.
%
%Pitfall:
%  If you have a single line of text inside your comment, which is itself
%  more than say 5 pages, then I'm in trouble and you know why. But it is
%  really most unlikely to happen naturally.
%
%Others:
%  The following code is cut off from my style file formlett.sty, which
%  was written for sending letters to multiple receivers. So for our
%  limited purpose here,  there should be many ways to simplify the code.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% 1. COMMENT OUT TEXT 
%      \begincomment{password} <text> \endcomment or password
%     a. empty password implies \endcomment is the password to leave comment
%     b. whole line following \endcomment or password is also ignored
%
% 2. RAWTEXT LISTING
%      \beginrawlist [...]{password}  <text> \endrawlist or password
%      defaults for [..] supported, last {..} compulsory ({} allowed though)
%
%      \beginrawlist [<INICOUNT>][<STEP>][<DIGITS>][<FONT>]%
%                    [<TEXTSHIFT>][<MARKINGSHIFT>]{<ENDMARK>}
%       <INICOUNT>=\linecount: starts with where it is left   
%       <ENDMARK>= empty: \endrawlist ends the rawlist, otherwise 
%                         <ENDMARK> ends it
%       <DIGITS>=0: no line numbering
%
% 3. PRINTFILE  verbatim  
%      \printfile [...]{filename}
%      [...] same as \beginrawlist
%
%BEGINMACROS
%
{\catcode`\@=11\relax\wlog{}%
\wlog{This is a part of FORMLETT.STY version 1.22 Oct 1993}%
\wlog{By Z Jiang, University of New England, Australia}\wlog{}}%
%
%%% SAVE @'s STATUS
\xdef\EntryADDnuM{\the\catcode`\@}\catcode`\@=11\relax
%
\def\new@measures{%
  \def\temp@@macro##1##2##3{\expandafter\ifx\csname ##3temp##2##1\endcsname
     \relax\edef\next{\noexpand\csname new##1\noexpand\endcsname
                      \csname ##3temp##2##1\endcsname}%
     \else\let\next\relax\fi\next}%
  \def\temp@macro##1{%
     \temp@@macro{##1}{@}{}\temp@@macro{##1}{@@}{}\temp@@macro{##1}{@@@}{}}%
  \temp@macro{count}\temp@macro{toks}\temp@macro{box}\temp@macro{read}%
  \temp@@macro{if}{@}{if}\temp@@macro{if}{@@}{if}\temp@@macro{if}{@@@}{if}%
  \def\temp@@macro##1{\expandafter\ifx\csname temp##1dim\endcsname
     \relax\edef\next{\noexpand\csname newdimen\noexpand\endcsname
                      \csname temp##1dim\endcsname}%
     \else\let\next\relax\fi\next}%
  \temp@@macro{@}\temp@@macro{@@}\temp@@macro{@@@}%
}%
\let\temp@@@macro=\wlog\def\wlog#1{}\new@measures 
%
%%% GENERAL STACK
%
\def\make@STKcount{\csname newcount\endcsname
  \STKcount\global\STKcount=0\relax}%
\ifx\STKcount\undefined@
  \def\next{\make@STKcount}\else\def\next{}\fi
\next % ensures stack pointer not flushed if this piece of code 
      % is loaded again
%
\long\def\push#1{\global\advance\STKcount1\relax
\expandafter\gdef\csname STK\the\STKcount\string~\endcsname{#1}}%
%
\def\popnil{\expandafter\let\expandafter\temp@macro
  \csname STK\the\STKcount\string~\endcsname
  \ifnum\STKcount>0\global\expandafter\let
    \csname STK\the\STKcount\string~\endcsname=\undefined@
    \global\advance\STKcount-1%
  \else 
    \def\temp@macro{}\global\STKcount=0%
  \fi\relax % \temp@macro for pop
}% 
%
\def\pop{\popnil\temp@macro}%
%
%% GET PARAMETERS
%
\long\def\get@nepara[#1][#2]{{\def\next@{#2}%
\ifx\next@\empty\push{#1}\else\push{#2}\fi}\ag@in}%
%
\long\def\get@para\left@#1\right@{%
\def\check@{%
 \ifx[\next@ \def\full@####1{\get@nepara[#1]####1}%
 \else \def\full@{\get@nepara[#1][#1]}\fi
 \full@}%
\futurelet\next@\check@}%
%
\long\def\do@nepara\left@#1\right@#2\p@r@end{%
\gdef\p@r@data{#2}\global\advance\p@r@count1\get@para\left@#1\right@}%
%
\def\ag@in{\ifx\p@r@data\empty \def\next@{\relax
\getp@r@s\run@CMD}\else
\def\next@{\expandafter\do@nepara\p@r@data\p@r@end}\fi
\next@}%
%
\def\run@CMD{\csname STK\the\STKcount\string~\endcsname}%
%
\newcount\p@r@count
\long\def\st@ckparas#1\p@r@end{%
\global\p@r@count=0\gdef\p@r@data{#1}\ag@in}%
%
%
% PARAMETER ASSIGNMENT
%
%% \newcount\temp@count
\newtoks\p@r@one \newtoks\p@r@two \newtoks\p@r@three
\newtoks\p@r@four \newtoks\p@r@five \newtoks\p@r@six
\newtoks\p@r@seven \newtoks\p@r@eight \newtoks\p@r@nine
\def\getp@r@s{\temp@count=\p@r@count
{\loop
 \ifnum\temp@count>0%
 \expandafter\let\expandafter
 \temp@macro\csname STK\the\STKcount\string~\endcsname
 \ifcase\temp@count
 \or \global\p@r@one=\expandafter{\temp@macro}%
 \or \global\p@r@two=\expandafter{\temp@macro}%
 \or \global\p@r@three=\expandafter{\temp@macro}%
 \or \global\p@r@four=\expandafter{\temp@macro}%
 \or \global\p@r@five=\expandafter{\temp@macro}%
 \or \global\p@r@six=\expandafter{\temp@macro}%
 \or \global\p@r@seven=\expandafter{\temp@macro}%
 \or \global\p@r@eight=\expandafter{\temp@macro}%
 \or \global\p@r@nine=\expandafter{\temp@macro}%
 \else \errmessage{Parameter capacity exceeded.}% 
     % this should never happen:  TeX's max para no. is 9
 \fi
 \global\expandafter\let
 \csname STK\the\STKcount\string~\endcsname=\undefined@%
 \global\advance\STKcount-1%
 \global\advance\temp@count-1\relax
 \fi
 \ifnum\temp@count>0%
\repeat}}%
%
\def\clrp@r@s{%GLOBALLY clear
\global\p@r@one={}\global\p@r@two={}\global\p@r@three={}%
\global\p@r@four={}\global\p@r@five={}\global\p@r@six={}%
\global\p@r@seven={}\global\p@r@eight={}\global\p@r@nine={}}%
% The above is the minimum for setting default parametrisation
%
%  EXIST FILE ?
%  \temp@iftrue if the file #1 exist when tested via \existfile{#1}%
% \newread\temp@read 
\def\existfile#1{\temp@iftrue
\openin\temp@read=#1\relax
\ifeof\temp@read \temp@iffalse \fi \closein\temp@read}%
%
% a private \l@@p
\def\l@@p#1\repe@t{\def\b@dy{#1}\iter@te}%
\def\iter@te{\b@dy\let\n@xt=\iter@te \else\let\n@xt=\relax\fi \n@xt}%
\let\repe@t=\fi %
%
%  RAW CHARACTERS
%
\def\raw@chars[#1][#2][#3][#4][#5]{% 
   % #1=11, #2=\`=12, #3=^^I=10, #4=char32=10, #5=^^M=5
  \temp@count=0\relax %
  \l@@p \catcode\temp@count=11\advance\temp@count1\relax %
   \ifnum\temp@count<128\repe@t %
  \catcode`\%=#1\catcode`\^=#1\catcode`\_=#1%
  \catcode`\&=#1\catcode`\$=#1\catcode`\#=#1%
  \catcode`\{=#1\catcode`\}=#1\catcode`\@=#1%
  \catcode`\~=#1\catcode`\\=#1%
  \catcode`\`=#2\catcode`\^^I=#3\catcode`\ =#4%
  \catcode`\^^M=#5\relax %
}%
%
\chardef\temp@char=`\`\catcode`\`=13\relax
\def\rm@ligature{\def`{\null\string`}}%
\catcode\temp@char=12\relax
%
\catcode`\^^I=13\relax\def\set@tab{\def^^I{\ \ \ \ }}\catcode`\^^I=10\relax%
\catcode`\^^M=13\relax\def\set@cr{\def^^M{\par}}\catcode`\^^M=5\relax%
\catcode`\ =13\relax\def\set@space{\def {\ }}\catcode`\ =10\relax%
%
% TEST EMPTY LINE 
%
\catcode`\ =13\relax% space active
%
% Delete leading spaces (catcode=13)
% Throw the rest to \temp@macro
\long\def\del@truespaces#1#2\s@fetymark{\temp@iffalse%
\def\temp@macro{#1}\def\one@space{ }\def\temp@@macro{}%
\ifx\temp@macro\one@space%  front spaces not allowed
\def\temp@macro{#2}%
\ifx\temp@macro\empty\temp@iftrue%
\else\def\temp@@macro{\del@truespaces#2\s@fetymark}\fi%
\fi%
\temp@@macro}%  
%
\catcode`\ =10\relax%
%
% \temp@iftrue if empty line, 
% \temp@macro holds nonspace part (space catcode=13 or normal)
\long\def\is@emptyline#1{\def\one@space{ }%
  \def\temp@macro{#1}\def\temp@@macro{}\temp@iftrue
  \ifx\temp@macro\empty
  \else \ifx\temp@macro\one@space 
        \else \def\temp@@macro{\del@truespaces#1\s@fetymark}%
        \fi
  \fi
\temp@@macro}%
%
%  TEST STRING
%
%% \newif\iftemp@if \newtoks\temp@toks
% return \iftemp@iftrue if yes, 
%        \first@half,\second@half are global
\long\def\test@str#1#2{%
  \long\def\strip@endmark##1\s@fetymarkI#1\s@fetymark{%
    \gdef\second@half{##1}}%
  \long\def\strip@markI##1\s@fetymarkI\s@fetymark{%
    \gdef\first@half{##1}}%
  \long\def\p@rse##1#1##2\s@fetymark{%
    \gdef\first@half{##1}%
    \gdef\second@half{##2}%
    \ifx\second@half\empty 
       \strip@markI##1\s@fetymark \temp@iffalse
    \else
       \strip@endmark##2\s@fetymark \temp@iftrue
    \fi}%
  \temp@toks={#2\s@fetymarkI#1\s@fetymark}%
  \expandafter\p@rse\the\temp@toks }%
%
% #1 supposed to a toks register
\long\def\test@tokstr#1#2{% #1 =toks
   \temp@toks={#2}%
   \edef\temp@macro{\noexpand\test@str{#1}{\the\temp@toks}}%
   \temp@macro }%
%
%  MAKE ESCAPE CHAR
%
% \esc@=the character '\' of catcode 11
\newtoks\name@endtoks \newtoks\true@endtoks 
\catcode`\*=0\relax *catcode`*\=11*relax
*gdef*esc@{\}%*name@endtoks={\endrawlist}%
*catcode`*\=0*relax \catcode`\*=12\relax
%
%
%  FLUSH ZEROS  \fillzeros[<WIDTH>]<NUMBER>
%
%% \newcount\temp@count \newcount\temp@@count 
\def\fillzeros[#1]#2{\temp@@count=#2\relax 
  \ifnum\temp@@count<0\temp@@count=-\temp@@count\fi
  \temp@count=1\relax
  {\loop\ifnum\temp@@count<10\else
    \global\divide\temp@@count by 10\global\advance\temp@count by 1\fi
    \ifnum\temp@@count=10\relax\global\temp@@count=11\relax\fi
    \ifnum\temp@@count>10\repeat}%
  \ifnum#2<0\advance\temp@count1\relax-\fi
  {\loop\ifnum\temp@count<#1\relax0\advance\temp@count1\fi
  \ifnum\temp@count<#1\repeat}%
  \temp@@count=#2\relax\ifnum\temp@@count<0\temp@@count=-\temp@@count\fi
  \the\temp@@count}%
%
%
% BEGINLIST--ENDLIST:    activate  <space> and <linebreak>
%
\catcode`\^^M=13% 
\newcount\linecount\global\linecount=1%
{\obeyspaces\gdef {\ }}%
%
%  \name@endtoks: token to end the list
%  \true@endtoks: tokens to be executed at the end
%  \name@endtoks and \true@endtoks must be defined on entry
%  \no@emptylinefalse: the first or the last line empty
%
\newif\ifno@emptyline         % iftemp@if
\newif\ifprint@file \global\print@filefalse  %
\def\begin@list[#1][#2][#3][#4][#5][#6]{%
  \global\linecount=#1\catcode`\^^M=13\no@emptylinetrue %
  \ifprint@file \def^^M{\put@linenumber}\else\def^^M{\par}\fi %
  \def\put@linenumber{\par\noindent\hbox to #5{}%
       \rlap{\hskip-1em\hskip#6%
       \ifnum#3>0\relax\hbox to0em{\hss#4\fillzeros[#3]\linecount~~}\fi}%
       \global\advance\linecount#2\relax}%
  \def\out@aline{%
    \ifno@emptyline %
       \expandafter\is@emptyline\expandafter{\first@half}%
       \ifprint@file \temp@@iffalse \else\temp@@iftrue \fi %
    \else \temp@iffalse \temp@@iftrue %
    \fi \no@emptylinefalse%
    \iftemp@if \else %
       \iftemp@@if \put@linenumber \fi % 
       \first@half \par %    extra \par is absorbed, put here for last line
    \fi }%
  \def\readyt@quit{\no@emptylinetrue%
    \temp@toks=\expandafter{\first@half}%
    \temp@@toks=\expandafter{\second@half}%
    \edef\first@half{\the\temp@toks\the\temp@@toks}\out@aline %
    \edef\temp@macro{\the\true@endtoks}%
    \temp@macro  %   \second@half removed
    }%
  \def\moret@get{\out@aline\get@phys@line}%
  \long\def\get@phys@line##1^^M{%
    \test@tokstr{\the\name@endtoks}{##1}%
    \iftemp@if \let\temp@macro=\readyt@quit
    \else \let\temp@macro=\moret@get %
    \fi %
    \temp@macro }%
  \catcode`\ =13\relax\get@phys@line%
}%
%
\def\endlist{\catcode`\^^M=13%
\catcode`\ =10\let^^M=\par\catcode`\^^M=5}%
\def\beginlist[#1][#2][#3][#4][#5][#6]{%
  \name@endtoks={\endlist}\true@endtoks={\endlist}%
  \begin@list[#1][#2][#3][#4][#5][#6]}%
%
\catcode`\^^M=5\relax%
%
%
\def\endrawlist{\endgroup}%
\def\begin@@rawlist[#1][#2][#3][#4][#5][#6]#7{\begingroup
  \def\temp@macro{#7}%     #7=token to end the list
  \ifx\temp@macro\empty
     \name@endtoks=\expandafter{\esc@ endrawlist}%
  \else \name@endtoks={#7}%
  \fi
  \true@endtoks={\endlist\endrawlist}%
  \rm@ligature\set@tab\set@cr\set@space
  \raw@chars[11][13][13][13][13]%
  \begin@list[#1][#2][#3][#4][#5][#6]}%
%
\def\begin@rawlist[#1][#2][#3][#4][#5][#6]#{%
      \begin@@rawlist[#1][#2][#3][#4][#5][#6]}%
%
\def\beginrawlist{\push{%
  \edef\next@@{\noexpand\begin@rawlist
      [\the\p@r@one][\the\p@r@two][\the\p@r@three][\the\p@r@four]%
      [\the\p@r@five][\the\p@r@six]}%
  \popnil\clrp@r@s\next@@}%  end of push
  \font\tiny@rm=cmr5%
  \edef\temp@macro{%
      \noexpand\left@\the\linecount\noexpand\right@
      \noexpand\left@1\noexpand\right@
      \noexpand\left@0\noexpand\right@
      \noexpand\left@\noexpand\tiny@rm\noexpand\right@
      \noexpand\left@0pt\noexpand\right@ 
      \noexpand\left@0pt\noexpand\right@}%
  \expandafter\st@ckparas\temp@macro\p@r@end}%
%
%
%
\catcode`\^^M=13\relax %
\def\print@@file[#1][#2][#3][#4][#5][#6]#7{%
   \temp@toks={\bgroup\print@filetrue %
                \beginrawlist[#1][#2][#3][#4][#5][#6]{}}%
   \existfile{#7}%
   \iftemp@if %
      \edef\temp@macro##1{\the\temp@toks %
        \noexpand\input##1\leavevmode %
        \setbox\temp@box=\lastbox\esc@ endrawlist^^M%
        \global\advance\linecount-1\relax\egroup}%
   \else \def\temp@macro##1{\message{(File #7 not found)}}%
   \fi %
   \temp@macro{#7}}%
\catcode`\^^M=5\relax %
%
\def\print@file[#1][#2][#3][#4][#5][#6]#{%
      \print@@file[#1][#2][#3][#4][#5][#6]}%
%
\def\printfile{\push{%
  \edef\next@@{\noexpand\print@file
      [\the\p@r@one][\the\p@r@two][\the\p@r@three][\the\p@r@four]%
      [\the\p@r@five][\the\p@r@six]}%
  \popnil\clrp@r@s\next@@}%  end of push
  \font\tiny@rm=cmr5%
  \edef\temp@macro{%
      \noexpand\left@\the\linecount\noexpand\right@
      \noexpand\left@1\noexpand\right@
      \noexpand\left@6\noexpand\right@
      \noexpand\left@\noexpand\tiny@rm\noexpand\right@
      \noexpand\left@46pt\noexpand\right@ 
      \noexpand\left@-10pt\noexpand\right@}%
  \expandafter\st@ckparas\temp@macro\p@r@end}%
%
\catcode`\^^M=13% 
\def\begin@@comment{\let\par\relax %
  \catcode`\^^M=13\message{< Comment}%
  \temp@count=0\temp@@count=0\relax%
  \long\def\get@phys@line##1^^M{%
    \ifnum\temp@@count<500\advance\temp@@count1\else
    \message{\the\temp@count}\temp@@count=1\fi\relax
    \global\advance\temp@count1\relax
    \test@tokstr{\the\name@endtoks}{##1}%
    \iftemp@if  %
      \def\temp@macro{\message{\the\temp@count\space lines}%
       \expandafter\is@emptyline\expandafter{\second@half}%
        \iftemp@if\message{>}\else %
           \message{| WARNING >}%
           \wlog{(Ignored on comment line: \second@half)}%
        \fi \the\true@endtoks }%
    \else \let\temp@macro=\get@phys@line %
    \fi \temp@macro }%
  \catcode`\ =13\relax\get@phys@line}%
%
\def\end@comment{\catcode`\^^M=13\catcode`\ =10\def^^M{\par}\catcode`\^^M=5}%
\catcode`\^^M=5\relax% 
%  
\def\endcomment{\endgroup}%  \read@buffline\temp@macro
\def\begin@comment#1{\begingroup\nullfont
  \tolerance=10000 \hbadness=10000 \vbadness=10000 
  \hfuzz=\maxdimen \vfuzz=\maxdimen
  \def\temp@macro{#1}%     #1=token to end the list
  \ifx\temp@macro\empty
     \name@endtoks=\expandafter{\esc@ endcomment}%
  \else \name@endtoks={#1}%
  \fi \true@endtoks={\end@comment\endcomment}%
  \rm@ligature\set@tab\set@cr\set@space
  \raw@chars[11][13][13][13][13]\begin@@comment}%
%
\def\begincomment#{\begin@comment}%
%
\let\wlog\temp@@@macro\let\temp@@@macro\undefined@
%
\catcode`\@=\EntryADDnuM\relax
%
%ENDMACROS



