asp.tar" from alt.ascii-art.animation (6 Jun 1994), preserved in the Historic Archives."> Correction for asp.tar.gz-->asp.tar - alt.ascii-art.animation - ASCII Art Archive

Settings

The page will reload to apply your changes.
Theme

ASCII Art Font

ASCII Art Menu

Original Usenet thread from alt.ascii-art.animation, started 6 Jun 1994.
 _   _                     _        _             _     _           
| | | |___  ___ _ __   ___| |_     / \   _ __ ___| |__ (_)_   _____ 
| | | / __|/ _ \ '_ \ / _ \ __|   / _ \ | '__/ __| '_ \| \ \ / / _ \
| |_| \__ \  __/ | | |  __/ |_   / ___ \| | | (__| | | | |\ V /  __/
 \___/|___/\___|_| |_|\___|\__| /_/   \_\_|  \___|_| |_|_| \_/ \___|
Correction for asp.tar.gz-->asp.tar

Correction for asp.tar.gz-->asp.tar

alt.ascii-art.animation · 1 message · 6 Jun 1994
I was told I have to uuecode this on news...I guess this is what they mean...
Eric

________________________Cut Here___________________________________
COVER_LETTER



From the README:

> Asp is a simplistic description language for carriage-return based ascii
> animations, as commonly found in ".plan" files when you finger someone.
> It is simple to use, so large, smooth, neat animations can be built
> quickly and easily, and with a lot of room for imagination.

Asp is a simple, rule-based language for generating those wonderful
scrolling ".plan" files that many people have written diddy programs to
generate.  Asp was desigend to do go "one bit further" that those
programs usually do, and to be flexible with it.  It seems to achieve
this end.

I hope you have fun with it.  The most obvious problem you might have is
the standard index()/strchr() incompatibility.  Check "asp.h"

alec
--
INET: ae...@aber.ac.uk      JANET: ae...@uk.ac.aber      BITNET: aem%aber@ukacrl
UUCP: ...!mcsun!ukc!aber!aem         ARPA: aem...@nsfnet-relay.ac.uk
SNAIL: Alec Muffett, Computer Unit, Llandinam UCW, Aberystwyth, UK, SY23 3DB
n


-----------------------------------------------------------
 COVER_LETTER               1	letter to go with distribution
 MANIFEST                   1	This file
 Makefile                   1	Makefile (Oh, come on!!!)
 README                     1	documentation on programming ASP
 anim.c                     1	animation primitives
 asp.c                      1	main()
 asp.h                      1	header file with major declarations
 copy.c                     1	string copying primitives
 demo1.asp                  1	demo 1 of asp in action 
 demo2.asp                  1	demo 2 of asp in action 
 demo3.asp                  1	demo 3 of asp in action 
 demo4.asp                  1	demo 4 of asp in action 
 demo5.asp                  1	demo 5 of asp in action 
 display.c                  1	display primitives 
 effects.c                  2	special effects
ARPA: aem...@nsfnet-relay.ac.uk
SNAIL: Alec Muffett, Computer Unit, Llandinam UCW, Aberystwyth, UK, SY23 3DB
n


CFLAGS=		-g
OBJECTS=	anim.o asp.o copy.o display.o effects.o

demo:	$(EXE)
	$(EXE) demo1.asp 2> /dev/null
	$(EXE) demo2.asp 2> /dev/null
	$(EXE) demo3.asp 2> /dev/null
	$(EXE) demo4.asp 2> /dev/null
	$(EXE) demo5.asp 2> /dev/null

$(EXE):	$(OBJECTS)
	cc $(CFLAGS) -o $@ $(OBJECTS)

clean:
	rm -f *.o asp 

 anim.c                     1	animation primitives
 asp.c                      1	main()
 asp.h                      1	header file with major declarations
 copy.c                     1	string copyiREADME


(c) Alec Muffett, September 1991

As detailed in the demonstration programs (just type 'make'), this is
"asp", Alec's Scrolling Program, a diddy little hack I put together to
finish a war over who could make the longest, best, and prettiest
".plan" files, using only the printable ascii character set.

Asp is a simplistic description language for carriage-return based ascii
animations, as commonly found in ".plan" files when you finger someone.
It is simple to use, so large, smooth, neat animations can be built
quickly and easily, and with a lot of room for imagination.

The language is crude, I haven't put together a decent lexical analyser,
there is no real parser as such, to whit, it is a realio trulio hack, as
stated before.

The language divides roughly into three sections: boring effects,
special effects, and directives.  A good idea of how they work can be
obtained from the demo files supplied with this distribution, but here's
a little primer anyway:-

*** Primer

Asp works by reading a "asp program" which is full of "rules" and
"data".  A "rule" line is made up of a series of "commands", all of
which begin with a "." character.  With me so far ?

So, for example, a "rule" line might look like:-

.clear .p .p .show .p .p

Since the commands all begin with a dot, the rule line begins with a dot
also.  Any line which begins with a dot in an asp program is assumed to
be a "rule" line.  If a rule line is too long for convenience's sake, it
may be broken with a backslash at the end of the line, in the same way
as in C and shell scripts, eg:

.speed 2 \
.object his -30 40 \
.object dreams, -50 44 \
.object computer -15 22 \
.object he -2 58 \
.object ? -250 61 \
.object can 89 31 \
.object have 100 35 \
.object can 111 52 \
.object A 150 20 \
.object 't 200 55 \
.anim .resetanim .p .p .p .nl

- is a single rule line.  When a valid rule line is encountered, it is
stored in memory and becomes the "current rule".

Next, Data lines.  Any non-blank line which is not a rule line, is a
"data line".  When a data line is encountered, asp applies all the
commands specified in the current rule to the data line, and then moves
onto the next data line. eg:

.show .nl
Hello World!

Will print the line "Hello World!" (.show), and throw a linefeed (.nl).

Blank lines in an asp program are ignored, and so, on occasions, dummy
data lines must be supplied to asp in order to get a rule to do
anything.  The traditional dummy line consists of two hyphens on a line
of their own, eg:

.p .p .p
--

Invokes the Pause function (.p) three times.  If there were no dummy
line before the next rule was specified, the command would be ignored.
Note that the Pause function does not print anything on the standard
output, so the appearance of the line is not changed.

Similarly, the command:

.p .p .p
--
--
--

Invokes Pause nine times, three times for each dummy line.

Next, asp internals.  Asp pinches an idea from the curses library, in
that it stores a copy of what the current output line looks like, and
then prints only the differences between the current line and what you
want it to look like.  This "optimised refresh" improves on how an asp
program looks when you view it, and also on the size of the output file
asp generates compared to other scrolling programs.

You should also note that asp does not begin processing of a program
until it encounters the first "rule line".  Up to that point it behaves
in the same way as the 'cat' program, copying the program to stdout.
This allows you to embed a lot of plain text in your program before you
start scrolling things about.

*** Undercoat

The above gives a fairly simple introduction to how asp works. Now for a
description of commands in detail.

The asp commands break down into three rough types: Boring effects,
Special effects, and Directives.  Some of these take arguments, which
are either VALUES, BOOLEANS, or STRINGS.

Values are basically any integer quantity, positive or negative.

Booleans are the same as values, where 0=FALSE and Non-0=TRUE.

Strings are continuous sets of characters which do not contain
whitespace (I haven't bothered in putting an escaping mechanism for
spaces yet.)

There may be a problem if you specify a string as an argument to a
command, and the string happens to begin with a dot - asp will, at some
point, try to treat it as a command.  Don't worry about this, it will
probably work out okay, and I'll fix it in due course.

Finally, please note that asp uses only columns 0->78 of the screen,
because some terminals will wrap immediately you write a character into
column 79, and this spoils the fun...

IMPORTANT: Asp does not expand TABs in asp programs.  Run your program
through "expand" before feeding it into "asp".

*** Topcoat

Here is a list of asp directives and effects, their function and arguments:

-------------------------------
DIRECTIVES AND BORING EFFECTS:-
-------------------------------
	.clear

Wipes the current line clear and refreshes it, so as to put a blank line
on screen.
-------------------------------
	.wipe

Wipes the current line clear without refreshing it, so that the next
command does not have to worry about the mess left by previous lines.

