├── Makefile ├── README ├── changelog ├── clojlisp.pamphlet ├── clojlisp.pdf └── tangle.c /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT=clojlisp 2 | TANGLE=tangle 3 | LATEX=/usr/bin/latex 4 | MAKEINDEX=/usr/bin/makeindex 5 | UUDECODE=uudecode 6 | PDF=dvipdf 7 | 8 | all: 9 | ${TANGLE} ${PROJECT}.pamphlet ${PROJECT} >${PROJECT}.lisp 10 | ${TANGLE} ${PROJECT}.pamphlet clojureIcon.eps.uu >clojureIcon.eps.uu 11 | ${UUDECODE} clojureIcon.eps.uu 12 | ${LATEX} ${PROJECT}.pamphlet 13 | ${MAKEINDEX} ${PROJECT}.idx 14 | ${LATEX} ${PROJECT}.pamphlet 15 | ${PDF} ${PROJECT}.dvi 16 | rm -f ${PROJECT}.aux ${PROJECT}.idx ${PROJECT}.ilg ${PROJECT}.ind 17 | rm -f ${PROJECT}.log ${PROJECT}.out ${PROJECT}.toc ${PROJECT}.aps 18 | rm -f ${PROJECT}.dvi *.eps.uu *~ clojureIcon.eps 19 | 20 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is a port of Clojure to Common Lisp. 2 | We use SBCL as our version of Common Lisp. 3 | We use latex as our markup language. 4 | We use git as our repository. 5 | 6 | On Linux, you will need to install certain tools. 7 | 8 | apt-get install sbcl git-core texlive 9 | 10 | The program is implemented as a literate program. A literate program 11 | is a book that contains both the explanation and the source code. The 12 | idea is that you write words to communicate ideas to other people and 13 | then implement these words in lisp to communicate ideas to the machine. 14 | 15 | The "quick start" is: 16 | 17 | gcc -o tangle tangle.c 18 | ./tangle clojlisp.pamphlet Makefile >Makefile 19 | make 20 | xpdf clojlisp.pdf & 21 | emacs clojlisp.pamphlet 22 | .... loop 23 | .... make changes 24 | .... type make at the command line 25 | .... see changes reflected in the pdf 26 | .... play in the lisp command line 27 | 28 | 29 | In slightly more detail, the idea is that you have a program called 30 | "tangle" which extracts "chunks" from the clojure.pamphlet file. 31 | You can choose any "chunk" in the file. Chunks are in latex chunk 32 | environments which are just pieces of text between 33 | 34 | \begin{chunk}{theChunkName} 35 | your code goes here 36 | \end{chunk} 37 | 38 | To build the tangle program just type: 39 | 40 | gcc -o tangle tangle.c 41 | 42 | which compiles the program and creates a command line function called 43 | "tangle". Because it is in the local directory you need to use use 44 | "./tangle" to run it. 45 | 46 | The tangle program accepts two arguments, the file and the chunk name, 47 | and outputs the result to standard output. You can redirect this to a 48 | file as in: 49 | 50 | ./tangle clojlisp.pamphlet clojlisp >clojlisp.lisp 51 | 52 | which will extract the clojlisp program and put it in the clojlisp.lisp 53 | file. 54 | 55 | Most of the build steps are automated in the Makefile. 56 | 57 | Working in literate programming is simple. You need an editor and a 58 | command line. Make changes directly to this document using the editor 59 | and then type 60 | 61 | make 62 | 63 | This will destroy the old source and rebuild the clojlisp.lisp file. 64 | 65 | If you change the Makefile section in the document, which is rare, you 66 | will have to extract it before the changes take effect: 67 | 68 | ./tangle clojlisp.pamphlet Makefile >Makefile 69 | 70 | If you are working in Linux it is very effective to use emacs with a 71 | split screen. Start a command line in one buffer and a shell in the 72 | other buffer. If you start xdvi running in the background you will 73 | immediately see the ``printed'' form of the document every time you 74 | switch to the xdvi window. 75 | 76 | xdvi clojlisp.dvi & 77 | 78 | 79 | The same trick can be used with the PDf file instead. Both xdvi and 80 | xpdf will update automatically when the file is changed on disk. 81 | 82 | xpdf clojlisp.pdf & 83 | 84 | Resist the urge to edit the clojlisp.lisp file. It is only there for 85 | the computer. Edit this file directly. Be sure to write words to 86 | communicate your ideas just as you would when writing a book. The 87 | machine code is secondary and intended to make the ideas concrete. 88 | 89 | To run the clojlisp command line, type: 90 | 91 | sbcl 92 | (load "clojlisp.lisp") 93 | (in-package "CLOJLISP") 94 | (clojlisp) 95 | 96 | Note that the clojlisp function knows almost nothing so you have to 97 | fully qualify every symbol. Try: 98 | 99 | (common-lisp::+ 2 3) 100 | 101 | To quit SBCL from the clojlisp function type: 102 | 103 | (sb-ext:quit) 104 | 105 | Questions and comments should be directed to: 106 | 107 | Tim Daly 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /changelog: -------------------------------------------------------------------------------- 1 | 20111117 tpd clojlisp.pdf cached 2 | 20111117 tpd tangle.c make it always available 3 | 20111117 tpd Makefile clean up immediately 4 | 20111117 tpd clojlisp.pamphlet fix Makefile to clean up immediately 5 | 20111116 tpd 20111116.01.tpd.patch 6 | 20111116 tpd Makefile add clean stanza 7 | 20111116 tpd tangle.c removed, already in clojure.pamphlet 8 | 20111116 tpd clojure.pdf cache 9 | 20111116 tpd clojure.pamphlet add env global, muffle warnings, add imports 10 | 20111115 tpd 20111115.02.tpd.patch remove unnecessary file 11 | 20111115 tpd clojlisp.pdf cached 12 | 20111115 tpd clojureIcon.eps removed, generated from the document 13 | 20111115 tpd 20111115.01.tpd.patch add new user documentation 14 | 20111115 tpd Makefile add the automatic PDF generation 15 | 20111115 tpd clojlisp.pdf cache the PDF 16 | 20111115 tpd clojlisp.pamphlet remove axiom.sty, add local latex tags 17 | 20111115 tpd axiom.sty removed. extracted the latex tags into clojlisp 18 | 20111115 tpd README document the startup process 19 | 20111114 tpd 20111114.01.tpd.patch initial pamphlet and REPL 20 | 20111114 tpd Makefile cache Makefile 21 | 20111114 tpd clojureIcon.eps cache icon 22 | 20111114 tpd tangle.c cache tangle code 23 | 20111114 tpd axiom.sty style file for pamphlet 24 | 20111114 tpd clojlisp.pamphlet created 25 | -------------------------------------------------------------------------------- /clojlisp.pamphlet: -------------------------------------------------------------------------------- 1 | \documentclass{book} 2 | \usepackage{verbatim} 3 | \usepackage{makeidx} 4 | \usepackage{pstricks} 5 | \usepackage{pst-node} 6 | \usepackage{pst-tree} 7 | \usepackage{hyperref} 8 | \usepackage{graphicx} 9 | % make underscore be an ordinary character 10 | \catcode`\_=12 11 | % we need to have an index 12 | \makeindex 13 | \raggedbottom 14 | 15 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 | %%% Define tags to make refs and indexes pretty 17 | \newcommand{\defclass}[1]{% e.g. \defclass{classname} 18 | \label{#1}% 19 | \index{#1}% 20 | \index{Class!#1}% 21 | \index{#1!Class}} 22 | 23 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 24 | %%% Define tags to make refs and indexes pretty 25 | \newcommand{\defsubclass}[2]{% e.g. \defsubclass{classname}{subclassname} 26 | \label{#2}% 27 | \index{#1\$#2}% 28 | \index{Class!#2\ in\ \pageref{#1}}% 29 | \index{#2,\ class in\ \pageref{#1}}} 30 | 31 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 32 | %%% Define tags to make refs and indexes pretty 33 | \newcommand{\definterface}[1]{% e.g. \definterface{ifname} 34 | \label{#1}% 35 | \index{#1}% 36 | \index{Interface!#1}% 37 | \index{#1!Interface}} 38 | 39 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 40 | %%% Define tags to make refs and indexes pretty 41 | \newcommand{\defmethod}[2]{% e.g. \defmethod{classname}{methodname} 42 | \label{#2}% 43 | \index{#1.#2}% 44 | \index{#2,\ method\ in\ \pageref{#1}}} 45 | 46 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 47 | %%% Define tags to make refs and indexes pretty 48 | \newcommand{\implements}[2]{% e.g. \implements{class}{interface} 49 | (#2 [\pageref{#2}])% 50 | \index{Implements!#2,\ by\ #1}% 51 | \index{#1!\ implements\ \pageref{#2}}% 52 | \index{#2!\ implemented\ by\ \pageref{#1}}} 53 | 54 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 55 | %%% Define tags to make refs and indexes pretty 56 | \newcommand{\extends}[2]{% e.g. \extends{class}{interface} 57 | (#2 [\pageref{#2}])% 58 | \index{Extends!#2,\ by\ #1}% 59 | \index{#1!\ extends\ \pageref{#2}}% 60 | \index{#2!\ extended\ by\ \pageref{#1}}} 61 | 62 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 63 | %%% Make our own sectioning commands 64 | \newcommand{\defsection}[1]{% e.g. \defsection{sectionname} 65 | \newpage% 66 | \section{#1}% 67 | \label{#1}} 68 | 69 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 70 | %%% Make our own sectioning commands 71 | \newcommand{\defsubsection}[1]{% e.g. \defsubsection{sectionname} 72 | \subsection{{#1}}% 73 | \label{#1}} 74 | 75 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 76 | %%% Make our own references so we can have hyperlinks in pdfs 77 | \newcommand{\refto}[1]{% e.g. \refto{name} 78 | \index{#1}% 79 | [\pageref{#1}] #1} 80 | 81 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 82 | %%% a pretty box around some example text for quoting and examples 83 | %%% boxed{boxcolor}{textcolor}{width}{text} 84 | %%% boxed{yellow}{black}{4.6in}{text} 85 | \providecommand\boxed[4]{% \boxed{boxcolor}{textcolor}{width}{text} 86 | \begin{center} 87 | \begin{tabular}{|c|} 88 | \hline 89 | \fcolorbox{#1}{#2}{ 90 | \begin{minipage}{#3} 91 | \normalsize 92 | {#4}\hfill 93 | \end{minipage}}\\ 94 | \hline 95 | \end{tabular} 96 | \end{center}} 97 | 98 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 99 | %%% a colored box around quotes 100 | %%% boxed{boxcolor}{textcolor}{width}{text} 101 | %%% boxed{yellow}{black}{4.6in}{text} 102 | \providecommand\quoteme[4]{% \boxed{boxcolor}{textcolor}{width}{text} 103 | \begin{center} 104 | \fcolorbox{#1}{#2}{ 105 | \begin{minipage}{#3} 106 | \normalsize 107 | {#4}\hfill 108 | \end{minipage}}\\ 109 | \end{center}} 110 | 111 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 112 | %%% define the text and background colors for REPL boxes 113 | \definecolor{ExampleTextColor}{rgb}{0.5 1.0 1.0} 114 | \definecolor{ExampleBackColor}{rgb}{0.5.0.0 0.0} 115 | 116 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 117 | %%% a colored box around quotes 118 | %%% boxed{boxcolor}{textcolor}{width}{text} 119 | %%% boxed{yellow}{black}{4.6in}{text} 120 | \providecommand\forexample[1]{% \boxed{boxcolor}{textcolor}{width}{text} 121 | \begin{center} 122 | \fcolorbox{ExampleBackColor}{ExampleTextColor}{ 123 | \begin{minipage}{4.6in} 124 | \normalsize 125 | {#1}\hfill 126 | \end{minipage}}\\ 127 | \end{center}} 128 | 129 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 130 | %%% REPL shows a prompt line and the response 131 | %%% e.g. repl{(+ 2 3)}{5} 132 | \providecommand\repl[2]{% \repl{input}{output} 133 | \forexample{\noindent$>$\ {#1}\\{#2}}} 134 | 135 | 136 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 137 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 138 | %%% The literate environments commands %%%%%%%% 139 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 140 | 141 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 142 | %%% The begin{chunk} environment 143 | \newenvironment{chunk}[1]{% we need the chunkname as an argument 144 | {\ }\newline\noindent% make sure we are in column 1 145 | %{\small $\backslash{}$begin\{chunk\}\{{\bf #1}\}}% alternate begin mark 146 | \hbox{\hskip 2.0cm}{\bf --- #1 ---}% mark the beginning 147 | \verbatim}% say exactly what we see 148 | {\endverbatim% process \end{chunk} 149 | \par{}% we add a newline 150 | \noindent{}% start in column 1 151 | \hbox{\hskip 2.0cm}{\bf ----------}% mark the end 152 | %$\backslash{}$end\{chunk\}% alternate end mark (commented) 153 | \par% and a newline 154 | \normalsize\noindent}% and return to the document 155 | 156 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 157 | %%% the getchunk command 158 | \providecommand{\getchunk}[1]{% 159 | \noindent% 160 | {\small $\backslash{}$begin\{chunk\}\{{\bf #1}\}}% mark the reference 161 | \index{{#1}}} 162 | 163 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 164 | %%% make the chunk font smaller 165 | \chardef\atcode=\catcode`\@ 166 | \catcode`\@=11 167 | \renewcommand{\verbatim@font}{\ttfamily\small} 168 | \catcode`\@=\atcode 169 | 170 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 171 | %%% we need a single column index so write our own 172 | \renewenvironment{theindex}{ 173 | {\Huge {\bf {\hskip 1.0in}Index}}% 174 | \thispagestyle{plain}% \parindent\z@% 175 | \begin{itemize}% 176 | \setlength{\itemsep}{1pt}% 177 | \setlength{\parskip}{0pt}% 178 | \setlength{\parsep}{0pt}% 179 | }{\end{itemize}\clearpage} 180 | 181 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 182 | %%% we need a packed itemize so write our own 183 | \newenvironment{packeditemize}{% 184 | \begin{itemize}% 185 | \setlength{\itemsep}{1pt}% 186 | \setlength{\parskip}{0pt}% 187 | \setlength{\parsep}{0pt}% 188 | }{\end{itemize}} 189 | 190 | 191 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 192 | %%% leave notes for future work 193 | \newcommand{\tpdhere}[1]{% e.g. \tpdhere{Some note} 194 | {\bf TPDHERE: #1}% 195 | \index{TPDHERE!{#1}}} 196 | 197 | \begin{document} 198 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 199 | \begin{titlepage} 200 | \center{\includegraphics{clojureIcon.eps}} 201 | \vskip 0.1in 202 | \vskip 0.1in 203 | \center{{\Huge{Clojure in Common Lisp}}} 204 | \vskip 0.1in 205 | \center{\huge{Timothy Daly}} 206 | \vskip 0.1in 207 | \center{\large{\today}} 208 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 209 | %%% Make sure everyone gets credit 210 | \begin{center} 211 | \begin{tabular}{lll} 212 | \end{tabular} 213 | \end{center} 214 | \vskip 0.1in 215 | \end{titlepage} 216 | 217 | 218 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 219 | %%% Use roman numeral pages for frontmatter 220 | \pagenumbering{roman} 221 | 222 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 223 | %%% because I add lines to the toc, the toc is 4.5pts too wide 224 | %%% so I use this hack to fix it -- TimDaly 225 | \makeatletter 226 | \renewcommand{\@pnumwidth}{2.75em} 227 | \renewcommand{\@tocrmarg}{2.75em} 228 | \makeatother 229 | \tableofcontents 230 | \vfill 231 | \eject 232 | 233 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 234 | %%% Make the forward be business block text style 235 | \setlength{\parindent}{0em} 236 | \setlength{\parskip}{1ex} 237 | {\Large{\bf Foreword}} 238 | \vskip .25in 239 | 240 | Rich Hickey invented Clojure. 241 | This is a fork of the project to build 242 | Clojure in Common Lisp. 243 | 244 | We would like to have these new lisp ideas available in a standard 245 | common lisp environment. There will be some language changes due to 246 | the loss of Java and some enhancements due to Common Lisp. This is 247 | unavoidable but within the spirit of Clojure. 248 | 249 | Every effort is made to give credit for any and all contributions. 250 | 251 | We are also experimenting with literate 252 | programming as a development and documentation technology. 253 | 254 | Clojure is a break with the past traditions of Lisp. This literate 255 | fork is a break with the past traditions of code development. As such 256 | it is intended as an experiment, not a replacement or competition with 257 | the official version of Clojure. 258 | 259 | \vskip .25in 260 | %\noindent 261 | Timothy Daly\\ 262 | November 10, 2011 ((iHy)) 263 | \vfill 264 | \eject 265 | 266 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 267 | %%% Start using regular numbers 268 | \pagenumbering{arabic} 269 | \setcounter{chapter}{0} % Chapter 1 270 | %\textunderscore 271 | 272 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 273 | %%% fix the preface in the table of contents 274 | \frontmatter 275 | 276 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 277 | %%% Preface %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 278 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 279 | 280 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 281 | %%% Make this fake chapter show up in the table of contents 282 | \cleardoublepage 283 | \phantomsection 284 | {\bf {\Large Preface: Why Literate Programming}} 285 | \addcontentsline{toc}{chapter}{Preface: Why Literate Programming} 286 | 287 | {\vbox {\vskip 0.3in}} 288 | 289 | This is a literate program, inspired by Donald Knuth \cite{Knu84}. It is 290 | intended to be read like a novel from cover to cover. The ideas are 291 | expressed clearly but they are grounded in the actual source code. 292 | 293 | The code in this documment is the executable source. The chapter 294 | \refto{building} on Building ClojLisp gives the procedure for building 295 | a running system from the enclosed sources. 296 | 297 | Most programmers are still locked into the idea of making a program 298 | out of a large pile of tiny files containing pieces of programs. 299 | They do not realize that this organization was forced by the fact 300 | that machines like the PDP 11 only had 8k of memory and a limit 301 | of 4k buffers in the editor. Thus there was a lot of machinery built 302 | up, such as overlay linkers, to try to reconstruct the whole program. 303 | 304 | The time has come to move into a more rational means of creating and 305 | maintaining programs. Knuth suggested we write programs like we write 306 | literature, with the idea that we are trying to communicate the ideas 307 | to other people. The fact that the machine can also run the programs 308 | is a useful side-effect but not important. 309 | 310 | Very few people have seen a literate program so this is intended 311 | as a complete working example, published in book form. The intent 312 | is that you can sit and read this book like any other novel. At 313 | the end of it you will be familiar with the ideas and how those 314 | ideas are actually expressed in the code. 315 | 316 | If programmers can read it and understand it then they can maintain 317 | and modify it. The ideas will have been communicated. The code will 318 | be changed to match changes in the idea. We will all benefit. 319 | 320 | I've tried to make it as simple as possible. 321 | Try it once, you might like it. 322 | 323 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 324 | %%% Make this fake section show up in the table of contents 325 | {\bf {\large Steps to build ClojLisp}} 326 | \addcontentsline{toc}{section}{Steps to build Clojure} 327 | {\vbox {\vskip 0.1in}} 328 | 329 | {\bf Step 1} 330 | 331 | We will be using SBCL as the initial development environment so you 332 | need to get an SBCL version running. 333 | 334 | You also need the C program \refto{tangle.c} which you can clip 335 | from this file using a text editor and save it as tangle.c. If you 336 | got this file from a git repository the tangle.c program is probably 337 | already available. The tangle program is used to extract the source 338 | files from this document. 339 | 340 | {\bf Step 2} 341 | 342 | Compile tangle.c to create a function called tangle. 343 | \begin{verbatim} 344 | gcc -o tangle tangle.c 345 | \end{verbatim} 346 | 347 | {\bf Step 3} 348 | 349 | Run tangle to extract the \refto{Makefile} from this document. 350 | \begin{verbatim} 351 | ./tangle clojure.pamphlet Makefile >Makefile 352 | \end{verbatim} 353 | 354 | {\bf Step 4} 355 | 356 | Running make will create a PDF of the documentation and will 357 | create the clojlisp.lisp file containing the latest source code. 358 | \begin{verbatim} 359 | make 360 | \end{verbatim} 361 | 362 | {\bf Step 5} 363 | 364 | Start lisp, change to the new package, and start the REPL. 365 | \begin{verbatim} 366 | sbcl 367 | (load "clojlisp.lisp") 368 | (in-package "CLOJLISP") 369 | (clojlisp) 370 | \end{verbatim} 371 | The new REPL knows almost nothing at all. In particular, it has no 372 | functions and no symbols defined yet so you need to qualify everything. 373 | For example, 374 | \begin{verbatim} 375 | (common-lisp::+ 2 3) 376 | \end{verbatim} 377 | 378 | To exit the program type: 379 | \begin{verbatim} 380 | (sb-ext:quit) 381 | \end{verbatim} 382 | 383 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 384 | %%% Make this fake section show up in the table of contents 385 | {\vbox {\vskip 0.1in}} 386 | {\bf {\large Steps to change Clojure}} 387 | \addcontentsline{toc}{section}{Steps to change Clojure} 388 | {\vbox {\vskip 0.1in}} 389 | 390 | Working in literate programming is simple. You need an editor and a 391 | command line. Make changes directly to this document using the editor 392 | and then type 393 | \begin{verbatim} 394 | make 395 | \end{verbatim} 396 | This will destroy the old source and rebuild the clojlisp.lisp file. 397 | 398 | If you change the Makefile section in the document you will have to 399 | extract it before the changes take effect: 400 | \begin{verbatim} 401 | ./tangle clojlisp.pamphlet Makefile >Makefile 402 | \end{verbatim} 403 | 404 | If you are working in Linux it is very effective to use emacs 405 | with a split screen. Start a command line in one buffer and a 406 | shell in the other buffer. If you start xdvi running in the 407 | background you will immediately see the ``printed'' form of the 408 | document every time you switch to the xdvi window. 409 | \begin{verbatim} 410 | xdvi clojlisp.dvi & 411 | \end{verbatim} 412 | 413 | The same trick can be used with the PDf file instead. Both xdvi and 414 | xpdf will update automatically when the file is changed on disk. 415 | \begin{verbatim} 416 | xpdf clojlisp.pdf & 417 | \end{verbatim} 418 | 419 | Resist the urge to edit the clojlisp.lisp file. It is only there for 420 | the computer. Edit this file directly. Be sure to write words to 421 | communicate your ideas just as you would when writing a book. 422 | The machine code is secondary and intended to make the ideas concrete. 423 | 424 | %%% Tim Daly %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 425 | %%% Make this fake section show up in the table of contents 426 | {\vbox {\vskip 0.1in}} 427 | {\bf {\large Why Bother?}} 428 | \addcontentsline{toc}{section}{Why Bother?} 429 | {\vbox {\vskip 0.1in}} 430 | 431 | Why bother with such a difficult method of programming? Because 432 | worthwhile programs should ``live''. 433 | 434 | Programs ``live'' because people maintain them. Maintaining and 435 | modifying code correctly requires that you understand why the program 436 | is written as it is, what the key ideas that make the program work, 437 | and why certain, not very obvious, pieces of code exist. Programmers 438 | almost never write this information down anywhere. Great ideas are 439 | invented, the code is written, a man page of documentation is created, 440 | and the job is done. 441 | 442 | Well, almost. What does is mean for a program to ``live''? How does a 443 | program survive once the original developers leave the project? There 444 | are many sources of information but almost no source of knowledge. 445 | New programmers don't know what the ``elders'' know. In order to ``live'' 446 | and continue to grow there has to be a way to transmit this knowledge. 447 | 448 | Literate programming is Knuth's proposed idea for moving from the 449 | world of ideas to the world of information. This is not simply another 450 | documentation format. This is meant to be {\bf Literature}. The ideas 451 | are presented, the implications are explored, the tradeoffs are discussed, 452 | and the code is ``motivated'', like characters in a novel. 453 | 454 | You are encouraged to write or rewrite sections of this document to 455 | improve the communication with the readers. 456 | 457 | ``But I have to learn latex!''. Well, for this document you do. 458 | But \LaTeX is no more than a document markup language like 459 | HTML and it is no harder to learn. It gives you the added advantage 460 | that you have a real language for publishing real documents. Most 461 | books are typeset with this technology and a lot of conferences 462 | and Journals require it. If you can learn Clojure, you can learn 463 | \LaTeX. If you're a programmer you will always need to continue 464 | to learn, at least until you retire into management. 465 | 466 | Having used literate programming for years I have collected some key 467 | quotes that might stimulate your interest. 468 | 469 | \quoteme{gray}{yellow}{4.6in} 470 | {\vskip 0.1cm 471 | I believe that the time is ripe for significantly better documentation 472 | of programs, and that we can best achieve this by considering programs 473 | to be works of literature. Hence, my title ``Literate Programming''. 474 | Let us change our traditional attitude to the construction of programs. 475 | Instead of imagining that our main task is to instruct a computer what to 476 | do, let us concentrate on explaining to human beings what we want a 477 | computer to do. 478 | 479 | {\bf --Donald Knuth ``Literate Programming (1984)''}} 480 | 481 | 482 | \quoteme{gray}{yellow}{4.6in} 483 | {\vskip 0.1cm 484 | Step away from the machine. Literate programming has nothing to do with 485 | tools or style. It has very little to do with programming. One of the 486 | hard transitions to literate programming is ``literate thinking''. 487 | 488 | {\bf --Timothy Daly in Lambda the Ultimate (2010)}} 489 | 490 | \quoteme{gray}{yellow}{4.6in} 491 | {\vskip 0.1cm 492 | The effect of this simple shift of emphasis can be so profound as to 493 | change one's whole approach to programming. Under the literate programming 494 | paradigm, the central activity of programming becomes that of conveying 495 | meaning to other intelligent beings rather than merely convincing the 496 | computer to behave in a particular way. It is the difference between 497 | performing and exposing a magic trick. 498 | 499 | {\bf --Ross Williams, FunnelWeb Tutorial Manual}} 500 | 501 | \quoteme{gray}{yellow}{4.6in} 502 | {\vskip 0.1cm 503 | Another thing I've been enjoying lately is literate programming. Amazingly 504 | it turns out to be faster to write a literate program than an ordinary 505 | program because debugging takes almost no time. 506 | 507 | {\bf --Bill Hart, SAGE Mailing list, May 3, 2010}} 508 | 509 | \quoteme{gray}{yellow}{4.6in} 510 | {\vskip 0.1cm 511 | The conversation is much more direct if the Design Concept per se, rather 512 | than derivative representatives or partial details, is the focus. 513 | 514 | {\bf --Fred Brooks, ``The Design of Design''}} 515 | 516 | \quoteme{gray}{yellow}{4.6in} 517 | {\vskip 0.1cm 518 | We are banning the old notion of literate programming that I used when 519 | developing \TeX{}82 because documentation has proven to be too much of 520 | a pain. 521 | 522 | {\bf --Donald Knuth TUG 2010}} 523 | 524 | \quoteme{gray}{yellow}{4.6in} 525 | {\vskip 0.1cm 526 | Once upon a time I took great care to ensure that \TeX{}82 would be truly 527 | archival so that results obtainable today would produce the same output 528 | 50 years from now but that was manifestly foolish. Let's face it, who is 529 | going to care one whit for what I do today after even 5 years have 530 | elapsed, let alone 50. Life is too short to re-read anything anymore 531 | in the internet age. Nothing over 30 months old is trustworthy or 532 | interesting. 533 | 534 | {\bf --Donald Knuth TUG 2010}} 535 | 536 | \mainmatter 537 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 538 | %%% From ideas to implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 539 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 540 | \chapter{From ideas to implementation} 541 | 542 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 543 | %\defsection{} 544 | 545 | \chapter{The clojlisp package} 546 | We are defining a lisp-in-lisp so there will be a significant number 547 | of symbol collisions. We have to be very careful to only import symbols 548 | that do not conflict. 549 | 550 | \begin{chunk}{defpackage clojlisp} 551 | #+:AKCL (make-package "COMMON-LISP" :use '("LISP")) 552 | #+:AKCL (in-package "USER") 553 | #+:SBCL (declaim (sb-ext:muffle-conditions style-warning)) 554 | #+:SBCL (declaim (sb-ext:muffle-conditions warning)) 555 | #+:SBCL (declaim (sb-ext:muffle-conditions sb-ext:compiler-note)) 556 | (make-package "CLOJLISP") 557 | (in-package "CLOJLISP") 558 | 559 | \end{chunk} 560 | 561 | \chapter{Imported functions} 562 | We import some functions from other packages which have useful definitions 563 | or which match the semantics of Clojure. 564 | 565 | The {\tt bye} function can be used to exit the lisp system. 566 | \begin{chunk}{imported functions} 567 | #+AKCL (lisp::defun bye () (si::bye)) 568 | #+SBCL (common-lisp::defun clojlisp::bye () (sb-ext:quit)) 569 | 570 | \end{chunk} 571 | 572 | \chapter{The Reader} 573 | The reader uses the common lisp reader. 574 | 575 | \begin{chunk}{defun read} 576 | (common-lisp::defun 577 | clojlisp::read ( 578 | common-lisp::&optional input-stream eof-error-p eof-value recursive-p) 579 | (common-lisp::case 580 | (common-lisp::peek-char 581 | common-lisp::nil input-stream eof-error-p eof-value recursive-p) 582 | ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) 583 | (common-lisp::print "number") 584 | (common-lisp::terpri) 585 | (common-lisp::read-char)))) 586 | 587 | \end{chunk} 588 | 589 | \chapter{The Evaluator} 590 | The evaluator uses the common lisp evaluator. 591 | \begin{chunk}{defmacro eval} 592 | (common-lisp::defmacro clojlisp::eval (x) `(common-lisp::eval ,x)) 593 | 594 | \end{chunk} 595 | 596 | \chapter{The Printer} 597 | The printer uses the common lisp printer. 598 | \begin{chunk}{defun print} 599 | (common-lisp::defun clojlisp::print (x) (common-lisp::print x)) 600 | 601 | \end{chunk} 602 | 603 | \chapter{The Clojlisp REPL} 604 | By typing 605 | \begin{verbatim} 606 | (load "clojlisp.lisp") 607 | (in-package "CLOJLISP") 608 | (clojlisp) 609 | \end{verbatim} 610 | you have a read-eval-print loop (REPL). The REPL knows almost nothing 611 | about anything so it can be quite painful. You need to qualify symbols 612 | that come from any other package at the moment. A working example is: 613 | \begin{verbatim} 614 | (common-lisp::+ 2 3) 615 | \end{verbatim} 616 | \begin{chunk}{defun repl} 617 | (common-lisp::defun clojlisp::clojlisp () 618 | (common-lisp::loop 619 | (clojlisp::print 620 | (clojlisp::eval 621 | (clojlisp::read))) 622 | (common-lisp::terpri))) 623 | 624 | \end{chunk} 625 | 626 | \chapter{Building ClojLisp} 627 | \label{building} 628 | This is the whole source listing in one file. 629 | If you define a new chunk, add it here. 630 | 631 | \defsection{The env global environment} 632 | \label{globalEnv} 633 | We wrap all of the code in a {\tt let} construct which defines a {\tt env} 634 | variable. This variable is accessible from everywhere. It is intended to 635 | contain ``globally scoped information'' such as the current reader setting. 636 | Default values are kept in the {\tt env} variable. 637 | 638 | The {\tt env} variable is a stack. Managing the {\tt env} as a stack allows 639 | us to temporarily push information that overrides existing information. 640 | 641 | Functions that require temporary bindings can wrap a let around the function 642 | that rebinds {\tt env} with new information cons-ed on the front of the stack. 643 | Leaving the let allows the bindings to pop. 644 | 645 | \defsection{The whole thing} 646 | \begin{chunk}{clojlisp} 647 | 648 | \getchunk{defpackage clojlisp} 649 | \getchunk{imported functions} 650 | (common-lisp::let (env) 651 | 652 | \getchunk{defun read} 653 | \getchunk{defmacro eval} 654 | \getchunk{defun print} 655 | \getchunk{defun repl} 656 | 657 | ) 658 | \end{chunk} 659 | 660 | \defsection{tangle.c} 661 | The tangle program extract pieces of this document and puts them in a file. 662 | Any piece that can be extracted is called a ``chunk''. Each chunk is in a 663 | \LaTeX {\bf chunk} environment. The tangle program expects two arguments, 664 | the name of this file and the chunk to extract as in: 665 | \begin{verbatim} 666 | ./tangle clojure.pamphlet clojlisp 667 | \end{verbatim} 668 | It outputs the chunk to standard output. To be useful, redirect the 669 | output to a file as in: 670 | \begin{verbatim} 671 | ./tangle clojure.pamphlet clojlisp >clojlisp.lisp 672 | \end{verbatim} 673 | 674 | This trivial function walks the document looking for the named chunk. 675 | When it finds it the chunk is printed to standard output. The only 676 | exception is if the chunk contains a {\bf getchunk} markup. This is 677 | used to embed other chunks inline. So tangle will pause the output of 678 | the current chunk, find and print the getchunk reference, and then continue. 679 | Of course, if the getchunk reference contains an embedded getchunk we 680 | recurse into it. This program could be a lot smarter $\ldots$ but why? 681 | 682 | \begin{chunk}{tangle.c} 683 | #include 684 | #include 685 | #include 686 | #include 687 | #include 688 | #include 689 | #include 690 | 691 | #define DEBUG 0 692 | 693 | /* forward reference for the C compiler */ 694 | int getchunk(char *chunkname); 695 | 696 | /* a memory mapped buffer copy of the file */ 697 | char *buffer; 698 | int bufsize; 699 | 700 | /* return the length of the next line */ 701 | int nextline(int i) { 702 | int j; 703 | if (i >= bufsize) return(-1); 704 | for (j=0; ((i+j < bufsize) && (buffer[i+j] != '\n')); j++); 705 | return(j); 706 | } 707 | 708 | /* output the line we need */ 709 | int printline(int i, int length) { 710 | int j; 711 | for (j=0; j>>>"); printline(k,linelen); printf("<<<<\n"); 764 | } 765 | if ((getlen=foundGetchunk(k,linelen)) > 0) { 766 | getname = getChunkname(k,getlen); 767 | getchunk(getname); 768 | free(getname); 769 | k=k+getlen+12l; 770 | } else { 771 | if ((linelen >= 11) && (foundEnd(k) == 1)) { 772 | if (DEBUG) { printf("=================\\end{%s}\n",chunkname); } 773 | return(k+12); 774 | } else { 775 | if (DEBUG==2) { 776 | printf("======== printchunk else %d %d\n",k,linelen); 777 | } 778 | printline(k,linelen); 779 | k=k+linelen+1; 780 | } 781 | }} 782 | if (DEBUG==2) { 783 | printf("=================\\out{%s} %d\n",chunkname,k); 784 | } 785 | return(k); 786 | } 787 | 788 | /* find the named chunk and call printchunk on it */ 789 | int getchunk(char *chunkname) { 790 | int i; 791 | int j; 792 | int linelen; 793 | int chunklen = strlen(chunkname); 794 | for (i=0; ((linelen=nextline(i)) != -1); ) { 795 | if (DEBUG==2) { 796 | printf("----"); printline(i,linelen); printf("----\n"); 797 | } 798 | if ((linelen >= chunklen+15) && (foundchunk(i,chunkname) == 1)) { 799 | if (DEBUG) { 800 | fprintf(stderr,"=================\\getchunk(%s)\n",chunkname); 801 | } 802 | i=printchunk(i,linelen,chunkname); 803 | } else { 804 | i=i+linelen+1; 805 | } 806 | } 807 | if (DEBUG) { 808 | fprintf(stderr,"=================getchunk returned=%d\n",i); 809 | } 810 | return(i); 811 | } 812 | 813 | /* memory map the input file into the global buffer and get the chunk */ 814 | int main(int argc, char *argv[]) { 815 | int fd; 816 | struct stat filestat; 817 | if ((argc < 2) || (argc > 3)) { 818 | perror("Usage: tangle filename chunkname"); 819 | exit(-1); 820 | } 821 | fd = open(argv[1], O_RDONLY); 822 | if (fd == -1) { 823 | perror("Error opening file for reading"); 824 | exit(-2); 825 | } 826 | if (fstat(fd,&filestat) < 0) { 827 | perror("Error getting input file size"); 828 | exit(-3); 829 | } 830 | bufsize = (int)filestat.st_size; 831 | buffer = mmap(0,filestat.st_size,PROT_READ,MAP_SHARED,fd,0); 832 | if (buffer == MAP_FAILED) { 833 | close(fd); 834 | perror("Error reading the file"); 835 | exit(-4); 836 | } 837 | getchunk(argv[2]); 838 | close(fd); 839 | return(0); 840 | } 841 | 842 | \end{chunk} 843 | 844 | \defsection{Makefile} 845 | This book is actually a literate program\cite{Knu84} and can contain 846 | executable source code. In particular, the Makefile for this book 847 | is part of the source of the book and is included below. 848 | 849 | You can extract this chunk with an editor or use the tangle function: 850 | \begin{verbatim} 851 | ./tangle clojlisp.pamphlet Makefile >Makefile 852 | \end{verbatim} 853 | \begin{chunk}{Makefile} 854 | PROJECT=clojlisp 855 | TANGLE=tangle 856 | LATEX=/usr/bin/latex 857 | MAKEINDEX=/usr/bin/makeindex 858 | UUDECODE=uudecode 859 | PDF=dvipdf 860 | 861 | all: 862 | ${TANGLE} ${PROJECT}.pamphlet ${PROJECT} >${PROJECT}.lisp 863 | ${TANGLE} ${PROJECT}.pamphlet clojureIcon.eps.uu >clojureIcon.eps.uu 864 | ${UUDECODE} clojureIcon.eps.uu 865 | ${LATEX} ${PROJECT}.pamphlet 866 | ${MAKEINDEX} ${PROJECT}.idx 867 | ${LATEX} ${PROJECT}.pamphlet 868 | ${PDF} ${PROJECT}.dvi 869 | rm -f ${PROJECT}.aux ${PROJECT}.idx ${PROJECT}.ilg ${PROJECT}.ind 870 | rm -f ${PROJECT}.log ${PROJECT}.out ${PROJECT}.toc ${PROJECT}.aps 871 | rm -f ${PROJECT}.dvi *.eps.uu *~ clojureIcon.eps 872 | 873 | \end{chunk} 874 | 875 | \defsection{The Clojure Icon} 876 | This document uses the Clojure Icon on the front page. 877 | This is a uuencoded, encapsulated postscript version of the icon. 878 | You can recreate the {\bf clojureIcon.eps} file with: 879 | \begin{verbatim} 880 | ./tangle clojlisp.pamphlet clojureIcon.eps.uu >clojureIcon.eps.uu 881 | uudecode clojureIcon.eps.uu 882 | \end{verbatim} 883 | \begin{chunk}{clojureIcon.eps.uu} 884 | begin 644 clojureIcon.eps 885 | M)2%04RU!9&]B92TS+C`@15!31BTS+C`*)25#`I;(#$P,"`P(#`@,3`P(#`@,"!="B4@4W1R:6YGV-U6$T\1D`M2BQ^/@IN+$5&96AO-#1+9T$H+CI*+'X^ 928 | M"FY'8$]>1TID36!`8S9B54HL?CX*;D=@3V!21%A25DT\1D,N2BQ^/@IN1V!/ 929 | M9FAO(BA)9T$H,3M*+'X^"FYC)EA?1U!K4$-$/F8E9$!A)7!41#XA2"%*+'X^ 930 | M"FYC)EAA4DI?53E/;SIS4DTY3$U/3VY<1$=*+'X^"FYC)EAG:'4I*RQH/E$] 931 | M-6<\03%-:#Y1;41*+'X^"FYC)F,Z/4-25S1I.RI"5&DT=%MR8W)>/&UP)28M 932 | M-7X^"FYC)F-<2E9G5EAK4#XL6VM+<$=Q9"(I-&-P6UP_-WX^"FYC)F1-9EPU 933 | M3EAQ(F%P;'$A9$HF9"M!0E9R551U/7X^"F\I06-82R,D<%8A5#D]03TY3BEL 934 | M6$]:."MR;S,K44I(,ED^:"%P22Q1 951 | M9'1S-"$Q,RY6(2Q?2S%*+'X^"FY'8$]08%8V5CMC3%\F.6MJ8R)<7&`\4&0A 952 | M,VMP0R$P4B152BQ^/@IN1V!/*$%B4G%;2BM%6"]R<5I1;VM/-R4G:#UP+7-S-F9M8')R3BE0;D-2839Q/EES?CX*<$%9,&1*1FT]3V--6UQ#;$)Q 963 | M23(A.48H6"%6:2--3SDH7C5R.U%C26XU;UM7<3Y9/'([46)@;C5O7&!Q674G 967 | M?CX*<%QT.6I?(CUL,V%O*2\^;6HW<74[,'X^"G%9<%%*;FU?6U!R5FQL66\X 994 | M7G)6;&Q*;2-6-$MR.UHZ:"$W:"-)2BQ^/@IQ=39:*6\A)C)K*758 1064 | M4B5&;T0]/V]?.F]6:VMT2E-R<75C17,J='X^ 1074 | M"G$^54AA;C]%(R9Q65X_<7!T:F9J8D]94B]. 1090 | M+4U2)R(S56Y>9%]J?CX*<$%9+5YM0DA=+6Y'*B)D<7-S*#=H66PT-&A7/2AO 1091 | M<7!T9'1^/@IP05DM1VTT;EU%9R5B4DUK9&TN*#MU2S)H.V1DTX/4YN65Y*+'X^"F]@(G!.;#TP:E!C2VM+-6-"4#90 1095 | M<"1?;EYM*CXZ.&M(4#`E8TI`:EMQ=39F;&TK;W0A:TA0)"]O 1102 | M*48T?CX*;RE!73YK.R$P-DHC,4).<74V9EQB8EUE7VL[(218;RE&-'X^"F\I 1103 | M06%@2D$U4G!*1R9,-4HL?CX*;RE!865><5LL5%\C(5@E2BQ^/@IO*4%A73U- 1104 | M2%1L/5)U)5]*+'X^"FYC)EA?2D%'7G)$/B%((4HL?CX*;F,F6&1><6TX5EME 1105 | M9D]O2BQ^/@IN8R987#U-6F!N-5`B0$5*+'X^"FY'8$]+1#A4:6%$.W0G8DHL 1106 | M?CX*;D=@3UE;7V\_3EMD8&5D2BQ^/@IN1V!/0C5*;S57-4T^42M*+'X^"FXL 1107 | M149*1#AF=6-$.W0D84HL?CX*;BQ%1EA;8"Q+4%MD8&)C2BQ^/@IN+$5&035+ 1108 | M+$%9-4T^3BI*+'X^"FUF*CU<2D(I+B-*120B3C 1120 | M1%DJ:7(]3GX^"FAU/&`F4&E:0E509CM06THL?CX*:'4\8#]A;%1C+F%L.S18 1121 | M2BQ^/@IH=3Q?;$5O9B5716I&529*+'X^"F@^6U1-8T-4-TE`9G!Q2&-,<"-N 1122 | M2BQ^/@IH/EM44FM+7EXL66QH5F!K4$8D-THL?CX*:#Y;5$I>3TIR13$G.C0B 1123 | M7EMG-%Q*+'X^"F 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define DEBUG 0 10 | 11 | /* forward reference for the C compiler */ 12 | int getchunk(char *chunkname); 13 | 14 | /* a memory mapped buffer copy of the file */ 15 | char *buffer; 16 | int bufsize; 17 | 18 | /* return the length of the next line */ 19 | int nextline(int i) { 20 | int j; 21 | if (i >= bufsize) return(-1); 22 | for (j=0; ((i+j < bufsize) && (buffer[i+j] != '\n')); j++); 23 | return(j); 24 | } 25 | 26 | /* output the line we need */ 27 | int printline(int i, int length) { 28 | int j; 29 | for (j=0; j>>>"); printline(k,linelen); printf("<<<<\n"); 82 | } 83 | if ((getlen=foundGetchunk(k,linelen)) > 0) { 84 | getname = getChunkname(k,getlen); 85 | getchunk(getname); 86 | free(getname); 87 | k=k+getlen+12l; 88 | } else { 89 | if ((linelen >= 11) && (foundEnd(k) == 1)) { 90 | if (DEBUG) { printf("=================\\end{%s}\n",chunkname); } 91 | return(k+12); 92 | } else { 93 | if (DEBUG==2) { 94 | printf("======== printchunk else %d %d\n",k,linelen); 95 | } 96 | printline(k,linelen); 97 | k=k+linelen+1; 98 | } 99 | }} 100 | if (DEBUG==2) { 101 | printf("=================\\out{%s} %d\n",chunkname,k); 102 | } 103 | return(k); 104 | } 105 | 106 | /* find the named chunk and call printchunk on it */ 107 | int getchunk(char *chunkname) { 108 | int i; 109 | int j; 110 | int linelen; 111 | int chunklen = strlen(chunkname); 112 | for (i=0; ((linelen=nextline(i)) != -1); ) { 113 | if (DEBUG==2) { 114 | printf("----"); printline(i,linelen); printf("----\n"); 115 | } 116 | if ((linelen >= chunklen+15) && (foundchunk(i,chunkname) == 1)) { 117 | if (DEBUG) { 118 | fprintf(stderr,"=================\\getchunk(%s)\n",chunkname); 119 | } 120 | i=printchunk(i,linelen,chunkname); 121 | } else { 122 | i=i+linelen+1; 123 | } 124 | } 125 | if (DEBUG) { 126 | fprintf(stderr,"=================getchunk returned=%d\n",i); 127 | } 128 | return(i); 129 | } 130 | 131 | /* memory map the input file into the global buffer and get the chunk */ 132 | int main(int argc, char *argv[]) { 133 | int fd; 134 | struct stat filestat; 135 | if ((argc < 2) || (argc > 3)) { 136 | perror("Usage: tangle filename chunkname"); 137 | exit(-1); 138 | } 139 | fd = open(argv[1], O_RDONLY); 140 | if (fd == -1) { 141 | perror("Error opening file for reading"); 142 | exit(-2); 143 | } 144 | if (fstat(fd,&filestat) < 0) { 145 | perror("Error getting input file size"); 146 | exit(-3); 147 | } 148 | bufsize = (int)filestat.st_size; 149 | buffer = mmap(0,filestat.st_size,PROT_READ,MAP_SHARED,fd,0); 150 | if (buffer == MAP_FAILED) { 151 | close(fd); 152 | perror("Error reading the file"); 153 | exit(-4); 154 | } 155 | getchunk(argv[2]); 156 | close(fd); 157 | return(0); 158 | } 159 | 160 | --------------------------------------------------------------------------------