@q Changes for CWEB in TeX Live from numerous contributors. @> @q This file is in the Public Domain. @> @q Most of the original Kpathsea changes by Wlodek Bzyl and Olaf Weber @> @q were merged with the set of change files of the CWEBbin project; @> @q see https://github.com/ascherer/cwebbin for the original parts. @> @q This stripped change file {comm,ctang,cweav,ctwill,cwebman}-w2c.ch @> @q has been created from the elaborate set of change files @> @q {comm,ctang,cweav,cwebman}-patch.ch, @> @q {comm,cweav,cwebman}-extensions.ch, {comm,ctang,cweav}-output.ch, @> @q {comm,ctang,cweav}-i18n.ch, and cweav-twill.ch for CTWILL, and @> @q {comm,ctang,cweav,ctwill,cwebman}-texlive.ch with the 'tie' processor @> @q and is used as a monolithic changefile for {common,ctangle,cweave}.w @> @q and cwebman.tex in TeX Live. @> @q Please send comments, suggestions, etc. to tex-k@@tug.org. @> @x \def\title{CWEAVE (Version 4.5)} @y \def\title{CWEAVE (Version 4.5 [\TeX~Live])} @z @x \centerline{(Version 4.5)} @y \centerline{(Version 4.5 [\TeX~Live])} @z @x \def\botofcontents{\vfill @y \def\covernote{\vbox{% @z @x } @y }}\datecontentspage @z @x @d banner "This is CWEAVE (Version 4.5)" @y @d banner "This is CWEAVE, Version 4.5" /* will be extended by the \TeX~Live |versionstring| */ @z @x if (show_banner) puts(banner); /* print a ``banner line'' */ @y if (show_banner) cb_show_banner(); /* print a ``banner line'' */ @z @x @i common.h @y @i comm-w2c.h @z @x @d max_refs 20000 /* number of cross-references; must be less than 65536 */ @d max_scraps 2000 /* number of tokens in \CEE/ texts being parsed */ @y @d max_refs 65535 /* number of cross-references; must be less than 65536 */ @d max_scraps 5000 /* number of tokens in \CEE/ texts being parsed */ @z @x @d append_xref(c) if (xref_ptr==xmem_end) overflow("cross-reference"); @y @d append_xref(c) if (xref_ptr==xmem_end) overflow(_("cross-reference")); @z @x @d max_toks 20000 /* number of symbols in \CEE/ texts being parsed; must be less than 65536 */ @d max_texts 4000 /* number of phrases in \CEE/ texts being parsed; must be less than 10240 */ @y @d max_toks 65535 /* number of symbols in \CEE/ texts being parsed; must be less than 65536 */ @d max_texts 10239 /* number of phrases in \CEE/ texts being parsed; must be less than 10240 */ @z @x err_print("! String didn't end"); loc=limit; break; @y err_print(_("! String didn't end")); loc=limit; break; @z @x err_print("! Input ended in middle of string"); loc=buffer; break; @y err_print(_("! Input ended in middle of string")); loc=buffer; break; @z @x fputs("\n! String too long: ",stdout); @y fputs(_("\n! String too long: "),stdout); @z @x case translit_code: err_print("! Use @@l in limbo only"); continue; @y case translit_code: err_print(_("! Use @@l in limbo only")); continue; @z @x err_print("! Input ended in section name"); @y err_print(_("! Input ended in section name")); @z @x fputs("\n! Section name too long: ",stdout); @y fputs(_("\n! Section name too long: "),stdout); @z @x err_print("! Section name didn't end"); break; @y err_print(_("! Section name didn't end")); break; @z @x err_print("! Control codes are forbidden in section name"); break; @y err_print(_("! Control codes are forbidden in section name")); break; @z @x err_print("! Control text didn't end"); loc=limit; @y err_print(_("! Control text didn't end")); loc=limit; @z @x err_print("! Control codes are forbidden in control text"); @y err_print(_("! Control codes are forbidden in control text")); @z @x if (loc>=limit) err_print("! Verbatim string didn't end"); @y if (loc>=limit) err_print(_("! Verbatim string didn't end")); @z @x if (++section_count==max_sections) overflow("section number"); @y if (++section_count==max_sections) overflow(_("section number")); @z @x case translit_code: err_print("! Use @@l in limbo only"); continue; @y case translit_code: err_print(_("! Use @@l in limbo only")); continue; @z @x err_print("! Missing left identifier of @@s"); @y err_print(_("! Missing left identifier of @@s")); @z @x err_print("! Missing right identifier of @@s"); @y err_print(_("! Missing right identifier of @@s")); @z @x fputs("\n! Never defined: <",stdout); print_section_name(p); putchar('>'); mark_harmless; @y fputs(_("\n! Never defined: <"),stdout); print_section_name(p); putchar('>'); mark_harmless; @z @x fputs("\n! Never used: <",stdout); print_section_name(p); putchar('>'); mark_harmless; @y fputs(_("\n! Never used: <"),stdout); print_section_name(p); putchar('>'); mark_harmless; @z @x @ In particular, the |finish_line| procedure is called near the very beginning of phase two. We initialize the output variables in a slightly tricky way so that the first line of the output file will be `\.{\\input cwebmac}'. @= out_ptr=out_buf+1; out_line=1; active_file=tex_file; tex_printf("\\input cwebma"); *out_ptr='c'; @y @ In particular, the |finish_line| procedure is called near the very beginning of phase two. We initialize the output variables in a slightly tricky way so that the first line of the output file will be dependent of the user language set by the `\.{+l}' option and its argument. If you call \.{CWEAVE} with `\.{+lX}' (or `\.{-lX}' as well), where `\.X' is the (possibly empty) string of characters to the right of~`\.l', `\.X'~will be prepended to `\.{cwebmac.tex}', e.g., if you call \.{CWEAVE} with `\.{+ldeutsch}', you will receive the line `\.{\\input deutschcwebmac}'. Without this option the first line of the output file will be `\.{\\input cwebmac}'. @= out_ptr=out_buf+1; out_line=1; active_file=tex_file; tex_puts("\\input "); tex_printf(use_language); tex_puts("cwebma"); *out_ptr='c'; @z @x printf("\n! Line had to be broken (output l. %d):\n",out_line); @y printf(_("\n! Line had to be broken (output l. %d):\n"),out_line); @z @x default: err_print("! Double @@ should be used in limbo"); @y default: err_print(_("! Double @@ should be used in limbo")); @z @x @d app_tok(c) {if (tok_ptr+2>tok_mem_end) overflow("token"); *(tok_ptr++)=c;} @y @d app_tok(c) {if (tok_ptr+2>tok_mem_end) overflow(_("token")); *(tok_ptr++)=c;} @z @x err_print("! Input ended in mid-comment"); @y err_print(_("! Input ended in mid-comment")); @z @x if (bal>1) err_print("! Missing } in comment"); @y if (bal>1) err_print(_("! Missing } in comment")); @z @x else {err_print("! Extra } in comment"); @y else {err_print(_("! Extra } in comment")); @z @x if (bal>1) err_print("! Missing } in comment"); @y if (bal>1) err_print(_("! Missing } in comment")); @z @x err_print("! Illegal use of @@ in comment"); @y err_print(_("! Illegal use of @@ in comment")); @z @x @i prod.w @y @i prod-cweave.w @z @x @d inner_tok_flag (5*id_flag) /* signifies a token list in `\pb' */ @c static void print_text( /* prints a token list for debugging; not used in |main| */ @y @d inner_tok_flag (5*id_flag) /* signifies a token list in `\pb' */ @= #if 0 static void print_text(text_pointer p); #endif @ @c #if 0 @t\4\4@>static void print_text( /* prints a token list for debugging; not used in |main| */ @z @x } @y } #endif @z @x @ @=@+static void print_text(text_pointer p); @y @z @x @= if (cat1==lbrace || cat1==int_like || cat1==decl) { make_underlined(pp); big_app1(pp); big_app(dindent); reduce(pp,1,fn_decl,0,1); } @y @= if(cat1==lbrace || cat1==int_like || cat1==decl) { make_underlined(pp); big_app1(pp); if (indent_param_decl) big_app(dindent); reduce(pp,1,fn_decl,0,1); } @z @x @ @= if (cat1==comma) { big_app2(pp); big_app(' '); reduce(pp,2,decl_head,-1,33); } else if (cat1==ubinop) { big_app1_insert(pp,'{'); big_app('}'); reduce(pp,2,decl_head,-1,34); } else if (cat1==exp && cat2!=lpar && cat2!=lbrack && cat2!=exp && cat2!=cast) { make_underlined(pp+1); squash(pp,2,decl_head,-1,35); } else if ((cat1==binop||cat1==colon) && cat2==exp && (cat3==comma || cat3==semi || cat3==rpar)) squash(pp,3,decl_head,-1,36); else if (cat1==cast) squash(pp,2,decl_head,-1,37); else if (cat1==lbrace || cat1==int_like || cat1==decl) { big_app(dindent); squash(pp,1,fn_decl,0,38); } else if (cat1==semi) squash(pp,2,decl,-1,39); @y @ @= if (cat1==comma) { big_app2(pp); big_app(' '); reduce(pp,2,decl_head,-1,33); } else if (cat1==ubinop) { big_app1_insert(pp,'{'); big_app('}'); reduce(pp,2,decl_head,-1,34); } else if (cat1==exp && cat2!=lpar && cat2!=lbrack && cat2!=exp && cat2!=cast) { make_underlined(pp+1); squash(pp,2,decl_head,-1,35); } else if ((cat1==binop||cat1==colon) && cat2==exp && (cat3==comma || cat3==semi || cat3==rpar)) squash(pp,3,decl_head,-1,36); else if (cat1==cast) squash(pp,2,decl_head,-1,37); else if (cat1==lbrace || cat1==int_like || cat1==decl) { if (indent_param_decl) big_app(dindent); squash(pp,1,fn_decl,0,38); } else if (cat1==semi) squash(pp,2,decl,-1,39); @z @x @ @= if (cat1==decl) { big_app1_insert(pp,force); reduce(pp,2,decl,-1,40); } else if (cat1==stmt || cat1==function) { big_app1_insert(pp,big_force); reduce(pp,2,cat1,-1,41); } @y @ @= if (cat1==decl) { big_app1_insert(pp,force); reduce(pp,2,decl,-1,40); } else if (cat1==stmt || cat1==function) { big_app1_insert(pp,order_decl_stmt ? big_force : force); reduce(pp,2,cat1,-1,41); } @z @x @ @= if (cat1==decl) { big_app1_insert(pp,force); reduce(pp,2,fn_decl,0,51); } else if (cat1==stmt) { big_app1(pp); app(outdent); app(outdent); big_app(force); big_app1(pp+1); reduce(pp,2,function,-1,52); } @y @ @= if (cat1==decl) { big_app1_insert(pp,force); reduce(pp,2,fn_decl,0,51); } else if (cat1==stmt) { big_app1(pp); if (indent_param_decl) { app(outdent); app(outdent); } big_app(force); big_app1(pp+1); reduce(pp,2,function,-1,52); } @z @x big_app1_insert(pp,dindent); reduce(pp,2,fn_decl,0,73); @y big_app1(pp); if (indent_param_decl) big_app(dindent); big_app1(pp+1); reduce(pp,2,fn_decl,0,73); @z @x big_app1_insert(pp, (cat1==function || cat1==decl) ? big_force : force_lines ? force : break_space); reduce(pp,2,cat1,-1,76); @y big_app1_insert(pp, (cat1==function || cat1==decl) ? @| ( order_decl_stmt ? big_force : force ) : @| ( force_lines ? force : break_space ) ); reduce(pp,2,cat1,-1,76); @z @x overflow("token"); @y overflow(_("token")); @z @x overflow("text"); @y overflow(_("text")); @z @x if (tok_ptr+6>tok_mem_end) overflow("token"); @y if (tok_ptr+6>tok_mem_end) overflow(_("token")); @z @x printf("\nIrreducible scrap sequence in section %d:",(int)section_count); @y printf(_("\nIrreducible scrap sequence in section %d:"),(int)section_count); @z @x printf("\nTracing after l. %d:\n",cur_line); mark_harmless; @y printf(_("\nTracing after l. %d:\n"),cur_line); mark_harmless; @z @x overflow("scrap/token/text"); @y overflow(_("scrap/token/text")); @z @x else err_print("! Double @@ should be used in strings"); @y else err_print(_("! Double @@ should be used in strings")); @z @x if (next_control!='|') err_print("! Missing '|' after C text"); @y if (next_control!='|') err_print(_("! Missing '|' after C text")); @z @x if (stack_ptr==stack_end) overflow("stack"); @y if (stack_ptr==stack_end) overflow(_("stack")); @z @x fputs("\n! Illegal control code in section name: <",stdout); @y fputs(_("\n! Illegal control code in section name: <"),stdout); @z @x fputs("\n! C text in section name didn't end: <",stdout); @y fputs(_("\n! C text in section name didn't end: <"),stdout); @z @x if (j>buffer+long_buf_size-3) overflow("buffer"); @y if (j>buffer+long_buf_size-3) overflow(_("buffer")); @z @x if (j>buffer+long_buf_size-4) overflow("buffer"); @y if (j>buffer+long_buf_size-4) overflow(_("buffer")); @z @x if (show_progress) fputs("\nWriting the output file...",stdout); @y if (show_progress) fputs(_("\nWriting the output file..."),stdout); @z @x err_print("! TeX string should be in C text only"); break; @y err_print(_("! TeX string should be in C text only")); break; @z @x err_print("! You can't do that in TeX text"); break; @y err_print(_("! You can't do that in TeX text")); break; @z @x err_print("! Improper macro definition"); @y err_print(_("! Improper macro definition")); @z @x default: err_print("! Improper macro definition"); break; @y default: err_print(_("! Improper macro definition")); break; @z @x if (scrap_ptr!=scrap_info+2) err_print("! Improper format definition"); @y if (scrap_ptr!=scrap_info+2) err_print(_("! Improper format definition")); @z @x err_print("! You need an = sign after the section name"); @y err_print(_("! You need an = sign after the section name")); @z @x err_print("! You can't do that in C text"); @y err_print(_("! You can't do that in C text")); @z @x if (no_xref) { finish_line(); out_str("\\end"); @.\\end@> finish_line(); } @y if (no_xref) { finish_line(); out_str("\\end"); @.\\end@> active_file=tex_file; } @z @x phase=3; if (show_progress) fputs("\nWriting the index...",stdout); @y phase=3; if (show_progress) fputs(_("\nWriting the index..."),stdout); @z @x fatal("! Cannot open index file ",idx_file_name); @y fatal(_("! Cannot open index file "),idx_file_name); @z @x fatal("! Cannot open section file ",scn_file_name); @y fatal(_("! Cannot open section file "),scn_file_name); @z @x @.\\end@> finish_line(); fclose(active_file); } @y @.\\end@> } finish_line(); fclose(active_file); active_file=NULL; @@; @z @x fputs("Done.",stdout); @y fputs(_("Done."),stdout); @z @x if (sort_ptr>=scrap_info_end) overflow("sorting"); @y if (sort_ptr>=scrap_info_end) overflow(_("sorting")); @z @x puts("\nMemory usage statistics:"); @.Memory usage statistics:@> printf("%td names (out of %ld)\n", (ptrdiff_t)(name_ptr-name_dir),(long)max_names); printf("%td cross-references (out of %ld)\n", (ptrdiff_t)(xref_ptr-xmem),(long)max_refs); printf("%td bytes (out of %ld)\n", (ptrdiff_t)(byte_ptr-byte_mem),(long)max_bytes); puts("Parsing:"); printf("%td scraps (out of %ld)\n", (ptrdiff_t)(max_scr_ptr-scrap_info),(long)max_scraps); printf("%td texts (out of %ld)\n", (ptrdiff_t)(max_text_ptr-tok_start),(long)max_texts); printf("%td tokens (out of %ld)\n", (ptrdiff_t)(max_tok_ptr-tok_mem),(long)max_toks); printf("%td levels (out of %ld)\n", (ptrdiff_t)(max_stack_ptr-stack),(long)stack_size); puts("Sorting:"); printf("%td levels (out of %ld)\n", (ptrdiff_t)(max_sort_ptr-scrap_info),(long)max_scraps); @y puts(_("\nMemory usage statistics:")); @.Memory usage statistics:@> printf(_("%td names (out of %ld)\n"), (ptrdiff_t)(name_ptr-name_dir),(long)max_names); printf(_("%td cross-references (out of %ld)\n"), (ptrdiff_t)(xref_ptr-xmem),(long)max_refs); printf(_("%td bytes (out of %ld)\n"), (ptrdiff_t)(byte_ptr-byte_mem),(long)max_bytes); puts(_("Parsing:")); printf(_("%td scraps (out of %ld)\n"), (ptrdiff_t)(max_scr_ptr-scrap_info),(long)max_scraps); printf(_("%td texts (out of %ld)\n"), (ptrdiff_t)(max_text_ptr-tok_start),(long)max_texts); printf(_("%td tokens (out of %ld)\n"), (ptrdiff_t)(max_tok_ptr-tok_mem),(long)max_toks); printf(_("%td levels (out of %ld)\n"), (ptrdiff_t)(max_stack_ptr-stack),(long)stack_size); puts(_("Sorting:")); printf(_("%td levels (out of %ld)\n"), (ptrdiff_t)(max_sort_ptr-scrap_info),(long)max_scraps); @z @x @** Index. @y @** Extensions to {\tentex CWEB}. The following sections introduce new or improved features that have been created by numerous contributors over the course of a quarter century. Care has been taken to keep the original section numbering intact, so this new material should nicely integrate with the original ``\&{271.~Index}.'' @* Formatting alternatives. \.{CWEAVE} indents declarations after old-style function definitions and long parameter lists of modern function definitions. With the \.{-i} option they will come out flush left. @d indent_param_decl flags['i'] /* should formal parameter declarations be indented? */ @= indent_param_decl=true; @ The original manual described the \.{-o} option for \.{CWEAVE}, but this was not yet present. Here is a simple implementation. The purpose is to suppress the extra space between local variable declarations and the first statement in a function block. @d order_decl_stmt flags['o'] /* should declarations and statements be separated? */ @= order_decl_stmt=true; @* Output file update. Most \CEE/ projects are controlled by a \.{Makefile} that automatically takes care of the temporal dependecies between the different source modules. It is suitable that \.{CWEB} doesn't create new output for all existing files, when there are only changes to some of them. Thus the \.{make} process will only recompile those modules where necessary. The idea and basic implementation of this mechanism can be found in the program \.{NUWEB} by Preston Briggs, to whom credit is due. @= if((tex_file=fopen(tex_file_name,"r"))!=NULL) { boolean comparison=false; if((check_file=fopen(check_file_name,"r"))==NULL) fatal(_("! Cannot open output file "),check_file_name); @.Cannot open output file@> if (check_for_change) @@; fclose(tex_file); tex_file=NULL; fclose(check_file); check_file=NULL; @@; } else rename(check_file_name,tex_file_name); /* This was the first run */ strcpy(check_file_name,""); /* We want to get rid of the temporary file */ @ We hope that this runs fast on most systems. @= do { char x[BUFSIZ],y[BUFSIZ]; int x_size = fread(x,sizeof(char),BUFSIZ,tex_file); int y_size = fread(y,sizeof(char),BUFSIZ,check_file); comparison = (x_size == y_size) && !memcmp(x,y,x_size); } while(comparison && !feof(tex_file) && !feof(check_file)); @ Note the superfluous call to |remove| before |rename|. We're using it to get around a bug in some implementations of |rename|. @= if(comparison) remove(check_file_name); /* The output remains untouched */ else { remove(tex_file_name); rename(check_file_name,tex_file_name); } @* Print ``version'' information. Don't do this at home, kids! Push our local macro to the variable in \.{COMMON} for printing the |banner| and the |versionstring| from there. @d max_banner 50 @= extern char cb_banner[]; @ @= strncpy(cb_banner,banner,max_banner-1); @** Index. @z