/*  file: ca.c  */

/*
 *  Unix: gcc -o ca ca.c -lX11
 *
 *  DOS:  Compile with Borland C 3.1
 *        Link with EGAVGA.OBJ
 */

/*  Remove the next line if using X11R3 or older  */
#define X11R4UP

#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef __MSDOS__
#  include <bios.h>
#  include <dir.h>
#  include <dos.h>
#  include <graphics.h>
#else  /* X11 */
#  include <unistd.h>
#  include <X11/Xlib.h>
#  include <X11/Xutil.h>
#  include <X11/cursorfont.h>
#endif  /* X11 */

#ifndef __MSDOS__  /* X11 */
#define BORDER_WIDTH 0
#define APPL_CLASS "Automata"
#endif  /* X11 */

enum MODUS { SCR, ROOT, XPM, DUMP };

char
#ifndef __MSDOS__
    *color [4] = { "black", "blue", "green", "red" },
#endif
    buffer [1024],
    rule [1024],
    *line0,
    *line1,
    *programname;

int
    scale = 1,
    border = 1,
    verbose = 1,
    pages = -1,
    skip = 0,
    modus = SCR,
    iso = 0,
    async = 0,
    height = 0,
    width = 0,
    seconds = 0,
    *ro,
    ln = 0;

long
    seed,
    rand_val;

float
    lambda = 0.4;

void
    syntax (void),
    message (void),
    get_programname (char const *argv0),
    errit (char const *format, ...);

#ifdef __MSDOS__

int
    in_graph = 0;

void
    start_graph (void),
    close_graph (void);

int
    escape_pressed (void);

#else  /* X11 */

#ifdef X11R4UP
Atom
    wm_delete_window;
#endif

Window OpenWindow (
    Display *display,
    Window parent,
    int x,
    int y,
    int width,
    int height,
    unsigned long bordercolor,
    unsigned long backcolor,
    unsigned long event_mask,
    Visual * visual);

void
    SetStandardHints (
        Display *display,
        Window window,
        char app_name[],
        char wind_name[],
        int width, int height,
        int max_width, int max_height);

int
    SetUpVisual (Display *display, int screen, Visual **visual, int *depth),
    SetUpColormap (
        Display *display,
        int screen,
        Window window,
        Visual *visual,
        Colormap *colormap),
    QuitPressed (XEvent *event);

unsigned long
    AllocNamedColor (
        Display *display,
        Colormap colormap,
        char colorname [],
        unsigned long default_color);

Display *ConnectToServer (
    char display_name [],
    int *screen,
    Window *rootwindow);

#endif  /* X11 */

char
    *get_arg (int *argc, char *argv [], int *index);

long
    p_rand (void);

