/*  037  23-May-87  ovwin.c

        Copyright (c) 1987 by Blue Sky Software.  All rights reserved.
*/

#include <setjmp.h>
#include <dos.h>
#include "ov.h"
#include "overr.h"
#include "direct.h"
#include "strmem.h"

#define V_bar (0xba)
#define H_bar (0xcd)

int diridx = 0;                        /* # dir names when showall */
char **dirlst = NULL;                  /* ptr to dir name ptrs when showall */

static int win_update;                         /* NZ if refresh_screen update */
static unsigned char inwin = 0;                /* # active info windows */
static unsigned char numwin = 1;               /* # active windows */
static WINDOW *curwin = NULL, *winlis = NULL, *winp;

static char *tdir;                             /* target dir */
static char *tname;                            /* target name */
static FILE_ENT holdf;                         /* save file_ent */

static char *nomem = "Insufficient memory for another window, no window created!";
static char *noaccess = "Unable to access specified directory: ";

extern WINDOW cw;
extern int winupdate;
extern FILE_ENT files[];
extern unsigned dataseg;
extern jmp_buf back_to_main;
extern unsigned char anyshowall;

char far *malloc_f();
int ALTCALL scanwindows(), ALTCALL win_switch();
int addfile_ent(), delfile_ent(), refresh_window();
char *strrchr(), *strchr(), *parsepath(), *findir();
int ALTCALL wincpy(WINDOW *, WINDOW *), ALTCALL disp_empty_msg(int);
int ALTCALL savefiles(char far *, int), ALTCALL restorefiles(char far *, int);

/******************************************************************************
 **                         W I N _ O P E N                                  **
 *****************************************************************************/

win_open() {           /* open another file name display window */

   register WINDOW *wp;

   /* make sure the current window is large enough to split */

   if (cw.wrows < 6)
      show_error(0,WIN_2_SMALL,1,"Current window is too small to open another");

   /* allocate memory for the new window structure */

   if ((wp = (WINDOW *) malloc(sizeof(WINDOW))) == NULL)
      show_error(0,NO_MEM,1,nomem);

   wincpy(wp,&cw);             /* initialize new window via current window */

   /* allocate memory to store files[] data */

   if ((wp->save_files = malloc_f(MAX_FILES * sizeof(FILE_ENT))) == NULL) {
      free((char *)wp);
      show_error(0,NO_MEM,1,nomem);
   }

   /*  if there is only one window open so far, create the window structure
       and files[] save area to store the current window stuff */

   if (numwin == 1) {
      curwin = (WINDOW *) malloc(sizeof(WINDOW));
      cw.save_files = malloc_f(MAX_FILES * sizeof(FILE_ENT));
      if (curwin == NULL || cw.save_files == NULL) {
         free((char *)wp);
         if (curwin) {
            free((char *)curwin);
            curwin = NULL;
         }
         show_error(0,NO_MEM,1,nomem);
      }
      cw.prev = cw.next = winlis = curwin;
   }

   savefiles(cw.save_files,cw.nfiles); /* save current window's files[] data */

   /* link the new window just after the current window */

   wincpy(curwin,&cw);
   wp->next = curwin->next;
   wp->prev = curwin;
   wp->prev->next = wp;
   wp->next->prev = wp;
   wincpy(&cw,curwin);

   /* adjust the current window and new window display sizes */

   wp->wrows = cw.wrows / 2;           /* new is at most 1/2 of current */
   cw.wrows = cw.wrows - wp->wrows;    /* current keeps whats left */
   wp->fwrow = cw.fwrow + cw.wrows;    /* new start at end of current */
   cw.ndrows -= wp->wrows;             /* all new rows came from name disp */
   wp->fnrow = wp->fwrow + 1;          /* one overhead row for dir name */
   wp->ndrows = wp->wrows - 1;

   /* adjust the top window if it was the only one and it didn't already
      have a header line */

   if (numwin == 1 && !cw.showall) {
      cw.fnrow++;                         /* need a line to display window */
      cw.ndrows--;                        /*   directory line */
      insert_line(cw.fwrow+1,cw.wrows-1); /* scroll file info down a line */
      disp_dirname();                     /* disp the dir name */
   }

   /* adjust old window if current item is no longer visible and turn off
      the file pointer in the old window */

   if (!on_screen(cw.curidx)) {        /* adjust/redisplay window */

      adjust_window();                 /*   if current item no longer */
      update_window(0);                /*   displayed */

   } else              /* not redisplaying window, turn off highlighted ptr */

      if (cw.nfiles)                      /* turn off file ptr in old window */
         fp_off(cw.curidx);
      else                                /* or de-highlight empty dir msg */
         disp_empty_msg(0);

   /* make the new window the current one */

   wincpy(curwin,&cw);                 /* save the old current one */
   wincpy(&cw,wp);                     /* new one becomes current */
   curwin = wp;                        /* remember who it is */

   numwin++;                           /* one more window than there was */

   if (cw.info_display)                /* if info display is active, there */
      infocnt(1);                      /*   is now 1 more info window active */

   /* only one window can be in showall mode */

   if (cw.showall) {                   /* did the old window have showall? */
      cw.showall = 0;                  /* yes, turn off on this one */
      getfiles();                      /* reread current dir only */
      update_header();                 /* display current dir header info */
   }

   /* display the file data in the new window */

   adjust_window();
   update_window(1);

}


