diff options
Diffstat (limited to 'Build/source/texk/web2c/cwebdir/common.w')
-rw-r--r-- | Build/source/texk/web2c/cwebdir/common.w | 583 |
1 files changed, 236 insertions, 347 deletions
diff --git a/Build/source/texk/web2c/cwebdir/common.w b/Build/source/texk/web2c/cwebdir/common.w index d8aacfb7b91..79083985c6a 100644 --- a/Build/source/texk/web2c/cwebdir/common.w +++ b/Build/source/texk/web2c/cwebdir/common.w @@ -2,7 +2,7 @@ % This program by Silvio Levy and Donald E. Knuth % is based on a program by Knuth. % It is distributed WITHOUT ANY WARRANTY, express or implied. -% Version 3.64 --- January 2002 +% Version 4.0 --- February 2021 % Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth @@ -15,14 +15,19 @@ % entire resulting derived work is given a different name and distributed % under the terms of a permission notice identical to this one. +% Amendments to 'common.w' resulting in this updated version were created +% by numerous collaborators over the course of many years. + +% Please send comments, suggestions, etc. to tex-k@@tug.org. + \def\v{\char'174} % vertical (|) in typewriter font -\def\title{Common code for CTANGLE and CWEAVE (Version 3.64)} +\def\title{Common code for CTANGLE and CWEAVE (Version 4.0)} \def\topofcontents{\null\vfill \centerline{\titlefont Common code for {\ttitlefont CTANGLE} and {\ttitlefont CWEAVE}} \vskip 15pt - \centerline{(Version 3.64)} + \centerline{(Version 4.0)} \vfill} \def\botofcontents{\vfill \noindent @@ -41,7 +46,10 @@ under the terms of a permission notice identical to this one. \pageno=\contentspagenumber \advance\pageno by 1 \let\maybe=\iftrue -@s not_eq normal @q unreserve a C++ keyword @> + +@s boolean int +@s uint8_t int +@s uint16_t int @** Introduction. This file contains code common to both \.{CTANGLE} and \.{CWEAVE}, which roughly concerns the following @@ -58,20 +66,23 @@ The file begins with a few basic definitions. @c @<Include files@>@/ @h -@<Definitions that should agree with \.{CTANGLE} and \.{CWEAVE}@>@/ -@<Other definitions@>@/ +@<Common code for \.{CWEAVE} and \.{CTANGLE}@>@/ +@<Global variables@>@/ @<Predeclaration of procedures@>@/ +@ The details will be filled in due course. The interface of this module +is included first. It is also used by the main programs. + +First comes general stuff: + +@i common.h + @ In certain cases \.{CTANGLE} and \.{CWEAVE} should do almost, but not quite, the same thing. In these cases we've written common code for both, differentiating between the two by means of the global variable |program|. -@d ctangle 0 -@d cweave 1 - -@<Definitions...@>= -typedef short boolean; +@<Global var...@>= boolean program; /* \.{CWEAVE} or \.{CTANGLE}? */ @ \.{CWEAVE} operates in three phases: First it inputs the source @@ -80,7 +91,7 @@ produces the \TEX/ output file, and finally it sorts and outputs the index. Similarly, \.{CTANGLE} operates in two phases. The global variable |phase| tells which phase we are in. -@<Other...@>= int phase; /* which phase are we in? */ +@<Global var...@>= int phase; /* which phase are we in? */ @ There's an initialization procedure that gets both \.{CTANGLE} and \.{CWEAVE} off to a good start. We will fill in the details of this @@ -88,29 +99,26 @@ procedure later. @c void -common_init() +common_init(void) { - @<Initialize pointers@>; - @<Set the default options common to \.{CTANGLE} and \.{CWEAVE}@>; - @<Scan arguments and open output files@>; + @<Initialize pointers@>@; + @<Set the default options common to \.{CTANGLE} and \.{CWEAVE}@>@; + @<Scan arguments and open output files@>@; } @* The character set. \.{CWEB} uses the conventions of \CEE/ programs found in the standard \.{ctype.h} header file. -@<Include files@>= -#include <ctype.h> - -@ A few character pairs are encoded internally as single characters, -using the definitions below. These definitions are consistent with -an extension of ASCII code originally developed at MIT and explained in -Appendix~C of {\sl The \TEX/book\/}; thus, users who have such a -character set can type things like \.{\char'32} and \.{\char'4} instead -of \.{!=} and \.{\&\&}. (However, their files will not be too portable -until more people adopt the extended code.) +A few character pairs are encoded internally as single characters, +using the definitions in the interface sections above. These definitions +are consistent with an extension of ASCII code originally developed at +MIT and explained in Appendix~C of {\sl The \TEX/book\/}; thus, users +who have such a character set can type things like \.{\char'32} and +\.{\char'4} instead of \.{!=} and \.{\&\&}. (However, their files will +not be too portable until more people adopt the extended code.) -If the character set is not ASCII, the definitions given here may conflict +If the character set is not ASCII, the definitions given may conflict with existing characters; in such cases, other arbitrary codes should be substituted. The indexes to \.{CTANGLE} and \.{CWEAVE} mention every case where similar codes may have to be changed in order to @@ -120,21 +128,11 @@ in those indexes. @^ASCII code dependencies@> @^system dependencies@> -@d and_and 04 /* `\.{\&\&}'\,; corresponds to MIT's {\tentex\char'4} */ -@d lt_lt 020 /* `\.{<<}'\,; corresponds to MIT's {\tentex\char'20} */ -@d gt_gt 021 /* `\.{>>}'\,; corresponds to MIT's {\tentex\char'21} */ -@d plus_plus 013 /* `\.{++}'\,; corresponds to MIT's {\tentex\char'13} */ -@d minus_minus 01 /* `\.{--}'\,; corresponds to MIT's {\tentex\char'1} */ -@d minus_gt 031 /* `\.{->}'\,; corresponds to MIT's {\tentex\char'31} */ -@d not_eq 032 /* `\.{!=}'\,; corresponds to MIT's {\tentex\char'32} */ -@d lt_eq 034 /* `\.{<=}'\,; corresponds to MIT's {\tentex\char'34} */ -@d gt_eq 035 /* `\.{>=}'\,; corresponds to MIT's {\tentex\char'35} */ -@d eq_eq 036 /* `\.{==}'\,; corresponds to MIT's {\tentex\char'36} */ -@d or_or 037 /* `\.{\v\v}'\,; corresponds to MIT's {\tentex\char'37} */ -@d dot_dot_dot 016 /* `\.{...}'\,; corresponds to MIT's {\tentex\char'16} */ -@d colon_colon 06 /* `\.{::}'\,; corresponds to MIT's {\tentex\char'6} */ -@d period_ast 026 /* `\.{.*}'\,; corresponds to MIT's {\tentex\char'26} */ -@d minus_gt_ast 027 /* `\.{->*}'\,; corresponds to MIT's {\tentex\char'27} */ +@<Global var...@>= +char section_text[longest_name+1]; /* text being sought for */ +char *section_text_end = section_text+longest_name; /* end of |section_text| */ +char *id_first; /* where the current identifier begins in the buffer */ +char *id_loc; /* just after the current identifier in the buffer */ @** Input routines. The lowest level of input to the \.{CWEB} programs is performed by |input_ln|, which must be told which file to read from. @@ -150,28 +148,22 @@ Since |buf_size| is strictly less than |long_buf_size|, some of \.{CWEB}'s routines use the fact that it is safe to refer to |*(limit+2)| without overstepping the bounds of the array. -@d buf_size 100 /* for \.{CWEAVE} and \.{CTANGLE} */ -@d longest_name 10000 -@d long_buf_size (buf_size+longest_name) /* for \.{CWEAVE} */ -@d xisspace(c) (isspace(c)&&((unsigned char)c<0200)) -@d xisupper(c) (isupper(c)&&((unsigned char)c<0200)) - -@<Definitions...@>= +@<Global var...@>= char buffer[long_buf_size]; /* where each line of input goes */ char *buffer_end=buffer+buf_size-2; /* end of |buffer| */ char *limit=buffer; /* points to the last character in the buffer */ char *loc=buffer; /* points to the next character to be read from the buffer */ -@ @<Include files@>= -#include <stdio.h> - @ In the unlikely event that your standard I/O library does not support |feof|, |getc|, and |ungetc| you may have to change things here. @^system dependencies@> -@c -int input_ln(fp) /* copies a line into |buffer| or returns 0 */ -FILE *fp; /* what file to read from */ +@<Predecl...@>= +static boolean input_ln(FILE *);@/ + +@ @c +static boolean input_ln(@t\1\1@> /* copies a line into |buffer| or returns 0 */ +FILE *fp@t\2\2@>) /* what file to read from */ { register int c=EOF; /* character read; initialized so some compilers won't complain */ register char *k; /* where next character goes */ @@ -183,7 +175,7 @@ FILE *fp; /* what file to read from */ if ((c=getc(fp))!=EOF && c!='\n') { ungetc(c,fp); loc=buffer; err_print("! Input line too long"); @.Input line too long@> - } + } if (c==EOF && limit==buffer) return(0); /* there was nothing after the last newline */ return(1); @@ -201,17 +193,7 @@ from the |change_file|. The line number of each open file is also kept for error reporting and for the benefit of \.{CTANGLE}. -@f line x /* make |line| an unreserved word */ -@d max_include_depth 10 /* maximum number of source files open - simultaneously, not counting the change file */ -@d max_file_name_length 60 -@d cur_file file[include_depth] /* current file */ -@d cur_file_name file_name[include_depth] /* current file name */ -@d cur_line line[include_depth] /* number of current line in current file */ -@d web_file file[0] /* main source file */ -@d web_file_name file_name[0] /* main source file name */ - -@<Definitions...@>= +@<Global var...@>= int include_depth; /* current level of nesting */ FILE *file[max_include_depth]; /* stack of non-change files */ FILE *change_file; /* change file */ @@ -234,10 +216,10 @@ so that no further matches will be made. Here's a shorthand expression for inequality between the two lines: -@d lines_dont_match (change_limit-change_buffer != limit-buffer || - strncmp(buffer, change_buffer, limit-buffer)) +@d lines_dont_match (change_limit-change_buffer != limit-buffer || @| + strncmp(buffer, change_buffer, (size_t)(limit-buffer))) -@<Other...@>= +@<Global var...@>= char change_buffer[buf_size]; /* next line of |change_file| */ char *change_limit; /* points to the last character in |change_buffer| */ @@ -248,14 +230,17 @@ Since blank lines in the change file are not used for matching, we have the change file is exhausted. This procedure is called only when |changing| is 1; hence error messages will be reported correctly. -@c -void -prime_the_change_buffer() +@<Predecl...@>= +static void prime_the_change_buffer(void);@/ + +@ @c +static void +prime_the_change_buffer(void) { change_limit=change_buffer; /* this value is used if the change file ends */ - @<Skip over comment lines in the change file; |return| if end of file@>; - @<Skip to the next nonblank line; |return| if end of file@>; - @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>; + @<Skip over comment lines in the change file; |return| if end of file@>@; + @<Skip to the next nonblank line; |return| if end of file@>@; + @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>@; } @ While looking for a line that begins with \.{@@x} in the change file, we @@ -268,7 +253,7 @@ while(1) { if (!input_ln(change_file)) return; if (limit<buffer+2) continue; if (buffer[0]!='@@') continue; - if (xisupper(buffer[1])) buffer[1]=tolower(buffer[1]); + if (xisupper(buffer[1])) buffer[1]=tolower((eight_bits)buffer[1]); if (buffer[1]=='x') break; if (buffer[1]=='y' || buffer[1]=='z' || buffer[1]=='i') { loc=buffer+2; @@ -291,8 +276,8 @@ do { @ @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>= { - change_limit=change_buffer+(limit-buffer); - strncpy(change_buffer,buffer,limit-buffer+1); + change_limit=change_buffer+(ptrdiff_t)(limit-buffer); + strncpy(change_buffer,buffer,(size_t)(limit-buffer+1)); } @ The following procedure is used to see if the next change entry should @@ -317,9 +302,12 @@ current line is nonempty. if (*loc=='@@' && (xisspace(*(loc+1)) || *(loc+1)=='*')) change_pending=b; } -@c -void -check_change() /* switches to |change_file| if the buffers match */ +@<Predecl...@>= +static void check_change(void);@/ + +@ @c +static void +check_change(void) /* switches to |change_file| if the buffers match */ { int n=0; /* the number of discrepancies found */ if (lines_dont_match) return; @@ -337,11 +325,11 @@ check_change() /* switches to |change_file| if the buffers match */ return; } if (limit>buffer+1 && buffer[0]=='@@') { - char xyz_code=xisupper(buffer[1])? tolower(buffer[1]): buffer[1]; + char xyz_code=xisupper(buffer[1])? tolower((eight_bits)buffer[1]): buffer[1]; @<If the current line starts with \.{@@y}, - report any discrepancies and |return|@>; + report any discrepancies and |return|@>@; } - @<Move |buffer| and |limit|...@>; + @<Move |buffer| and |limit|...@>@; changing=0; cur_line++; while (!input_ln(cur_file)) { /* pop the stack or quit */ if (include_depth==0) { @@ -377,10 +365,10 @@ phases one and two of \.{CWEAVE}. @c void -reset_input() +reset_input(void) { limit=buffer; loc=buffer+1; buffer[0]=' '; - @<Open input files@>; + @<Open input files@>@; include_depth=0; cur_line=0; change_line=0; change_depth=include_depth; changing=1; prime_the_change_buffer(); changing=!changing; @@ -412,11 +400,7 @@ If we've just changed from the |cur_file| to the |change_file|, or if the |cur_file| has changed, we tell \.{CTANGLE} to print this information in the \CEE/ file by means of the |print_where| flag. -@d max_sections 2000 /* number of identifiers, strings, section names; - must be less than 10240 */ - -@<Defin...@>= -typedef unsigned short sixteen_bits; +@<Global var...@>= sixteen_bits section_count; /* the current section number */ boolean changed_section[max_sections]; /* is the section changed? */ boolean change_pending; /* if the current change is not yet recorded in @@ -424,13 +408,13 @@ boolean change_pending; /* if the current change is not yet recorded in boolean print_where=0; /* should \.{CTANGLE} print line and file info? */ @ @c -int get_line() /* inputs the next line */ +boolean get_line(void) /* inputs the next line */ { restart: if (changing && include_depth==change_depth) - @<Read from |change_file| and maybe turn off |changing|@>; + @<Read from |change_file| and maybe turn off |changing|@>@; if (! changing || include_depth>change_depth) { - @<Read from |cur_file| and maybe turn on |changing|@>; + @<Read from |cur_file| and maybe turn on |changing|@>@; if (changing && include_depth==change_depth) goto restart; } if (input_has_ended) return 0; @@ -449,7 +433,7 @@ int get_line() /* inputs the next line */ goto restart; } include_depth++; /* push input stack */ - @<Try to open include file, abort push if unsuccessful, go to |restart|@>; + @<Try to open include file, abort push if unsuccessful, go to |restart|@>@; } return 1; } @@ -468,10 +452,7 @@ The remainder of the \.{@@i} line after the file name is ignored. @d too_long() {include_depth--; err_print("! Include file name too long"); goto restart;} -@<Include...@>= -#include <stdlib.h> /* declaration of |getenv| and |exit| */ - -@ @<Try to open...@>= { +@.CWEBINPUTS@>@<Try to open...@>= { char temp_file_name[max_file_name_length]; char *cur_file_name_end=cur_file_name+max_file_name_length-1; char *k=cur_file_name, *kk; @@ -550,7 +531,7 @@ The remainder of the \.{@@i} line after the file name is ignored. } *limit=' '; if (buffer[0]=='@@') { - if (xisupper(buffer[1])) buffer[1]=tolower(buffer[1]); + if (xisupper(buffer[1])) buffer[1]=tolower((eight_bits)buffer[1]); if (buffer[1]=='x' || buffer[1]=='y') { loc=buffer+2; err_print("! Where is the matching @@z?"); @@ -568,10 +549,10 @@ had a line that didn't match any relevant line in |web_file|. @c void -check_complete(){ +check_complete(void) { if (change_limit!=change_buffer) { /* |changing| is 0 */ - strncpy(buffer,change_buffer,change_limit-change_buffer+1); - limit=buffer+(int)(change_limit-change_buffer); + strncpy(buffer,change_buffer,(size_t)(change_limit-change_buffer+1)); + limit=buffer+(ptrdiff_t)(change_limit-change_buffer); changing=1; change_depth=include_depth; loc=buffer; err_print("! Change file entry did not match"); @.Change file entry did not match@> @@ -584,37 +565,50 @@ other strings in a large array of |char|s, called |byte_mem|. Information about the names is kept in the array |name_dir|, whose elements are structures of type |name_info|, containing a pointer into the |byte_mem| array (the address where the name begins) and other data. -A |name_pointer| variable is a pointer into |name_dir|. - -@d max_bytes 90000 /* the number of bytes in identifiers, - index entries, and section names; must be less than $2^{24}$ */ -@d max_names 4000 /* number of identifiers, strings, section names; - must be less than 10240 */ - -@<Definitions that...@>= -typedef struct name_info { - char *byte_start; /* beginning of the name in |byte_mem| */ - @<More elements of |name_info| structure@>@; -} name_info; /* contains information about an identifier or section name */ -typedef name_info *name_pointer; /* pointer into array of |name_info|s */ +A |name_pointer| variable is a pointer into |name_dir|. You find the +complete layout of |name_info| in the interface sections above. + +The actual sequence of characters in the name pointed to by a |name_pointer +p| appears in positions |p->byte_start| to |(p+1)->byte_start-1|, inclusive. + +The names of identifiers are found by computing a hash address |h| and +then looking at strings of bytes signified by the |name_pointer|s +|hash[h]|, |hash[h]->link|, |hash[h]->link->link|, \dots, +until either finding the desired name or encountering the null pointer. + +The names of sections are stored in |byte_mem| together +with the identifier names, but a hash table is not used for them because +\.{CTANGLE} needs to be able to recognize a section name when given a prefix of +that name. A conventional binary search tree is used to retrieve section names, +with fields called |llink| and |rlink| (where |llink| takes the place +of |link|). The root of this tree is stored in |name_dir->rlink|; +this will be the only information in |name_dir[0]|. + +Since the space used by |rlink| has a different function for +identifiers than for section names, we declare it as a |union|. + +The last component of |name_info| is different for \.{CTANGLE} and +\.{CWEAVE}. In \.{CTANGLE}, if |p| is a pointer to a section name, +|p->equiv| is a pointer to its replacement text, an element of the +array |text_info|. In \.{CWEAVE}, on the other hand, if +|p| points to an identifier, |p->xref| is a pointer to its +list of cross-references, an element of the array |xmem|. The make-up +of |text_info| and |xmem| is discussed in the \.{CTANGLE} and \.{CWEAVE} +source files, respectively; here we just declare a common field +|equiv_or_xref| as a pointer to |void|. + +@<Global var...@>= char byte_mem[max_bytes]; /* characters of names */ char *byte_mem_end = byte_mem+max_bytes-1; /* end of |byte_mem| */ name_info name_dir[max_names]; /* information about names */ name_pointer name_dir_end = name_dir+max_names-1; /* end of |name_dir| */ -@ The actual sequence of characters in the name pointed to by a |name_pointer -p| appears in positions |p->byte_start| to |(p+1)->byte_start-1|, inclusive. -The |print_id| macro prints this text on the user's terminal. - -@d length(c) (c+1)->byte_start-(c)->byte_start /* the length of a name */ -@d print_id(c) term_write((c)->byte_start,length((c))) /* print identifier */ - @ The first unused position in |byte_mem| and |name_dir| is kept in |byte_ptr| and |name_ptr|, respectively. Thus we usually have |name_ptr->byte_start==byte_ptr|, and certainly we want to keep |name_ptr<=name_dir_end| and |byte_ptr<=byte_mem_end|. -@<Defini...@>= +@<Global var...@>= name_pointer name_ptr; /* first unused position in |name_dir| */ char *byte_ptr; /* first unused position in |byte_mem| */ @@ -622,14 +616,7 @@ char *byte_ptr; /* first unused position in |byte_mem| */ name_dir->byte_start=byte_ptr=byte_mem; /* position zero in both arrays */ name_ptr=name_dir+1; /* |name_dir[0]| will be used only for error recovery */ name_ptr->byte_start=byte_mem; /* this makes name 0 of length zero */ - -@ The names of identifiers are found by computing a hash address |h| and -then looking at strings of bytes signified by the |name_pointer|s -|hash[h]|, |hash[h]->link|, |hash[h]->link->link|, \dots, -until either finding the desired name or encountering the null pointer. - -@<More elements of |name...@>= -struct name_info *link; +root=NULL; /* the binary search tree starts out with nothing in it */ @ The hash table itself consists of |hash_size| entries of type |name_pointer|, and is @@ -639,17 +626,13 @@ function |names_match|, which is slightly different in \.{CWEAVE} and \.{CTANGLE}. If there is no match for the identifier, it is inserted into the table. -@d hash_size 353 /* should be prime */ +@d hash_size 8501 /* should be prime */ -@<Defini...@>= -typedef name_pointer *hash_pointer; +@<Global var...@>= name_pointer hash[hash_size]; /* heads of hash lists */ hash_pointer hash_end = hash+hash_size-1; /* end of |hash| */ hash_pointer h; /* index into hash-head array */ -@ @<Predec...@>= -extern int names_match(); - @ Initially all the hash lists are empty. @<Init...@>= @@ -659,20 +642,20 @@ for (h=hash; h<=hash_end; *h++=NULL) ; @c name_pointer -id_lookup(first,last,t) /* looks up a string in the identifier table */ -char *first; /* first character of string */ -char *last; /* last character of string plus one */ -char t; /* the |ilk|; used by \.{CWEAVE} only */ +id_lookup(@t\1\1@> /* looks up a string in the identifier table */ +const char *first, /* first character of string */ +const char *last, /* last character of string plus one */ +char t@t\2\2@>) /* the |ilk|; used by \.{CWEAVE} only */ { - char *i=first; /* position in |buffer| */ + const char *i=first; /* position in |buffer| */ int h; /* hash code */ int l; /* length of the given identifier */ name_pointer p; /* where the identifier is being sought */ if (last==NULL) for (last=first; *last!='\0'; last++); - l=last-first; /* compute the length */ - @<Compute the hash code |h|@>; - @<Compute the name location |p|@>; - if (p==name_ptr) @<Enter a new name into the table at position |p|@>; + l=(int)(last-first); /* compute the length */ + @<Compute the hash code |h|@>@; + @<Compute the name location |p|@>@; + if (p==name_ptr) @<Enter a new name into the table at position |p|@>@; return(p); } @@ -681,8 +664,8 @@ character codes is $c_1c_2\ldots c_n$, its hash value will be $$(2^{n-1}c_1+2^{n-2}c_2+\cdots+c_n)\,\bmod\,|hash_size|.$$ @<Compute the hash...@>= -h=(unsigned char)*i; -while (++i<last) h=(h+h+(int)((unsigned char)*i)) % hash_size; +h=(eight_bits)*i; +while (++i<last) h=(h+h+(int)((eight_bits)*i)) % hash_size; @^high-bit character handling@> @ If the identifier is new, it will be placed in position |p=name_ptr|, @@ -699,44 +682,14 @@ if (p==NULL) { @ The information associated with a new identifier must be initialized in a slightly different way in \.{CWEAVE} than in \.{CTANGLE}; hence the |init_p| procedure. - -@<Pred...@>= -void init_p(); - -@ @<Enter a new name...@>= { +@<Enter a new name...@>= { if (byte_ptr+l>byte_mem_end) overflow("byte memory"); if (name_ptr>=name_dir_end) overflow("name"); strncpy(byte_ptr,first,l); (++name_ptr)->byte_start=byte_ptr+=l; - if (program==cweave) init_p(p,t); + init_p(p,t); } -@ The names of sections are stored in |byte_mem| together -with the identifier names, but a hash table is not used for them because -\.{CTANGLE} needs to be able to recognize a section name when given a prefix of -that name. A conventional binary search tree is used to retrieve section names, -with fields called |llink| and |rlink| (where |llink| takes the place -of |link|). The root of this tree is stored in |name_dir->rlink|; -this will be the only information in |name_dir[0]|. - -Since the space used by |rlink| has a different function for -identifiers than for section names, we declare it as a |union|. - -@d llink link /* left link in binary search tree for section names */ -@d rlink dummy.Rlink /* right link in binary search tree for section names */ -@d root name_dir->rlink /* the root of the binary search tree - for section names */ - -@<More elements of |name...@>= -union { - struct name_info *Rlink; /* right link in binary search tree for section - names */ - char Ilk; /* used by identifiers in \.{CWEAVE} only */ -} dummy; - -@ @<Init...@>= -root=NULL; /* the binary search tree starts out with nothing in it */ - @ If |p| is a |name_pointer| variable, as we have seen, |p->byte_start| is the beginning of the area where the name corresponding to |p| is stored. However, if |p| refers to a section @@ -756,24 +709,24 @@ to additional chunks in the same way. Null links are represented by |name_dir|. @d first_chunk(p) ((p)->byte_start+2) -@d prefix_length(p) (int)((unsigned char)*((p)->byte_start)*256 + - (unsigned char)*((p)->byte_start+1)) +@d prefix_length(p) (int)((eight_bits)*((p)->byte_start)*256 + + (eight_bits)*((p)->byte_start+1)) @d set_prefix_length(p,m) (*((p)->byte_start)=(m)/256, *((p)->byte_start+1)=(m)%256) @c void -print_section_name(p) -name_pointer p; +print_section_name( +name_pointer p) { char *ss, *s = first_chunk(p); name_pointer q = p+1; while (p!=name_dir) { ss = (p+1)->byte_start-1; if (*ss==' ' && ss>=s) { - term_write(s,ss-s); p=q->link; q=p; + term_write(s,(size_t)(ss-s)); p=q->link; q=p; } else { - term_write(s,ss+1-s); p=name_dir; q=NULL; + term_write(s,(size_t)(ss+1-s)); p=name_dir; q=NULL; } s = p->byte_start; } @@ -782,9 +735,9 @@ name_pointer p; @ @c void -sprint_section_name(dest,p) - char*dest; - name_pointer p; +sprint_section_name( + char *dest, + name_pointer p) { char *ss, *s = first_chunk(p); name_pointer q = p+1; @@ -795,7 +748,7 @@ sprint_section_name(dest,p) } else { ss++; p=name_dir; } - strncpy(dest,s,ss-s), dest+=ss-s; + strncpy(dest,s,(size_t)(ss-s)), dest+=ss-s; s = p->byte_start; } *dest='\0'; @@ -803,8 +756,8 @@ sprint_section_name(dest,p) @ @c void -print_prefix_name(p) -name_pointer p; +print_prefix_name( +name_pointer p) { char *s = first_chunk(p); int l = prefix_length(p); @@ -822,10 +775,17 @@ are null-terminated, and we keep an eye open for prefixes and extensions. @d prefix 3 /* the first name is a proper prefix of the second */ @d extension 4 /* the first name is a proper extension of the second */ -@c -int web_strcmp(j,j_len,k,k_len) /* fuller comparison than |strcmp| */ - char *j, *k; /* beginning of first and second strings */ - int j_len, k_len; /* length of strings */ +@<Predecl...@>= +static int web_strcmp(char *,int,char *,int);@/ +static name_pointer add_section_name(name_pointer,int,char *,char *,int);@/ +static void extend_section_name(name_pointer,char *,char *,int);@/ + +@ @c +static int web_strcmp(@t\1\1@> /* fuller comparison than |strcmp| */ + char *j, /* beginning of first string */ + int j_len, /* length of first string */ + char *k, /* beginning of second string */ + int k_len@t\2\2@>) /* length of second string */ { char *j1=j+j_len, *k1=k+k_len; while (k<k1 && j<j1 && *j==*k) k++, j++; @@ -849,21 +809,18 @@ differently in \.{CWEAVE} and \.{CTANGLE}; hence the |init_node| procedure, which is defined differently in \.{cweave.w} and \.{ctangle.w}. -@<Prede...@>= -extern void init_node(); - -@ @c -name_pointer -add_section_name(par,c,first,last,ispref) /* install a new node in the tree */ -name_pointer par; /* parent of new node */ -int c; /* right or left? */ -char *first; /* first character of section name */ -char *last; /* last character of section name, plus one */ -int ispref; /* are we adding a prefix or a full name? */ +@c +static name_pointer +add_section_name(@t\1\1@> /* install a new node in the tree */ +name_pointer par, /* parent of new node */ +int c, /* right or left? */ +char *first, /* first character of section name */ +char *last, /* last character of section name, plus one */ +int ispref@t\2\2@>) /* are we adding a prefix or a full name? */ { name_pointer p=name_ptr; /* new node */ char *s=first_chunk(p); - int name_len=last-first+ispref; /* length of section name */ + int name_len=(int)(last-first)+ispref; /* length of section name */ if (s+name_len>byte_mem_end) overflow("byte memory"); if (name_ptr+1>=name_dir_end) overflow("name"); (++name_ptr)->byte_start=byte_ptr=s+name_len; @@ -882,16 +839,16 @@ int ispref; /* are we adding a prefix or a full name? */ } @ @c -void -extend_section_name(p,first,last,ispref) -name_pointer p; /* name to be extended */ -char *first; /* beginning of extension text */ -char *last; /* one beyond end of extension text */ -int ispref; /* are we adding a prefix or a full name? */ +static void +extend_section_name(@t\1\1@> +name_pointer p, /* name to be extended */ +char *first, /* beginning of extension text */ +char *last, /* one beyond end of extension text */ +int ispref@t\2\2@>) /* are we adding a prefix or a full name? */ { char *s; name_pointer q=p+1; - int name_len=last-first+ispref; + int name_len=(int)(last-first)+ispref; if (name_ptr>=name_dir_end) overflow("name"); while (q->link!=name_dir) q=q->link; q->link=name_ptr; @@ -911,9 +868,9 @@ exactly equals or is a prefix or extension of a name in the tree. @c name_pointer -section_lookup(first,last,ispref) /* find or install section name in tree */ -char *first, *last; /* first and last characters of new name */ -int ispref; /* is the new name a prefix or a full name? */ +section_lookup(@t\1\1@> /* find or install section name in tree */ +char *first,char *last, /* first and last characters of new name */ +int ispref@t\2\2@>) /* is the new name a prefix or a full name? */ { int c=0; /* comparison between two names; initialized so some compilers won't complain */ name_pointer p=root; /* current node of the search tree */ @@ -921,11 +878,11 @@ int ispref; /* is the new name a prefix or a full name? */ name_pointer r=NULL; /* where a match has been found */ name_pointer par=NULL; /* parent of |p|, if |r| is |NULL|; otherwise parent of |r| */ - int name_len=last-first+1; + int name_len=(int)(last-first)+1; @<Look for matches for new name among shortest prefixes, complaining - if more than one is found@>; - @<If no match found, add new name to tree@>; - @<If one match found, check for compatibility and return match@>; + if more than one is found@>@; + @<If no match found, add new name to tree@>@; + @<If one match found, check for compatibility and return match@>@; } @ A legal new name matches an existing section name if and only if it @@ -942,10 +899,10 @@ while (p) { /* compare shortest prefix of |p| with new name */ p=(c==less?p->llink:p->rlink); } else { /* new name matches |p| */ if (r!=NULL) { /* and also |r|: illegal */ - printf("\n! Ambiguous prefix: matches <"); + fputs("\n! Ambiguous prefix: matches <",stdout); @.Ambiguous prefix ... @> print_prefix_name(p); - printf(">\n and <"); + fputs(">\n and <",stdout); print_prefix_name(r); err_print(">"); return name_dir; /* the unsection */ @@ -971,7 +928,7 @@ switch(section_name_cmp(&first,name_len,r)) { /* compare all of |r| with new name */ case prefix: if (!ispref) { - printf("\n! New name is a prefix of <"); + fputs("\n! New name is a prefix of <",stdout); @.New name is a prefix...@> print_section_name(r); err_print(">"); @@ -983,16 +940,16 @@ switch(section_name_cmp(&first,name_len,r)) { extend_section_name(r,first,last+1,ispref); return r; case bad_extension: - printf("\n! New name extends <"); + fputs("\n! New name extends <",stdout); @.New name extends...@> print_section_name(r); err_print(">"); return r; default: /* no match: illegal */ - printf("\n! Section name incompatible with <"); + fputs("\n! Section name incompatible with <",stdout); @.Section name incompatible...@> print_prefix_name(r); - printf(">,\n which abbreviates <"); + fputs(">,\n which abbreviates <",stdout); print_section_name(r); err_print(">"); return r; @@ -1015,13 +972,13 @@ us to regard \.{@@<foo...@@>} as an ``extension'' of itself. @d bad_extension 5 @<Predec...@>= -int section_name_cmp(); +static int section_name_cmp(char **,int,name_pointer);@/ @ @c -int section_name_cmp(pfirst,len,r) -char **pfirst; /* pointer to beginning of comparison string */ -int len; /* length of string */ -name_pointer r; /* section name being compared */ +static int section_name_cmp(@t\1\1@> +char **pfirst, /* pointer to beginning of comparison string */ +int len, /* length of string */ +name_pointer r@t\2\2@>) /* section name being compared */ { char *first=*pfirst; /* beginning of comparison string */ name_pointer q=r+1; /* access to subsequent chunks */ @@ -1035,33 +992,20 @@ name_pointer r; /* section name being compared */ switch(c=web_strcmp(first,len,s,ss-s)) { case equal: if (q==name_dir) if (ispref) { - *pfirst=first+(ss-s); + *pfirst=first+(ptrdiff_t)(ss-s); return extension; /* null extension */ } else return equal; else return (q->byte_start==(q+1)->byte_start)? equal: prefix; case extension: if (!ispref) return bad_extension; first += ss-s; - if (q!=name_dir) {len -= ss-s; s=q->byte_start; r=q; continue;} + if (q!=name_dir) {len -= (int)(ss-s); s=q->byte_start; r=q; continue;} *pfirst=first; return extension; default: return c; } } } -@ The last component of |name_info| is different for \.{CTANGLE} and -\.{CWEAVE}. In \.{CTANGLE}, if |p| is a pointer to a section name, -|p->equiv| is a pointer to its replacement text, an element of the -array |text_info|. In \.{CWEAVE}, on the other hand, if -|p| points to an identifier, |p->xref| is a pointer to its -list of cross-references, an element of the array |xmem|. The make-up -of |text_info| and |xmem| is discussed in the \.{CTANGLE} and \.{CWEAVE} -source files, respectively; here we just declare a common field -|equiv_or_xref| as a pointer to a |char|. - -@<More elements of |name...@>= -char *equiv_or_xref; /* info corresponding to names */ - @** Reporting errors to the user. A global variable called |history| will contain one of four values at the end of every run: |spotless| means that no unusual messages were @@ -1072,14 +1016,7 @@ terminated abnormally. The value of |history| does not influence the behavior of the program; it is simply computed for the convenience of systems that might want to use such information. -@d spotless 0 /* |history| value for normal jobs */ -@d harmless_message 1 /* |history| value when non-serious info was printed */ -@d error_message 2 /* |history| value when an error was noted */ -@d fatal_message 3 /* |history| value when we had to stop prematurely */ -@d mark_harmless {if (history==spotless) history=harmless_message;} -@d mark_error history=error_message - -@<Definit...@>= +@<Global var...@>= int history=spotless; /* indicates how bad this run was */ @ The command `|err_print("! Error message")|' will report a syntax error to @@ -1089,17 +1026,14 @@ Note that no period follows the error message, since the error routine will automatically supply a period. A newline is automatically supplied if the string begins with |"!"|. -@<Predecl...@>= -void err_print(); - -@ @c +@c void -err_print(s) /* prints `\..' and location of error message */ -char *s; +err_print(@t\1\1@> /* prints `\..' and location of error message */ +const char *s@t\2\2@>) { char *k,*l; /* pointers into |buffer| */ printf(*s=='!'? "\n%s" : "%s",s); - if(web_file_open) @<Print error location based on input buffer@>; + if(web_file_open) @<Print error location based on input buffer@>@; update_terminal; mark_error; } @@ -1135,52 +1069,46 @@ up and quit as graciously as possible. This is done by calling the function |wrap_up| at the end of the code. \.{CTANGLE} and \.{CWEAVE} have their own notions about how to -print the job statistics. - -@<Prede...@>= -int wrap_up(); -extern void print_stats(); +print the job statistics. See the function(s) |print_stats| in the +interface above and in the index. -@ Some implementations may wish to pass the |history| value to the +Some implementations may wish to pass the |history| value to the operating system so that it can be used to govern whether or not other programs are started. Here, for instance, we pass the operating system a status of 0 if and only if only harmless messages were printed. @^system dependencies@> @c -int wrap_up() { - putchar('\n'); +int wrap_up(void) { + if (show_progress) new_line; if (show_stats) print_stats(); /* print statistics about memory usage */ - @<Print the job |history|@>; + @<Print the job |history|@>@; if (history > harmless_message) return(1); else return(0); } @ @<Print the job |history|@>= switch (history) { -case spotless: if (show_happiness) printf("(No errors were found.)\n"); break; +case spotless: if (show_happiness) puts("(No errors were found.)"); break; case harmless_message: - printf("(Did you see the warning message above?)\n"); break; + puts("(Did you see the warning message above?)"); break; case error_message: - printf("(Pardon me, but I think I spotted something wrong.)\n"); break; -case fatal_message: printf("(That was a fatal error, my friend.)\n"); + puts("(Pardon me, but I think I spotted something wrong.)"); break; +case fatal_message: puts("(That was a fatal error, my friend.)"); } /* there are no other cases */ @ When there is no way to recover from an error, the |fatal| subroutine is invoked. This happens most often when |overflow| occurs. -@<Predec...@>= -void fatal(), overflow(); - -@ The two parameters to |fatal| are strings that are essentially +The two parameters to |fatal| are strings that are essentially concatenated to print the final error message. @c void -fatal(s,t) - char *s,*t; +fatal( + const char *s,const char *t) { - if (*s) printf(s); + if (*s) err_print(s); err_print(t); history=fatal_message; exit(wrap_up()); } @@ -1188,8 +1116,8 @@ fatal(s,t) @ An overflow stop occurs if \.{CWEB}'s tables aren't large enough. @c void -overflow(t) - char *t; +overflow( + const char *t) { printf("\n! Sorry, %s capacity exceeded",t); fatal("",""); } @@ -1200,9 +1128,6 @@ and \.{CWEB} prints an error message that is really for the \.{CWEB} maintenance person, not the user. In such cases the program says |confusion("indication of where we are")|. -@d confusion(s) fatal("! This can't happen: ",s) -@.This can't happen@> - @** Command line arguments. The user calls \.{CWEAVE} and \.{CTANGLE} with arguments on the command line. These are either file names or flags to be turned off (beginning with |"-"|) @@ -1212,12 +1137,7 @@ of the program. The various file name variables contain strings with the names of those files. Most of the 128 flags are undefined but available for future extensions. -@d show_banner flags['b'] /* should the banner line be printed? */ -@d show_progress flags['p'] /* should progress reports be printed? */ -@d show_stats flags['s'] /* should statistics be printed at end of run? */ -@d show_happiness flags['h'] /* should lack of errors be announced? */ - -@<Defin...@>= +@<Global var...@>= int argc; /* copy of |ac| parameter to |main| */ char **argv; /* copy of |av| parameter to |main| */ char C_file_name[max_file_name_length]; /* name of |C_file| */ @@ -1231,7 +1151,8 @@ scanning the arguments; if additional flags are 1 by default they should be set before calling |common_init|. @<Set the default options common to \.{CTANGLE} and \.{CWEAVE}@>= -show_banner=show_happiness=show_progress=1; +show_banner=show_happiness=show_progress=make_xrefs=true;@/ +show_stats=false;@/ @ We now must look at the command line arguments and set the file names accordingly. At least one file name must be present: the \.{CWEB} @@ -1249,19 +1170,19 @@ when no changes are desired. If there's a third file name, it will be the output file. @<Pred...@>= -void scan_args(); +static void scan_args(void);@/ @ @c -void -scan_args() +static void +scan_args(void) { char *dot_pos; /* position of |'.'| in the argument */ char *name_pos; /* file name beginning, sans directory */ register char *s; /* register for scanning strings */ boolean found_web=0,found_change=0,found_out=0; /* have these names been seen? */ - boolean flag_change; + strcpy(change_file_name,"/dev/null"); while (--argc > 0) { if ((**(++argv)=='-'||**argv=='+')&&*(*argv+1)) @<Handle flag argument@>@; else { @@ -1275,11 +1196,10 @@ scan_args() |web_file_name|, |tex_file_name|, and |C_file_name|@>@; else if (!found_change) @<Make |change_file_name| from |fname|@>@; else if (!found_out) @<Override |tex_file_name| and |C_file_name|@>@; - else @<Print usage error message and quit@>; + else @<Print usage error message and quit@>@; } } - if (!found_web) @<Print usage error message and quit@>; - if (found_change<=0) strcpy(change_file_name,"/dev/null"); + if (!found_web) @<Print usage error message and quit@>@; } @ We use all of |*argv| for the |web_file_name| if there is a |'.'| in it, @@ -1292,7 +1212,7 @@ after the dot. We must check that there is enough room in @<Make |web_file_name|...@>= { if (s-*argv > max_file_name_length-5) - @<Complain about argument length@>; + @<Complain about argument length@>@; if (dot_pos==NULL) sprintf(web_file_name,"%s.w",*argv); else { @@ -1309,21 +1229,20 @@ after the dot. We must check that there is enough room in @ @<Make |change_file_name|...@>= { - if (strcmp(*argv,"-")==0) found_change=-1; - else { + if (strcmp(*argv,"-")!=0) { if (s-*argv > max_file_name_length-4) - @<Complain about argument length@>; + @<Complain about argument length@>@; if (dot_pos==NULL) sprintf(change_file_name,"%s.ch",*argv); else strcpy(change_file_name,*argv); - found_change=1; } + found_change=1; } @ @<Override...@>= { if (s-*argv > max_file_name_length-5) - @<Complain about argument length@>; + @<Complain about argument length@>@; if (dot_pos==NULL) { sprintf(tex_file_name,"%s.tex",*argv); sprintf(idx_file_name,"%s.idx",*argv); @@ -1332,7 +1251,7 @@ after the dot. We must check that there is enough room in } else { strcpy(tex_file_name,*argv); strcpy(C_file_name,*argv); - if (flags['x']) { /* indexes will be generated */ + if (make_xrefs) { /* indexes will be generated */ *dot_pos=0; sprintf(idx_file_name,"%s.idx",*argv); sprintf(scn_file_name,"%s.scn",*argv); @@ -1341,12 +1260,11 @@ after the dot. We must check that there is enough room in found_out=1; } -@ @<Handle flag...@>= +@ @d flag_change (**argv!='-') +@<Handle flag...@>= { - if (**argv=='-') flag_change=0; - else flag_change=1; for(dot_pos=*argv+1;*dot_pos>'\0';dot_pos++) - flags[*dot_pos]=flag_change; + flags[(eight_bits)*dot_pos]=flag_change; } @ @<Print usage error message and quit@>= @@ -1367,7 +1285,7 @@ else fatal( @** Output. Here is the code that opens the output file: @^system dependencies@> -@<Defin...@>= +@<Global var...@>= FILE *C_file; /* where output of \.{CTANGLE} goes */ FILE *tex_file; /* where output of \.{CWEAVE} goes */ FILE *idx_file; /* where index from \.{CWEAVE} goes */ @@ -1377,42 +1295,13 @@ FILE *active_file; /* currently active file for \.{CWEAVE} output */ @ @<Scan arguments and open output files@>= scan_args(); if (program==ctangle) { - if ((C_file=fopen(C_file_name,"w"))==NULL) + if ((C_file=fopen(C_file_name,"wb"))==NULL) fatal("! Cannot open output file ", C_file_name); @.Cannot open output file@> } else { - if ((tex_file=fopen(tex_file_name,"w"))==NULL) + if ((tex_file=fopen(tex_file_name,"wb"))==NULL) fatal("! Cannot open output file ", tex_file_name); } -@ The |update_terminal| procedure is called when we want -to make sure that everything we have output to the terminal so far has -actually left the computer's internal buffers and been sent. -@^system dependencies@> - -@d update_terminal fflush(stdout) /* empty the terminal output buffer */ - -@ Terminal output uses |putchar| and |putc| when we have to -translate from \.{CWEB}'s code into the external character code, -and |printf| when we just want to print strings. -Several macros make other kinds of output convenient. -@^system dependencies@> -@d new_line putchar('\n') @d putxchar putchar -@d term_write(a,b) fflush(stdout),fwrite(a,sizeof(char),b,stdout) -@d C_printf(c,a) fprintf(C_file,c,a) -@d C_putc(c) putc(c,C_file) /* isn't \CEE/ wonderfully consistent? */ - -@ We predeclare several standard system functions here instead of including -their system header files, because the names of the header files are not as -standard as the names of the functions. (For example, some \CEE/ environments -have \.{<string.h>} where others have \.{<strings.h>}.) - -@<Predecl...@>= -extern int strlen(); /* length of string */ -extern int strcmp(); /* compare strings lexicographically */ -extern char* strcpy(); /* copy one string to another */ -extern int strncmp(); /* compare up to $n$ string characters */ -extern char* strncpy(); /* copy up to $n$ string characters */ - @** Index. |