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