/*
 * FILEDLG.C
 *
 * File selection popup dialog box routines. Released to the public domain.
 * Attention: Routines are not reentrant.
 *
 * Originally written on Dec. 1997 by Frank Adam
 *
 * Improvements Oct. 1998 and Nov. 1998 by Frank Adam
 *  - Added file sorting
 *  - Added filtering
 *  - Added dynamic allocation
 *  - Changes wrt porting
 *
 * Modifications Apr. 1999 by Tobias Ernst
 * - Moved code to it's own module
 * - Changed dialog box layout
 * - Better support for long file names
 * - Made all colors configurable
 * - Users can now enter a full path in the "file/mask" entry box. If it
 *   is a file name, it will be used. If it is a path with a mask following,
 *   we will change to that path and then use the mask.
 * - Support the "outfile" keyword as default message box content.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

#ifdef __TURBOC__
#include <dir.h>
#endif

#ifdef __DJGPP__
#include <unistd.h>
#endif

#ifdef __CYGWIN__
#include <unistd.h>
#endif

#ifdef UNIX 
#include <unistd.h>
#endif

#ifdef __MINGW32__
#define chdir _chdir
#endif

#ifdef __IBMC__
#define chdir _chdir
#define getcwd _getcwd
#endif

#ifdef __WATCOMC__
#include <sys/types.h>
#include <direct.h>
#endif

#include "addr.h"
#include "config.h"
#include "nedit.h"
#include "msged.h"
#include "winsys.h"
#include "menu.h"
#include "dialogs.h"
#include "memextra.h"
#include "strextra.h"
#include "main.h"
#include "help.h"
#include "keys.h"
#include "dirute.h"
#include "mprotos.h"
#include "unused.h"
#include "mctype.h"

/* #include <smapi/msgapi.h> 
   commented out on 2004-08-24 by tobi
   seems to be not needed, but causes compilation problems under cygwin
   if nobody needs this within the next few months, these lines
   should be deleted altogether*/

struct UFILES
{
    int attrib;
    char *name;
};

struct CURFILE
{
    int attrib;
    char name[FILENAME_MAX + 1];
};

#define DRVATTR -1
#define MAXDRIVES 26

static char avdrives[MAXDRIVES + 1];
static char FileFilter[FILENAME_MAX + 1];
static struct CURFILE curfile;
static struct UFILES **files;
static int fmax = 0;             /* maximum files allocated for at any time */
static WND *IEDhCurr, *IEDhWnd;  /* pointers to current and previous windows */


/* dialog box geometry info */

const int fdp_masklength   = 29,
          fdp_maskx        = 9,
          fdp_masky        = 1,
          fdp_listx  = 9,
          fdp_listy  = 4,
          fdp_listx2 = 29,
          fdp_listy2 = 19,
          fdp_xsize        = 40,
          fdp_ysize        = 21,
          fdp_curdirlength = 29,
          fdp_curdirx      = 9,
          fdp_curdiry      = 2,
          fdp_listlabelx   = 1,
          fdp_listlabely   = 4,
          fdp_masklabelx   = 1,
          fdp_masklabely   = 1,
          fdp_curdirlabelx = 1,
          fdp_curdirlabely = 2;


/*
 * Allocates the file array.
 * To be called with 0 for initial, or fmax + X for subsequent reallocs
 */

static int AllocFiles(size_t request)
{
    int i;
    struct UFILES **tmp = files;

    if(!request)
    {
        files = xmalloc(sizeof(*files) * 100);
        if(NULL != files)
        {
            for(i = 0; i < 100; i++)
            {
		files[i] = xmalloc(sizeof (struct UFILES));
                files[i]->name = NULL;
                if(NULL == files[i]) break;
            }
            fmax = i - 1;
	}
    }
    else
    {
	files = xrealloc(files,sizeof(*files) * (fmax + request));

	if(NULL == files)
        {
            files = tmp; /* No more mem  */
        }
	else
	{
            for (i = fmax; i < request + fmax; i++)
            {
                files[i] = xmalloc(sizeof(struct UFILES));
                files[i]->name = NULL;
                if(NULL == files[i]) break;
            }
            fmax = i - 1;
        }
    }
    return fmax;
}