This command is probably best tagged onto the beginning of every rule
where you do not want to have to specifically overstrike anything that
was left by the previous rule & data.
-------------------------------
	.nl

Throws a newline.  Please note that the default action of asp once it
has acquired a rule it to print EVERYTHING without newlines, so you must
be explicit about where you want them.
-------------------------------
	.show

Does a .wipe and then prints the current line on screen.  This is the
most basic of the output primitives, and you will probably use this a
lot.
-------------------------------
	.p

Generates a pause in the display by firing approximately 2Kb of carriage
returns at your screen (roughly 1 second at 9600 baud).  See also
".speed" below. 
-------------------------------
	.noop

Does bugger all.
-------------------------------
	.flush

Is a nice one.  It deletes the current rule from asp's memory, so it's
behaviour is once again like 'cat' (check the 'Undercoat' section,
above).  This means you can embed small bits of asp code in any text
file, without having to modify the rest of the file to get it through
the asp processor.  Do NOT forget to invoke ".flush" with a dummy data
line, though:

This is a bit of cat'ted text.
.speed 3 .spatter .p .p .p .nl
This is a somewhat longer bit of asp'ed text
.flush
--
This is another bit of cat'ted text.

- ok ?
-------------------------------
	.smooth BOOLEAN

Switches on 80-character smoothing mode.  This is useful where you are
going to be scrolling small bits of text back and forth across the
screen.  If you do not have smoothing on, asp will generate code which
will make the object move faster towards the left hand side of the
screen.  This is due to the optimised refresh code mentioned above.

If smoothing is swithched on (".smooth 1"), asp pads out (with carriage
returns) each line that it prints in order to remedy this situation.
This leads to smoother, neater animations.
-------------------------------
	.speed VALUE

This is a speed adjustment function which pads out each line that asp
sends, in order to cope with fast terminals, and for special effects.

The default is ".speed 0" and as the speed value is increased, each line
is padded with 'x' carriage returns (x = 8 * n, where 'n' is the
argument to ".speed").  The higher the value, the slower it goes.

Be judicious with your use of .speed - remember, some people still work
at under 1200 baud.
-------------------------------
	.background
	.foreground

These are both commands which break the rules outlined above.  They both
read the next line DIRECTLY BENEATH the command into special buffers for
use during output.  It does not matter whether this line is blank or
not, and indeed, a blank line will be necessary to reset the buffer to a
blank when desired.

".background" and ".foreground" load their following line into a
background or foreground buffer respectively.  The buffer will then be
used either be used as a backdrop or overlay mask for whatever is
printed from then on.  This means that you don't have to worry about
your landscapes getting corrupted, having to redraw them, and so on.

As an example, see the two occurances of ".background" in "demo2.asp"
-------------------------------
SPECIAL EFFECTS:-
-------------------------------
	.fade

Prints the message on the screen and fades it one character at a time.
To get slower fades, whack the speed up either side of it, eg:

.show .p .p .speed 10 .fade .speed 0 .p
    This piece of text should fade quite gradually into nothingness...

-------------------------------
	.flash

Flashes all the text in a data line several times before moving onto the
next. Does not overstrike text with whitespace, and can be used thusly:

.show
"Beep Beep", went the little car's horn.
.speed 20 .flash .speed 0
 Beep Beep

-------------------------------
	.layb
	.layetm
	.laymte
	.layf

Prints the line by laying down one character at a time, backwards,
ends-to-middle, middle-to-ends, or forwards, respectively.  See the
demos for examples.
-------------------------------
	.tshow

Is like ".show" but does not call ".wipe", and it uses transparent
whitespace, ie: whitespace in the data line does not overstrike any
printable character that is already on screen.  eg:

.tshow .p
                                 LIFE
                                      ON
                                         UNIX

-------------------------------
	.letter1
	.letter2
	.letter3

Are effects macros based on the "let's-cycle-through-the-ascii-character-set"
principle. See the demos for examples.
-------------------------------
	.scrollb
	.scrollf

Scrolls the data line backwards or forwards (respectively) onto the
screen, overstriking what is already there, eg:

.scrollb .p .p
This message will scroll from right to left across the width of the screen
This message will also scroll from right to left.

-------------------------------
	.scrollob
	.scrollof

Like .scroll[bf], but these commands scroll what it already there off of
the screen, rather than overstriking it.  See the demos for examples.

.scrollob .p .p
This message will scroll from right to left across the width of the screen
This message will also scroll from right to left, without overstriking.

-------------------------------
	.spatter
	.wspatter

".spatter" is the opposite of ".fade".  ".wspatter" is similar, but
spatters whole words onto the screen, rather than characters.
-------------------------------
	.object STRING1 VALUE1 VALUE2
	.anim
	.resetanim

These are the three Asp animation primitives.

Basically, the idea of an animation is to build up a series of "objects"
using the ".object" directive.  This specifies that you want to move
"STRING1" from position VALUE1 to position VALUE2, where the value is
between +/-37267 (or possibly larger), and position 0 is the left hand
column of the screen, position 78 the right hand corner of the screen.

After specifying the series of objects to be animated, the animation is
run by invoking the ".anim" command.  Once you are finished with the
animation, you delete the objects from the screen by the ".resetanim"
command.  Simple, eh ? Here's the lorry animation from demo1.asp:

.object oo-oP -15 80 .anim .resetanim .p
--

Clever people will see that if you want to produce delays and odd timing
effects, you merely have to start an object a long way away from it's
destination.  eg: several lorries-

.object oo-oP -15 80 \
.object oo-oP -21 80 \
.object oo-oP -27 80 \
.object oo-oP -33 80 \
.object oo-oP -39 80 \
.object ooo-----ooP -45 80 \
.anim .resetanim .p
--

Because their nature is that of a sort of "compound command", several
animations can be built into a single rule and then fired off upon
multiple data lines.  Add a few extra dummy lines to the animation above
to get a whole convoy.  (see also the "flying arrows" in demos 3 & 5).

For the technically minded, asp animations run in an entirely separate
buffer from the rest of asp.  The buffer lies in the second position
thus:-

				USER VIEW
				    |
				    V
			    FOREGROUND BUFFER
			    ANIMATIONS BUFFER
			   RULE BUFFER (STDLINE)
			    BACKGROUND BUFFER

Hence, what you do in an animation cannot affect the rule buffer (ie:
where your data lines end up after being processed by a rule), nor the
foregrounds and backgrounds.

*** Usage

Now for the easy bit: for your file "aspprog.asp";

		asp aspprog.asp > $HOME/.plan

or, if you must use tabs

		expand < aspprog.asp | asp > $HOME/.plan

Bugs, reports, suggestions, patches to the address below...

						alec 8-)
--
INET: ae...@aber.ac.uk      JANET: ae...@uk.ac.aber      BITNET: aem%aber@ukacrl
UUCP: ...!mcsun!ukc!aber!aem         ARPA: aem...@nsfnet-relay.ac.uk
SNAIL: Alec Muffett, Computer Unit, Llandinam UCW, Aberystwyth, UK, SY23 3DB
---------
DIRECTIVES AND BORING EFFECTS:-
-------------------------------
	.clear

Wipes the current line clear and refreshes it, so as to put a blank line
on screen.
-------------------------anim.c


 * This code is copyright ADE Muffett, September 1991, and is distributed as
 * part of the ASP .plan description language compiler.  This code is freely
 * redistributable as long as this copyright notice remains intact. No
 * responsibility is assumed by the author for any situation which arises
 * from the use of this code, including insanity, late nights, or disk
 * storage problems.
 */

#include "asp.h"

void
AddObject (string)
    char *string;
{
    register int i;
    int start;
    int finish;
    char buff[SCREENWIDTH];
    char *obj;

    sscanf (string, "%*s %s %d %d", buff, &start, &finish);

    obj = CopyString (buff);

    for (i = 0; aobjects[i].object && (i < MAX_ANIM_OBJS - 1); i++);

    aobjects[i].object = obj;
    aobjects[i].location = start;
    aobjects[i].destination = finish;
    aobjects[++i].object = NULL;
}

void
ResetAnim ()
{
    aobjects[0].object = NULL;
    NullSet (anim_buffer, sizeof (anim_buffer));
}

