summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/ctiedir/ctie.w
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/ctiedir/ctie.w')
-rw-r--r--Build/source/texk/web2c/ctiedir/ctie.w1280
1 files changed, 0 insertions, 1280 deletions
diff --git a/Build/source/texk/web2c/ctiedir/ctie.w b/Build/source/texk/web2c/ctiedir/ctie.w
deleted file mode 100644
index 33abf6312c8..00000000000
--- a/Build/source/texk/web2c/ctiedir/ctie.w
+++ /dev/null
@@ -1,1280 +0,0 @@
-% This is ctie.w
-% Copyright (c) 2002,2003 by Julian Gilbey
-% All rights reserved.
-%
-% This program is distributed WITHOUT ANY WARRANTY, express or implied.
-%
-% Permission is granted to make and distribute verbatim copies of this
-% program 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
-% program under the conditions for verbatim copying, provided that the
-% entire resulting derived work is distributed under the terms of a
-% permission notice identical to this one.
-%
-% This program is based heavily on tie.w and common.w, part of the
-% CWEB source.
-
-\def\title{The CTIE processor}
-\def\botofcontents{%
-\vfill
-$\copyright$ 2002,2003 Julian Gilbey
-
-All rights reserved.
-
-This program is distributed WITHOUT ANY WARRANTY, express or implied.
-
-Permission is granted to make and distribute verbatim copies of this
-program 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
-program under the conditions for verbatim copying, provided that the
-entire resulting derived work is distributed under the terms of a
-permission notice identical to this one.
-}
-
-
-@* Introduction.
-Whenever a programmer wants to change a given \.{WEB} or \.{CWEB}
-program (referred to as a \.{WEB} program throughout this program)
-because of system dependencies, she or he will create a new change
-file. In addition there may be a second change file to modify system
-independent modules of the program. But the \.{WEB} file cannot be
-tangled and weaved with more than one change file simultaneously.
-The \.{TIE} program was designed to merge a \.{WEB} file
-and several change files producing a new \.{WEB} file, and since the
-input files are tied together, the program was called \.{TIE}.
-Furthermore, the program could be used to merge several change files
-giving a new single change file. This method seems to be more
-important because it doesn't modify the original source file.
-
-However, the introduction of \.{CWEB} has meant that \.{TIE} is not
-quite able to perform its task correctly any longer: \.{CWEB}
-introduced the idea of include files, which are input into \.{CWEB}
-files using the \.{@@i} command, and \.{TIE} is unable to handle such
-constructs if the change files modify lines included in those files.
-The present program, \.{CTIE}, is designed to overcome this lack.
-Like \.{TIE}, upon which it is based, it can either output a single
-master \.{WEB} file or a master change file. However, in both cases,
-any include commands will be totally expanded and the files included
-in the output rather than the \.{@@i} commands being left; this makes
-this code feasible, which it would not necessarily be otherwise.
-Other than this difference, \.{CTIE} should function identically to
-\.{TIE} on files which do not involve any \.{CWEB} include commands.
-
-The algorithm used is essentially the same as that of \.{TIE}, with
-modifications to check for and handle \.{@@i} commands. Thus, as with
-\.{TIE}, the method used only needs one buffer line for each input
-file. Thus the storage requirement of \.{CTIE} does not depend on the
-sizes of the input files but only on their number.
-
-The program is written in \CEE/ and has few system dependencies.
-
-The ``banner line'' defined here should be changed whenever
-\.{CTIE} is modified. We also keep the version number here separately
-for ease; it is used below.
-
-@d version_number "1.1"
-@d banner "This is CTIE, Version 1.1"
-@d copyright
- "Copyright 2002,2003 Julian Gilbey. All rights reserved. There is no warranty.\n\
-Run with the --version option for other important information."
-
-
-@ The main outline of the program is now given.
-This can be used more or less for any \CEE/ program.
-
-@c
-@<Global \&{\#include}s@>@;
-@<Global types@>@;
-@<Predeclaration of functions@>@;
-@<Global variables@>@;
-@<Error handling functions@>@;
-@<Internal functions@>@;
-@<The main function@>@;
-
-@ And this is the structure of the |main| function: this is where
-\.{CTIE} starts, and where it ends.
-
-@<The main function@>=
-main(argc, argv)
- int argc; string *argv;
-{
- @<Initialise parameters@>;
- @<Scan the parameters@>@;
- @<Print the banners@>;
- @<Get the master file started@>@;
- @<Prepare the change files@>@;
- @<Prepare the output file@>@;
- @<Process the input@>@;
- @<Check that all changes have been read@>@;
- exit(wrap_up());
-}
-
-@ We include the additional types |boolean| and |string|. \.{CTIE}
-replaces the complex \.{TIE} character set handling (based on that of
-the original \.{WEB} system) with the standard \.{CWEB} behaviour, and
-so uses the |char| type for input and output.
-
-@d false 0
-@d true 1
-
-@<Global types@>=
-typedef int boolean;
-typedef char* string;
-
-
-@ We predeclare some standard string-handling 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. (There's confusion
-between \.{<string.h>} and \.{<strings.h>}.)
-
-@<Predecl...@>=
-extern int strlen(); /* length of string */
-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 */
-extern char *strerror();
-
-
-@ The following parameters should be sufficient for most
-applications of \.{CTIE}.
-@^system dependencies@>
-
-@d buf_size 1024 /* maximum length of one input line */
-@d max_file_index 32
-/* we don't think that anyone needs more than 32 change files */
-@d xisupper(c) (isupper(c)&&((unsigned char)c<0200))
-
-
-@ We introduce a history variable that allows us to set a
-return code if the operating system can use it.
-First we introduce the coded values for the history.
-This variable must be initialized.
-(We do this even if the value given may be the default for
-variables, just to document the need for the initial value.)
-@d spotless 0
-@d troublesome 1
-@d fatal 2
-
-@<Global variables@>=
-int history=spotless;
-
-
-@* Input and output.
-Standard output for the user is done by writing on |stdout|. Error
-messages are written to |stderr|. Terminal input is not needed in
-this version of \.{CTIE}. |stdin|, |stdout| and |stderr| are
-predefined as we include the \.{stdio.h} definitions.
-
-@<Global \&{\#include}s@>=
-#include <stdio.h>
-
-
-@ And we need dynamic memory allocation.
-This should cause no trouble in any \CEE/ program.
-@^system dependencies@>
-
-@<Global \&{\#include}s@>=
-#ifdef __STDC__
-#include <stdlib.h>
-#else
-#include <malloc.h>
-#endif
-
-
-@* Data structures.
-The multiple primary input files (master file and change
-files) are treated the same way. To organize the
-simultaneous usage of several input files, we introduce the
-data type \&{in\_file\_modes}.
-
-The mode |search| indicates that \.{CTIE} searches for a
-match of the input line with any line of an input file in
-|reading| mode. |test| is used whenever a match is found
-and it has to be tested if the next input lines do match
-also. |reading| describes that the lines can be read without
-any check for matching other lines. |ignore| denotes
-that the file cannot be used. This may happen because an
-error has been detected or because the end of the file has
-been found.
-
-\leavevmode |file_types| is used to describe whether a file
-is a master file or a change file. The value |unknown| is added
-to this type to set an initial mode for the output file.
-This enables us to check whether any option was used to select
-the kind of output. (this would even be necessary if we
-would assume a default action for missing options.)
-
-@<Global types@>=
-#define search 0
-#define test 1
-#define reading 2
-#define ignore 3
-typedef int in_file_modes; /* should be |enum(search, test, reading, ignore)| */
-#define unknown 0
-#define master 1
-#define chf 2
-typedef int file_types; /* should be |enum(unknown, master, chf)| */
-
-
-@ A variable of type |out_md_type| will tell us in what state the output
-change file is during processing. |normal| will be the state, when we
-did not yet start a change, |pre| will be set when we write the lines
-to be changes and |post| will indicate that the replacement lines are
-written.
-
-@<Global types@>=
-#define normal 0
-#define pre 1
-#define post 2
-typedef int out_md_type; /* should be |enum(normal, pre, post)| */
-
-
-@ The next type will indicate variables used as an index into the file
-table.
-
-@<Global types@>=
-typedef int file_index; /* |-1..max_file_index+1| */
-
-
-@ This is the data structure in which we collect information about
-each include file.
-
-@<Global types@>=
-typedef struct _indsc {
- char file_name[max_file_name_length];
- long line;
- FILE *the_file;
- struct _indsc *parent;
-} include_description;
-
-
-@ The following data structure contains all of the information needed
-to use these input files.
-%`line' is a normal identifier throughout this program
-@f line dummy
-@<Global types@>=
-typedef struct _idsc{
- string file_name;
- char buffer[buf_size];
- in_file_modes mode;
- long line;
- file_types type_of_file;
- include_description *current_include;
- char *buffer_end;
- char *limit;
- char *loc;
- FILE *the_file;
- int dont_match;
- } input_description;
-
-
-@ Every one of the primary input files might include another file
-using the \.{@@i} include mechanism. In turn, each of these might
-include other files, and so on. We allow a limited number of these
-files to be opened simultaneously, and we store information about the
-currently open include files as a linked list attached to each primary
-file.
-
-@d max_include_files 20
- /* maximum number of include files open simultaneously */
-@d max_file_name_length 60
-
-@<Global variables@>=
-int total_include_files = 0; /* count 'em */
-
-@ The following variables refer to the files in action, the number of
-change files, the mode of operation and the current output state.
-
-@<Global variables@>=
-file_index actual_input, test_input, no_ch;
-file_types prod_chf=unknown;
-out_md_type out_mode;
-
-@ And the |actual_input| and |out_mode| variables need to be
-initialised sensibly.
-
-@<Initialise parameters@>=
-actual_input=0;
-out_mode=normal;
-
-@ All primary input files (including the master file) are recorded
-in the following structure.
-The components are usually accessed through a local pointer variable,
-requiring only a one-time-computation of the index expression.
-
-@<Global variables@>=
-input_description *input_organisation[max_file_index+1];
-
-
-@* File I/O.
-The basic function |get_line| can be used to get a line from
-an input file. The line is stored in the |buffer| part of the
-descriptor. The components |limit| and |line| are updated. If the
-end of the file is reached |mode| is set to |ignore|. On some systems
-it might be useful to replace tab characters by a proper number of
-spaces since several editors used to create change files insert tab
-characters into a source file not under control of the user. So it
-might be a problem to create a matching change file.
-@^tab character expansion@>
-
-We define |get_line| to read a line from a file specified by the
-corresponding file descriptor. This function returns |true| if it is
-successful and |false| if the end of the file has been reached.
-
-@<Internal functions@>=
-boolean get_line(i, do_includes)
- file_index i; boolean do_includes;
-{
- register input_description *inp_desc=input_organisation[i];
- register FILE *fp;
-
- if (inp_desc->mode==ignore) return false;
-
- restart:
- if (inp_desc->current_include != NULL) {
- register include_description *inc_desc=inp_desc->current_include;
-
- fp=inc_desc->the_file;
- @<Get include line into buffer or |goto restart| if end of file@>@;
- }
- else {
- fp=inp_desc->the_file;
- @<Get line into buffer, |return false| if end of file@>@;
- }
-
- if (do_includes)
- @<Check for \.{@@i} in newly read line, |goto restart| if
- include fails@>@;
- return true;
-}
-
-
-@ Lines must fit into the buffer completely.
-We read all characters sequentially until an end of line is found
-(but do not forget to check for |EOF|!).
-Too long input lines will be truncated.
-This will result in a damaged output if they occur in the
-replacement part of a change file, or in an incomplerte check if the
-matching part is concerned.
-Tab character expansion might be done here.
-@^tab character expansion@>
-
-@<Get line into buffer,...@>=
-{
- register int c; /* the actual character read */
- register char *k; /* where the next character goes */
-
- if (feof(fp))
- @<Handle end of file and return@>@;
-
- inp_desc->limit = k = inp_desc->buffer; /* beginning of buffer */
- while (k<=inp_desc->buffer_end && (c=getc(fp)) != EOF && c!='\n')
- if ((*(k++) = c) != ' ') inp_desc->limit = k;
- if (k>inp_desc->buffer_end)
- if ((c=getc(fp))!=EOF && c!='\n') {
- ungetc(c, fp); inp_desc->loc=inp_desc->buffer;
- err_print(i, "! Input line too long");
-@.Input line too long@>
- }
- if (c==EOF && inp_desc->limit==inp_desc->buffer)
- @<Handle end of file...@>@;
-
- @<Increment the line number and print a progess report at
- certain times@>@;
-}
-
-
-@ End of file is special if this file is the master file.
-Then we set the global flag variable |input_has_ended|.
-
-@<Handle end of file ...@>=
-{
- inp_desc->mode=ignore;
- inp_desc->limit=NULL; /* mark end-of-file */
- if (inp_desc->type_of_file==master) input_has_ended=true;
- fclose(fp);
- return false;
-}
-
-
-@ This variable must be declared for global access.
-
-@<Global variables@>=
-boolean input_has_ended=false;
-
-
-@ This section does what its name says. Every 100 lines
-in the master file we print a dot, every 500 lines the number
-of lines is shown.
-
-@<Increment the line number and print ...@>=
-inp_desc->line++;
-if (inp_desc->type_of_file==master && inp_desc->line % 100==0) {
- if (inp_desc->line % 500 == 0) printf("%ld", inp_desc->line);
- else putchar('.');
- fflush(stdout);
-}
-
-
-@ The following is very similar to the above, but for the case where
-we are reading from an include file.
-
-@<Get include line into buffer or |goto restart| if end of file@>=
-{
- register int c; /* the actual character read */
- register char *k; /* where the next character goes */
-
- if (feof(fp))
- @<Handle end of include file and |goto restart|@>@;
-
- inp_desc->limit = k = inp_desc->buffer; /* beginning of buffer */
- while (k<=inp_desc->buffer_end && (c=getc(fp)) != EOF && c!='\n')
- if ((*(k++) = c) != ' ') inp_desc->limit = k;
- if (k>inp_desc->buffer_end)
- if ((c=getc(fp))!=EOF && c!='\n') {
- ungetc(c, fp); inp_desc->loc=inp_desc->buffer;
- err_print(i, "! Input line too long");
-@.Input line too long@>
- }
- if (c==EOF && inp_desc->limit==inp_desc->buffer)
- @<Handle end of include file...@>@;
-
- inc_desc->line++;
-}
-
-@ We don't bail out if we find the end of an include file, we just
-return to the parent file.
-
-@<Handle end of include file and |goto restart|@>=
-{
- include_description *temp=inc_desc->parent;
-
- fclose(fp);
- free(inc_desc);
- total_include_files--;
- inp_desc->current_include=temp;
- goto restart;
-}
-
-
-@ Usually, we have to check the line we have just read to see whether
-it begins with \.{@@i} and therefore needs expanding.
-
-@<Check for \.{@@i} in newly read line...@>=
-{
- inp_desc->loc=inp_desc->buffer;
- *inp_desc->limit=' ';
- if (*inp_desc->buffer=='@@' &&
- (inp_desc->buffer[1]=='i' || inp_desc->buffer[1]=='I')) {
- inp_desc->loc=inp_desc->buffer+2;
- *inp_desc->limit='"'; /* this will terminate the search in all cases */
- while (*inp_desc->loc==' '||*inp_desc->loc=='\t')
- inp_desc->loc++;
- if (inp_desc->loc>=inp_desc->limit) {
- err_print(i, "! Include file name not given");
-@.Include file name ...@>
- goto restart;
- }
- if (total_include_files>=max_include_files) {
- err_print(i, "! Too many nested includes");
-@.Too many nested includes@>
- goto restart;
- }
- total_include_files++; /* push input stack */
- @<Try to open include file, abort push if unsuccessful, go to |restart|@>;
- }
-}
-
-
-@ When an \.{@@i} line is found in the 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() {total_include_files--; free(new_inc);
- err_print(i, "! Include file name too long"); goto restart;}
-
-@<Try to open...@>=
-{
- include_description *new_inc;
- char temp_file_name[max_file_name_length];
- char *file_name_end;
- char *k, *kk;
- int l; /* length of file name */
-
- new_inc=(include_description *) malloc(sizeof(include_description));
- if (new_inc==NULL)
- fatal_error(i, "! No memory for new include descriptor", "");
- new_inc->line=0;
- k=new_inc->file_name;
- file_name_end=k+max_file_name_length-1;
-
- if (*inp_desc->loc=='"') {
- inp_desc->loc++;
- while (*inp_desc->loc!='"' && k<=file_name_end)
- *k++=*inp_desc->loc++;
- if (inp_desc->loc==inp_desc->limit)
- k=file_name_end+1; /* unmatched quote is `too long' */
- } else
- while (*inp_desc->loc!=' '&&*inp_desc->loc!='\t'&&
- *inp_desc->loc!='"'&&k<=file_name_end) *k++=*inp_desc->loc++;
- if (k>file_name_end) too_long();
-@.Include file name ...@>
- *k='\0';
- if ((new_inc->the_file=fopen(new_inc->file_name, "r"))!=NULL) {
- new_inc->parent=inp_desc->current_include; /* link it in */
- inp_desc->current_include=new_inc;
- 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>=file_name_end) too_long();
- for (; k>= new_inc->file_name; k--) *(k+l+1)=*k;
- strcpy(new_inc->file_name, temp_file_name);
- new_inc->file_name[l]='/'; /* \UNIX/ pathname separator */
- if ((new_inc->the_file=fopen(new_inc->file_name, "r"))!=NULL) {
- new_inc->parent=inp_desc->current_include; /* link it in */
- inp_desc->current_include=new_inc;
- goto restart; /* success */
- }
- }
- total_include_files--;
- free(new_inc);
- err_print(i, "! Cannot open include file");
-@.Cannot open include file@>
- goto restart;
-}
-
-
-
-@* Reporting errors to the user.
-There may be errors if a line in a given change
-file does not match a line in the master file or a
-replacement in a previous change file. Such errors are
-reported to the user by saying
-$$
- \hbox{|err_print(file_no, "! Error message")|;}
-$$
-where |file_no| is the number of the file which is concerned by the
-error. Please note that no trailing dot is supplied in the error
-message because it is appended by |err_print|.
-
-@<Predecl...@>=
-void err_print();
-
-@ Here is the outline of the |err_print| function.
-
-@<Error handling...@>=
-void err_print(i, s) /* prints `\..' and location of error message */
-file_index i; char *s;
-{
- char *k, *l; /* pointers into an appropriate |buffer| */
- fprintf(stderr, *s=='!'? "\n%s" : "%s", s);
- if(i>=0) @<Print error location based on input buffer@>@;
- else putc('\n', stderr);
- fflush(stderr);
- history=troublesome;
-}
-
-@ The error locations can be indicated by using the variables
-|loc|, |line| and |file_name| within the appropriate file description
-structures, which tell respectively the first
-unlooked-at position in the |buffer|, the current line number and the
-current file. We can determine whether we are looking at an included
-file or not by examining the |current_include| variable.
-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@>=
-{
- register input_description *inp_desc=input_organisation[i];
- register include_description *inc_desc=inp_desc->current_include;
-
- if (inc_desc!=NULL) {
- fprintf(stderr, ". (l. %ld of include file %s", inc_desc->line,
- inc_desc->file_name);
- fprintf(stderr, " included from l. %ld of %s file %s)\n",
- inp_desc->line,
- inp_desc->type_of_file==master?"master":"change",
- inp_desc->file_name);
- }
- else
- fprintf(stderr, ". (l. %ld of %s file %s)\n", inp_desc->line,
- inp_desc->type_of_file==master?"master":"change",
- inp_desc->file_name);
- l=(inp_desc->loc>=inp_desc->limit? inp_desc->limit: inp_desc->loc);
- if (l>inp_desc->buffer) {
- for (k=inp_desc->buffer; k<l; k++)
- if (*k=='\t') putc(' ', stderr);
- else putc(*k, stderr); /* print the characters already read */
- putc('\n', stderr);
- for (k=inp_desc->buffer; k<l; k++)
- putc(' ', stderr); /* space out the next line */
- }
- for (k=l; k<inp_desc->limit; k++)
- putc(*k, stderr); /* print the part not yet read */
- putc('\n', stderr);
-}
-
-
-@ Non recoverable errors are handled by calling |fatal_error| that
-outputs a message and then calls `|wrap_up|' and exits. |err_print|
-will print the error message followed by an indication of where the
-error was spotted in the source files. |fatal_error| cannot state any
-files because the problem is usually to access these.
-
-@d fatal_error(i, s, t) {
- fprintf(stderr, "\n%s", s);
- err_print(i, t);
- history=fatal;
- exit(wrap_up());
- }
-
-
-@ 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@>
-
-@<Internal func...@>=
-int wrap_up()
-{
- @<Print the job |history|@>;
- if (history > spotless) return 1;
- else return 0;
-}
-
-@ Always good to prototype.
-
-@<Predecl...@>=
-int wrap_up();
-
-@ We report the history to the user, although this may not
-be ``\UNIX/'' style---but we are in good company: \.{WEB} and
-\TEX/ do the same. We put this on |stdout| rather than |stderr|, so
-that users can easily filter this away if they wish.
-@^system dependencies@>
-
-@<Print the job |history|@>=
-switch (history) {
- case spotless:
- printf("\n(No errors were found.)\n"); break;
- case troublesome:
- printf("\n(Pardon me, but I think I spotted something wrong.)\n"); break;
- case fatal: printf("(That was a fatal error, my friend.)\n");
-} /* there are no other cases */
-
-
-@ If there's a system error, we may be able to give the user more
-information with the |pfatal_error| function. This prints out system
-error information if it is available.
-
-@<Predecl...@>=
-void pfatal_error();
-
-@ @<Error handling...@>=
-void pfatal_error(s, t)
-char *s, *t;
-{
- char *strerr=strerror(errno);
-
- fprintf(stderr, "\n%s%s", s, t);
- if (strerr) fprintf(stderr, " (%s)\n", strerr);
- else fprintf(stderr, "\n");
- history=fatal;
- exit(wrap_up());
-}
-
-
-@ We need an include file for the above.
-
-@<Global \&{\#include}s@>=
-#include <errno.h>
-
-
-@* Handling multiple change files.
-In the standard version we take the name of the
-files from the command line.
-It is assumed that filenames can be used as given in the
-command line without changes.
-
-First there are some sections to open all files.
-If a file is not accessible, the run will be aborted.
-Otherwise the name of the open file will be displayed.
-
-@<Prepare the output file@>=
-{
- out_file=fopen(out_name, "w");
- if (out_file==NULL) {
- pfatal_error("! Cannot open/create output file", "");
-@.Cannot open/create output file@>
- }
-}
-
-
-@ The name of the file and the file desciptor are stored in
-global variables.
-
-@<Global variables@>=
-FILE *out_file;
-string out_name;
-
-
-@ For the master file we start by reading its first line into the
-buffer, if we could open it.
-
-@<Get the master file started@>=
-{
- input_organisation[0]->the_file=
- fopen(input_organisation[0]->file_name, "r");
-
- if (input_organisation[0]->the_file==NULL)
- pfatal_error("! Cannot open master file ",
- input_organisation[0]->file_name);
-@.Cannot open master file@>
- printf("(%s)\n", input_organisation[0]->file_name);
- input_organisation[0]->type_of_file=master;
- get_line(0, true);
-}
-
-
-@ For the change files we must skip any comment part and see whether
-there are any changes in it. This is done by |init_change_file|.
-
-@<Prepare the change files@>=
-{
- file_index i;
-
- i=1;
- while (i<no_ch) {
- input_organisation[i]->the_file=
- fopen(input_organisation[i]->file_name, "r");
- if (input_organisation[i]->the_file==NULL)
- pfatal_error("! Cannot open change file ",
- input_organisation[i]->file_name);
-@.Cannot open change file@>
- printf("(%s)\n", input_organisation[i]->file_name);
- init_change_file(i);
- i++;
- }
-}
-
-
-@*Input/output organisation.
-Here's a simple function that checks if two lines
-are different.
-
-@<Internal functions@>=
-boolean lines_dont_match(i, j)
- file_index i, j;
-{
- register input_description *iptr=input_organisation[i],
- *jptr=input_organisation[j];
-
- if (iptr->limit-iptr->buffer != jptr->limit-jptr->buffer)
- return true;
- return strncmp(iptr->buffer, jptr->buffer, iptr->limit-iptr->buffer);
-}
-
-
-@ Function |init_change_file(i)| is used to ignore all
-lines of the input file with index~|i| until the next change
-module is found.
-
-@<Internal functions@>=
-void init_change_file(i)
- file_index i;
-{
- register input_description *inp_desc=input_organisation[i];
- char ccode;
-
- inp_desc->limit=inp_desc->buffer;
- @<Skip over comment lines; |return| if end of file@>@;
- @<Skip to the next nonblank line; |return| if end of file@>@;
- inp_desc->dont_match=0;
-}
-
-
-@ 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...@>=
-while(1) {
- if (!get_line(i, false)) return; /* end of file reached */
- if (inp_desc->limit<inp_desc->buffer+2) continue;
- if (inp_desc->buffer[0]!='@@') continue;
- ccode=inp_desc->buffer[1];
- if (xisupper(ccode)) ccode=tolower(ccode);
- if (ccode=='x') break;
- if (ccode=='y' || ccode=='z' || ccode=='i') {
- inp_desc->loc=inp_desc->buffer+2;
- err_print(i, "! Missing @@x in change file");
-@.Missing @@x...@>
- }
-}
-
-@ Here we are looking at lines following the \.{@@x}.
-
-@<Skip to the next nonblank line...@>=
-do {
- if (!get_line(i, true)) {
- err_print(i, "! Change file ended after @@x");
-@.Change file ended...@>
- return;
- }
-} while (inp_desc->limit==inp_desc->buffer);
-
-
-@ The |put_line| function is used to write a line from
-input buffer |j| to the output file.
-
-@<Internal functions@>=
-void put_line(j)
- file_index j;
-{
- char *ptr=input_organisation[j]->buffer;
- char *lmt=input_organisation[j]->limit;
-
- while(ptr<lmt) putc(*ptr++, out_file);
- putc('\n', out_file);
-}
-
-
-@ The function |e_of_ch_module| returns true if the input
-line from file |i| starts with \.{@@z}.
-
-@<Internal functions@>=
-boolean e_of_ch_module(i)
- file_index i;
-{
- register input_description *inp_desc=input_organisation[i];
-
- if (inp_desc->limit==NULL) {
- err_print(i, "! Change file ended without @@z");
-@.Change file ended without @@z@>
- return true;
- } else if (inp_desc->limit>=inp_desc->buffer+2)
- if (inp_desc->buffer[0]=='@@' &&
- (inp_desc->buffer[1]=='Z' || inp_desc->buffer[1]=='z'))
- return true;
- return false;
-}
-
-
-@ The function |e_of_ch_preamble| returns |true| if the input
-line from file~|i| starts with \.{@@y}.
-
-@<Internal functions@>=
-boolean e_of_ch_preamble(i)
- file_index i;
-{
- register input_description *inp_desc=input_organisation[i];
-
- if (inp_desc->limit>=inp_desc->buffer+2 && inp_desc->buffer[0]=='@@')
- if (inp_desc->buffer[1]=='Y'||inp_desc->buffer[1]=='y') {
- if (inp_desc->dont_match>0) {
- inp_desc->loc=inp_desc->buffer+2;
- fprintf(stderr, "\n! Hmm... %d ", inp_desc->dont_match);
- err_print(i, "of the preceding lines failed to match");
- }
- return true;
- }
- return false;
-}
-
-
-
-@ To process the input file the next section reads a line of the
-current (actual) input file and updates the |input_organisation| for
-all files with index greater than |actual_input|.
-
-@<Process a line, |break| when end of source reached@>=
-{
- file_index test_file;
-
- @<Check the current files for any ends of changes@>@;
- if (input_has_ended && actual_input==0) break; /* all done */
- @<Scan all other files for changes to be done@>@;
- @<Handle output@>@;
- @<Step to next line@>@;
-}
-
-
-@ Any of the current change files may have reached the end of the
-current change. In such a case, intermediate lines must be skipped
-and the next start of change is to be found. This may make a change
-file become inactive if the end of the file is reached.
-
-@<Check the...@>=
-{
- register input_description *inp_desc;
- while (actual_input>0 && e_of_ch_module(actual_input)) {
- inp_desc=input_organisation[actual_input];
- if (inp_desc->type_of_file==master) {
- /* emergency exit, everything mixed up!*/
- fatal_error(-1, "! This can't happen: change file is master file", "");
-@.This can't happen...@>
- }
- inp_desc->mode=search;
- init_change_file(actual_input);
- while ((input_organisation[actual_input]->mode!=reading
- && actual_input>0))
- actual_input--;
- }
-}
-
-
-@ Now we will set |test_input| to the first change file that is being
-tested against the current line. If no other file is testing, then
-|actual_input| refers to a line to write and |test_input| is set to
-|none|.
-
-@d none (-1)
-
-@<Scan all other files...@>=
-test_input=none;
-test_file=actual_input;
-while (test_input==none && test_file<no_ch-1){
- test_file++;
- switch (input_organisation[test_file]->mode) {
- case search:
- if (lines_dont_match(actual_input, test_file)==false) {
- input_organisation[test_file]->mode=test;
- test_input=test_file;
- }
- break;
- case test:
- if (lines_dont_match(actual_input, test_file)) {
- /* error, sections do not match; just note at this point */
- input_organisation[test_file]->dont_match++;
- }
- test_input=test_file;
- break;
- case reading: /* this can't happen */
- break;
- case ignore: /* nothing to do */
- break;
- }
-}
-
-
-@ For the output we must distinguish between whether we are creating a
-new change file or a new master file. Change file creation requires
-closer inspection because we may be before a change, in the pattern
-(match) part or in the replacement part. For master file creation, we
-simply have to write the line from the current (actual) input.
-
-@<Handle output@>=
-if (prod_chf==chf) {
- while(1) {
- @<Test for |normal|, |break| when done@>@;
- @<Test for |pre|, |break| when done@>@;
- @<Test for |post|, |break| when done@>@;
- }
-} else
- if (test_input==none) put_line(actual_input);
-
-
-@ Check whether we have to start a change file entry.
-Without a match nothing needs to be done.
-
-@<Test for |normal|...@>=
-if (out_mode==normal) {
- if (test_input!=none) {
- fprintf(out_file, "@@x\n");
- out_mode=pre;
- } else break;
-}
-
-
-@ Check whether we have to start the replacement text. This is the
-case when we are in |pre| mode but have no more matching lines.
-Otherwise the master file source line must be copied to the change
-file.
-
-@<Test for |pre|...@>=
-if (out_mode==pre) {
- if (test_input==none) {
- fprintf(out_file, "@@y\n");
- out_mode=post;
- } else {
- if (input_organisation[actual_input]->type_of_file==master)
- put_line(actual_input);
- break;
- }
-}
-
-
-@ Check whether an entry from a change file is complete. If the
-current input is from a change file which is not being tested against
-a later change file, then this change file line must be written. If
-the actual input has been reset to the master file, we can finish this
-change.
-
-@<Test for |post|...@>=
-if (out_mode==post) {
- if (input_organisation[actual_input]->type_of_file==chf) {
- if (test_input==none) put_line(actual_input);
- break;
- } else {
- fprintf(out_file, "@@z\n\n");
- out_mode=normal;
- }
-}
-
-
-@ If we had a change, we must proceed in the actual file
-to be changed and in the change file in effect.
-
-@<Step to next line@>=
-get_line(actual_input, true);
-if (test_input!=none) {
- get_line(test_input, true);
- if (e_of_ch_preamble(test_input)==true) {
- get_line(test_input, true); /* update current changing file */
- input_organisation[test_input]->mode=reading;
- actual_input=test_input;
- test_input=none;
- }
-}
-
-
-@ To create the new output file we have to scan the whole
-master file and all changes in effect when it ends.
-At the very end it is wise to check for all changes
-to have completed, in case the last line of the master file
-was to be changed.
-
-@<Process the input@>=
-actual_input=0;
-input_has_ended=false;
-while (input_has_ended==false||actual_input!=0)
- @<Process a line...@>@;
-if (out_mode==post) /* last line has been changed */
- fprintf(out_file, "@@z\n");
-
-
-@ 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 the master file or any of the change files.
-
-@<Check that all changes have been read@>=
-{
- file_index i;
-
- for (i=1;i<no_ch;i++) { /* all change files */
- if (input_organisation[i]->mode!=ignore) {
- input_organisation[i]->loc=input_organisation[i]->buffer;
- err_print(i, "! Change file entry did not match");
-@.Change file entry ...@>
- }
- }
-}
-
-
-@ We want to tell the user about our command line options if they made
-a mistake. This is done by the |usage_error()| function. It contains
-merely the necessary print statements and exits afterwards.
-
-@<Intern...@>=
-void usage_error()
-{
- @<Print the banners@>;
- fprintf(stderr, "Usage: ctie -[mc] outfile master changefile(s)\n");
- fprintf(stderr, "Type ctie --help for more information\n");
- exit(1);
-}
-
-
-@ Printing our welcome banners; we only do this if we are not asked
-for version or help information.
-
-@<Print the banners@>=
-printf("%s\n", banner); /* print a ``banner line'' */
-printf("%s\n", copyright); /* include the copyright notice */
-
-
-@ We must scan through the list of parameters, given in |argv|. The
-number is in |argc|. We must pay attention to the flag parameter. We
-need at least 3~parameters (\.{-m} or \.{-c}, an output file and a
-master file) and can handle up to |max_file_index| change files. The
-names of the file parameters will be inserted into the structure of
-|input_organisation|. The first file is special. It indicates the
-output file. When we allow flags at any position, we must find out
-which name is for what purpose. The master file is already part of
-the |input_organisation| structure (index~0). As long as the number
-of files found (counted in |no_ch|) is |-1| we have not yet found the
-output file name.
-
-@<Scan the parameters@>=
-{
- if (argc>max_file_index+5-1) usage_error();
- no_ch = -1; /* fill this part of |input_organisation| */
- while (--argc>0) {
- argv++;
- if (strcmp("-help", *argv)==0 || strcmp("--help", *argv)==0)
- @<Display help message and exit@>;
- if (strcmp("-version", *argv)==0 || strcmp("--version", *argv)==0)
- @<Display version information and exit@>;
- if (**argv=='-') @<Set a flag@>@;
- else @<Get a file name@>@;
- }
- if (no_ch<=0|| prod_chf==unknown) usage_error();
-}
-
-
-@ The flag is about to determine the processing mode.
-We must make sure that this flag has not been set before.
-Further flags might be introduced to avoid/force overwriting of
-output files.
-Currently we just have to set the processing flag properly.
-
-@<Set a flag@>=
-if (prod_chf!=unknown) usage_error();
-else
- switch (*(*argv+1)) {
- case 'c': case 'C': prod_chf=chf; break;
- case 'm': case 'M': prod_chf=master; break;
- default: usage_error();
- }
-
-
-@ We have to distinguish whether this is the very first file name
-(which is the case if |no_ch==(-1)|) or if the next element of
-|input_organisation| must be filled.
-
-@<Get a file name@>=
-{
- if (no_ch==(-1)) {
- out_name=*argv;
- } else {
- register input_description *inp_desc;
-
- inp_desc=(input_description *) malloc(sizeof(input_description));
- if (inp_desc==NULL)
- fatal_error(-1, "! No memory for input descriptor", "");
-@.No memory for descriptor@>
- inp_desc->mode=search;
- inp_desc->line=0;
- inp_desc->type_of_file=chf;
- inp_desc->limit=inp_desc->buffer;
- inp_desc->buffer[0]=' ';
- inp_desc->loc=inp_desc->buffer+1;
- inp_desc->buffer_end=inp_desc->buffer+buf_size-2;
- inp_desc->file_name=*argv;
- inp_desc->current_include=NULL;
- input_organisation[no_ch]=inp_desc;
- }
- no_ch++;
-}
-
-
-@ Modules for dealing with help messages and version info. We follow
-the \.{kpathsea} standard code here, so that we can easily adapt this
-to work with \.{kpathsea}.
-
-@<Display help message and exit@>=
-usage_help();
-@.--help@>
-
-
-@
-@<Display version information and exit@>=
-{
- print_version_and_exit("CTIE", version_number);
-@.--version@>
-}
-
-
-@ Here is the usage information for \.{--help}.
-
-@<Global variables@>=
-string CTIEHELP[] = {
- "Usage: ctie -[mc] outfile master changefile(s)",
- " Create a new master file or change file from the given",
- " master (C)WEB file and changefiles.",
- " All filenames are taken literally; no suffixes are added.",
- "",
- "-m create a new master file from original (C)WEB and change file(s)",
- "-c create a master change file for original (C)WEB file from changefile(s)",
- "--help display this help and exit",
- "--version display version information and exit",
- NULL
-};
-
-
-@ @<Predec...@>=
-void usage_help();
-void print_version_and_exit();
-
-
-@ @c
-void usage_help()
-{
- string *message=CTIEHELP;
-
- while (*message) {
- fputs(*message, stdout);
- putchar('\n');
- ++message;
- }
- putchar('\n');
- exit(0);
-}
-
-
-@ @c
-void print_version_and_exit(name, version)
- string name, version;
-{
- printf ("%s %s\n", name, version);
-
- puts ("Copyright (C) 2002,2003 Julian Gilbey.");
-
- puts ("There is NO warranty. This is free software. See the source");
- puts ("code of CTIE for redistribution conditions.");
-
- exit (0);
-}
-
-
-@* System-dependent changes.
-This section should be replaced, if necessary, by
-changes to the program that are necessary to make \.{CTIE}
-work at a particular installation. It is usually best to
-design your change file so that all changes to previous
-modules preserve the module numbering; then everybody's
-version will be consistent with the printed program. More
-extensive changes, which introduce new modules, can be
-inserted here; then only the index itself will get a new
-module number.
-@^system dependencies@>
-
-
-@* Index.