/* Called on exit */
/* redundant "if"s for debugging, can be removed when working OK */
static void KillFiles(void)
{
    int i;

    if (files != NULL)
    {
        for (i = 0; i < fmax; i++)
        {
            if (files[i] != NULL)
            {
                if (files[i]->name != NULL)
                    xfree(files[i]->name);
                xfree(files[i]);
            }
        }
    }
}


/*
 * Sort the files..
 * This gets a bit complicated, we want the drives at top, that's done
 * outside the sort, the directories straight after, that's done with the
 * attributes, and the files on the bottom. BUT, numeric filenames will
 * precede upper cases, hence the rather overdone comparison below.
 */

static int FileSort(const void *a, const void *b)
{
    struct UFILES* a1 = *((struct UFILES**) a);
    struct UFILES* b1 = *((struct UFILES**) b);

    if(a1->attrib & DIR_DIRECT || b1->attrib & DIR_DIRECT)
    {
        if(a1->attrib & DIR_DIRECT && !(b1->attrib & DIR_DIRECT)) return -1;
        else if(b1->attrib & DIR_DIRECT && !(a1->attrib & DIR_DIRECT)) return 1;
        /* else return strcmp(a1->name,b1->name);  */
    }

    if(m_isdigit(*a1->name) && !m_isdigit(*b1->name)) return 1;
    else if (m_isdigit(*b1->name) && !m_isdigit(*a1->name))  return -1;

    return stricmp(a1->name,b1->name);
}

/* Allocate and add a dirname, return true/false */
static int AddDir(int fcount, const char *dirname)
{
    size_t l = strlen(dirname);
    files[fcount]->name = xmalloc(l + 3);
    if(NULL == files[fcount]->name) return 0;

    strcpy(files[fcount]->name,"[");
    strcpy(files[fcount]->name + 1,dirname);
    strcat(files[fcount]->name + 1 + l,"]");

    files[fcount]->attrib = DIR_DIRECT;

    return 1;
}

/* Gets the directories...truely :-) */
static int GetDirs(char *curdir, int start)
{
    int count = start, done;
    char sdir[FILENAME_MAX + 1];
    struct _dta f;

    strcpy(sdir,curdir);
#ifdef MSDOS
    strcat(sdir,"*.*");
#else
    strcat(sdir,"*");
#endif

    done = dir_findfirst(sdir,DIR_DIRECT,&f);

    while(!done)
    {
        if(f.attrib & DIR_DIRECT && *f.name != '.')
        {
            if(!AddDir(count,f.name)) break;
            files[count]->attrib = f.attrib;
            count++;
	}

        if(count >= fmax) /* out of space ? Try to alloc more */
        {
            if(!AllocFiles(50)) break;
            if(count >= fmax) break; /* test again to be sure ? */
	}

        done = dir_findnext(&f);
    }

    return count;
}

/*
 * Shows the current file filter, called when apropriate.
 * Otherwise poor senile user just won't remember it. I didn't. :-)
 */

static void ShowFileFilter(void)
{
    WndFillField(fdp_maskx, fdp_masky, fdp_masklength + 1, ' ', cm[DL_ENRM]);
    WndPrintf(fdp_maskx, fdp_masky, cm[DL_ENRM], "%s", FileFilter);
}

/*
 * Show the current directory.
 */

static void ShowCurDir(char *curdir)
{
    char cp[FILENAME_MAX + 1];
    int i, j;
    size_t l;

    l = strlen(curdir);
    if (l > fdp_curdirlength)
    {
        strcpy(cp, "...");
        j = 3;
        i = l - (fdp_curdirlength - 3);
    }
    else
    {
        i = j = 0;
    }

    for (; curdir[i]; i++, j++)
    {
        if (curdir[i] == '/' && drive_letters)
            cp[j] = '\\';
        else
            cp[j] = curdir[i];
    }
    cp[j] = '\0';

    WndFillField(fdp_curdirx, fdp_curdiry, fdp_curdirlength + 1, ' ',
                 cm[DL_WTXT]);
    WndPrintf(fdp_curdirx, fdp_curdiry, cm[DL_WTXT], "%s", cp);
}


/*
 * Retrieves and builds the file list.
 * Curdir is passed in with trailing slash.
 */

