summaryrefslogtreecommitdiff
path: root/web/c_cpp/cnoweb
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 /web/c_cpp/cnoweb
Initial commit
Diffstat (limited to 'web/c_cpp/cnoweb')
-rw-r--r--web/c_cpp/cnoweb/README4
-rw-r--r--web/c_cpp/cnoweb/cnoweb.tex511
-rw-r--r--web/c_cpp/cnoweb/pf.c371
3 files changed, 886 insertions, 0 deletions
diff --git a/web/c_cpp/cnoweb/README b/web/c_cpp/cnoweb/README
new file mode 100644
index 0000000000..d78ceb03be
--- /dev/null
+++ b/web/c_cpp/cnoweb/README
@@ -0,0 +1,4 @@
+This is the cnoweb `literate programming'
+demonstration program (pf.c) and macro package (cnoweb.tex).
+
+Comments to Jim Fox, fox@cac.washington.edu
diff --git a/web/c_cpp/cnoweb/cnoweb.tex b/web/c_cpp/cnoweb/cnoweb.tex
new file mode 100644
index 0000000000..c9de58413e
--- /dev/null
+++ b/web/c_cpp/cnoweb/cnoweb.tex
@@ -0,0 +1,511 @@
+% c-NO_WEB (a c program pretty printer)
+% by Jim Fox, February 1987
+% version 1.1, August 10, 1989
+% version 1.2, October 30, 1989
+% fixed spacing after ?, :, etc.
+% version 1.3, June 28, 1990
+% added OOdent and IIdent, added \|typewriter|
+% version 1.4, January 4, 1991
+% allow /* and */ in strings
+% version 1.5, December 11, 1991
+% page offset shift for two-sided page print alignment
+% nicer setting of too-long code lines
+% add \listfile and \includefile macros
+% version 1.6, March 17, 1992
+% Restore plain-tex meaning of right quote in math
+%
+%------------------------------------------------------------------
+%
+% The TeX input file is a c source program. It is assumed to have
+% this structure:
+%
+% /* comments ignored by c-no-web
+% \input cnoweb
+% \title{A one line title of the program (optional) }
+% \synopsis{Synopsis of the program (optional) }
+% \section{Name of the first section}
+% rest of comments */
+%
+% The rest of the file is normal c code.
+% Within the title a \\ may be used to separate lines.
+%
+% Each major section begins with
+% /* \section{name of the section} .... */
+% The section names are printed boldface, marked for reference in
+% the page headline, and written to the table of contents.
+%
+% Each minor section begins with
+% /* \subsection{name of the subsection} .... */
+% The subsection names are written to the table of contents.
+%
+% A new page can be forced by
+% /* \newpage */
+%
+% Code and other text containing special characters may be
+% typed in text mode if it is bracked by *< ... >*
+% e.g. /* *<inactive c-code>* */
+% but this may not be used in a macro argument.
+%
+% You can print in bold by enclosing text in double quotes: \"text".
+% You can print in typewriter by enclosing text in vertical bars: \|text|.
+% You can print in italics by enclosing text in single quotes: \'text'.
+%
+% You can include a verbatim listing of a file with \listfile, e.g.,
+% ... \listfile{program.h} ...
+% You can include a c file to be formatted with \includefile, e.g.,
+% ... \includefile{program.h} ...
+%
+% The file must end with \endc in a comment. e.g.,
+% ... last c code statement ...
+% /* \endc */
+%
+%-----------------------------------------------------------------
+%
+% Make sure macros loaded only once
+%
+\expandafter\ifx\csname cnoweb loaded\endcsname\relax
+ \expandafter\let\csname cnoweb loaded\endcsname*
+ \else\endinput\fi
+%
+\catcode`\@=11
+%
+\message{[c-no-web vers 1.6]}
+%
+%
+% page parameters -- most of these can be changed without harm
+% The default setup is for 12 point type on an 8.5 x 11 inch page.
+% Two side printing is assumed, 1-inch margins on the inside.
+%
+\vsize=55pc
+\hsize=37pc
+\topskip=2pc
+\parindent=0pt
+\parskip=6pt
+\overfullrule=0pt
+\newdimen\oddsideshift \oddsideshift=0pc % adjustment to odd, left margins
+\newdimen\evensideshift \evensideshift=2pc % adjustment to even, left margins
+\newdimen\rightmarginslop \rightmarginslop=3pc % right margin slop in code
+\newdimen\blockindent \blockindent=18pt % '{' block indentation
+\newdimen\longblockindent \longblockindent=30pt % '(' indentation
+\newskip\sectionskip \sectionskip2pc
+%
+% fonts
+%
+\font\titles=cmr10 scaled\magstep3 % for titles
+%
+% normal commentary size is 12 point
+%
+\font\twelverm=cmr12 % roman text
+\font\twelvei=cmmi12 % math italic
+\font\twelvesy=cmsy10 scaled\magstep1 % math symbols
+\font\twelvebf=cmbx12 % boldface extended
+\font\twelvett=cmtt12 % typewriter
+\font\twelvesl=cmsl12 % slanted roman
+\font\twelveit=cmti12 % text italic
+\font\twelveex=cmex10 scaled\magstep1 % math symbols
+%
+\font\ninerm=cmr9 % roman text
+\font\ninei=cmmi9 % math italic
+\font\ninesy=cmsy9 % math symbols
+%
+\def\normaltype{%
+ \def\rm{\fam0\twelverm}%
+ \textfont0=\twelverm \scriptfont0=\ninerm \scriptscriptfont0=\sevenrm
+ \textfont1=\twelvei \scriptfont1=\ninei \scriptscriptfont1=\seveni
+ \textfont2=\twelvesy \scriptfont2=\ninesy \scriptscriptfont2=\sevensy
+ \textfont3=\twelveex \scriptfont3=\twelveex \scriptscriptfont3=\twelveex
+ \textfont\itfam=\twelveit \def\it{\fam\itfam\twelveit}%
+ \textfont\slfam=\twelvesl \def\sl{\fam\slfam\twelvesl}%
+ \textfont\bffam=\twelvebf \def\bf{\fam\bffam\twelvebf}%
+ \textfont\ttfam=\twelvett \def\tt{\fam\ttfam\twelvett}%
+ \normalbaselineskip 14\p@
+ \setbox\strutbox=\hbox{\vrule height10\p@ depth4\p@
+ width0\p@}%
+ \normalbaselines\rm}
+\normaltype
+%
+% normal code size is 11 point
+%
+\font\elevenrm=cmr10 scaled\magstephalf % roman text
+\font\eleveni=cmmi10 scaled\magstephalf % math italic
+\font\elevensy=cmsy10 scaled\magstephalf % math symbols
+\font\elevenbf=cmbx10 scaled\magstephalf % boldface extended
+\font\eleventt=cmtt10 scaled\magstephalf % typewriter
+\font\elevensl=cmsl10 scaled\magstephalf % slanted roman
+\font\elevenit=cmti10 scaled\magstephalf % text italic
+%
+\def\codetype{%
+ \def\rm{\fam0\elevenrm}%
+ \textfont0=\elevenrm \scriptfont0=\sevenrm \scriptscriptfont0=\fiverm
+ \textfont1=\eleveni \scriptfont1=\seveni \scriptscriptfont1=\fivei
+ \textfont2=\elevensy \scriptfont2=\sevensy \scriptscriptfont2=\fivesy
+ \textfont3=\tenex \scriptfont3=\tenex \scriptscriptfont3=\tenex
+ \textfont\itfam=\elevenit \def\it{\fam\itfam\elevenit}%
+ \textfont\slfam=\elevensl \def\sl{\fam\slfam\elevensl}%
+ \textfont\bffam=\elevenbf \def\bf{\fam\bffam\elevenbf}%
+ \textfont\ttfam=\eleventt \def\tt{\fam\ttfam\eleventt}%
+ \normalbaselineskip 13\p@
+ \setbox\strutbox=\hbox{\vrule height9.5\p@ depth3.5\p@ width0\p@}%
+ \normalbaselines\rm}
+%
+% restricted code size is 10 point
+%
+\def\rcodetype{%
+ \def\rm{\fam0\tenrm}%
+ \textfont0=\tenrm \scriptfont0=\sevenrm \scriptscriptfont0=\fiverm
+ \textfont1=\teni \scriptfont1=\seveni \scriptscriptfont1=\fivei
+ \textfont2=\tensy \scriptfont2=\sevensy \scriptscriptfont2=\fivesy
+ \textfont3=\tenex \scriptfont3=\tenex \scriptscriptfont3=\tenex
+ \textfont\itfam=\tenit \def\it{\fam\itfam\tenit}%
+ \textfont\slfam=\tensl \def\sl{\fam\slfam\tensl}%
+ \textfont\bffam=\tenbf \def\bf{\fam\bffam\tenbf}%
+ \textfont\ttfam=\tentt \def\tt{\fam\ttfam\tentt}%
+ \normalbaselineskip 13\p@
+ \setbox\strutbox=\hbox{\vrule height9.5\p@ depth3.5\p@ width0\p@}%
+ \normalbaselines\rm}
+%
+% try using 11pt for text also
+%
+\let\normaltype\codetype
+\let\smalltype\rcodetype
+\normaltype
+%
+% allow underscore as char in non-math text
+\def\oldun{_}
+\def\specialunderscore{\ifmmode_\else{\tt\char"5F}\fi}
+\catcode`\_=\active
+\let_\specialunderscore
+%
+\def\\{{\tt\char"5C}} % for \ in comments
+\def\section#1{\mark{#1}%
+ {\let\folio=\relax\let_=\oldun \edef\\{\write\cfile{\endgraf
+ \tocnormaltype#1\cdots\cpageno\endgraf}}\\}%
+ {\bf#1.\ }}
+\def\subsection#1{%
+ {\let\folio=\relax\let_=\oldun \edef\\{\write\cfile{\endgraf
+ \toccodetype\hskip12pt#1\cdots\cpageno\endgraf}}\\}%
+ {#1.\ }}
+\def\subsubsection#1{%
+ {\let\folio=\relax\let_=\oldun \edef\\{\write\cfile{\endgraf
+ \tocrcodetype\hskip18pt#1\cdots\cpageno\endgraf}}\\}%
+ {#1.\ }}
+%
+%
+% headline contains (title, page number, section)
+%
+\def\makeheadline{\vbox to0pt{\vskip-30pt
+ \ifnum\pageno=-1\else\line{\strut\normaltype
+ \ifodd\pageno\firstmark\hfill\bf\the\job\rlap{\ -- \folio}%
+ \else\bf\llap{\folio\ -- }\the\job\rm\hfill\firstmark\fi}\fi
+ \vss}\nointerlineskip}
+\def\makefootline{\line{\tenrm\vrule height30pt depth0pt width0pt
+ \ifodd\pageno\today\ @\rightnow\ by \cnoweb\hfill
+ \else\hfill\today\ @\rightnow\ by \cnoweb\fi}}
+%
+\def\plainoutput{\shipout\vbox{%
+ \ifodd\pageno\moveright\oddsideshift\else\moveright\evensideshift\fi
+ \vbox{\makeheadline\pagebody\makefootline}}%
+ \advancepageno
+ \ifnum\outputpenalty>-\@MM \else\dosupereject\fi}
+
+\let\oldpagebody\pagebody
+\def\toprules{\vrule height4pt width.4pt\kern-.4pt\hskip\blockindent}
+\def\pagebody{\ifnum\pageno>0\vbox to0pt{\hrule height.3pt width\hsize
+ \leftline{\leaders\hbox{\toprules}}%
+ \vss}\nointerlineskip
+ \hbox{\llap{\vrule height\vsize width.3pt\hskip3pt}%
+ \oldpagebody}%
+ \else\oldpagebody\fi}
+
+%
+% table of contents
+%
+\newwrite\cfile
+\immediate\openout\cfile=\jobname.toc
+\def\cdots{\nobreak\leaders\hbox to1pc{\hss.\hss}
+ \hskip24pt plus1fill}
+\def\cpageno{\rlap{\hbox to18pt{\hfill\folio}}}
+%
+% these set the type size in toc entries
+%
+\let\tocnormaltype\relax % de-activate
+\let\toccodetype\relax
+\let\tocrcodetype\relax
+%
+%
+%-------------------------------------------------------------------
+%
+%
+% All comment fields are formatted normally (plain TeX style).
+% All c code is scanned and formatted verbatim.
+%
+% '/*' triggers TeX mode, '*/' triggers verbatim mode
+%
+\let\star=* % a catcode 11 star
+\let\slash=/ % a catcode 11 slash
+\let\rarrow=> % a catcode 11 right arrow
+%
+% ---------------------------------------------------------------
+%
+% In TeX mode the * is active and looks for */ or *<
+% \setex sets TeX mode
+%
+\newif\ifrestricted\restrictedfalse
+\def\setex{% begins TeX mode
+ \ifrestricted\rcodetype
+ \else\ifvmode\normaltype\filbreak\else\codetype\fi\fi
+ \catcode`\*=\active
+ {\tt/* }\ignorespaces}
+%
+{\catcode`\*=\active
+ \gdef*{\futurelet\next\checkslash}
+ }
+\def\checkslash{%
+ \ifx\next/\ifrestricted\let\next\resetrcc\else\let\next\setcc\fi
+ \else\ifx\next<\let\next\setrcc
+ \else\let\next\star\fi\fi\next}
+%
+%
+% In code mode / is active and looks for /*
+% \setcc sets the active code mode
+%
+\def\setcc/{\@setcc}
+\def\@setcc{% set code mode
+ \begingroup\ccverbatim\catcode`\/=\active
+ */
+ \parskip=0pt}
+%
+{\catcode`\/=\active
+ \gdef/{\futurelet\next\checkstar}
+ }
+\def\checkstar{\ifx\next*\let\next\endcc
+ \else\let\next\slash\fi\next}
+\def\endcc*{\@endcc}
+\def\@endcc{\endgroup\ifvmode\filbreak\fi\setex}
+%
+%
+% In restricted code mode > is active and looks for >*
+% \setrcc sets the restricted code mode
+%
+\def\setrcc<{% set little code mode
+ \begingroup\restrictedtrue
+ \begingroup\ccverbatim\rccverbatim\tt\catcode`\>=\active
+ \catcode`\/=\active
+ \parskip=0pt}
+%
+\def\resetrcc/{% reset little code mode
+ \begingroup\ccverbatim\rccverbatim\tt\catcode`\>=\active
+ \catcode`\/=\active
+ */
+ \parskip=0pt}
+%
+{\catcode`\>=\active
+ \gdef>{\futurelet\next\checkrstar}
+ }
+\def\checkrstar{\ifx\next*\let\next\endrcc
+ \else\let\next\rarrow\fi\next}
+\def\endrcc*{\endgroup\endgroup}
+%
+%
+% ---------------------------------------------------------------
+%
+% \leftskip is controlled by the presence of '{', '}',
+% '(', and ')' in the code text.
+%
+% \Ident increases \leftskip and takes effect after the current line
+% \Odent decreases \leftskip and takes effect on the current line
+% \IIdent and \OOdent do the same but use the long indentation
+%
+\newdimen\leftadjust % leftskip adjustment at next par
+\def\Ident{\global\advance\leftadjust\blockindent}
+\def\Odent{\global\advance\leftadjust-\blockindent\doOdent}
+\def\IIdent{\global\advance\leftadjust\longblockindent}
+\def\OOdent{\global\advance\leftadjust-\longblockindent\doOdent}
+\def\doOdent{%
+ \ifvmode\ifdim\leftadjust<\z@\global\advance\leftskip\leftadjust
+ \global\leftadjust0pt\fi\fi}
+%
+\def\codepar{% this is \par in code mode
+ \ifvmode\bigskip % this way blank lines are ignored at page tops
+ \else\endgraf
+ \ifdim\leftadjust=\z@\else\global\advance\leftskip\leftadjust
+ \global\leftadjust0pt\fi\fi}
+%
+% ---------------------------------------------------------------
+%
+% Here are the catcodes and definitions for c-code verbatim
+%
+\chardef\other=12
+\def\ccverbatim{% set all chars to type `other' or `active'
+ \catcode`\\=\other
+ \catcode`\{=\active
+ \catcode`\}=\active
+ \catcode`\(=\active
+ \catcode`\)=\active
+ \catcode`\$=\other
+ \catcode`\*=\other
+ \catcode`\&=\other
+ \catcode`\#=\active
+ \catcode`\%=\other
+ \catcode`\~=\other
+ \catcode`\_=\other
+ \catcode`\^=\other
+ \catcode`\|=\other
+ \catcode`\`=\active
+ \catcode`\'=\active
+ \catcode`\"=\active
+ \let\par\codepar
+ \obeyspaces \obeylines \frenchspacing \codetype
+ \pretolerance10000 % don't hyphenate variable names, etc.
+ \everypar{\hangindent\longblockindent\hangafter1}% indent wrapped
+ \rightskip0pt minus\rightmarginslop % allow some extension
+ \tt}
+\def\rccverbatim{% additional \other chars for restricted mode
+ \catcode`\{=\other
+ \catcode`\}=\other
+ \catcode`\(=\other
+ \catcode`\)=\other
+ \catcode`\#=\other
+ \catcode`\'=\other
+ \catcode`\"=\other
+ \rcodetype \tt}
+%
+% And here are the definitions for the c-code active characters.
+% These perform the little formatting we do on c-code.
+% {, }, (, ), and # adjust the indentation
+% `, ', ", and / trigger more complete verbatim
+%
+% Note that the right quote already has a plain-tex definition
+%
+{ \catcode`\<=1\catcode`\>=2
+ \catcode`\{=\active \gdef{<<\Ident\char`\{>>
+ \catcode`\}=\active \gdef}<<\Odent\char`\}>>
+ \catcode`\(=\active \gdef(<<\IIdent\char`\(>>
+ \catcode`\)=\active \gdef)<<\OOdent\char`\)>>
+ \catcode`\|=0
+ \catcode`\\=\active
+ |catcode`|"=|active
+ |gdef"<|char`|"|bgroup
+ |catcode`|{=|other |catcode`|}=|other
+ |catcode`|(=|other |catcode`|)=|other
+ |catcode`|'=|other |catcode`|/=|other
+ |catcode`|\=|active |let\|verbslash
+ |def"<<|char`|"|egroup>>>
+ |catcode`|'=|active
+ |global|let|plain@rquote'
+ |gdef|cnoweb@rquote<|char`|'|bgroup
+ |catcode`|{=|other |catcode`|}=|other
+ |catcode`|(=|other |catcode`|)=|other
+ |catcode`|"=|other |catcode`|/=|other
+ |catcode`|\=|active |let\|verbslash
+ |def'<<|char`|'|egroup>>>
+ |gdef'<|ifmmode|let|next|plain@rquote
+ |else|let|next|cnoweb@rquote|fi|next>
+ >
+\def\verbslash{\begingroup\catcode`\'=\other\catcode`\"=\other\doverbslash}
+\def\doverbslash#1{\\#1\endgroup}
+{\catcode`\`=\active\gdef`{\relax\lq}}
+{\catcode`\#=\active\gdef#{\ifvmode\ifdim\leftskip>\z@
+ \noindent\llap{\hbox to\leftskip{\#\hss}}\ignorespaces
+ \else\#\fi\else\#\fi}}
+%
+%
+% ---------------------------------------------------------------
+%
+% \listfile produces a verbatim listing of a file
+% \includefile formats the file (assumed to be c-code)
+%
+{\obeyspaces\gdef\hardspaces{\global\let =\ }}
+\def\listfile#1{\par\begingroup\leftskip\blockindent\parskip0pt
+ \ccverbatim\rccverbatim\hardspaces\input#1\par\endgroup}
+\def\includefile#1{\@setcc\par\input#1\par\@endcc}
+%
+% ---------------------------------------------------------------
+%
+% \endc signals end of the c program
+%
+\def\endc{{\it end~\tt*/}\vfill\eject\dotitle\docontents\end}
+%
+% ---------------------------------------------------------------
+%
+% /* \newpage */ should give nice new page
+\def\newpage{\vadjust{\vfill\eject}}
+%
+% some ebcdic systems get 05 for tabs
+\catcode`\^^E=10 % make them spaces
+%
+% \"bold text" and \|typewriter text| and \'italic text'
+%
+\def\"#1"{{\bf#1}}
+\def\|#1|{{\tt#1}}
+\def\'#1'{{\it#1}}
+%
+% fix \item, etc. to work without \parindent
+%
+\newdimen\itemindent\itemindent2\blockindent
+\def\hang{\hangindent\itemindent}
+\def\textindent#1{\indent\hbox to\itemindent{\hss#1\enspace}\ignorespaces}
+\def\item{\par\hang\textindent}
+\def\textiindent#1{\indent\hbox to2\itemindent{\hss#1\enspace}\ignorespaces}
+\def\itemitem{\par\indent\hangindent2\itemindent\textiindent}
+\def\narrower{\advance\leftskip\itemindent
+ \advance\rightskip\itemindent}
+%
+% c-no-web name
+%
+\def\cnoweb{\hbox{c-\setbox0=\hbox{web}%
+ \vrule depth-.25\ht0 height.33\ht0 width\wd0\kern-\wd0\box0}}
+%
+% print the title and table of contents
+%
+\newtoks\job\job={\jobname}
+\newtoks\title\title={}
+\newtoks\synopsis\synopsis={}
+\def\dotitle{
+ \ifodd\pageno\else
+ \message{page alignment}Intentionally blank \vfill\eject\fi
+ \pageno=-1
+ \vglue2pc
+ \centerline{\titles\the\job}
+ \vskip18pt
+ \centerline{\bf\the\title}
+ {\openup3pt\narrower\noindent\the\synopsis\par}
+ \vfill}
+\def\docontents{% print table of contents
+ \mark{Contents}
+ \immediate\closeout\cfile
+ \begingroup
+ \catcode`\@=11
+ \leftskip=18pt\rightskip=\leftskip
+ \everypar={\hang}
+ \rightline{Page}
+ \medskip
+ \let\tocnormaltype\normaltype % activate these type size macros
+ \let\toccodetype\codetype
+ \let\tocrcodetype\rcodetype
+ \input \jobname.toc
+ \catcode`\@=12
+ \endgroup
+ \vfill
+ \eject}
+\def\today{\ifcase\month\or
+ January\or February\or March\or April\or May\or June\or
+ July\or August\or September\or October\or November\or December\fi
+ \space\number\day, \number\year}
+\def\today{\ifcase\month\or
+ Jan\or Feb\or Mar\or Apr\or May\or Jun\or
+ Jul\or Aug\or Sep\or Oct\or Nov\or Dec\fi
+ \space\number\day, \number\year}
+\def\rightnow{\count0=\time\count1=\count0 \divide\count0by60
+ \ifnum\count0<10 0\fi\number\count0:% hours
+ \multiply\count0by60 \advance\count1by-\count0
+ \ifnum\count1<10 0\fi\number\count1% minutes
+ }
+%
+\catcode`\@=11
+%
+{\hsize\maxdimen
+ \output={\setbox0=\box255}\eject} % delete all before \input cnoweb
+\setex % begin with TeX mode
+
+% end of cnoweb.tex
diff --git a/web/c_cpp/cnoweb/pf.c b/web/c_cpp/cnoweb/pf.c
new file mode 100644
index 0000000000..5fb0af98de
--- /dev/null
+++ b/web/c_cpp/cnoweb/pf.c
@@ -0,0 +1,371 @@
+/*
+ pf.c in c-no-web format. (8/10/89)
+ by Jim Fox, University of Washington
+
+ \input cnoweb % load the c-no-web system
+%
+% \nweb ... \bewn = \cnoweb commentary
+ \def\nweb{\leavevmode\begingroup\codetype$\lbrack\!\lbrack\;$}
+ \def\bewn{$\;\rbrack\!\rbrack$\ \endgroup}
+%
+ \title{Printing factorials: a demonstration of \cnoweb}
+ \synopsis{You are reading a program listing that was formatted
+ with \par\item{}{\tt \% tex pf.c}\par
+ The same program is compiled
+ with \par\item{}{\tt \% cc pf.c}\par
+ The key to this dual function source file is a \TeX\ macro
+ package called \cnoweb\ that treats all comments as `\TeX-text'
+ and all else as `verbatim-text.' The C compiler naturally
+ does the opposite and interprets only the text outside the comments.
+
+ \nweb In this program comments about
+ \cnoweb\ itself look like this.\bewn}
+ \section{Introduction}
+
+ This program prints factorials of positive integers.
+ It uses this definition of $n!$
+ $$ n! = \prod_{i=1}^n i$$
+
+ {\narrower
+ \nweb \"pf.c" begins with a comment which
+ is treated as \TeX-text by \cnoweb.
+
+ The first comment contains the
+ string *<\input cnoweb>*. This begins the \cnoweb\ listing.
+ Included also in this leading comment section is
+ *<\title{Printing ...}>*,
+ *<\synopsis{You are reading ...}>*,
+ and
+ *<\section{Introduction}>*.\bewn\par}
+
+ The program is invoked with the command
+ \item{}\"pf $[$-l$]$ $[$-e$]$ $n$"
+
+ where
+ \item{\bf -l} prints the factorials of all numbers
+ up to and including the limit $n$.
+ \item{\bf -e} includes an exponential notation approximation.
+ \item{$n$} is the number whose factorial will be printed.
+ */
+
+#define GOODEXIT 0 /* exit with this if factorial OK */
+#define BADEXIT 1 /* exit with this if error */
+
+#include <stdio.h> /* standard io stuff */
+#include <math.h> /* math stuff */
+char *malloc(); /* memory allocator */
+
+/* \section{Big-integer routines}
+
+ \"pf" would be trivial were it not for the rapid
+ growth of $n!$, which is much greater than exponential
+ and quickly surpasses even the real number capacity of most machines.
+ We therefore define a new data type (\"Int") to hold big integers.
+ */
+
+ typedef struct Int_ {
+ int radix; /* $2^1 \le \hbox{radix} \le 2^8$ */
+ char *digits; /* the \"Int"'s digits */
+ int length; /* number of digits available */
+ int limit; /* number of digits in use */
+ } Int;
+
+/* We do not need many operations on \"Int"s to compute factorials:
+ only `set' and `multiply'.
+ */
+
+/* \subsection{\"Set(I,\ i)"}
+ Return \"I" initialized to \"i". */
+
+Set(I,i)
+Int *I;
+int i;
+{
+ int d;
+ I->digits[0] = (i?1:0);
+ for (d=1; d<I->length; I->digits[d++]=0);
+ I->limit = 0;
+ if ((i!=0)&&(i!=1)) Product(I,i);
+ return (0);
+}
+
+/* \subsection{\"Product(I,\ i)"}
+ Return \"I" multiplied by \"i".
+ Returns true if the product is OK. */
+
+Product(I,i)
+Int *I;
+int i;
+{
+ int d,n;
+ int l = I->limit+1;
+ int r = I->radix;
+ int carry = 0;
+
+ for (d=0; ((d<l)||(carry!=0)); d++) {
+ if (d>=I->length) return (0); /* not enough digits */
+ n = I->digits[d] * i + carry;
+ if ((I->digits[d] = n % r)>0) I->limit = d;
+ carry = n / r;
+ }
+ return (1);
+}
+
+
+
+/* \section{\"main()"} Print the factorial of the integer
+ found on the command line.
+
+ \item{1.} Parse command line arguments.
+ \item{2.} Compute number of digits needed and allocate space.
+ \item{3.} Calculate the factorial.
+ \item{4.} Print the factorial.
+
+ \nweb \cnoweb\ breaks pages only before comments.\hfill\break
+ You can control pagination with this knowledge.\bewn
+
+ The higher the radix the fewer digits needed, but
+ we use an internal radix of 10
+ to save a lot of division when printing the number.
+ Also, we already have a log$_{10}$ function.
+
+ */
+
+#define RADIX 10
+
+Int nfactorial; /* place for the factorial */
+Int *nf = &nfactorial;
+
+/* command line parameters */
+
+ int limit_mode = 0; /* true if printing all factorials */
+ int expon_mode = 0; /* true if printing exponential notation */
+
+/* start of the program */
+
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ int n;
+ int i;
+
+ /* 1. Parse the command line */
+
+ n = parse_args(argc,argv); /* we will print $n!$ */
+
+ /* 2. Compute digits needed and allocate space */
+
+ nf->radix = RADIX;
+ nf->length = digits(n,RADIX);
+
+ if ((nf->digits = malloc(nf->length))==NULL) {
+ printf("Sorry, cannot allocate space for %d digits\n",
+ nf->length);
+ exit (BADEXIT);
+ }
+
+ /* 3. Calculate the factorial. */
+
+ Set(nf,1); /* initialize \"nf" */
+
+ for (i=1; i<=n; i++) {
+ if (Product(nf,i)==0) {
+ printf("Sorry, miscalculated the number of digits.\n");
+ exit (BADEXIT);
+ }
+ if (limit_mode) print_Int(nf,i);
+ }
+
+ /* 4. Print the result, if it hasn't been printed yet. */
+
+ if (!limit_mode) print_Int(nf,n);
+ exit (GOODEXIT);
+}
+
+/* \subsection{\"parse_args(argc,argv)"}
+
+ This is a standard UNIX idiom.
+ See Kernighan \& Ritchie.
+
+ \nweb \cnoweb\ automatically indents after
+ {\tt\char`\{} and {\tt\char`\(}.\bewn */
+
+parse_args(argc,argv)
+int argc;
+char *argv[];
+{
+ int n = (-1);
+
+ while (--argc > 0) {
+ argv++;
+ if (argv[0][0]=='-') { /* is an option flag */
+ switch (argv[0][1]) {
+ case 'l': {
+ limit_mode = 1;
+ break;
+ }
+ case 'e': {
+ expon_mode = 1;
+ break;
+ }
+ default: show_usage();
+ }
+ } else { /* is the number */
+ sscanf(argv[0],"%d",&n);
+ }
+ }
+
+ if (n<=0) show_usage();
+ return (n);
+}
+
+/* \subsection{\"digits(n,r)"} Returns number of digits in \"n"
+ using a radix of \"r".
+
+ A factorial can be approximated by the Sterling formula
+ $$ n! \approx e^{-n} n^{n} \sqrt{2\pi n}$$
+ What we want is the number of digits, which is
+ $$ \hbox{\# digits} \approx \log_r(n!)=\log(n!)/\log(r) \approx
+ (-n \log e + n \log n + {1\over2}\log (2\pi n))/\log(r)$$
+
+ We will add a couple of digits to this value
+ to allow for the approximations and assure that we
+ have enough.
+ */
+
+#define PI 3.141592653589793238462643 /* $\pi$ */
+#define E 2.718281828459045235360287 /* $e$ */
+
+digits(n,r)
+int n;
+int r;
+{
+ double dn = n;
+ int nd;
+
+ nd = (int)((-dn * log10(E)) +
+ (dn * log10(dn)) + (.5 * log10(2*PI*dn)))/log10((double)r) + 2;
+ /* *<printf("requires %d digits\n",nd);>* */
+
+ /* \nweb The
+ `Commented out' code above was typed:
+ {\tt/{}* *{}<printf...;>{}* *{}/}.\bewn */
+
+ return (nd);
+}
+
+/* \subsection{\"print_Int(I,\ i)"}
+ Print {\tt{\it value(}i{\it)} = {\it value(}I{\it)}}.
+ The internal radix that matches the display radix
+ clearly makes this procedure easier.
+
+ This display uses the convention that separates each
+ three-digit set with commas.
+*/
+
+#define MAX_WIDTH 80 /* maximum width of the output */
+
+print_Int(I,i)
+Int *I;
+int i;
+{
+ int d;
+ int lp,bp;
+ char line[MAX_WIDTH];
+
+ sprintf(line,"%d! = ",i);
+ bp = lp = strlen(line);
+ for (d=I->limit; d>=0; d--) {
+ line[lp++] = I->digits[d] + '0'; /* assumes radix $\le 10$ */
+ if ((d%3)==0) {
+ line[lp++] = (d?',':'.');
+ if ((d==0) || (lp>MAX_WIDTH-5)) {
+ line[lp] = '\0';
+ printf("%s\n",line);
+ for (lp=0; lp<bp; line[lp++]=' ');
+ }
+ }
+ }
+
+ /* If the exponential notation was desired, print it now.
+ */
+
+ if (expon_mode) {
+ int d = I->limit; /* the most significant digit */
+ sprintf(line+bp,"approximately = %d.%d x 10e%d",
+ I->digits[d],d?I->digits[d-1]:0,d);
+ printf("%s\n",line);
+ }
+ return (0);
+}
+
+/* \section{\"show_usage()"} invocation syntax error---show
+ correct usage */
+
+int show_usage()
+{
+ printf("usage: pf [-l] [-e] positive_integer\n");
+ exit (BADEXIT);
+}
+
+/* \section{Summary of \cnoweb\ commands}
+
+ These control sequences are defined in the \cnoweb\ macro package.
+
+ \begingroup
+ \def\{{{\tt\char`\{}}
+ \def\}{{\tt\char`\}}}
+ \def\cs#1{\smallskip\noindent\hangindent7\blockindent\hangafter1
+ \hbox to7\blockindent{\bf#1\qquad\hss}\ignorespaces}
+
+ \cs{\\title\{ ... \}} Titles the program.
+ \cs{\\job\{ ... \}} Another title area. Defaults to input filename.
+ \cs{\\section\{ ... \}} Begins a section. The section title
+ is also included in the table of contents and
+ in the page header.
+ \cs{\\subsection\{ ... \}} Begins a subsection. The subsection title
+ is also included in the table of contents.
+ \cs{\\subsubsection\{ ... \}} Begins a subsubsection.
+ The subsubsection title
+ is also included in the table of contents.
+ \cs{\\newpage} Causes a page eject after the current line. This
+ is usually used in a comment by itself, e.g.,
+ \hbox{\tt /{}* \\newpage *{}/}.
+ \cs{\\endc} Ends the \cnoweb\ listing. This
+ is usually the last line in the file, e.g.,
+ \hbox{\tt /{}* \\endc *{}/}.
+ \cs{\\{\tt"} ... {\tt"}} Prints {\bf bold} text.
+ \cs{\\{\tt'} ... {\tt'}} Prints {\it italic} text.
+ \cs{\\{\tt|} ... {\tt|}} Prints {\tt typewriter} text.
+ \cs{*{\tt<} ... {\tt>}*} Allows C code to be included in comments.
+ You can nest comments within the `commented out' C code, e.g.,
+ \hfill\break
+ {\tt/{}* comment out this section *{}<} \hfill\break
+ \hglue\blockindent{\tt i = 0; /{}* initialize \"i" *{}/} \hfill\break
+ \hglue\blockindent{\tt ...} \hfill\break
+ \hglue\blockindent{\tt >{}* end of the commented out section *{}/}
+
+ \cs{\\item, \\hang, {\rm etc.}} Work as you hope they would.
+ \endgroup
+
+ */
+
+/* \section{How to obtain \cnoweb}
+
+ You may obtain \cnoweb\ by anonymous ftp to
+ {\tt u.washington.edu}.
+
+ It is in the directory: {\tt pub/tex/cnoweb}
+
+ \bigskip
+ \rightline{--- Jim Fox,
+ University of Washington}
+ \rightline{\strut \tt fox@cac.washington.edu}
+
+ \medskip
+
+ The file ends with the comment
+ `{\tt /{}* \\endc *{}/}' */
+
+/* \endc */