void
Animate ()
{
    register int i;
    struct anim_object *ap;
    int changed;

    for (changed = 1; changed; /* nothing */ )
    {
	changed = 0;
	NullSet (anim_buffer, sizeof (anim_buffer));
	SpaceFlood (anim_buffer, SCREENWIDTH);

	for (i = 0; aobjects[i].object && (i < MAX_ANIM_OBJS - 1); i++)
	{
	    ap = &aobjects[i];

	    LimCopy (anim_buffer, ap -> object, ap -> location);
	    if (ap -> location > ap -> destination)
	    {
		ap -> location--;
		changed++;
	    } else if (ap -> location < ap -> destination)
	    {
		ap -> location++;
		changed++;
	    }
	}
	/* anim_buffer is dealt with in Update() for masking reasons */
	UpdateCR ();
    }
}
ommand does not have to worry about the mess left by previous lines.

This command is probably best tagged onto the beginning of every rule
where you do not want to have to specifically overstrike anything that
was left by the previous rule & data.
-------------------------------
	.nl

Throws a newline.  Please note that the default action of asp once it
has acquired a rule it to print EVERYTHING without newlines, so you muasp.c


 * This code is copyright ADE Muffett, September 1991, and is distributed as
 * part of the ASP .plan description language compiler.  This code is freely
 * redistributable as long as this copyright notice remains intact. No
 * responsibility is assumed by the author for any situation which arises
 * from the use of this code, including insanity, late nights, or disk
 * storage problems.
 */

/* Unix is a Bellmark of Lab Tradeoratories */

#include "asp.h"
#undef TESTING

/* GLOBAL DATA */
int speed;
int smooth;
char stdline[SCREENWIDTH + 1];
char anim_buffer[SCREENWIDTH + 1];
char foreground[SCREENWIDTH + 1];
char background[SCREENWIDTH + 1];
struct anim_object aobjects[MAX_ANIM_OBJS];
/* END OF GLOBAL DATA */

struct command_structure
{
    char *codeword;
    void (*fn) ();
    char has_args;
};

struct command_call
{
    int c_index;
    char *invocation;
};

static FILE *fp;
static char version[] = "asp3.2(c)aem@aber";
static struct command_call command_calls[COMMAND_COUNT];
static struct command_structure command_name[COMMAND_COUNT];

void
Smooth (command)
    char *command;
{
    sscanf (command, "%*s %d", &smooth);
}

void
Speed (command)
    char *command;
{
    sscanf (command, "%*s %d", &speed);
}

void
Flush ()
{
    command_calls[0].c_index = 0;
}

char *
BuildArgs (commstring, name_index)
    char *commstring;
    int name_index;
{
    char cbuf[255];

    if (!strcmp (command_name[name_index].codeword, ".object") ||
	!strcmp (command_name[name_index].codeword, ".speed") ||
	!strcmp (command_name[name_index].codeword, ".smooth"))
    {
	return (CopyString (commstring));
    }
    if (!strcmp (command_name[name_index].codeword, ".foreground"))
    {
	fgets (cbuf, 255, fp);
	NullSet (foreground, sizeof (foreground));
	strncpy (foreground, cbuf, SCREENWIDTH);
	return ((char *) NULL);
    }
    if (!strcmp (command_name[name_index].codeword, ".background"))
    {
	fgets (cbuf, 255, fp);
	NullSet (background, sizeof (background));
	strncpy (background, cbuf, SCREENWIDTH);
	return ((char *) NULL);
    }
    fprintf (stderr, "%s: NYI\n", commstring);
    return ((char *) 0);
}

void
NewFunction (cw, fn, args)
    char *cw;
    void (*fn) ();
    char args;
{
    static int command_count = 1;	/* load commands from 1st element */

    command_name[command_count].codeword = cw;
    command_name[command_count].fn = fn;
    command_name[command_count].has_args = args;
    command_count++;
    command_name[command_count].codeword = NULL;
}

void
ParseCommands (cstring)
    register char *cstring;
{
    int i;
    int comm_number;
    char *ptr;
    int get_next_line;
    char otherbuffer[255];
    static char dot = '.';

    comm_number = 0;
    command_calls[comm_number].c_index = 0;

  start_parsing:
    i = strlen (cstring) - 1;
    if (cstring[i] == '\\')
    {
	get_next_line = 1;
	cstring[i] = '\0';
    } else
    {
	get_next_line = 0;
    }

    for (ptr = (char *) strchr (cstring, dot);
	 ptr;
	 ptr = (char *) strchr (ptr, dot))
    {
	if (!*ptr)		/* no more commands */
	{
	    break;
	}
	for (i = 1; command_name[i].codeword; i++)
	{
	    if (!strncmp (ptr, command_name[i].codeword,
			  strlen (command_name[i].codeword)))
	    {
		command_calls[comm_number].c_index = i;

		if (command_name[i].has_args != 'Y')
		{
		    command_calls[comm_number].invocation = (char *) 0;
		    comm_number++;
		    break;
		} else
		{
		    command_calls[comm_number].invocation = BuildArgs (ptr, i);
		    comm_number++;
		    break;
		}
	    }
	}

	if (!command_name[i].codeword)
	{
	    fprintf (stderr, "Error: unknown command '%s'\n", ptr);
	}
	ptr++;			/* make this neater */
    }
    if (get_next_line)
    {
	fgets (otherbuffer, 255, fp);
	Trim (otherbuffer);
	cstring = otherbuffer;
	goto start_parsing;
    }
    command_calls[comm_number++].c_index = 0;
}

void
ExecuteCommandsOn (dstring)
    register char *dstring;
{
    register int i;
    register int j;

    for (i = 0; command_calls[i].c_index; i++)
    {
	j = command_calls[i].c_index;
#ifdef TESTING
	printf ("executing '%s' as '%s' on \n'%s'\n", command_name[j].codeword,
		command_calls[i].invocation, dstring);
#else
	(*command_name[j].fn) (command_calls[i].invocation, dstring);
#endif
    }
}