int GetFiles(char *curdir)
{
    struct _dta f;
    int done, count = 0, drvflag = 0, drvcount = 0;
    char sdir[FILENAME_MAX + 1]; /* MAXPATH */

    strcpy(sdir,curdir);

    if(NULL == FileFilter || !*FileFilter) /* let's not search for nothing. */
    {
#ifdef MSDOS
	strcpy(FileFilter,"*.*");
#else
        strcpy(FileFilter,"*");
#endif
    }
    strcat(sdir, FileFilter);  /* slash to be fixed at call */

    ShowFileFilter();  /* Show the filter here, the search could be Nil */
                       /* So this should avoid some confusion. */

    if(strlen(curdir) > ((drive_letters) ? 3 : 1)) /* then must be a sub-dir */
    {
        AddDir(count,"..");
        files[count++]->attrib = DIR_DIRECT;
    }
    else if (drive_letters && curdir[0] && curdir[1] == ':')
    {
	while(avdrives[drvflag] != '\0')
	{
            if(avdrives[drvflag] != toupper(*curdir))  /* ..except this one */
            {
                files[count]->name = xmalloc(sizeof(char) * 6);
                if(NULL == files[count]->name) return -1;

                strcpy(files[count]->name,"");
                /* We want drives up top, see below */

                files[count++]->attrib = DRVATTR;
            }
            drvflag++;
        }
    }

    count = GetDirs(curdir,count);
    /* Retrieve all dirs regardless of filter */


    /* Ok, now get the files */
    done = dir_findfirst(sdir, DIR_DIRECT | DIR_NORMAL | DIR_ARCHVD |
                         DIR_HIDDEN | DIR_SYSTEM | DIR_READON, &f);

    while(!done)
    {
        if(!(f.attrib & DIR_DIRECT))
        {

            files[count]->name = strdup(f.name);
            if(NULL == files[count]->name) break;
            files[count]->attrib = f.attrib;
            count++;
        }

        if(count >= fmax) /* out of space ? Try to alloc more */
        {
            if(!AllocFiles(50)) break;  /* Oh well, that's all then */
            if(count >= fmax) break;
            /* test again in case we just got more pointers
               but no actual file structs. */
	}
        done = dir_findnext(&f);
    }

    /* Sort them, this places all empty strings at top of list(ie: drives) */
    /* Capitals (ie: dirs) will be next, followed by the files */
    qsort((void*)files, count, sizeof(files[0]), FileSort);

    if(drive_letters && drvflag) /* Now we can add the drives */
    {
        drvflag = drvcount = 0;
        /* NOTE: drvflag is now used for something else */

        while(avdrives[drvflag] != '\0')
        {
            if(avdrives[drvflag] != toupper(*curdir))  /* ..except this one */
            {
                strcpy(files[drvcount]->name,"< :\\>");
                files[drvcount]->name[1] = avdrives[drvflag];
                files[drvcount++]->attrib = DRVATTR;
            }
            drvflag++;
        }
    }

    return count - 1;
}

/*
 * TrimEdge
 * Used in showfile to remove leading and trailing edges from dirs and drives
 */
static void TrimEdge(char *retdir, int attrib)
{
    char *p = retdir;
    size_t l = strlen(p);

    if(attrib == DRVATTR || attrib & DIR_DIRECT)
    {
        p[l-1] = '\0';
        memmove(p, p + 1, l);
    }
}

/*
 * Show the files..
 * This handles most of the user i/o in conjunction with the caller
 * may not be the best method of doing things, but this is how it developed
 * i can certainly live with it.
 */
