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