int main (int argc, char *argv [])
{
#ifdef __MSDOS__

    int
	c [4] = {0, 9, 10, 12};

#else  /* X11 */

    Display
        *display;
    XGCValues
        xgcvalues;
    Window
        window,
        rootwindow;
    GC
        pix_gc;
    Pixmap
        pixmap;
    Visual
        *visual = CopyFromParent;
    Colormap
        colormap;
    XEvent
        event;
    XRectangle
        *rectangles [4];
    Cursor
        cursor_watch;
    unsigned long
        max_req_size,
        c [4];
    int
        p [4],
        screen,
        status,
        depth;

#endif  /* X11 */

    int
	dot,
	page,
	i,
	n,
        m,
	r,
	t,
	y,
	v [5];
    long
	ln;

    get_programname (argv [0]);

    seed = (long) time (NULL);

    for (i = 1; i < argc; i++)
	if (argv [i][0] == '-')
	    switch (argv [i][1]) {
		case '1':
		    scale = 1;
		    break;
		case '2':
		    scale = 2;
		    break;
		case '3':
		    scale = 3;
		    break;
		case '4':
		    scale = 4;
		    break;
		case '5':
		    scale = 5;
		    break;
		case '6':
		    scale = 6;
		    break;
		case '7':
		    scale = 7;
		    break;
		case '8':
		    scale = 8;
		    break;
		case '9':
		    scale = 9;
		    break;
		case 'a':
		    async = 1;
		    break;
#ifndef __MSDOS__
                case 'c':
                    n = argv [i][2] - '0';
		    if (n >= 0 && n <= 3) {
                        argv [i]++;
                        color [n] = get_arg (&argc, argv, &i);
                    } else
                        syntax ();
                    break;
#endif
		case 'd':
                    modus = DUMP;
		    break;
		case 'f':
		    border = 0;
                    break;
		case 'h':
                    if ((height = atoi (get_arg (&argc, argv, &i))) < 10)
                        errit ("Illegal height");
                    break;
                case 'i':
                    iso = 1;
                    break;
                case 'l':
                    n = sscanf (
                        get_arg (&argc, argv, &i),
                        "%f",
                        &lambda);
                    if (n != 1 || lambda < 0.0 || lambda > 1.0)
                        errit ("Illegal value for lambda");
                    break;
                case 'n':
                    n = sscanf (
                        get_arg (&argc, argv, &i),
                        "%i",
			&skip);
		    if (n != 1 || skip < 1)
			errit ("Illegal number of lines to skip");
                    break;
                case 'p':
                    n = sscanf (
                        get_arg (&argc, argv, &i),
                        "%i",
                        &pages);
                    if (n != 1 || pages < 0)
			errit ("Illegal number of pages");
                    break;
		case 'q':
                    verbose = 0;
                    break;
#ifndef __MSDOS__  /* X11 */
		case 'r':
                    modus = ROOT;
                    break;
#endif  /* X11 */
		case 's':
                    sscanf (get_arg (&argc, argv, &i), "%li", &seed);
                    break;
		case 't':
                    if ((seconds = atoi (get_arg (&argc, argv, &i))) < 0)
                        errit ("Illegal time");
                    break;
		case 'w':
                    if ((width = atoi (get_arg (&argc, argv, &i))) < 10)
                        errit ("Illegal width");
                    break;
		case 'x':
                    modus = XPM;
                    break;
                default:
                    syntax ();
	    }
	else
	    syntax ();

    if (scale == 1)
        border = 0;

#ifndef __MSDOS__ /* X11 */
#ifndef X11R4UP
    if (verbose && modus == SCR)
        fprintf (stderr, "\nPress 'q' in window to quit\n\n");
#endif
#endif  /* X11 */

    if (pages < 0)
        pages = ((modus == ROOT) ? 1 : 0);

    rand_val = seed;

    ro = (int *) malloc (1024 * sizeof (int));
    for (i = 0; i < 1024; i++) {
	rule [i] = 0;
	ro [i] = i;
    }
    for (i = 1023; i > 1; i--) {
	r = 1 + (int)(p_rand () % i);
	t = ro [i];
	ro [i] = ro [r];
	ro [r] = t;
    }
    t = (int)(1023.0 * lambda);
    for (i = 1; i <= t; i++) {
        r = 1 + (int)(p_rand () % 3);
	if (iso) {
	    v [0] =  ro [i]        % 4;
	    v [1] = (ro [i] /   4) % 4;
	    v [2] = (ro [i] /  16) % 4;
	    v [3] = (ro [i] /  64) % 4;
	    v [4] = (ro [i] / 256) % 4;
	    rule [v [0] + 4 * v [1] + 16 * v [2] + 64 * v [3] + 256 * v [4]] =
	    rule [v [1] + 4 * v [3] + 16 * v [2] + 64 * v [4] + 256 * v [0]] =
	    rule [v [3] + 4 * v [4] + 16 * v [2] + 64 * v [0] + 256 * v [1]] =
	    rule [v [4] + 4 * v [0] + 16 * v [2] + 64 * v [1] + 256 * v [3]] =
		r;
	    r = 0;
	    for (n = 0; n < 1024; n++)
		if (rule [n])
		    r++;
	    if (r >= t)
		break;
	} else
	    rule [ro [i]] = r;
    }
    free (ro);

    if (modus == DUMP) {
	for (i = 0; i < 1024; i++)
	    printf (((i % 32) == 31) ? "%i\n" : "%i ", (int) rule [i]);
	message ();
	return 0;
    }

#ifndef __MSDOS__  /* X11 */
    message ();
#endif

    if (modus == SCR) {
#ifdef __MSDOS__
	start_graph ();
	height = (getmaxy () + 1) / scale;
	width = (getmaxx () + 1) / scale;
#else  /* X11 */
	display = ConnectToServer (NULL, &screen, &rootwindow);
	if (! height)
	    height = 480;
	if (! width)
	    width = 640;
        if (height > DisplayHeight (display, screen))
            height = DisplayHeight (display, screen);
        if (width > DisplayWidth (display, screen))
            width = DisplayWidth (display, screen);
        height /= scale;
        width /= scale;
    } else if (modus == ROOT) {
	display = ConnectToServer (NULL, &screen, &rootwindow);
	height = DisplayHeight (display, screen);
	if (! width)
	    width = 256;
	if (width > DisplayWidth (display, screen))
	    width = DisplayWidth (display, screen);
        height /= scale;
        width /= scale;
#endif  /* X11 */
    } else {
	if (! height)
	    height = 256;
	if (! width)
	    width = 128;
        height /= scale;
        width /= scale;
    }

    rand_val = seed;
    line0 = (char *) malloc (width * sizeof (char));
    line1 = (char *) malloc (width * sizeof (char));
    for (i = 0; i < width; i++)
	line1 [i] = p_rand () % 4;

    if (modus == SCR || modus == ROOT) {
#ifdef __MSDOS__
#else  /* X11 */
	status = SetUpVisual (display, screen, &visual, &depth);
	if (status != True)
	    errit ("Setup PseudoColor/TrueColor visual");

        if (modus == SCR) {
            sprintf (
                buffer,
                "%s -s %li -l %g%s%s",
                programname,
                (long int) seed,
                (double) lambda,
                iso ? " -i" : "",
                async ? " -a" : ""
            );
            window = OpenWindow (
                display,
	        rootwindow,
                100, 100,
                width * scale, height * scale,
                BlackPixel (display, screen),
                BlackPixel (display, screen),
                /* ExposureMask | */ KeyPressMask,
                visual);
#ifdef X11R4UP
            wm_delete_window = XInternAtom (display, "WM_DELETE_WINDOW", False);
            XSetWMProtocols (display, window, &wm_delete_window, 1);
#endif
            SetStandardHints (
                display,
                window,
                buffer,
                programname,
                width * scale, height * scale,
                DisplayWidth (display, screen), height * scale);
        }

	status = SetUpColormap (
            display, screen, (modus == SCR) ? window : rootwindow, visual, &colormap);
	if (status != True)
	    errit ("Creating Colormap");

	c [0] = AllocNamedColor (display, colormap, color [0], BlackPixel (display, screen));
	c [1] = AllocNamedColor (display, colormap, color [1], WhitePixel (display, screen));
	c [2] = AllocNamedColor (display, colormap, color [2], WhitePixel (display, screen));
	c [3] = AllocNamedColor (display, colormap, color [3], WhitePixel (display, screen));

	pixmap = XCreatePixmap (
            display,
            (modus == SCR) ? window : rootwindow,
            width * scale,
            (modus == SCR) ? height * scale : DisplayHeight (display, screen),
            depth
        );
	if (pixmap == (Pixmap) None)
	    errit ("Creating pixmap");

	pix_gc = XCreateGC (
	    display,
	    pixmap,
	    0,
	    &xgcvalues);

	XSetForeground(display, pix_gc, c [0]);
	XFillRectangle (
            display,
            pixmap,
            pix_gc,
            0, 0,
            width * scale,
            (modus == SCR) ? height * scale : DisplayHeight (display, screen)
        );

	XSetWindowBackgroundPixmap (display, (modus == SCR) ? window : rootwindow, pixmap);
	XClearWindow (display, (modus == SCR) ? window : rootwindow);

        if (modus == SCR) {
            XMapRaised (display, window);
            XFlush (display);

            cursor_watch = XCreateFontCursor (display, XC_watch);
            if (cursor_watch != (Cursor) None)
                XDefineCursor (display, window, cursor_watch);
	}

        for (i = 1; i < 4; i++) {
            rectangles [i] = (XRectangle *) malloc (width * sizeof (XRectangle));
            if (! rectangles [i])
                errit ("Out of memory!");
            for (t = 0; t < width; t++)
                rectangles [i][t].width = rectangles [i][t].height = scale - border;
	}
        max_req_size = XMaxRequestSize (display);

#endif  /* X11 */
    } else
	printf (
	    "/* XPM */\n"
	    "/* lambda: %f */\n"
	    "/* seed:   %li */\n"
	    "static char* cellular_automata = {\n"
	    "\"%i %i 4 1\",\n"
	    "\"a c black\",\n"
	    "\"b c blue\",\n"
	    "\"c c green\",\n"
	    "\"d c red\",\n",
	    lambda,
	    seed,
	    width * scale,
	    height * scale
	);

    ln = 0;
    y = -1;
    page = 1;
    for (;;) {

	if ((modus == SCR) || (modus == ROOT) || (ln >= skip))          /* hier '>=' ... */
	    if (++y == height) {
		if (modus == XPM)
		    break;
                dot = 0;
                for (i = 0; i < width; i++)
		    dot |= (line0 [i] ^ line1 [i]);
		if ((! dot) || (pages && ++page > pages)) {
#ifdef __MSDOS__
		    while (! escape_pressed ())
			;
#endif
		    break;
		}
		y = 0;
#ifndef __MSDOS__
		XFlush (display);
#endif
                if (seconds)
                    sleep (seconds);
	    }

	ln++;
	if (modus == SCR || modus == ROOT) {
#ifdef __MSDOS__
	    for (i = 0; i < width; i++)
		if (scale == 1)
		    putpixel (i, y, c [line1 [i]]);
		else {
		    setfillstyle (SOLID_FILL, c [line1 [i]]);
		    bar (
			i * scale,
			y * scale,
			(i + 1) * scale - 1 - border,
			(y + 1) * scale - 1 - border
		    );
		}
	    if (escape_pressed ())
		break;
#else  /* X11 */
	    XSetForeground (display, pix_gc, c [0]);
	    XFillRectangle (display, pixmap, pix_gc, 0, y * scale, width * scale, scale);
	    p [1] = p [2] = p [3] = 0;
	    for (i = 0; i < width; i++)
		if ((n = line1 [i]) != 0) {
                    rectangles [n][p [n]].x = i * scale;
                    rectangles [n][p [n]].y = y * scale;
		    if (++(p [n]) == max_req_size) {
			XSetForeground (display, pix_gc, c [n]);
			XFillRectangles (
                            display, pixmap, pix_gc, rectangles [n], p [n]);
			p [n] = 0;
		    }
		}
            for (i = 1; i < 4; i++)
                if (p [i]) {
                    XSetForeground (display, pix_gc, c [i]);
                    XFillRectangles (display, pixmap, pix_gc, rectangles [i], p [i]);
                }
            XClearArea (display, (modus == SCR) ? window : rootwindow, 0, y * scale, 0, scale, False);
            if (modus == SCR) {
                XFlush (display);
                while (XPending (display)) {
                    XNextEvent (display, &event);
                    if (QuitPressed (& event)) {
                  	XFreePixmap (display, pixmap);
	                XCloseDisplay (display);
                        return 0;
		    }
		}
	      }
#endif  /* X11 */
        } else if (ln > skip) {                        /* ... en hier '>'  */
            for (n = 1; n <= scale; n++) {
	        putchar ('"');
	        for (i = 0; i < width; i++)
                    for (m = 1; m <= scale; m++)
                        putchar (
                            (n > scale - border || m > scale - border) ? 'a' : line1 [i] + 'a'
                        );
	        printf ("\",\n");
	    }
	}

        if (async) {
            if (y == height - 2)
                memcpy (line0, line1, width * sizeof (line0 [0]));
            for (i = 0; i < width; i++) {
                r = (int)(p_rand () % width);
                line1 [r] = rule [    ((int)line1 [(r + width - 2) % width])
                              +   4 * ((int)line1 [(r + width - 1) % width])
                              +  16 * ((int)line1 [r])
                              +  64 * ((int)line1 [(r + 1) % width])
                              + 256 * ((int)line1 [(r + 2) % width])];
            }
        } else {
            memcpy (line0, line1, width * sizeof (line0 [0]));

            for (i = 0; i < width; i++)
                line1 [i] = rule [    ((int)line0 [(i + width - 2) % width])
                              +   4 * ((int)line0 [(i + width - 1) % width])
                              +  16 * ((int)line0 [i])
                              +  64 * ((int)line0 [(i + 1) % width])
                              + 256 * ((int)line0 [(i + 2) % width])];
        }
    }

    if (modus == SCR || modus == ROOT) {
#ifdef __MSDOS__
	close_graph ();
#else  /* X11 */
        if (modus == SCR) {
            if (cursor_watch != (Cursor) None)
                XUndefineCursor (display, window);
            for (;;) {
                XNextEvent (display, &event);
                if (QuitPressed (& event))
                        break;
            }
        }
	XFreePixmap (display, pixmap);
        if (modus == ROOT)
	    XSetCloseDownMode (display, RetainPermanent);
	XCloseDisplay (display);
#endif
    } else {
	printf ("} ;\n");
    }

#ifdef __MSDOS__
    message ();
#endif

    return 0;
}