/******************************************************************************
                            W I N _ C L O S E
 *****************************************************************************/

win_close() {          /* close the current window */

   int fwrowadj;
   register WINDOW *wp;

   if (numwin == 1)            /* nothing to do if only one window */
      return;

   /* determine the window adjustment fudge factor, 1 extra line is available
      if only one window will remain and that window is not showall */

   fwrowadj = (numwin == 2 && (!anyshowall || cw.showall)) ? 0 : 1;

   /* adjust the next or prior window to take up the closing windows space
      on the screen.  Always pick the next window unless current is the
      last one displyed */

   if ((wp = cw.next) != winlis) {             /* next = winlis if last */

      wp->fwrow = cw.fwrow;                    /* adj nxt to take over */

   } else              /* closing last window on screen */

      wp = cw.prev;                            /* prev is current to be */

   wp->wrows += cw.wrows;              /* it has this many more rows */
   wp->fnrow = wp->fwrow + fwrowadj;   /*   name display rows */
   wp->ndrows = wp->wrows - fwrowadj;

   cw.next->prev = cw.prev;            /* delink the current (closing) */
   cw.prev->next = cw.next;            /* windows block from window list */

   if (curwin == winlis)               /* keep track of new top window if */
      winlis = wp;                     /* old top is being closed */

   if (cw.showall)                     /* turn off showall mode if this */
      showoff();                       /*   window had it on */

   if (cw.info_display)                /* one less info window if this wind */
      infocnt(-1);                     /*   had info display active */

   free_f(cw.save_files);              /* free the cur win's  files[] area */
   free((char *)curwin);               /* free the cur/old win's block */

   /* make the next (or prior) window current, restore its files */

   wincpy(&cw,curwin = wp);
   restorefiles(cw.save_files,cw.nfiles);

   numwin--;                           /* one less window now */

   /* when there is only one window, don't keep the block and files[]
      save area overhead */

   if (numwin == 1) {
      free((char *)curwin);
      free_f(cw.save_files);
      curwin = winlis = NULL;
      cw.save_files = (char far *) NULL;
   }

   update_header();            /* make volume, dir, file, tag info correct */

   adjust_window();            /* adjust the display */
   update_window(1);

   /* switch to the window's directory */

   if (change_dir(cw.dirbuf) != 0)
      show_error(SHOW_DOS,0,1,noaccess);
}


/******************************************************************************
                            W I N _ E X P A N D
 *****************************************************************************/

win_expand() {         /* expand current window to full screen */

   int i;
   register WINDOW *wp, *np;

   if (numwin == 1)            /* nothing to do if only one window */
      return;

   /* there will only be one window left, free up all memory blocks */

   for (i == numwin, wp = winlis; i; i--) {
      np = wp->next;
      free_f(wp->save_files);
      free((char *)wp);
      wp = np;
   }

   numwin = 1;                 /* set counters/pointer to 1 window status */
   curwin = winlis = NULL;

   if (anyshowall && !cw.showall)      /* turn off showall mode if it was */
      showoff();                       /*   active in another window */

   infocnt(cw.info_display ? -(inwin-1) : -inwin); /* at most 1 info win left */

   /* adjust to full screen */

   cw.fwrow = cw.fnrow = FIRST_NROW + cw.info_display;
   cw.wrows = cw.ndrows = NAME_ROWS - cw.info_display;

   if (cw.showall) {           /* showall always has a header */
      cw.fnrow++;
      cw.ndrows--;
   }

   adjust_window();            /* redisplay the window with new size */
   update_window(1);

}


