]> git.lyx.org Git - lyx.git/blob - lib/examples/Literate.lyx
- Spanish documentation updates by Ignacio
[lyx.git] / lib / examples / Literate.lyx
1 #LyX 1.5.0svn created this file. For more info see http://www.lyx.org/
2 \lyxformat 276
3 \begin_document
4 \begin_header
5 \textclass literate-article
6 \language english
7 \inputencoding default
8 \font_roman default
9 \font_sans default
10 \font_typewriter default
11 \font_default_family default
12 \font_sc false
13 \font_osf false
14 \font_sf_scale 100
15 \font_tt_scale 100
16 \graphics default
17 \paperfontsize default
18 \spacing single
19 \papersize default
20 \use_geometry false
21 \use_amsmath 0
22 \use_esint 0
23 \cite_engine basic
24 \use_bibtopic false
25 \paperorientation portrait
26 \secnumdepth 3
27 \tocdepth 3
28 \paragraph_separation indent
29 \defskip medskip
30 \quotes_language english
31 \papercolumns 1
32 \papersides 1
33 \paperpagestyle default
34 \tracking_changes false
35 \output_changes false
36 \end_header
37
38 \begin_body
39
40 \begin_layout Title
41
42 LyX and Literate Programming
43 \newline
44 An example program
45 \end_layout
46
47 \begin_layout Author
48
49 Edmar Wienskoski Jr.
50 \newline
51 edmar-w-jr@technologist.com
52 \begin_inset Foot
53 status collapsed
54
55 \begin_layout Standard
56
57 Modified by Bernard Michael Hurley bernardh@westherts.ac.uk ---- Don't blame
58  Edmar for any errors that have crept in!
59 \end_layout
60
61 \end_inset
62
63
64 \end_layout
65
66 \begin_layout Abstract
67
68
69 \series bold
70 Note:
71 \series default
72  This example program is provided for educational use only.
73  The functionality in this C program has been superceded by the equivalent
74  Python code in
75 \emph default
76  
77 \emph on
78 examples/listerrors.lyx
79 \emph default
80  which should be installed in the LyX scripts directory.
81 \end_layout
82
83 \begin_layout Date
84
85
86 \begin_inset ERT
87 status collapsed
88
89 \begin_layout Standard
90
91 \backslash
92 today
93 \end_layout
94
95 \end_inset
96
97
98 \end_layout
99
100 \begin_layout Standard
101
102
103 \begin_inset LatexCommand tableofcontents
104 \end_inset
105
106
107 \end_layout
108
109 \begin_layout Section
110
111 Introduction
112 \end_layout
113
114 \begin_layout Standard
115
116 After typesetting a document, LyX scans the LaTeX log file looking for errors.
117  For each error found, the line number is obtained and a error box is displayed
118  in the LyX screen at that position.
119 \end_layout
120
121 \begin_layout Standard
122
123 To use this feature to view compilation errors while working with literate
124  documents, we need a program that filters the compilation errors and puts
125  them in a format suitable for LyX reading it.
126  
127 \end_layout
128
129 \begin_layout Standard
130
131 In this document we present a filter that recognizes compilation error messages
132  from noweb, gnu C, and the IBM C compiler (xlc).
133 \end_layout
134
135 \begin_layout Standard
136
137 The filter is required to read from standard input, parse for error messages
138  and copy the error messages to the standard output.
139  During the output process, the filter must present the error messages in
140  a format that LyX can interpret, currently, the LaTeX error message format.
141  Of course, nothing will prevent future LyX releases from being able to
142  read other formats as well (like gcc error messages for example).
143  This mechanism is necessary to fully explore the literate programming tool's
144  capabilities.
145 \end_layout
146
147 \begin_layout Section
148
149 Algorithm
150 \end_layout
151
152 \begin_layout Scrap
153
154 <<Function bodies>>=
155 \newline
156 int
157 \newline
158 main (int argc, char **argv)
159 \newline
160 {
161 \newline
162   if (argc == 2) {
163 \newline
164     switch (argv[1][0]) {
165 \newline
166     case 'n':
167 \newline
168       <<Scan input for noweb error messages>>
169 \newline
170       break;
171 \newline
172     case 'x':
173 \newline
174       <<Scan input for xlc error messages>>
175 \newline
176       break;
177 \newline
178     case 'a':
179 \newline
180       <<AIX system using both noweb and xlc>>
181 \newline
182       break;
183 \newline
184     case 's':
185 \newline
186     case 'b':
187 \newline
188       <<Solaris and Linux systems using both noweb and gcc>>
189 \newline
190       break;
191 \newline
192     case 'g':
193 \newline
194     default:
195 \newline
196       <<Scan input for gcc error messages>>
197 \newline
198       break;
199 \newline
200     }
201 \newline
202   } else {
203 \newline
204     <<Scan input for gcc error messages>>
205 \newline
206   }
207 \newline
208 }
209 \newline
210 @
211 \end_layout
212
213 \begin_layout Scrap
214
215 <<Function prototypes>>=
216 \newline
217 int main (int argc, char **argv);
218 \newline
219 @
220 \end_layout
221
222 \begin_layout Section
223
224 Data Structures
225 \end_layout
226
227 \begin_layout Standard
228
229 We resort to some global variables to allow access from several different
230  routines.
231  These are the buffer and related pointers used during the parse of the
232  input.
233 \end_layout
234
235 \begin_layout Scrap
236
237 <<Global variables>>=
238 \newline
239 char    buffer[200][200];
240 \newline
241 int     last_buf_line;
242 \newline
243 int     last_err_line;
244 \newline
245 int     err_line;
246 \newline
247
248 \end_layout
249
250 \begin_layout Section
251
252 The output format
253 \end_layout
254
255 \begin_layout Standard
256
257 The output format mimics the TeX error messages format.
258  This function prints a number of lines residing in the global variable
259
260 \family default
261  
262 \family typewriter
263 buffer
264 \family default
265 , a program name and line number.
266  There is no special requirement on the input strings, they can be anything.
267 \begin_inset Foot
268 status collapsed
269
270 \begin_layout Standard
271
272 This function has been slightly changed from EW's original to make scanning
273  a bit easier with LaTeX::scanLogFile().
274  The test has been added because LyX can crash if empty lines are allowed
275  here --- I can't figure out why! --- BMH
276 \end_layout
277
278 \end_inset
279
280
281 \end_layout
282
283 \begin_layout Scrap
284
285 <<Function bodies>>=
286 \newline
287 void
288 \newline
289 output_error (int buf_size, int error_line, char *tool)
290 \newline
291 {
292 \newline
293   int     i;
294 \newline
295  
296 \newline
297   fprintf(stdout, "! Build Error: ==> %s ==>
298 \backslash
299 n", tool);
300 \newline
301   fprintf(stdout, " ...
302 \backslash
303 n
304 \backslash
305 nl.%d ...
306 \backslash
307 n", error_line);
308 \newline
309  
310 \newline
311   for (i=0; i<buf_size; i++)
312 \newline
313     if (strlen(buffer[i]) != 0)
314 \newline
315       fprintf(stdout, "%s", buffer[i]);
316 \newline
317  
318 \newline
319   fprintf(stdout, "
320 \backslash
321 n");
322 \newline
323 }
324 \newline
325 @
326 \end_layout
327
328 \begin_layout Scrap
329
330 <<Function prototypes>>=
331 \newline
332 void output_error (int buf_size, int error_line, char *tool);
333 \newline
334 @
335 \end_layout
336
337 \begin_layout Section
338
339 Functions Implementation
340 \end_layout
341
342 \begin_layout Standard
343
344 Both noweave and notangle routines, always output one single line for each
345  error found, thus to scan the buffer for noweb error messages is enough
346  to exam one input line at a time.
347  Note that the noweb software does not provide a line error number, so all
348  errors boxes related to noweb messages will be displayed at the beginning
349  of the file.
350 \end_layout
351
352 \begin_layout Scrap
353
354 <<Scan input for noweb error messages>>=
355 \newline
356 {
357 \newline
358   last_buf_line = 0;
359 \newline
360   while (fgets(buffer[0], 200, stdin)) {
361 \newline
362     if (noweb_try(0))
363 \newline
364       output_error(1, err_line, "noweb");
365 \newline
366   }
367 \newline
368 }
369 \newline
370 @
371 \end_layout
372
373 \begin_layout Standard
374
375 The examination itself is very inefficient.
376  Unfortunately noweb doesn't have any characteristic that would help to
377  identify one of its error messages.
378  The solution is to collect all possible output messages in an array of
379  strings, and turn the examination process into a linear search in this
380  array.
381 \end_layout
382
383 \begin_layout Scrap
384
385 <<Global variables>>=
386 \newline
387 char *noweb_msgs[] = {
388 \newline
389   "couldn't open file",
390 \newline
391   "couldn't open temporary file",
392 \newline
393   "error writing temporary file",
394 \newline
395   "ill-formed option",
396 \newline
397   "unknown option",
398 \newline
399   "Bad format sequence",
400 \newline
401   "Can't open output file",
402 \newline
403   "Can't open temporary file",
404 \newline
405   "Capacity exceeded:",
406 \newline
407   "Ignoring unknown option -",
408 \newline
409   "This can't happen:",
410 \newline
411   "non-numeric line number in"
412 \newline
413 };
414 \newline
415
416 \newline
417 char *noweb_msgs_mimic_gcc[] = {
418 \newline
419   ": unescaped << in documentation chunk"
420 \newline
421 };
422 \newline
423 @
424 \end_layout
425
426 \begin_layout Standard
427
428 A noweb error message can be any string that contains a matching pair of
429  < <\InsetSpace ~
430 \InsetSpace ~
431 \InsetSpace ~
432 > >, or any of the above strings
433 \end_layout
434
435 \begin_layout Scrap
436
437 <<Function bodies>>=
438 \newline
439 int
440 \newline
441 noweb_try (int buf_line)
442 \newline
443 {
444 \newline
445   char    *s, *t, *b;
446 \newline
447   int     i; 
448 \newline
449
450 \newline
451   b = buffer[buf_line];
452 \newline
453   err_line = 0;
454 \newline
455
456 \newline
457   for (i=0; i<1; i++) {
458 \newline
459       s = (char *)strstr (b, noweb_msgs_mimic_gcc[i]);
460 \newline
461       if (s != NULL) {
462 \newline
463         t = (char *)strchr(buffer[buf_line], ':');
464 \newline
465         err_line = atoi(t+1);
466 \newline
467         t = buffer[buf_line];
468 \newline
469         ++s;
470 \newline
471         while (*(t++) = *(s++));
472 \newline
473         return 1;
474 \newline
475       }
476 \newline
477   }
478 \newline
479   s = (char *)strstr(b, "<<");
480 \newline
481   if (s != NULL) {
482 \newline
483     s = (char *)strstr(s+2, ">>");
484 \newline
485     if (s != NULL) {
486 \newline
487       return 1;
488 \newline
489     }
490 \newline
491   } else { 
492 \newline
493      for (i = 0; i < 12; ++i) {
494 \newline
495         s = (char *)strstr (b, noweb_msgs[i]);
496 \newline
497         if (s != NULL) {
498 \newline
499            return 1;
500 \newline
501         }
502 \newline
503     }
504 \newline
505   }
506 \newline
507   return 0;
508 \newline
509 }
510 \newline
511 @
512 \end_layout
513
514 \begin_layout Scrap
515
516 <<Function prototypes>>=
517 \newline
518 int noweb_try (int buf_line);
519 \newline
520 @
521 \end_layout
522
523 \begin_layout Standard
524
525 The xlc compiler always outputs one single line for each error found, thus
526  to scan the buffer for xlc error messages it is enough to exam one input
527  line at a time.
528 \end_layout
529
530 \begin_layout Scrap
531
532 <<Scan input for xlc error messages>>= 
533 \newline
534 {
535 \newline
536   last_buf_line = 0;
537 \newline
538   while (fgets(buffer[last_buf_line], 200, stdin)) {
539 \newline
540     if (xlc_try(0))
541 \newline
542       output_error(1, err_line, "xlc");
543 \newline
544   }
545 \newline
546 }
547 \newline
548 @
549 \end_layout
550
551 \begin_layout Standard
552
553 A xlc error message is easy to identify.
554  Every error message starts with a quoted string with no spaces, a comma,
555  a space, the word 
556 \begin_inset Quotes eld
557 \end_inset
558
559 line
560 \begin_inset Quotes erd
561 \end_inset
562
563 , a space, and some variable text.
564  The following routine tests if a given buffer line matches this criteria:
565 \end_layout
566
567 \begin_layout Scrap
568
569 <<Function bodies>>=
570 \newline
571 int 
572 \newline
573 xlc_try (int buf_line)
574 \newline
575 {
576 \newline
577   char    *s, *t;
578 \newline
579  
580 \newline
581   t = buffer[buf_line];
582 \newline
583   s = t+1;
584 \newline
585   while (*s != '"' && *s != ' ' && *s != '
586 \backslash
587 0')
588 \newline
589     s++;
590 \newline
591   if (*t != '"' || *s != '"' || strncmp(s+1, ", line ", 7) != 0)
592 \newline
593     return 0;
594 \newline
595   s += 8;
596 \newline
597   err_line = atoi(s);
598 \newline
599   return 1;
600 \newline
601 }
602 \newline
603 @
604 \end_layout
605
606 \begin_layout Scrap
607
608 <<Function prototypes>>=
609 \newline
610 int xlc_try (int buf_line);
611 \newline
612 @
613 \end_layout
614
615 \begin_layout Standard
616
617 The gcc compiler error messages are more complicated to scan.
618  Each error can span more than one line in the buffer.
619  The good news is that every buffer line on each error has the same pattern,
620  and share the same line number.
621  Thus the strategy will be to accumulate lines in the buffer while the reported
622  line number is still the same.
623  At the time they differ, all the accumulated lines, except the last one,
624  will belong to one single error message, which now can be output-ed to
625  LyX.
626 \end_layout
627
628 \begin_layout Standard
629
630 Every gcc error message contains a string with no space followed by a 
631 \begin_inset Quotes eld
632 \end_inset
633
634 :
635 \begin_inset Quotes eld
636 \end_inset
637
638 .
639  If the next character is a space, then this line is a header of a error
640  message and the next line will detail the line number of the source code
641  where the error was found.
642  Otherwise, the next thing is a integer number followed by another 
643 \begin_inset Quotes eld
644 \end_inset
645
646 :
647 \begin_inset Quotes eld
648 \end_inset
649
650 .
651 \end_layout
652
653 \begin_layout Scrap
654
655 <<Scan input for gcc error messages>>=
656 \newline
657 {
658 \newline
659   char    *s, *t;
660 \newline
661  
662 \newline
663   last_buf_line = 0;
664 \newline
665   while (fgets(buffer[last_buf_line], 200, stdin)) {
666 \newline
667     /****** Skip lines until I find an error */
668 \newline
669     s = (char *)strpbrk(buffer[last_buf_line], " :");
670 \newline
671     if (s == NULL || *s == ' ')
672 \newline
673       continue; /* No gcc error found here */
674 \newline
675     do {
676 \newline
677       <<gcc error message criteria is to find a "...:999:" or a "...: ">>
678 \newline
679       /****** OK It is an error message, get line number */
680 \newline
681       err_line = atoi(s+1);
682 \newline
683       if (last_err_line == 0 || last_err_line == err_line) {
684 \newline
685         last_err_line = err_line;
686 \newline
687         continue; /* It's either a header or a continuation, don't output
688  yet */
689 \newline
690       }
691 \newline
692       /****** Completed the scan of one error message, output it to LyX
693  */
694 \newline
695       discharge_buffer(1);
696 \newline
697       break;
698 \newline
699     } while (fgets(buffer[last_buf_line], 200, stdin));
700 \newline
701   }
702 \newline
703   /****** EOF completes the scan of whatever was being scanned */
704 \newline
705   discharge_buffer(0);
706 \newline
707 }
708 \newline
709 @
710 \end_layout
711
712 \begin_layout Scrap
713
714 <<gcc error message criteria is to find a "...:999:" or a "...: ">>=
715 \newline
716 /****** Search first ":" in the error number */
717 \newline
718 s = (char *)strpbrk(buffer[last_buf_line], " :");
719 \newline
720 last_buf_line++;
721 \newline
722 if (s == NULL || *s == ' ') 
723 \newline
724   <<No gcc error found here, but it might terminate the scanning of a previous
725  one>>
726 \newline
727 /****** Search second ":" in the error number */
728 \newline
729 t = (char *)strpbrk(s+1, " :");
730 \newline
731 if (t == NULL || *t == ' ')
732 \newline
733   <<No gcc error found here, but it might terminate the scanning of a previous
734  one>>
735 \newline
736 /****** Verify if is all digits between ":" */
737 \newline
738 if (t != s+1+strspn(s+1, "0123456789")) 
739 \newline
740   <<No gcc error found here, but it might terminate the scanning of a previous
741  one>>
742 \newline
743 @
744 \end_layout
745
746 \begin_layout Scrap
747
748 <<No gcc error found here, but it might terminate the scanning of a previous
749  one>>=
750 \newline
751 {
752 \newline
753   err_line = 0;
754 \newline
755   discharge_buffer(1);
756 \newline
757   continue;
758 \newline
759 }
760 \newline
761 @
762 \end_layout
763
764 \begin_layout Standard
765
766 As we mentioned, when the scan of one gcc error message is completed everything
767  in the buffer except the last line is one single error message.
768  But if the scan terminates with a EOF or through finding one line that
769  does not match the gcc error message criteria, then there is no 
770 \begin_inset Quotes eld
771 \end_inset
772
773 last line
774 \begin_inset Quotes erd
775 \end_inset
776
777  in the buffer to be concerned with.
778  In those cases we empty the buffer completely.
779 \end_layout
780
781 \begin_layout Scrap
782
783 <<Function bodies>>=
784 \newline
785 void
786 \newline
787 discharge_buffer (int save_last)
788 \newline
789 {
790 \newline
791  if (last_err_line != 0) { 
792 \newline
793    clean_gcc_messages();
794 \newline
795    if (save_last != 0) {
796 \newline
797       output_error(last_buf_line-1, last_err_line, "gcc");
798 \newline
799       strcpy (buffer[0], buffer[last_buf_line-1]);
800 \newline
801       last_err_line = err_line;
802 \newline
803       last_buf_line = 1;
804 \newline
805     } else { 
806 \newline
807       ++last_buf_line;
808 \newline
809       clean_gcc_messages();
810 \newline
811       output_error(last_buf_line-1, last_err_line, "gcc");
812 \newline
813       last_err_line = 0;
814 \newline
815       last_buf_line = 0;
816 \newline
817     }
818 \newline
819   }
820 \newline
821 }
822 \newline
823 @
824 \end_layout
825
826 \begin_layout Scrap
827
828 <<Function prototypes>>=
829 \newline
830 void discharge_buffer (int save_last);
831 \newline
832 @
833 \end_layout
834
835 \begin_layout Standard
836
837 The next function 
838 \begin_inset Quotes eld
839 \end_inset
840
841 cleans
842 \begin_inset Quotes erd
843 \end_inset
844
845  superfluous information from gcc messages, namely the name of the noweb
846  file and the line number of the Error.
847 \begin_inset Foot
848 status collapsed
849
850 \begin_layout Standard
851
852 More could be done.
853  For instance, some way of distinguishing between gcc Errors and Warnings
854  should be devised.
855 \end_layout
856
857 \end_inset
858
859
860 \end_layout
861
862 \begin_layout Scrap
863
864 <<Function bodies>>=
865 \newline
866 void
867 \newline
868 clean_gcc_messages ()
869 \newline
870 {
871 \newline
872   int index;
873 \newline
874   char search [30]; 
875 \newline
876   char *tail, *head; 
877 \newline
878   int search_len = sprintf(search, ".nw:%d:", last_err_line);
879 \newline
880   
881 \newline
882   for (index = 0; index < last_buf_line-1; index++) {
883 \newline
884     tail = (char *)strstr (buffer[index], search);
885 \newline
886     if ( tail == NULL) {
887 \newline
888        tail = (char *) strstr (buffer[index], ".nw:");
889 \newline
890        if (tail) {
891 \newline
892           tail += 4;
893 \newline
894        }
895 \newline
896     } else {
897 \newline
898        tail += search_len;
899 \newline
900     }
901 \newline
902     if (tail != NULL) {
903 \newline
904        head = buffer[index];
905 \newline
906        while (*(head++) = *(tail++));
907 \newline
908     }
909 \newline
910   }
911 \newline
912 }
913 \newline
914 @
915 \end_layout
916
917 \begin_layout Scrap
918
919 <<Function prototypes>>=
920 \newline
921 void clean_gcc_messages ();
922 \newline
923 @
924 \end_layout
925
926 \begin_layout Standard
927
928 To combine the scan of noweb error messages and xlc error messages is very
929  simple.
930  We just try each one for every input line:
931 \end_layout
932
933 \begin_layout Scrap
934
935 <<AIX system using both noweb and xlc>>=
936 \newline
937 {
938 \newline
939   last_buf_line = 0;
940 \newline
941   while (fgets(buffer[0], 200, stdin)) {
942 \newline
943     if (noweb_try(0))
944 \newline
945       output_error(1, err_line, "noweb");
946 \newline
947     else if (xlc_try(0))
948 \newline
949       output_error(1, err_line, "xlc");
950 \newline
951   }
952 \newline
953 }
954 \newline
955 @
956 \end_layout
957
958 \begin_layout Standard
959
960 To combine the scan of noweb error messages and gcc error messages is simple
961  if we realize that it is not possible to find a noweb error message in
962  the middle of a gcc error message.
963  So we just repeat the gcc procedure and test for noweb error messages in
964  the beginning of the scan:
965 \end_layout
966
967 \begin_layout Scrap
968
969 <<Solaris and Linux systems using both noweb and gcc>>=
970 \newline
971 {
972 \newline
973   char    *s, *t;
974 \newline
975  
976 \newline
977   last_buf_line = 0;
978 \newline
979   while (fgets(buffer[last_buf_line], 200, stdin)) {
980 \newline
981     /****** Skip lines until I find an error */
982 \newline
983     if (last_buf_line == 0 && noweb_try(0)) {
984 \newline
985       output_error(1, err_line, "noweb");
986 \newline
987       continue;
988 \newline
989     }
990 \newline
991     s = (char *)strpbrk(buffer[last_buf_line], " :");
992 \newline
993     if (s == NULL || *s == ' ')
994 \newline
995       continue; /* No gcc error found here */
996 \newline
997     do {
998 \newline
999       <<gcc error message criteria is to find a "...:999:" or a "...: ">>
1000 \newline
1001       /****** OK It is an error, get line number */
1002 \newline
1003       err_line = atoi(s+1);
1004 \newline
1005       if (last_err_line == 0 || last_err_line == err_line) {
1006 \newline
1007         last_err_line = err_line;
1008 \newline
1009         continue; /* It's either a header or a continuation, don't output
1010  yet */
1011 \newline
1012       }
1013 \newline
1014       /****** Completed the scan of one error message, output it to LyX
1015  */
1016 \newline
1017       discharge_buffer(1);
1018 \newline
1019       break;
1020 \newline
1021     } while (fgets(buffer[last_buf_line], 200, stdin));
1022 \newline
1023   }
1024 \newline
1025   /****** EOF completes the scan of whatever was being scanned */
1026 \newline
1027   discharge_buffer(0);
1028 \newline
1029 }
1030 \newline
1031 @
1032 \end_layout
1033
1034 \begin_layout Section
1035
1036 Wrapping the code into a file
1037 \end_layout
1038
1039 \begin_layout Scrap
1040
1041 <<listerrors.c>>=
1042 \newline
1043 #include <stdio.h>
1044 \newline
1045 #include <strings.h>       
1046 \newline
1047  
1048 \newline
1049 <<Global variables>>
1050 \newline
1051 <<Function prototypes>>
1052 \newline
1053 <<Function bodies>>
1054 \newline
1055 @
1056 \end_layout
1057
1058 \begin_layout Standard
1059
1060 To build this program, we want to add the 
1061 \begin_inset Quotes eld
1062 \end_inset
1063
1064 -L
1065 \begin_inset Quotes erd
1066 \end_inset
1067
1068  option in the tangle command to force gdb to load the file
1069 \family default
1070  
1071 \family typewriter
1072 Literate.nw
1073 \family default
1074  instead of
1075 \family default
1076  
1077 \family typewriter
1078 listerrors.c
1079 \family default
1080 .
1081  In accordance with this, we pass the 
1082 \begin_inset Quotes eld
1083 \end_inset
1084
1085 -g
1086 \begin_inset Quotes erd
1087 \end_inset
1088
1089  option to gcc.
1090 \end_layout
1091
1092 \begin_layout Scrap
1093
1094 <<build-script>>=
1095 \newline
1096 #!/bin/sh
1097 \newline
1098 if [ -z "$NOWEB_SOURCE" ]; then NOWEB_SOURCE=Literate.nw; fi
1099 \newline
1100 notangle -L -Rlisterrors.c ${NOWEB_SOURCE} > listerrors.c
1101 \newline
1102 gcc -g -o listerrors listerrors.c
1103 \newline
1104 @
1105 \end_layout
1106
1107 \begin_layout Standard
1108
1109 This project can be tangled and compiled from LyX if you set
1110 \family default
1111  
1112 \family typewriter
1113
1114 \backslash
1115 build_command
1116 \family default
1117  to call a generic script that always extracts a scrap named
1118 \family default
1119  
1120 \family typewriter
1121 build-script
1122 \family default
1123  and executes it.
1124  Here is a example of such generic script:
1125 \end_layout
1126
1127 \begin_layout LyX-Code
1128
1129 #!/bin/sh
1130 \newline
1131 notangle -Rbuild-script $1 | env NOWEB_SOURCE=$1 sh
1132 \end_layout
1133
1134 \begin_layout LyX-Code
1135
1136 \end_layout
1137
1138 \end_body
1139 \end_document