/*      CURSIVE SIGNATURE PROGRAM       Version 0.10
 *              (c) 1985 - Jan Wolter
 *
 *  Purpose:    This program translates text into crude cursive script.
 *      It works on any terminal with a fairly normal character
 *      set (must have backslashes and underscores and suchlike).
 *      The font includes all upper and lower case letters, most
 *      punctuation, and a few symbols.  No numbers are included
 *      (It's difficult to make a nice italicized set of numbers).
 *      Cursive was originally written to generate fancy signatures
 *      for electronic mail messages, but other uses may occur to
 *      you.  The attractiveness of the font varies greatly with
 *      the display device.
 *
 *  Usage:  If no command line arguments are given, cursive reads the
 *      text to translate from standard input.  Otherwise the args
 *      are translated (e.g. "cursive Jan Wolter" prints my name).
 *      Output is always to standard output.  A couple command line
 *      arguments are recognized:
 *
 *        -in   Sets the amount of space to insert between letters.
 *          The default is "-i1".  "-i0" gives interesting
 *          results.
 *        -tn   Sets the length of the trailing line off the end
 *          of each word.  The default is "-t1".
 *
 *      One character in the text is treated in a special way:
 *
 *        '_'   Can be inserted in text to slightly lengthen the
 *          the spacing between two letters, or add a longer
 *          tail to the end of a word.
 *
 *  Internals:  Unfortunately, the program is a kludge and the font is
 *      somewhat difficult to edit.  It should be easy to port
 *      though.  Systems with short integers or unsigned characters
 *      should be no problem.  You should probably run "xstr" on the
 *      font.c file, but if you haven't got "xstr", just compiling it
 *      the usual way works fine.
 *
 *  Copyright:  Both the cursive program and the font it generates are
 *      copyrighted by yours truly.  However, both may be used
 *      and distributed freely.  You even have my permission to
 *      sell it, or include in it a system that you sell.  I only
 *      ask that my name be retained on this program, or any direct
 *      decendents of this program with approximately the same
 *      visibility as in this posting.
 *
 *  Mail:   I'm interested in any comments you have on this program.
 *      I can be mailed at "janc@crim.eecs.umich.edu".  Better yet,
 *      if you are into teleconferencing, call M-Net at (313) 994-6333
 *      and type "newuser" at the "login:" prompt to give yourself an
 *      account.  Send mail to janc, or join the "ugames" conference.
 *
 *      Have fun,
 *                ___                _     __  _
 *               (   >              ' )   /   // _/_
 *                __/___.  ____      / / / __|/  /  _  __
 *               / / (_/|_/ / <__   (_(_/ (_) \_<__</_/ (__
 *              <_/
 */

#include "a:stdio.h"
#include "cursive.h"

char *buffer[6];    /* memory buffers to build up line in */
int c[6];       /* current index in each of the buffer lines */
int tail[6];        /* which buffer lines have tails in them */
int lasttail;       /* which line was the last letter's tail */
int space;      /* how much white space before the next letter */
int interspace = 1; /* how much to spread adjacent letters out */
int taillen = 1;    /* how long the tails on ends of words should be */
char firstletter;   /* is this the first letter on the line? */
char message[256] = ""; /* message to print */

char *malloc();

/* These are used by atoi */

#define TAB             '\t'
#define SP              ' '
#define PLUS            '+'
#define MINUS           '-'     /* Redundant, but clearer */
#define LEASTN          '0'
#define MOSTN           '9'


main(argc,argv)
int argc;
char **argv;
{
int i;
char *s,*m;
char ch;

    m = message;
    for (i = 1; i < argc; i++)
    {
        if (*argv[i] == '-')
            switch(ch = argv[i][1])
            {
            case 'i':
            case 't':
                s = argv[i]+2;
                if (*s == '\000')
                    if (++i < argc)
                        s = argv[i];
                if (*s < '0' || *s > '9')
                {
                    printf("%s: Illegal value %s\n",
                        argv[0],s);
                    exit(1);
                }
                if (ch == 'i')
                    interspace = atoi(s);
                else
                    taillen = atoi(s);
                break;
            default:
                printf("usage: %s [-tn] [-in] message\n",
                    argv[0]);
                exit(1);
            }
        else
        {
            if (m != message)
                *(m++) = ' ';
            for (s=argv[i]; *s != '\000'; s++)
                *(m++) = *s;
        }
    }
    /* Do the deed */
    if (m != message)
    {
        /* Message from the arg list */
        *(m++) = 0;
        prline(message);
    }
    else
    {
        /* Message from standard input */
        while (gets(message) != NULL)
            prline(message);
    }
}


