diff options
author | Denis Bitouzé <dbitouze@wanadoo.fr> | 2021-02-25 18:23:07 +0000 |
---|---|---|
committer | Denis Bitouzé <dbitouze@wanadoo.fr> | 2021-02-25 18:23:07 +0000 |
commit | c6101f91d071883b48b1b4b51e5eba0f36d9a78d (patch) | |
tree | 1bf7f5a881d7a4f5c5bf59d0b2821943dd822372 /Build/source/texk/web2c/cwebdir/common.w | |
parent | 07ee7222e389b0777456b427a55c22d0e6ffd267 (diff) |
French translation for tlmgr updated
git-svn-id: svn://tug.org/texlive/trunk@57912 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/cwebdir/common.w')
-rw-r--r-- | Build/source/texk/web2c/cwebdir/common.w | 1301 |
1 files changed, 0 insertions, 1301 deletions
diff --git a/Build/source/texk/web2c/cwebdir/common.w b/Build/source/texk/web2c/cwebdir/common.w deleted file mode 100644 index 15e93c2c5e6..00000000000 --- a/Build/source/texk/web2c/cwebdir/common.w +++ /dev/null @@ -1,1301 +0,0 @@ -% This file is part of CWEB. -% 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 4.2 --- February 2021 - -% Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth - -% Permission is granted to make and distribute verbatim copies of this -% document provided that the copyright notice and this permission notice -% are preserved on all copies. - -% Permission is granted to copy and distribute modified versions of this -% document under the conditions for verbatim copying, provided that the -% 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 4.2)} -\def\topofcontents{\null\vfill - \centerline{\titlefont Common code for {\ttitlefont CTANGLE} and - {\ttitlefont CWEAVE}} - \vskip 15pt - \centerline{(Version 4.2)} - \vfill} -\def\botofcontents{\vfill -\noindent -Copyright \copyright\ 1987, 1990, 1993, 2000 Silvio Levy and Donald E. Knuth -\bigskip\noindent -Permission is granted to make and distribute verbatim copies of this -document provided that the copyright notice and this permission notice -are preserved on all copies. - -\smallskip\noindent -Permission is granted to copy and distribute modified versions of this -document under the conditions for verbatim copying, provided that the -entire resulting derived work is given a different name and distributed -under the terms of a permission notice identical to this one. -} - -\pageno=\contentspagenumber \advance\pageno by 1 -\let\maybe=\iftrue - -@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 -problems: character uniformity, input routines, error handling and -parsing of command line. We have tried to concentrate in this file -all the system dependencies, so as to maximize portability. - -In the texts below we will -sometimes use \.{CWEB} to refer to either of the two component -programs, if no confusion can arise. - -The file begins with a few basic definitions. - -@c -@<Include files@>@/ -@h -@<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. - -@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|. - -@<Global var...@>= -boolean program; /* \.{CWEAVE} or \.{CTANGLE}? */ - -@ \.{CWEAVE} operates in three phases: First it inputs the source -file and stores cross-reference data, then it inputs the source once again and -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. - -@<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 -procedure later. - -@c -void -common_init(void) -{ - @<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. - -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 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 -avoid character conflicts. Look for the entry ``ASCII code dependencies'' -in those indexes. - -@^ASCII code dependencies@> -@^system dependencies@> - -@<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. -The return value of |input_ln| is |true| if the read is successful and -|false| if not (generally this means the file has ended). The conventions -of \TEX/ are followed; i.e., the characters of the next line of the file -are copied into the |buffer| array, -and the global variable |limit| is set to the first unoccupied position. -Trailing blanks are ignored. The value of |limit| must be strictly less -than |buf_size|, so that |buffer[buf_size-1]| is never filled. - -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. - -@<Global var...@>= -char buffer[long_buf_size]; /* where each line of input goes */ -char *buffer_end=buffer+buf_size-2; /* end of |buffer| */ -char *loc=buffer; /* points to the next character to be read from the buffer */ -char *limit=buffer; /* points to the last character in the buffer */ - -@ 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 -static boolean input_ln(@t\1\1@> /* copies a line into |buffer| or returns |false| */ -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 */ - if (feof(fp)) return false; /* we have hit end-of-file */ - limit = k = buffer; /* beginning of buffer */ - while (k<=buffer_end && (c=getc(fp)) != EOF && c!='\n') - if ((*(k++) = c) != ' ') limit = k; - if (k>buffer_end) - 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 false; /* there was nothing after - the last newline */ - return true; -} - -@ @<Predecl...@>=@+static boolean input_ln(FILE *); - -@ Now comes the problem of deciding which file to read from next. -Recall that the actual text that \.{CWEB} should process comes from two -streams: a |web_file|, which can contain possibly nested include -commands \.{@@i}, and a |change_file|, which might also contain -includes. The |web_file| together with the currently open include -files form a stack |file|, whose names are stored in a parallel stack -|file_name|. The boolean |changing| tells whether or not we're reading -from the |change_file|. - -The line number of each open file is also kept for error reporting and -for the benefit of \.{CTANGLE}. - -@<Global var...@>= -int include_depth; /* current level of nesting */ -FILE *file[max_include_depth]; /* stack of non-change files */ -FILE *change_file; /* change file */ -char file_name[max_include_depth][max_file_name_length]; - /* stack of non-change file names */ -char change_file_name[max_file_name_length]; /* name of change file */ -static char alt_web_file_name[max_file_name_length]; /* alternate name to try */ -int line[max_include_depth]; /* number of current line in the stacked files */ -int change_line; /* number of current line in change file */ -int change_depth; /* where \.{@@y} originated during a change */ -boolean input_has_ended; /* if there is no more input */ -boolean changing; /* if the current line is from |change_file| */ -boolean web_file_open=false; /* if the web file is being read */ - -@ When |changing==false|, the next line of |change_file| is kept in -|change_buffer|, for purposes of comparison with the next -line of |cur_file|. After the change file has been completely input, we -set |change_limit=change_buffer|, -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, (size_t)(limit-buffer))) - -@<Global var...@>= -static char change_buffer[buf_size]; /* next line of |change_file| */ -static char *change_limit; /* points to the last character in |change_buffer| */ - -@ Procedure |prime_the_change_buffer| -sets |change_buffer| in preparation for the next matching operation. -Since blank lines in the change file are not used for matching, we have -|(change_limit==change_buffer && !changing)| if and only if -the change file is exhausted. This procedure is called only when -|changing| is |true|; hence error messages will be reported correctly. - -@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|@>@; -} - -@ @<Predecl...@>=@+static void prime_the_change_buffer(void); - -@ While looking for a line that begins with \.{@@x} in the change file, we -allow lines that begin with \.{@@}, as long as they don't begin with \.{@@y}, -\.{@@z}, or \.{@@i} (which would probably mean that the change file is fouled up). - -@<Skip over comment lines in the change file...@>= -while(true) { - change_line++; - if (!input_ln(change_file)) return; - if (limit<buffer+2) continue; - if (buffer[0]!='@@') continue; - 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; - err_print("! Missing @@x in change file"); -@.Missing @@x...@> - } -} - -@ Here we are looking at lines following the \.{@@x}. - -@<Skip to the next nonblank line...@>= -do { - change_line++; - if (!input_ln(change_file)) { - err_print("! Change file ended after @@x"); -@.Change file ended...@> - return; - } -} while (limit==buffer); - -@ @<Move |buffer| and |limit| to |change_buffer| and |change_limit|@>= -{ - 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 -go into effect; it is called only when |changing| is |false|. -The idea is to test whether or not the current -contents of |buffer| matches the current contents of |change_buffer|. -If not, there's nothing more to do; but if so, a change is called for: -All of the text down to the \.{@@y} is supposed to match. An error -message is issued if any discrepancy is found. Then the procedure -prepares to read the next line from |change_file|. - -When a match is found, the current section is marked as changed unless -the first line after the \.{@@x} and after the \.{@@y} both start with -either `\.{@@*}' or `\.{@@\ }' (possibly preceded by whitespace). - -This procedure is called only when |buffer<limit|, i.e., when the -current line is nonempty. - -@d if_section_start_make_pending(b) {@+*limit='!'; - for (loc=buffer;xisspace(*loc);loc++) ; - *limit=' '; - if (*loc=='@@' && (xisspace(*(loc+1)) || *(loc+1)=='*')) change_pending=b; -} - -@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; - change_pending=false; - if (!changed_section[section_count]) { - if_section_start_make_pending(true); - if (!change_pending) changed_section[section_count]=true; - } - while (true) { - changing=true; print_where=true; change_line++; - if (!input_ln(change_file)) { - err_print("! Change file ended before @@y"); -@.Change file ended...@> - change_limit=change_buffer; changing=false; - return; - } - if (limit>buffer+1 && buffer[0]=='@@') { - 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|@>@; - } - @<Move |buffer| and |limit|...@>@; - changing=false; cur_line++; - while (!input_ln(cur_file)) { /* pop the stack or quit */ - if (include_depth==0) { - err_print("! CWEB file ended during a change"); -@.CWEB file ended...@> - input_has_ended=true; return; - } - include_depth--; cur_line++; - } - if (lines_dont_match) n++; - } -} - -@ @<Predecl...@>=@+static void check_change(void); - -@ @<If the current line starts with \.{@@y}...@>= -if (xyz_code=='x' || xyz_code=='z') { - loc=buffer+2; err_print("! Where is the matching @@y?"); -@.Where is the match...@> - } -else if (xyz_code=='y') { - if (n>0) { - loc=buffer+2; - printf("\n! Hmm... %d ",n); - err_print("of the preceding lines failed to match"); -@.Hmm... n of the preceding...@> - } - change_depth=include_depth; - return; -} - -@ The |reset_input| procedure, which gets \.{CWEB} ready to read the -user's \.{CWEB} input, is used at the beginning of phase one of \.{CTANGLE}, -phases one and two of \.{CWEAVE}. - -@c -void -reset_input(void) -{ - limit=buffer; loc=buffer+1; buffer[0]=' '; - @<Open input files@>@; - include_depth=0; cur_line=0; change_line=0; - change_depth=include_depth; - changing=1; prime_the_change_buffer(); changing=!changing; - limit=buffer; loc=buffer+1; buffer[0]=' '; input_has_ended=false; -} - -@ The following code opens the input files. -@^system dependencies@> - -@<Open input files@>= -if ((web_file=fopen(web_file_name,"r"))==NULL) { - strcpy(web_file_name,alt_web_file_name); - if ((web_file=fopen(web_file_name,"r"))==NULL) - fatal("! Cannot open input file ", web_file_name); -} -@.Cannot open input file@> -@.Cannot open change file@> -web_file_open=true; -if ((change_file=fopen(change_file_name,"r"))==NULL) - fatal("! Cannot open change file ", change_file_name); - -@ The |get_line| procedure is called when |loc>limit|; it puts the next -line of merged input into the buffer and updates the other variables -appropriately. A space is placed at the right end of the line. -This procedure returns |!input_has_ended| because we often want to -check the value of that variable after calling the procedure. - -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. - -@<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 - |changed_section[section_count]| */ -boolean print_where=false; /* should \.{CTANGLE} print line and file info? */ - -@ @c -boolean get_line(void) /* inputs the next line */ -{ - restart: - if (changing && include_depth==change_depth) - @<Read from |change_file| and maybe turn off |changing|@>@; - if (! changing || include_depth>change_depth) { - @<Read from |cur_file| and maybe turn on |changing|@>@; - if (changing && include_depth==change_depth) goto restart; - } - if (input_has_ended) return false; - loc=buffer; *limit=' '; - if (buffer[0]=='@@' && (buffer[1]=='i' || buffer[1]=='I')) { - loc=buffer+2; *limit='"'; - while (*loc==' '||*loc=='\t') loc++; - if (loc>=limit) { - err_print("! Include file name not given"); -@.Include file name ...@> - goto restart; - } - if (include_depth>=max_include_depth-1) { - err_print("! Too many nested includes"); -@.Too many nested includes@> - goto restart; - } - include_depth++; /* push input stack */ - @<Try to open include file, abort push if unsuccessful, go to |restart|@>@; - } - return true; -} - -@ When an \.{@@i} line is found in the |cur_file|, we must temporarily -stop reading it and start reading from the named include file. The -\.{@@i} line should give a complete file name with or without -double quotes. -If the environment variable \.{CWEBINPUTS} is set, or if the compiler flag -of the same name was defined at compile time, -\.{CWEB} will look for include files in the directory thus named, if -it cannot find them in the current directory. -(Colon-separated paths are not supported.) -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;} - -@.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; - int l; /* length of file name */ - - if (*loc=='"') { - loc++; - while (*loc!='"' && k<=cur_file_name_end) *k++=*loc++; - if (loc==limit) k=cur_file_name_end+1; /* unmatched quote is `too long' */ - } else - while (*loc!=' '&&*loc!='\t'&&*loc!='"'&&k<=cur_file_name_end) *k++=*loc++; - if (k>cur_file_name_end) too_long(); -@.Include file name ...@> - *k='\0'; - if ((cur_file=fopen(cur_file_name,"r"))!=NULL) { - cur_line=0; print_where=true; - goto restart; /* success */ - } - kk=getenv("CWEBINPUTS"); - if (kk!=NULL) { - if ((l=strlen(kk))>max_file_name_length-2) too_long(); - strcpy(temp_file_name,kk); - } - else { -#ifdef CWEBINPUTS - if ((l=strlen(CWEBINPUTS))>max_file_name_length-2) too_long(); - strcpy(temp_file_name,CWEBINPUTS); -#else - l=0; -#endif /* |CWEBINPUTS| */ - } - if (l>0) { - if (k+l+2>=cur_file_name_end) too_long(); -@.Include file name ...@> - for (; k>= cur_file_name; k--) *(k+l+1)=*k; - strcpy(cur_file_name,temp_file_name); - cur_file_name[l]='/'; /* \UNIX/ pathname separator */ - if ((cur_file=fopen(cur_file_name,"r"))!=NULL) { - cur_line=0; print_where=true; - goto restart; /* success */ - } - } - include_depth--; err_print("! Cannot open include file"); goto restart; -} - -@ @<Read from |cur_file|...@>= { - cur_line++; - while (!input_ln(cur_file)) { /* pop the stack or quit */ - print_where=true; - if (include_depth==0) {input_has_ended=true; break;} - else { - fclose(cur_file); include_depth--; - if (changing && include_depth==change_depth) break; - cur_line++; - } - } - if (!changing && !input_has_ended) - if (limit-buffer==change_limit-change_buffer) - if (buffer[0]==change_buffer[0]) - if (change_limit>change_buffer) check_change(); -} - -@ @<Read from |change_file|...@>= { - change_line++; - if (!input_ln(change_file)) { - err_print("! Change file ended without @@z"); -@.Change file ended...@> - buffer[0]='@@'; buffer[1]='z'; limit=buffer+2; - } - if (limit>buffer) { /* check if the change has ended */ - if (change_pending) { - if_section_start_make_pending(false); - if (change_pending) { - changed_section[section_count]=true; change_pending=false; - } - } - *limit=' '; - if (buffer[0]=='@@') { - 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?"); -@.Where is the match...@> - } - else if (buffer[1]=='z') { - prime_the_change_buffer(); changing=!changing; print_where=true; - } - } - } -} - -@ At the end of the program, we will tell the user if the change file -had a line that didn't match any relevant line in |web_file|. - -@c -void -check_complete(void) { - if (change_limit!=change_buffer) { /* |changing| is |false| */ - strncpy(buffer,change_buffer,(size_t)(change_limit-change_buffer+1)); - limit=buffer+(ptrdiff_t)(change_limit-change_buffer); - changing=true; change_depth=include_depth; loc=buffer; - err_print("! Change file entry did not match"); -@.Change file entry did not match@> - } -} - -@** Storage of names and strings. -Both \.{CWEAVE} and \.{CTANGLE} store identifiers, section names and -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|. 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 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|. - -@<Global var...@>= -char *byte_ptr; /* first unused position in |byte_mem| */ -name_pointer name_ptr; /* first unused position in |name_dir| */ - -@ @<Init...@>= -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 */ -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 -updated by the |id_lookup| procedure, which finds a given identifier -and returns the appropriate |name_pointer|. The matching is done by the -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 8501 /* should be prime */ - -@<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 */ - -@ Initially all the hash lists are empty. - -@<Init...@>= -for (h=hash; h<=hash_end; *h++=NULL) ; - -@ Here is the main procedure for finding identifiers: - -@c -name_pointer -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 */ -{ - 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=(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; -} - -@ A simple hash code is used: If the sequence of -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=(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|, -otherwise |p| will point to its existing location. - -@<Compute the name location...@>= -p=hash[h]; -while (p && !names_match(p,first,l,t)) p=p->link; -if (p==NULL) { - p=name_ptr; /* the current identifier is new */ - p->link=hash[h]; hash[h]=p; /* insert |p| at beginning of hash list */ -} - -@ 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. -@<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; - init_p(p,t); -} - -@ 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 -name, the name may need to be stored in chunks, because it may -``grow'': a prefix of the section name may be encountered before -the full name. Furthermore we need to know the length of the shortest -prefix of the name that was ever encountered. - -We solve this problem by inserting two extra bytes at |p->byte_start|, -representing the length of the shortest prefix, when |p| is a -section name. Furthermore, the last byte of the name will be a blank -space if |p| is a prefix. In the latter case, the name pointer -|p+1| will allow us to access additional chunks of the name: -The second chunk will begin at the name pointer |(p+1)->link|, -and if it too is a prefix (ending with blank) its |link| will point -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)((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( -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,(size_t)(ss-s)); p=q->link; q=p; - } else { - term_write(s,(size_t)(ss+1-s)); p=name_dir; q=NULL; - } - s = p->byte_start; - } - if (q) term_write("...",3); /* complete name not yet known */ -} - -@ @c -void -sprint_section_name( - char *dest, - 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) { - p=q->link; q=p; - } else { - ss++; p=name_dir; - } - strncpy(dest,s,(size_t)(ss-s)), dest+=ss-s; - s = p->byte_start; - } - *dest='\0'; -} - -@ @c -void -print_prefix_name( -name_pointer p) -{ - char *s = first_chunk(p); - int l = prefix_length(p); - term_write(s,l); - if (s+l<(p+1)->byte_start) term_write("...",3); -} - -@ When we compare two section names, we'll need a function analogous to -|strcmp|. But we do not assume the strings -are null-terminated, and we keep an eye open for prefixes and extensions. - -@d less 0 /* the first name is lexicographically less than the second */ -@d equal 1 /* the first name is equal to the second */ -@d greater 2 /* the first name is lexicographically greater than the second */ -@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 */ - -@<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++; - if (k==k1) if (j==j1) return equal; - else return extension; - else if (j==j1) return prefix; - else if (*j<*k) return less; - else return greater; -} - -@ Adding a section name to the tree is straightforward if we know its -parent and whether it's the |rlink| or |llink| of the parent. As a -special case, when the name is the first section being added, we set the -``parent'' to |NULL|. When a section name is created, it has only one -chunk, which however may be just a prefix; the full name will -hopefully be unveiled later. Obviously, |prefix_length| starts -out as the length of the first chunk, though it may decrease later. - -The information associated with a new node must be initialized -differently in \.{CWEAVE} and \.{CTANGLE}; hence the -|init_node| procedure, which is defined differently in \.{cweave.w} -and \.{ctangle.w}. - -@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=(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; - if (ispref) { - *(byte_ptr-1)=' '; - name_len--; - name_ptr->link=name_dir; - (++name_ptr)->byte_start=byte_ptr; - } - set_prefix_length(p,name_len); - strncpy(s,first,name_len); - p->llink=NULL; - p->rlink=NULL; - init_node(p); - return par==NULL ? (root=p) : c==less ? (par->llink=p) : (par->rlink=p); -} - -@ @c -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=(int)(last-first)+ispref; - if (name_ptr>=name_dir_end) overflow("name"); - while (q->link!=name_dir) q=q->link; - q->link=name_ptr; - s=name_ptr->byte_start; - name_ptr->link=name_dir; - if (s+name_len>byte_mem_end) overflow("byte memory"); - (++name_ptr)->byte_start=byte_ptr=s+name_len; - strncpy(s,first,name_len); - if (ispref) *(byte_ptr-1)=' '; -} - -@ The |section_lookup| procedure is supposed to find a -section name that matches a new name, installing the new name if -it doesn't match an existing one. The new name is the string -between |first| and |last|; a ``match'' means that the new name -exactly equals or is a prefix or extension of a name in the tree. - -@c -name_pointer -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 */ - name_pointer q=NULL; /* another place to look in the tree */ - 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=(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@>@; -} - -@ A legal new name matches an existing section name if and only if it -matches the shortest prefix of that section name. Therefore we can -limit our search for matches to shortest prefixes, which eliminates -the need for chunk-chasing at this stage. - -@<Look for matches for new name among...@>= -while (p) { /* compare shortest prefix of |p| with new name */ - c=web_strcmp(first,name_len,first_chunk(p),prefix_length(p)); - if (c==less || c==greater) { /* new name does not match |p| */ - if (r==NULL) /* no previous matches have been found */ - par=p; - p=(c==less?p->llink:p->rlink); - } else { /* new name matches |p| */ - if (r!=NULL) { /* and also |r|: illegal */ - fputs("\n! Ambiguous prefix: matches <",stdout); -@.Ambiguous prefix ... @> - print_prefix_name(p); - fputs(">\n and <",stdout); - print_prefix_name(r); - err_print(">"); - return name_dir; /* the unsection */ - } - r=p; /* remember match */ - p=p->llink; /* try another */ - q=r->rlink; /* we'll get back here if the new |p| doesn't match */ - } - if (p==NULL) - p=q, q=NULL; /* |q| held the other branch of |r| */ -} - -@ @<If no match ...@>= - if (r==NULL) /* no matches were found */ - return add_section_name(par,c,first,last+1,ispref); - -@ Although error messages are given in anomalous cases, we do return the -unique best match when a discrepancy is found, because users often -change a title in one place while forgetting to change it elsewhere. - -@<If one match found, check for compatibility and return match@>= -switch(section_name_cmp(&first,name_len,r)) { - /* compare all of |r| with new name */ - case prefix: - if (!ispref) { - fputs("\n! New name is a prefix of <",stdout); -@.New name is a prefix...@> - print_section_name(r); - err_print(">"); - } - else if (name_len<prefix_length(r)) set_prefix_length(r,name_len); - /* fall through */ - case equal: return r; - case extension: if (!ispref || first<=last) - extend_section_name(r,first,last+1,ispref); - return r; - case bad_extension: - fputs("\n! New name extends <",stdout); -@.New name extends...@> - print_section_name(r); - err_print(">"); - return r; - default: /* no match: illegal */ - fputs("\n! Section name incompatible with <",stdout); -@.Section name incompatible...@> - print_prefix_name(r); - fputs(">,\n which abbreviates <",stdout); - print_section_name(r); - err_print(">"); - return r; -} - -@ The return codes of |section_name_cmp|, which compares a string with -the full name of a section, are those of |web_strcmp| plus -|bad_extension|, used when the string is an extension of a -supposedly already complete section name. This function has a side -effect when the comparison string is an extension: It advances the -address of the first character of the string by an amount equal to -the length of the known part of the section name. - -The name \.{@@<foo...@@>} should be an acceptable ``abbreviation'' -for \.{@@<foo@@>}. If such an abbreviation comes after the complete -name, there's no trouble recognizing it. If it comes before the -complete name, we simply append a null chunk. This logic requires -us to regard \.{@@<foo...@@>} as an ``extension'' of itself. - -@d bad_extension 5 - -@c -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 */ - char *ss, *s=first_chunk(r); - int c; /* comparison */ - int ispref; /* is chunk |r| a prefix? */ - while (true) { - ss=(r+1)->byte_start-1; - if (*ss==' ' && ss>=r->byte_start) ispref=1,q=q->link; - else ispref=0,ss++,q=name_dir; - switch(c=web_strcmp(first,len,s,ss-s)) { - case equal: if (q==name_dir) - if (ispref) { - *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 -= (int)(ss-s); s=q->byte_start; r=q; continue;} - *pfirst=first; return extension; - default: return c; - } - } -} - -@ @<Predec...@>=@+static int section_name_cmp(char **,int,name_pointer); - -@** 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 -printed; |harmless_message| means that a message of possible interest -was printed but no serious errors were detected; |error_message| means that -at least one error was found; |fatal_message| means that the program -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. - -@<Global var...@>= -int history=spotless; /* indicates how bad this run was */ - -@ The command `|err_print("! Error message")|' will report a syntax error to -the user, by printing the error message at the beginning of a new line and -then giving an indication of where the error was spotted in the source file. -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 |"!"|. - -@c -void -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@>@; - update_terminal; mark_error; -} - -@ The error locations can be indicated by using the global variables -|loc|, |cur_line|, |cur_file_name| and |changing|, -which tell respectively the first -unlooked-at position in |buffer|, the current line number, the current -file, and whether the current line is from |change_file| or |cur_file|. -This routine should be modified on systems whose standard text editor -has special line-numbering conventions. -@^system dependencies@> - -@<Print error location based on input buffer@>= -{if (changing && include_depth==change_depth) - printf(". (l. %d of change file)\n", change_line); -else if (include_depth==0) printf(". (l. %d)\n", cur_line); - else printf(". (l. %d of include file %s)\n", cur_line, cur_file_name); -l= (loc>=limit? limit: loc); -if (l>buffer) { - for (k=buffer; k<l; k++) - if (*k=='\t') putchar(' '); - else putchar(*k); /* print the characters already read */ - putchar('\n'); - for (k=buffer; k<l; k++) putchar(' '); /* space out the next line */ -} -for (k=l; k<limit; k++) putchar(*k); /* print the part not yet read */ -if (*limit=='|') putchar('|'); /* end of \CEE/ text in section names */ -putchar(' '); /* to separate the message from future asterisks */ -} - -@ When no recovery from some error has been provided, we have to wrap -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. 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 -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(void) { - if (show_progress) new_line; - if (show_stats) - print_stats(); /* print statistics about memory usage */ - @<Print the job |history|@>@; - if (history > harmless_message) return EXIT_FAILURE; - else return EXIT_SUCCESS; -} - -@ @<Print the job |history|@>= -switch (history) { -case spotless: if (show_happiness) puts("(No errors were found.)"); break; -case harmless_message: - puts("(Did you see the warning message above?)"); break; -case error_message: - 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. - -The two parameters to |fatal| are strings that are essentially -concatenated to print the final error message. - -@c void -fatal( - const char *s,const char *t) -{ - if (*s) err_print(s); - err_print(t); - history=fatal_message; exit(wrap_up()); -} - -@ An overflow stop occurs if \.{CWEB}'s tables aren't large enough. - -@c void -overflow( - const char *t) -{ - printf("\n! Sorry, %s capacity exceeded",t); fatal("",""); -} -@.Sorry, capacity exceeded@> - -@ Sometimes the program's behavior is far different from what it should be, -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")|. - -@** 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 |"-"|) -or flags to be turned on (beginning with |"+"|). -The following globals are for communicating the user's desires to the rest -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. - -@<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| */ -char tex_file_name[max_file_name_length]; /* name of |tex_file| */ -char idx_file_name[max_file_name_length]; /* name of |idx_file| */ -char scn_file_name[max_file_name_length]; /* name of |scn_file| */ -boolean flags[128]; /* an option for each 7-bit code */ - -@ The |flags| will be initially |false|. Some of them are set to~|true| before -scanning the arguments; if additional flags are |true| 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=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} -file. It may have an extension, or it may omit the extension to get |".w"| or -|".web"| added. The \TEX/ output file name is formed by replacing the \.{CWEB} -file name extension by |".tex"|, and the \CEE/ file name by replacing -the extension by |".c"|, after removing the directory name (if any). - -If there is a second file name present among the arguments, it is the -change file, again either with an extension or without one to get |".ch"|. -An omitted change file argument means that |"/dev/null"| should be used, -when no changes are desired. -@^system dependencies@> - -If there's a third file name, it will be the output file. - -@c -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=false,found_change=false,found_out=false; - /* have these names been seen? */ - - strcpy(change_file_name,"/dev/null"); - while (--argc > 0) { - if ((**(++argv)=='-'||**argv=='+')&&*(*argv+1)) @<Handle flag argument@>@; - else { - s=name_pos=*argv;@+dot_pos=NULL; - while (*s) { - if (*s=='.') dot_pos=s++; - else if (*s=='/') dot_pos=NULL,name_pos=++s; - else s++; - } - if (!found_web) @<Make - |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@>@; - } - } - if (!found_web) @<Print usage error message and quit@>@; -} - -@ @<Pred...@>=@+static void scan_args(void); - -@ We use all of |*argv| for the |web_file_name| if there is a |'.'| in it, -otherwise we add |".w"|. If this file can't be opened, we prepare an -|alt_web_file_name| by adding |"web"| after the dot. -The other file names come from adding other things -after the dot. We must check that there is enough room in -|web_file_name| and the other arrays for the argument. - -@<Make |web_file_name|...@>= -{ - if (s-*argv > max_file_name_length-5) - @<Complain about argument length@>@; - if (dot_pos==NULL) - sprintf(web_file_name,"%s.w",*argv); - else { - strcpy(web_file_name,*argv); - *dot_pos=0; /* string now ends where the dot was */ - } - sprintf(alt_web_file_name,"%s.web",*argv); - sprintf(tex_file_name,"%s.tex",name_pos); /* strip off directory name */ - sprintf(idx_file_name,"%s.idx",name_pos); - sprintf(scn_file_name,"%s.scn",name_pos); - sprintf(C_file_name,"%s.c",name_pos); - found_web=true; -} - -@ @<Make |change_file_name|...@>= -{ - if (strcmp(*argv,"-")!=0) { - if (s-*argv > max_file_name_length-4) - @<Complain about argument length@>@; - if (dot_pos==NULL) - sprintf(change_file_name,"%s.ch",*argv); - else strcpy(change_file_name,*argv); - } - found_change=true; -} - -@ @<Override...@>= -{ - if (s-*argv > max_file_name_length-5) - @<Complain about argument length@>@; - if (dot_pos==NULL) { - sprintf(tex_file_name,"%s.tex",*argv); - sprintf(idx_file_name,"%s.idx",*argv); - sprintf(scn_file_name,"%s.scn",*argv); - sprintf(C_file_name,"%s.c",*argv); - } else { - strcpy(tex_file_name,*argv); - strcpy(C_file_name,*argv); - if (make_xrefs) { /* indexes will be generated */ - *dot_pos=0; - sprintf(idx_file_name,"%s.idx",*argv); - sprintf(scn_file_name,"%s.scn",*argv); - } - } - found_out=true; -} - -@ @d flag_change (**argv!='-') -@<Handle flag...@>= -{ - for(dot_pos=*argv+1;*dot_pos>'\0';dot_pos++) - flags[(eight_bits)*dot_pos]=flag_change; -} - -@ @<Print usage error message and quit@>= -{ -if (program==ctangle) - fatal( -"! Usage: ctangle [options] webfile[.w] [{changefile[.ch]|-} [outfile[.c]]]\n" - ,""); -@.Usage:@> -else fatal( -"! Usage: cweave [options] webfile[.w] [{changefile[.ch]|-} [outfile[.tex]]]\n" - ,""); -} - -@ @<Complain about arg...@>= fatal("! Filename too long\n", *argv); -@.Filename too long@> - -@** Output. Here is the code that opens the output file: -@^system dependencies@> - -@<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 */ -FILE *scn_file; /* where list of sections from \.{CWEAVE} goes */ -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,"wb"))==NULL) - fatal("! Cannot open output file ", C_file_name); -@.Cannot open output file@> -} -else { - if ((tex_file=fopen(tex_file_name,"wb"))==NULL) - fatal("! Cannot open output file ", tex_file_name); -} - -@** Index. |