/******************************************************************************
 **                         W I N _ N E X T                                  **
 *****************************************************************************/

win_next() {           /* switch to the next window */

   if (numwin == 1)            /* nothing to do if only one window */
      return;

   win_switch(curwin->next);   /* switch to next window */
}


/******************************************************************************
                            W I N _ P R E V
 *****************************************************************************/

win_prev() {           /* switch to the previous window */

   if (numwin == 1)            /* nothing to do if only one window */
      return;

   win_switch(curwin->prev);   /* switch to previous window */
}


/******************************************************************************
                            W I N _ S W I T C H
 *****************************************************************************/

static int ALTCALL
win_switch(newp)       /* switch to a new window */
register WINDOW *newp;
{
   savefiles(cw.save_files,cw.nfiles); /* save current window's files[] data */

   if (cw.nfiles)                      /* deselect current item in widow */
      fp_off(cw.curidx);
   else                                /* or de-highlight empty dir msg */
      disp_empty_msg(0);

   wincpy(curwin,&cw);                 /* switch to new window */
   wincpy(&cw,curwin = newp);

   restorefiles(cw.save_files,cw.nfiles); /* get new windows files[] entries */

   if (cw.nfiles)                      /* select current item in new window */
      fp_on(cw.curidx);
   else                                /* or highlight empty dir msg */
      disp_empty_msg(1);

   if (change_dir(cw.dirbuf) != 0)     /* switch to the window's directory */
      show_error(SHOW_DOS,0,1,noaccess);

   update_header();               /* make volume, dir, file, tag info correct */
}


/*****************************************************************************
                          A D D 2 W I N D O W S
 *****************************************************************************/

add2windows(todir,tofn,fp)     /* add file to any windows showing dest dir */
FILE_ENT *fp;
char *todir, *tofn;
{
   tdir = Strdup(todir);       /* save dir and fn in var's for addfile_ent */
   tname = Strdup(tofn);

   holdf = *fp;                /* save file_ent 'cause files[] is changed */
   holdf.flags &= ~TAGGED;     /* we don't want the tagged flag */

   scanwindows(addfile_ent);   /* add the file_ent to all matching windows */

   free(tdir);                 /* local strings alloc'd because callers tend */
   free(tname);                /* to use strings in files[] which is swapped */
}


/*****************************************************************************
                          D E L F R O M W I N S
 *****************************************************************************/

delfromwins(fromdir,fromfn)  /* delete file from all windows showing dest dir */
char *fromdir, *fromfn;
{

   tdir = Strdup(fromdir);     /* save target dir and name in var's */
   tname = Strdup(fromfn);     /*   for delfile_ent */

   scanwindows(delfile_ent);   /* delete the file_ent from all windows */

   free(tdir);                 /* local strings alloc'd because callers tend */
   free(tname);                /* to use strings in files[] which is swapped */
}


/****************************************************************************
                          A D D F I L E _ E N T
 ****************************************************************************/

