home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume9
/
browse_pds
/
browse.c
next >
Wrap
C/C++ Source or Header
|
1989-12-14
|
36KB
|
2,154 lines
/* -- Just what the hell am I ??? --- */
#include <stdio.h>
#ifdef M_XENIX
#define USG
#define rindex strrchr
#define GETCWD
#else
#ifdef L_ctermid
#define USG
#define rindex strrchr
#define minor(i) ((i)&0xFF)
#define major(i) minor((i)>>8)
#else
#include <whoami.h>
#endif
#endif
/* -- Miscellaneous include files -- */
#include <sys/param.h> /* NCARGS, and others */
#ifndef M_XENIX
#include <sys/types.h> /* data types for various files */
#endif
#include <sys/stat.h> /* stat data structure for getdir(), statout() */
#include <sys/dir.h> /* dir data structure for getdir() */
#include <pwd.h> /* passwd data structure for u_name() */
#include <grp.h> /* group data structure for g_name() */
#ifdef BSD
#include <sys/time.h> /* time data structure for printime() */
#else
#include <time.h> /* time data structure for printime() */
#endif
#ifdef USG
#ifdef M_XENIX
#include <sys/ioctl.h>
#endif
#include <termio.h>
#else
#include <sgtty.h> /* terminal modes for tinit(), tend() */
#endif
#include <signal.h>
/* -- make information --
BUILD
browse: browse.c
cc browse.c -O -o browse -ltermlib
END
*/
/* -- Miscellaneous defines -- */
#define FALSE 0
#define TRUE 1
#define MAXENTS 320
#define MAXID 16
#define MAXLINE 81
#define NCOL 64
#define MAXNAME 14
#define FILENAME 256
#define MAXARGC (NCARGS/16) /* Estimate max ARGC */
#define CHARSET 256 /* Number of macros == size of byte */
#define NOMAC (0) /* Null macro (last) */
#define TERMBUF 1024 /* Size of term buf for termcap */
#define SMALLBUF 256
/* -- Extended directory entry format -- */
struct entry {
char *e_name;
int e_flags;
#define FTAGGED (1<<0)
#define FPERMANENT (1<<1)
struct stat e_stat; /* file status field */
char e_uname[9]; /* user name */
char e_gname[9]; /* user's group name */
}
*xentries[MAXENTS], **entries=xentries;
int nentries;
/* -- Look-up cache for user names -- */
struct idtab {
int id_id; /* user (or group) id */
char id_name[9]; /* name[8] + filler */
}
u_list[MAXID], /* Matched user id's. */
g_list[MAXID]; /* ditto group */
int u_ptr=0, g_ptr=0; /* current entries */
/* -- Global variables -- */
FILE *efp; /* Environment file */
char efname[MAXLINE]; /* " name */
char *tent; /* Pointer to tbuf */
char PC; /* Pad character */
char *UP, *BC; /* Upline, backsapce character */
short ospeed; /* Terminal output speed */
char termbuf[TERMBUF]; /* Place to put term info */
char *macbuf[CHARSET], ungetbuf[SMALLBUF]; /* Buffers for pushback and macros */
char c_macro=NOMAC; /* current macro */
char *macptr = ""; /* Pointer to currently executing macro */
char *ungetptr = ungetbuf; /* Pointer to pushed-back characters */
char *errname; /* Name of file error found in */
extern int errno; /* system error number */
int xerrno; /* extended error number */
int ccol=NCOL; /* Width of used display, current column */
int quickmode; /* short display mode (files only) */
#ifdef USG
struct termio rawbuf;
struct termio cookedbuf;
#else
struct sgttyb sgbuf; /* buffer for terminal mode info */
int rawflags, cookflags; /* flags for raw & cooked tty mode */
#endif
char *cm, /* Cursor motion */
*cs, /* Change scrolling region */
*sf, /* - scroll forward */
*sr, /* - scroll backwards */
*ce, /* Clear to end of line */
*cl, /* Clear screen */
*al, /* Insert line */
*dl, /* delete ditto */
*so, /* standout */
*se, /* standout end */
*us, /* underline */
*ue, /* underline end */
*ti, /* Init terminal */
*te; /* Reset terminal */
int li, /* lines on screen */
co; /* columns ditto */
char xn; /* Magic cookie kludge */
/* -- Global error messages -- */
char *emesg[4]={
"??",
#define TOO_MANY 1
"Too many directory entries",
#define NOMATCH 2
"No match",
0
};
int top, curr; /* Positions of screen in directory */
#define bottom ((top+nlines>nentries)?nentries:(top+nlines))
char *dot; /* name of current directory */
int nlines; /* number of lines displayed on page */
char display_up; /* Does the display exist? */
int todump=1; /* Do we want to dump data? */
int ended; /* Have we quite finished? */
int intrup; /* Have we been interrupted? */
char *HOME; /* Where did I start from? */
char *SHELL; /* How do I run programs? */
/* -- types of functions !!! */
char *getenv(), *tgetstr();
char *malloc();
#define NEW(t) (t *)malloc(sizeof (t))
#define NIL(t) ((t) 0)
/* -- Code starts here: dummy main -- */
main(ac, av, ep)
int ac;
char **av;
char **ep;
{
if(ac>1) chdir(av[1]);
sprintf(efname, "/tmp/br.env.%d", getpid());
HOME=getenv("HOME");
SHELL=getenv("SHELL");
dumpenv(ep);
intrup=0;
tinit(getenv("TERM"));
clear_all();
browse();
tend();
unlink(efname);
}
clear_all()
{
int i;
for(i = 0; i < MAXENTS; i++)
entries[i] = 0;
}
char *clone(name)
char *name;
{
char *hold;
hold = (char *)malloc(strlen(name)+1);
if(hold==0)
return 0;
strcpy(hold, name);
return hold;
}
newname(e, name)
struct entry *e;
char *name;
{
if(e->e_name)
free(e->e_name);
e->e_name = clone(name);
}
#if BSD
readent(dp, db)
DIR *dp;
struct direct *db;
{
struct direct *ptr;
ptr = readdir(dp);
if(!ptr) return 0;
*db = *ptr; /* V7 'C' and above... safe, since UCB=V7+ */
free(ptr);
return 1;
}
#else
#define opendir(n) fopen(n, "r")
#define DIR FILE
readent(dp, db)
DIR *dp;
struct direct *db;
{
if(fread(db, sizeof(struct direct), 1, dp))
return 1;
/* else */
return 0;
}
#define closedir fclose
#endif
getdir()
{
char *u_name(), *g_name();
DIR *dp;
int valid;
struct direct *hold = NEW(struct direct);
int i, p;
if(!(dp = opendir("."))) {
errname=".";
return FALSE;
}
p = 0;
for(i = 0; i < nentries; i++) {
if(entries[i]->e_flags & FPERMANENT) {
if(p != i) {
struct entry *hold;
hold = entries[p];
entries[p] = entries[i];
entries[i] = hold;
}
p++;
}
}
for(nentries = p; !intrup && nentries < MAXENTS; nentries += valid) {
if(!entries[nentries]) {
entries[nentries] = NEW(struct entry);
if(!entries[nentries])
break;
entries[nentries]->e_name = NIL(char *);
}
if(!readent(dp, hold))
break;
valid = (hold->d_ino != 0);
if(valid) {
if(stat(hold->d_name, &entries[nentries]->e_stat)==-1) {
closedir(dp);
errname=hold->d_name;
free(hold);
return FALSE;
}
newname(entries[nentries], hold->d_name);
#ifndef BSD /* truncate name to 14 characters in non-BSD systems */
if(strlen(entries[nentries]->e_name)>14)
entries[nentries]->e_name[14] = 0;
#endif
entries[nentries]->e_flags = 0;
strcpy(entries[nentries]->e_uname,
u_name(entries[nentries]->e_stat.st_uid));
strcpy(entries[nentries]->e_gname,
g_name(entries[nentries]->e_stat.st_gid));
}
}
closedir(dp);
free(hold);
if(intrup)
return FALSE;
if(nentries>=MAXENTS || entries[nentries]==NIL(struct entry *)) {
errno=0;
xerrno=TOO_MANY;
errname=".";
return FALSE;
}
sortdir();
if(intrup)
return FALSE;
return TRUE;
}
at_current()
{
at_file(curr);
}
at_file(file)
int file;
{
if(display_up) {
if(file < top || file >= top+nlines)
return 0;
at(0, curr-top+2);
} else {
if(file != curr)
return 0;
cmdline();
}
return 1;
}
display_flags(flags)
{
outc((flags&FTAGGED)?'+':((flags&FPERMANENT)?'!':' '));
}
repaint_flags()
{
if(!display_up) return;
at(NCOL-1, curr-top+2);
display_flags(entries[curr]->e_flags);
}
repaint_current()
{
if(!display_up) return;
at_current();
dump(curr, curr+1);
}
tag()
{
entries[curr]->e_flags ^= FTAGGED;
repaint_flags();
}
tag_all(flag)
int flag;
{
int i;
for(i = 0; i < nentries; i++)
if(flag)
entries[i]->e_flags |= FTAGGED;
else
entries[i]->e_flags &= ~FTAGGED;
if(display_up)
todump = TRUE;
}
delete_from_display(file)
int file;
{
if(!display_up) return;
if(file>=top+nlines) return;
if(file < top) file = top;
scroll(2+file-top, 2+nlines, 1);
at(0, 2+nlines-1);
if(top+nlines >= nentries)
outc('~');
else
dump(bottom, bottom+1);
}
delete_file_entry(file)
int file;
{
struct entry *hold;
int i;
delete_from_display(file);
hold = entries[file];
for(i=file; i<nentries-1; i++)
entries[i]=entries[i+1];
entries[nentries-1]=hold;
nentries--;
if(file < curr || curr >= nentries) {
curr--;
if(top >= nentries) {
top--;
display_up = 0;
todump = 1;
}
}
}
remove_one(file, doit)
int file;
int doit;
{
if(!doit) {
cmdline();
outs("Delete ");
ctlouts(entries[file]->e_name);
outs(" [n]?");
doit = getchar() == 'y';
outs(doit?"Yes.":"No.");
}
if(doit) {
if(unlink(entries[file]->e_name) == 0) {
cmdline();
outs("Deleted ");
ctlouts(entries[file]->e_name);
outs(".");
delete_file_entry(file);
return 1;
} else {
wperror(entries[file]->e_name);
return 0;
}
}
return 0;
}
remove(doit)
int doit;
{
int i;
int found_tags;
found_tags = 0;
i = 0;
while(i < nentries) {
if(entries[i]->e_flags & FTAGGED) {
found_tags = 1;
if(!remove_one(i, doit)) /* decrements nentries */
break;
} else
i++;
}
if(!found_tags)
remove_one(curr, doit);
}
insert_entry_at(ent, i)
struct entry *ent;
int i;
{
struct entry *hold;
int j;
/* Allocate slot at end */
if(!entries[nentries]) {
entries[nentries] = NEW(struct entry);
if(!entries[nentries])
return 0;
entries[nentries]->e_name = NIL(char *);
} else if(entries[nentries]->e_name) {
free(entries[nentries]->e_name);
entries[nentries]->e_name = NIL(char *);
}
/* Copy data into slot */
*entries[nentries] = *ent;
entries[nentries]->e_name = clone(ent->e_name);
if(!entries[nentries]->e_name)
return 0;
if(i != nentries) {
/* Rotate slot to middle */
hold = entries[nentries];
for(j = nentries; j > i; j--)
entries[j] = entries[j-1];
entries[i] = hold;
}
nentries++;
if(display_up) {
if(i < top)
i = top;
if(i >= bottom)
return;
scroll(2+i-top, 2+nlines, -1);
at(0, 2+i-top);
dump(i, i+1);
}
}
insert_entry(ent)
struct entry *ent;
{
int i;
if(nentries >= MAXENTS)
return 0;
for(i = 0; i < nentries; i++)
if(entcmp(&ent, &entries[i]) < 0)
break;
return insert_entry_at(ent, i);
}
move()
{
char scratch[FILENAME];
struct entry hold;
char inps();
hold = *entries[curr];
cmdline();
outs("Rename ");
ctlouts(entries[curr]->e_name);
outc(' ');
if(inps(scratch, entries[curr]->e_name, 0)=='\033') {
killcmd();
return;
}
if(link(entries[curr]->e_name, scratch)!=0) {
char tmbuf[42];
sprintf(tmbuf, "(rename %s %s)", entries[curr]->e_name, scratch);
wperror(tmbuf);
return;
}
if(unlink(entries[curr]->e_name)!=0) {
wperror(entries[curr]->e_name);
return;
}
hold.e_name = scratch;
hold.e_flags &= ~FTAGGED;
delete_file_entry(curr);
insert_entry(&hold);
}
pname(name, mode)
char *name;
int mode;
{
int i;
char *slash, *rindex();
int max=quickmode?MAXLINE:(MAXNAME+1);
if((mode&S_IFMT)==S_IFDIR)
max--;
else if((mode&S_IFMT)==S_IFREG && (mode&0111))
max--;
else if((mode&S_IFMT)!=S_IFREG)
max--;
if(!quickmode && (slash=rindex(name, '/'))) {
name=slash;
outc('<');
max--;
}
for(i=0; i<max && *name; name++)
i += ctlout(*name);
standend();
if(i==max && *name)
outs("\b>");
if((mode&S_IFMT)==S_IFDIR) {
outc('/');
}
else if((mode&S_IFMT)==S_IFREG && (mode&0111)) {
outc('*');
}
else if((mode&S_IFMT)!=S_IFREG) {
outc('?');
}
}
sortdir()
{
int entcmp();
qsort(entries, nentries, sizeof(struct entry *), entcmp);
}
addname(flag)
char flag;
{
char buf[FILENAME], *ptr, *tmp;
char scratch[FILENAME];
struct entry hold;
char inps();
cmdline();
outs("Add ");
if(inps(scratch, entries[curr]->e_name, 0)=='\033') {
killcmd();
return;
}
if(stat(scratch, &hold.e_stat)==-1) {
wperror(scratch);
return;
}
if(flag!='+' && *scratch != '/') {
strcpy(buf, dot);
ptr = scratch;
for(;;) { /* eat '../' and './' */
if(ptr[0]=='.' && ptr[1]=='.' &&
(ptr[2]=='/' || !ptr[2])) {
tmp = rindex(buf, '/');
if(!tmp) break;
*tmp=0;
ptr += 2+(ptr[2]=='/');
continue;
}
if(ptr[0]=='.' &&
(ptr[1]=='/' || !ptr[1])) {
ptr += 1+(ptr[1]=='/');
continue;
}
break;
}
if(*ptr) {
strcat(buf, "/");
strcat(buf, ptr);
}
hold.e_name = buf;
} else
hold.e_name = scratch;
strcpy(hold.e_uname,
u_name(hold.e_stat.st_uid));
strcpy(hold.e_gname,
g_name(hold.e_stat.st_gid));
hold.e_flags = 0;
if(flag!='+')
hold.e_flags |= FPERMANENT;
insert_entry(&hold);
}
addperm()
{
char buf[FILENAME], *ptr, *tmp;
struct entry hold;
int entcmp(), i;
if(entries[curr]->e_flags & FPERMANENT)
return;
if(entries[curr]->e_name[0]!='/') {
strcpy(buf, dot);
ptr = entries[curr]->e_name;
for(;;) { /* eat '../' and './' */
if(ptr[0]=='.' && ptr[1]=='.' &&
(ptr[2]=='/' || !ptr[2])) {
tmp = rindex(buf, '/');
if(!tmp) break;
*tmp=0;
ptr += 2+(ptr[2]=='/');
continue;
}
if(ptr[0]=='.' &&
(ptr[1]=='/' || !ptr[1])) {
ptr += 1+(ptr[1]=='/');
continue;
}
break;
}
if(*ptr) {
strcat(buf, "/");
strcat(buf, ptr);
}
hold = *entries[curr];
hold.e_name = buf;
hold.e_flags &= ~FTAGGED;
hold.e_flags |= FPERMANENT;
insert_entry(&hold);
} else {
entries[curr]->e_flags |= FPERMANENT;
entries[curr]->e_flags &= ~FTAGGED;
repaint_flags();
}
}
delperm()
{
entries[curr]->e_flags &= ~(FPERMANENT|FTAGGED);
repaint_flags();
}
entcmp(e1, e2)
struct entry **e1, **e2;
{
if((*e1)->e_name[0] == '/') {
if((*e2)->e_name[0] != '/')
return 1;
} else if((*e2)->e_name[0] == '/')
return -1;
return strcmp((*e1)->e_name, (*e2)->e_name);
}
dump(start, end)
int start;
int end;
{
int i;
int lo = (start<nentries)?start:nentries;
int hi = (end<nentries)?end:nentries;
for(i=lo; i<hi; i++) {
statout(entries[i]->e_name,
&entries[i]->e_stat,
entries[i]->e_uname,
entries[i]->e_gname,
entries[i]->e_flags);
nl();
}
return TRUE;
}
statout(name, sbuf, user, group, flags)
char *name;
struct stat *sbuf;
char *user, *group;
int flags;
{
int mode = sbuf->st_mode;
if(!quickmode) {
printf("%5u ", sbuf->st_ino);
if((mode&S_IFMT)==S_IFCHR) outc('c');
else if((mode&S_IFMT)==S_IFBLK) outc('b');
else if((mode&S_IFMT)==S_IFDIR) outc('d');
else if((mode&S_IFMT)==S_IFREG) outc('-');
else outc('?');
triad((mode>>6)&7, mode&S_ISUID, 's');
triad((mode>>3)&7, mode&S_ISGID, 's');
triad(mode&7, mode&S_ISVTX, 't');
outc(' ');
printf("%3u ", sbuf->st_nlink);
printf("%-8s ", user);
printf("%-8s ", group);
if((mode&S_IFMT)==S_IFREG || (mode&S_IFMT)==S_IFDIR)
printf("%7ld ", sbuf->st_size);
else
printf("%3d,%3d ",
major(sbuf->st_rdev),
minor(sbuf->st_rdev));
outc(' ');
printime(&sbuf->st_mtime);
}
display_flags(flags);
pname(name, sbuf->st_mode);
}
char *
u_name(uid)
int uid;
{
int i;
struct passwd *pwptr, *getpwuid();
for(i=0; i<u_ptr; i++)
if(u_list[i].id_id==uid)
return u_list[i].id_name;
if(u_ptr>=MAXID) /* cache full */
u_ptr = 0; /* simplistic algorithm, wrap to beginning */
/* with MAXID >> # common id's it's good enough */
u_list[u_ptr].id_id=uid;
if(pwptr=getpwuid(uid)) { /* Copy name */
for(i=0; pwptr->pw_name[i]>' '; i++)
u_list[u_ptr].id_name[i]=pwptr->pw_name[i];
u_list[u_ptr].id_name[i]=0;
}
else /* Default to UID */
sprintf(u_list[u_ptr].id_name, "%d", uid);
return u_list[u_ptr++].id_name;
}
char *
g_name(gid)
int gid;
{
int i;
struct group *grptr, *getgrgid();
for(i=0; i<g_ptr; i++)
if(g_list[i].id_id==gid)
return g_list[i].id_name;
if(g_ptr>=MAXID) /* cache full */
g_ptr = 0; /* simplistic algorithm, wrap to beginning */
/* with MAXID >> # common id's it's good enough */
g_list[g_ptr].id_id=gid;
if(grptr=getgrgid(gid)) { /* Copy name */
for(i=0; grptr->gr_name[i]>' '; i++)
g_list[g_ptr].id_name[i]=grptr->gr_name[i];
g_list[g_ptr].id_name[i]=0;
}
else /* Default to UID */
sprintf(g_list[g_ptr].id_name, "%d", gid);
return g_list[g_ptr++].id_name;
}
printime(clock)
long *clock;
{
struct tm *tmbuf, *localtime();
static char *months[12]= {
"Jan","Feb","Mar","Apr","May","Jun",
"Jul","Aug","Sep","Oct","Nov","Dec"
};
tmbuf=localtime(clock);
printf("%2d %3s %02d %2d:%02d",
tmbuf->tm_mday,
months[tmbuf->tm_mon],
tmbuf->tm_year,
tmbuf->tm_hour,
tmbuf->tm_min);
}
header()
{
int i;
if(quickmode)
printf(" File Name");
else
printf(
"Inode Long mode LNX User Group Size/Dev Modify Time File name"
);
nl();
}
triad(bits, special, code)
int bits, special;
char code;
{
if(bits&4) outc('r');
else outc('-');
if(bits&2) outc('w');
else outc('-');
if(special) outc(code);
else if(bits&1) outc('x');
else outc('-');
}
outs(s)
char *s;
{
int outc();
if(s)
tputs(s, 0, outc);
}
outc(c)
char c;
{
putchar(c);
}
/* Screen manipulation primitives: dumb set for smart terminals */
at(x, y)
int x, y;
{
outs(tgoto(cm, x, y));
}
nl()
{
outs(ce);
outc('\n');
}
/* Scroll lines in window (from:to) n lines */
scroll(from, to, n)
int from, to, n;
{
if(cs && sf && sr) {
outs(tgoto(cs, from, to-1));
if(n<0)
while(n++)
outs(sr);
else
while(n--)
outs(sf);
outs(tgoto(cs, 0, li-1));
}
else if(al && dl) {
if(n<0) {
int i=n;
outs(tgoto(cm, 0, to+n));
while(i++)
outs(dl);
outs(tgoto(cm, 0, from));
while(n++)
outs(al);
}
else {
int i=n;
outs(tgoto(cm, 0, from));
while(i--)
outs(dl);
outs(tgoto(cm, 0, to-n));
while(n--)
outs(al);
}
}
}
wperror(file)
char *file;
{
extern int errno;
extern char *sys_errlist[];
cmdline();
ctlouts(file);
ctlouts(": ");
ctlouts(errno?sys_errlist[errno]:emesg[xerrno]);
if(!display_up)
nl();
}
fperror(prog, file)
char *prog, *file;
{
extern int errno;
fprintf(stderr, "%s -- ", prog);
if(errno)
perror(file);
else
fprintf(stderr, "%s: %s\n", file, emesg[xerrno]);
}
tinit(name)
char *name;
{
char *termptr;
char tbuf[TERMBUF], *tmp;
int intr();
#ifdef BSD
int stop();
#endif
termptr = termbuf;
tgetent(tbuf, name);
tmp = tgetstr("pc", &termptr);
if(tmp) PC = *tmp;
UP = tgetstr("up", &termptr);
BC = tgetstr("bc", &termptr);
cm = tgetstr("cm", &termptr);
cs = tgetstr("cs", &termptr);
sf = tgetstr("sf", &termptr);
sr = tgetstr("sr", &termptr);
ce = tgetstr("ce", &termptr);
cl = tgetstr("cl", &termptr);
al = tgetstr("al", &termptr);
dl = tgetstr("dl", &termptr);
us = tgetstr("us", &termptr);
ue = tgetstr("ue", &termptr);
so = tgetstr("so", &termptr);
se = tgetstr("se", &termptr);
ti = tgetstr("ti", &termptr);
te = tgetstr("te", &termptr);
li = tgetnum("li");
co = tgetnum("co");
xn = tgetflag("xn");
nlines=li-3;
#ifdef USG
ioctl(1, TCGETA, &rawbuf);
cookedbuf = rawbuf;
rawbuf.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
rawbuf.c_cc[VMIN] = 1;
rawbuf.c_cc[VTIME] = 0;
#else
gtty(1, &sgbuf);
ospeed=sgbuf.sg_ospeed;
quickmode=ospeed<10;
cookflags=sgbuf.sg_flags;
sgbuf.sg_flags = (sgbuf.sg_flags&~ECHO)|CBREAK;
rawflags=sgbuf.sg_flags;
#endif
signal(SIGINT, intr);
#ifdef BSD
signal(SIGTSTP, stop);
#endif
rawtty();
}
int tmode=0;
entty()
{
if(!tmode)
outs(ti);
tmode=1;
}
extty()
{
if(tmode)
outs(te);
tmode=0;
}
rawtty()
{
#ifdef USG
ioctl(1, TCSETA, &rawbuf);
#else
sgbuf.sg_flags=rawflags;
stty(1, &sgbuf);
#endif
entty();
}
cooktty()
{
#ifdef USG
ioctl(1, TCSETA, &cookedbuf);
#else
sgbuf.sg_flags=cookflags;
stty(1, &sgbuf);
#endif
extty();
}
intr()
{
int intr();
signal(SIGINT, intr);
intrup=1;
bell();
}
#ifdef BSD
stop()
{
int stop();
signal(SIGTSTP, stop);
intrup=1;
tend();
kill(getpid(), SIGSTOP);
rawtty();
display_up=0;
}
#endif
tend()
{
cmdline();
cooktty();
fflush(stdout);
}
char *
pwd()
#ifdef GETCWD
{
static char mydir[FILENAME+1] = "";
char *getcwd();
return getcwd(mydir, FILENAME);
}
#else
{
static char mydir[FILENAME] = "";
int status;
int pip[2];
int n;
int (*sigs[2])();
sigs[0] = signal(2, 1);
sigs[1] = signal(3, 1);
if(pipe(pip)<0)
return 0;
if(!fork()) {
close(1);
dup(pip[1]);
close(pip[0]);
execl("/bin/pwd", "pwd", 0);
exit(-1);
}
close(pip[1]);
wait(&status);
signal(2, sigs[0]);
signal(3, sigs[1]);
if(status) {
close(pip[0]);
return "/";
}
n = read(pip[0], mydir, FILENAME);
close(pip[0]);
if(n<=0)
return "/";
mydir[n-1] = 0;
return mydir;
}
#endif
browse()
{
int c;
char *env;
if(env=getenv("BROWSE"))
macptr = env;
defmacs();
newdir();
redraw();
ended=0;
do {
if(intrup) {
intrup=0; /* clear interrupt */
cmdline(); /* go to the command line */
outs("Interrupt"); /* let us know about it */
endmac(); /* clear macros */
clearin(); /* and input buffer */
}
here_i_am();
fflush(stdout);
c = getch();
cmd(c);
}
while(!ended);
}
clearin()
{
fseek(stdin, 0L, 1); /* stay here messily */
}
cmd(c)
char c;
{
int i;
if(intrup)
return;
switch(c) {
case ' ':
if(isdir(entries[curr])) {
if(!cd(entries[curr]->e_name))
wperror(entries[curr]->e_name);
} else
if(!macro(c))
bell();
else
cmd(getch());
break;
case '&':
syscom(0);
break;
case '!':
syscom(1);
break;
case '=':
todir();
break;
case '?':
sample(entries[curr]->e_name);
break;
case '[':
define();
break;
case 'B'-'@':
prev(nlines);
break;
case 'D'-'@':
next(nlines/2);
break;
case 'F'-'@':
next(nlines);
break;
case 'H':
curr=top;
break;
case 'J':
tail();
break;
case 'K':
home();
break;
case 'L'-'@':
redraw();
break;
case 'L':
curr=bottom-1;
break;
case 'M':
definitions();
break;
case 'N':
next(nlines);
break;
case 'P':
prev(nlines);
break;
case 'R':
move();
break;
case 'S':
savedefs();
break;
case 'U'-'@':
prev(nlines/2);
break;
case 'D':
case 'd':
if(getch()==c && !intrup)
remove(c=='D');
else
bell();
break;
case 'h':
ccol=0;
break;
case 'l':
ccol=NCOL;
break;
case '<':
quickmode=1;
if(display_up) {
todump=1;
at(0, 1);
header();
}
break;
case '+': case '^':
addname(c);
break;
case '(':
addperm();
break;
case ')':
delperm();
break;
case '>':
quickmode=0;
if(display_up) {
todump=1;
at(0, 1);
header();
}
break;
case 'J'-'@':
case 'j':
newline();
break;
case 'K'-'@':
case 'k':
upline();
break;
case 'n':
next(nlines/2);
break;
case 'p':
prev(nlines/2);
break;
case 'q': case 'Z': case 'Q':
if(getchar()==c && !intrup)
ended=1;
else
bell();
break;
case 'r':
reload();
break;
case 't':
tag();
break;
case 'T': case 'U':
tag_all(c=='T');
break;
default:
if(!macro(c))
bell();
else
cmd(getch()); /* make sure it does something */
} /* and thus avoid unneeded redraws */
}
cmdline()
{
at(0, li-1);
outs(ce);
}
newdir()
{
if(display_up)
at(0,0);
fflush(stdout);
dot=pwd();
if(!getdir())
wperror(dot);
curr=0;
top=0;
topline();
if(display_up)
todump=TRUE;
}
reload()
{
getdir();
curr=(curr>=bottom)?bottom-1:curr;
if(display_up) {
topline();
todump=TRUE;
}
}
topline()
{
if(display_up)
at(0,0);
printf("%s: %d files", dot, nentries);
nl();
}
redraw()
{
outs(cl);
display_up=0;
topline();
at(0,1);
header();
todump=1;
display_up=1;
}
dumpdata()
{
at(0,2);
dump(top,bottom);
if(top+nlines>nentries) {
int i;
at(0, bottom-top+2);
for(i=bottom-top; i<nlines; i++) {
outc('~');
nl();
}
}
}
upline()
{
if(curr>0)
curr--;
else bell();
}
home()
{
curr=0;
}
next(l)
{
curr += l;
if(curr>=nentries) curr=nentries-1;
}
prev(l)
{
curr -= l;
if(curr<0) curr=0;
}
tail()
{
curr=nentries-1;
}
newline()
{
if(curr<nentries-1)
curr++;
else
bell();
}
here_i_am()
{
int c;
if(*macptr)
return;
if(todump)
display_up = 1;
if(!display_up) {
cmdline();
statout(entries[curr]->e_name,
&entries[curr]->e_stat,
entries[curr]->e_uname,
entries[curr]->e_gname,
entries[curr]->e_flags);
at(quickmode?1:ccol, li-1);
fflush(stdout);
if((c=getch())=='\n') {
redraw();
here_i_am();
}
else
ungetch(c);
} else if(todump) {
if(!(curr-top > 0 && curr-top < nlines)) {
top = curr-nlines/2;
if(top<0) top=0;
}
dumpdata();
at(quickmode?1:ccol, curr-top+2);
todump=0;
} else {
int lines_to_scroll = curr-top;
if(lines_to_scroll > 0)
if((lines_to_scroll -= nlines-1) < 0)
lines_to_scroll = 0;
if(lines_to_scroll < 1-nlines) {
top=curr;
at(0,2);
dump(top, bottom);
} else if(lines_to_scroll > nlines-1) {
top=curr-nlines+1;
at(0,2);
dump(top, bottom);
} else if(lines_to_scroll) {
scroll(2, nlines+2, lines_to_scroll);
top += lines_to_scroll;
if(lines_to_scroll < 0) {
at(0, 2);
dump(top, top-lines_to_scroll);
} else {
at(0, 2+nlines-lines_to_scroll);
dump(bottom-lines_to_scroll, bottom);
}
}
at(quickmode?1:ccol, curr-top+2);
}
}
bell()
{
outc(7);
}
perform(command)
char *command;
{
char cmdbuf[MAXLINE];
cmdline();
extty();
outc('!');
printf(command, entries[curr]->e_name);
sprintf(cmdbuf, command, entries[curr]->e_name);
system(cmdbuf, 1);
entty();
}
system(command, rdflag)
char *command;
int rdflag; /* Should I redraw? */
{
char scratch[32];
int status;
int (*sigint)(), (*sigquit)();
char c;
sigint=signal(2, 1);
sigquit=signal(3, 1);
cooktty();
fflush(stdout);
strcpy(scratch, entries[curr]->e_name);
if(!fork()) {
int i;
static char *envp[MAXARGC];
static char env[NCARGS];
char *hold;
char line[MAXLINE];
char *tmp;
signal(2,0);
signal(3,0);
if(!(efp=fopen(efname, "r"))) {
fputc('\n', stderr);
perror(efname);
execl(SHELL, SHELL, "-c", command, 0);
execl("/bin/sh", "sh", "-c", command, 0);
perror("/bin/sh");
exit(-77);
}
i=0;
tmp=hold=env;
while(!feof(efp)) {
fgets(line, MAXLINE, efp);
if(strlen(line)+(tmp-env)>NCARGS)
break;
if(line[0]=='$')
if(tmp>hold) {
envp[i] = hold;
i++;
if(i > MAXARGC-2) break;
tmp[-1]=0; /* eat line-feed at end */
hold = tmp;
}
strcpy(tmp, line+(line[0]=='$'));
tmp += strlen(tmp);
}
if(tmp>hold) {
envp[i] = hold;
i++;
tmp[-1]=0; /* and eat this one as well */
}
sprintf(tmp, "FILE=%s", scratch);
envp[i++]=tmp;
envp[i]=0;
if(rdflag)
putchar('\n');
else
putchar('\r');
fflush(stdout);
execle(SHELL, SHELL, "-c", command, 0, envp);
execle("/bin/sh", "sh", "-c", command, 0, envp);
perror("/bin/sh");
exit(-77);
}
wait(&status);
signal(2, sigint);
signal(3, sigquit);
rawtty();
if(rdflag || status!=0)
display_up=0;
}
char
inps(buf, text, termin)
char *buf;
char *text;
char termin;
{
int i = 0;
char c, *ptr, *txp;
txp=text?text:"!";
while(!intrup &&
(fflush(stdout), c=getch()) != '\033' &&
c != '\n' &&
c != termin)
switch(c) {
case '\b':
case '\177':
if(i>0) {
printf("\b \b");
i--;
}
else
bell();
break;
case 'U'-'@':
txp=text?text:"!";
case 'X'-'@':
if(i>0)
while(i>0) {
printf("\b \b");
i--;
}
else
bell();
break;
case 'K'-'@':
if(*txp)
ctloutc(buf[i++] = *txp++);
break;
case '%':
for(ptr=entries[curr]->e_name; *ptr; ptr++)
ctlout(buf[i++] = *ptr);
standend();
break;
case '#':
for(ptr=dot; *ptr; ptr++)
ctlout(buf[i++] = *ptr);
standend();
break;
case '~':
for(ptr=HOME; *ptr; ptr++)
ctlout(buf[i++] = *ptr);
standend();
break;
case '@':
outc(c);
fflush(stdout);
c = getch();
if(!macro(c)) {
ungetch(c);
buf[i++]='@';
}
else
outs("\b \b");
break;
case '$':
outc(c);
fflush(stdout);
c = getch();
if(c=='$') {
char tmp[10];
sprintf(tmp, "%d", getpid());
outs("\b \b");
for(ptr=tmp; *ptr; ptr++)
ctlout(buf[i++] = *ptr);
standend();
}
else if(!macbuf[c]) {
ungetch(c);
buf[i++]='$';
}
else {
outs("\b \b");
for(ptr=macbuf[c]; *ptr; ptr++)
ctlout(buf[i++] = *ptr);
standend();
}
break;
case '!':
while(*txp)
ctlout(buf[i++] = *txp++);
standend();
break;
case '\\':
outc(c);
fflush(stdout);
c=getch();
if(c=='~' || c=='%' || c=='#' ||
c=='\\' || c=='!' ||
c=='K'-'@' || c=='U'-'@' || c=='X'-'@' ||
c=='\b' || c=='\177' ||
c==termin || c=='\033' || c=='\n' ||
c=='@' || c=='$') {
outc('\b');
ctloutc(buf[i++]=c);
break;
}
else if(c>='0' && c<='7') {
int n, val=0;
for(n=0; n<3 && c>='0' && c<='7'; n++) {
val = val*8 + c-'0';
outc('\b');
ctloutc(val);
c=getch();
}
ungetch(c);
c=buf[i++]=val;
break;
}
else if(c=='^') {
outc('\b');
outc('^');
fflush(stdout);
c=getch();
if(c>='?'&&c<='_') {
outc('\b');
ctloutc(buf[i++]=(c-'@')&'\177');
break;
}
else if(c>='`'&&c<='~') {
outc('\b');
ctloutc(buf[i++]=c-'`');
break;
} /* otherwise default */
else buf[i++]='^'; /* after adding caret */
} /* otherwise fall through to default */
else buf[i++]='\\'; /* after adding backslash */
default:
ctloutc(buf[i++] = c);
break;
}
buf[i] = 0;
return intrup?'\033':c;
}
ctlouts(s)
char *s;
{
int cnt = 0;
while(*s)
cnt += ctlout(*s++);
cnt += standend();
return cnt;
}
ctloutc(c)
char c;
{
int cnt;
cnt = ctlout(c);
cnt += standend();
return cnt;
}
int somode = 0;
int ulmode = 0;
standout()
{
if(!somode) {
outs(so);
somode = 1;
if(xn) return 1;
}
return 0;
}
underline()
{
if(!ulmode) {
outs(us);
ulmode = 1;
if(xn) return 1;
}
return 0;
}
standend()
{
int cnt = 0;
if(somode) {
outs(se);
somode = 0;
if(xn) cnt++;
}
if(ulmode) {
outs(ue);
ulmode = 0;
if(xn) cnt++;
}
return cnt;
}
ctlout(c)
char c;
{
int cnt = 0;
if(c&'\200') {
cnt += underline();
cnt += ctlout(c&'\177');
return cnt;
}
else if(c<' ' || c=='\177') {
cnt += standout();
outc((c+'@')&'\177');
cnt++;
return cnt;
}
else {
cnt += standend();
outc(c);
cnt++;
return cnt;
}
}
todir()
{
char cmdbuf[MAXLINE];
static char lastdir[MAXLINE] = ".";
char *slash, *rindex();
cmdline();
printf("goto ");
if(inps(cmdbuf, lastdir, 0)!='\033' && cmdbuf[0]) {
strcpy(lastdir, cmdbuf);
if(!cd(cmdbuf, 0)) {
if(!fgoto(cmdbuf))
if(slash=rindex(cmdbuf, '/')) {
*slash++=0;
if(cd(cmdbuf, 1)) {
if(!fgoto(slash)) {
errno=0;
xerrno=NOMATCH;
wperror(slash);
}
} else
wperror(cmdbuf);
} else
wperror(cmdbuf);
}
}
else
killcmd();
}
fgoto(file)
char *file;
{
int i;
for(i = 0; i<nentries; i++)
if(match(entries[i]->e_name, file)) {
curr=i;
return 1;
}
return 0;
}
match(target, sample)
char *target, *sample;
{
while(*sample && *target==*sample) {
target++;
sample++;
}
return !*sample;
}
killcmd()
{
if(!intrup) {
cmdline();
printf("Command killed");
if(!display_up)
nl();
}
}
cd(dir, flag)
char *dir;
int flag;
{
if(flag) {
cmdline();
printf("cd %s\r", dir);
}
else
outc('\r');
fflush(stdout);
if(access(dir, 5)==0 && chdir(dir)==0) {
newdir();
return 1;
}
return 0;
}
syscom(rd)
int rd; /* should I redraw? */
{
char buf[MAXLINE];
static char lastcmd[MAXLINE] = "";
char inps();
cmdline();
extty();
putchar(rd?'!':'&');
if(inps(buf, lastcmd, 0)=='\033') {
entty();
killcmd();
return;
}
else
strcpy(lastcmd, buf);
system(buf, rd);
entty();
}
isdir(entry)
struct entry *entry;
{
return((entry->e_stat.st_mode&S_IFMT)==S_IFDIR);
}
sample(name)
char *name;
{
int col;
int c, i;
FILE *tfp;
if(!(tfp = fopen(name, "r"))) {
wperror(name);
return;
}
i=0;
do {
cmdline();
col = 0;
for(c=fgetc(tfp); col<72 && !feof(tfp); c=fgetc(tfp))
col+=ctlout(c);
standend();
if(display_up)
outc('\r');
else
outc('\n');
}
while(!feof(tfp) && (i=getch())=='?');
fclose(tfp);
if(i && i!=' ' && i!='q' && i!='?')
ungetch(i);
}
macro(c)
char c;
{
if(c==NOMAC)
return 0;
else if(!macbuf[c])
return 0;
else if(c==c_macro) {
cmdline();
printf("Recursive macro.");
endmac();
return 0;
}
else {
c_macro = c;
macptr = macbuf[c];
return 1;
}
}
getch()
{
char c;
if(ungetptr>ungetbuf)
return *--ungetptr;
if(*macptr)
if(*macptr=='\007') {
macptr++;
if(*macptr!='\007')
return getchar();
else {
if((c=getchar()) != '\n')
macptr--;
else
macptr++;
return (c=='\n')?getch():c;
}
}
else if(*macptr=='\\') {
if(macptr[1]=='\007')
macptr++;
return *macptr++;
}
else
return *macptr++;
else {
endmac();
return getchar();
}
}
endmac() {
c_macro=NOMAC;
macptr="";
}
ungetch(c)
char c;
{
if(ungetptr-ungetbuf>SMALLBUF)
return;
*ungetptr++=c;
}
define()
{
int c;
char buf[SMALLBUF];
cmdline();
printf("define ");
c = getch();
if(intrup)
return;
ctloutc(c);
printf(" as [");
if(inps(buf, macbuf[c], ']')=='\033') {
killcmd();
return;
}
printf("]");
defent(c, buf);
}
defent(c, buf)
char c;
char *buf;
{
if(macbuf[c])
free(macbuf[c]);
if(!buf[0]) {
macbuf[c]=0;
return;
}
macbuf[c] = (char *)malloc(strlen(buf)+1);
if(!macbuf[c]) {
cmdline();
printf("No room");
return;
}
strcpy(macbuf[c], buf);
}
defmacs()
{
defent(' ', "!more %\n");
defent('%', "!%\n");
defent('.', "=.");
defent('/', "=/");
defent('~', "=~");
defent('v', "!vi %\n");
defent('$', "!vi /tmp/br.env.$$\n");
}
definitions()
{
char *ptr;
int i;
cmdline();
for(i=0; i<CHARSET; i++)
if(macbuf[i]) {
printf("define ");
ctloutc(i);
printf(" as [");
ctlouts(macbuf[i]);
printf("]\n");
}
display_up=0;
}
savedefs()
{
int i;
char filename[MAXLINE];
static char lastfile[MAXLINE] = "/usr/tmp/macros";
FILE *fp;
cmdline();
outs("Save macros as ");
if(inps(filename, lastfile, '\033')=='\033') {
killcmd();
return;
}
strcpy(lastfile, filename);
if(!(fp = fopen(filename, "w"))) {
wperror(filename);
return;
}
for(i=1; i<CHARSET; i++)
if(macbuf[i])
fprintf(fp, "[%c%s]\n", i, macbuf[i]);
fclose(fp);
}
dumpenv(envp)
char **envp;
{
if(!(efp=fopen(efname, "w"))) {
fperror(efname);
exit(-1);
}
while(*envp)
fprintf(efp, "$%s\n", *envp++);
fflush(efp);
}