/* Add the given letter to the end of the current line */

place(let)
struct letter *let;
{
int i,j,n;
int col;
int maxx= -10000;
char pad;
char *l;

    if (firstletter)
    {
        col = space;        /* Leading spaces */
        firstletter = 0;
    }
    else
    {
        /* Find the furthest left position we can place this letter */
        for(i=0; i<6; i++)
        {
            if (let->line[i][0] != '\000' &&
                (col = c[i] - let->spcs[i]) > maxx)
                maxx = col;
        }

        /* Insert some spaces between letters */
        col = maxx + space + interspace;
    }

    for(i=0; i<6; i++)

        /* If Nothing on this Line, Skip It */
        if (let->line[i][0] != '\000')
        {
            /* Number of Spaces to Put on this Line? */
            n = col - c[i] + let->spcs[i];

            /* Flyers off Ends of Letters */
            if (tail[i])
                for (j = 0;
                     j < 5 && n > space + 2; j++,n--)
                    buffer[i][c[i]++] = '_';

            /* Connecting Lines Between Letters */
            pad = (lasttail == i && let->tailin == i) ? '_' : ' ';

            /* In the middle of the intersection of South and */
            /* East University, someone is playing the piano. */
            for ( ; n > 0; n--)
                buffer[i][c[i]++] = pad;

            /* Copy in the letter text */
            for (l = let->line[i]; *l != '\000'; l++)
                buffer[i][c[i]++] = *l;

            tail[i] = (i == let->tailout);
        }

    lasttail = let->tailout;
    space = 0;
}

/* Lengthen the last trailer by n */
tailer(n)
int n;
{
int j;
    if (lasttail >= 0)
        for (j = 0; j < n; j++)
            buffer[lasttail][c[lasttail]++] = '_';
}

/* Handle a line */
prline(s)
char *s;
{
int l,i;
char *ch;
short lcode;

    lasttail = -1;
    firstletter = 1;
    space = 0;
    /* Get some memory to put the output into */
    l = strlen(s) * (CHARWIDTH + interspace);
    for (i=0;i<6;i++)
    {
        buffer[i] = malloc((unsigned)l);
        tail[i] = c[i] = 0;
    }

    /* do each letter */
    for (ch=s; *ch != '\000'; ch++)
    {

        *ch &= '\177';
        /* Find the letter */
        lcode = (lasttail != 2) ? code1[*ch] : code2[*ch];
        if (lcode >= 0)
            place(&list[lcode]);
        else
            /* Various Special characters */
            switch(lcode)
            {
            case SP:
                /* Insert white space before next letter */
                tailer(taillen);
                space += 3;
                lasttail = -1;
                break;
            case ST:
                /* Lengthen the last tail */
                if (lasttail >= 0)
                    buffer[lasttail][c[lasttail]++] = '_';
                break;
            }
    }
    tailer(taillen);

    /* print the line and release the memory */
    for (i=0;i<6;i++)
    {
        buffer[i][c[i]++] = '\n';
        write(1,buffer[i],c[i]);
        free(buffer[i]);
    }
}

/*
**      atoi
**
**      Convert an ASCII string to an integer
**
*/


int atoi( ap )
char *ap;
{
        register int n, c;
        register char *p;
        int f;

        p = ap;
        n = 0;
        f = 1;

        /* Scan the string for spaces or signs */
        for( ; ;p++ ){
                if( *p == SP || *p == TAB || *p == PLUS )
                        continue;
                if( *p == MINUS ){
                        f = -f;
                        continue;
                }
                break;
        }

        /* Now assemble the number */
        while( *p >= LEASTN && *p <= MOSTN )
                n = n*10 + *p++ - LEASTN;
        if( f < 0 )
                n = -n;

        return( n );
}

