TOOLKIT\LIBRARY.C  ·  C  ·  22.4 KB  ·  1989-05-01  ·  from PersonalComputer_May-1989
/*******************************   LIBRARY   **********************************

                             By Robin Nixon 1989

These routines are intendwed to be used with any version of Borlan's Turbo C.
However, they should work with little (or no) adaptation on many other compilers. Each routine is briefly documented, giving sufficient information for
their use. Any queries with regard to this library can only be answered through
the letter pages of PC magazine.

I hope you find them useful!


                                  FUNCTIONS:

TEXT:       CLS, LOCATE, GETCUR, INDENT, PRINT, CURSIZE, COLPUTCH
            CRLF, COLOUR, PEN, PAPER, CURSOROFF, PHEX1, PHEX2, PHEX4
            PHEX8, BORDER, SCROLLDOWN
GRAPHICS:   MODE, GCOL, MOVE, DRAW, POINT, FILL, BIGPRINT, CHARSET
KEYBOARD:   INKEY, INPUT
SYSTEM:     ISMONO
MATHS:      SGN

******************************************************************************/

/* Macros - for clarity */

#define TRUE 1
#define FALSE 0
#define SP 32
#define CR 13
#define LF 10
#define TAB 9

#define cursoroff() cursize(9,9)

#define uchar unsigned char
#define uint unsigned int
#define bool uint
#define file FILE
#define NOTHING

#define BLACK       0
#define BLUE        1
#define GREEN       2
#define CYAN        3
#define RED         4
#define VIOLET      5
#define BROWN       6
#define YELLOW      BROWN
#define WHITE       7

#define INTENSE     8 +
#define FLASHING    8 +

#define STACKLIM 5000 /* stack for fills */

