talkfilters
***********

Introduction
************

The GNU Talk Filters are filter programs that convert English text into text that mimics a stereotyped or otherwise humorous type of speech. This package is not an original work but rather a collection and integration of existing filter programs that were written by various people and that have been in the public domain for many years. For a list of authors, see Credits.

The filters are provided in both executable and library form. See The Filters for synopses of the programs, and The Talkfilters Library for a description of the library API.

Since the filters do word and substring substitution on the text they process, any word-wrap formatting of the original text will not be preserved in the output. The included wrap filter program may be used to reformat the output of the other filters to fit within a specified number of columns.

Some of these filters contain vulgarity, and thus are not appropriate for all audiences. If you find something offensive in one or more of these filters, please do not flame the maintainer of this package or the original authors, or request that the filter(s) in question be censored or removed; requests of this type will be summarily ignored.

These filters are not guaranteed to be idempotent across all inputs; that is, repeated applications of a given filter on an input may cause the output to differ each time. Moreover, some of the filters use randomization techniques so a given input is not guaranteed to produce the same output across invocations.

The `flex' lexer (or any other lexer program, for that matter) is not required to build and use this package. However, `flex' is required to rebuild the filters if the .l source files are changed.

These filters are provided for amusement only. No racial or societal slurs are intended nor should be inferred.

The Filters
***********

The filters provided in this package are enumerated below. This chapter describes the synopses for the individual filter programs; for a description of the library API, see The Talkfilters Library.

austro   Austrian (Ahhhhnold)
b1ff   B1FF of USENET yore
brooklyn   Brooklyn accent
chef   Swedish Chef (from The Muppet Show)
cockney   Londoner accent
drawl   Southern drawl
dubya   George "Dubya" Bush
fudd   Elmer Fudd (from the Looney Tunes cartoons)
funetak   Thick Asian accent
jethro   Jethro from The Beverly Hillbillies
jive   1970's Jive
kraut   German accent
pansy   Effeminate male
pirate   Pirate talk
postmodern   Postmodernist talk (``Feminazi'')
redneck   Country redneck
valspeak   Valley talk
warez   H4x0r code
wrap   Word-wrap filter

The filter programs read from standard input and write to standard output. They all recognize the following switches:

--version
     Print version information and exit.

--help
     Print usage information and exit.

The wrap filter program additionally recognizes the following switch:

-w width
     Specify the maximum number of columns width that the text may span. The minimum value of width is 10.

An example usage might be:

     man ls | jive | wrap -w 78 | less

The Talkfilters Library
***********************

All of the filters in the GNU Talk Filters are available collectively as a C library which can be linked with other programs to provide embedded text filtering support. While the individual filter programs filter from standard input to standard output, the filtering functions in the library operate on in-memory buffers instead.

This chapter describes the API to the Talkfilters library. All of the functions and types described below are declared in the header file talkfilters.h.

 -- Function: int gtf_filter_count (void)

     This function returns the number of filters in the library.

 -- Function: gtf_filter_t * gtf_filter_list (void)

     This function returns a pointer to an array of gtf_filter_t structures which contain information about each of the filters in the library, including the filter's symbolic name, a brief description of the filter that is suitable for display purposes, and a pointer to the filter function.

The following C program illustrates the use of gtf_filter_count() and gtf_filter_list() to display information about each filter in the library and invoke the filter on some test input:

     #include <stdio.h>
     #include <talkfilters.h>

     int main(void)
       {
       int ct, i;
       const gtf_filter_t *filters, *fp;
       const char *inbuf = "This is a test.";
       char outbuf[1024];

       ct = gtf_filter_count();
       printf("There are %d filters available.\n", ct);
       filters = gtf_filter_list();
       for(i = 0, fp = filters; i < ct; i++, fp++)
         {
         printf("filter #%d: %s - %s\n", i + 1, fp->name, fp->desc);
         fp->filter(inbuf, outbuf, sizeof(outbuf));
         puts(outbuf);
         }

       exit(0);
       }

The type gtf_filter_t is a structure which contains the following members:

char *name
     The symbolic name of the filter.

char *desc
     A brief description of the filter.

