]> git.lyx.org Git - lyx.git/blobdiff - lib/examples/Literate.lyx
another translation from Hartmut
[lyx.git] / lib / examples / Literate.lyx
index 47db33766a1c829d19bdb7035ceb1ed603bfc7da..80a72f97a7f5131f1742f17006d07a2cd819ea41 100644 (file)
@@ -1,17 +1,19 @@
-#This file was created by <wiensk> Tue Feb 23 22:25:52 1999
-#LyX 1.0 (C) 1995-1999 Matthias Ettrich and the LyX Team
-\lyxformat 2.15
+#LyX 1.4.0cvs created this file. For more info see http://www.lyx.org/
+\lyxformat 243
+\begin_document
+\begin_header
 \textclass literate-article
-\language default
+\language english
 \inputencoding default
 \fontscheme default
 \graphics default
 \paperfontsize default
-\spacing single 
-\papersize Default
-\paperpackage a4
-\use_geometry 0
+\spacing single
+\papersize default
+\use_geometry false
 \use_amsmath 0
+\cite_engine basic
+\use_bibtopic false
 \paperorientation portrait
 \secnumdepth 3
 \tocdepth 3
 \papercolumns 1
 \papersides 1
 \paperpagestyle default
+\tracking_changes false
+\output_changes true
+\end_header
 
-\layout Title
+\begin_body
 
-LyX and Literate Programming
-\newline 
-An example program
-\layout Author
-
-Edmar Wienskoski Jr.
-\newline 
-edmar-w-jr@technologist.com
-\layout Date
-
-
-\latex latex 
-
-\backslash 
-today
-\layout Standard
-
-
-\begin_inset LatexCommand \tableofcontents
-
-\end_inset 
-
-
-\layout Section
-
-Introduction
-\layout Standard
-
-After typesetting a document, LyX scans the LaTeX log file looking for errors.
- For each error found, the line number is obtained and a error box is displayed
- in the LyX screen at that position.
-\layout Standard
-
-To use this feature to view compilation errors while working with literate
- documents, we need a program that filters the compilation errors and puts
- them in a format suitable for LyX reading it.
-\layout Standard
-
-In this document we present a filter that recognizes compilation error messages
- from noweb, gnu C, and the IBM C compiler (xlc).
-\layout Standard
-
-The filter is required to read from standard input, parse for error messages
- and copy the error messages to the standard output.
- During the output process, the filter must present the error messages in a
- format that LyX can interpret, currently, the LaTeX error message format.
- Of course, nothing will prevent future LyX releases from being able to read
- other formats as well (like gcc error messages for example).
- This mechanism is necessary to fully explore the literate programming
- tool's capabilities.
-\layout Section
-
-Algorithm
-\layout Scrap
-
-<<Function bodies>>=
-\newline 
-int
-\newline 
-main (int argc, char **argv)
-\newline 
-{
-\newline 
-
-\protected_separator 
- if (argc == 2) {
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- switch (argv[1][0]) {
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- case 'n':
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- <<Scan input for noweb error messages>>
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- break;
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- case 'x':
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- <<Scan input for xlc error messages>>
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- break;
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- case 'a':
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-<<AIX system using both noweb and xlc>>
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- break;
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- case 's':
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- case 'b':
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- <<Solaris and Linux systems using both noweb and gcc>>
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- break;
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- case 'g':
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- default:
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- <<Scan input for gcc error messages>>
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- break;
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- }
-\newline 
-
-\protected_separator 
- } else {
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- <<Scan input for gcc error messages>>
-\newline 
-
-\protected_separator 
- }
-\newline 
-}
-\newline 
-@
-\layout Scrap
-
-<<Function prototypes>>=
-\newline 
-int main (int argc, char **argv);
-\newline 
-@
-\layout Section
-
-Data Structures
-\layout Standard
-
-We resort to some global variables to allow access from several different
- routines.
- These are the buffer and related pointers used during the parse of the
- input.
-\layout Scrap
-
-<<Global variables>>=
-\newline 
-char
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- buffer[200][200];
-\newline 
-int
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- last_buf_line;
-\newline 
-int
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- last_err_line;
-\newline 
-int
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- err_line;
-\newline 
-@ 
-\layout Section
-
-The output format
-\layout Standard
-
-The output format mimics the LaTeX error messages format.
- This function prints a number of lines residing in the global variable
-\family typewriter 
-buffer
-\family default 
-, a program name and line number.
- There is no special requirement on the input strings, they can be anything.
-\layout Scrap
-
-<<Function bodies>>=
-\newline 
-void
-\newline 
-output_error (int buf_size, int error_line, char *tool)
-\newline 
-{
-\newline 
-
-\protected_separator 
- int
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- i;
-\newline 
-
-\protected_separator 
-
-\newline 
-
-\protected_separator 
- fprintf(stdout, "! Build Error: ==> %s ==>
-\backslash 
-n", tool);
-\newline 
-
-\protected_separator 
- for (i=0; i<buf_size; i++)
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- fprintf(stdout, "%s", buffer[i]);
-\newline 
-
-\protected_separator 
- fprintf(stdout, " ...
-\backslash 
-n
-\backslash 
-nl.%d ...
-\backslash 
-n
-\backslash 
-n", error_line);
-\newline 
-}
-\newline 
-@
-\layout Scrap
-
-<<Function prototypes>>=
-\newline 
-void output_error (int buf_size, int error_line, char *tool);
-\newline 
-@
-\layout Section
-
-Functions Implementation
-\layout Standard
-
-Both noweave and notangle routines, always output one single line for each
- error found, thus to scan the buffer for noweb error messages is enough
- to exam one input line at a time.
- Note that the noweb software does not provide a line error number, so all
- errors boxes related to noweb messages will be displayed at the beginning
- of the file.
-\layout Scrap
-
-<<Scan input for noweb error messages>>=
-\newline 
-{
-\newline 
-
-\protected_separator 
- last_buf_line = 0;
-\newline 
-
-\protected_separator 
- while (fgets(buffer[0], 200, stdin)) {
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- if (noweb_try(0))
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- output_error(1, 0, "noweb");
-\newline 
-
-\protected_separator 
- }
-\newline 
-}
-\newline 
-@
-\layout Standard
-
-The examination itself is very inefficient.
- Unfortunately noweb doesn't have any characteristic that would help to
- identify one of its error messages.
- The solution is to collect all possible output messages in an array of
- strings, and turn the examination process into a linear search in this
- array.
-\layout Scrap
-
-<<Global variables>>=
-\newline 
-char *noweb_msgs[] = {
-\newline 
-
-\protected_separator 
- "couldn't open file",
-\newline 
-
-\protected_separator 
- "couldn't open temporary file",
-\newline 
-
-\protected_separator 
- "error writing temporary file",
-\newline 
-
-\protected_separator 
- "ill-formed option",
-\newline 
-
-\protected_separator 
- "unknown option",
-\newline 
-
-\protected_separator 
- "Bad format sequence",
-\newline 
-
-\protected_separator 
- "Can't open output file",
-\newline 
-
-\protected_separator 
- "Can't open temporary file",
-\newline 
-
-\protected_separator 
- "Capacity exceeded:",
-\newline 
-
-\protected_separator 
- "Ignoring unknown option -",
-\newline 
-
-\protected_separator 
- "This can't happen:",
-\newline 
-
-\protected_separator 
- "non-numeric line number in" 
-\newline 
-};
-\newline 
-@
-\layout Standard
-
-A noweb error message can be any string that contains a matching pair of
- < <
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-> >, or any of the above strings.
-\layout Scrap
-
-<<Function bodies>>=
-\newline 
-int
-\newline 
-noweb_try (int buf_line)
-\newline 
-{
-\newline 
-
-\protected_separator 
- char
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- *s, *b;
-\newline 
-
-\protected_separator 
- int
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- i;
-\newline 
-
-\protected_separator 
-
-\newline 
-
-\protected_separator 
- b = buffer[buf_line];
-\newline 
-
-\protected_separator 
- s = strstr(b, "<<");
-\newline 
-
-\protected_separator 
- if (s != NULL) {
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- s = strstr(s+2, ">>");
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- if (s != NULL)
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- return 1;
-\newline 
-
-\protected_separator 
- } else {
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- for (i=0; i<12; i++) {
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- s = strstr (b, noweb_msgs[i]);
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- if (s != NULL)
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-break;
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- }
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- if (s != NULL)
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- return 1;
-\newline 
-
-\protected_separator 
- }
-\newline 
-
-\protected_separator 
- return 0;
-\newline 
-}
-\newline 
-@
-\layout Scrap
-
-<<Function prototypes>>=
-\newline 
-int noweb_try (int buf_line);
-\newline 
-@
-\layout Standard
-
-The xlc compiler always outputs one single line for each error found, thus
- to scan the buffer for xlc error messages it is enough to exam one input
- line at a time.
-\layout Scrap
-
-<<Scan input for xlc error messages>>=
-\protected_separator 
-
-\newline 
-{
-\newline 
-
-\protected_separator 
- last_buf_line = 0;
-\newline 
-
-\protected_separator 
- while (fgets(buffer[last_buf_line], 200, stdin)) {
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- if (xlc_try(0))
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- output_error(1, err_line, "xlc");
-\newline 
-
-\protected_separator 
- }
-\newline 
-}
-\newline 
-@
-\layout Standard
-
-A xlc error message is easy to identify.
- Every error message starts with a quoted string with no spaces, a comma,
- a space, the word 
-\begin_inset Quotes eld
-\end_inset 
-
-line
-\begin_inset Quotes erd
-\end_inset 
-
-, a space, and some variable text.
- The following routine tests if a given buffer line matches this criteria:
-\layout Scrap
-
-<<Function bodies>>=
-\newline 
-int 
-\newline 
-xlc_try (int buf_line)
-\newline 
-{
-\newline 
-
-\protected_separator 
- char
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- *s, *t;
-\newline 
-
-\protected_separator 
-
-\newline 
-
-\protected_separator 
- t = buffer[buf_line];
-\newline 
-
-\protected_separator 
- s = t+1;
-\newline 
-
-\protected_separator 
- while (*s != '"' && *s != ' ' && *s != '
-\backslash 
-0')
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- s++;
-\newline 
-
-\protected_separator 
- if (*t != '"' || *s != '"' || strncmp(s+1, ", line ", 7) != 0)
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- return 0;
-\newline 
-
-\protected_separator 
- s += 8;
-\newline 
-
-\protected_separator 
- err_line = atoi(s);
-\newline 
-
-\protected_separator 
- return 1;
-\newline 
-}
-\newline 
-@
-\layout Scrap
-
-<<Function prototypes>>=
-\newline 
-int xlc_try (int buf_line);
-\newline 
-@
-\layout Standard
-
-The gcc compiler error messages are more complicated to scan.
- Each error can span more than one line in the buffer.
- The good news is that every buffer line on each error has the same pattern,
- and share the same line number.
- Thus the strategy will be to accumulate lines in the buffer while the reported
- line number is still the same.
- At the time they differ, all the accumulated lines, except the last one,
- will belong to one single error message, which now can be output-ed to
- LyX.
-\layout Standard
-
-Every gcc error message contains a string with no space followed by a 
-\begin_inset Quotes eld
-\end_inset 
-
-:
-\begin_inset Quotes eld
-\end_inset 
-
-.
- If the next character is a space, then this line is a header of a error
- message and the next line will detail the line number of the source code
- where the error was found.
- Otherwise, the next thing is a integer number followed by another 
-\begin_inset Quotes eld
-\end_inset 
-
-:
-\begin_inset Quotes eld
-\end_inset 
-
-.
-\layout Scrap
-
-<<Scan input for gcc error messages>>=
-\newline 
-{
-\newline 
-
-\protected_separator 
- char
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- *s, *t;
-\newline 
-
-\protected_separator 
-
-\newline 
-
-\protected_separator 
- last_buf_line = 0;
-\newline 
-
-\protected_separator 
- while (fgets(buffer[last_buf_line], 200, stdin)) {
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- /****** Skip lines until I find an error */
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- s = strpbrk(buffer[last_buf_line], " :");
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- if (s == NULL || *s == ' ')
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- continue; /* No gcc error found here */
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- do {
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-<<gcc error message criteria is to find a "...:999:" or a "...: ">>
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- /****** OK It is an error message, get line number */
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- err_line = atoi(s+1);
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- if (last_err_line == 0 || last_err_line == err_line) {
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-last_err_line = err_line;
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-continue; /* It's either a header or a continuation, don't output yet */
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- }
-\newline 
-
-\protected_separator 
-\protected_separator 
-\protected_separator 
- /****** Completed the scan of one error message, output it to LyX */
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- discharge_buffer(1);
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- break;
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- } while (fgets(buffer[last_buf_line], 200, stdin));
-\newline 
-
-\protected_separator 
- }
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-/****** EOF completes the scan of whatever was being scanned */
-\newline 
-
-\protected_separator 
- discharge_buffer(0);
-\newline 
-}
-\newline 
-@
-\layout Scrap
-
-<<gcc error message criteria is to find a "...:999:" or a "...: ">>=
-\newline 
-/****** Search first ":" in the error number */
-\newline 
-s = strpbrk(buffer[last_buf_line], " :");
-\newline 
-last_buf_line++;
-\newline 
-if (s == NULL || *s == ' ') 
-\newline 
-
-\protected_separator 
- <<No gcc error found here, but it might terminate the scanning of a previous
- one>>
-\newline 
-/****** Search second ":" in the error number */
-\newline 
-t = strpbrk(s+1, " :");
-\newline 
-if (t == NULL || *t == ' ')
-\newline 
-
-\protected_separator 
- <<No gcc error found here, but it might terminate the scanning of a previous
- one>>
-\newline 
-/****** Verify if is all digits between ":" */
-\newline 
-if (t != s+1+strspn(s+1, "0123456789")) 
-\newline 
-
-\protected_separator 
- <<No gcc error found here, but it might terminate the scanning of a previous
- one>>
-\newline 
-@
-\layout Scrap
-
-<<No gcc error found here, but it might terminate the scanning of a previous
- one>>=
-\newline 
-{
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-err_line = 0;
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-discharge_buffer(1);
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-continue;
-\newline 
-}
-\newline 
-@
-\layout Standard
-
-As we mentioned, when the scan of one gcc error message is completed everything
- in the buffer except the last line is one single error message.
- But if the scan terminates with a EOF or through finding one line that
- does not match the gcc error message criteria, then there is no 
-\begin_inset Quotes eld
-\end_inset 
-
-last line
-\begin_inset Quotes erd
-\end_inset 
-
- in the buffer to be concerned with.
- In those cases we empty the buffer completely.
-\layout Scrap
-
-<<Function bodies>>=
-\newline 
-void
-\newline 
-discharge_buffer (int save_last)
-\newline 
-{
-\newline 
+\begin_layout Title
 
-\protected_separator 
- if (last_err_line != 0) {
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- if (save_last != 0) {
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
+LyX and Literate Programming
+\newline
+An example program
+\end_layout
 
-\protected_separator 
- output_error(last_buf_line-1, last_err_line, "gcc");
-\newline 
+\begin_layout Author
 
-\protected_separator 
+Edmar Wienskoski Jr.
+\newline
+edmar-w-jr@technologist.com
+\begin_inset Foot
+status collapsed
 
-\protected_separator 
+\begin_layout Standard
 
-\protected_separator 
+Modified by Bernard Michael Hurley bernardh@westherts.ac.uk ---- Don't blame
+ Edmar for any errors that have crept in!
+\end_layout
 
-\protected_separator 
+\end_inset
 
-\protected_separator 
- strcpy (buffer[0], buffer[last_buf_line-1]);
-\newline 
 
-\protected_separator 
+\end_layout
 
-\protected_separator 
+\begin_layout Abstract
 
-\protected_separator 
 
-\protected_separator 
+\series bold
+Note:
+\series default
+ This example program is provided for educational use only.
+ The functionality in this C program has been superceded by the equivalent
+ Python code in 
+\emph on
+examples/listerrors.lyx
+\emph default
+ which should be installed in the LyX scripts directory.
+\end_layout
 
-\protected_separator 
- last_err_line = err_line;
-\newline 
+\begin_layout Date
 
-\protected_separator 
 
-\protected_separator 
+\begin_inset ERT
+status collapsed
 
-\protected_separator 
+\begin_layout Standard
 
-\protected_separator 
+\backslash
+today
+\end_layout
 
-\protected_separator 
- last_buf_line = 1;
-\newline 
+\end_inset
 
-\protected_separator 
 
-\protected_separator 
+\end_layout
 
-\protected_separator 
- } else {
-\newline 
+\begin_layout Standard
 
-\protected_separator 
 
-\protected_separator 
+\begin_inset LatexCommand \tableofcontents{}
 
-\protected_separator 
+\end_inset
 
-\protected_separator 
 
-\protected_separator 
- output_error (last_buf_line, last_err_line, "gcc");
-\newline 
+\end_layout
 
-\protected_separator 
+\begin_layout Section
 
-\protected_separator 
+Introduction
+\end_layout
 
-\protected_separator 
+\begin_layout Standard
 
-\protected_separator 
+After typesetting a document, LyX scans the LaTeX log file looking for errors.
+ For each error found, the line number is obtained and a error box is displayed
+ in the LyX screen at that position.
+\end_layout
 
-\protected_separator 
- last_err_line = 0;
-\newline 
+\begin_layout Standard
 
-\protected_separator 
+To use this feature to view compilation errors while working with literate
+ documents, we need a program that filters the compilation errors and puts
+ them in a format suitable for LyX reading it.
+\end_layout
 
-\protected_separator 
+\begin_layout Standard
 
-\protected_separator 
+In this document we present a filter that recognizes compilation error messages
+ from noweb, gnu C, and the IBM C compiler (xlc).
+\end_layout
 
-\protected_separator 
+\begin_layout Standard
 
-\protected_separator 
- last_buf_line = 0;
-\newline 
+The filter is required to read from standard input, parse for error messages
+ and copy the error messages to the standard output.
+ During the output process, the filter must present the error messages in
+ a format that LyX can interpret, currently, the LaTeX error message format.
+ Of course, nothing will prevent future LyX releases from being able to
+ read other formats as well (like gcc error messages for example).
+ This mechanism is necessary to fully explore the literate programming tool's
+ capabilities.
+\end_layout
 
-\protected_separator 
+\begin_layout Section
 
-\protected_separator 
+Algorithm
+\end_layout
 
-\protected_separator 
- }
-\newline 
+\begin_layout Scrap
 
-\protected_separator 
- }
-\newline 
+<<Function bodies>>=
+\newline
+int
+\newline
+main (int argc, char **argv)
+\newline
+{
+\newline
+  if (argc == 2) {
+\newline
+    switch (argv[1][0]) {
+\newline
+    case 'n':
+\newline
+      <<Scan input for noweb error messages>>
+\newline
+      break;
+\newline
+    case 'x':
+\newline
+      <<Scan input for xlc error messages>>
+\newline
+      break;
+\newline
+    case 'a':
+\newline
+      <<AIX system using both noweb and xlc>>
+\newline
+      break;
+\newline
+    case 's':
+\newline
+    case 'b':
+\newline
+      <<Solaris and Linux systems using both noweb and gcc>>
+\newline
+      break;
+\newline
+    case 'g':
+\newline
+    default:
+\newline
+      <<Scan input for gcc error messages>>
+\newline
+      break;
+\newline
+    }
+\newline
+  } else {
+\newline
+    <<Scan input for gcc error messages>>
+\newline
+  }
+\newline
 }
-\newline 
+\newline
 @
-\layout Scrap
+\end_layout
+
+\begin_layout Scrap
 
 <<Function prototypes>>=
-\newline 
-void discharge_buffer (int save_last);
-\newline 
+\newline
+int main (int argc, char **argv);
+\newline
 @
-\layout Standard
+\end_layout
 
-To combine the scan of noweb error messages and xlc error messages is very
- simple.
- We just try each one for every input line:
-\layout Scrap
-
-<<AIX system using both noweb and xlc>>=
-\newline 
-{
-\newline 
-
-\protected_separator 
- last_buf_line = 0;
-\newline 
-
-\protected_separator 
- while (fgets(buffer[0], 200, stdin)) {
-\newline 
+\begin_layout Section
 
-\protected_separator 
-
-\protected_separator 
+Data Structures
+\end_layout
 
-\protected_separator 
- if (noweb_try(0))
-\newline 
+\begin_layout Standard
 
-\protected_separator 
+We resort to some global variables to allow access from several different
+ routines.
+ These are the buffer and related pointers used during the parse of the
+ input.
+\end_layout
 
-\protected_separator 
+\begin_layout Scrap
 
-\protected_separator 
+<<Global variables>>=
+\newline
+char    buffer[200][200];
+\newline
+int     last_buf_line;
+\newline
+int     last_err_line;
+\newline
+int     err_line;
+\newline
+@ 
+\end_layout
 
-\protected_separator 
+\begin_layout Section
 
-\protected_separator 
- output_error(1, 0, "noweb");
-\newline 
+The output format
+\end_layout
 
-\protected_separator 
+\begin_layout Standard
 
-\protected_separator 
+The output format mimics the TeX error messages format.
+ This function prints a number of lines residing in the global variable
+\family typewriter
+buffer
+\family default
+, a program name and line number.
+ There is no special requirement on the input strings, they can be anything.
+\begin_inset Foot
+status collapsed
 
-\protected_separator 
- else if (xlc_try(0))
-\newline 
+\begin_layout Standard
 
-\protected_separator 
+This function has been slightly changed from EW's original to make scanning
+ a bit easier with LaTeX::scanLogFile().
+ The test has been added because LyX can crash if empty lines are allowed
+ here --- I can't figure out why! --- BMH
+\end_layout
 
-\protected_separator 
+\end_inset
 
-\protected_separator 
 
-\protected_separator 
+\end_layout
 
-\protected_separator 
- output_error(1, err_line, "xlc");
-\newline 
+\begin_layout Scrap
 
-\protected_separator 
- }
-\newline 
+<<Function bodies>>=
+\newline
+void
+\newline
+output_error (int buf_size, int error_line, char *tool)
+\newline
+{
+\newline
+  int     i;
+\newline
+\newline
+  fprintf(stdout, "! Build Error: ==> %s ==>
+\backslash
+n", tool);
+\newline
+  fprintf(stdout, " ...
+\backslash
+n
+\backslash
+nl.%d ...
+\backslash
+n", error_line);
+\newline
+\newline
+  for (i=0; i<buf_size; i++)
+\newline
+    if (strlen(buffer[i]) != 0)
+\newline
+      fprintf(stdout, "%s", buffer[i]);
+\newline
+\newline
+  fprintf(stdout, "
+\backslash
+n");
+\newline
 }
-\newline 
+\newline
 @
-\layout Standard
-
-To combine the scan of noweb error messages and gcc error messages is simple
- if we realize that it is not possible to find a noweb error message
- in the middle of a gcc error message.
- So we just repeat the gcc procedure and test for noweb error messages in
- the beginning of the scan:
-\layout Scrap
-
-<<Solaris and Linux systems using both noweb and gcc>>=
-\newline 
-{
-\newline 
-
-\protected_separator 
- char
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- *s, *t;
-\newline 
-
-\protected_separator 
-
-\newline 
-
-\protected_separator 
- last_buf_line = 0;
-\newline 
-
-\protected_separator 
- while (fgets(buffer[last_buf_line], 200, stdin)) {
-\newline 
-
-\protected_separator 
+\end_layout
 
-\protected_separator 
+\begin_layout Scrap
 
-\protected_separator 
- /****** Skip lines until I find an error */
-\newline 
-
-\protected_separator 
+<<Function prototypes>>=
+\newline
+void output_error (int buf_size, int error_line, char *tool);
+\newline
+@
+\end_layout
 
-\protected_separator 
+\begin_layout Section
 
-\protected_separator 
- if (last_buf_line == 0 && noweb_try(0)) {
-\newline 
+Functions Implementation
+\end_layout
 
-\protected_separator 
+\begin_layout Standard
 
-\protected_separator 
+Both noweave and notangle routines, always output one single line for each
+ error found, thus to scan the buffer for noweb error messages is enough
+ to exam one input line at a time.
+ Note that the noweb software does not provide a line error number, so all
+ errors boxes related to noweb messages will be displayed at the beginning
+ of the file.
+\end_layout
 
-\protected_separator 
+\begin_layout Scrap
 
-\protected_separator 
+<<Scan input for noweb error messages>>=
+\newline
+{
+\newline
+  last_buf_line = 0;
+\newline
+  while (fgets(buffer[0], 200, stdin)) {
+\newline
+    if (noweb_try(0))
+\newline
+      output_error(1, err_line, "noweb");
+\newline
+  }
+\newline
+}
+\newline
+@
+\end_layout
 
-\protected_separator 
- output_error(1, 0, "noweb");
-\newline 
+\begin_layout Standard
 
-\protected_separator 
+The examination itself is very inefficient.
+ Unfortunately noweb doesn't have any characteristic that would help to
+ identify one of its error messages.
+ The solution is to collect all possible output messages in an array of
+ strings, and turn the examination process into a linear search in this
+ array.
+\end_layout
 
-\protected_separator 
+\begin_layout Scrap
 
-\protected_separator 
+<<Global variables>>=
+\newline
+char *noweb_msgs[] = {
+\newline
+  "couldn't open file",
+\newline
+  "couldn't open temporary file",
+\newline
+  "error writing temporary file",
+\newline
+  "ill-formed option",
+\newline
+  "unknown option",
+\newline
+  "Bad format sequence",
+\newline
+  "Can't open output file",
+\newline
+  "Can't open temporary file",
+\newline
+  "Capacity exceeded:",
+\newline
+  "Ignoring unknown option -",
+\newline
+  "This can't happen:",
+\newline
+  "non-numeric line number in"
+\newline
+};
+\newline
 
-\protected_separator 
+\newline
+char *noweb_msgs_mimic_gcc[] = {
+\newline
+  ": unescaped << in documentation chunk"
+\newline
+};
+\newline
+@
+\end_layout
 
-\protected_separator 
- continue;
-\newline 
+\begin_layout Standard
 
-\protected_separator 
+A noweb error message can be any string that contains a matching pair of
+ < <\InsetSpace ~
+\InsetSpace ~
+\InsetSpace ~
+> >, or any of the above strings
+\end_layout
 
-\protected_separator 
+\begin_layout Scrap
 
-\protected_separator 
- }
-\newline 
+<<Function bodies>>=
+\newline
+int
+\newline
+noweb_try (int buf_line)
+\newline
+{
+\newline
+  char    *s, *t, *b;
+\newline
+  int     i; 
+\newline
+
+\newline
+  b = buffer[buf_line];
+\newline
+  err_line = 0;
+\newline
+
+\newline
+  for (i=0; i<1; i++) {
+\newline
+      s = (char *)strstr (b, noweb_msgs_mimic_gcc[i]);
+\newline
+      if (s != NULL) {
+\newline
+        t = (char *)strchr(buffer[buf_line], ':');
+\newline
+        err_line = atoi(t+1);
+\newline
+        t = buffer[buf_line];
+\newline
+        ++s;
+\newline
+        while (*(t++) = *(s++));
+\newline
+        return 1;
+\newline
+      }
+\newline
+  }
+\newline
+  s = (char *)strstr(b, "<<");
+\newline
+  if (s != NULL) {
+\newline
+    s = (char *)strstr(s+2, ">>");
+\newline
+    if (s != NULL) {
+\newline
+      return 1;
+\newline
+    }
+\newline
+  } else { 
+\newline
+     for (i = 0; i < 12; ++i) {
+\newline
+        s = (char *)strstr (b, noweb_msgs[i]);
+\newline
+        if (s != NULL) {
+\newline
+           return 1;
+\newline
+        }
+\newline
+    }
+\newline
+  }
+\newline
+  return 0;
+\newline
+}
+\newline
+@
+\end_layout
 
-\protected_separator 
+\begin_layout Scrap
 
-\protected_separator 
+<<Function prototypes>>=
+\newline
+int noweb_try (int buf_line);
+\newline
+@
+\end_layout
 
-\protected_separator 
- s = strpbrk(buffer[last_buf_line], " :");
-\newline 
+\begin_layout Standard
 
-\protected_separator 
+The xlc compiler always outputs one single line for each error found, thus
+ to scan the buffer for xlc error messages it is enough to exam one input
+ line at a time.
+\end_layout
 
-\protected_separator 
+\begin_layout Scrap
 
-\protected_separator 
- if (s == NULL || *s == ' ')
-\newline 
+<<Scan input for xlc error messages>>= 
+\newline
+{
+\newline
+  last_buf_line = 0;
+\newline
+  while (fgets(buffer[last_buf_line], 200, stdin)) {
+\newline
+    if (xlc_try(0))
+\newline
+      output_error(1, err_line, "xlc");
+\newline
+  }
+\newline
+}
+\newline
+@
+\end_layout
 
-\protected_separator 
+\begin_layout Standard
 
-\protected_separator 
+A xlc error message is easy to identify.
+ Every error message starts with a quoted string with no spaces, a comma,
+ a space, the word 
+\begin_inset Quotes eld
+\end_inset
 
-\protected_separator 
+line
+\begin_inset Quotes erd
+\end_inset
 
-\protected_separator 
+, a space, and some variable text.
+ The following routine tests if a given buffer line matches this criteria:
+\end_layout
 
-\protected_separator 
- continue; /* No gcc error found here */
-\newline 
+\begin_layout Scrap
 
-\protected_separator 
+<<Function bodies>>=
+\newline
+int 
+\newline
+xlc_try (int buf_line)
+\newline
+{
+\newline
+  char    *s, *t;
+\newline
+\newline
+  t = buffer[buf_line];
+\newline
+  s = t+1;
+\newline
+  while (*s != '"' && *s != ' ' && *s != '
+\backslash
+0')
+\newline
+    s++;
+\newline
+  if (*t != '"' || *s != '"' || strncmp(s+1, ", line ", 7) != 0)
+\newline
+    return 0;
+\newline
+  s += 8;
+\newline
+  err_line = atoi(s);
+\newline
+  return 1;
+\newline
+}
+\newline
+@
+\end_layout
 
-\protected_separator 
+\begin_layout Scrap
 
-\protected_separator 
- do {
-\newline 
+<<Function prototypes>>=
+\newline
+int xlc_try (int buf_line);
+\newline
+@
+\end_layout
 
-\protected_separator 
+\begin_layout Standard
 
-\protected_separator 
+The gcc compiler error messages are more complicated to scan.
+ Each error can span more than one line in the buffer.
+ The good news is that every buffer line on each error has the same pattern,
+ and share the same line number.
+ Thus the strategy will be to accumulate lines in the buffer while the reported
+ line number is still the same.
+ At the time they differ, all the accumulated lines, except the last one,
+ will belong to one single error message, which now can be output-ed to
+ LyX.
+\end_layout
 
-\protected_separator 
+\begin_layout Standard
 
-\protected_separator 
+Every gcc error message contains a string with no space followed by a 
+\begin_inset Quotes eld
+\end_inset
 
-\protected_separator 
+:
+\begin_inset Quotes eld
+\end_inset
 
-\protected_separator 
-<<gcc error message criteria is to find a "...:999:" or a "...: ">>
-\newline 
+.
+ If the next character is a space, then this line is a header of a error
+ message and the next line will detail the line number of the source code
+ where the error was found.
+ Otherwise, the next thing is a integer number followed by another 
+\begin_inset Quotes eld
+\end_inset
 
-\protected_separator 
+:
+\begin_inset Quotes eld
+\end_inset
 
-\protected_separator 
+.
+\end_layout
 
-\protected_separator 
+\begin_layout Scrap
 
-\protected_separator 
+<<Scan input for gcc error messages>>=
+\newline
+{
+\newline
+  char    *s, *t;
+\newline
+\newline
+  last_buf_line = 0;
+\newline
+  while (fgets(buffer[last_buf_line], 200, stdin)) {
+\newline
+    /****** Skip lines until I find an error */
+\newline
+    s = (char *)strpbrk(buffer[last_buf_line], " :");
+\newline
+    if (s == NULL || *s == ' ')
+\newline
+      continue; /* No gcc error found here */
+\newline
+    do {
+\newline
+      <<gcc error message criteria is to find a "...:999:" or a "...: ">>
+\newline
+      /****** OK It is an error message, get line number */
+\newline
+      err_line = atoi(s+1);
+\newline
+      if (last_err_line == 0 || last_err_line == err_line) {
+\newline
+        last_err_line = err_line;
+\newline
+        continue; /* It's either a header or a continuation, don't output
+ yet */
+\newline
+      }
+\newline
+      /****** Completed the scan of one error message, output it to LyX
+ */
+\newline
+      discharge_buffer(1);
+\newline
+      break;
+\newline
+    } while (fgets(buffer[last_buf_line], 200, stdin));
+\newline
+  }
+\newline
+  /****** EOF completes the scan of whatever was being scanned */
+\newline
+  discharge_buffer(0);
+\newline
+}
+\newline
+@
+\end_layout
 
-\protected_separator 
- /****** OK It is an error, get line number */
-\newline 
+\begin_layout Scrap
 
-\protected_separator 
+<<gcc error message criteria is to find a "...:999:" or a "...: ">>=
+\newline
+/****** Search first ":" in the error number */
+\newline
+s = (char *)strpbrk(buffer[last_buf_line], " :");
+\newline
+last_buf_line++;
+\newline
+if (s == NULL || *s == ' ') 
+\newline
+  <<No gcc error found here, but it might terminate the scanning of a previous
+ one>>
+\newline
+/****** Search second ":" in the error number */
+\newline
+t = (char *)strpbrk(s+1, " :");
+\newline
+if (t == NULL || *t == ' ')
+\newline
+  <<No gcc error found here, but it might terminate the scanning of a previous
+ one>>
+\newline
+/****** Verify if is all digits between ":" */
+\newline
+if (t != s+1+strspn(s+1, "0123456789")) 
+\newline
+  <<No gcc error found here, but it might terminate the scanning of a previous
+ one>>
+\newline
+@
+\end_layout
 
-\protected_separator 
+\begin_layout Scrap
 
-\protected_separator 
+<<No gcc error found here, but it might terminate the scanning of a previous
+ one>>=
+\newline
+{
+\newline
+  err_line = 0;
+\newline
+  discharge_buffer(1);
+\newline
+  continue;
+\newline
+}
+\newline
+@
+\end_layout
 
-\protected_separator 
+\begin_layout Standard
 
-\protected_separator 
- err_line = atoi(s+1);
-\newline 
+As we mentioned, when the scan of one gcc error message is completed everything
+ in the buffer except the last line is one single error message.
+ But if the scan terminates with a EOF or through finding one line that
+ does not match the gcc error message criteria, then there is no 
+\begin_inset Quotes eld
+\end_inset
 
-\protected_separator 
+last line
+\begin_inset Quotes erd
+\end_inset
 
-\protected_separator 
+ in the buffer to be concerned with.
+ In those cases we empty the buffer completely.
+\end_layout
 
-\protected_separator 
+\begin_layout Scrap
 
-\protected_separator 
+<<Function bodies>>=
+\newline
+void
+\newline
+discharge_buffer (int save_last)
+\newline
+{
+\newline
+ if (last_err_line != 0) { 
+\newline
+   clean_gcc_messages();
+\newline
+   if (save_last != 0) {
+\newline
+      output_error(last_buf_line-1, last_err_line, "gcc");
+\newline
+      strcpy (buffer[0], buffer[last_buf_line-1]);
+\newline
+      last_err_line = err_line;
+\newline
+      last_buf_line = 1;
+\newline
+    } else { 
+\newline
+      ++last_buf_line;
+\newline
+      clean_gcc_messages();
+\newline
+      output_error(last_buf_line-1, last_err_line, "gcc");
+\newline
+      last_err_line = 0;
+\newline
+      last_buf_line = 0;
+\newline
+    }
+\newline
+  }
+\newline
+}
+\newline
+@
+\end_layout
 
-\protected_separator 
- if (last_err_line == 0 || last_err_line == err_line) {
-\newline 
+\begin_layout Scrap
 
-\protected_separator 
+<<Function prototypes>>=
+\newline
+void discharge_buffer (int save_last);
+\newline
+@
+\end_layout
 
-\protected_separator 
+\begin_layout Standard
 
-\protected_separator 
+The next function 
+\begin_inset Quotes eld
+\end_inset
 
-\protected_separator 
+cleans
+\begin_inset Quotes erd
+\end_inset
 
-\protected_separator 
+ superfluous information from gcc messages, namely the name of the noweb
+ file and the line number of the Error.
+\begin_inset Foot
+status collapsed
 
-\protected_separator 
+\begin_layout Standard
 
-\protected_separator 
+More could be done.
+ For instance, some way of distinguishing between gcc Errors and Warnings
+ should be devised.
+\end_layout
 
-\protected_separator 
-last_err_line = err_line;
-\newline 
+\end_inset
 
-\protected_separator 
 
-\protected_separator 
+\end_layout
 
-\protected_separator 
+\begin_layout Scrap
 
-\protected_separator 
+<<Function bodies>>=
+\newline
+void
+\newline
+clean_gcc_messages ()
+\newline
+{
+\newline
+  int index;
+\newline
+  char search [30]; 
+\newline
+  char *tail, *head; 
+\newline
+  int search_len = sprintf(search, ".nw:%d:", last_err_line);
+\newline
+  
+\newline
+  for (index = 0; index < last_buf_line-1; index++) {
+\newline
+    tail = (char *)strstr (buffer[index], search);
+\newline
+    if ( tail == NULL) {
+\newline
+       tail = (char *) strstr (buffer[index], ".nw:");
+\newline
+       if (tail) {
+\newline
+          tail += 4;
+\newline
+       }
+\newline
+    } else {
+\newline
+       tail += search_len;
+\newline
+    }
+\newline
+    if (tail != NULL) {
+\newline
+       head = buffer[index];
+\newline
+       while (*(head++) = *(tail++));
+\newline
+    }
+\newline
+  }
+\newline
+}
+\newline
+@
+\end_layout
 
-\protected_separator 
+\begin_layout Scrap
 
-\protected_separator 
+<<Function prototypes>>=
+\newline
+void clean_gcc_messages ();
+\newline
+@
+\end_layout
 
-\protected_separator 
+\begin_layout Standard
 
-\protected_separator 
-continue; /* It's either a header or a continuation, don't output yet */
-\newline 
+To combine the scan of noweb error messages and xlc error messages is very
+ simple.
+ We just try each one for every input line:
+\end_layout
 
-\protected_separator 
+\begin_layout Scrap
 
-\protected_separator 
+<<AIX system using both noweb and xlc>>=
+\newline
+{
+\newline
+  last_buf_line = 0;
+\newline
+  while (fgets(buffer[0], 200, stdin)) {
+\newline
+    if (noweb_try(0))
+\newline
+      output_error(1, err_line, "noweb");
+\newline
+    else if (xlc_try(0))
+\newline
+      output_error(1, err_line, "xlc");
+\newline
+  }
+\newline
+}
+\newline
+@
+\end_layout
 
-\protected_separator 
+\begin_layout Standard
 
-\protected_separator 
+To combine the scan of noweb error messages and gcc error messages is simple
+ if we realize that it is not possible to find a noweb error message in
+ the middle of a gcc error message.
+ So we just repeat the gcc procedure and test for noweb error messages in
+ the beginning of the scan:
+\end_layout
 
-\protected_separator 
- }
-\newline 
+\begin_layout Scrap
 
-\protected_separator 
-\protected_separator 
+<<Solaris and Linux systems using both noweb and gcc>>=
+\newline
+{
+\newline
+  char    *s, *t;
+\newline
  
-\protected_separator 
- /****** Completed the scan of one error message, output it to LyX */
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- discharge_buffer(1);
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- break;
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-
-\protected_separator 
- } while (fgets(buffer[last_buf_line], 200, stdin));
-\newline 
-
-\protected_separator 
- }
-\newline 
-
-\protected_separator 
-
-\protected_separator 
-/****** EOF completes the scan of whatever was being scanned */
-\newline 
-
-\protected_separator 
- discharge_buffer(0);
-\newline 
+\newline
+  last_buf_line = 0;
+\newline
+  while (fgets(buffer[last_buf_line], 200, stdin)) {
+\newline
+    /****** Skip lines until I find an error */
+\newline
+    if (last_buf_line == 0 && noweb_try(0)) {
+\newline
+      output_error(1, err_line, "noweb");
+\newline
+      continue;
+\newline
+    }
+\newline
+    s = (char *)strpbrk(buffer[last_buf_line], " :");
+\newline
+    if (s == NULL || *s == ' ')
+\newline
+      continue; /* No gcc error found here */
+\newline
+    do {
+\newline
+      <<gcc error message criteria is to find a "...:999:" or a "...: ">>
+\newline
+      /****** OK It is an error, get line number */
+\newline
+      err_line = atoi(s+1);
+\newline
+      if (last_err_line == 0 || last_err_line == err_line) {
+\newline
+        last_err_line = err_line;
+\newline
+        continue; /* It's either a header or a continuation, don't output
+ yet */
+\newline
+      }
+\newline
+      /****** Completed the scan of one error message, output it to LyX
+ */
+\newline
+      discharge_buffer(1);
+\newline
+      break;
+\newline
+    } while (fgets(buffer[last_buf_line], 200, stdin));
+\newline
+  }
+\newline
+  /****** EOF completes the scan of whatever was being scanned */
+\newline
+  discharge_buffer(0);
+\newline
 }
-\newline 
+\newline
 @
-\layout Section
+\end_layout
+
+\begin_layout Section
 
 Wrapping the code into a file
-\layout Scrap
+\end_layout
+
+\begin_layout Scrap
 
 <<listerrors.c>>=
-\newline 
+\newline
 #include <stdio.h>
-\newline 
-#include <strings.h> 
-\protected_separator 
+\newline
+#include <strings.h>       
+\newline
  
-\protected_separator 
-\protected_separator 
-\newline 
-
-\protected_separator 
-
-\newline 
+\newline
 <<Global variables>>
-\newline 
+\newline
 <<Function prototypes>>
-\newline 
+\newline
 <<Function bodies>>
-\newline 
+\newline
 @
-\layout Standard
+\end_layout
+
+\begin_layout Standard
 
 To build this program, we want to add the 
 \begin_inset Quotes eld
-\end_inset 
+\end_inset
 
 -L
 \begin_inset Quotes erd
-\end_inset 
+\end_inset
 
  option in the tangle command to force gdb to load the file 
-\family typewriter 
+\family typewriter
 Literate.nw
-\family default 
+\family default
  instead of 
-\family typewriter 
+\family typewriter
 listerrors.c
-\family default 
+\family default
 .
  In accordance with this, we pass the 
 \begin_inset Quotes eld
-\end_inset 
+\end_inset
 
 -g
 \begin_inset Quotes erd
-\end_inset 
+\end_inset
 
  option to gcc.
-\layout Scrap
+\end_layout
+
+\begin_layout Scrap
 
 <<build-script>>=
-\newline 
-#!/usr/local/bin/bash
-\newline 
-notangle -L -Rlisterrors.c Literate.nw > listerrors.c
-\newline 
+\newline
+#!/bin/sh
+\newline
+if [ -z "$NOWEB_SOURCE" ]; then NOWEB_SOURCE=Literate.nw; fi
+\newline
+notangle -L -Rlisterrors.c ${NOWEB_SOURCE} > listerrors.c
+\newline
 gcc -g -o listerrors listerrors.c
-\newline 
+\newline
 @
-\layout Standard
+\end_layout
+
+\begin_layout Standard
 
 This project can be tangled and compiled from LyX if you set 
-\family typewriter 
+\family typewriter
 
-\backslash 
+\backslash
 build_command
-\family default 
+\family default
  to call a generic script that always extracts a scrap named 
-\family typewriter 
+\family typewriter
 build-script
-\family default 
+\family default
  and executes it.
  Here is a example of such generic script:
-\layout LyX-Code
-
-#!/bin/sh
-\newline 
-notangle -Rbuild-script $1 | sh
-\the_end
-
+\end_layout
 
+\begin_layout LyX-Code
 
+#!/bin/sh
+\newline
+notangle -Rbuild-script $1 | env NOWEB_SOURCE=$1 sh
+\end_layout
 
+\begin_layout LyX-Code
 
+\end_layout
 
+\end_body
+\end_document