uchar defs[768]=    /* second character set */
{
    0,0,0,0,0,0,0,0,               /*   */ 24,24,24,24,24,0,24,0,         /* ! */
    108,108,108,0,0,0,0,0,         /* " */ 108,108,254,108,254,108,108,0, /* # */
    24,62,88,60,26,124,24,0,       /* $ */ 0,198,204,24,48,102,198,0,     /* % */
    56,108,56,118,220,204,118,0,   /* & */ 24,24,48,0,0,0,0,0,            /* ' */
    12,24,48,48,48,24,12,0,        /* ( */ 48,24,12,12,12,24,48,0,        /* ) */
    0,102,60,255,60,102,0,0,       /* * */ 0,24,24,126,24,24,0,0,         /* + */
    0,0,0,0,0,24,24,48,            /* , */ 0,0,0,126,0,0,0,0,             /* - */
    0,0,0,0,0,24,24,0,             /* . */ 6,12,24,48,96,192,128,0,       /* / */
    124,198,206,214,230,198,124,0, /* 0 */ 24,56,24,24,24,24,126,0,       /* 1 */
    60,102,6,60,96,102,126,0,      /* 2 */ 60,102,6,28,6,102,60,0,        /* 3 */
    28,60,108,204,254,12,30,0,     /* 4 */ 126,98,96,124,6,102,60,0,      /* 5 */
    60,102,96,124,102,102,60,0,    /* 6 */ 126,102,6,12,24,24,24,0,       /* 7 */
    60,102,102,60,102,102,60,0,    /* 8 */ 60,102,102,62,6,102,60,0,      /* 9 */
    0,0,24,24,0,24,24,0,           /* : */ 0,0,24,24,0,24,24,48,          /* ; */
    12,24,48,96,48,24,12,0,        /* < */ 0,0,126,0,0,126,0,0,           /* = */
    96,48,24,12,24,48,96,0,        /* > */ 60,102,102,12,24,0,24,0,       /* ? */
    124,198,222,222,222,192,124,0, /* @ */ 24,60,102,102,126,102,102,0,   /* A */
    252,102,102,124,102,102,252,0, /* B */ 60,102,192,192,192,102,60,0,   /* C */
    248,108,102,102,102,108,248,0, /* D */ 254,98,104,120,104,98,254,0,   /* E */
    254,98,104,120,104,96,240,0,   /* F */ 60,102,192,192,206,102,62,0,   /* G */
    102,102,102,126,102,102,102,0, /* H */ 126,24,24,24,24,24,126,0,      /* I */
    30,12,12,12,204,204,120,0,     /* J */ 230,102,108,120,108,102,230,0, /* K */
    240,96,96,96,98,102,254,0,     /* L */ 198,238,254,254,214,198,198,0, /* M */
    198,230,246,222,206,198,198,0, /* N */ 56,108,198,198,198,108,56,0,   /* O */
    252,102,102,124,96,96,240,0,   /* P */ 56,108,198,198,218,204,118,0,  /* Q */
    252,102,102,124,108,102,230,0, /* R */ 60,102,96,60,6,102,60,0,       /* S */
    126,90,24,24,24,24,60,0,       /* T */ 102,102,102,102,102,102,60,0,  /* U */
    102,102,102,102,102,60,24,0,   /* V */ 198,198,198,214,254,238,198,0, /* W */
    198,108,56,56,108,198,198,0,   /* X */ 102,102,102,60,24,24,60,0,     /* Y */
    254,198,140,24,50,102,254,0,   /* Z */ 60,48,48,48,48,48,60,0,        /* [ */
    192,96,48,24,12,6,2,0,         /* \ */ 60,12,12,12,12,12,60,0,        /* ] */
    24,60,126,24,24,24,24,0,       /*  */ 0,0,0,0,0,0,0,255,             /* _ */
    48,24,12,0,0,0,0,0,            /* ` */ 0,0,120,12,124,204,118,0,      /* a */
    224,96,124,102,102,102,220,0,  /* b */ 0,0,60,102,96,102,60,0,        /* c */
    28,12,124,204,204,204,118,0,   /* d */ 0,0,60,102,126,96,60,0,        /* e */
    28,54,48,120,48,48,120,0,      /* f */ 0,0,62,102,102,62,6,124,       /* g */
    224,96,108,118,102,102,230,0,  /* h */ 24,0,56,24,24,24,60,0,         /* i */
    6,0,14,6,6,102,102,60,         /* j */ 224,96,102,108,120,108,230,0,  /* k */
    56,24,24,24,24,24,60,0,        /* l */ 0,0,108,254,214,214,198,0,     /* m */
    0,0,220,102,102,102,102,0,     /* n */ 0,0,60,102,102,102,60,0,       /* o */
    0,0,220,102,102,124,96,240,    /* p */ 0,0,118,204,204,124,12,30,     /* q */
    0,0,220,118,96,96,240,0,       /* r */ 0,0,60,96,60,6,124,0,          /* s */
    48,48,124,48,48,54,28,0,       /* t */ 0,0,102,102,102,102,62,0,      /* u */
    0,0,102,102,102,60,24,0,       /* v */ 0,0,198,214,214,254,108,0,     /* w */
    0,0,198,108,56,108,198,0,      /* x */ 0,0,102,102,102,62,6,124,      /* y */
    0,0,126,76,24,50,126,0,        /* z */ 14,24,24,112,24,24,14,0,       /* { */
    24,24,24,24,24,24,24,0,        /* | */ 112,24,24,14,24,24,112,0,      /* } */
    118,220,0,0,0,0,0,0,           /* ~ */ 204,51,204,51,204,51,204,51    /* ▒ */
};

uchar   masks1[4]={63,207,243,252}, /* for graphic manipulation */
        masks2[8]={127,191,223,239,247,251,253,254},
        array[4];

/* Library functions */

extern void cls(),      locate(),       getcur(),       indent(),
            print(),    cursize(),      colour(),       colputch(),
            crlf(),     pen(),          paper(),        plot(),
            mode(),     move(),         draw(),         gcol(),
            push(),     pop(),          bigprint(),     charset(),
            phex1(),    phex2(),        phex4(),        phex8(),
            plot1512(), plot1512a(),    border(),       scrolldown();

extern int  inkey(),    ismono(),       point(),        sgn(),
            fill(),     fill1(),        fillkey();

extern
    uchar*  input();

extern uint rnd();

int         attrib=15,  mono,           oldx=0,
            oldy=0,     gcolour=1,      stack[STACKLIM][2],
            sptr1,      sptr2,          mwidth=80,
            pwidth=0,   setnum=0,       modeflag,
            pc1512,     ptr=0;

uint        seed=17,    seed2=37637;

/* Supplied Header files */

