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