#ifdef __MSDOS__

void start_graph ()
{
    int
	gdriver = DETECT,
	gmode,
	errorcode;

    registerbgidriver (EGAVGA_driver);
    initgraph (&gdriver, &gmode, getenv ("BGI"));
    errorcode = graphresult ();
    if (errorcode != grOk)
	errit (
	    "%s\n\n"
	    "Environment variable BGI can be used to point to\n"
	    "directory where graphic driver files are to be found",
	    grapherrormsg (errorcode)
	);
    in_graph = 1;
}

void close_graph ()
{
    if (in_graph) {
	closegraph ();
	in_graph = 0;
    }
}

int escape_pressed ()
{
    while (_bios_keybrd (_KEYBRD_READY))
	if ((_bios_keybrd (_KEYBRD_READ) & 0xFF) == 27)
	    return 1;
    return 0;
}

#else  /* X11 */

/*
 * Quit Press OR WINDOW DELETE
 */
int QuitPressed (XEvent *event)
{
    XComposeStatus
        composestatus;
    KeySym
        keysym;
    char
        keybuffer [2];
    int
        i;
    if (event->type == KeyPress) {
        i = XLookupString (
            &(event->xkey),
            keybuffer,
            1,
            &keysym,
            &composestatus
         );
         return ((i > 0) && (keybuffer [0] == 'q'));
     }
#ifdef X11R4UP
        else if (event->type == ClientMessage &&
                 event->xclient.data.l [0] == wm_delete_window)
            return 1;
#endif

    return 0;
}