static int
addfile_ent() {        /* add a FILE_ENT to target windows */

   register int i;
   register FILE_ENT *tfp;

   /* if the current window displays the target dir or the target drive
      in showall mode, add the file ent to it */

   if (stricmp(cw.dirbuf,tdir) == 0 || (cw.showall && *cw.dirbuf == *tdir)) {

      /* don't add the file if it doesn't match the selection criteria */

      if ((cw.selatrs & holdf.flags) != holdf.flags ||
          (*cw.mask && (cw.maskcmp != match_name(holdf.name,cw.mask))))
         return;

      if (numwin > 1)                       /* make sure files[] is ok */
         restorefiles(cw.save_files,cw.nfiles);

      /* see if there is an existing file by that name in the target dir */

      for (i = 0, tfp = files; i < cw.nfiles; i++, tfp++)
          if (stricmp(tname,tfp->name) == 0 && stricmp(tdir,tfp->dirp) == 0)
             break;

      if (i < cw.nfiles) {          /* back out info for an existing  */
         delent(tfp);               /* file by the same name          */
         packfiles();               /* pack files[] now, not later    */
         if (i < cw.curidx)         /* adjust current file pointer if */
            cw.curidx--;            /* deleted file before current    */
      }

      /* modify holding file entry to its final form */

      strncpy(holdf.name,tname,sizeof(holdf.name));        /* file name */
      holdf.dirp = cw.showall ? findir(tdir) : cw.dirbuf;  /* file's dir */
      holdf.index = cw.nfiles+1;                           /* a guess */

      /* add file to files[] if there is room */

      if (cw.nfiles < MAX_FILES) {

         /* since the files may be sorted by something other than name (say
            date for example) we need to scan files[] again to find where to
            insert the new entry - I used to just sort files[] again but qsort
            is way to slow when files[] is already almost sorted */

         for (i = cw.nfiles, tfp = files; i; i--, tfp++)
             if ((*cw.sortfunc)(&holdf,tfp) < 0)
                break;

         /* i > 0 if entry needs to be inserted, i = 0 if at end */

         if (i)
            memcpy((char *)(tfp+1),(char *)tfp,i*sizeof(FILE_ENT));

         *tfp = holdf;                 /* finally, add entry */
         cw.nfiles++;                  /* there is one more file now */
         cw.num_files++;
         cw.files_size += tfp->size;   /* taking this much more space */
         cw.updated = W_DISP;          /* win needs redisplay (not packing) */
         winupdate++;                  /* some window needs redisplay */

         if (tfp < &files[cw.curidx])  /* bump current file pointer if added */
            cw.curidx++;               /* file is before current file        */

         if (numwin > 1)
            savefiles(cw.save_files,cw.nfiles);
      }
   }
}


/****************************************************************************
                          D E L F I L E _ E N T
 ****************************************************************************/

static int
delfile_ent() {        /* delete a FILE_ENT from target windows */

   register int i;
   register FILE_ENT *tfp;

   /* if the current window displays the target dir or the target drive
      in showall mode, delete the file ent */

   if (stricmp(cw.dirbuf,tdir) == 0 || (cw.showall && *cw.dirbuf == *tdir)) {

      if (numwin > 1)                       /* make sure files[] is ok */
         restorefiles(cw.save_files,cw.nfiles);

      /* see if there is an existing file by that name in the target dir */

      for (i = 0, tfp = files; i < cw.nfiles; i++, tfp++)
          if (stricmp(tname,tfp->name) == 0 && stricmp(tdir,tfp->dirp) == 0)
             break;

      if (i < cw.nfiles) {          /* back out info for an existing */
         delent(tfp);               /* file by the same name         */
         winupdate++;               /* window needs redisplay        */
         cw.updated |= W_PACK;      /* files[] needs to be packed    */
         if (i < cw.curidx)         /* move file pointer if deleted  */
            cw.curidx--;            /* file is before current        */
         if (numwin > 1)
            savefiles(cw.save_files,cw.nfiles);
      }
   }
}


/*****************************************************************************
                                D E L E N T
 *****************************************************************************/

delent(fp)             /* remove an entry from files[] */
register FILE_ENT *fp;
{
   /* Note: this routine changes cw.num_files, but it doesn't change
      cw.nfiles - this is because the routine packfiles which should
      be called shortly needs the old value of cw.nfiles */

   cw.num_files--;                     /* one fewer file */
   cw.files_size -= fp->size;          /* that much space not used */
   if (fp->flags & TAGGED) {           /* was file tagged? */
      cw.num_tagged--;                 /* one less tagged file */
      cw.tag_size -= fp->size;         /* this space not tagged now */
   }
   *fp->name = '\0';                   /* mark this entry as deleted */
}


/****************************************************************************
                          S C A N W I N D O W S
 ****************************************************************************/

