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