#include "stdio.h"
#include "process.h"
#include "stdlib.h"
#include "dir.h"
#include "dos.h"

/* Functions */

int ismono()    /* Is a mono monitor being used? If so the internal variable
                   mono is set *.
{
    union REGS inregs, outregs;

    inregs.h.ah=0x0f;

    int86(0x10,&inregs,&outregs);
    mono=(outregs.h.al == 7);
    return(mono);
}

void cls()  /* Clear the screen */
{
    union REGS inregs, outregs;

    inregs.h.ah=0x0f;
    int86(0x10,&inregs,&outregs);
    inregs.h.ah=0;
    inregs.h.al=outregs.h.al;

    int86(0x10,&inregs,&outregs);
}

void border(n)  /* Set the border - won't work on all EGA or VGA, should be
                   fine on CGA */
int n;
{
    outport(0x3d9,n);
}

void mode(n)    /* Set screen mode */
int n;
{
    union REGS inregs, outregs;

    modeflag=n;
    pc1512=FALSE;

    switch(n)
    {
        case 0: pwidth=0;   mwidth=40;  break;
        case 1: pwidth=0;   mwidth=40;  break;
        case 2: pwidth=0;   mwidth=80;  break;
        case 3: pwidth=0;   mwidth=80;  break;
        case 4: pwidth=320; mwidth=40;  break;
        case 5: pwidth=320; mwidth=40;  break;
        case 6: pwidth=640; mwidth=80;  break;
        case 7: pwidth=0;   mwidth=80;  break;

        case 141:pwidth=640; mwidth=80; /* 1512 16 colour mode */
                pc1512=TRUE; mode(6); outp(0x3D9,0xf); break;
    }
    inregs.h.ah=0;
    inregs.h.al=n;

    int86(0x10,&inregs,&outregs);
}

void locate(x,y)    /* Set cursor x,y */
int x,y;
{
    union REGS inregs, outregs;

    inregs.h.ah=2;
    inregs.h.bh=0;
    inregs.h.dl=x;
    inregs.h.dh=y;

    int86(0x10,&inregs,&outregs);
}

void getcur(x,y)    /* Get cursor x,y */
int *x,*y;
{
    union REGS inregs, outregs;

    inregs.h.ah=3;
    inregs.h.bh=0;

    int86(0x10,&inregs,&outregs);

    *x=outregs.h.dl;
    *y=outregs.h.dh;
}

void indent(i)  /* Indent at next line down */
int i;
{
    int x,y;
    getcur(&x,&y);
    locate(i,y);
}

void print(string)  /* V. fast print routine - careful, uses direct screen
                       access */
char *string;
{
    uint a,b,c,j,k,x,y;
    uint d[2];
    union REGS inregs, outregs;

    a=0xf000;
    b=0xfa6e;
    c=0xb000;
    if (mono)
        d[0]=0;
    else
        d[0]=0x8000;
    d[1]=0x9fD8;

    getcur(&x,&y);
    if (pwidth > 0)
    {
        if (pwidth == 320)
        {
            inregs.h.ah=9;
            inregs.x.bx=attrib;
            inregs.x.cx=1;

            for (j=0 ; j<strlen(string) ; ++j)
            {
                inregs.h.al=string[j];
                int86(0x10,&inregs,&outregs);
                if (++x >= mwidth)
                {
                    crlf();
                    getcur();
                }
                else
                    locate(x,y);
            }
        }
        else if (pwidth == 640)
        {
            if (attrib & 128)
                for (j=0 ; j<strlen(string) ; ++j)
                {
                    for (k=0 ; k<8 ; ++k)
                        pokeb(c,d[k & 1] + x + y*320 + k*40,
                        peekb(c,d[k & 1] + x + y*320 + k*40) ^
                        peekb(a,b + string[j]*8+k));
                    if (++x > 79)
                    {
                        crlf();
                        getcur(&x,&y);
                    }
                    else
                        locate(x,y);
                }
            else
            if (attrib & 16)
                for (j=0 ; j<strlen(string) ; ++j)
                {
                    for (k=0 ; k<8 ; ++k)
                        pokeb(c,d[k & 1] + x + y*320 + k*40,
                        peekb(a,b + string[j]*8+k) ^ 0xff);
                    if (++x > 79)
                    {
                        crlf();
                        getcur(&x,&y);
                    }
                    else
                        locate(x,y);
                }
            else
            for (j=0 ; j<strlen(string) ; ++j)
            {
                for (k=0 ; k<8 ; ++k)
                    pokeb(c,d[k & 1] + x + y*320 + k*40,
                    peekb(a,b + string[j]*8+k));
                if (++x > 79)
                {
                    crlf();
                    getcur(&x,&y);
                }
                else
                    locate(x,y);
            }
        }
    }
    else
    for (j=0 ; j<strlen(string) ; ++j)
    {
        pokeb(c,d[0] + x*2 + y*mwidth*2,    string[j]);
        pokeb(c,d[0] + x*2 + y*mwidth*2 + 1,attrib);
        if (++x >= mwidth)
        {
            crlf();
            getcur(&x,&y);
        }
    }
    locate(x,y);
}

