* Introduction. This is the \.{CTANGLE program by Silvio Levy and Donald E. Knuth, based on \.{TANGLE by Knuth. We are thankful to Nelson Beebe, Hans-Hermann Bode (to whom the \CPLUSPLUS/ adaptation is due), Klaus Guntermann, Norman Ramsey, Tomas Rokicki, Joachim Schnitter, Joachim Schrod, Lee Wittenberg, and others who have contributed improvements.
The “banner line” defined here should be changed whenever \.{CTANGLE is modified.
@d banner "This is CTANGLE (Version 3.4)\n"
@<Include files@> @h @<Common code for \.{CWEAVE and \.{CTANGLE@> @<Typedef declarations@> @<Global variables@> @<Predeclaration of procedures@>
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 */
\.{CTANGLE has a fairly straightforward outline. It operates in two phases: first it reads the source file, saving the \CEE/ code in compressed form; then outputs the code, after shuffling it around.
Please read the documentation for \.{common, the set of routines common to \.{CTANGLE and \.{CWEAVE, before proceeding further.
int main (ac, av) int ac; char **av; { argc=ac; argv=av; program=ctangle; @<Set initial values@>; common_init(); if (show_banner) printf(banner); /* print a “banner line” */ phase_one(); /* read all the user’s text and compress it into |tok_mem| */ phase_two(); /* output the contents of the compressed tables */ return wrap_up(); /* and exit gracefully */
The following parameters were sufficient in the original \.{TANGLE to handle \TEX/, so they should be sufficient for most applications of \.{CTANGLE. If you change |max_bytes|, |max_names| or |hash_size| you should also change them in the file |"common.w"|.
@d max_bytes 90000 /* the number of bytes in identifiers, index entries, and section names; used in |"common.w"| */ @d max_toks 270000 /* number of bytes in compressed \CEE/ code */ @d max_names 4000 /* number of identifiers, strings, section names; must be less than 10240; used in |"common.w"| */ @d max_texts 2500 /* number of replacement texts, must be less than 10240 */ @d hash_size 353 /* should be prime; used in |"common.w"| */ @d longest_name 1000 /* section names shouldn’t be longer than this */ @d stack_size 50 /* number of simultaneous levels of macro expansion */ @d buf_size 100 /* for \.{CWEAVE and \.{CTANGLE */
The next few sections contain stuff from the file |"common.w"| that must be included in both |"ctangle.w"| and |"cweave.w"|. It appears in file |"common.h"|, which needs to be updated when |"common.w"| changes.
@i common.h
Data structures exclusive to {\tt CTANGLE. We’ve already seen that the |byte_mem| array holds the names of identifiers, strings, and sections; the |tok_mem| array holds the replacement texts for sections. Allocation is sequential, since things are deleted only during Phase II, and only in a last-in-first-out manner.
A \&{text variable is a structure containing a pointer into |tok_mem|, which tells where the corresponding text starts, and an integer |text_link|, which, as we shall see later, is used to connect pieces of text that have the same name. All the \&{texts are stored in the array |text_info|, and we use a |text_pointer| variable to refer to them.
The first position of |tok_mem| that is unoccupied by replacement text is called |tok_ptr|, and the first unused location of |text_info| is called |text_ptr|. Thus we usually have the identity |text_ptr->tok_start==tok_ptr|.
If your machine does not support |unsigned char| you should change the definition of \&{eight\_bits to |unsigned short|. ŝystem dependencies@>
@<Typed...@>= typedef struct { eight_bits *tok_start; /* pointer into |tok_mem| */ sixteen_bits text_link; /* relates replacement texts */ text; typedef text *text_pointer;
@<Glob...@>= text text_info[max_texts]; text_pointer text_info_end=text_info+max_texts-1; text_pointer text_ptr; /* first unused position in |text_info| */ eight_bits tok_mem[max_toks]; eight_bits *tok_mem_end=tok_mem+max_toks-1; eight_bits *tok_ptr; /* first unused position in |tok_mem| */
@<Set init...@>= text_info->tok_start=tok_ptr=tok_mem; text_ptr=text_info+1; text_ptr->tok_start=tok_mem; /* this makes replacement text 0 of length zero */
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|.
@d equiv equiv_or_xref /* info corresponding to names */
@<Set init...@>= name_dir->equiv=(char *)text_info; /* the undefined section has no replacement t ext */
Here’s the procedure that decides whether a name of length |l| starting at position |first| equals the identifier pointed to by |p|:
int names_match(p,first,l) name_pointer p; /* points to the proposed match */ char *first; /* position of first character of string */ int l; /* length of identifier */ { if (length(p)!=l) return 0; return !strncmp(first,p->byte_start,l);
The common lookup routine refers to separate routines |init_node| and |init_p| when the data structure grows. Actually |init_p| is called only by \.{CWEAVE, but we need to declare a dummy version so that the loader won’t complain of its absence.
void init_node(node) name_pointer node; { node->equiv=(char *)text_info; void init_p() {
This document was generated on January 4, 2025 using texi2html 5.0.