int (*filter)(const char *, char *, size_t)
     The filter function.

 -- Function: gtf_filter_t * gtf_filter_lookup (const char *NAME)

     This is a lookup function for locating a specific filter. The function searches for the filter with the symbolic name NAME, and returns a pointer to the gtf_filter_t structure for that filter. If a filter with the given name is not found, the function returns NULL.

 -- Function: int gtf_filter_austro (const char *INPUT, char *BUF, size_t BUFSZ)
 -- Function: int gtf_filter_b1ff (const char *INPUT, char *BUF, size_t BUFSZ)
 -- Function: int gtf_filter_brooklyn (const char *INPUT, char *BUF, size_t BUFSZ)
 -- Function: int gtf_filter_chef (const char *INPUT, char *BUF, size_t BUFSZ)
 -- Function: int gtf_filter_cockney (const char *INPUT, char *BUF, size_t BUFSZ)
 -- Function: int gtf_filter_drawl (const char *INPUT, char *BUF, size_t BUFSZ)
 -- Function: int gtf_filter_dubya (const char *INPUT, char *BUF, size_t BUFSZ)
 -- Function: int gtf_filter_fudd (const char *INPUT, char *BUF, size_t BUFSZ)
 -- Function: int gtf_filter_funetak (const char *INPUT, char *BUF, size_t BUFSZ)
 -- Function: int gtf_filter_jethro (const char *INPUT, char *BUF, size_t BUFSZ)
 -- Function: int gtf_filter_jive (const char *INPUT, char *BUF, size_t BUFSZ)
 -- Function: int gtf_filter_kraut (const char *INPUT, char *BUF, size_t BUFSZ)
 -- Function: int gtf_filter_pansy (const char *INPUT, char *BUF, size_t BUFSZ)
 -- Function: int gtf_filter_pirate (const char *INPUT, char *BUF, size_t BUFSZ)
 -- Function: int gtf_filter_postmodern (const char *INPUT, char *BUF, size_t BUFSZ)
 -- Function: int gtf_filter_redneck (const char *INPUT, char *BUF, size_t BUFSZ)
 -- Function: int gtf_filter_valspeak (const char *INPUT, char *BUF, size_t BUFSZ)
 -- Function: int gtf_filter_warez (const char *INPUT, char *BUF, size_t BUFSZ)

     These functions invoke the corresponding filters on the input buffer INPUT, which must be a NUL-terminated string. At most BUFSZ - 1 bytes of output are written to the buffer BUF. The output is unconditionally NUL-terminated, but the text itself may be truncated if the buffer is too small to accommodate all of the output.

     The functions return 0 on success, or 1 if a buffer overflow occurred (signifying that the output was truncated).

     Note that lexical scanners generated by `flex' are not reentrant, so no assumptions should be made about the reentrancy of the above functions. When this library is used in a multithreaded environment, calls to these functions should be protected by mutex locks.

Writing New Filters
*******************

Writing new filters and adding them to the library is fairly straightforward, but certain conventions must be observed to ensure that the filters will work properly both as standalone programs and as library functions. The internal header file common.h declares some utility functions and macros that should be used to ensure proper behavior.

 -- Macro: gtf_parse_args ()

     A filter's main() function should make a call to this macro to process the command line arguments. Currently, only the standard --help and --version switches are recognized. A call to this macro should typically be the first statement in main().

 -- Macro: gtf_random_seed ()

     Filters which make calls to the gtf_random() macro (described below), should make a call to this macro (preferably in main()) to seed the random number generator. This macro seeds the random number sequence with a bitwise OR of the current system time and the PID of the calling process.

 -- Macro: gtf_random (range)

     This macro returns a random integer in the range [0, RANGE).

 -- Macro: gtf_printf (format, ...)
 -- Macro: gtf_putc (char)
 -- Macro: gtf_puts (string)

     Filters must be able to function both as standalone programs and as library functions, so the stdio library functions cannot be used to write output. Instead, these macros should be used in place of the stdio library functions printf(), putchar(), and puts(), respectively. When a filter is compiled to run as an executable, these macros simply evaluate to calls to the stdio functions they replace; when it is compiled into the library, they evaluate to calls to internal library functions which write to a data buffer.

 -- Macro: gtf_puts_case (string)

     This macro is a specialized form of gtf_puts() which ensures that the case of the first character in STRING matches that of the first character in the currently matched token. For example, if yytext is ``Hello'', calling gtf_puts_case() with either ``howdy'' or ``Howdy'' as an argument will write the string ``Howdy'', whereas if yytext is ``hello'', the string written will be ``howdy''.

 -- Macro: gtf_unput_last ()

     This macro ``unputs'' the last character of the current token. In other words, the last character of yytext will be returned back to the input stream, so that it will be the next character read by the lexical scanner.

 -- Function: void gtf_strbuf_init (gtf_databuf_t *SBUF, char *BUF, size_t BUFSZ)

     This function initializes the gtf_databuf_t structure at SBUF to point to the buffer BUF, which is BUFSZ bytes in length; these values specify the buffer to which the gtf_printf(), gtf_putc(), gtf_puts(), and gtf_puts_case() macros will ultimately write their output when the filter is called through the library API. The gtf_databuf_t structure contains an integer field named overflow which will contain the value 1 after the call to yylex() if a buffer overflow occurred during filtering; otherwise it will contain the value 0.

 -- Macro: gtf_reset ()

     This macro should be called after the call to yylex() within the filter API function in order to reset the state of the lexical scanner in preparation for the next call.

The following example shows the C code that implements both the library interface and the main() function for the chef filter.

     #ifdef LIBRARY_MODE

     int gtf_filter_chef(const char *input, char *buf, size_t bufsz)
       {
       gtf_databuf_t buffer;
       YY_BUFFER_STATE _yybuf;

       gtf_strbuf_init(&buffer, buf, bufsz);
       _yybuf = yy_scan_string(input);
       yylex(&buffer);
       yy_delete_buffer(_yybuf);
       gtf_reset();

       return(buffer.overflow);
       }

     #else /* LIBRARY_MODE */

     int main(int argc, char **argv)
       {
       gtf_parse_args();

       yylex(NULL);

       exit(EXIT_SUCCESS);
       }

     #endif /* LIBRARY_MODE */

Each filter lex file must have an introductory fragment similar to the following:

     %option prefix="chef_yy"
     %option outfile="lex.yy.c"
     %option noyywrap

     %{

     #include "common.h"

     #define YY_DECL int yylex(gtf_databuf_t *buf)

     %}

The prefix option specifies a prefix for the names of the functions generated for this filter; the function names for each filter must be unique so that multiple filters can coexist within the library.

The outfile option reverses an undesirable side effect of the prefix option, which is to name the generated C source file based on the prefix; this breaks ylwrap (an Automake helper program), which expects the output file to be named lex.yy.c.

The noyywrap option specifies that no yywrap() function is needed.

The macro YY_DECL is defined to specify that the yylex() function takes a single argument, a pointer to the gtf_databuf_t structure described above. When yylex() is called from main(), no output buffer is needed since text is written to standard output, so in that case, it is called with a NULL pointer as the argument. This function can be declared to accept additional arguments, but the BUF argument must be present.

The file talkfilters.c contains a filter registry in the form of an array of structures. Entries should be added therein for new filters. Appropriate extern declarations of the API functions for new filters should also be added to talkfilters.h.

Credits
*******

While all of these filters have been available in one form or another in the public domain for many years, the original authors of some of the filters are unknown. Reasonable attempts were made to find the authors and obtain written permission to repackage the filters as GNU software, but in some cases they could not be located.

The following table lists the known authors and contributors.

austro   Tom van Nes
b1ff   Matt Welsh, David Whitten
brooklyn   Daniel V Klein (nyc.l)
chef   John Hagerman
cockney   Stephen K Mulrine, Edward Betts (ken.l); unknown (cockney.l); extensive enhancements by Samuel Stoddard
drawl   Adam Hudd
dubya   anonymous contribution
fudd   unknown
funetak   Eclipse Enterprises
jethro   Duane Paulson
jive   Daniel V Klein, Clement Cole, with enhancements by Samuel Stoddard
kraut   unknown
pansy   unknown
pirate   Original Perl/PHP version by Dougal Campbell, with enhancements by Mark Lindner
postmodern   unknown
redneck   Brand Hilton
valspeak   unknown
warez   Ian Johnston, with enhancements by Mark Lindner
wrap   Mark Lindner

The filters were repackaged, integrated, optimized, and documented by Mark Lindner (markl@gnu.org).

Software License
****************

     [file gpl.texi not included]