int ShowFiles(int maxfiles, struct CURFILE *retdir, int *current)
{
    int top = fdp_listy + 1, depth = fdp_listy2 - fdp_listy - 2, key = 0, i;
    int fnlen = fdp_listx2 - fdp_listx - 4;
    int curtop, prnflag = 0, inppos, drop = 0, done;
    int nattr = cm[DL_ENRM], hattr = cm[DL_ESEL];
    char temp[FILENAME_MAX + 1];
    static int cur;
    int directzap = 1; /* directly go to the enter field? */

    /* Init things */
    curtop = *current;
    if(!curtop) cur = 0;
    WndPrintf(fdp_listlabelx, fdp_listlabely, cm[DL_WTXT], "Select:");
    WndPrintf(fdp_masklabelx, fdp_masklabely, cm[DL_WTXT], "File:");
    WndPrintf(fdp_curdirlabelx, fdp_curdirlabely, cm[DL_WTXT], "CurDir:");
    /* WndPrintf(6, top-1, cm[DL_WTXT] | _BLINK, ":"); */
    WndClear(fdp_listx + 1, top, fdp_listx2 - 1, top + depth, nattr);
    for(i = curtop; i <= maxfiles && i <= (curtop + depth); i++)
    {
        WndPrintf(fdp_listx + 1, i + top, nattr, " %-*.*s ",
                  fnlen, fnlen, files[i]->name);
    }

    /* Ok, wait for user */
    while(1)
    {
        if (!(directzap && retdir->name[0]))
        {
            WndPrintf(fdp_listx + 1, top + (cur - curtop), hattr,
                  ">%-*.*s<", fnlen, fnlen, files[cur]->name);
            key = GetKey();
            WndPrintf(fdp_listx + 1, top + (cur - curtop), nattr,
                  " %-*.*s ", fnlen, fnlen, files[cur]->name);
            directzap = 0;
        }
        else
        {
            key = Key_Tab;
            strcpy(temp, retdir->name);
        }

        switch(key)
        {
	case Key_F1:
            if (ST->helpfile != NULL)
            {
                DoHelp(5);
            }
            break;

	case Key_Tab:
            /* This drops us to the file/filter box
             * User can enter a valid filename or filter.
             * Esc will take us back to the flist area.
             * The input is parsed elsewhere
             */
            if (!directzap)
            {
                *temp = '\0';
                inppos = 0;
            }
            else
            {
                directzap = 0;
                inppos = strlen(temp);
            }
            done = 0;
            /*WndPrintf(6,top-1,cm[DL_WTXT],":");
              WndPrintf(13,19,cm[DL_WTXT] | _BLINK,":"); */

            while(!done)     /* PITA or bug,but getline assumes edit
                                is done if cursor goes passed the end */
            {
                drop = WndGetLine(fdp_maskx,fdp_masky,fdp_masklength,temp,nattr,
                                  &inppos,0,0,1,NULL);
                switch(drop)
                {
                case Key_Esc:
                    drop = 0;
                    done = 1 ;
                    /*WndPrintf(13,19,cm[DL_WTXT],":");
                      WndPrintf(6,top-1,cm[DL_WTXT] | _BLINK,":"); */
                    break;

                case Key_Ent:
                    if(!*temp || *temp == '\t') drop = 0;
                    done = 1; /* Also traps accidental TAB */
                    break;

                default:
                    drop = 0;
                }
            }
            ShowFileFilter(); /* Refresh the current filter display */
            if(!drop) break;

	case Key_Ent:
            if(!drop)
            {
                strcpy(retdir->name,files[cur]->name);
                retdir->attrib = files[cur]->attrib;
                *current = curtop;
                TrimEdge(retdir->name,retdir->attrib);
               return key;
            }
            else
            {
                drop = 0;
                strcpy(retdir->name,temp);
                retdir->attrib = 0;
                return 13;
            }

	case Key_Esc:
            return 27;

	case Key_Up:
            if(cur > 0)
            {
                if(cur > curtop)
                    cur--;
                else
                {
                    cur--;
                    curtop--;
                    prnflag = 1;
                }
            }
            break;

	case Key_Dwn:
            if(cur < maxfiles)
            {
                if(cur < curtop + depth)
                {
                    cur++;
                }
                else
                {
                    cur++;
                    curtop++;
                    prnflag = 1;
                }
            }
            break;

	case Key_Home:
            curtop = 0; cur = 0;
            prnflag = 1;
            break;

	case Key_End:
            curtop = maxfiles - depth;
            if(curtop < 0)
            {
                curtop = 0;
            }
            cur = curtop + depth;
            if (cur > maxfiles)
            {
                cur = maxfiles;
            }
            prnflag = 1;
            break;

	case Key_PgUp:
            if(curtop == 0 || maxfiles < depth)
            {
                break;
            }
            if(curtop < depth)
            {
                curtop = 0;
                cur = 0;
            }
            else
            {
                curtop -= depth;
                cur = curtop;
            }
            prnflag = 1;
            break;

	case Key_PgDn:
            if(curtop + depth > maxfiles)
            {
                break;
            }
            curtop += depth;
            cur = curtop;
            prnflag = 1;
            break;

	default:
            if(m_isalnum(key))
            {
                if(cur + depth < maxfiles)
                {
                    i = cur + 1;
                }
                else
                {
                    i = 0;
                }

                for(; i <= maxfiles; i++)
                {
                    if(toupper(key) == toupper(*files[i]->name))
                    {
                        curtop = cur = i;
                        prnflag = 1;
                        break;
                    }
                }
            }


        } /* end switch */

        if(prnflag) /* This is set if a display refresh is required */
        {
            prnflag = 0;
            WndClear(fdp_listx + 1, top, fdp_listx2 - 1, top + depth,
                     cm[DL_WTXT]);

            for(i = curtop; i <= curtop + depth && i <= maxfiles; i++)
            {
                WndPrintf(fdp_listx + 1, top + (i - curtop), nattr,
                          " %-*.*s ", fnlen, fnlen, files[i]->name);
            }
        }
    } /* end while */
}


/*
 * Retrieves availabale drives
 */

static void GetAvDrives(void)
{
    char *c;
    int i;

    if (drive_letters)
    {
        c = dir_getdrivelist();

	for(i = 0; c && c[i] && i < MAXDRIVES;i++)
	{
            avdrives[i] = (char)toupper((int)(c[i]));
        }
        avdrives[i] = '\0';
        xfree(c);
    }
    else
    {
        avdrives[0] = '\0';
    }
}

/*
 * Normalize path to forward slashes
 */
static void FixPath(char *path)
{
    char *p = path;
    while(*p)
    {
        if(*p == '\\') *p = '/';
        p++;
    }
}


/*
 * Add a slash to directory path if necessary
 */

static void AddDirSlash(char *path)
{
    size_t l = strlen(path);

    if (l)
    {
        if (path[l - 1] != '/' && path[l - 1] != '\\')
        {
            path[l] = '/';
            path[l + 1] = '\0';
        }
    }
}


static void ImpExpDlgInit(const char *title)
{
    IEDhCurr = WndTop();

    IEDhWnd = WndPopUp(fdp_xsize, fdp_ysize , DBDR | SHADOW,
                       cm[DL_BTXT], cm[DL_WTXT]);
    WndBox(fdp_listx, fdp_listy,
           fdp_listx2, fdp_listy2, cm[DL_BTXT], SBDR);
    WndCurr(IEDhWnd);
    WndTitle(title, cm[DL_WTXT]);
    WndFillField(fdp_maskx,fdp_masky, fdp_masklength, ' ', cm[DL_ENRM]);

    TTCurSet(0);
}

static void ImpExpDlgDone(void)
{
    WndClose(IEDhWnd);
    WndCurr(IEDhCurr);
    TTCurSet(1);
}

/*
 * A getcwd routine that always adds the drive letter.
 * Unfortunately, some getcwd implementations include the drive letter,
 * while others don't ...
 */

static char *dlgetcwd(char *storehere, int buflen)
{
    getcwd(storehere, buflen);
    if (drive_letters)
    {
        if (storehere[0] == '\0' || storehere[1] != ':')
        {
            memmove(storehere + 2, storehere, buflen - 3);
            storehere[buflen - 1] = '\0';
            storehere[0] = (char)(dir_getdrive() + 'A');
            storehere[1] = ':';
        }
    }
    return storehere;
}


/*
 * Analyse user input if the input was a complete path with filename.
 * Also used for parsing the default settings.
 */

static int process_fileinput(char *retpath, char *curdir)
{
    char *sp;
    int savech;
    int retval = 0;

    FixPath(curfile.name);

    /* split in path and file */
    sp = strrchr(curfile.name, '/');
    if (sp != NULL)
    {
        /* user entered a path. */

        if (sp == curfile.name || (drive_letters && *(sp - 1) == ':'))
        {
            /* special treatment for root */
            savech = sp[1];
            sp[1] = '\0';
        }
        else
        {
            savech = -1;
            *sp = '\0';
        }
        if (!chdir(curfile.name))
        {
            /* change dir succeeded -
               change drive letters as well */

            if (drive_letters)
            {
                if (curfile.name[1] == ':')
                {
                    dir_setdrive(toupper(*curfile.name) - 'A');
                }
            }

            /* the path existed. good. use it. */
            dlgetcwd(curdir,FILENAME_MAX);
            AddDirSlash(curdir);

            sp++;
            if (savech != -1)
                *sp = (char) savech;
        }
        else
        {
            sp = NULL;
            fprintf(stderr, "\a");
            fflush(stderr);
            curfile.name[0]='\0';
            /* path does not exist. beep and do nothing */
        }
    }
    else
    {
        sp = curfile.name;
    }

    /* Now we have evaluted the path component in the user
       entry. Now let's see about the rest. It could be a file
       mask, a subdirectory name, or a file name. */

    if (sp)
    {
        if(strchr(sp, '?') || strchr(sp, '*'))
        {
            /* it is a file mask */
            strcpy(FileFilter, sp);
            curfile.name[0]='\0';
        }
        else if (!chdir(sp))
        {
            /* it is another subdirectory */
            dlgetcwd(curdir,FILENAME_MAX);
            AddDirSlash(curdir);
            curfile.name[0]='\0';
        }
        else
        {
            /* it is a file name that the user wishes to use */
            retval = 1;
            strcpy(retpath, curdir);
            strcat(retpath, sp);
            if (sp != curfile.name)
            {
                memmove(curfile.name, sp, strlen(sp) + 1);
            }
        }
    }
    else
    {
        curfile.name[0]='\0';
    }

    return retval;
}


/*
 * The main routine
 */

int FileDialog(char *retpath, const char *title)
{
    int key = 0,max,cur = 0,retval=0;
    char curdir[FILENAME_MAX + 1];
    char homedir[FILENAME_MAX + 1], *sp;

    int homedisk = (drive_letters) ? dir_getdrive() : 0;

    if(AllocFiles(0) <= 0)      /* init the file array */
        return -1;

    GetAvDrives();

    dlgetcwd(homedir, FILENAME_MAX); /* save home location */

    strcpy(curdir,homedir);
    if (!(*retpath))
    {
        curfile.name[0]='\0';
    }
    else
    {
                                /* in case retpath does not include a path */
        strcpy(curfile.name, retpath);
        process_fileinput(retpath, curdir);
    }


    AddDirSlash(curdir);
    ImpExpDlgInit(title);

    max = GetFiles(curdir);

    while(key != 27)
    {
        FixPath(curdir);

        ShowCurDir(curdir);

        key = ShowFiles(max,&curfile,&cur); /* Go get user input */

        if(key == Key_Ent)
        {
            if(curfile.attrib == DRVATTR)  /* User asking for drive */
            {
                dir_setdrive(toupper(*curfile.name) - 'A');
                chdir("/");
                sprintf(curdir,"%c:/",*curfile.name);
                curfile.name[0]='\0';
            }

            else if(curfile.attrib & DIR_DIRECT)   /* User asking for dir */
            {
                if(*curfile.name != '.') /* build a new path */
                {
                    dlgetcwd(curdir,FILENAME_MAX);
                    AddDirSlash(curdir);
                    strcat(curdir,curfile.name);  /* Add new dirname.. */
                    strcat(curdir,"/");    /* ..and a trailer */
                    chdir(curdir);
                    dlgetcwd(curdir,FILENAME_MAX);
                    AddDirSlash(curdir);
                    curfile.name[0] = '\0';
                }
                else  /* ".."  bit easier */
                {
                    sp = strrchr(curdir, '/');
                    if (sp != NULL)
                    {
                        *sp = '\0';
                        sp = strrchr(curdir, '/');
                        if (sp != NULL)
                        {
                            if (sp == curdir)
                                sp[1] = '\0';
                            else
                                *sp = '\0';
                            chdir(curdir);
                            dlgetcwd(curdir,FILENAME_MAX);
                            AddDirSlash(curdir);
                            curfile.name[0] = '\0';
                        }
                    }
                }
            } /* end else if dirattrib */

            /* user entered a file or filter, or selected a file. */
            else if (*curfile.name)
            {
                if (process_fileinput(retpath, curdir))
                {
                    retval = 1; /* it is a valid file */
                    break;
                }
            }

            /* If we get here something changed so re-scan */
            max = GetFiles(curdir);
            cur = 0;
	} /* end if Key_Ent */

	else   /* Key must be 27 we're done */
	{
            retval = 0;
            *retpath = '\0';
            *curfile.name = '\0';
            break;
        }
    }  /* end while */

    KillFiles();
    ImpExpDlgDone();

    /* Restore startup locations */
    if (drive_letters)
        dir_setdrive(homedisk);

    chdir(homedir);
    return retval;
}


syntax highlighted by Code2HTML, v. 0.9.1