void colputch(chr)  /* Like putch but uses the internal variable attrib for
                       colour */
int chr;
{
    int x,y,p;

    getcur(&x,&y);
    p=x*2 + y*mwidth*2;
    pokeb(0xb000,0x8001+p,attrib);
    pokeb(0xb000,0x8000+p,chr);
    if (x++ >= mwidth) crlf();
    else locate(x,y);
}

int inkey() /* Test for a key press */
{
    union REGS inregs, outregs;

    inregs.h.ah=6;
    inregs.h.dl=0xff;
    intdos(&inregs,&outregs);
    if (outregs.x.flags & 64)
        return(0);
    else
        return(outregs.h.al);
}

void cursize(start,end) /* Set the cursor size */
int start,end;
{
    union REGS inregs, outregs;

    inregs.h.ah=1;
    inregs.h.ch=start;
    inregs.h.cl=end;

    int86(0x10,&inregs,&outregs);
}

void crlf() /* Perform carriage return/linefeed */
{
    putch(13);
    putch(10);
}

int sgn(n)  /* sgn function */
int n;
{
    if (n < 0) return(-1);
    if (n == 0) return(0);
    return(1);
}

void colour(col1,col2)  /* Set pen & paper */
int col1,col2;
{
    if (!mono)
        attrib=col1+col2*16;
}

void pen(col)   /* Pen colour */
{
    colour(col,(attrib & 0xf0)/16);
}

void paper(col) /* Paper colour */
{
    colour(attrib & 0x0f,col);
}

void gcol(c)    /* Graphic colour */
int c;
{
    gcolour=c;
}

void move(x,y)  /* Move cursor */
int x,y;
{
    oldx=x;
    oldy=y;
}

void plot(x,y)  /* Plot a point */
int x,y;
{
    union REGS inregs, outregs;
    int n=16112;

    if (y & 1)
        n=7960;

    if (pc1512 == TRUE)
        plot1512(x,y);
    else if (pwidth == 320)
    {
        if (gcolour & 128)
            pokeb(0xb000,0x8000 + (x>>2) + n - y*40,
            peekb(0xb000,0x8000 + (x>>2) + n - y*40) ^
            ((gcolour & 3) << (6-(x & 3)*2)));
        else
            pokeb(0xb000,0x8000 + (x>>2) + n - y*40,
            (peekb(0xb000,0x8000 + (x>>2) + n - y*40) &
            masks1[x & 3]) | ((gcolour & 3) << (6-(x & 3)*2)));
    }
    else if (pwidth == 640)
    {
        if (gcolour & 128)
            pokeb(0xb000,0x8000 + (x>>3) + n - y*40,
            peekb(0xb000,0x8000 + (x>>3) + n - y*40) ^
            (gcolour & 1) << (7-(x & 7)) );
        else
            pokeb(0xb000,0x8000 + (x>>3) + n - y*40,
            (peekb(0xb000,0x8000 + (x>>3) + n - y*40) &
            masks2[x & 7]) | ((gcolour & 1) << (7-(x & 7))));
    }
    else
    {
        inregs.h.ah=12;
        inregs.x.cx=x;
        inregs.h.dl=199-y;
        inregs.h.al=gcolour;

        int86(0x10,&inregs,&outregs);
    }
    oldx=x;
    oldy=y;
}

