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