int
main (argc, argv)
    int argc;
    char *argv[];
{
    char command_buffer[255];
    char line_buffer[255];
    register char *ptr;
    register int i;
    static char dot = '.';

    srand (time (0));

    NewFunction (".wspatter", WordSpatter, 'N');
    NewFunction (".wipe", Wipe, 'N');
    NewFunction (".tshow", TShow, 'N');
    NewFunction (".speed", Speed, 'Y');
    NewFunction (".spatter", Spatter, 'N');
    NewFunction (".smooth", Smooth, 'Y');
    NewFunction (".show", Show, 'N');
    NewFunction (".scrollof", ScrollOffForward, 'N');
    NewFunction (".scrollob", ScrollOffBackward, 'N');
    NewFunction (".scrollf", ScrollForward, 'N');
    NewFunction (".scrollb", ScrollBackward, 'N');
    NewFunction (".reset", ResetAnim, 'N');
    NewFunction (".p", Pause, 'N');
    NewFunction (".object", AddObject, 'Y');
    NewFunction (".noop", Noop, 'N');
    NewFunction (".nl", LineFeed, 'N');
    NewFunction (".macro", NULL, 'N');
    NewFunction (".letter3", Letter3, 'N');
    NewFunction (".letter2", Letter2, 'N');
    NewFunction (".letter1", Letter1, 'N');
    NewFunction (".laymte", LayMiddleToEnds, 'N');
    NewFunction (".layf", LayForward, 'N');
    NewFunction (".layetm", LayEndsToMiddle, 'N');
    NewFunction (".layb", LayBackward, 'N');
    NewFunction (".foreground", Noop, 'Y');
    NewFunction (".flush", Flush, 'N');
    NewFunction (".flash", Flash, 'N');
    NewFunction (".fade", Fade, 'N');
    NewFunction (".clear", Clear, 'N');
    NewFunction (".background", Noop, 'Y');
    NewFunction (".anim", Animate, 'N');

    if (isatty (fileno (stdin)))
    {
	if (argc == 1)
	{
	    fprintf (stderr, "Usage:\t%s <filename>\n", argv[0]);
	    exit (1);
	}
	fp = fopen (argv[1], "r");
	if (!fp)
	{
	    perror (argv[1]);
	    exit (1);
	}
    } else
    {
	fp = stdin;
    }

    for (*line_buffer = '\0'; !feof (fp); *line_buffer = '\0')
    {
	fgets (line_buffer, 255, fp);

	if (!*line_buffer || *line_buffer == '\n')	/* allow blank lines */
	{
	    if (!command_calls[0].c_index)
	    {
		putchar ('\n');
	    }
	    continue;
	}
	Trim (line_buffer);	/* trim w/s */

	if (*line_buffer == dot)
	{
	    ParseCommands (line_buffer);
	    continue;
	}
	if (!command_calls[0].c_index)	/* don't faff around... */
	{
	    printf ("%s\n", line_buffer);
	    continue;
	}
	ExecuteCommandsOn (line_buffer);
    }
    fclose (fp);

    printf ("\n\r%s\r", version);
    i = strlen (version);
    while (i--)
    {
	putchar (' ');
    }
    putchar ('\r');

    return (0);
}

			  strlen (command_name[i].codeword)))
	    {
		command_calls[comm_number].c_index = i;

		if (command_name[i].has_args != 'Y')
		{
		    command_calls[comm_number].invocation = (char *) 0;
		    comm_number++;
		    break;
		} else
		{
		    command_calls[comm_number].invocation = BuildArgs (ptr, i);
		    comm_number++;
		    break;
		}
	    }
	}

	if (!command_name[i].codeword)
	{
	    fprintf (stderr, "Error: unknown commanasp.h


 * This code is copyright ADE Muffett, September 1991, and is distributed as
 * part of the ASP .plan description language compiler.  This code is freely
 * redistributable as long as this copyright notice remains intact. No
 * responsibility is assumed by the author for any situation which arises
 * from the use of this code, including insanity, late nights, or disk
 * storage problems.
 */

#include <stdio.h>

#define USE_INDEX		/* use index instead of strchr() */
#define SCREENWIDTH	79	/* colourbook screws you up */
#define COMMAND_COUNT	1024	/* max number of commands in a rule */
#define LOOP_COUNT 	2048	/* several things, eg: delay loop */
#define MAX_ANIM_OBJS	512	/* maximum number of objects in an anim */
#define DUMMY_RETURNS	8	/* speed 0 = 0; 1 = 64, 2 = 128... */
#define NUM_FLASH	16	/* number of flashes for 1 ".flash" */

/* strdup() if you have it... */
#define CopyString(xxx)	((char *)strcpy((char *)malloc(strlen(xxx)+1), xxx))

#ifdef USE_INDEX
#define strchr(a,b)	index(a,b)
#endif

struct anim_object
{
    char *object;
    int location;
    int destination;
};

extern char *BuildArgs ();
extern char *Memcpy ();
extern char anim_buffer[SCREENWIDTH + 1];
extern char background[SCREENWIDTH + 1];
extern char foreground[SCREENWIDTH + 1];
extern char stdline[SCREENWIDTH + 1];
extern int Update ();
extern int smooth;
extern int speed;
extern struct anim_object aobjects[MAX_ANIM_OBJS];
extern void AddObject ();
extern void Animate ();
extern void CReturn ();
extern void Clear ();
extern void ExecuteCommandsOn ();
extern void Fade ();
extern void Flash ();
extern void Flush ();
extern void LayBackward ();
extern void LayEndsToMiddle ();
extern void LayForward ();
extern void LayMiddleToEnds ();
extern void Letter1 ();
extern void Letter2 ();
extern void Letter3 ();
extern void LimCopy ();
extern void LineFeed ();
extern void NewFunction ();
extern void Noop ();
extern void NullSet ();
extern void Overlay ();
extern void ParseCommands ();
extern void Pause ();
extern void ResetAnim ();
extern void ScrollBackward ();
extern void ScrollForward ();
extern void ScrollOffBackward ();
extern void ScrollOffForward ();
extern void Show ();
extern void Smooth ();
extern void SpaceFlood ();
extern void Spatter ();
extern void Speed ();
extern void TShow ();
extern void TransparentOverlay ();
extern void Trim ();
extern void UpdateCR ();
extern void Wipe ();
extern void WordSpatter ();
else
    {
	fp = stdin;
    }

    for (*line_buffer = '\0'; !feof (fp); *line_buffer = '\0')
    {
	fgets (line_buffer, 255, fp);

	copy.c


 * This code is copyright ADE Muffett, September 1991, and is distributed as
 * part of the ASP .plan description language compiler.  This code is freely
 * redistributable as long as this copyright notice remains intact. No
 * responsibility is assumed by the author for any situation which arises
 * from the use of this code, including insanity, late nights, or disk
 * storage problems.
 */

#include "asp.h"

/* alas, for ANSI... */
char *
Memcpy (to2, from, num)
    char *to2;
    register char *from;
    register int num;
{
    register char *to = to2;

    while (num--)
    {
	*(to++) = *(from++);
    }
    return (to2);
}
/* Set a buffer to be full of nulls */
void
NullSet (string, num)
    register char *string;
    register int num;
{
    while (num--)
    {
	*(string++) = '\0';
    }
}
/* Set all nulls in a buffer to be whitespace */
void
SpaceFlood (string, num)
    register char *string;
    register int num;
{
    while (num--)
    {
	if (!*string)
	{
	    *string = ' ';
	}
	string++;
    }
}
/* copy source to destination without adding trailing null */
void
Overlay (destination, source)
    register char *destination;
    register char *source;
{
    while (*source)
    {
	*(destination++) = *(source++);
    }
}
/* copy source to destination without adding trailing null, except whitespace */
void
TransparentOverlay (destination, source)
    register char *destination;
    register char *source;
{
    while (*source)
    {
	if (*source != ' ')
	{
	    *destination = *source;
	}
	source++;
	destination++;
    }
}
/* copy into a bounded buffer */
void
LimCopy (to, from, start)
    register char *to;
    register char *from;
    register int start;
{
    while (*from)
    {
	if (start >= 0 && start < SCREENWIDTH)
	{
	    to[start] = *from;
	}
	from++;
	start++;
    }
}
/* END OF COPY PRIMITIVES */
ll nulls in a buffer to be whitespace */
void
SpaceFlood (string, num)
    register char *string;
    register int num;
{
    while (num--)
    {
	if (!*string)
	{
	    *string = ' ';
	}
	string++;
    }
}
/*demo1.asp


--
.show .p .p
                    Beware the M25 - heavy lorries !
.object oo-oP -15 80 .anim .resetanim .p
--
register char *source;
{
    while (*source)
    {
	*(destination++) = *(source++);
    }
}
/* copy source to destination without adding trailing null, except whitespace */
void
TransparentOverlay (destination, source)
    register char *destination;
    register char *source;
{
    while (*source)
    {
	if (*source != ' ')
	{
	    *destination = *source;
	}
	source++;
	destinademo2.asp



.nl .nl .nl .p .show .p
******************* scrolling enterprises proudly presents:- *******************

.scrollob
--------------------------------------------------------------------------------

.show .p .p .fade
----------------------(A Roadrunner>>>++>> Production)--------------------------

.spatter .p .p .fade
----------------------------- DAVID ATTENBOROUGH'S -----------------------------

.tshow .p
                                 LIFE
                                      ON
                                         UNIX

.clear .scrollf .p .fade .p
Hello and good evening. 8)

.show .p .p
Tonight we are going to examine the sex life of that rare and elusive creature,
The Andalusian Video Snail.

.object \@_ 85 40 .anim .resetanim .p
--
.object \@_ 40 40 .object ? 38 38 .anim .resetanim .p
--
.object _@_ 40 40 .anim .resetanim
--
.object _@/ 40 85 .anim .resetanim
--

.fade
The Andalusian Video Snail.

.show .p .p

Yes, this small and unobtrusive gastropod, which has never before been studied
in it's native habitat, has confused biologists for years; feeding as it does

.show .p .object _@/ -5 80 .anim .resetanim .p
upon the core dumps and executable images to be found on large UNIX mainframes.

.clear
--

.show .p .p
It derives nourishment from bad blocks and thrives on operating systems where
kernel crashes are frequent.  There is some evidence to suggest that they are
the original computer 'bugs', but this would then be a misnomer, because they
are, of course, actually snails.

.object \@_ 80 34 .anim .resetanim .p
--
.object _@_ 34 34 .anim .resetanim .p
--
.object _!_ 34 34 .anim .resetanim .p
--
.object _@_ 34 34 .anim .resetanim .p
--
.object _@/ 34 80 .anim .resetanim .p
--

.clear
--

.show .p .p
No-one has yet captured one of these creatures, for whenever a snail happens
onto the screen of a VDU, it immediately vanishes once the terminal has been
disconnected from the network.  After searching the length and breadth of the
network, we are now able to bring you pictures of the extraordinary courtship
and mating rituals of these snails...

.fade .p .clear
and mating rituals of these snails...

.show .p .p .clear .nl
                            (photographs courtesy of the digital corporation)
.show .nl
			___/--~                            ~~~\____
                    _/\/                                             \_
      /\          _/                                                  ||\_
     /   \/\_    /                                                       ~ \_

.background
\___/        \__/                                                            \_

.tshow .p .wipe
                                   (ANDALUSIA)

.object _@/ -20 37 .anim .p
--

.object \@_ 100 62 .anim
--

.object ? 60 60 .anim .p .resetanim
--

.object _@/ 37 37 \
.object \@_ 62 62 .anim .p
--

.object ! 60 60 .anim .p .resetanim
--

.object _@/ 37 37 \
.object \@_ 60 40 \
.anim .p .resetanim
--

.show .p
               (let us draw a delicate veil over these proceedings)

.show .p .p
                              {}{}{}CENSORED{}{}{}

.object _@/ 40 60 \
.object \@_ 40 -5 \
.object {}{}{}CENSORED{}{}{} 30 30 \
.anim .p .resetanim
--

.object {}{}{}CENSORED{}{}{} 30 30 \
.object _@_ 60 60 \
.anim .p
--

.object <ZZZzzz...> 63 63 \
.anim .p .resetanim .clear
--

.laymte .p .wipe
                                -  THE END -

.background

.wipe .nl .nl
--

.layetm .p .clear
             This educational program has been brought to you by:-

.show .p .wipe
                           The numbers 4 and 17
                               The letter 'Q'
                                and also...
.spatter .p .nl .wipe .p
                             Alec D.E. Muffett
                             Roadrunner>>>++>>
                              (using asp 3.2)

.scrollf .p .wipe
    [Next week we investigate the habits of the Lothian Software Wombat.]

.nl .nl
--

is padded with 'x' carriage returns (x = 8 * n, where 'n' is the
argument to ".speed").  The higher the value, the slower it goes.

Be judicious with your use of .spdemo3.asp


--

.wspatter .p .p .p .fade
  (C) ADE Muffett, UCW Aberystwyth, 1991. "ae...@aber.ac.uk" "...!ukc!aber!aem"

.spatter .p .p .fade .p
                        A Roadrunner>>>++>> production

.show .p .p .clear
                                  Hello there.
               I bet you're wondering what I've been up to of late.
                      On the other hand maybe you haven't.
          Perhaps you don't know about scrolling ".plan" files at all ?

.p .p
--

.show .p .p .wipe
 You see (for those newcomers amongst you), a long time ago, two undergraduates
                   here in Aberystwyth decided to have a 'war'.

.p .p
--

.show .p .p .clear
              They were (are) Alun Jones "alj8" and Kev Brooks "kkb9".

.p .p
--

.show .p .p .clear
          The war was over who could produce the 'prettiest' ".plan" file.

.p .p
--

.show .p .p .wipe
     They fought tooth and nail, with many people watching on the sidelines.
 Letters scrolled on and off the screen, flashed at you, it was quite amusing.

.p .p
--

.scrollob .p .p
    But then one day, I saw one effort (Kev's) that was really appalling:
   A huge data file that flashed, flickered and grunged its way across the
     screen, and I thought to myself :- "I can do much better than that!"

.p .p
--

.show .p .p .clear
I think that in retrospect I was right.  8)
I sat down, and I wrote "ASP" :-

.show .nl .p .p .wipe
Alec's Scrolling Program: a description language for plan files
                - written in fairly portable C
                - with a nice simple syntax
                - and above all, pleasant and easy to use.

.nl .p .p
--

.scrollb .p .p .clear
So - What can you do with ASP ? (I hear you scream)

.show .p .p
(apart from flashing messages like this on and off of the screen)

.speed 20 .flash
            flashing

.speed 0 .clear .p .p
--

.scrollf .p .p
You can scroll a piece of text onto the screen line, either forwards...

.scrollb .p .p
 ...or backwards onto the screen (just like this !)

.scrollof .p .p
Or what you have on the screen already can be scrolled off to the right ----->

.scrollob .p .p .wipe
<----------------- and ditto off to the left, as you might expect.

.spatter .p .p .wipe
               You can spatter bits of text onto the screen

.show .p .p .fade .p
               and then just let them fade into nothingness....

.layf .p .p .wipe
       Messages can be laid down letter by letter, from left to right;

.layb .p .p .wipe
             ...and of course, ditto for messages right to left.

.laymte .p .p .wipe
 Then there is laying messages down from the middle to the ends of the screen

.layetm .p .p .wipe
                - and vice versa for messages, ends to middle.

.laymte
         really build up some                                         these...

.layetm
 You can really build up some quite complex

.laymte .p .p .fade .wipe
 You can really build up some quite complex special effects with only these...

.letter1
but thats nothing compared to what you can do with the special text functions.
BUT THATS NOTHING COMPARED TO WHAT YOU CAN DO WITH THE SPECIAL TEXT FUNCTIONS.
But thats nothing compared to what you can do with the special text functions.

.wipe .p .p
--

.letter2
       ESPECIALLY when YOU employ THE RANDOM-character-SEARCH macros.

.letter1
       especially WHEN you EMPLOY the random-CHARACTER-search MACROS.
       esPECIALLY when yoU emPLOY the random-chARACTER-sEARCH macros.
       ESPEcially wHEN YOu EMPloy THE RANDOM-character-SEarch macROS.
       especiALLY whEN you EMPLoy the ranDOM-CHARacter-seaRCH macROS.
       Especially when you employ the random-character-search macros.

.clear .p .p
--

.show .p .p .clear
        But the thing that really "made it" in my mind, was animation.
                      Foregrounds and backgrounds.
                           The whole kaboodle.

.p .p .show .p .p
And thus was born the Andalusian Video Snail:

.object \@_ 100 50 .anim .resetanim .p .p
--

.object _@_ 50 50 .anim .resetanim .p
--

.object _@/ 50 100 .anim .resetanim .p .p
--

.tshow .p .p .clear
                                              And everyone copied it... Foo !

.show .p .p .wipe
                                        8)
                  Oh well. Back to the hack. See you again soon.
   ps: a copy of the asp source code for this plan can be found in the file

.show \
.object ----> 0 74 \
.object <---- 74 0 \
.anim .resetanim \
.object ----> 0 74 \
.object <---- 74 0 \
.anim .resetanim \
.show
                 "demo3.asp" in the standard asp distribution.

.nl .show .p
                                     Bye Now...
                                Alec D.E. Muffett
                                     (c) 1991
lec D.E. Muffett
                             Roadrunner>>>++>>
                              (using asp 3.2)

.scrollf .p .wipe
    [Next week we investigate the habits of the Lothian Software Wombat.]

.nl .nl
--

is padded with 'x' carriage returns (x = 8 * n, where 'n' is the
argument to ".speed").  The higher the value, the slower it goes.

Be judicious with your use of .spdemo4.asp


                                    Hello.

.scrollob .p .p
                                 I'm sad.  8(

.scrollof .p .p
                           Do you know why I'm sad ?

.scrollob .p .p
                     No, you wouldn't. Why would you care ?

.scrollof .p .p
                       Do you want to know why I'm sad ?

.scrollob .p .p
                  No, you still wouldn't. Why would you care ?

.scrollof .object \@_ 85 0 .anim .resetanim
                Is it because my Andalusian Video snail escaped ?

.scrollob .p .p
                           Look ! There it goes now !!!

.scrollof .p .p
                                    No...

.scrollob .p .p .fade .p
                                It's not that.

.spatter .p .p .fade
       Is it because I've been listening to too many Joy Division tracks ?
                              I don't think so...
           I haven't been listening to ANY Joy Division Tracks...

.object _@/ -5 80 .anim .resetanim
--

.wspatter .p .p .wipe .p
                             There it goes again.
                                Bloody snail.
                     I'm not really sure *WHY* I'm sad.
                                  after all...

.wspatter .p .p .fade .p
  there aren't many screen drivers that can fade messages into nothingness...

.spatter .p .p .clear .p
or others which magic them up from nothingness, only to wipe them into oblivion

.scrollf .p .p
                        Scroll them in from the left

.scrollob .p .p
                       .thgir eht morf ni meht llorcS
.wipe
--

.speed 4 .wspatter .wipe .wspatter .wipe .wspatter .wipe .wspatter .wipe
         Flashing messages seem to be very much in vogue at the moment.
         Flashing messages seem to be very much in vogue at the moment.
         Flashing messages seem to be very much in vogue at the moment.
         Flashing messages seem to be very much in vogue at the moment.

.speed 15 .show
       I don't like this style of flashing very much to tell the truth...

.flash .wipe
                    this          flashing

.speed 15 .p .wspatter .p
  Words can just be laid down in any old order you like, no problems at all...

.speed 0 .wipe
--

.layetm
                           whether it is worth it
                                                  all, being a microprocessor.
 Sometimes I really wonder

.wipe .p
--

.laymte
              should have been a
                                                        like my mother wanted.
 Or whether I
                                 Scientific Calculator,

.wipe .p
--

.speed 0 .p .clear .p .show .p
                    I ALWAYS WANTED TO BE A FRUIT MACHINE !!!!

.wipe .layb .p .fade
                              I wanted the fame !
.wipe .layf .p .fade
                           I wanted the high life !
.wipe .layb .p .fade
                               But most of all....

.show .p .p .fade
                              I WANTED THE MONEY !

.speed 20 .spatter .p .wipe
                                    Oh well.
.speed 2 \
.object his -30 40 \
.object dreams, -50 44 \
.object computer -15 22 \
.object he -2 58 \
.object ? -250 61 \
.object can 89 31 \
.object have 100 35 \
.object can 111 52 \
.object A 150 20 \
.object 't 200 55 \
.anim .resetanim .p .p .p .nl
--

.show .p .p .nl .wipe
                               Alec D.E. Muffett
                                (using asp 3.2)
 ----> 0 74 \
.object <---- 74 0 \
.anim .resetanim \
.show
                 "demo3.asp" in the standard asp distribution.

.nl .show .p
             demo5.asp


   Now it's my turn to show off and show these upstarts whats IT is all about!

.letter3
       I spent an hour bolting a few extra effects onto ASP (v3.1) today...

.speed 1 .flash .flash .speed 0 .p .wipe
                                                             v3.1

.letter1 .p
  Setting up all sorts of miscellaneous effects which I'm not going to explain.

.smooth 1 .scrollob .p
   I'll just let you watch what effect they have on the output.  Okey-dokey ?
(Oh yes, Alun, I did spot the optimisation. Looks much better now, doesn't it?)

.clear .p
--

.laymte
     First things first.
                                                     a space invaders gun.
                         Kev, your spider looks like

.p .p .wipe
--

.layetm
 At least my snail LOOKS like a snail.
                                        Pity I never brought the centipede out.

.p .p .wipe
--

.foreground
[----->                                                                 <-----]

.scrollof
                   By centipede, of course, I mean this one...

.p .scrollob
                                                                            --

.p .object nmmme -10 80 .anim .resetanim
--

.foreground

.p .p .wipe
--

.show \
.object ----> 0 74 \
.object <---- 74 0 \
.anim .resetanim \
.object ----> 0 74 \
.object <---- 74 0 \
.anim .resetanim \
.show
   Forgive me, but I'm going to bring out the flying arrows too. I Like them.

.wipe .layf .p .p
   I could always get back to basics I suppose. There are a few effects which

.wipe .layb .p .p
            have been grossly under-used since this .plan war took off.

.wipe .spatter .p .p .fade
These poor little effects just sit idle, languishing as an unused ASP operator.
                              They need the odd outing.

.wipe .scrollf .p .p .wipe
                                      Erm...

.speed 10 .wspatter .speed 0 .p .wipe
       Here's an idea! How about some hippy ethics to help pass the time ?

.letter2 .p .wipe
         Ban the bomb. I mean, if it's not too much trouble ? Ok, man ?

.letter3 .p .wipe
                        Ban soap commercials on JANET!
                        Ban Baldness. Ban Mathematics.
      Ban Hippies. Be Vegetarian. Real Veggie Hippies don't wear Leather.

.p .show .clear
              <my girlfriend told me this, so it must be true...>

.wipe .wspatter .p .p
  Hohum. Enough of the little in-jokes. Maybe I just ought to run the credits.

.scrollof .p
       First and probably least, Alun Jones, alj8. It's all his fault.

.scrollob .p
 And then kkb9, Kev Brooks, for doing such an awful effort I had to do one too.
          (He's improved a lot now, by the way. Not TOO much though)

.scrollof .p
 Simon Y Sais, ssw9, who never really got the hang of it, even if it was in 'C'

.scrollof
      [What IS the difference between C on UNIX and anywhere else, Simon?)

.flash .flash .p
            IS                        C    UNIX

.scrollob .p
Carl the hard-coding Hippy (ckw0), and JD (ccs7) for competition and enthusiasm
                                  (respectively)

.speed 10 .wipe .wspatter .wipe .wspatter .wipe .wspatter .wipe .wspatter .show
 and all my friends: Gilly, Alun (Baronson), Michelle, Daniel and the Plyn Mob.

.flash .flash
                     Gilly

.wipe .p .show .p .clear
               (Now you've had your names in lights, so push off!)

.spatter .nl .p .flush
     At least I haven't succumbed to the temptation of

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full

sysdd:/var: write failed,  file system full
Connection closed.

.p .p .p .p .p .p
--

.show .nl
                                   <grin!>
t, eg:

.show .p .p .speed 10 .fade .speed 0 .p
    This piece of text should fade quite gradually into nothingness...

-------------------------------
	.flash

Flashes all the text in a data line several times before moving onto the
next. Does not overstrike text with whitespace, and can be used thusly:

.show
"Beep Beep", went the little car's horn.
.speed 20 .flash .speed 0
 Beep Beep

-------------------------------
	.layb
	.layetm
	.laymte
	.layf

Prints the line by layineffects.c


 * This code is copyright ADE Muffett, September 1991, and is distributed as
 * part of the ASP .plan description language compiler.  This code is freely
 * redistributable as long as this copyright notice remains intact. No
 * responsibility is assumed by the author for any situation which arises
 * from the use of this code, including insanity, late nights, or disk
 * storage problems.
 */

#include "asp.h"

/* Cycle letters on the line backwards until they match the target letter */

void
Letter1 (cstring, dstring)
    register char *cstring;
    register char *dstring;
{
    int length;
    int changes;
    register int i;
    char c;

    length = strlen (dstring);

    for (c = '~'; c >= ' '; c--)
    {
	changes = 0;

	for (i = 0; i < length; i++)
	{
	    if ((!isspace (dstring[i])) && dstring[i] == c)
	    {
		stdline[i] = c;
		changes++;
	    }
	}
	if (changes)
	{
	    UpdateCR ();
	}
    }
}
/* Cycle letters on the line backwards until they match the target letter */

void
Letter2 (cstring, dstring)
    register char *cstring;
    register char *dstring;
{
    register int i;
    int changes;
    int length;
    char c;

    length = strlen (dstring);

    for (c = '~'; c >= ' '; c--)
    {
	changes = 0;

	for (i = 0; i < length; i++)
	{
	    if ((!isspace (dstring[i])) && dstring[i] <= c)
	    {
		stdline[i] = c;
		changes++;
	    }
	}
	if (changes)
	{
	    UpdateCR ();
	}
    }
}
/* Cycle letters on the line backwards until they match the target letter */

void
Letter3 (cstring, dstring)
    register char *cstring;
    register char *dstring;
{
    int length;
    int changes;
    register int i;
    char c;

    length = strlen (dstring);

    for (c = '~'; c >= ' '; c--)
    {
	changes = 0;

	for (i = 0; i < length; i++)
	{
	    if ((!isspace (dstring[i])) && dstring[i] <= c)
	    {
		stdline[i] = c;
		if (dstring[i] == c)
		{
		    changes++;
		}
	    }
	}
	if (changes)
	{
	    UpdateCR ();
	}
    }
}
/* flash all printable characters on the line */

void
Flash (cstring, dstring)
    register char *cstring;
    register char *dstring;
{
    int length;
    int i;
    register int j;

    length = strlen (dstring);

    i = NUM_FLASH;

    while (i--)
    {
	for (j = 0; j < length; j++)
	{
	    if (!isspace (dstring[j]))
	    {
		stdline[j] = ' ';
	    }
	}
	UpdateCR ();

	for (j = 0; j < length; j++)
	{
	    if (!isspace (dstring[j]))
	    {
		stdline[j] = dstring[j];
	    }
	}
	UpdateCR ();
    }
}
/* Spatter line down randomly */
void
Spatter (cstring, dstring)
    register char *cstring;
    register char *dstring;
{
    int length;
    register int i;
    register int dindex;

    length = strlen (dstring);

    for (i = 0; i < LOOP_COUNT; i++)
    {
	if (!length)
	{
	    continue;
	}
	dindex = rand () % length;
	if (stdline[dindex] == dstring[dindex])
	{
	    continue;
	}
	stdline[dindex] = dstring[dindex];
	UpdateCR ();
    }
    TransparentOverlay (stdline, dstring);
    UpdateCR ();
}
/* Like Spatter(), but on a by-word basis */
void
WordSpatter (cstring, dstring)
    register char *cstring;
    register char *dstring;
{
    int length;
    register int i;
    register int j;
    register int dindex;

    length = strlen (dstring);

    for (i = 0; i < LOOP_COUNT; i++)
    {
	if (!length)
	{
	    continue;
	}
	for (dindex = rand () % length;
	     dindex >= 0 && !isspace (dstring[dindex]);
	     dindex--);
	dindex++;
	if (stdline[dindex] == dstring[dindex])
	{
	    continue;
	}
	while (dstring[dindex] && !isspace (dstring[dindex]))
	{
	    stdline[dindex] = dstring[dindex];
	    dindex++;
	}
	UpdateCR ();
	if (!strcmp (dstring, stdline))
	{
	    break;
	}
    }
    TransparentOverlay (stdline, dstring);
    UpdateCR ();
}
/* Draw line and then remove, char by char */
void
Fade (cstring, dstring)
    register char *cstring;
    register char *dstring;
{
    int length;
    register int i;
    register int dindex;

    TransparentOverlay (stdline, dstring);
    UpdateCR ();

    for (i = 0; i < LOOP_COUNT; i++)
    {
	length = strlen (stdline);
	if (!length)
	{
	    continue;
	}
	dindex = rand () % length;
	if (stdline[dindex] == ' ')
	{
	    continue;
	}
	stdline[dindex] = ' ';
	UpdateCR ();
	Trim (stdline);
    }

    for (i = 0; stdline[i]; i++)
    {
	stdline[i] = ' ';
    }
    UpdateCR ();
}
/* Scroll characters l->r, one by one */
void
ScrollForward (cstring, dstring)
    char *cstring;
    char *dstring;
{
    register int i;
    register int j;
    register int oplength;

    oplength = strlen (dstring);

    for (i = oplength - 1; i >= 0; i--)
    {
	for (j = 0; dstring[j + i]; j++)
	{
	    stdline[j] = dstring[j + i];
	}
	UpdateCR ();
    }
}
/* Scroll characters r->l, one by one */
void
ScrollBackward (cstring, dstring)
    char *cstring;
    char *dstring;
{
    register int i;
    register int j;
    char srcbuffer[SCREENWIDTH + 1];

    NullSet (srcbuffer, sizeof (srcbuffer));
    strcpy (srcbuffer, dstring);
    SpaceFlood (srcbuffer, SCREENWIDTH);

    for (i = SCREENWIDTH - 1; i >= 0; i--)
    {
	for (j = 0; (j + i) < SCREENWIDTH; j++)
	{
	    stdline[j + i] = srcbuffer[j];
	}
	UpdateCR ();
    }

}
/* scroll entire line r->l, bringing on new stuff from the right */
void
ScrollOffBackward (cstring, dstring)
    char *cstring;
    char *dstring;
{
    register int i;
    register int j;
    char srcbuffer[SCREENWIDTH + 1];

    NullSet (srcbuffer, sizeof (srcbuffer));
    strcpy (srcbuffer, dstring);
    SpaceFlood (srcbuffer, SCREENWIDTH);

    for (i = 0; i < SCREENWIDTH; i++)
    {
	for (j = 1; j < SCREENWIDTH; j++)
	{
	    stdline[j - 1] = stdline[j];
	}
	stdline[SCREENWIDTH - 1] = srcbuffer[i];
	UpdateCR ();
    }
}
/* scroll entire line l->r, bringing on new stuff from the left */
void
ScrollOffForward (cstring, dstring)
    char *cstring;
    char *dstring;
{
    register int i;
    register int j;
    char srcbuffer[SCREENWIDTH + 1];

    NullSet (srcbuffer, sizeof (srcbuffer));
    strcpy (srcbuffer, dstring);
    SpaceFlood (srcbuffer, SCREENWIDTH);

    for (i = SCREENWIDTH - 1; i >= 0; i--)
    {
	for (j = SCREENWIDTH - 2; j > 0; j--)
	{
	    stdline[j] = stdline[j - 1];
	}
	stdline[0] = srcbuffer[i];
	UpdateCR ();
    }
}
/* Lay characters down l->r, one by one */
void
LayForward (cstring, dstring)
    char *cstring;
    register char *dstring;
{
    register int i;

    /* do not copy last null. */
    for (i = 0; dstring[i]; i++)
    {
	stdline[i] = dstring[i];
	UpdateCR ();
    }
}
/* Lay characters down r->l, one by one */
void
LayBackward (cstring, dstring)
    char *cstring;
    register char *dstring;
{
    register int i;

    i = strlen (dstring) - 1;	/* index of last character */

    if (i >= 0)
    {
	stdline[i] = dstring[i];
	for ( /* nothing */ ; i >= 0; i--)
	{
	    stdline[i] = dstring[i];
	    UpdateCR ();
	}
    }
}
/* Lay r->l and v.v. meeting in	middle */
void
LayEndsToMiddle (cstring, dstring)
    char *cstring;
    register char *dstring;
{
    register int start;
    int middle;
    register int end;
    int dlength;

    dlength = strlen (dstring) - 1;
    end = dlength;
    for (start = 0; dstring[start] && isspace (dstring[start]); start++);
    if (!dstring[start])
    {
	return;
    }
    middle = ((end - start) / 2) + start;

    for (; end >= middle; end--, start++)
    {
	if (start <= dlength)
	{
	    stdline[start] = dstring[start];
	}
	if (end <= dlength)
	{
	    stdline[end] = dstring[end];
	}
	UpdateCR ();
    }
}
/* Lay l->r and v.v., middle to end */
void
LayMiddleToEnds (cstring, dstring)
    char *cstring;
    register char *dstring;
{
    register int dlength;
    register int backwards;
    register int forwards;
    int start;
    int end;

    dlength = strlen (dstring) - 1;
    end = dlength;
    for (start = 0; dstring[start] && isspace (dstring[start]); start++);
    if (!dstring[start])
    {
	return;
    }
    forwards = backwards = ((end - start) / 2) + start;

    for (; backwards >= start || forwards <= end;)
    {
	if (backwards >= start)
	{
	    if (backwards <= dlength)
	    {
		stdline[backwards] = dstring[backwards];
	    }
	    backwards--;
	}
	if (forwards <= end)
	{
	    if (forwards <= dlength)
	    {
		stdline[forwards] = dstring[forwards];
	    }
	    forwards++;
	}
	UpdateCR ();
    }
}
 it already there off of
the screen, rather than overstriking it.  See the demos for examples.

.scrollob .p .p
This message will scroll from right to left across the width of the screen
This message will also scroll from right to left, without overstriking.

-------------------------------
	.spatter
	.wspatter

".spatter" is the opposite of ".fade".  ".wspatter" is similar, but
spatters whole words onto the screen, rather than characters.
--display.c


 * This code is copyright ADE Muffett, September 1991, and is distributed as
 * part of the ASP .plan description language compiler.  This code is freely
 * redistributable as long as this copyright notice remains intact. No
 * responsibility is assumed by the author for any situation which arises
 * from the use of this code, including insanity, late nights, or disk
 * storage problems.
 */

#include "asp.h"
#undef DEBUG

static char currline[SCREENWIDTH + 1];	/* The state of the union... */

/* nothing */
void
Noop ()
{
}
/* Throw a newline */
void
LineFeed ()
{
    static char lf = '\n';

    putchar (lf);
    NullSet (currline, sizeof (currline));
    SpaceFlood (currline, sizeof (currline));
    currline[SCREENWIDTH] = '\0';
}
/* Throw a carriage return */
void
CReturn ()
{
    static char cr = '\r';

    putchar (cr);
}
/* Fast clear of the current line */
void
Wipe ()
{
    NullSet (stdline, sizeof (stdline));
}
/* Fast clear of the current line */
void
Clear ()
{
    Wipe ();
    UpdateCR ();
}
/* show something onto screen destructively */
void
Show (cstring, dstring)
    char *cstring;
    char *dstring;
{
    Wipe ();
    Overlay (stdline, dstring);
    UpdateCR ();
}
/* show something onto screen non destructively */
void
TShow (cstring, dstring)
    char *cstring;
    char *dstring;
{
    TransparentOverlay (stdline, dstring);
    UpdateCR ();
}
/* Pause about 1 second @ 9600 baud */
void
Pause ()
{
    register int i;

    for (i = 0; i < LOOP_COUNT; i++)
    {
	CReturn ();
    }
    for (i = (LOOP_COUNT * (speed / DUMMY_RETURNS)); i; i--)
    {
	CReturn ();
    }
}
/* Trim off all whitespace from a text line */
void
Trim (ptr)
    register char *ptr;
{
    while (*ptr)
    {
	ptr++;
    }
    while (isspace (*(--ptr)));
    *(++ptr) = '\0';
}
/* the display primitive */
int
Update ()
{
    register int i;
    int j;
    int print_anim;
    int print_stdline;
    char diffline[SCREENWIDTH + 1];

    /* fix up all spaces */
    SpaceFlood (background, SCREENWIDTH);
    background[SCREENWIDTH] = '\0';
    Trim (background);

    SpaceFlood (stdline, SCREENWIDTH);
    stdline[SCREENWIDTH] = '\0';
    Trim (stdline);

    SpaceFlood (anim_buffer, SCREENWIDTH);
    anim_buffer[SCREENWIDTH] = '\0';
    Trim (anim_buffer);

    SpaceFlood (foreground, SCREENWIDTH);
    foreground[SCREENWIDTH] = '\0';
    Trim (foreground);

#ifdef DEBUG
    printf ("bg'%s'\n", background);
    printf ("st'%s'\n", stdline);
    printf ("ab'%s'\n", anim_buffer);
    printf ("fg'%s'\n", foreground);
#endif

    /* zero the differences buffer */
    NullSet (diffline, sizeof (diffline));
    SpaceFlood (diffline, SCREENWIDTH);
    diffline[SCREENWIDTH] = '\0';

    TransparentOverlay (diffline, background);
    TransparentOverlay (diffline, stdline);
    TransparentOverlay (diffline, anim_buffer);
    TransparentOverlay (diffline, foreground);
    Trim (diffline);

    /* and tidy up the memory copy of the current line */
    Trim (currline);		/* this is what the screen is */

    i = strlen (diffline);
    j = strlen (currline);
    if (i < j)
    {
	for (; i < j && i < SCREENWIDTH; i++)
	{
	    diffline[i] = ' ';
	}
	diffline[j] = '\0';
    }
    diffline[SCREENWIDTH] = '\0';

    /* there is a difference between screen and stdline+overstrikes */
    if (strcmp (currline, diffline))
    {
	char printline[SCREENWIDTH + 1];

	/* backup diffline */
	Memcpy (printline, diffline, sizeof (printline));

	/* don't print common trailing characters except space */
	if ((i = strlen (currline)) == strlen (diffline))
	{
	    while (i-- && (diffline[i] == currline[i]))
	    {
		printline[i] = '\0';
	    }
	}
	/* print only what is necessary to make changes */
	printf ("%s", printline);

	/* make diffline the current line */
	Memcpy (currline, diffline, sizeof (currline));

	/* fill out line */
	return (strlen (printline));
    } else
    {
	return (SCREENWIDTH);
    }
}
/* save typing */
void
UpdateCR ()
{
    register int i;

    i = Update ();
    CReturn ();

    while (smooth && (i++ < SCREENWIDTH))
    {
	CReturn ();
    }

    for (i = 0; i < (speed * DUMMY_RETURNS); i++)
    {
	CReturn ();
    }
}
/* END OF DISPLAY PRIMITIVES */
OffBackward (cstring, dstring)
    char *cstring;
    char *dstring;
{
    register int i;
    register int j;
    char srcbuffer[SCREENWIDTH + 1];

    NullSet (srcbuffer, sizeof (srcbuffer));
    strcpy (srcbuffer, dstring);
    SpaceFlood (srcbuffer, SCREENWIDTH);

    for (i = 0; i < SCREENWIDTH; i++)
    {
	for (j = 1; j < SCREENWIDTH; j++)
	{
	    stdline[j - 1] = stdline[j];
	}
	stdline[SCREENWIDTH - 1] = s





    if (i >= 0)
    {
	stdline[i] = dstring[i];
	for ( /* nothing */ ; i >= 0; i--)
	{
	    stdline[i] = dstring[i];
	    UpdateCR ();
	}
    }
}
/* Lay r->l and v.v. meeting in	middle */
void
LayEndsToMiddle (cstring, dstring)
    char *cstring;
    register char *dstring;
{
    register int start;
    int middle;
    register int end;
    int dlength;

    dlength = strlen (dstring) - 1;
    end = dlength;
    for (start = 0; dstring[start] && isspace (dstring[start]); start++);
    if (!dstring[start])
    {
	return;
    }
    middle = ((end - start) / 2) + start;

    for (; end >= middle; end--, start++)
    {
	if (start <= dlength)
	{
	    stdline[start] = dstring[start];
	}
	if (end <= dlength)
	{
	    stdline[end] = dstring[end];
	}
	UpdateCR ();
    }
}
/* Lay l->r and v.v., middle to end */
void
LayMiddleToEnds (cstring, dstring)
    char *cstring;
    register char *dstring;
{
    register int dlength;
    register int backwards;
    register int forwards;
    int start;
    int end;

    dlength = strlen (dstring) - 1;
    end = dlength;
    for (start = 0; dstring[start] && isspace (dstring[start]); start++);
    if (!dstring[start])
    {
	return;
    }
    forwards = backwards = ((end - start) / 2) + start;

    for (; backwards >= start || forwards <= end;)
    {
	if (backwards >= start)
	{
	    if (backwards <= dlength)
	    {
		stdline[backwards] = dstring[backwards];
	    }
	    backwards--;
	}
	if (forwards <= end)
	{
	    if (forwards <= dlength)
	    {
		stdline[forwards] = dstring[forwards];
	    }
	    forwards++;
	}
	UpdateCR ();
    }
}
 it already there off of
the screen, rather than overstriking it.  See the demos for examples.

.scrollob .p .p
This message will scroll from right to left across the width of the screen
This message will also scroll from right to left, without overstriking.

-------------------------------
	.spatter
	.wspatter

".spatter" is the opposite of ".fade".  ".wspatter" is similar, but
spatters whole words onto the screen, rather than characters.
--display.c


 * This code is copyright ADE Muffett, September 1991, and is distributed as
 * part of the ASP .plan description language compiler.  This code is freely
 * redistributable as long as this copyright notice remains intact. No
 * responsibility is assumed by the author for any situation which arises
 * from the use of this code, including insanity, late nights, or disk
 * storage problems.
 */

#include "asp.h"
#undef DEBUG

static char currline[SCREENWIDTH + 1];	/* The state of the union... */

/* nothing

About this thread. These messages were posted publicly to the newsgroup alt.ascii-art.animation in 1994 and are mirrored here unchanged as part of the Historic Archives – only email addresses are masked. The artwork and text belong to their original authors: if you copy a piece, keep the artist's initials or signature intact and credit them where you can. Are you one of the authors? Contact us to get your posts attributed, connected to your artist profile, or removed.