void draw(x2,y2)    /* Draw a line */
uint x2,y2;
{
    uint x,y,dx,dy,change=0,i;
    int s1,s2,temp,e;

    x=oldx; y=oldy;
    dx=abs(x2-oldx); dy=abs(y2-oldy);
    s1=sgn(x2-oldx); s2=sgn(y2-oldy);

    if (dy > dx)
    {
        temp=dx; dx=dy; dy=temp;
        change=1;
    }
    e=(dy << 1)-dx;
    for (i=1 ; i <= dx ; ++i)
    {
        plot(x,y);
        while (e >= 0)
        {
            if (change) x += s1;
            else y += s2;
            e-=(dx << 1);
        }
        if (change) y += s2;
        else x += s1;
        e+=(dy << 1);
    }
    oldx=x; oldy=y;
    plot(x,y);
}

int point(x,y)  /* Test a point */
int x,y;
{
    int n=16112;

    if (y & 1)
        n=7960;

    if (pwidth == 320)
        return((peekb(0xb000,0x8000 + (x>>2) + n - y*40) >>
        (6-(x & 3)*2)) & 3);
    else if (pwidth == 640)
        return((peekb(0xb000,0x8000 + (x>>3) + n - y*40) &
        1 << (7-(x & 7))) > 0);
    else
        return(-1);
}  

int fillkey(x,y)    /* Call this instead of fill if you want to be able to
                       abort a fill by pressing a key */
int x,y;
{
    return(fill1(x,y,1));
}

int fill(x,y)       /* Fill an area */
uint x,y;
{
    return(fill1(x,y,0));
}

int fill1(x,y,flag) /* Used by fill */
uint x,y,flag;
{
    int background=point(x,y);

    sptr1=0;
    sptr2=0;
    push(x,y);

    while (sptr1 != sptr2)
    {
        pop(&x,&y);
        if (point(x,y+1) == background)
            push(x,y+1);
        if (point(x+1,y) == background)
            push(x+1,y);
        if (point(x-1,y) == background)
            push(x-1,y);
        if (point(x,y-1) == background)
            push(x,y-1);

        if (flag && inkey() != 0)
            return(1);
    }
    return(0);
}

void push(x,y)  /* Used by fill */
uint x,y;
{
    stack[sptr1][0]=x;
    stack[sptr1++][1]=y;
    if (sptr1 >= STACKLIM)
        sptr1=0;
    plot(x,y);
}

void pop(x,y)   /* Used by fill */
uint *x,*y;
{
    *x=stack[sptr2][0];
    *y=stack[sptr2++][1];
    if (sptr2 >= STACKLIM)
        sptr2=0;
}

void bigprint(string,x,y,w,h)   /* Print large text in graphic modes.
                                    w=width : h=height */
uchar *string;
uint x,y,w,h;
{
    uint j,k,l,m,n,q;

    for (j=0 ; j<strlen(string) ; ++j)
        for (k=0 ; k<8 ; ++k)
            for (l=0 ; l<h ; ++l)
                for (m=0 ; m<8 ; ++m)
                    for (n=0 ; n<w ; ++n)
                    {
                        switch(setnum)
                        {
                            default:
                            case 0:
                                q=peekb(0xf000,0xfa6e+string[j]*8+k);
                                break;
                            case 1:
                                q=defs[(string[j]-32)*8+k];
                                break;
                        }
                        if (q & 1 << (7-m))
                            plot(x+w*8*j+m*w+n,y-k*h-l);
                    }
}

void charset(c) /* Switch character set. 0 or 1 */
int c;
{
    setnum=c;
}

