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