Display *ConnectToServer (
    char display_name [],
    int *screen,
    Window *rootwindow
)
{
    Display
	*display = XOpenDisplay (display_name);

    if (! display)
        errit (
            "Cannot connect to X server [%s]",
	    XDisplayName (display_name)
	);

    *screen = DefaultScreen (display);

    *rootwindow = RootWindow (display, *screen);

    return display;
}

Window OpenWindow (
    Display *display,
    Window parent,
    int x,
    int y,
    int width,
    int height,
    unsigned long bordercolor,
    unsigned long backcolor,
    unsigned long event_mask,
    Visual * visual)
{
    Window
        window;
    XSetWindowAttributes
        attributes;
    unsigned long
        attr_mask;

    attributes.event_mask = event_mask;
    attributes.border_pixel = bordercolor;
    attributes.background_pixel = backcolor;
    attr_mask = CWEventMask | CWBackPixel | CWBorderPixel;

    window = XCreateWindow (
        display,
        parent,
        x, y, width, height,
        BORDER_WIDTH,
        CopyFromParent,
        InputOutput,
        visual,
        attr_mask,
        &attributes);

    return window;
}

void SetStandardHints (
    Display *display,
    Window window,
    char app_name[],
    char wind_name[],
    int width, int height,
    int max_width, int max_height
)
{
    XSizeHints
        sizehints;
    XWMHints
        wm_hints;
    XClassHint
        class_hints;

    sizehints.height = height;
    sizehints.width = width;
    sizehints.min_height = height;
    sizehints.min_width = width;
    sizehints.max_height = max_height;
    sizehints.max_width = max_width;
    sizehints.flags = USSize | PMinSize | PMaxSize;
#ifdef X11R4UP   /* X11R4 or up */
    sizehints.base_width = width;
    sizehints.base_height = height;
    sizehints.flags |= PBaseSize;
    XSetWMNormalHints (display, window, &sizehints);
#else         /* older versions */
    XSetNormalHints (display, window, &sizehints);
#endif

    XStoreName (display, window, app_name);

    class_hints.res_class = APPL_CLASS;
    class_hints.res_name = app_name;
    XSetClassHint (display, window, &class_hints);

    wm_hints.flags = InputHint | StateHint;
    wm_hints.initial_state = NormalState;
    wm_hints.input = True;
    XSetWMHints (display, window, &wm_hints);
}

