Tymeg

Full Version: Uncle DT's Random Image Thread
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Nice!  I like pie...  ;-)
I'm glad you got the South Park reference...
Foxtrot is a great comic...
I definitely agree with that...
Yup.  The geek shall inherit the earth...
Do you remember the old days. Then finding out how to increase the screen to 50 rows and it was awesome - so much more desktop real-estate...
mode con:lines=50  (never forget...  I hated DOS boxes that didn't automatically load ansi.sys)

Oh yeah, I remember.  And you created that awesome library that made development of those Printronix programs easy and quite attractive...
The one thing that was good about SR was the freedom to create...

Code:
#include <box3d_v4.h>

/* globals used only for this library */
int    SavedVideoMode;
int    VideoRam;
int    GraphInit=FALSE;
char    cutpastebuf[256];

RasterBlock    *ImageBuffer;
/* end globals


/*
** determine the size of the memory area required to store an image
**
** return value - unsigned long number of bytes for screen image
*/
unsigned long ImageSize(int x1, int y1, int x2, int y2)
{
    return((unsigned long)(((long)(x2-x1+1) * (long)(y2-y1+1)) + 4));
}


/*
**    check processor type - return FALSE if less than I386
** determine video card - return FALSE if not supported
** store video ram size
** save current video mode
** create a buffer for misc usgage
** enable box3dfnt font
** set initialized flag
**
** on success - return TRUE
** on failure - return FALSE
*/
int InitGraphics()
{
    if(GraphInit==TRUE)
        return(FALSE);

    GraphInit=FALSE;

    if(whichcpu() < I386)
        return(FALSE);

    if(whichvga()==0)
        return(FALSE);

    /* Build an 8k buffer for misc. graphic functions */
    ImageBuffer=(RasterBlock *)farmalloc(MEM8K);
    if(ImageBuffer==NULL)
        return(FALSE);

    box3dfnt();

    SavedVideoMode=videomodeget();
    VideoRam=whichmem();
    GraphInit=TRUE;

    return(TRUE);
}

/*
** returns video mode to previous state
**
** return value - none
*/
void CloseGraphics()
{
    if(GraphInit==TRUE)
    {
        farfree(ImageBuffer);
        videomodeset(SavedVideoMode);
    }
}

/*
** set the graphics mode
**
** on success - return TRUE
** on failure - return FALSE
**              invalid Mode or unable to set video mode
*/
int SetVideoMode(int Mode)
{
    PaletteData    pal;

    if(GraphInit==FALSE)
        return(FALSE);

    switch(Mode)
    {
        case RES320:
            res320();
            break;

        case RES640:
            if(!res640())
                return(FALSE);
            break;

        case RES640L:
            if(!res640l())
                return(FALSE);
            break;

        case RES800:
            if(!res800())
                return(FALSE);
            break;

        case RES1024:
            if(!res1024())
                return(FALSE);
            break;

        case RES1280:
            if(!res1280())
                return(FALSE);
            break;

        default:
            return(FALSE);
    }

    pal[LIGHTBLUEGRAY].r=(192 >> 2);
    pal[LIGHTBLUEGRAY].g=(204 >> 2);
    pal[LIGHTBLUEGRAY].b=(216 >> 2);
    palset(pal, LIGHTBLUEGRAY, LIGHTBLUEGRAY);

    return(TRUE);
}

void SetBackgroundColor(int color)
{
    drwfillbox(SET, color, 0, 0, maxx, maxy);
}

BOX3D *CreateBox(int    left,
                      int    top,
                      int    right,
                      int    bottom,
                      int    highlight,
                      int    fill,
                      int    shadow,
                     BOOL    title,
                     char    justify,
                     char    *titletext,
                     char    titletextcolor,
                     char    titlebackground,
                     BOOL    saveimage,
                     BOOL    waitforsync)
{
    int    Vert;

    char    Tmp[MAXPATH];
    char    DirBuffer[MAXPATH];

    FILE    *FilePtr;

    BOX3D *Box;

    /* allocate memory */
    Box=farmalloc(sizeof(BOX3D));
    if(Box==NULL)
        return(FALSE);

    /* check for overscan and clip as necessary */
    if(top    < 0 || top    > maxy ||
        bottom < 0 || bottom > maxy ||
        left   < 0 || left   > maxx ||
        right  < 0 || right  > maxx)
        return(FALSE);

    /* check for continuity and fix if necessary */
    if(top > bottom)
    {
        bottom+=top;
        top-=bottom;
        top*=-1;
        bottom-=top;
    }

    if(left > right)
    {
        right+=left;
        left-=right;
        left*=-1;
        right-=left;
    }

    /* the box needs to be high enough and long enough to hold a titlebar */
    if(title)
    {
        if(bottom-top < TITLEBAR)
        {
            bottom=top + TITLEBAR;
            if(bottom > maxy)
            {
                top-=bottom - maxy;
                bottom=maxy;
            }
        }

        if(right-left < (BORDERSPACE * 2) + (CHARSPACE * 2))
        {
            right=left + (BORDERSPACE * 2) + (CHARSPACE * 2);
            if(right > maxx)
            {
                left-=right - maxx;
                right=maxx;
            }
        }
    }

    /* save background image */
    if(saveimage)
    {
        /* save image to memory */
        Box->image=NULL;
        Box->imagefile[0]=NULL;
        if(ImageSize(left, top, right, bottom) < 0xFFFF)
        {
            Box->image=(RasterBlock *)farmalloc((unsigned long)ImageSize(left,
                                                                                             top,
                                                                                             right,
                                                                                             bottom));
            if(Box->image!=NULL)
                blkget(left, top, right, bottom, Box->image);
        }

        /* there's not enough physical memory to save the image    */
        /* in memory, so save it to disk instead                        */
        if(Box->image==NULL && ImageBuffer!=NULL)
        {
            sprintf(DirBuffer, "%s\\%s", getcwd(Tmp, MAXPATH), tmpnam(NULL));
            FilePtr=_fsopen(DirBuffer, "wb", SH_DENYNO);
            if(FilePtr!=NULL)
            {
                strcpy(Box->imagefile, DirBuffer);
                for(Vert=top; Vert<=bottom; Vert++)
                {
                    blkget(left, Vert, right, Vert, ImageBuffer);
                    fwrite(ImageBuffer, (size_t)ImageSize(left, Vert, right, Vert), 1, FilePtr);
                }
                fclose(FilePtr);
            }
            else
                return(FALSE);
        }
    }
    else
    {
        Box->image=NULL;
        Box->imagefile[0]=0x00;
    }

    /* avoid screen flicker... wait for vertical retrace */
    if(waitforsync)
        sdelay(1);

    /* draw the solid box */
    drwfillbox(SET, fill, left, top, right, bottom);

    /* create the highligh and shadown effects */
    drwline(SET, highlight, left, top, right, top);
    drwline(SET, highlight, left, top, left, bottom);
    drwline(SET, shadow, right, bottom, right, top);
    drwline(SET, shadow, right, bottom, left, bottom);

    /* create a titlebar */
    if(title)
    {
        drwfillbox(SET, titlebackground, left  + BORDERSPACE,
                                                    top   + BORDERSPACE,
                                                    right - BORDERSPACE,
                                                    top   + BORDERSPACE + TITLEAREA);

        drwline(SET, shadow, left  + BORDERSPACE,
                                    top   + BORDERSPACE,
                                    right - BORDERSPACE,
                                    top   + BORDERSPACE);
        drwline(SET, shadow, left  + BORDERSPACE,
                                    top   + BORDERSPACE,
                                    left  + BORDERSPACE,
                                    top   + BORDERSPACE + TITLEAREA);

        drwline(SET, highlight, right - BORDERSPACE,
                                        top   + BORDERSPACE + TITLEAREA,
                                        right - BORDERSPACE,
                                        top   + BORDERSPACE);
        drwline(SET, highlight, right - BORDERSPACE,
                                        top   + BORDERSPACE + TITLEAREA,
                                        left  + BORDERSPACE,
                                        top   + BORDERSPACE + TITLEAREA);

        /* make sure we don't exceed the number of characters */
        if(strlen(titletext) >= TITLELEN)
            titletext[TITLELEN-1]=0x00;

        /* truncate any text that will not fit nicely in the titlebar */
        while(((strlen(titletext)+1)*CHARSPACE) > (right-BORDERSPACE)-(left+BORDERSPACE))
        {
            titletext[strlen(titletext)-1]=0x00;
            justify=LEFT;
        }

        if(justify==LEFT)
            drwstring(SET, titletextcolor, titlebackground, titletext,
                         left + CHARSPACE, top + CHARSPACE);

        else if(justify==CENTERED)
            drwstring(SET, titletextcolor, titlebackground, titletext,
                         left + (((right-left) - (strlen(titletext) * CHARSPACE)) / 2),
                         top  + CHARSPACE);

        else if(justify==RIGHT)
            drwstring(SET, titletextcolor, titlebackground, titletext,
                         right - (strlen(titletext) * CHARSPACE) - CHARSPACE,
                         top + CHARSPACE);
    }

    /* copy the variables into the structure */
    Box->left=left;
    Box->top=top;
    Box->right=right;
    Box->bottom=bottom;
    Box->highlight=highlight;
    Box->fill=fill;
    Box->shadow=shadow;
    Box->title=title;
    Box->justify=justify;
    Box->titletextcolor=titletextcolor;
    Box->titlebackground=titlebackground;
    Box->saveimage=saveimage;
    Box->waitforsync=waitforsync;
    strcpy(Box->titletext, titletext);

    return(Box);
}

/*
** removes boxes off screen that were created with the save command
** restores previous background image
** cleans up memory allocation or temporary disk files
*/
int DestroyBox(BOX3D *Box)
{
    int Vert;

    FILE *FilePtr;

    /* remove the box and replace the background */
    if(Box->image!=NULL)
    {
        /* nackground image was stored in memory */
        /* replace image and clean-up variables  */
        blkput(SET, Box->left, Box->top, Box->image);
        farfree(Box->image);
        Box->image=NULL;
        memset(&Box, 0x00, sizeof(Box));

        return(TRUE);
    }
    else if(Box->imagefile!=NULL)
    {
        /* background image was stored on disk in a temporary file */
        FilePtr=_fsopen(Box->imagefile, "rb", SH_DENYNO);
        if(FilePtr==NULL)
            return(TRUE);

        /* restore the image one line at a time */
        for(Vert=Box->top; Vert <= Box->bottom; Vert++)
        {
            fread(ImageBuffer, (size_t)ImageSize(Box->left, Vert, Box->right, Vert), 1, FilePtr);
            blkput(SET, Box->left, Vert, ImageBuffer);
        }

        /* clean-up */
        fclose(FilePtr);
        remove(Box->imagefile);
        Box->imagefile[0]=NULL;
        memset(&Box, 0x00, sizeof(Box));

        return(TRUE);
    }

    return(FALSE);
}

/*
** frees up allocated memory associated with createbox
*/
void DestroyBoxPtr(BOX3D *Box)
{
    if(Box!=NULL)
    {
        farfree(Box);
        Box=NULL;
    }
}

/*
** create a border frame within a box. coordinates are relative
** to the left/top of the box which the border is being created in.
** the title bar area if exists is taken into account.
*/
int Bump3D(BOX3D *box, int left, int top, int right, int bottom)
{
    /* adjust to coordinates when a title bar exists */
    if(box->title)
        top+=TITLEBAR;

    /* check coordinates to make sure they will fit */
    if(left < box->left || right > box->right-1 ||
        top < box->top || bottom > box->bottom-1)
        return(FALSE);

    /* create the 3d frame effect */
    drwbox(SET, box->highlight, left+1, top+1, right, bottom);
    drwbox(SET, box->highlight, left, top, right, bottom);
    drwbox(SET, box->shadow, left, top, right-1, bottom-1);

    return(TRUE);
}

/*
** create a border frame with a label within a box. coordinates are relative
** to the left/top of the box which the border is being created in.
** the title bar area if exists is taken into account.
*/
int Bump3DTitle(BOX3D *box, int left, int top, int right, int bottom, int titlecolor, char *title, int is3d)
{
    if(Bump3D(box, left, top, right, bottom))
    {
        /* adjust to coordinates when a title bar exists */
        if(box->title)
            top+=TITLEBAR;

        /* check length of string */
        if((right-left) <= ((strlen(title)-2) * CHARSPACE))
            return(FALSE);

        /* Remove the area of the frame where the title will be displayed */
        drwline(SET, box->fill, left+BORDERSPACE+CHARSPACE,
                                        top,
                                        left+BORDERSPACE+CHARSPACE + ((strlen(title)+2)*CHARSPACE),
                                        top);
        drwline(SET, box->fill, left+BORDERSPACE+CHARSPACE,
                                        top+1,
                                        left+BORDERSPACE+CHARSPACE+((strlen(title)+2)*CHARSPACE),
                                        top+1);

        /* 3d style forces text to white with black shadow */
        if(is3d)
        {
            drwstring(SET, BLACK, box->fill, title,
                                         left+BORDERSPACE + (CHARSPACE*2)+1,
                                         top - (BORDERSPACE-1)+1);
            drwstring(OR, WHITE, BLACK, title,
                                              left+BORDERSPACE + (CHARSPACE*2),
                                              top - (BORDERSPACE-1));
        }
        else
            drwstring(SET, titlecolor, box->fill, title,
                                                left+BORDERSPACE + (CHARSPACE*2)+1,
                                                top - (BORDERSPACE-1)+1);
    }
    else
        return(FALSE);

    return(TRUE);
}

/*
** BoxText allows text to be placed in a pseudo column/row within a box.
**
** The dot parameters specify how many dots down/right to adjust the text
** for. Valid entries are between 0-CHARSPACE.
**
** If the word wrap option is on, text strings that are longer than the box
** will be wrapped to the next line. Otherwise, the string will be truncated
** to fit on one line.
**
** \FE Function returns TRUE success.
** \FE Function returns FALSE when invalid coordinates are given.
*/

int BoxText(BOX3D *box, int column, char dotc, int row, char dotr, int textcolor, char *text, int wordwrap)
{
    char    *headptr;
    char    *tailptr;
    char    *tempbuffer;
    char    *outputtext;

    int    tempcol;
    int    stringlen;
    int    templen;

    /* don't print it if it doesn't exist */
    if(strlen(text)==0)
        return(FALSE);

    /* initialize the variables */
    tempbuffer=malloc(512);
    outputtext=malloc(512);
    if(tempbuffer==NULL || outputtext==NULL)
    {    free(outputtext);
        free(tempbuffer);
        return(FALSE);
    }
    stringlen=strlen(text);
    tempcol=column;
    headptr=text;
    tailptr=text+stringlen;
    memset(tempbuffer, 0x00, 512);
    memset(outputtext, 0x00, 512);


    /* Calculate pseudo column within box */
    column=(column * CHARSPACE) + box->left + BORDERSPACE + dotc;

    /* adjust row if a titlebar exists */
    if(box->title)
        row=((row * CHARROW)+TITLEBAR+box->top) + BORDERSPACE + dotr;
    else
        row=(row * CHARROW)+box->top + BORDERSPACE + dotr;

    if(row > box->bottom-(CHARROW))
    {
        free(outputtext);
        free(tempbuffer);
        return(FALSE);
    }

    /* check dot parameters */
    if(dotc > CHARROW)
        dotc=CHARROW;
    if(dotr > CHARROW)
        dotr=CHARROW;

    /* truncate any text that will not fit in the box */
    if(!wordwrap)
    {
        while(column + ((stringlen=strlen(text))*CHARSPACE) > box->right)
            text[stringlen-1]=NULL;
        strcpy(outputtext, text);
    }
    else
    {
        if(column + (stringlen*CHARSPACE) > box->right-BORDERSPACE)
        {
            /* find where to start truncate */
            while(headptr!=tailptr)
            {
                stringlen=strlen(headptr);

                /* find one line */
                while(column + (stringlen*CHARSPACE) > box->right-BORDERSPACE)
                    stringlen--;

                /* search for a [SPACE] if line needs to be truncated */
                templen=stringlen;
                if(column + (stringlen*CHARSPACE) >= box->right-(BORDERSPACE * 2))
                {
                    while(headptr[stringlen]!=0x20 && stringlen!=0)
                        stringlen--;

                    /* if no space was found and column not at 0, move line down */
                    if(stringlen==0 && tempcol!=0)
                    {
                        column=box->left+BORDERSPACE+dotc;
                        strncpy(tempbuffer, headptr, templen);
                        tempbuffer[templen]=0x00;
                        headptr+=templen;
                    }

                    /* if no space was found and column is at 0, truncate at end */
                    else if(stringlen==0 && tempcol==0)
                    {
                        stringlen=templen;
                        headptr+=templen;
                        strncpy(tempbuffer, headptr, templen);
                        tempbuffer[templen]=0x00;
                    }
                    else
                    {
                        strncpy(tempbuffer, headptr, stringlen);
                        tempbuffer[stringlen]=0x00;
                        headptr+=stringlen+1;
                    }
                }
                else
                {
                    /* no truncating left to do */
                    strncpy(tempbuffer, headptr, stringlen);
                    tempbuffer[stringlen]=0x00;
                    headptr+=stringlen;
                }

                drwstring(SET, textcolor, box->fill, tempbuffer, column, row);
                column=box->left+BORDERSPACE;
                row+=CHARROW;
                if(row > box->bottom-(CHARROW))
                    break;
                /* check for bottom of box */

            }
            /* Done truncating */
            free(outputtext);
            free(tempbuffer);
            return(TRUE);
        }
        else
            strcpy(outputtext, text);
    }

    if(column < box->right-BORDERSPACE && row < box->bottom-CHARROW)
    {
        drwstring(SET, textcolor, box->fill, outputtext, column, row);
        free(outputtext);
        free(tempbuffer);
        return(TRUE);
    }

    free(outputtext);
    free(tempbuffer);
    return(FALSE);
}

/*
** This will allow the user to enter text into a box at a specified
** column and row using any text color they want. The *textedit
** variable will hold the users entry. The length of the text is
** is specified in int len. There are various flags that can be OR'd
** together to allow a little more diversity in the type of
** characters the user can enter. There is also a PASSWORD option
** that when enabled, echos back the '*' (asterik) character.
**
** \FE Flags
**      ALPHA         A-Z || a-z
**   DIGIT         0-9
**   LOWER         a-z
**   UPPER         A-Z
**   PRINT         0x20 - 0x7E
**   EXTENDED     0x7F - 0xFF
**   PWORD         display * instead of character
**   NOWAIT         returns even when no character is ready
**
** \FE Returns
** ASCII characters (0x20 - 0xFF) return thier value.
** Extended key presses (F1-F12, ALT-key) return hi-byte=0xFF lo-byte=val
**
** \FE Remarks
** Full function editing is enabled (cut & paste are disabled if the
** PASSWORD flag is set). Left and Right arrow key presses, Home, End,
** Insert and Delete do not return. Page Up, Page Down, Up and Down
** arrow return thier normal extended values. The cut and paste buffer
** is set at 80 characters (including the NULL terminator). This function
** was not meant to be a full-blown word processor.
*/
unsigned int BoxEdit(BOX3D *box, int color, int col, int row, char *textedit, int len, int flag)
{
    int    i;                            // temp interger
    int    k=0;                        // character buffer
    int    kb;                        // BIOS keyboard status
    int    lastkey=0;                // storage of last extended keypress
    int    mark=FALSE;                // text marking flag
    int    bufinuse=FALSE;        // is anything in the cut & paste buffer
    int    flash=0;                    // determine status of cursor
    int    delayf=1000;            // cursor blink dealy
    int    cdelay=0;                // increment to test when to blink
    int    validflag;                // check for a valid character key press
    int    functionkey;            // stores all extended keypresses
    int    left;                        // left coordinate in pixels
    int    top;                        // top coordinate in pixels
    int    insert=0;                // insert flag
    int    keystatus;                // SHIFT/CONTROL flag
    int    cursorpos;                // cursor position
    char    blockpos[2]={0xFF,
                             0xFF};    // text marking positions [0]=start [1]=stop

    char    cursor[68]={0x07, 0x00, 0x01, 0x00, // cursor image
                            0xFF, 0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF, 0xFF,
                            0xFF,    0xFF, 0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF,
                            0xFF, 0xFF,    0xFF, 0xFF, 0xFF, 0xFF,    0xFF, 0xFF,
                            0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                            0xFF, 0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF, 0xFF,
                            0xFF, 0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF, 0xFF,
                            0xFF, 0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF, 0xFF,
                            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

    char    highlight[68]={0x07, 0x00, 0x07, 0x00, // highlight image
                                0xFF, 0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF, 0xFF,
                                0xFF,    0xFF, 0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF,
                                0xFF, 0xFF,    0xFF, 0xFF, 0xFF, 0xFF,    0xFF, 0xFF,
                                0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                                0xFF, 0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF, 0xFF,
                                0xFF, 0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF, 0xFF,
                                0xFF, 0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF, 0xFF,
                                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

    unsigned int retvalue;    // return value of function

    cursorpos=strlen(textedit);

    /* return on C/R, TAB, ESC or function key press (F1-F12) */
    /* also returns on any extended key press (ie; ALT-X)     */
    while(k!=13 && k!=9 && k!=27 && k!=-1)
    {
        /* place text in the box */
        if((flag & PWORD)==PWORD)
        {
            /* if the password flag is set, echo back an asterik. */
            if(!mark)
                if(strlen(textedit)!=0)
                    BoxText(box, col+strlen(textedit)-1, 0, row, 0, color, "*", FALSE);
        }
        else
        {
            /* display the text as it should be seen. */
            if(!mark)
                BoxText(box, col, 0, row, 0, color, textedit, FALSE);
        }

        /* get a keypress                                                             */
        /* if the NOWAIT flag is set, the cursor will appear in the "on"    */
        /* state at all times.                                                            */
        while(!kbhit())
        {
            left=box->left + ((col+cursorpos) * CHARSPACE);
            if(left > box->right-(CHARSPACE*2))
                len=cursorpos;

            if(insert)
                top=box->top+(row*(CHARROW));
            else
                top=box->top+(row*(CHARROW))+CHARROW;

            if(cdelay++ >= delayf)
            {
                /* flash cursor while waiting. */
                blkput(XOR, left+4, top+4, (RasterBlock *)cursor);
                flash^=1;
                cdelay=0;
            }

            /* if NOWAIT flag is set, remove the cursor and return. */
            if((flag & NOWAIT)==NOWAIT)
            {
                if(flash)
                    blkput(XOR, left+4, top+4, (RasterBlock *)cursor);
                return(FALSE);
            }
        }

        /* get a keypress    */
        k=getch();
        validflag=0;

        /* check for valid characters against the f parameter. */
        if((flag & ALPHA)==ALPHA)
        {
            if(isalpha(k))
                validflag=1;
        }
        if((flag & DIGIT)==DIGIT)
        {
            if(isdigit(k))
                validflag=1;
        }
        if((flag & LOWER)==LOWER)
        {
            if(islower(k))
                validflag=1;
        }
        if((flag & UPPER)==UPPER)
        {
            if(isupper(k))
                validflag=1;
        }
        if((flag & PRINT)==PRINT)
        {
            if(isprint(k))
                validflag=1;
        }
        if((flag & EXTENDED)==EXTENDED)
        {
            if(k >= 0x20)
                validflag=1;
        }

        /* if the character was acceptable, append it to the string and    */
        /* display it.                                                                        */
        if(validflag)
        {
            /* remove cursor from the screen. */
            if(flash)
            {
                blkput(XOR, left+4, top+4, (RasterBlock *)cursor);
                flash^=1;
            }

            /* remove highlight */
            if(mark)
            {
                for(i=0; i<(blockpos[1]-blockpos[0])+1; i++)
                {
                    blkput(XOR, box->left+((col+blockpos[0]+i)*CHARSPACE)+4,
                                    box->top+(row*CHARROW)+4,
                                    (RasterBlock *)highlight);
                }
                blockpos[0]=0xFF;
                blockpos[1]=0xFF;
                keystatus=0;
                mark=FALSE;
            }

            /* check to make sure only the specified amount of characters    */
            /* get added to the string.                                                */
            if((strlen(textedit))!=len || (cursorpos!=len && !insert))
            {
                if(!insert)
                {
                    /* replace mode. put a character anywhere */
                    if(cursorpos!=strlen(textedit))
                        BoxText(box, col+cursorpos, 0, row, 0, box->fill, "\DB", FALSE);
                    if(cursorpos==strlen(textedit))
                        textedit[cursorpos+1]=NULL;
                    textedit[cursorpos]=k;
                    cursorpos++;
                }
                else
                {
                    /* insert mode. add character into string */
                    if(cursorpos==strlen(textedit))
                    {
                        textedit[cursorpos+1]=NULL;
                        textedit[cursorpos]=k;
                        if(cursorpos+1!=len)
                            cursorpos++;
                    }
                    else
                    {  /* remove any trailing characters */
                        BoxText(box, col+cursorpos, 0, row, 0, box->fill, textedit+cursorpos, FALSE);
                        movmem(textedit+cursorpos, textedit+cursorpos+1, strlen(textedit+cursorpos)+1);
                        textedit[cursorpos]=k;
                        if(cursorpos+1!=len)
                            cursorpos++;
                    }
                }
            }
            else
            {
                /* make some noise */
                sound(500);
                delay(200);
                nosound();
            }
        }

        /* look for extended keypress */
        if(!k)
        {
            k=getch();
            if(lastkey==0)
                lastkey=k;

            /* get SHIFT and CONTROL status (respectively) */
            kb=bioskey(2);
            if(((kb & 0x01) || (kb & 0x02) ? 1 : 0))
            {
                keystatus=1;
                if(k!=lastkey && k!=82 && k!=83)
                {
                    /* remove highlight */
                    if(mark)
                    {
                        for(i=0; i<(blockpos[1]-blockpos[0])+1; i++)
                        {
                            blkput(XOR, box->left+((col+blockpos[0]+i)*CHARSPACE)+4,
                                            box->top+(row*CHARROW)+4,
                                            (RasterBlock *)highlight);
                        }
                        blockpos[0]=0xFF;
                        blockpos[1]=0xFF;
                    }
                }
            }
            else if(((kb & 0x04) ? 1 : 0))
            {
                keystatus=2;

                if(k!=lastkey && k!=146 && k!=147)
                {
                    /* remove highlight */
                    if(mark)
                    {
                        for(i=0; i<(blockpos[1]-blockpos[0])+1; i++)
                        {
                            blkput(XOR, box->left+((col+blockpos[0]+i)*CHARSPACE)+4,
                                            box->top+(row*CHARROW)+4,
                                            (RasterBlock *)highlight);
                        }
                        blockpos[0]=0xFF;
                        blockpos[1]=0xFF;
                    }
                }
            }
            else
            {  /* keys to ignore: */
                /* delete             */
                /* insert             */
                if(k!=83 && k!=82)
                {
                    /* remove highlight */
                    if(mark)
                    {
                        for(i=0; i<(blockpos[1]-blockpos[0])+1; i++)
                        {
                            blkput(XOR, box->left+((col+blockpos[0]+i)*CHARSPACE)+4,
                                            box->top+(row*CHARROW)+4,
                                            (RasterBlock *)highlight);
                        }
                        blockpos[0]=0xFF;
                        blockpos[1]=0xFF;
                    }
                    keystatus=0;
                    mark=FALSE;
                }
            }

            /* Control-Insert, copy marked text to buffer */
            if(keystatus==2 && k==146)
            {
                if(mark)
                {
                    strncpy(cutpastebuf, textedit+blockpos[0], (blockpos[1]-blockpos[0])+1);
                    cutpastebuf[blockpos[1]-blockpos[0]+1]=NULL;
                    bufinuse=TRUE;
                }
            }
            /* Control-Delete or Delete, remove marked block, no copy */
            else if((keystatus==2 && k==147))
            {
                if(mark)
                {
                    /* Remove cursor */
                    if(flash)
                    {
                        blkput(XOR, left+4, top+4, (RasterBlock *)cursor);
                        flash^=1;
                    }

                    /* remove highlight */
                    for(i=0; i<(blockpos[1]-blockpos[0])+1; i++)
                    {
                        blkput(XOR, box->left+((col+blockpos[0]+i)*CHARSPACE)+4,
                                        box->top+(row*CHARROW)+4,
                                        (RasterBlock *)highlight);
                    }

                    /* remove text */
                    BoxText(box, col, 0, row, 0, box->fill, textedit, FALSE);

                    /* move text data to new location */
                    movmem(textedit+blockpos[1]+1, textedit+blockpos[0],
                             strlen(textedit)-(blockpos[1]-blockpos[0])+1);

                    /* reset variables */
                    mark=FALSE;
                    if(cursorpos!=blockpos[0])
                        cursorpos-=(blockpos[1]-blockpos[0])+1;
                    blockpos[0]=0xFF;
                    blockpos[1]=0xFF;
                }
            }
            /* insert pressed */
            else if(k==82)
            {
                /* remove cursor */
                if(flash)
                {
                    blkput(XOR, left+4, top+4, (RasterBlock *)cursor);
                    flash^=1;
                }

                if(keystatus==1 && bufinuse)
                {
                    if(mark)
                    {
                        /* remove highlight */
                        for(i=0; i<(blockpos[1]-blockpos[0])+1; i++)
                        {
                            blkput(XOR, box->left+((col+blockpos[0]+i)*CHARSPACE)+4,
                                        box->top+(row*CHARROW)+4,
                                        (RasterBlock *)highlight);
                        }

                        /* remove text */
                        BoxText(box, col, 0, row, 0, box->fill, textedit, FALSE);

                        /* move text data to new location */
                        movmem(textedit+blockpos[1]+1, textedit+blockpos[0],
                                 strlen(textedit)-(blockpos[1]-blockpos[0])+1);

                        /* reset variables */
                        mark=FALSE;
                        if(cursorpos!=blockpos[0])
                            cursorpos-=(blockpos[1]-blockpos[0])+1;
                        blockpos[0]=0xFF;
                        blockpos[1]=0xFF;
                    }

                    /* remove text */
                    BoxText(box, col, 0, row, 0, box->fill, textedit, FALSE);

                    /* paste Text */
                    for(i=0; i<strlen(cutpastebuf); i++)
                    {
                        /* Check for length overrun */
                        if(box->left+(col*CHARSPACE)+((strlen(textedit)+1)*CHARSPACE) >
                            box->right-(CHARSPACE*1))
                        {
                            len=strlen(textedit)-1;
                            break;
                        }
                        else
                        {
                            /* onsert text */
                            movmem(textedit+cursorpos+i,
                                     textedit+cursorpos+i+1,
                                     strlen(textedit+cursorpos+i)+1);
                            textedit[cursorpos+i]=cutpastebuf[i];
                        }
                    }

                    /* highlight new text */

                    keystatus=0;
                }
                else
                {
                    /* toggle cursor */
                    insert^=1;
                    if(insert)
                        cursor[2]=0x07;
                    else
                        cursor[2]=0x01;
                }
            }

            /* left arrow */
            else if(k==75)
            {
                if(cursorpos)
                {
                    /* remove cursor */
                    if(flash)
                    {
                        blkput(XOR, left+4, top+4, (RasterBlock *)cursor);
                        flash^=1;
                    }

                    cursorpos--;

                    /* mark text for cut & paste */
                    if(keystatus==1)
                    {
                        blkput(XOR, left+4-CHARSPACE, box->top+(row*CHARROW)+4, (RasterBlock *)highlight);
                        if(blockpos[0]==0xFF)
                        {
                            blockpos[1]=cursorpos;
                            blockpos[0]=cursorpos;
                        }
                        else
                            blockpos[0]=cursorpos;
                        mark=TRUE;
                    }
                }
            }
            /* right Arrow */
            else if(k==77)
            {
                if(cursorpos<strlen(textedit))
                {
                    /* remove cursor */
                    if(flash)
                    {
                        blkput(XOR, left+4, top+4, (RasterBlock *)cursor);
                        flash^=1;
                    }

                    /* mark text for cut & paste */
                    if(keystatus==1)
                    {
                        blkput(XOR, left+4, box->top+(row*CHARROW)+4, (RasterBlock *)highlight);
                        if(blockpos[0]==0xFF)
                        {
                            blockpos[0]=cursorpos;
                            blockpos[1]=cursorpos;
                        }
                        else
                            blockpos[1]=cursorpos;
                        mark=TRUE;
                    }

                    cursorpos++;
                }
            }
            /* delete key */
            else if(k==83)
            {
                if(strlen(textedit)!=0 && cursorpos!=strlen(textedit) && !mark && keystatus==0)
                {
                    /* remove cursor */
                    if(flash)
                    {
                        blkput(XOR, left+4, top+4, (RasterBlock *)cursor);
                        flash^=1;
                    }

                    /* clear trailing text */
                    BoxText(box, col+cursorpos, 0, row, 0, box->fill, textedit+cursorpos, FALSE);
                    movmem(textedit+cursorpos+1, textedit+cursorpos, strlen(textedit+cursorpos+1));
                    textedit[strlen(textedit)-1]=NULL;
                }
                else if(mark && keystatus==1)
                {
                    /* remove cursor */
                    if(flash)
                    {
                        blkput(XOR, left+4, top+4, (RasterBlock *)cursor);
                        flash^=1;
                    }

                    /* copy marked text into copy/paste buffer, remove text */
                    strncpy(cutpastebuf, textedit+blockpos[0], (blockpos[1]-blockpos[0])+1);
                    cutpastebuf[blockpos[1]-blockpos[0]+1]=NULL;
                    bufinuse=TRUE;

                    /* remove highlight */
                    for(i=0; i<(blockpos[1]-blockpos[0])+1; i++)
                    {
                        blkput(XOR, box->left+((col+blockpos[0]+i)*CHARSPACE)+4,
                                    box->top+(row*CHARROW)+4,
                                    (RasterBlock *)highlight);
                    }

                    /* remove text */
                    BoxText(box, col, 0, row, 0, box->fill, textedit, FALSE);

                    /* move text data to new location */
                    movmem(textedit+blockpos[1]+1, textedit+blockpos[0],
                             strlen(textedit)-(blockpos[1]-blockpos[0])+1);

                    /* reset variables */
                    if(cursorpos!=blockpos[0])
                        cursorpos-=(blockpos[1]-blockpos[0])+1;
                    blockpos[0]=0xFF;
                    blockpos[1]=0xFF;
                    mark=FALSE;
                    keystatus=0;
                }
            }
            /* end key */
            else if(k==79)
            {
                if(strlen(textedit)!=0 && cursorpos!=strlen(textedit))
                {
                    /* remove cursor */
                    if(flash)
                    {
                        blkput(XOR, left+4, top+4, (RasterBlock *)cursor);
                        flash^=1;
                    }

                    /* mark text for cut & paste */
                    if(keystatus==1)
                    {
                        for(i=cursorpos; i<strlen(textedit); i++)
                        {
                            blkput(XOR, left+4+((i-cursorpos)*CHARSPACE), box->top+(row*CHARROW)+4, (RasterBlock *)highlight);
                            if(blockpos[0]==0xFF)
                            {
                                blockpos[0]=cursorpos;
                                blockpos[1]=strlen(textedit)-1;
                            }
                            else
                                blockpos[1]=strlen(textedit)-1;
                        }
                        mark=TRUE;
                    }

                    cursorpos=strlen(textedit);
                }
            }
            /* home key */
            else if(k==71)
            {
                if(strlen(textedit)!=0 && cursorpos!=0)
                {
                    /* remove cursor */
                    if(flash)
                    {
                        blkput(XOR, left+4, top+4, (RasterBlock *)cursor);
                        flash^=1;
                    }

                    /* mark text for cut & paste */
                    if(keystatus==1)
                    {
                        for(i=cursorpos-1; i>=0; i--)
                        {
                            blkput(XOR, left+4-((i+1)*CHARSPACE), box->top+(row*CHARROW)+4, (RasterBlock *)highlight);
                            if(blockpos[0]==0xFF)
                            {
                                blockpos[1]=cursorpos-1;
                                blockpos[0]=0;
                            }
                            else
                                blockpos[0]=0;
                        }
                        mark=TRUE;
                    }

                    cursorpos=0;
                }
            }
            else
            {
                functionkey=k;
                k=-1;
            }

            lastkey=k;
        }

        /* check for a backspace character */
        if(k==8 && strlen(textedit)!=0 && cursorpos!=0)
        {
            /* remove cursor first */
            if(flash)
            {
                blkput(XOR, left+4, top+4, (RasterBlock *)cursor);
                flash^=1;
            }

            if(mark)
            {
                /* remove highlight */
                for(i=0; i<(blockpos[1]-blockpos[0])+1; i++)
                {
                    blkput(XOR, box->left+((col+blockpos[0]+i)*CHARSPACE)+4,
                                box->top+(row*CHARROW)+4,
                                (RasterBlock *)highlight);
                }
                blockpos[0]=0xFF;
                blockpos[1]=0xFF;
                mark=FALSE;
            }

            /* clear trailing text */
            if(cursorpos!=strlen(textedit))
            {
                BoxText(box, col+cursorpos-1, 0, row, 0, box->fill, textedit+cursorpos-1, FALSE);
                movmem(textedit+cursorpos, textedit+cursorpos-1, strlen(textedit+cursorpos));
                textedit[strlen(textedit)-1]=NULL;
            }
            else
            {
                /* remove last character from the string */
                BoxText(box, col+strlen(textedit)-1, 0, row, 0, box->fill, "\DB", FALSE);
                textedit[strlen(textedit)-1]=NULL;
            }

            /* Track cursor position */
            cursorpos--;
        }

    }
    /* return value is a 2 byte code. If the hi-byte is NULL, the next    */
    /* byte equals a character (0x20 - 0xFF). Else, hi-byte is 0xFF        */
    /* lo-byte equals an extened character (F1-F12, ALT+key).                */
    if(k==-1)
        retvalue=0xFF00 | functionkey;
    else
        retvalue=k;

    /* Remove cursor before returning                                                */
    if(flash)
    {
        blkput(XOR, left+4, top+4, (RasterBlock *)cursor);
        flash^=1;
    }

    return(retvalue);
}

/*
**  Clear the entire contents of a box. If there are any other objects such
**  as a titlebar, effects, text or any overlapping boxes, they will be
**  cleared or clipped with no redraw. This function is mainly used whe
**  working with the BoxEdit function.
*/
void ClrBox(BOX3D *box, int sync)
{
    /* avoid screen flicker... wait for vertical retrace */
    if(sync)
        sdelay(1);

    /* create the "new" box. */
    if(box->title)
        drwfillbox(SET, box->fill, box->left+1, box->top+TITLEBAR+1, box->right-1, box->bottom-1);
    else
        drwfillbox(SET, box->fill, box->left+1, box->top+1, box->right-1, box->bottom-1);
}

/*
** Create a message box to display on the screen.
** Delay sets the number of seconds to display the message for.
** A keypress will override the delay, and a delay set for 0 will
** disable the timer, requiring a keypress before proceeding.
** The *message text can contain up to five newline '\n' characters.
** The color passed should be in the range 0-7
*/
int MessageBox(char color, char *title, char *message, int delay)
{
    BOX3D *messagebox;

    int kp;
    int l;
    int lines;
    int longest;
    int xcentertext;
    int xcharlength;

    char linemessage[5][80];

    time_t first, second;

    l=0;
    lines=0;
    memset(linemessage, 0x00, sizeof(linemessage));
    for(kp=0; kp<strlen(message); kp++)
    {
        if(message[kp]=='\n')
        {
            /* found a new line character. NULL terminate the message        */
            /* line and increment to the next message line.                        */
            linemessage[lines][l]=NULL;
            lines++;

            /* make sure we don't exceed our number of lines. */
            if(lines==5)
            {
                lines--;
                break;
            }

            /* set the character line position back to the begining. */
            l=0;
        }
        else
        {
            /* keep appending the message characters. */
            linemessage[lines][l]=message[kp];
            linemessage[lines][l+1]=NULL;
            l++;
        }
    }

    /* truncate any long lines. */
    kp=0;
    longest=0;
    for(l=0; l<=lines; l++)
    {
        while(strlen(linemessage[l]) > 76)
            linemessage[l][strlen(linemessage[l])-1]=NULL;

        /* get the longest line. */
        if(strlen(linemessage[l]) > kp)
        {
            kp=strlen(linemessage[l]);
            longest=l;
        }
    }

    /* create the message box. */
    messagebox=CreateBox((maxx-((strlen(linemessage[longest]) + 3) * CHARSPACE)) / 2,
                                maxy / 2,
                                maxx-((maxx-((strlen(linemessage[longest]) + 3) * CHARSPACE)) / 2),
                                (maxy / 2) + TITLEBAR + ((lines+1) * CHARROW) + (BORDERSPACE * 2) + BORDERSPACE,
                                (color & 0x07) + 8,
                                color & 0x07,
                                BLACK,
                                TRUE,
                                CENTERED,
                                title,
                                WHITE,
                                BLACK,
                                TRUE,
                                TRUE);
    if(messagebox==NULL)
        return(0xFFFF);

    Bump3D(messagebox,
             messagebox->left+BORDERSPACE,
             messagebox->top+BORDERSPACE,
             messagebox->right-BORDERSPACE,
             messagebox->bottom-BORDERSPACE);

    /* output the message lines. */
    for(l=0; l<=lines; l++)
    {
        xcharlength=(messagebox->right - messagebox->left);
        xcharlength-=(BORDERSPACE *2);
        xcharlength/=CHARSPACE;
        xcentertext=xcharlength - strlen(linemessage[l]);
        xcentertext/=2;
        BoxText(messagebox,
                  xcentertext,
                  ((xcharlength % 2)==(strlen(linemessage[l]) % 2)) ? 0 : BORDERSPACE,
                  l,
                  BORDERSPACE,
                  WHITE,
                  linemessage[l],
                  FALSE);
    }

    /* activate the delay. */
    if(delay==0)
        kp=getch();
    else
    {
        first=time(NULL);
        second=time(NULL);
        while(!kbhit() && difftime(second, first) < delay)
            second=time(NULL);
        while(kbhit())
            getch();
    }

    /* remove the message box. */
    DestroyBox(messagebox);

    DestroyBoxPtr((BOX3D *)messagebox);

    return(kp);
}
And the freedom to maintain programs from other sites as we see fit...
I still couldn't believe Rochester stayed a mainly Cobol shop for as long as they did...
That's because they hung onto that mainframe until the bitter end.  They had another group of developers that were writing programs for their own facility that were developing in C.  It's only the group that developed for remote facilities that were writing OBOL...
They might have made it out of the tube era but they were still dinosaurs...
ummmmm, you know that OBOL has been updated and is still a language in use today...
I know. One of the groups I work with still have COBOL programmers. Although, they should rename it to BOL, because it's not very COmmon...
I haven't touched any BOL since a couple of Rottenchester's programs made it to the facility here and got converted to C.  In fact, there isn't much programming that I do anymore anyway.  A little Python when I was at Doxee, and some bits of JS when there isn't a plugin that will do what I need...