static int ALTCALL
scanwindows(func)      /* scan windows, call func for each one */
int (*func)();
{
   int i;
   register WINDOW *wp;

   /* if there is a list of windows, start with the 1st; switch if not there */

   if (numwin > 1) {
      wincpy(curwin,&cw);                      /* save current window if > 1 */
      savefiles(cw.save_files,cw.nfiles);
      if (curwin != winlis) {                  /* temp switch to top window */
         wincpy(&cw,winlis);
      }
   }

   /* Note: only the files for the original window are saved and restored,
      callers func should restore/savefiles if it needs to */

   for (i = numwin, wp = winlis; i; i--) {     /* check each file window */

      winp = wp;               /* let func know which window it is */

      (*func)();               /* invoke callers func with this window */

      if (numwin > 1) {        /* advance to next window if there is one */
         wincpy(wp,&cw);
         wincpy(&cw,wp = cw.next);
      }
   }

   if (numwin > 1) {           /* restore the current window if > 1 */
      wincpy(&cw,curwin);
      restorefiles(cw.save_files,cw.nfiles);
   }
}


/******************************************************************************
 **                             R E N E W                                    **
 *****************************************************************************/

renew() {              /* renew the file display */

   getcwd(cw.dirbuf,MAX_PATHLEN);        /* reinit drive/dir info incase */
   initdrive(*cw.dirbuf);                /*   it changed somehow */

   getfiles();                         /* reread the directory */
   setup_file_scr();                   /* display the static screen image */
   update_header();                    /* update header info */
   refresh_screen(0);                  /* redisplay all file data */
}


/******************************************************************************
                        R E N E W _ W I N D O W
 *****************************************************************************/

renew_window() {       /* renew the current window display */

   getfiles();                         /* reload the files[] structure */
   adjust_window();                    /* resize window data */
   update_header();                    /* update the header  */
   update_window(1);                   /* and the window data */
}


/******************************************************************************
                          R E F R E S H _ S C R E E N
 *****************************************************************************/

refresh_screen(wup)    /* (re)initialize the total file data display */
int wup;
{
   win_update = wup;          /* save wup in static for refresh_window */

   if (inwin && wup == 0)     /* display the info header if needed */
      infohead();

   scanwindows(refresh_window);        /* redisplay each window */
}

/*****************************************************************************
                        R E F R E S H _ W I N D O W
 *****************************************************************************/

static int
refresh_window() {     /* refresh one window - called by scanwindows */

   if (numwin > 1)
      restorefiles(cw.save_files,cw.nfiles);

   if (win_update && cw.updated) {     /* is this a window update call? */
      if (cw.updated & W_PACK)
         packfiles();
      if (numwin > 1)
         savefiles(cw.save_files,cw.nfiles);
   }

   /* redisplay this window if not a win_update call or win_update call and
      this window has been modified */

   if (!win_update || cw.updated) {
      adjust_window();                 /* calculate display parameters */
      update_window(winp == curwin);   /* update display window */
      cw.updated = 0;                  /* doesn't need to be updated again */
   }
}


/******************************************************************************
                    U P D A T E _ V O L _ S T A T S
 ******************************************************************************/

update_vol_stats() {   /* get and display volume statistics */

   getvolsiz(*cw.dirbuf,&cw.drivep->vol_size,&cw.drivep->vol_free,
             &cw.drivep->clustersiz);
   disp_vol_stats();
}


/******************************************************************************
                        U P D A T E _ H E A D E R
 ******************************************************************************/

update_header() {      /* update display header */

   gotorc(VOL_ROW,1);                  /* make sure volume, directory, */
   out_str(cw.drivep->volbuf,11,' ');  /* file, tagged info is correct */

   if (!cw.showall) {                  /* display the current dir name */
      gotorc(VOL_ROW,PATH_COL+1);      /*   but if showall is in effect */
      out_str(cw.dirbuf,65,' ');       /*   its done somewhere else */
   }

   disp_vol_stats();
   disp_file_stats();

   gotorc(MASK_ROW,MASK_COL-1);        /* display the selection mask */
   disp_char(cw.maskcmp ? ' ' : '~');
   out_str(cw.mask,MASK_LEN,' ');

   gotorc(MASK_ROW+1,MASK_COL-1);      /* display the selection attributes */
   disp_attrib(cw.selatrs);
   disp_str(cw.selatrs & DIR ? " D" : " .");
}


/******************************************************************************
                        U P D A T E _ W I N D O W
 *****************************************************************************/

int ALTCALL
update_window(fptr)    /* display a window full of file info */
int fptr;
{
   int col;
   register int i, m;

   if (numwin > 1 || cw.showall)       /* display window header if > 1 */
      disp_dirname();                  /*   window or showall mode */

   /* display a window of file names */

   for (i = 0; i + cw.fnrow < cw.fnrow + cw.ndrows; i++) {

      gotorc(i+cw.fnrow,0);

      if (i < cw.nrows) {
         for (col = 0, m = cw.nbase + i; m < cw.nfiles; col++, m += cw.nrows)
            disp_file(&files[m],(m == cw.curidx && fptr));

         if (col < cw.ncols)   /* try to only clear on rows where less */
            clr_eol();         /* than ncols are displayed */
      } else
         clr_eol();
   }

   /* display files dir path if showall mode */

   if (fptr && cw.showall && cw.curidx < cw.nfiles)
      disp_path(cw.curidx);

   if (cw.nfiles == 0)         /* display a msg if no files in dir */
      disp_empty_msg(fptr);
}


/******************************************************************************
                        A D J U S T _ W I N D O W
 *****************************************************************************/

int ALTCALL
adjust_window() {

   /* for MS DOS, assume the max length file name is 13.  8 for the primary
      name, 1 for '.', 3 for the extension, and 1 for '\' if its a directory */

   cw.maxlen = MAX_NAMELEN + 1;

   /* everything depends on # files in directory */

   if (cw.nfiles == 0)                 /* unusual, but dir may be empty */
      cw.nrows = cw.ncols = 1;
   else {                              /* are files, calc logical rows, cols */
      cw.ncols = (cw.info_display) ? 1 : 5;
      cw.nrows = (cw.nfiles+(cw.ncols-1)) / cw.ncols;
   }

   cw.colsiz = SCREEN_COLS / cw.ncols;         /* width of each column */

   /* update current logical idx */

   if (cw.curidx >= cw.nfiles)
      cw.curidx = cw.nfiles ? cw.nfiles - 1 : 0;

   /* make sure nbase is setup such that the current file is displayed */

   if (cw.nfiles <= cw.ndrows * cw.ncols) /* if file entries will fit on */
      cw.nbase = 0;                       /*   1 screen, start at 1st */
   else {
      cw.nbase = idx2lr(cw.curidx) - cw.ndrows / 2;  /* try to center curidx */
      if (cw.nbase > 0 && cw.nbase + cw.ndrows > cw.nrows) /* no blank rows  */
         cw.nbase = cw.nrows - cw.ndrows;                  /* if possible    */
      if (cw.nbase < 0)                              /* might overshoot */
         cw.nbase = 0;
   }

}


/******************************************************************************
                             I N F O C N T
 *****************************************************************************/

infocnt(chg)           /* display/remove info header when required */
int chg;
{
   int cur_isnt_top;

   inwin += chg;                       /* more or less info windows */

   cur_isnt_top = (numwin > 1 && curwin != winlis);

   /* if the count of info windows just went to 0, or it just went from 0 to 1,
      we need to add or remove the info display header.  The top display
      window losses or gains a row when this happens */

   if ((inwin == 0 && chg) || (inwin == 1 && chg > 0)) {

      /* do a temp switch to the top window if not already there */

      if (cur_isnt_top) {
         wincpy(curwin,&cw);
         savefiles(cw.save_files,cw.nfiles);
         wincpy(&cw,winlis);
         restorefiles(cw.save_files,cw.nfiles);
      }

      /* now add or remove a row from the window */

      if (inwin) {                     /* remove a line, display header */
         cw.fwrow++;  cw.fnrow++;
         cw.wrows--;  cw.ndrows--;
         infohead();
      } else {                         /* add a line, remove header */
         cw.fwrow--;  cw.fnrow--;
         cw.wrows++;  cw.ndrows++;
      }

      /* now update the top window display, but don't bother if the current
         window is the top window - it will be updated by caller */

      if (cur_isnt_top) {
         adjust_window();      /* calculate #rows, columns, etc to display */
         update_window(0);
      }

      /* restore windows if we did a temp switch above */

      if (cur_isnt_top) {
         wincpy(winlis,&cw);
         savefiles(cw.save_files,cw.nfiles);
         wincpy(&cw,curwin);
         restorefiles(cw.save_files,cw.nfiles);
      }
   }
}


