                     A FILE NAME SELECTION ROUTINE

                            Matthew Probert
                           Servile  Software


This routine allows the user to type in a file name, or to enter a 
name with a wildcard and then select a file name from a scrolling list 
of matching files in the current directory, and to change directory 
and select a file name from another directory.

The code is PC specific, and uses some Borland C windowing commands. 
Microsoft C and some other C compilers have similar functions.

-----------------------------Cut Here-----------------------------
/*
    Enter a filename in a window
    if a wildcard is included in the entry
    allow selection from a list of entries
*/


#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <dos.h>
#include <dir.h>
#include <ctype.h>

#define DISPLAY_ATTRIBUTE    14            /* Attribute to display text in */
#define HILITE_ATTRIBUTE        30            /* Attribute to mark block with */
#define MENU_ATTRIBUTE            23            /* Attribute to display menus */
#define MENU_HILITE            94                /* Attribute to hilite menu option */

char buffer[5000];                /* Block buffer */
char current_dir[80];            /* Current directory name */
char dir_entries[1000][14];
int dir_start;
int dir_row;
int lastone;
int wm;


void AT(int,int);
void BOX(int , int , int , int );
void CLRWINDOW(int, int,int, int, unsigned char);
void DIR_DISPLAY(void);
void DIR_DOWN(void);
void DIR_UP(void);
void GETWIN(int, int, int, int,char *);
int INPUT(char *,unsigned);
void PUTWIN(int, int, int, int,char *);
void SCAN_DIR(char *);
int SELECT_FILE(void);
void WHERE(int *, int *);
void XPUTS(char *,int );


char *GET_FILE_NAME(char *text)
{
    /*
        Display a message and request a file name
        If a wild card is entered the user can select from a window
        of file names, and even change directory.
        Returns the file name, or path to the file name if it is
        in a different directory
    */

    int left;
    int right;
    int key;
    static char rcvd_data[60];
    static char temp[60];
    char path[80];

    getcwd(current_dir,80);

    left = 6;
    right = 73;

    GETWIN(left,9,right,11,buffer);
    CLRWINDOW(left,9,right,11,30);
    BOX(left,9,right,11);

    /*
        Centralise the prompt
    */
    AT(9,40 - strlen(text)/ 2);
    XPUTS(text,30);
    AT(10,left + 2);

    key = INPUT(rcvd_data,60);
    if (key == 27)
        *rcvd_data = 0;
    if (strchr(rcvd_data,'*'))
    {
        for(;;)
        {
            SCAN_DIR(rcvd_data);
            if (SELECT_FILE() == 13)
            {
                if (islower(*dir_entries[dir_start + dir_row]))
                {
                    *temp = 1;
                    break;
                }
                chdir(dir_entries[dir_start + dir_row]);
            }
            else
            {
                *temp = 0;
                break;
            }
        }
        getcwd(path,70);
        chdir(current_dir);
        if (*temp)
        {
            if (strcmp(path,current_dir))
                sprintf(temp,"%s\\%s",path,dir_entries[dir_start + dir_row]);
            else
                strcpy(temp,dir_entries[dir_start + dir_row]);
            PUTWIN(left,9,right,11,buffer);
            return temp;
        }
        else
            *rcvd_data = 0;
    }
    PUTWIN(left,9,right,11,buffer);
    return rcvd_data;
}

void SCAN_DIR(char *fs)
{
    /*
        Scan the current directory, and enter file details in fname[]
    */

    int done;
    struct ffblk ffblk;

    lastone = 0;
    dir_start = 0;
    dir_row = 0;

    /*
        First make a parent directory entry if the current directory
        is not "\"
    */
    if (current_dir[3] != '\0')
    {
        sprintf(dir_entries[0],"..");
        lastone++;
    }

    /* Now get sub directory entries */

    done = findfirst("*.",&ffblk,16);

    while (!done)
    {
        if ((strcmp(ffblk.ff_name ,".") != 0) && (strcmp(ffblk.ff_name ,"..") != 0))
        {
            strcpy(dir_entries[lastone],ffblk.ff_name);
            lastone++;

            /* Limit the number of files to 1999 */
            if (lastone > 1999)
                return;
        }
        done = findnext(&ffblk);
    }

    /* Now get files matching filespec */

    done = findfirst(fs,&ffblk,231);

    while (!done)
    {
        if (strcmp(ffblk.ff_name ,".") != 0)
        {
            strcpy(dir_entries[lastone],strlwr(ffblk.ff_name));
            lastone++;
            if (lastone > 1999)
                return;
        }
        done = findnext(&ffblk);
    }
    /*
        Sort the entries into alphabetical order
    */
    qsort(dir_entries,lastone,14,strcmp);
    lastone--;
}

void DIR_DISPLAY()
{
    /*
        Display a window of file names from the array 'dir_entries[]'
        Starting at item 'dir_start'
    */

    int n;


    /* Nothing to display? */
    if (lastone == -1)
        return;

    window(33,8,48,19);
    textattr(MENU_ATTRIBUTE);
    clrscr();

    wm = 11;

    if (wm > lastone)
        wm = lastone;

    for(n = 0; n <= wm; n++)
    {
        gotoxy(2,n + 1);
        cprintf("%s",dir_entries[dir_start + n]);
    }
}

void DIR_HILITE(int attr)
{
    /*
        Highlight the current row when selecting a file name
    */

    if (lastone == -1)
        return;

    textattr(attr);
    gotoxy(2,dir_row + 1);
    cprintf("%s",dir_entries[dir_start + dir_row]);
    textattr(MENU_ATTRIBUTE);
}

int SELECT_FILE()
{
    /*
        A moving bar and scrolling window menu
    */

    int k;
    int left;
    int top;
    int right;
    int bottom;
    static char image[2000];

    left = 31;
    right = 49;
    top = 6;
    bottom = 19;

    GETWIN(left,top,right,bottom,image);
    CLRWINDOW(left,top,right,bottom,30);
    BOX(left,top,right,bottom);

    dir_start = 0;
    dir_row = 0;
    DIR_DISPLAY();

    k = 0;

    for(;;)
    {
        DIR_HILITE(MENU_HILITE);
        window(33,8,48,19);

        if ((k = getch()) == 0)
        {
            k = getch();
            switch(k)
            {
                case 72:DIR_UP();
                        break;

                case 80:DIR_DOWN();
                        break;

                case 73:if (dir_start > wm)
                            dir_start-= wm;
                        else
                            dir_start = 0;
                        DIR_DISPLAY();
                        break;

                case 81:if (dir_start < lastone - wm)
                        {
                            dir_start+= wm;
                            if (dir_start + wm > lastone)
                                dir_start = lastone - wm;
                            DIR_DISPLAY();
                        }
                        break;

                case 71:dir_row = 0;
                        dir_start = 0;
                        DIR_DISPLAY();
                        break;

                case 79:dir_row = wm;
                        dir_start = lastone - wm;
                        if (dir_row > lastone)
                            dir_row = lastone;
                        if (dir_start < 0)
                            dir_start = 0;
                        DIR_DISPLAY();
                        break;
            }
        }
        else
        if (k == 13 || k == 27)
        {
            PUTWIN(left,top,right,bottom,image);
            return(k);
        }
    }
}

void DIR_UP(void)
{
    if (dir_row > 0)
    {
        DIR_HILITE(MENU_ATTRIBUTE);
        dir_row--;
    }
    else
    if (dir_start > 0)
    {
        dir_start--;
        DIR_DISPLAY();
    }
}

void DIR_DOWN(void)
{
    if ((dir_row < wm) && (dir_row < lastone - dir_start))
    {
        DIR_HILITE(MENU_ATTRIBUTE);
        dir_row++;
    }
    else
    if (dir_start < lastone - wm)
    {
        dir_start++;
        DIR_DISPLAY();
    }
}

/*
    Support functions
*/

void BOX(int l, int t, int r, int b)
{
    /*
        Draw a single line box around the described area
    */

    int n;

    char far *video_ptr;

    video_ptr = MK_FP(0xB800,0);

    video_ptr += 160 * t + l * 2;
    *video_ptr++ = '';
    video_ptr++;

    for(n = l + 1; n < r; n++)
    {
        *video_ptr++ = '';
        video_ptr++;
    }
    *video_ptr = '';

    for(n = t + 1; n < b; n++)
    {
        video_ptr = MK_FP(0xB800,0);

        video_ptr += 160 * n + l * 2;
        *video_ptr = '';
        video_ptr = MK_FP(0xB800,0);

        video_ptr += 160 * n + r * 2;
        *video_ptr = '';
    }

    video_ptr = MK_FP(0xB800,0);

    video_ptr += 160 * b + l * 2;
    *video_ptr++ = '';
    video_ptr++;

    for(n = l + 1; n < r; n++)
    {
        *video_ptr++ = '';
        video_ptr++;
    }
    *video_ptr = '';
}

void CLRWINDOW(int x1, int y1,int x2, int y2, unsigned char attrib)
{
    /*
        Clear a text window
    */

    unsigned char width;

    width = y2 - y1 + 1;

    asm mov al , byte ptr width;
    asm mov bh , byte ptr attrib;
    asm mov cl , byte ptr x1;
    asm mov ch , byte ptr y1;
    asm mov dl , byte ptr x2;
    asm mov dh , byte ptr y2;
    asm mov ah , 6;
    asm int 10h;
}

void GETWIN(int left, int top, int right, int bottom, char *buffer)
{
    /*
        Read a text window into a variable
    */

    int oldleft;
    char far *video_ptr;

    video_ptr = MK_FP(0xB800,0);

    while(top <= bottom)
    {
        oldleft = left;
        while(left <= right)
        {
            *buffer++ = *(video_ptr + 160 * top + left * 2);
            *buffer++ = *(video_ptr + 160 * top + left * 2 + 1);
            left++;
        }
        left = oldleft;
        top++;
    }
}

void PUTWIN(int left, int top, int right, int bottom,char *buffer)
{
    /*
        Display a text window from a variable
    */

    int oldleft;
    unsigned char chr;
    unsigned char attr;
    char far *video_ptr;

    video_ptr = MK_FP(0xB800,0);

    while(top <= bottom)
    {
        oldleft = left;
        while(left <= right)
        {
            *(video_ptr + 160 * top + left * 2) = *buffer++;
            *(video_ptr + 160 * top + left * 2 + 1) = *buffer++;
            left++;
        }
        left = oldleft;
        top++;
    }
}

int INPUT(char *text,unsigned length)
{
    /*
        Receive an input string from the operator
        Overtype mode only
        The last string entered is retained unless the first key
        pressed is not a cursor key
    */

    unsigned key_pos;
    int key;
    int start_row;
    int start_col;
    unsigned end;
    char temp[80];
    char *p;
    int first_key;

    /* Locate current text cursor location */
    WHERE(&start_row,&start_col);

    /* Initialise varables */
    first_key = 1;
    key_pos = 0;
    end = strlen(text);
    XPUTS(text,30);
    AT(start_row,start_col);

    /* Loop */
    for(;;)
    {
        key = getch();
        if (key == 0)
        {
            /* Extended key presses */
            key = getch();

            if (key == 79)
            {
                first_key = 0;
                while(key_pos < end)
                    key_pos++;
            }
            else
            if (key == 71)
            {
                first_key = 0;
                key_pos = 0;
            }
            else
            if ((key == 75) && (key_pos > 0))
            {
                first_key = 0;
                key_pos--;
            }
            else
            if ((key == 77) && (key_pos < end))
            {
                first_key = 0;
                key_pos++;
            }
            else
            if (key == 83)
            {
                first_key = 0;
                p = text + key_pos;
                while(*(p+1))
                {
                    *p = *(p+1);
                    p++;
                }
                *p = 32;
                if (end > 0)
                    end--;
                AT(start_row,start_col);
                strcat(text," ");
                XPUTS(text,30);
                text[strlen(text) - 1] = 0;
                if ((key_pos > 0) && (key_pos == end))
                    key_pos--;
            }
            AT(start_row,start_col+key_pos);
        }
        else
        if (key == 13 || key == 27)
            break;
        else
        if ((key == 8) && (key_pos > 0))
        {
            first_key = 0;
            end--;
            key_pos--;
            text[key_pos--] = '\0';
            strcpy(temp,text);
            p = text + key_pos + 2;
            strcat(temp,p);
            strcpy(text,temp);
            AT(start_row,start_col);
            sprintf(temp,"%-*.*s",length,length,text);
            XPUTS(temp,30);
            key_pos++;
            AT(start_row,start_col + key_pos);
        }
        else
        if ((key > 31 || key == 9) && (key_pos < length))
        {
            if (first_key)
            {
                /* If first key is alpha-numeric, delete old string */
                *text = 0;
                end = 0;
            }
            text[key_pos++] = (char)key;
            if (key_pos > end)
            {
                end++;
                text[end] = '\0';
            }
            AT(start_row,start_col);
            sprintf(temp,"%-*.*s",length,length,text);
            XPUTS(temp,30);
            AT(start_row,start_col + key_pos);
            first_key = 0;
        }
        else
        if ((key > 31 || key == 9) && (key_pos == length))
        {
            text[end] = 0;
            return 13;
        }
    }
    text[end] = '\0';
    return key;
}

void AT(int row, int col)
{
    /*
        Position the text cursor on page 0
    */
    asm mov dh , byte ptr row;
    asm mov dl , byte ptr col;
    asm mov bh , 0;
    asm mov ah , 2;
    asm int 10h;
}

void WHERE(int *row, int *col)
{
    /*
        Return the cursor position on page 0
    */

    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 XPUTS(char *text,int attribute)
{
    /*
        Display a string directly to colour screen RAM page zero
        setting the display attributes at the same time
    */

    int r;
    int c;
    int offset;
    char far *video_ptr;

    /* Get current cursor position */
    WHERE(&r,&c);

    /* Calculate offset to cursor position */
    offset = r * 160 + c * 2;

    /* Make far pointer to appropiate part of RAM */
    video_ptr = MK_FP(0xB800,offset);
    while(*text)
    {
        *video_ptr++ = *text++;
        *video_ptr++ = attribute;
    }
}

/*
    Demonstrate the functions
*/

void main()
{
    char buffer[100];

    strcpy(buffer,GET_FILE_NAME("Enter File Name:"));
    printf("\nReturned: '%s'\n",buffer);
}
-----------------------------Cut Here-----------------------------

