📄 ovdir.c
字号:
/* 036 8-Jun-87 ovdir.c
Copyright (c) 1987 by Blue Sky Software. All rights reserved.
*/
#include <stdio.h>
#include "ov.h"
#include "overr.h"
#include "menu.h"
#include "direct.h"
#include "strmem.h"
#include "dosfile.h"
#define DCOLSIZ 15
#define DCOLS (SCREEN_COLS / DCOLSIZ)
#define dr2sr(r) (FIRST_NROW + (r - drbase))
#define dc2sc(c) ((c - dcbase) * DCOLSIZ)
#define TO_NONE 0
#define TO_SUBDIR 1
#define TO_SIBLING 2
#define TO_PARENT 3
#define TO_ROOT 4
char *strrchr(), *strupr();
struct search_block *nxtfile();
struct dir_ent {
struct dir_ent *subdir;
struct dir_ent *sibling;
struct dir_ent *parent;
struct dir_ent *prev_sib;
char name[13];
unsigned char row;
unsigned char col;
};
static last_drive = ' ';
static char dirpath[MAX_PATHLEN+6];
static int drbase, drend, dcbase, dcend;
static struct dir_ent *curdir, *logdir, *findir(), *dir_next();
static struct dir_ent root = { NULL, NULL, NULL, NULL, "", 0, 0 };
int dir_exit(), dir_login(), dir_mkdir(), dir_rmdir(), dir_new();
extern MENU top_file_menu[], *top_menu;
MENU top_dir_menu[] = {
{ "Login", "Login (switch) to the highlighted directory", dir_login, NULL },
{ "Mkdir", "Make a subdirectory of the highlighted directory", dir_mkdir, NULL },
{ "New", "Reread and redisplay directory tree", dir_new, NULL },
{ "Rmdir", "Remove (delete) the highlighted directory", dir_rmdir, NULL },
{ "Quit", "Return to file display", dir_exit, top_file_menu },
{ NULL, NULL, NULL, NULL }
};
extern WINDOW cw;
extern unsigned char dir_display, restricted;
char *strchr();
/******************************************************************************
** D T R E E **
*****************************************************************************/
dtree() { /* display / work with directory tree */
int drive;
dir_display = TRUE; /* dir tree is (will be) displayed */
restricted = TRUE; /* disable some file commands */
/* scan the current disk and create the internal directory tree if it
hasn't already been built or the user has changed disks */
if ((drive = current_drive()) != last_drive) { /* has the drive switched? */
if (root.subdir) { /* delete current tree */
del_dtree(root.subdir); /* if drive switch */
root.subdir = NULL;
}
last_drive = drive;
*dirpath = '\0'; /* scan_dir() starts at */
strncat(dirpath,cw.dirbuf,3); /* drives root dir */
strcpy(root.name,dirpath);
disp_msg(1,"Scanning disk"); /* takes awhile, tell user */
scan_dir(&root); /* build new dir tree */
dir_mark(); /* assign row/col's to ent's */
clr_msg(); /* done scanning */
drbase = dcbase = 0; /* assume dir */
drend = NAME_ROWS; /* will start */
dcend = DCOLS; /* at the root */
}
curdir = findir(); /* locate current dir in tree */
logdir = curdir; /* remember the logged dir */
/* now display the current portion of the dir tree */
adj_dir_dis(); /* make sure logged dir will show */
dir_distree(); /* let user see it */
top_menu = top_dir_menu; /* setup the dir menu as the main menu */
}
/******************************************************************************
D I R _ N E W
*****************************************************************************/
dir_new() { /* rescan the disk and redisplay the dir tree */
last_drive = ' '; /* simply force a rescan */
dtree(); /* and let dtree() do the work */
update_vol_stats(); /* in case its a new volume */
}
/******************************************************************************
** D I R _ E X I T **
*****************************************************************************/
dir_exit() { /* exit the dir display, return to file display */
dir_display = FALSE; /* dir tree will not be displayed */
restricted = FALSE; /* allow all file commands */
top_menu = top_file_menu; /* file menu is main again */
update_header(); /* always rewrite the entire screen */
refresh_screen(0); /* 'cause there may be > windows */
}
/******************************************************************************
** S C A N _ D I R **
*****************************************************************************/
scan_dir(dp) /* scan the specified dir tree for other directories */
struct dir_ent *dp;
{
int dplen;
int firsttime = TRUE;
struct search_block *sbp;
register struct dir_ent *ndp, *ldp = NULL;
/* build the pathname of the dir to scan */
dplen = strlen(dirpath); /* remember callers length */
if (strcmp(dp->name+2,"\\") != 0) { /* special case if root dir */
strcat(dirpath,dp->name); /* add name of dir to scan */
strcat(dirpath,"\\");
}
strcat(dirpath,"*.*"); /* add wildcard string */
/* scan all files in directory looking for subdirectories. When a
subdirectory is found, add it to the dir_ent tree. Note, the . and
.. directory entries are ignored. */
while (sbp = nxtfile(dirpath,0x16,&firsttime))
if (sbp->attrib & DIR && *sbp->fn != '.') {
/* found a subdir we want, build a struct dir_ent for it */
ndp = (struct dir_ent *) Malloc(sizeof(struct dir_ent));
strcpy(ndp->name,sbp->fn);
ndp->subdir = NULL;
ndp->sibling = NULL;
ndp->parent = dp;
ndp->prev_sib = ldp;
/* now link it to the dir_ent tree either as a subdir of the
parent (1st one only) or a sibling of the last one */
if (ldp)
ldp->sibling = ndp; /* not 1st, is a sibling */
else
dp->subdir = ndp; /* 1st one, subdir of parent */
ldp = ndp; /* new one is now the last one */
}
/* if any subdirectories were found, scan 'em. This isn't done
earlier so the file search isn't complicated by the directory
switches. */
if (ldp) { /* NULL if no sub's found */
dirpath[strlen(dirpath)-3] = '\0'; /* remove *.* for next level */
ldp = dp->subdir; /* start with the first one */
do {
scan_dir(ldp); /* call ourselves to scan this subtree */
} while (ldp = ldp->sibling); /* do all the subs found */
}
dirpath[dplen] = '\0'; /* restore dir pathname for caller */
}
/******************************************************************************
** D E L _ D T R E E **
*****************************************************************************/
del_dtree(dp) /* purge the current in memory dir tree structure */
register struct dir_ent *dp;
{
register struct dir_ent *ndp;
/* delete this subdirectory ENTRY and all sibling ENTRIES (not the
actual directories) */
do {
if (dp->subdir) /* if it has a subdir, make a recursive call */
del_dtree(dp->subdir); /* to delete the substructure */
ndp = dp->sibling; /* get address of any sibling */
free((char *)dp); /* free the dir_ent space itself */
} while (dp = ndp); /* do until no more siblings */
}
/******************************************************************************
D I R _ D I S T R E E
*****************************************************************************/
static int
dir_distree() { /* display the dir tree */
register int drow;
int i, ldrow = -1;
register struct dir_ent *dp = &root;
do {
drow = dp->row; /* speed things up a little */
/* if drow != ldrow, then this is the first entry on this display
row, clear the line to remove any old junk that might be there */
if (drow != ldrow && drow >= drbase && drow < drend) {
gotorc(dr2sr(drow),dc2sc(dcbase));
clr_eol();
ldrow = drow;
}
/* see if its necessary to put some spacer bars in from the previous
sibling. This will be necessary if the prev_sib had a desendent
with siblings because the siblings will occupy display lines
between this ent's prev_sib and where this ent goes. */
if (dp->prev_sib && (i = drow - dp->prev_sib->row - 1) > 0)
for (; i; i--)
if (dir_on_screen(drow-i,dp->col))
disp_char_at(0xb3,dr2sr(drow-i),dc2sc(dp->col));
/* only display a dir entry if it falls within the boundries, figure
out if this one does and display the name if so - the dir under
the pointer is highlighted, the logged dir is 'tagged' all others
are displayed 'normal' */
if (dir_on_screen(drow,dp->col))
disp_dir_name(dp,dp == curdir ? DIS_HIGH :
(dp == logdir ? DIS_TAGD : DIS_NORM));
} while (dp = dir_next(dp,&i,&i));
/* if we didn't reach the bottom of the display area, clear out the rest
of the lines to remove any garbage that might be there */
drow++; /* next would be display row */
if (drow - drbase < NAME_ROWS)
for (; drow - drbase < NAME_ROWS; drow++) {
gotorc(dr2sr(drow),dc2sc(dcbase));
clr_eol();
}
}
/******************************************************************************
** D I S P _ D I R _ N A M E **
*****************************************************************************/
disp_dir_name(dp,va) /* display a single dir name */
register struct dir_ent *dp;
int va;
{
gotorc(dr2sr(dp->row),dc2sc(dp->col)); /* move to display location */
/* display the leadin bar to the dir name, it depends on whether
this is the root, the 1st subdir, the last sibling, and if any
siblings follow */
if (dp->col) { /* root dir? */
if (dp->prev_sib == NULL) /* 1st subdir? */
disp_char((dp->sibling) ? 0xc2 : 0xc4); /* siblings follow? */
else
disp_char((dp->sibling) ? 0xc3 : 0xc0);
} else
disp_char(' '); /* root - no leadin */
if (va != DIS_NORM) /* setup highlight if needed */
setvattrib(va);
disp_char(' ');
disp_str(dp->name); /* display the name */
disp_char(' ');
/* draw bar to subdir or blank fill name */
disp_rep(dp->subdir ? 0xc4 : ' ',DCOLSIZ - strlen(dp->name) - 3);
if (va != DIS_NORM) /* restore normal attribute if changed */
setvattrib(DIS_NORM);
}
/*****************************************************************************
D I R _ M A R K
*****************************************************************************/
static int
dir_mark() { /* mark dir_ent's with logical row/column where they display */
register struct dir_ent *dp;
int nxtype, backup, drow, dcol;
dp = &root;
drow = dcol = 0;
/* scan the dir_ent tree in order */
while (dp = dir_next(dp,&nxtype,&backup)) {
if (nxtype) { /* NZ if dp is a sibling */
drow++; /* siblings go down a row */
dcol -= backup; /* and maybe back some */
} else
dcol++; /* sub dir's go over a column */
dp->row = drow; /* assign row/col to entry */
dp->col = dcol;
}
}
/******************************************************************************
D I R _ N E X T
******************************************************************************/
static struct dir_ent *
dir_next(dp,tp,bp) /* return address of next dir_ent */
register struct dir_ent *dp;
int *tp, *bp;
{
*bp = 0; /* assume we will not backup to parent */
if (dp->subdir) { /* subdir is next if there is one */
*tp = 0; /* tell caller its a sub dir */
return(dp->subdir);
}
*tp = 1; /* assume a sibling will be found */
if (dp->sibling) /* a sibling is next if there is one */
return(dp->sibling);
/* keep backing up until a parent is found with a sibling or root */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -