X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=lib%2Fexamples%2FLiterate.lyx;h=80a72f97a7f5131f1742f17006d07a2cd819ea41;hb=096de939a2e96f726d6232faa23a717e50ba6400;hp=47db33766a1c829d19bdb7035ceb1ed603bfc7da;hpb=27de1486ca34aaad446adb798d71a77d6f6304da;p=lyx.git diff --git a/lib/examples/Literate.lyx b/lib/examples/Literate.lyx index 47db33766a..80a72f97a7 100644 --- a/lib/examples/Literate.lyx +++ b/lib/examples/Literate.lyx @@ -1,17 +1,19 @@ -#This file was created by 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 @@ -22,1781 +24,1098 @@ \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 - -<>= -\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 - <> -\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 - <> -\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 -<> -\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 - <> -\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 - <> -\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 - <> -\newline - -\protected_separator - } -\newline -} -\newline -@ -\layout Scrap - -<>= -\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 - -<>= -\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 - -<>= -\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>= -\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 - -<>= -\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 - -<>= -\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 - -<>= -\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 - -<>= -\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 - -<>= -\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 - -<>= -\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 - -<>= -\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 - -<>= -\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 -<> -\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 - -<>= -\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 - <> -\newline -/****** Search second ":" in the error number */ -\newline -t = strpbrk(s+1, " :"); -\newline -if (t == NULL || *t == ' ') -\newline - -\protected_separator - <> -\newline -/****** Verify if is all digits between ":" */ -\newline -if (t != s+1+strspn(s+1, "0123456789")) -\newline - -\protected_separator - <> -\newline -@ -\layout Scrap - -<>= -\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 - -<>= -\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 +<>= +\newline +int +\newline +main (int argc, char **argv) +\newline +{ +\newline + if (argc == 2) { +\newline + switch (argv[1][0]) { +\newline + case 'n': +\newline + <> +\newline + break; +\newline + case 'x': +\newline + <> +\newline + break; +\newline + case 'a': +\newline + <> +\newline + break; +\newline + case 's': +\newline + case 'b': +\newline + <> +\newline + break; +\newline + case 'g': +\newline + default: +\newline + <> +\newline + break; +\newline + } +\newline + } else { +\newline + <> +\newline + } +\newline } -\newline +\newline @ -\layout Scrap +\end_layout + +\begin_layout Scrap <>= -\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 - -<>= -\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 +<>= +\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 +<>= +\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>= -\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 +<>= +\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 +<>= +\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 +<>= +\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 +<>= +\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 +<>= +\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 +<>= +\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 +<>= +\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 +<>= +\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 -<> -\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 +<>= +\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 + <> +\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 +<>= +\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 + <> +\newline +/****** Search second ":" in the error number */ +\newline +t = (char *)strpbrk(s+1, " :"); +\newline +if (t == NULL || *t == ' ') +\newline + <> +\newline +/****** Verify if is all digits between ":" */ +\newline +if (t != s+1+strspn(s+1, "0123456789")) +\newline + <> +\newline +@ +\end_layout -\protected_separator +\begin_layout Scrap -\protected_separator +<>= +\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 +<>= +\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 +<>= +\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 +<>= +\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 +<>= +\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 +<>= +\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 +<>= +\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 + <> +\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 <>= -\newline +\newline #include -\newline -#include -\protected_separator +\newline +#include +\newline -\protected_separator - -\protected_separator - -\newline - -\protected_separator - -\newline +\newline <> -\newline +\newline <> -\newline +\newline <> -\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 <>= -\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