int SetUpVisual (Display *display, int screen, Visual **visual, int *depth)
{
    XVisualInfo
        *visual_array,
        visual_info_template;
    int
        number_visuals;

    if (DefaultVisual (display, screen)->class == PseudoColor ||
        DefaultVisual (display, screen)->class == TrueColor) {
        *visual = DefaultVisual (display, screen);
        *depth = DefaultDepth (display, screen);
        return True;
    }

    visual_info_template.class  = PseudoColor;
    visual_info_template.screen = screen;
    visual_array = XGetVisualInfo (
        display,
        VisualClassMask | VisualScreenMask,
        &visual_info_template,
        &number_visuals
    );
    if ((number_visuals > 0) && (visual_array != NULL)) {
        *visual = visual_array [0].visual;
        *depth  = visual_array [0].depth;
        XFree (visual_array);
        return True;
    }

    visual_info_template.class  = TrueColor;
    visual_info_template.screen = screen;
    visual_array = XGetVisualInfo (
        display,
        VisualClassMask | VisualScreenMask,
        &visual_info_template,
        &number_visuals
    );
    if ((number_visuals > 0) && (visual_array != NULL)) {
        *visual = visual_array [0].visual;
        *depth  = visual_array [0].depth;
        XFree (visual_array);
        return True;
    }

    *visual = CopyFromParent;
    return False;
}

