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