]> git.lyx.org Git - lyx.git/blob - lib/examples/Literate.lyx
example files: fileformat and partly other updates second part
[lyx.git] / lib / examples / Literate.lyx
1 #LyX 1.6.0svn created this file. For more info see http://www.lyx.org/
2 \lyxformat 341
3 \begin_document
4 \begin_header
5 \textclass literate-article
6 \language english
7 \inputencoding default
8 \font_roman default
9 \font_sans default
10 \font_typewriter default
11 \font_default_family default
12 \font_sc false
13 \font_osf false
14 \font_sf_scale 100
15 \font_tt_scale 100
16
17 \graphics default
18 \paperfontsize default
19 \spacing single
20 \use_hyperref false
21 \papersize default
22 \use_geometry false
23 \use_amsmath 0
24 \use_esint 0
25 \cite_engine basic
26 \use_bibtopic false
27 \paperorientation portrait
28 \secnumdepth 3
29 \tocdepth 3
30 \paragraph_separation indent
31 \defskip medskip
32 \quotes_language english
33 \papercolumns 1
34 \papersides 1
35 \paperpagestyle default
36 \tracking_changes false
37 \output_changes false
38 \author "" 
39 \end_header
40
41 \begin_body
42
43 \begin_layout Title
44 LyX and Literate Programming
45 \begin_inset Newline newline
46 \end_inset
47
48 An example program
49 \end_layout
50
51 \begin_layout Author
52 Edmar Wienskoski Jr.
53 \begin_inset Newline newline
54 \end_inset
55
56 edmar-w-jr@technologist.com
57 \begin_inset Foot
58 status collapsed
59
60 \begin_layout Plain Layout
61 Modified by Bernard Michael Hurley bernardh@westherts.ac.uk ---- Don't blame
62  Edmar for any errors that have crept in!
63 \end_layout
64
65 \end_inset
66
67
68 \end_layout
69
70 \begin_layout Abstract
71
72 \series bold
73 Note:
74 \series default
75  This example program is provided for educational use only.
76  The functionality in this C program has been superceded by the equivalent
77  Python code in 
78 \emph on
79 examples/listerrors.lyx
80 \emph default
81  which should be installed in the LyX scripts directory.
82 \end_layout
83
84 \begin_layout Date
85 \begin_inset ERT
86 status collapsed
87
88 \begin_layout Plain Layout
89
90
91 \backslash
92 today
93 \end_layout
94
95 \end_inset
96
97
98 \end_layout
99
100 \begin_layout Standard
101 \begin_inset CommandInset toc
102 LatexCommand tableofcontents
103
104 \end_inset
105
106
107 \end_layout
108
109 \begin_layout Section
110 Introduction
111 \end_layout
112
113 \begin_layout Standard
114 After typesetting a document, LyX scans the LaTeX log file looking for errors.
115  For each error found, the line number is obtained and a error box is displayed
116  in the LyX screen at that position.
117 \end_layout
118
119 \begin_layout Standard
120 To use this feature to view compilation errors while working with literate
121  documents, we need a program that filters the compilation errors and puts
122  them in a format suitable for LyX reading it.
123  
124 \end_layout
125
126 \begin_layout Standard
127 In this document we present a filter that recognizes compilation error messages
128  from noweb, gnu C, and the IBM C compiler (xlc).
129 \end_layout
130
131 \begin_layout Standard
132 The filter is required to read from standard input, parse for error messages
133  and copy the error messages to the standard output.
134  During the output process, the filter must present the error messages in
135  a format that LyX can interpret, currently, the LaTeX error message format.
136  Of course, nothing will prevent future LyX releases from being able to
137  read other formats as well (like gcc error messages for example).
138  This mechanism is necessary to fully explore the literate programming tool's
139  capabilities.
140 \end_layout
141
142 \begin_layout Section
143 Algorithm
144 \end_layout
145
146 \begin_layout Scrap
147 <<Function bodies>>=
148 \begin_inset Newline newline
149 \end_inset
150
151 int
152 \begin_inset Newline newline
153 \end_inset
154
155 main (int argc, char **argv)
156 \begin_inset Newline newline
157 \end_inset
158
159 {
160 \begin_inset Newline newline
161 \end_inset
162
163   if (argc == 2) {
164 \begin_inset Newline newline
165 \end_inset
166
167     switch (argv[1][0]) {
168 \begin_inset Newline newline
169 \end_inset
170
171     case 'n':
172 \begin_inset Newline newline
173 \end_inset
174
175       <<Scan input for noweb error messages>>
176 \begin_inset Newline newline
177 \end_inset
178
179       break;
180 \begin_inset Newline newline
181 \end_inset
182
183     case 'x':
184 \begin_inset Newline newline
185 \end_inset
186
187       <<Scan input for xlc error messages>>
188 \begin_inset Newline newline
189 \end_inset
190
191       break;
192 \begin_inset Newline newline
193 \end_inset
194
195     case 'a':
196 \begin_inset Newline newline
197 \end_inset
198
199       <<AIX system using both noweb and xlc>>
200 \begin_inset Newline newline
201 \end_inset
202
203       break;
204 \begin_inset Newline newline
205 \end_inset
206
207     case 's':
208 \begin_inset Newline newline
209 \end_inset
210
211     case 'b':
212 \begin_inset Newline newline
213 \end_inset
214
215       <<Solaris and Linux systems using both noweb and gcc>>
216 \begin_inset Newline newline
217 \end_inset
218
219       break;
220 \begin_inset Newline newline
221 \end_inset
222
223     case 'g':
224 \begin_inset Newline newline
225 \end_inset
226
227     default:
228 \begin_inset Newline newline
229 \end_inset
230
231       <<Scan input for gcc error messages>>
232 \begin_inset Newline newline
233 \end_inset
234
235       break;
236 \begin_inset Newline newline
237 \end_inset
238
239     }
240 \begin_inset Newline newline
241 \end_inset
242
243   } else {
244 \begin_inset Newline newline
245 \end_inset
246
247     <<Scan input for gcc error messages>>
248 \begin_inset Newline newline
249 \end_inset
250
251   }
252 \begin_inset Newline newline
253 \end_inset
254
255 }
256 \begin_inset Newline newline
257 \end_inset
258
259 @
260 \end_layout
261
262 \begin_layout Scrap
263 <<Function prototypes>>=
264 \begin_inset Newline newline
265 \end_inset
266
267 int main (int argc, char **argv);
268 \begin_inset Newline newline
269 \end_inset
270
271 @
272 \end_layout
273
274 \begin_layout Section
275 Data Structures
276 \end_layout
277
278 \begin_layout Standard
279 We resort to some global variables to allow access from several different
280  routines.
281  These are the buffer and related pointers used during the parse of the
282  input.
283 \end_layout
284
285 \begin_layout Scrap
286 <<Global variables>>=
287 \begin_inset Newline newline
288 \end_inset
289
290 char    buffer[200][200];
291 \begin_inset Newline newline
292 \end_inset
293
294 int     last_buf_line;
295 \begin_inset Newline newline
296 \end_inset
297
298 int     last_err_line;
299 \begin_inset Newline newline
300 \end_inset
301
302 int     err_line;
303 \begin_inset Newline newline
304 \end_inset
305
306
307 \end_layout
308
309 \begin_layout Section
310 The output format
311 \end_layout
312
313 \begin_layout Standard
314 The output format mimics the TeX error messages format.
315  This function prints a number of lines residing in the global variable
316  
317 \family typewriter
318 buffer
319 \family default
320 , a program name and line number.
321  There is no special requirement on the input strings, they can be anything.
322 \begin_inset Foot
323 status collapsed
324
325 \begin_layout Plain Layout
326 This function has been slightly changed from EW's original to make scanning
327  a bit easier with LaTeX::scanLogFile().
328  The test has been added because LyX can crash if empty lines are allowed
329  here --- I can't figure out why! --- BMH
330 \end_layout
331
332 \end_inset
333
334
335 \end_layout
336
337 \begin_layout Scrap
338 <<Function bodies>>=
339 \begin_inset Newline newline
340 \end_inset
341
342 void
343 \begin_inset Newline newline
344 \end_inset
345
346 output_error (int buf_size, int error_line, char *tool)
347 \begin_inset Newline newline
348 \end_inset
349
350 {
351 \begin_inset Newline newline
352 \end_inset
353
354   int     i;
355 \begin_inset Newline newline
356 \end_inset
357
358  
359 \begin_inset Newline newline
360 \end_inset
361
362   fprintf(stdout, "! Build Error: ==> %s ==>
363 \backslash
364 n", tool);
365 \begin_inset Newline newline
366 \end_inset
367
368   fprintf(stdout, " ...
369 \backslash
370 n
371 \backslash
372 nl.%d ...
373 \backslash
374 n", error_line);
375 \begin_inset Newline newline
376 \end_inset
377
378  
379 \begin_inset Newline newline
380 \end_inset
381
382   for (i=0; i<buf_size; i++)
383 \begin_inset Newline newline
384 \end_inset
385
386     if (strlen(buffer[i]) != 0)
387 \begin_inset Newline newline
388 \end_inset
389
390       fprintf(stdout, "%s", buffer[i]);
391 \begin_inset Newline newline
392 \end_inset
393
394  
395 \begin_inset Newline newline
396 \end_inset
397
398   fprintf(stdout, "
399 \backslash
400 n");
401 \begin_inset Newline newline
402 \end_inset
403
404 }
405 \begin_inset Newline newline
406 \end_inset
407
408 @
409 \end_layout
410
411 \begin_layout Scrap
412 <<Function prototypes>>=
413 \begin_inset Newline newline
414 \end_inset
415
416 void output_error (int buf_size, int error_line, char *tool);
417 \begin_inset Newline newline
418 \end_inset
419
420 @
421 \end_layout
422
423 \begin_layout Section
424 Functions Implementation
425 \end_layout
426
427 \begin_layout Standard
428 Both noweave and notangle routines, always output one single line for each
429  error found, thus to scan the buffer for noweb error messages is enough
430  to exam one input line at a time.
431  Note that the noweb software does not provide a line error number, so all
432  errors boxes related to noweb messages will be displayed at the beginning
433  of the file.
434 \end_layout
435
436 \begin_layout Scrap
437 <<Scan input for noweb error messages>>=
438 \begin_inset Newline newline
439 \end_inset
440
441 {
442 \begin_inset Newline newline
443 \end_inset
444
445   last_buf_line = 0;
446 \begin_inset Newline newline
447 \end_inset
448
449   while (fgets(buffer[0], 200, stdin)) {
450 \begin_inset Newline newline
451 \end_inset
452
453     if (noweb_try(0))
454 \begin_inset Newline newline
455 \end_inset
456
457       output_error(1, err_line, "noweb");
458 \begin_inset Newline newline
459 \end_inset
460
461   }
462 \begin_inset Newline newline
463 \end_inset
464
465 }
466 \begin_inset Newline newline
467 \end_inset
468
469 @
470 \end_layout
471
472 \begin_layout Standard
473 The examination itself is very inefficient.
474  Unfortunately noweb doesn't have any characteristic that would help to
475  identify one of its error messages.
476  The solution is to collect all possible output messages in an array of
477  strings, and turn the examination process into a linear search in this
478  array.
479 \end_layout
480
481 \begin_layout Scrap
482 <<Global variables>>=
483 \begin_inset Newline newline
484 \end_inset
485
486 char *noweb_msgs[] = {
487 \begin_inset Newline newline
488 \end_inset
489
490   "couldn't open file",
491 \begin_inset Newline newline
492 \end_inset
493
494   "couldn't open temporary file",
495 \begin_inset Newline newline
496 \end_inset
497
498   "error writing temporary file",
499 \begin_inset Newline newline
500 \end_inset
501
502   "ill-formed option",
503 \begin_inset Newline newline
504 \end_inset
505
506   "unknown option",
507 \begin_inset Newline newline
508 \end_inset
509
510   "Bad format sequence",
511 \begin_inset Newline newline
512 \end_inset
513
514   "Can't open output file",
515 \begin_inset Newline newline
516 \end_inset
517
518   "Can't open temporary file",
519 \begin_inset Newline newline
520 \end_inset
521
522   "Capacity exceeded:",
523 \begin_inset Newline newline
524 \end_inset
525
526   "Ignoring unknown option -",
527 \begin_inset Newline newline
528 \end_inset
529
530   "This can't happen:",
531 \begin_inset Newline newline
532 \end_inset
533
534   "non-numeric line number in"
535 \begin_inset Newline newline
536 \end_inset
537
538 };
539 \begin_inset Newline newline
540 \end_inset
541
542
543 \begin_inset Newline newline
544 \end_inset
545
546 char *noweb_msgs_mimic_gcc[] = {
547 \begin_inset Newline newline
548 \end_inset
549
550   ": unescaped << in documentation chunk"
551 \begin_inset Newline newline
552 \end_inset
553
554 };
555 \begin_inset Newline newline
556 \end_inset
557
558 @
559 \end_layout
560
561 \begin_layout Standard
562 A noweb error message can be any string that contains a matching pair of
563  < <
564 \begin_inset space ~
565 \end_inset
566
567
568 \begin_inset space ~
569 \end_inset
570
571
572 \begin_inset space ~
573 \end_inset
574
575 > >, or any of the above strings
576 \end_layout
577
578 \begin_layout Scrap
579 <<Function bodies>>=
580 \begin_inset Newline newline
581 \end_inset
582
583 int
584 \begin_inset Newline newline
585 \end_inset
586
587 noweb_try (int buf_line)
588 \begin_inset Newline newline
589 \end_inset
590
591 {
592 \begin_inset Newline newline
593 \end_inset
594
595   char    *s, *t, *b;
596 \begin_inset Newline newline
597 \end_inset
598
599   int     i; 
600 \begin_inset Newline newline
601 \end_inset
602
603
604 \begin_inset Newline newline
605 \end_inset
606
607   b = buffer[buf_line];
608 \begin_inset Newline newline
609 \end_inset
610
611   err_line = 0;
612 \begin_inset Newline newline
613 \end_inset
614
615
616 \begin_inset Newline newline
617 \end_inset
618
619   for (i=0; i<1; i++) {
620 \begin_inset Newline newline
621 \end_inset
622
623       s = (char *)strstr (b, noweb_msgs_mimic_gcc[i]);
624 \begin_inset Newline newline
625 \end_inset
626
627       if (s != NULL) {
628 \begin_inset Newline newline
629 \end_inset
630
631         t = (char *)strchr(buffer[buf_line], ':');
632 \begin_inset Newline newline
633 \end_inset
634
635         err_line = atoi(t+1);
636 \begin_inset Newline newline
637 \end_inset
638
639         t = buffer[buf_line];
640 \begin_inset Newline newline
641 \end_inset
642
643         ++s;
644 \begin_inset Newline newline
645 \end_inset
646
647         while (*(t++) = *(s++));
648 \begin_inset Newline newline
649 \end_inset
650
651         return 1;
652 \begin_inset Newline newline
653 \end_inset
654
655       }
656 \begin_inset Newline newline
657 \end_inset
658
659   }
660 \begin_inset Newline newline
661 \end_inset
662
663   s = (char *)strstr(b, "<<");
664 \begin_inset Newline newline
665 \end_inset
666
667   if (s != NULL) {
668 \begin_inset Newline newline
669 \end_inset
670
671     s = (char *)strstr(s+2, ">>");
672 \begin_inset Newline newline
673 \end_inset
674
675     if (s != NULL) {
676 \begin_inset Newline newline
677 \end_inset
678
679       return 1;
680 \begin_inset Newline newline
681 \end_inset
682
683     }
684 \begin_inset Newline newline
685 \end_inset
686
687   } else { 
688 \begin_inset Newline newline
689 \end_inset
690
691      for (i = 0; i < 12; ++i) {
692 \begin_inset Newline newline
693 \end_inset
694
695         s = (char *)strstr (b, noweb_msgs[i]);
696 \begin_inset Newline newline
697 \end_inset
698
699         if (s != NULL) {
700 \begin_inset Newline newline
701 \end_inset
702
703            return 1;
704 \begin_inset Newline newline
705 \end_inset
706
707         }
708 \begin_inset Newline newline
709 \end_inset
710
711     }
712 \begin_inset Newline newline
713 \end_inset
714
715   }
716 \begin_inset Newline newline
717 \end_inset
718
719   return 0;
720 \begin_inset Newline newline
721 \end_inset
722
723 }
724 \begin_inset Newline newline
725 \end_inset
726
727 @
728 \end_layout
729
730 \begin_layout Scrap
731 <<Function prototypes>>=
732 \begin_inset Newline newline
733 \end_inset
734
735 int noweb_try (int buf_line);
736 \begin_inset Newline newline
737 \end_inset
738
739 @
740 \end_layout
741
742 \begin_layout Standard
743 The xlc compiler always outputs one single line for each error found, thus
744  to scan the buffer for xlc error messages it is enough to exam one input
745  line at a time.
746 \end_layout
747
748 \begin_layout Scrap
749 <<Scan input for xlc error messages>>= 
750 \begin_inset Newline newline
751 \end_inset
752
753 {
754 \begin_inset Newline newline
755 \end_inset
756
757   last_buf_line = 0;
758 \begin_inset Newline newline
759 \end_inset
760
761   while (fgets(buffer[last_buf_line], 200, stdin)) {
762 \begin_inset Newline newline
763 \end_inset
764
765     if (xlc_try(0))
766 \begin_inset Newline newline
767 \end_inset
768
769       output_error(1, err_line, "xlc");
770 \begin_inset Newline newline
771 \end_inset
772
773   }
774 \begin_inset Newline newline
775 \end_inset
776
777 }
778 \begin_inset Newline newline
779 \end_inset
780
781 @
782 \end_layout
783
784 \begin_layout Standard
785 A xlc error message is easy to identify.
786  Every error message starts with a quoted string with no spaces, a comma,
787  a space, the word 
788 \begin_inset Quotes eld
789 \end_inset
790
791 line
792 \begin_inset Quotes erd
793 \end_inset
794
795 , a space, and some variable text.
796  The following routine tests if a given buffer line matches this criteria:
797 \end_layout
798
799 \begin_layout Scrap
800 <<Function bodies>>=
801 \begin_inset Newline newline
802 \end_inset
803
804 int 
805 \begin_inset Newline newline
806 \end_inset
807
808 xlc_try (int buf_line)
809 \begin_inset Newline newline
810 \end_inset
811
812 {
813 \begin_inset Newline newline
814 \end_inset
815
816   char    *s, *t;
817 \begin_inset Newline newline
818 \end_inset
819
820  
821 \begin_inset Newline newline
822 \end_inset
823
824   t = buffer[buf_line];
825 \begin_inset Newline newline
826 \end_inset
827
828   s = t+1;
829 \begin_inset Newline newline
830 \end_inset
831
832   while (*s != '"' && *s != ' ' && *s != '
833 \backslash
834 0')
835 \begin_inset Newline newline
836 \end_inset
837
838     s++;
839 \begin_inset Newline newline
840 \end_inset
841
842   if (*t != '"' || *s != '"' || strncmp(s+1, ", line ", 7) != 0)
843 \begin_inset Newline newline
844 \end_inset
845
846     return 0;
847 \begin_inset Newline newline
848 \end_inset
849
850   s += 8;
851 \begin_inset Newline newline
852 \end_inset
853
854   err_line = atoi(s);
855 \begin_inset Newline newline
856 \end_inset
857
858   return 1;
859 \begin_inset Newline newline
860 \end_inset
861
862 }
863 \begin_inset Newline newline
864 \end_inset
865
866 @
867 \end_layout
868
869 \begin_layout Scrap
870 <<Function prototypes>>=
871 \begin_inset Newline newline
872 \end_inset
873
874 int xlc_try (int buf_line);
875 \begin_inset Newline newline
876 \end_inset
877
878 @
879 \end_layout
880
881 \begin_layout Standard
882 The gcc compiler error messages are more complicated to scan.
883  Each error can span more than one line in the buffer.
884  The good news is that every buffer line on each error has the same pattern,
885  and share the same line number.
886  Thus the strategy will be to accumulate lines in the buffer while the reported
887  line number is still the same.
888  At the time they differ, all the accumulated lines, except the last one,
889  will belong to one single error message, which now can be output-ed to
890  LyX.
891 \end_layout
892
893 \begin_layout Standard
894 Every gcc error message contains a string with no space followed by a 
895 \begin_inset Quotes eld
896 \end_inset
897
898 :
899 \begin_inset Quotes eld
900 \end_inset
901
902 .
903  If the next character is a space, then this line is a header of a error
904  message and the next line will detail the line number of the source code
905  where the error was found.
906  Otherwise, the next thing is a integer number followed by another 
907 \begin_inset Quotes eld
908 \end_inset
909
910 :
911 \begin_inset Quotes eld
912 \end_inset
913
914 .
915 \end_layout
916
917 \begin_layout Scrap
918 <<Scan input for gcc error messages>>=
919 \begin_inset Newline newline
920 \end_inset
921
922 {
923 \begin_inset Newline newline
924 \end_inset
925
926   char    *s, *t;
927 \begin_inset Newline newline
928 \end_inset
929
930  
931 \begin_inset Newline newline
932 \end_inset
933
934   last_buf_line = 0;
935 \begin_inset Newline newline
936 \end_inset
937
938   while (fgets(buffer[last_buf_line], 200, stdin)) {
939 \begin_inset Newline newline
940 \end_inset
941
942     /****** Skip lines until I find an error */
943 \begin_inset Newline newline
944 \end_inset
945
946     s = (char *)strpbrk(buffer[last_buf_line], " :");
947 \begin_inset Newline newline
948 \end_inset
949
950     if (s == NULL || *s == ' ')
951 \begin_inset Newline newline
952 \end_inset
953
954       continue; /* No gcc error found here */
955 \begin_inset Newline newline
956 \end_inset
957
958     do {
959 \begin_inset Newline newline
960 \end_inset
961
962       <<gcc error message criteria is to find a "...:999:" or a "...: ">>
963 \begin_inset Newline newline
964 \end_inset
965
966       /****** OK It is an error message, get line number */
967 \begin_inset Newline newline
968 \end_inset
969
970       err_line = atoi(s+1);
971 \begin_inset Newline newline
972 \end_inset
973
974       if (last_err_line == 0 || last_err_line == err_line) {
975 \begin_inset Newline newline
976 \end_inset
977
978         last_err_line = err_line;
979 \begin_inset Newline newline
980 \end_inset
981
982         continue; /* It's either a header or a continuation, don't output
983  yet */
984 \begin_inset Newline newline
985 \end_inset
986
987       }
988 \begin_inset Newline newline
989 \end_inset
990
991       /****** Completed the scan of one error message, output it to LyX
992  */
993 \begin_inset Newline newline
994 \end_inset
995
996       discharge_buffer(1);
997 \begin_inset Newline newline
998 \end_inset
999
1000       break;
1001 \begin_inset Newline newline
1002 \end_inset
1003
1004     } while (fgets(buffer[last_buf_line], 200, stdin));
1005 \begin_inset Newline newline
1006 \end_inset
1007
1008   }
1009 \begin_inset Newline newline
1010 \end_inset
1011
1012   /****** EOF completes the scan of whatever was being scanned */
1013 \begin_inset Newline newline
1014 \end_inset
1015
1016   discharge_buffer(0);
1017 \begin_inset Newline newline
1018 \end_inset
1019
1020 }
1021 \begin_inset Newline newline
1022 \end_inset
1023
1024 @
1025 \end_layout
1026
1027 \begin_layout Scrap
1028 <<gcc error message criteria is to find a "...:999:" or a "...: ">>=
1029 \begin_inset Newline newline
1030 \end_inset
1031
1032 /****** Search first ":" in the error number */
1033 \begin_inset Newline newline
1034 \end_inset
1035
1036 s = (char *)strpbrk(buffer[last_buf_line], " :");
1037 \begin_inset Newline newline
1038 \end_inset
1039
1040 last_buf_line++;
1041 \begin_inset Newline newline
1042 \end_inset
1043
1044 if (s == NULL || *s == ' ') 
1045 \begin_inset Newline newline
1046 \end_inset
1047
1048   <<No gcc error found here, but it might terminate the scanning of a previous
1049  one>>
1050 \begin_inset Newline newline
1051 \end_inset
1052
1053 /****** Search second ":" in the error number */
1054 \begin_inset Newline newline
1055 \end_inset
1056
1057 t = (char *)strpbrk(s+1, " :");
1058 \begin_inset Newline newline
1059 \end_inset
1060
1061 if (t == NULL || *t == ' ')
1062 \begin_inset Newline newline
1063 \end_inset
1064
1065   <<No gcc error found here, but it might terminate the scanning of a previous
1066  one>>
1067 \begin_inset Newline newline
1068 \end_inset
1069
1070 /****** Verify if is all digits between ":" */
1071 \begin_inset Newline newline
1072 \end_inset
1073
1074 if (t != s+1+strspn(s+1, "0123456789")) 
1075 \begin_inset Newline newline
1076 \end_inset
1077
1078   <<No gcc error found here, but it might terminate the scanning of a previous
1079  one>>
1080 \begin_inset Newline newline
1081 \end_inset
1082
1083 @
1084 \end_layout
1085
1086 \begin_layout Scrap
1087 <<No gcc error found here, but it might terminate the scanning of a previous
1088  one>>=
1089 \begin_inset Newline newline
1090 \end_inset
1091
1092 {
1093 \begin_inset Newline newline
1094 \end_inset
1095
1096   err_line = 0;
1097 \begin_inset Newline newline
1098 \end_inset
1099
1100   discharge_buffer(1);
1101 \begin_inset Newline newline
1102 \end_inset
1103
1104   continue;
1105 \begin_inset Newline newline
1106 \end_inset
1107
1108 }
1109 \begin_inset Newline newline
1110 \end_inset
1111
1112 @
1113 \end_layout
1114
1115 \begin_layout Standard
1116 As we mentioned, when the scan of one gcc error message is completed everything
1117  in the buffer except the last line is one single error message.
1118  But if the scan terminates with a EOF or through finding one line that
1119  does not match the gcc error message criteria, then there is no 
1120 \begin_inset Quotes eld
1121 \end_inset
1122
1123 last line
1124 \begin_inset Quotes erd
1125 \end_inset
1126
1127  in the buffer to be concerned with.
1128  In those cases we empty the buffer completely.
1129 \end_layout
1130
1131 \begin_layout Scrap
1132 <<Function bodies>>=
1133 \begin_inset Newline newline
1134 \end_inset
1135
1136 void
1137 \begin_inset Newline newline
1138 \end_inset
1139
1140 discharge_buffer (int save_last)
1141 \begin_inset Newline newline
1142 \end_inset
1143
1144 {
1145 \begin_inset Newline newline
1146 \end_inset
1147
1148  if (last_err_line != 0) { 
1149 \begin_inset Newline newline
1150 \end_inset
1151
1152    clean_gcc_messages();
1153 \begin_inset Newline newline
1154 \end_inset
1155
1156    if (save_last != 0) {
1157 \begin_inset Newline newline
1158 \end_inset
1159
1160       output_error(last_buf_line-1, last_err_line, "gcc");
1161 \begin_inset Newline newline
1162 \end_inset
1163
1164       strcpy (buffer[0], buffer[last_buf_line-1]);
1165 \begin_inset Newline newline
1166 \end_inset
1167
1168       last_err_line = err_line;
1169 \begin_inset Newline newline
1170 \end_inset
1171
1172       last_buf_line = 1;
1173 \begin_inset Newline newline
1174 \end_inset
1175
1176     } else { 
1177 \begin_inset Newline newline
1178 \end_inset
1179
1180       ++last_buf_line;
1181 \begin_inset Newline newline
1182 \end_inset
1183
1184       clean_gcc_messages();
1185 \begin_inset Newline newline
1186 \end_inset
1187
1188       output_error(last_buf_line-1, last_err_line, "gcc");
1189 \begin_inset Newline newline
1190 \end_inset
1191
1192       last_err_line = 0;
1193 \begin_inset Newline newline
1194 \end_inset
1195
1196       last_buf_line = 0;
1197 \begin_inset Newline newline
1198 \end_inset
1199
1200     }
1201 \begin_inset Newline newline
1202 \end_inset
1203
1204   }
1205 \begin_inset Newline newline
1206 \end_inset
1207
1208 }
1209 \begin_inset Newline newline
1210 \end_inset
1211
1212 @
1213 \end_layout
1214
1215 \begin_layout Scrap
1216 <<Function prototypes>>=
1217 \begin_inset Newline newline
1218 \end_inset
1219
1220 void discharge_buffer (int save_last);
1221 \begin_inset Newline newline
1222 \end_inset
1223
1224 @
1225 \end_layout
1226
1227 \begin_layout Standard
1228 The next function 
1229 \begin_inset Quotes eld
1230 \end_inset
1231
1232 cleans
1233 \begin_inset Quotes erd
1234 \end_inset
1235
1236  superfluous information from gcc messages, namely the name of the noweb
1237  file and the line number of the Error.
1238 \begin_inset Foot
1239 status collapsed
1240
1241 \begin_layout Plain Layout
1242 More could be done.
1243  For instance, some way of distinguishing between gcc Errors and Warnings
1244  should be devised.
1245 \end_layout
1246
1247 \end_inset
1248
1249
1250 \end_layout
1251
1252 \begin_layout Scrap
1253 <<Function bodies>>=
1254 \begin_inset Newline newline
1255 \end_inset
1256
1257 void
1258 \begin_inset Newline newline
1259 \end_inset
1260
1261 clean_gcc_messages ()
1262 \begin_inset Newline newline
1263 \end_inset
1264
1265 {
1266 \begin_inset Newline newline
1267 \end_inset
1268
1269   int index;
1270 \begin_inset Newline newline
1271 \end_inset
1272
1273   char search [30]; 
1274 \begin_inset Newline newline
1275 \end_inset
1276
1277   char *tail, *head; 
1278 \begin_inset Newline newline
1279 \end_inset
1280
1281   int search_len = sprintf(search, ".nw:%d:", last_err_line);
1282 \begin_inset Newline newline
1283 \end_inset
1284
1285   
1286 \begin_inset Newline newline
1287 \end_inset
1288
1289   for (index = 0; index < last_buf_line-1; index++) {
1290 \begin_inset Newline newline
1291 \end_inset
1292
1293     tail = (char *)strstr (buffer[index], search);
1294 \begin_inset Newline newline
1295 \end_inset
1296
1297     if ( tail == NULL) {
1298 \begin_inset Newline newline
1299 \end_inset
1300
1301        tail = (char *) strstr (buffer[index], ".nw:");
1302 \begin_inset Newline newline
1303 \end_inset
1304
1305        if (tail) {
1306 \begin_inset Newline newline
1307 \end_inset
1308
1309           tail += 4;
1310 \begin_inset Newline newline
1311 \end_inset
1312
1313        }
1314 \begin_inset Newline newline
1315 \end_inset
1316
1317     } else {
1318 \begin_inset Newline newline
1319 \end_inset
1320
1321        tail += search_len;
1322 \begin_inset Newline newline
1323 \end_inset
1324
1325     }
1326 \begin_inset Newline newline
1327 \end_inset
1328
1329     if (tail != NULL) {
1330 \begin_inset Newline newline
1331 \end_inset
1332
1333        head = buffer[index];
1334 \begin_inset Newline newline
1335 \end_inset
1336
1337        while (*(head++) = *(tail++));
1338 \begin_inset Newline newline
1339 \end_inset
1340
1341     }
1342 \begin_inset Newline newline
1343 \end_inset
1344
1345   }
1346 \begin_inset Newline newline
1347 \end_inset
1348
1349 }
1350 \begin_inset Newline newline
1351 \end_inset
1352
1353 @
1354 \end_layout
1355
1356 \begin_layout Scrap
1357 <<Function prototypes>>=
1358 \begin_inset Newline newline
1359 \end_inset
1360
1361 void clean_gcc_messages ();
1362 \begin_inset Newline newline
1363 \end_inset
1364
1365 @
1366 \end_layout
1367
1368 \begin_layout Standard
1369 To combine the scan of noweb error messages and xlc error messages is very
1370  simple.
1371  We just try each one for every input line:
1372 \end_layout
1373
1374 \begin_layout Scrap
1375 <<AIX system using both noweb and xlc>>=
1376 \begin_inset Newline newline
1377 \end_inset
1378
1379 {
1380 \begin_inset Newline newline
1381 \end_inset
1382
1383   last_buf_line = 0;
1384 \begin_inset Newline newline
1385 \end_inset
1386
1387   while (fgets(buffer[0], 200, stdin)) {
1388 \begin_inset Newline newline
1389 \end_inset
1390
1391     if (noweb_try(0))
1392 \begin_inset Newline newline
1393 \end_inset
1394
1395       output_error(1, err_line, "noweb");
1396 \begin_inset Newline newline
1397 \end_inset
1398
1399     else if (xlc_try(0))
1400 \begin_inset Newline newline
1401 \end_inset
1402
1403       output_error(1, err_line, "xlc");
1404 \begin_inset Newline newline
1405 \end_inset
1406
1407   }
1408 \begin_inset Newline newline
1409 \end_inset
1410
1411 }
1412 \begin_inset Newline newline
1413 \end_inset
1414
1415 @
1416 \end_layout
1417
1418 \begin_layout Standard
1419 To combine the scan of noweb error messages and gcc error messages is simple
1420  if we realize that it is not possible to find a noweb error message in
1421  the middle of a gcc error message.
1422  So we just repeat the gcc procedure and test for noweb error messages in
1423  the beginning of the scan:
1424 \end_layout
1425
1426 \begin_layout Scrap
1427 <<Solaris and Linux systems using both noweb and gcc>>=
1428 \begin_inset Newline newline
1429 \end_inset
1430
1431 {
1432 \begin_inset Newline newline
1433 \end_inset
1434
1435   char    *s, *t;
1436 \begin_inset Newline newline
1437 \end_inset
1438
1439  
1440 \begin_inset Newline newline
1441 \end_inset
1442
1443   last_buf_line = 0;
1444 \begin_inset Newline newline
1445 \end_inset
1446
1447   while (fgets(buffer[last_buf_line], 200, stdin)) {
1448 \begin_inset Newline newline
1449 \end_inset
1450
1451     /****** Skip lines until I find an error */
1452 \begin_inset Newline newline
1453 \end_inset
1454
1455     if (last_buf_line == 0 && noweb_try(0)) {
1456 \begin_inset Newline newline
1457 \end_inset
1458
1459       output_error(1, err_line, "noweb");
1460 \begin_inset Newline newline
1461 \end_inset
1462
1463       continue;
1464 \begin_inset Newline newline
1465 \end_inset
1466
1467     }
1468 \begin_inset Newline newline
1469 \end_inset
1470
1471     s = (char *)strpbrk(buffer[last_buf_line], " :");
1472 \begin_inset Newline newline
1473 \end_inset
1474
1475     if (s == NULL || *s == ' ')
1476 \begin_inset Newline newline
1477 \end_inset
1478
1479       continue; /* No gcc error found here */
1480 \begin_inset Newline newline
1481 \end_inset
1482
1483     do {
1484 \begin_inset Newline newline
1485 \end_inset
1486
1487       <<gcc error message criteria is to find a "...:999:" or a "...: ">>
1488 \begin_inset Newline newline
1489 \end_inset
1490
1491       /****** OK It is an error, get line number */
1492 \begin_inset Newline newline
1493 \end_inset
1494
1495       err_line = atoi(s+1);
1496 \begin_inset Newline newline
1497 \end_inset
1498
1499       if (last_err_line == 0 || last_err_line == err_line) {
1500 \begin_inset Newline newline
1501 \end_inset
1502
1503         last_err_line = err_line;
1504 \begin_inset Newline newline
1505 \end_inset
1506
1507         continue; /* It's either a header or a continuation, don't output
1508  yet */
1509 \begin_inset Newline newline
1510 \end_inset
1511
1512       }
1513 \begin_inset Newline newline
1514 \end_inset
1515
1516       /****** Completed the scan of one error message, output it to LyX
1517  */
1518 \begin_inset Newline newline
1519 \end_inset
1520
1521       discharge_buffer(1);
1522 \begin_inset Newline newline
1523 \end_inset
1524
1525       break;
1526 \begin_inset Newline newline
1527 \end_inset
1528
1529     } while (fgets(buffer[last_buf_line], 200, stdin));
1530 \begin_inset Newline newline
1531 \end_inset
1532
1533   }
1534 \begin_inset Newline newline
1535 \end_inset
1536
1537   /****** EOF completes the scan of whatever was being scanned */
1538 \begin_inset Newline newline
1539 \end_inset
1540
1541   discharge_buffer(0);
1542 \begin_inset Newline newline
1543 \end_inset
1544
1545 }
1546 \begin_inset Newline newline
1547 \end_inset
1548
1549 @
1550 \end_layout
1551
1552 \begin_layout Section
1553 Wrapping the code into a file
1554 \end_layout
1555
1556 \begin_layout Scrap
1557 <<listerrors.c>>=
1558 \begin_inset Newline newline
1559 \end_inset
1560
1561 #include <stdio.h>
1562 \begin_inset Newline newline
1563 \end_inset
1564
1565 #include <strings.h>       
1566 \begin_inset Newline newline
1567 \end_inset
1568
1569  
1570 \begin_inset Newline newline
1571 \end_inset
1572
1573 <<Global variables>>
1574 \begin_inset Newline newline
1575 \end_inset
1576
1577 <<Function prototypes>>
1578 \begin_inset Newline newline
1579 \end_inset
1580
1581 <<Function bodies>>
1582 \begin_inset Newline newline
1583 \end_inset
1584
1585 @
1586 \end_layout
1587
1588 \begin_layout Standard
1589 To build this program, we want to add the 
1590 \begin_inset Quotes eld
1591 \end_inset
1592
1593 -L
1594 \begin_inset Quotes erd
1595 \end_inset
1596
1597  option in the tangle command to force gdb to load the file 
1598 \family typewriter
1599 Literate.nw
1600 \family default
1601  instead of 
1602 \family typewriter
1603 listerrors.c
1604 \family default
1605 .
1606  In accordance with this, we pass the 
1607 \begin_inset Quotes eld
1608 \end_inset
1609
1610 -g
1611 \begin_inset Quotes erd
1612 \end_inset
1613
1614  option to gcc.
1615 \end_layout
1616
1617 \begin_layout Scrap
1618 <<build-script>>=
1619 \begin_inset Newline newline
1620 \end_inset
1621
1622 #!/bin/sh
1623 \begin_inset Newline newline
1624 \end_inset
1625
1626 if [ -z "$NOWEB_SOURCE" ]; then NOWEB_SOURCE=Literate.nw; fi
1627 \begin_inset Newline newline
1628 \end_inset
1629
1630 notangle -L -Rlisterrors.c ${NOWEB_SOURCE} > listerrors.c
1631 \begin_inset Newline newline
1632 \end_inset
1633
1634 gcc -g -o listerrors listerrors.c
1635 \begin_inset Newline newline
1636 \end_inset
1637
1638 @
1639 \end_layout
1640
1641 \begin_layout Standard
1642 This project can be tangled and compiled from LyX if you set 
1643 \family typewriter
1644
1645 \backslash
1646 build_command
1647 \family default
1648  to call a generic script that always extracts a scrap named 
1649 \family typewriter
1650 build-script
1651 \family default
1652  and executes it.
1653  Here is a example of such generic script:
1654 \end_layout
1655
1656 \begin_layout LyX-Code
1657 #!/bin/sh
1658 \begin_inset Newline newline
1659 \end_inset
1660
1661 notangle -Rbuild-script $1 | env NOWEB_SOURCE=$1 sh
1662 \end_layout
1663
1664 \begin_layout LyX-Code
1665
1666 \end_layout
1667
1668 \end_body
1669 \end_document