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