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