/*****************************************************************************
                      D I S P _ E M P T Y _ M S G
 *****************************************************************************/

static int ALTCALL
disp_empty_msg(on)     /* display empty dir msg w/wo highlighting */
int on;
{
   if (on)
      setvattrib(DIS_HIGH);

   disp_str_at("No files!",cw.fnrow+1,SCREEN_COLS/2-5);

   if (on)
      setvattrib(DIS_NORM);
}


/*****************************************************************************
                        D I S P _ D I R N A M E
 *****************************************************************************/

disp_dirname() {       /* display the dir name header */

   char allmsg[20];

   if (cw.showall) {                   /* special header if showall mode */

      strcpy(allmsg,"FILES ON DRIVE ");
      strncat(allmsg,cw.dirbuf,2);
      center_text(cw.fwrow,allmsg);

   } else

      center_text(cw.fwrow,cw.dirbuf);    /* disp the dir name */
}


/*****************************************************************************
                          I N F O H E A D
 *****************************************************************************/

infohead() {           /* display the info header */

   setvattrib(DIS_HEAD);
   disp_str_at("      NAME           USED  ALLOCATED     DATE         TIME      R H S A DIR",
      FIRST_NROW,0);
   clr_eol();
   setvattrib(DIS_NORM);
}


/*****************************************************************************
                            S H O W _ A L L
 *****************************************************************************/

show_all() {

   if (anyshowall && !cw.showall)      /* only one window can do showall */
      show_error(0,ONE_SH_ALL,1,"Only one window can show all files!");

   if (cw.showall ^= 1) {      /* toggle showall mode */

      /* showall mode is being turned on, allocate space for dir name ptrs */

      if ((dirlst = (char **) calloc(MAX_DIR,sizeof(char *))) == NULL) {
         cw.showall = 0;
         show_error(0,NO_MEM,1,"Out of memory!  Show All is not active!");
      }

      if (numwin == 1) {       /* make row for showall header if not already */
         cw.fnrow++;
         cw.ndrows--;
      }

      anyshowall = TRUE;       /* yes, a window has showall turned on */

   } else              /* showall is being turned off */

      showoff();

   renew_window();     /* redo window with/without showall mode */
}

/*****************************************************************************
                              S H O W O F F
 *****************************************************************************/

showoff() {            /* turn off show all mode */

   register int i;
   register char **cp;

   for (i = 0, cp = dirlst; i < diridx; i++, cp++)     /* release dir name */
       free(*cp);                                      /*   memory */

   free((char *)dirlst);       /* now release pointer memory */

   diridx = 0;                 /* reset for next time */
   dirlst = NULL;

   cw.showall = anyshowall = FALSE;    /* no window has showall now */

   if (numwin == 1) {          /* release showall header line if not needed */
      cw.fnrow--;
      cw.ndrows++;
   }
}


/******************************************************************************
                              W I N C P Y
 ******************************************************************************/

static int ALTCALL
wincpy(to,from)        /* copy window structures - I made this a separate */
WINDOW *to, *from;     /* routine cause MSC generates a bunch of code for */
{                      /* each structure asignment - in reality, it just a */
                       /* little more than the code required to call this */
                       /* function, but... */

   *to = *from;        /* not much to look at */
}


/******************************************************************************
 **                  S A V E / R E S T O R E  F I L E S                      **
 ******************************************************************************/

static int ALTCALL
savefiles(fp,nf)       /* copy files[] to save area */
char far *fp;
int nf;
{
   movedata(dataseg,(unsigned int) files,FP_SEG(fp),FP_OFF(fp),
             nf * sizeof(FILE_ENT));
}

static int ALTCALL
restorefiles(fp,nf)    /* copy files[] from save area */
char far *fp;
int nf;
{
   movedata(FP_SEG(fp),FP_OFF(fp),dataseg,(unsigned int) files,
            nf * sizeof(FILE_ENT));
}