uchar *input(string,max)    /* Input a string */
uchar *string;
uint max;
{
    int c,l,p,x,y,j;

    getcur(&x,&y);
    p=l=strlen(string);
    print(string);

    while (1)
    {
        cursize(6,7);
        c=getch();
        cursoroff();

        switch(c)
        {
            case  1:case  2:case  3:case  4:case  6:
            case  9:case 10:case 11:case 12:case 14:case 15:
            case 16:case 17:case 18:case 19:case 20:case 21:
            case 22:case 23:case 24:case 25:case 26:case 28:
            case 29:case 30:case 31:
                break;

            case  5:
                for (j=p ; j<l ; ++j)
                    colputch(' ');
                string[p]='\0';
                locate(x+p,y);                 
                l=p;
                break;

            case  7:    /* Delete right */
                if (p<l)
                {
                    for (j=p ; j<l ; ++j)
                        string[j]=string[j+1];
                    locate(x,y);
                    print(string);
                    colputch(' ');
                    locate(x+p,y);
                    --l;
                }
                break;
               
            case  8:    /* Delete left */
                if (p>0)
                {
                    if (p<l && p>0)
                    {
                        for (j=(--p) ; j<l ; ++j)
                            string[j]=string[j+1];
                        locate(x,y);
                        print(string);
                        colputch(' ');
                        locate(x+p,y);
                        --l;
                    }
                    else
                    if (p>0)
                    {
                        locate(x+(--p),y);
                        colputch(' ');
                        locate(x+p,y);
                        string[p]='\0';
                        --l;
                    }
                }
                break;

            case 13:    /* Return */
                return(string);

            case 27:    /* Escape */
                locate(x,y);
                for (j=0 ; j<l ; ++j)
                    colputch(' ');
                string[0]='\0';
                l=0;
                p=0;
                locate(x,y);
                break;
            case 0:
                c=getch();
                switch(c)
                {
                    case 71:    /* Home */
                        locate(x,y);
                        p=0;
                        break;
                    case 75:    /* Left */
                        if (p>0)
                            locate(x+(--p),y);
                        break;
                    case 77:    /* Right */
                        if (p<l)
                            locate(x+(++p),y);
                        break;
                    case 79:    /* End */
                        locate(x+(p=l),y);
                        break;
                }
                break;
            default:
                if (l<max)
                {
                    if (p<l)
                    {
                        for (j=l ; j>p ; --j)
                            string[j]=string[j-1];
                        string[p++]=c;
                        locate(x,y);
                        print(string);
                        locate(x+p,y);
                    }
                    else
                    {
                        string[p++]=c;
                        colputch(c);
                    }
                    string[++l]='\0';
                }
                break;
        }
    }
}

void phex1(num) /* Print 4 bit hex number */
uchar num;
{
    if (num<10)
        colputch(num+'0');
    else
        colputch(num+55);
}

void phex2(num) /* Print 8 bit hex number */
uchar num;
{
    phex1(num >> 4);
    phex1(num & 0x0f);
}

void phex4(num) /* Print 16 bit hex number */
uint num;
{
    phex2(num >> 8);
    phex2(num & 0xff);
}

void phex8(num) /* Print 32 bit hex number */
unsigned long num;
{
    phex4(num >> 16);
    phex4(num & 0xffff);
}

uint rnd(num)   /* Return a random number less than num */
uint num;
{
    seed=seed+seed2+(seed % 32767);
    return(seed % num);
}

void plot1512(x,y)  /* Plot a point in the 1512 specific 16 colour mode */
int x,y;
{
    if (gcolour & 1)
    {
        outp(0x3dd,1);
        plot1512a(x,y,0);   /* Blue */
    }
    if (gcolour & 2)
    {
        outp(0x3dd,2);
        plot1512a(x,y,1);   /* Green */
    }

    if (gcolour & 4)
    {
        outp(0x3dd,4);
        plot1512a(x,y,2);   /* Red */
    }

    if (gcolour & 8)
    {
        outp(0x3dd,8);
        plot1512a(x,y,3);   /* Intense */
    }

    ++ptr;
    if (ptr == 8)   /* a fudge! will be improved */
        ptr=array[0]=array[1]=array[2]=array[3]=0;
}

void plot1512a(x,y,num) /* Used by plot1512 */
int x,y,num;
{
    int n=0x3ef0;

    if (y & 1)
        n=0x1f18;

    array[num] |= (1 << (7-(x & 7)));
    pokeb(0xb000,0x8000 + (x>>3) + n - y*40,array[num]);
}

void scrolldown(num,x1,y1,x2,y2) /* Scroll the screen down */
uint num,x1,y1,x2,y2;
{
    union REGS inregs, outregs;

    inregs.h.ah=7;
    inregs.h.al=num;
    inregs.h.bh=attrib;
    inregs.h.ch=y1;
    inregs.h.cl=x1;
    inregs.h.dh=y2;
    inregs.h.dl=x2;

    int86(0x10,&inregs,&outregs);
}