mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-27 03:36:39 +00:00
8461827e90
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@26674 a592a061-630c-0410-9148-cb99ea01b6c8
1670 lines
29 KiB
Plaintext
1670 lines
29 KiB
Plaintext
#LyX 1.6.0svn created this file. For more info see http://www.lyx.org/
|
|
\lyxformat 341
|
|
\begin_document
|
|
\begin_header
|
|
\textclass literate-article
|
|
\language english
|
|
\inputencoding default
|
|
\font_roman default
|
|
\font_sans default
|
|
\font_typewriter default
|
|
\font_default_family default
|
|
\font_sc false
|
|
\font_osf false
|
|
\font_sf_scale 100
|
|
\font_tt_scale 100
|
|
|
|
\graphics default
|
|
\paperfontsize default
|
|
\spacing single
|
|
\use_hyperref false
|
|
\papersize default
|
|
\use_geometry false
|
|
\use_amsmath 0
|
|
\use_esint 0
|
|
\cite_engine basic
|
|
\use_bibtopic false
|
|
\paperorientation portrait
|
|
\secnumdepth 3
|
|
\tocdepth 3
|
|
\paragraph_separation indent
|
|
\defskip medskip
|
|
\quotes_language english
|
|
\papercolumns 1
|
|
\papersides 1
|
|
\paperpagestyle default
|
|
\tracking_changes false
|
|
\output_changes false
|
|
\author ""
|
|
\end_header
|
|
|
|
\begin_body
|
|
|
|
\begin_layout Title
|
|
LyX and Literate Programming
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
An example program
|
|
\end_layout
|
|
|
|
\begin_layout Author
|
|
Edmar Wienskoski Jr.
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
edmar-w-jr@technologist.com
|
|
\begin_inset Foot
|
|
status collapsed
|
|
|
|
\begin_layout Plain Layout
|
|
Modified by Bernard Michael Hurley bernardh@westherts.ac.uk ---- Don't blame
|
|
Edmar for any errors that have crept in!
|
|
\end_layout
|
|
|
|
\end_inset
|
|
|
|
|
|
\end_layout
|
|
|
|
\begin_layout Abstract
|
|
|
|
\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
|
|
|
|
\begin_layout Date
|
|
\begin_inset ERT
|
|
status collapsed
|
|
|
|
\begin_layout Plain Layout
|
|
|
|
|
|
\backslash
|
|
today
|
|
\end_layout
|
|
|
|
\end_inset
|
|
|
|
|
|
\end_layout
|
|
|
|
\begin_layout Standard
|
|
\begin_inset CommandInset toc
|
|
LatexCommand tableofcontents
|
|
|
|
\end_inset
|
|
|
|
|
|
\end_layout
|
|
|
|
\begin_layout Section
|
|
Introduction
|
|
\end_layout
|
|
|
|
\begin_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.
|
|
\end_layout
|
|
|
|
\begin_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.
|
|
|
|
\end_layout
|
|
|
|
\begin_layout Standard
|
|
In this document we present a filter that recognizes compilation error messages
|
|
from noweb, gnu C, and the IBM C compiler (xlc).
|
|
\end_layout
|
|
|
|
\begin_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.
|
|
\end_layout
|
|
|
|
\begin_layout Section
|
|
Algorithm
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Function bodies>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
int
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
main (int argc, char **argv)
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
{
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (argc == 2) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
switch (argv[1][0]) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
case 'n':
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
<<Scan input for noweb error messages>>
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
break;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
case 'x':
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
<<Scan input for xlc error messages>>
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
break;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
case 'a':
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
<<AIX system using both noweb and xlc>>
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
break;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
case 's':
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
case 'b':
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
<<Solaris and Linux systems using both noweb and gcc>>
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
break;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
case 'g':
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
default:
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
<<Scan input for gcc error messages>>
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
break;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
} else {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
<<Scan input for gcc error messages>>
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Function prototypes>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
int main (int argc, char **argv);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_layout Section
|
|
Data Structures
|
|
\end_layout
|
|
|
|
\begin_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.
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Global variables>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
char buffer[200][200];
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
int last_buf_line;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
int last_err_line;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
int err_line;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_layout Section
|
|
The output format
|
|
\end_layout
|
|
|
|
\begin_layout Standard
|
|
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
|
|
|
|
\begin_layout Plain Layout
|
|
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
|
|
|
|
\end_inset
|
|
|
|
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Function bodies>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
void
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
output_error (int buf_size, int error_line, char *tool)
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
{
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
int i;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
fprintf(stdout, "! Build Error: ==> %s ==>
|
|
\backslash
|
|
n", tool);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
fprintf(stdout, " ...
|
|
\backslash
|
|
n
|
|
\backslash
|
|
nl.%d ...
|
|
\backslash
|
|
n", error_line);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
for (i=0; i<buf_size; i++)
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (strlen(buffer[i]) != 0)
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
fprintf(stdout, "%s", buffer[i]);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
fprintf(stdout, "
|
|
\backslash
|
|
n");
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Function prototypes>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
void output_error (int buf_size, int error_line, char *tool);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_layout Section
|
|
Functions Implementation
|
|
\end_layout
|
|
|
|
\begin_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.
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Scan input for noweb error messages>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
{
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
last_buf_line = 0;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
while (fgets(buffer[0], 200, stdin)) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (noweb_try(0))
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
output_error(1, err_line, "noweb");
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_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.
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Global variables>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
char *noweb_msgs[] = {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
"couldn't open file",
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
"couldn't open temporary file",
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
"error writing temporary file",
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
"ill-formed option",
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
"unknown option",
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
"Bad format sequence",
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
"Can't open output file",
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
"Can't open temporary file",
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
"Capacity exceeded:",
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
"Ignoring unknown option -",
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
"This can't happen:",
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
"non-numeric line number in"
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
};
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
char *noweb_msgs_mimic_gcc[] = {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
": unescaped << in documentation chunk"
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
};
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_layout Standard
|
|
A noweb error message can be any string that contains a matching pair of
|
|
< <
|
|
\begin_inset space ~
|
|
\end_inset
|
|
|
|
|
|
\begin_inset space ~
|
|
\end_inset
|
|
|
|
|
|
\begin_inset space ~
|
|
\end_inset
|
|
|
|
> >, or any of the above strings
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Function bodies>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
int
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
noweb_try (int buf_line)
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
{
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
char *s, *t, *b;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
int i;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
b = buffer[buf_line];
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
err_line = 0;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
for (i=0; i<1; i++) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
s = (char *)strstr (b, noweb_msgs_mimic_gcc[i]);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (s != NULL) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
t = (char *)strchr(buffer[buf_line], ':');
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
err_line = atoi(t+1);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
t = buffer[buf_line];
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
++s;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
while (*(t++) = *(s++));
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
return 1;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
s = (char *)strstr(b, "<<");
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (s != NULL) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
s = (char *)strstr(s+2, ">>");
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (s != NULL) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
return 1;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
} else {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
for (i = 0; i < 12; ++i) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
s = (char *)strstr (b, noweb_msgs[i]);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (s != NULL) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
return 1;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
return 0;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Function prototypes>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
int noweb_try (int buf_line);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_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.
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Scan input for xlc error messages>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
{
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
last_buf_line = 0;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
while (fgets(buffer[last_buf_line], 200, stdin)) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (xlc_try(0))
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
output_error(1, err_line, "xlc");
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_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:
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Function bodies>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
int
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
xlc_try (int buf_line)
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
{
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
char *s, *t;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
t = buffer[buf_line];
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
s = t+1;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
while (*s != '"' && *s != ' ' && *s != '
|
|
\backslash
|
|
0')
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
s++;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (*t != '"' || *s != '"' || strncmp(s+1, ", line ", 7) != 0)
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
return 0;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
s += 8;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
err_line = atoi(s);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
return 1;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Function prototypes>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
int xlc_try (int buf_line);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_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.
|
|
\end_layout
|
|
|
|
\begin_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
|
|
|
|
.
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Scan input for gcc error messages>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
{
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
char *s, *t;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
last_buf_line = 0;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
while (fgets(buffer[last_buf_line], 200, stdin)) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
/****** Skip lines until I find an error */
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
s = (char *)strpbrk(buffer[last_buf_line], " :");
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (s == NULL || *s == ' ')
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
continue; /* No gcc error found here */
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
do {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
<<gcc error message criteria is to find a "...:999:" or a "...: ">>
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
/****** OK It is an error message, get line number */
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
err_line = atoi(s+1);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (last_err_line == 0 || last_err_line == err_line) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
last_err_line = err_line;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
continue; /* It's either a header or a continuation, don't output
|
|
yet */
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
/****** Completed the scan of one error message, output it to LyX
|
|
*/
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
discharge_buffer(1);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
break;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
} while (fgets(buffer[last_buf_line], 200, stdin));
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
/****** EOF completes the scan of whatever was being scanned */
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
discharge_buffer(0);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<gcc error message criteria is to find a "...:999:" or a "...: ">>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
/****** Search first ":" in the error number */
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
s = (char *)strpbrk(buffer[last_buf_line], " :");
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
last_buf_line++;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (s == NULL || *s == ' ')
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
<<No gcc error found here, but it might terminate the scanning of a previous
|
|
one>>
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
/****** Search second ":" in the error number */
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
t = (char *)strpbrk(s+1, " :");
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (t == NULL || *t == ' ')
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
<<No gcc error found here, but it might terminate the scanning of a previous
|
|
one>>
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
/****** Verify if is all digits between ":" */
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (t != s+1+strspn(s+1, "0123456789"))
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
<<No gcc error found here, but it might terminate the scanning of a previous
|
|
one>>
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<No gcc error found here, but it might terminate the scanning of a previous
|
|
one>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
{
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
err_line = 0;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
discharge_buffer(1);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
continue;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_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.
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Function bodies>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
void
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
discharge_buffer (int save_last)
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
{
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (last_err_line != 0) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
clean_gcc_messages();
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (save_last != 0) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
output_error(last_buf_line-1, last_err_line, "gcc");
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
strcpy (buffer[0], buffer[last_buf_line-1]);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
last_err_line = err_line;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
last_buf_line = 1;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
} else {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
++last_buf_line;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
clean_gcc_messages();
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
output_error(last_buf_line-1, last_err_line, "gcc");
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
last_err_line = 0;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
last_buf_line = 0;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Function prototypes>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
void discharge_buffer (int save_last);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_layout Standard
|
|
The next function
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
cleans
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
superfluous information from gcc messages, namely the name of the noweb
|
|
file and the line number of the Error.
|
|
\begin_inset Foot
|
|
status collapsed
|
|
|
|
\begin_layout Plain Layout
|
|
More could be done.
|
|
For instance, some way of distinguishing between gcc Errors and Warnings
|
|
should be devised.
|
|
\end_layout
|
|
|
|
\end_inset
|
|
|
|
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Function bodies>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
void
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
clean_gcc_messages ()
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
{
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
int index;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
char search [30];
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
char *tail, *head;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
int search_len = sprintf(search, ".nw:%d:", last_err_line);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
for (index = 0; index < last_buf_line-1; index++) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
tail = (char *)strstr (buffer[index], search);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if ( tail == NULL) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
tail = (char *) strstr (buffer[index], ".nw:");
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (tail) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
tail += 4;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
} else {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
tail += search_len;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (tail != NULL) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
head = buffer[index];
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
while (*(head++) = *(tail++));
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Function prototypes>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
void clean_gcc_messages ();
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_layout Standard
|
|
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
|
|
|
|
\begin_layout Scrap
|
|
<<AIX system using both noweb and xlc>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
{
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
last_buf_line = 0;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
while (fgets(buffer[0], 200, stdin)) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (noweb_try(0))
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
output_error(1, err_line, "noweb");
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
else if (xlc_try(0))
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
output_error(1, err_line, "xlc");
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_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:
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<Solaris and Linux systems using both noweb and gcc>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
{
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
char *s, *t;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
last_buf_line = 0;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
while (fgets(buffer[last_buf_line], 200, stdin)) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
/****** Skip lines until I find an error */
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (last_buf_line == 0 && noweb_try(0)) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
output_error(1, err_line, "noweb");
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
continue;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
s = (char *)strpbrk(buffer[last_buf_line], " :");
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (s == NULL || *s == ' ')
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
continue; /* No gcc error found here */
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
do {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
<<gcc error message criteria is to find a "...:999:" or a "...: ">>
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
/****** OK It is an error, get line number */
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
err_line = atoi(s+1);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if (last_err_line == 0 || last_err_line == err_line) {
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
last_err_line = err_line;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
continue; /* It's either a header or a continuation, don't output
|
|
yet */
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
/****** Completed the scan of one error message, output it to LyX
|
|
*/
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
discharge_buffer(1);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
break;
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
} while (fgets(buffer[last_buf_line], 200, stdin));
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
/****** EOF completes the scan of whatever was being scanned */
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
discharge_buffer(0);
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
}
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_layout Section
|
|
Wrapping the code into a file
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<listerrors.c>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
#include <stdio.h>
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
#include <strings.h>
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
<<Global variables>>
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
<<Function prototypes>>
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
<<Function bodies>>
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_layout Standard
|
|
To build this program, we want to add the
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
-L
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
option in the tangle command to force gdb to load the file
|
|
\family typewriter
|
|
Literate.nw
|
|
\family default
|
|
instead of
|
|
\family typewriter
|
|
listerrors.c
|
|
\family default
|
|
.
|
|
In accordance with this, we pass the
|
|
\begin_inset Quotes eld
|
|
\end_inset
|
|
|
|
-g
|
|
\begin_inset Quotes erd
|
|
\end_inset
|
|
|
|
option to gcc.
|
|
\end_layout
|
|
|
|
\begin_layout Scrap
|
|
<<build-script>>=
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
#!/bin/sh
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
if [ -z "$NOWEB_SOURCE" ]; then NOWEB_SOURCE=Literate.nw; fi
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
notangle -L -Rlisterrors.c ${NOWEB_SOURCE} > listerrors.c
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
gcc -g -o listerrors listerrors.c
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
@
|
|
\end_layout
|
|
|
|
\begin_layout Standard
|
|
This project can be tangled and compiled from LyX if you set
|
|
\family typewriter
|
|
|
|
\backslash
|
|
build_command
|
|
\family default
|
|
to call a generic script that always extracts a scrap named
|
|
\family typewriter
|
|
build-script
|
|
\family default
|
|
and executes it.
|
|
Here is a example of such generic script:
|
|
\end_layout
|
|
|
|
\begin_layout LyX-Code
|
|
#!/bin/sh
|
|
\begin_inset Newline newline
|
|
\end_inset
|
|
|
|
notangle -Rbuild-script $1 | env NOWEB_SOURCE=$1 sh
|
|
\end_layout
|
|
|
|
\begin_layout LyX-Code
|
|
|
|
\end_layout
|
|
|
|
\end_body
|
|
\end_document
|