                             Text Windows

                            Matthew Probert
                           Servile  Software


Standard C functions allow text to be displayed anywhere on the 
screen. But often a programmer wants to be able to define a sub area - 
or window - of the screen within which text should be displayed. It is 
convenient if this window behaves like an independant sub screen; 
wrapping text around the confines of the area and scrolling without 
disturbing the surrounding screen areas.

The code offered here allows a C programmer to define text windows. 
Each text window may then be written to independantly of the other 
windows and the main screen display. The window will scroll when it is 
full, and wrap text around the edges, just like the main screen in 
miniature.

The code offered here is compatible with both standard and VESA text 
modes.


--------------------------------Cut Here------------------------------
#include <stdio.h>
#include <dos.h>
#include <stdarg.h>
#include <stdlib.h>

/*
    Window structure
*/
struct WI
{
    unsigned char left;            /* Window coordinates */
    unsigned char top;
    unsigned char right;
    unsigned char bottom;
    unsigned char row;            /* Cursor position within window */
    unsigned char col;
    unsigned char attribute;    /* Colour attribute for window */
};
typedef struct WI SWINDOW;

void win_ok(SWINDOW *);
void win_up(SWINDOW *);

void getcursor(int *row, int *col)
{
    /*
        Return the cursor position
    */

    union REGS inreg,outreg;

    inreg.h.bh = 0;
    inreg.h.ah = 0x03;
    int86(0x10, &inreg, &outreg);
    *row = outreg.h.dh;
    *col = outreg.h.dl;
}

void at(unsigned char row, unsigned char col)
{
    /*
        select cursor position
    */

    asm mov bh , 0;
    asm mov dh , row;
    asm mov dl , col;
    asm mov ah , 02h;
    asm int 10h;
}

void wprintf(SWINDOW *winstruc,char *format, ...)
{
    /*
        print text to window
    */

    va_list arg_ptr;
    int c;
    int r;
    char attribute;
    char chr;
    static char *output;

    /*
        output is a temporary buffer into which the output string
        is built.
    */
    if (output == NULL)
        output = malloc(4000);

    /*
        Build output string
    */
    va_start(arg_ptr, format);
    vsprintf(output, format, arg_ptr);

    /*
        Preserve main cursor position
    */
    getcursor(&r,&c);

    /*
        Check the window
    */
    win_ok(winstruc);

    /*
        Move window colour attribute information into a
        local variable
    */
    attribute = winstruc->attribute;

    /*
        Now display the output text
        Only '\n' of the control characters
        is recognised by this function.
    */
    while (*output)
    {
        /*
            Position cursor within window
        */
        at(winstruc->top + winstruc->row,winstruc->left + winstruc->col);

        /*
            Fetch next output character
        */
        chr = *output;

        if (chr == '\n')
        {
            /*
                Move window cursor down one line
            */
            winstruc->col = 0;
            winstruc->row++;
            win_ok(winstruc);
        }
        else
        if (chr > 31)
        {
            /*
                Use BIOS interrupt 10h, function 09h
                to display the character
                This is at least compatible with different
                text display modes, CGA,EGA,VGA and VESA
            */
            asm mov bh,0;
            asm mov bl,attribute;
            asm mov cx,1;
            asm mov ah,9;
            asm mov al,chr;
            asm int 10h;

            /*
                Move the cursor right one column in the
                window
            */
            winstruc->col++;

            /*
                Check the window to see if the cursor needs
                to move down a row, and if the window needs
                scrolling
            */
            win_ok(winstruc);
        }
        output++;

    }
    /*
        Restore main screen cursor position
    */
    at(r,c);
}

void win_ok(SWINDOW *winstruc)
{
    /*
        Check window cursor coordinates
        moving cursor down a line and
        scrolling the window if required
    */

    if (winstruc->left + winstruc->col > winstruc->right)
    {
        winstruc->col = 0;
        winstruc->row++;
    }

    if (winstruc->top + winstruc->row > winstruc->bottom)
    {
        winstruc->row--;
        win_up(winstruc);
    }
}

void win_up(SWINDOW *winstruc)
{
    /*
        Scroll text window up one line
    */

    unsigned char left, top, right, bottom, attribute;

    left = winstruc->left;
    top = winstruc->top;
    right = winstruc->right;
    bottom = winstruc->bottom;
    attribute = winstruc->attribute;

    asm mov al , 1;
    asm mov cl , left;
    asm mov ch , top;
    asm mov dl , right;
    asm mov dh , bottom;
    asm mov bh , attribute;
    asm mov ah , 6;
    asm int 10h;
}

void wincls(SWINDOW *winstruc)
{
    /*
        Clear text window
    */

    unsigned char left, top, right, bottom, attribute;

    winstruc->col = 0;
    winstruc->row = 0;

    left = winstruc->left;
    top = winstruc->top;
    right = winstruc->right;
    bottom = winstruc->bottom;
    attribute = winstruc->attribute;

    asm mov al , 53;
    asm mov cl , left;
    asm mov ch , top;
    asm mov dl , right;
    asm mov dh , bottom;
    asm mov bh , attribute;
    asm mov ah , 6;
    asm int 10h;
}

/*
    Demonstration code
*/

void main()
{
    SWINDOW mywin;
    int n;

    /*
        Initialise a window
    */
    mywin.left = 7;
    mywin.top = 5;
    mywin.right = 47;
    mywin.bottom = 10;
    mywin.attribute = 32;
    mywin.col = 6;
    mywin.row = 6;


    /*
        Fill the screen with nonsense
    */
    for(n = 0; n < 120; n++)
    {
        printf("This is displayed on the main screen");
    }

    /*
        Clear the window
    */
    wincls(&mywin);

    /*
        Write to the window
    */
    for(n = 0; n < 50; n++)
    {
        wprintf(&mywin,"Text in a user defined window line #%04d\n",n);
    }
}
--------------------------------Cut Here------------------------------

