%
%                            W R E T C H
%                       The Ink-Stained Wretch
%
%                     A Torture Test for QPRINT
%
%                           by John Walker
%                      http://www.fourmilab.ch/

@** Introduction.

\vskip 15pt
\centerline{\ttitlefont WRETCH}
\vskip 10pt
\centerline{\titlefont Torture Test for \.{QPRINT}}
\vskip 15pt
\centerline{\pdfURL{by John Walker}{http://www.fourmilab.ch/}}

\vskip 15pt
\centerline{This program is in the public domain.}

\vskip 30pt

@d REVDATE "26th February 2001"

@** Program global context.
@d TRUE  1
@d FALSE 0
@d LINELEN 72  /* Encoded line length (max 76) */

@c
#include "config.h"                   /* System-dependent configuration */

@h

@<System include files@>@/
@<Windows-specific include files@>@/
@<Global variables@>@/

@ Because we may be built on an EBCDIC system, we can't assume
  that quoted characters generate the ASCII character codes we
  require for output.  The following definitions provide the
  ASCII codes for characters we need in the program.

@d ASCII_TAB  9                 /* Tab */
@d ASCII_LINE_FEED  10          /* Line feed */
@d ASCII_CARRIAGE_RETURN 13     /* Carriage return */
@d ASCII_SPACE 32               /* Space */
@d ASCII_0  48                  /* Digit 0 */
@d ASCII_EQUAL_SIGN 61          /* Equal sign */
@d ASCII_A  65                  /* Letter A */
@d ASCII_LOWER_CASE_A  97       /* Letter a */ 


@ We include the following POSIX-standard C library files.
  Conditionals based on a probe of the system by the
  \.{configure} program allow us to cope with the
  peculiarities of specific systems.
 
@<System include files@>=
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif

@ The following include files are needed in Win32 builds
  to force binary mode for the output file.

@<Windows-specific include files@>=
#ifdef _WIN32
#define FORCE_BINARY_IO
#endif

@ These variables are global to all procedures; many are used
  as ``hidden arguments'' to functions in order to simplify
  calling sequences.

@<Global variables@>=
typedef unsigned char byte;           /* Byte type */

static FILE *fo;                      /* Output file */

@** Executable program.

@
Our first test is one of the most fundamental: can we
correctly represent all 256 binary codes?  Note that
this test assumes we're encoding the file in binary mode,
as otherwise the potential end of line codes will be
encoded according to the vagaries of the host system.

@<Generate all 256 binary codes@>=
    for (i = 0; i < 256; i++) {
        putc(i, fo);
    }

@
Next, we probe the interactions between binary codes and
end of line sequences in various modes by emitting a sequence
of lines with lengths ranging from 0 through 256 characters,
each containing binary characters in the corresponding range.
Encoding this in text mode is a very dubitable operation, but
it should produce reproducible results on all platforms.

@<Generate line length cascade of binary codes@>=
    for (i = 0; i < 256; i++) {
        for (j = 0; j <= i; j++) {
            putc(j, fo);
        }
        @<Emit standard CR/LF sequence@>;
    }

@
The following excerpt from Jules Verne's {\it De la terre \`a la lune}
serves as a test of our handling of routine Latin-1 characters with
embedded white space and line breaks.

@c

static char *verne_test_text[] = {
    "Des récipients solidement assujettis étaient destinés à contenir l'eau",
    "et les vivres nécessaires aux trois voyageurs; ceux-ci pouvaient même",
    "se procurer le feu et la lumière au moyen de gaz emmagasiné dans un",
    "récipient spécial sous une pression de plusieurs atmosphères.  Il",
    "suffisait de tourner un robinet, et pendant six jours ce gaz devait",
    "éclairer et chauffer ce confortable véhicule.  On le voit, rien ne",
    "manquait des choses essentielles à la vie et même au bien-être.  De",
    "plus, grâce aux instincts de Michel Ardan, l'agréable vint se joindre",
    "à l'utile sous la forme d'objets d'art; il eût fait de son projectile",
    "un véritable atelier d'artiste, si l'espace ne lui eût pas manqué.  Du",
    "reste, on se tromperait en supposant que trois personnes dussent se",
    "trouver à l'étroit dans cette tour de métal.  Elle avait une surface",
    "de cinquante-quatre pieds carrés à peu près sur dix pieds de hauteur,",
    "ce qui permettait à ses hôtes une certaine liberté de mouvement.  Ils",
    "n'eussent pas été aussi à leur aise dans le plus confortable wagon des",
    "États-Unis.",
    NULL
};

@
We commence our excursion into Latin-1 with a simple case: the
Jules Verne text above output as individual lines with an end of
line sequence between each.

@<Generate Latin-1 test with line breaks@>=
    for (i = 0; verne_test_text[i] != NULL; i++) {
        fputs(verne_test_text[i], fo);
        @<Emit standard CR/LF sequence@>;
    }

@
Next, let's abuse the program by reiterating our Latin-1
text as a single text line.  This will force soft line breaks
in all kinds of circumstances by the program.

@<Generate Latin-1 test without any line breaks@>=
    for (i = 0; verne_test_text[i] != NULL; i++) {
        fputs(verne_test_text[i], fo);
        if (verne_test_text[i + 1] == NULL) {
            @<Emit standard CR/LF sequence@>;
        } else {
            /* Alternate space and tab line separators to be nasty. */
            fputc((i & 1) ? ASCII_SPACE : ASCII_TAB, fo);
        }
    }

@
Write an ASCII carriage return / line feed sequence to the output
file.

@<Emit standard CR/LF sequence@>=
    putc(ASCII_CARRIAGE_RETURN, fo);
    putc(ASCII_LINE_FEED, fo);

@
We also want to test input with all of the different end of
line sequences we may encounter in input.  The following
procedure accepts an argument between 0 and 3 which determines
which of the sequences is emitted.

@c
static void emit_selected_end_of_line_sequence(int which)
{
    switch (which) {
        case 0:         /* CR LF */
            @<Emit standard CR/LF sequence@>;
            break;

        case 1:         /* LF CR */
            putc(ASCII_LINE_FEED, fo);
            putc(ASCII_CARRIAGE_RETURN, fo);
            break;

        case 2:         /* CR */
            putc(ASCII_CARRIAGE_RETURN, fo);
            break;

        case 3:         /* LF */
            putc(ASCII_LINE_FEED, fo);
            break;
    }
}

@
We begin verification of correct operation with variant
end of line sequences by generating the Verne quotation
with successive lines terminated by the variant sequences
in rotation.

@<Generate Latin-1 test with variant line breaks@>=
    for (i = 0; verne_test_text[i] != NULL; i++) {
        fputs(verne_test_text[i], fo);
        emit_selected_end_of_line_sequence(i & 3);
    }

@
Moving right along, we next generate a sequence of blank
lines in all combinations of end of line conventions.

@<Generate consecutive blank lines in various line breaks@>=
    for (i = 0; i <= 3; i++) {
        for (j = 0; j <= 3; j++) {
            emit_selected_end_of_line_sequence(i);
            emit_selected_end_of_line_sequence(j);
        }
    }

@ Main program.

@c

int main(int argc, char *argv[])
{
    int i, j;

    fo = fopen("wretch.bin",
#ifdef FORCE_BINARY_IO
                              "wb"
#else
                              "w"
#endif
              );

    @<Generate all 256 binary codes@>;
    @<Generate line length cascade of binary codes@>;
    @<Generate Latin-1 test with line breaks@>;
    @<Generate Latin-1 test without any line breaks@>;
    @<Generate Latin-1 test with variant line breaks@>;
    @<Generate consecutive blank lines in various line breaks@>;

    return 0;
}

@** Index.
The following is a cross-reference table for \.{wretch}.
Single-character identifiers are not indexed, nor are
reserved words.  Underlined entries indicate where
an identifier was declared.