int SetUpColormap (
    Display *display,
    int screen,
    Window window,
    Visual *visual,
    Colormap *colormap)
{
    if (visual == DefaultVisual (display, screen)) {
	*colormap = DefaultColormap (display, screen);
        return True;
    } 

    if ((*colormap = XCreateColormap (display, window, visual, AllocNone)) != None) {
        XSetWindowColormap (display, window, *colormap);
        return True;
    }
    
    *colormap = DefaultColormap (display, screen);
    return False;
}

unsigned long AllocNamedColor (
    Display *display,
    Colormap colormap,
    char colorname [],
    unsigned long default_color)
{
    XColor
        hardwarecolor,
        exactcolor;

    if (XAllocNamedColor (display, colormap, colorname, &hardwarecolor, &exactcolor))
        return hardwarecolor.pixel;

    return default_color;
}

#endif  /* X11 */

long p_rand ()
{
    rand_val = 16807L * (rand_val % 127773L) - 2836L * (rand_val / 127773L);
    while (rand_val <= 0L)
        rand_val += 0x7FFFFFFFL;
    return rand_val;
 }

void errit (char const *format, ...)
{
    va_list
	list;

    va_start (list, format);
    fprintf (stderr, "\a\nError %s: ", programname);
    vfprintf (stderr, format, list);
    fprintf (stderr, "\n\n");
    va_end (list);

    exit (1);
}

void get_programname (char const *argv0)
{
#ifdef __MSDOS__
    char
        name [MAXFILE];
    fnsplit (argv0, NULL, NULL, name, NULL);
    programname = strdup (name);
#else   /* unix */
    char
        *p;
    p = strrchr (argv0, '/');
    if (p)
        programname = strdup (p + 1);
    else
	programname = strdup (argv0);
#endif    
}

char *get_arg (int *argc, char *argv [], int *index)
{
    int
        i;
    i = 1;
    while (argv [*index][++i]) {
        if (! isspace ((unsigned char) argv [*index][i]))
            return argv [*index] + i;
    }
    if (*index == *argc - 1)
        errit ("Missing argument for \"%s\"", argv [*index]);
    return argv [++*index];
}

void message ()
{
    if (verbose)
        fprintf (
            stderr,
            "Lambda: %f\n"
            "Seed:   %li\n",
            lambda,
	    seed
        );
}

void syntax ()
{
    fprintf (
        stderr,
        "\n"
        "Cellular Automata\n\n"
        "(C) P. Kleiweg 1996, 1998, 2004\n\n"
	"Usage: %s [options]\n\n"
        "Options are:\n\n"
	"  -2..-9     : scaling\n"
	"  -a         : asynchronous automata\n"
#ifndef __MSDOS__
        "  -c0 string : color instead of black\n"
        "  -c1 string : color instead of blue\n"
        "  -c2 string : color instead of green\n"
        "  -c3 string : color instead of red\n"
#endif
	"  -d         : dump rule\n"
	"  -f         : fill scaling\n"
	"  -h         : height\n"
	"  -i         : restrict to spatial isotropy\n"
	"  -l float   : lambda (between 0 and 1)\n"
	"  -n         : number of lines to skip before top of pixmap\n"
	"  -p int     : number of pages (use 0 for unlimited)\n"
	"  -q         : quiet\n"
#ifndef __MSDOS__  /* X11 */
	"  -r         : set root window\n"
#endif  /* X11 */
	"  -s int     : random number seed\n"
	"  -t int     : time in seconds to pause between pages\n"
	"  -w int     : width\n"
	"  -x         : create xpm pixmap\n\n",
	programname
    );
    exit (1);
}

