summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/cwebdir/common.w
diff options
context:
space:
mode:
authorAndreas Scherer <andreas_tex@freenet.de>2021-02-07 11:02:17 +0000
committerAndreas Scherer <andreas_tex@freenet.de>2021-02-07 11:02:17 +0000
commit3063cfbe5a32a13420a310bad225be72bcde4982 (patch)
tree01cdd5b69339785bc339eeaa5ec8e5e0dc7e29d0 /Build/source/texk/web2c/cwebdir/common.w
parent1842aa2477fe04aa641c9332262e21b78c4e50ed (diff)
CWEB – release 4.0, 2021-02-07.
In the course of the "2021 TeX tuneup", Don Knuth kindly transferred the responsibility for CWEB to me; see the original CWEB home page (https://www-cs-faculty.stanford.edu/~knuth/cweb.html), section "CWEB 4.0" and the updated CWEB development project (https://github.com/ascherer/cweb). This first new release draws heavily on the multi-decade work collected in my "CWEBbin" project (https://github.com/ascherer/cwebbin). I moved (almost) all stuff from the "*-patch.*" changefiles into the new CWEB sources and applied all of the "*-ansi.*" changes as well. Moreover, I made "common.h" the full interface of "common.w" in order to avoid code redundancy. And I tried to fix as many of the bugs reported by email to DEK and/or tex-k@tug.org. In total, "make; make cautiously; make fullmanual" runs flawlessly with GCC on Linux and with LLVM on MacOS. After the release of "CWEB 4.0", also "CWEBbin 2021" has also been fully revised. Thousands of lines of changefiles could be purged. What's left are the clearcut extensions for CWEB and the additional stuff for integration in "TeX Live 2021". git-svn-id: svn://tug.org/texlive/trunk@57658 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/cwebdir/common.w')
-rw-r--r--Build/source/texk/web2c/cwebdir/common.w583
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.