This source file includes following definitions.
- main
- clear_all
- clone
- newname
- readent
- readent
- getdir
- at_current
- at_file
- disp_flags
- show_flags
- tag
- tagged
- delete_from_display
- delete_entry
- ins_at
- ins_entry
- domove
- addfile
- pname
- sortdir
- entcmp
- dump
- statout
- u_name
- g_name
- printime
- header
- triad
- pwd
- browse
- clearin
- name_of
- cmd
- macro
- newdir
- reload
- topline
- set_quickmode
- redraw
- dumpdata
- here_i_am
- bell
- system
- addstring
- inps
- ctlouts
- ctloutc
- ctlout
- get_index
- file_name
- enter
- isdir
- getch
- ungetch
#include <stdio.h>
#include "system.h"
#include <sys/param.h>
#ifndef M_XENIX
# include <sys/types.h>
#endif
#include <sys/stat.h>
#include <sys/dir.h>
#include <pwd.h>
#include <grp.h>
#ifdef BSD
# include <sys/time.h>
#else
# include <time.h>
#endif
#include <signal.h>
#ifndef MAXNAMLEN
# ifdef BSD
# define MAXNAMLEN 256
# else
# define MAXNAMLEN DIRSIZ
# endif
#endif
#define FALSE 0
#define TRUE 1
#define MAXENTS 1024
#define MAXID 16
#define MAXLINE 81
#define NCOL 64
#define MAXNAME 14
#define FILENAME 256
struct entry {
char *e_name;
int e_flags;
#define FTAGGED (1<<0)
#define FPERMANENT (1<<1)
struct stat e_stat;
char e_uname[9];
char e_gname[9];
}
*xentries[MAXENTS], **entries=xentries;
int nentries;
struct idtab {
int id_id;
char id_name[9];
}
u_list[MAXID],
g_list[MAXID];
int u_ptr=0, g_ptr=0;
int ccol=NCOL;
int quickmode;
int top, curr;
#define bottom ((top+nlines>nentries)?nentries:(top+nlines))
char *dot;
int nlines;
char display_up;
int todump=1;
int ended;
int intrup;
char *HOME;
char *SHELL;
char *getenv();
char *malloc();
#define NEW(t) (t *)malloc(sizeof (t))
#define NIL(t) ((t) 0)
main(ac, av)
int ac;
char **av;
{
if(ac>1) chdir(av[1]);
HOME=getenv("HOME");
SHELL=getenv("SHELL");
intrup=0;
if(tcl_init()) {
tinit(getenv("TERM"));
clear_all();
browse();
tend();
tcl_end();
}
exit(0);
}
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, buffer)
DIR *dp;
char *buffer;
{
struct direct *ptr;
do {
ptr = readdir(dp);
if(!ptr) return 0;
} while(ptr->d_ino == 0);
strcpy(buffer, ptr->d_name);
return 1;
}
#else
#define opendir(n) fopen(n, "r")
#define DIR FILE
readent(dp, buffer)
DIR *dp;
char *buffer;
{
struct direct db;
while(fread(&db, sizeof(struct direct), 1, dp)) {
if(db.d_ino) {
strncpy(buffer, db.d_name, MAXNAMLEN);
buffer[MAXNAMLEN] = 0;
return 1;
}
}
return 0;
}
#define closedir fclose
#endif
getdir()
{
char *u_name(), *g_name();
DIR *dp;
static char buffer[MAXNAMLEN+1];
int i, p;
if(!(dp = opendir("."))) {
save_errno(".");
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++) {
if(!entries[nentries]) {
entries[nentries] = NEW(struct entry);
if(!entries[nentries])
break;
entries[nentries]->e_name = NIL(char *);
}
if(!readent(dp, buffer))
break;
if(stat(buffer, &entries[nentries]->e_stat)==-1) {
closedir(dp);
save_errno(buffer);
return FALSE;
}
newname(entries[nentries], buffer);
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);
if(intrup)
return FALSE;
if(nentries>=MAXENTS || entries[nentries]==NIL(struct entry *)) {
save_errmsg(".: Directory too large");
return FALSE;
}
sortdir();
if(intrup) {
save_errmsg("Interrupted");
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;
}
disp_flags(flags)
{
outc((flags&FTAGGED)?'+':((flags&FPERMANENT)?'!':' '));
}
show_flags(ent)
{
if(!display_up) return;
if(ent < top || ent >= top+nlines) return;
at(quickmode?0:(ccol-1), ent-top+2);
disp_flags(entries[ent]->e_flags);
}
tag(ent, mode, bit)
{
switch(bit) {
case 'P': bit = FPERMANENT; break;
case 'T': bit = FTAGGED; break;
}
switch(mode) {
case -1: entries[ent]->e_flags &= ~bit; break;
case 0: entries[ent]->e_flags ^= bit; break;
case 1: entries[ent]->e_flags |= bit; break;
}
show_flags(ent);
}
tagged(ent)
{
return (entries[ent]->e_flags & FTAGGED) ? 1 : 0;
}
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_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;
}
}
}
ins_at(ent, i)
struct entry *ent;
int i;
{
struct entry *hold;
int j;
if(!entries[nentries]) {
entries[nentries] = NEW(struct entry);
if(!entries[nentries]) {
save_errno(ent->e_name);
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 *);
}
*entries[nentries] = *ent;
entries[nentries]->e_name = clone(ent->e_name);
if(!entries[nentries]->e_name) {
save_errno(ent->e_name);
return 0;
}
if(i != nentries) {
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 1;
scroll(2+i-top, 2+nlines, -1);
at(0, 2+i-top);
dump(i, i+1);
}
return 1;
}
ins_entry(ent)
struct entry *ent;
{
int i;
if(nentries >= MAXENTS) {
save_errmsg("Too many files");
return 0;
}
for(i = 0; i < nentries; i++)
if(entcmp(&ent, &entries[i]) < 0)
break;
return ins_at(ent, i);
}
domove(ent, new_name)
int ent;
char *new_name;
{
struct entry hold;
hold = *entries[ent];
if(link(entries[ent]->e_name, new_name)!=0) {
save_errno(entries[ent]->e_name);
return 0;
}
if(unlink(entries[ent]->e_name)!=0) {
save_errno(entries[ent]->e_name);
return 0;
}
hold.e_name = new_name;
hold.e_flags &= ~FTAGGED;
delete_entry(ent);
return ins_entry(&hold);
}
addfile(name)
char *name;
{
struct entry hold;
if(stat(name, &hold.e_stat)==-1) {
save_errno(name);
return FALSE;
}
hold.e_name = name;
hold.e_flags = 0;
strcpy(hold.e_uname, u_name(hold.e_stat.st_uid));
strcpy(hold.e_gname, g_name(hold.e_stat.st_gid));
return ins_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) {
outc('\b');
outc('>');
}
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);
}
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);
}
disp_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)
u_ptr = 0;
u_list[u_ptr].id_id=uid;
if(pwptr=getpwuid(uid)) {
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
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)
g_ptr = 0;
g_list[g_ptr].id_id=gid;
if(grptr=getgrgid(gid)) {
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
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()
{
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('-');
}
char *
pwd()
#ifdef GETCWD
{
static char mydir[FILENAME+1] = "";
char *getcwd();
return getcwd(mydir, FILENAME);
}
#else
{
static char buffer[FILENAME+1];
strcpy(buffer, "exec pwd");
if(tcl_call(buffer, sizeof buffer)) {
int len = strlen(buffer);
while(len > 0 && buffer[len-1] <= ' ')
len--;
buffer[len] = 0;
return buffer;
}
save_errmsg(buffer);
return 0;
}
#endif
browse()
{
int c;
newdir();
redraw();
ended=0;
do {
intrup=0;
here_i_am();
fflush(stdout);
c = getch();
cmd(c);
}
while(!ended);
}
clearin()
{
fseek(stdin, 0L, 1);
}
char *name_of(c)
int c;
{
static char *p, b[80];
int ctrl = 0;
p = b;
if(c & 0x80) {
c &= 0x7F;
strcpy(b, "meta_");
p += 5;
}
switch(c) {
case '\033':
strcpy(p, "escape");
return b;
case '\034':
strcpy(p, "ctrl_backslash");
return b;
case '\035':
strcpy(p, "ctrl_close_bracket");
return b;
}
if(c < ' ') {
c += '@';
ctrl = 1;
}
switch(c) {
case ' ': strcpy(p, "space"); break;
case '$': strcpy(p, "dollar_sign"); break;
case '\'': strcpy(p, "quote"); break;
case '"': strcpy(p, "double_quote"); break;
case ';': strcpy(p, "semicolon"); break;
case '{': strcpy(p, "open_brace"); break;
case '}': strcpy(p, "close_brace"); break;
case '\177': strcpy(p, "delete"); break;
case '\\': strcpy(p, "backslash"); break;
case '[': strcpy(p, "open_bracket"); break;
case ']': strcpy(p, "close_bracket"); break;
default:
if(ctrl)
sprintf(p, "'^%c'", c);
else
sprintf(p, "'%c'", c);
break;
}
return b;
}
cmd(c)
int c;
{
char buffer[80];
if(intrup) {
cmdline();
outs("Interrupt");
return;
}
sprintf(buffer, "key_%s\n", name_of(c));
if(!tcl_call(buffer, 80)) {
cmdline();
ctlouts(buffer);
if(!display_up) outc('\n');
bell();
}
}
char *macro(c)
int c;
{
static char buffer[80];
sprintf(buffer, "macro_%s\n", name_of(c));
if(tcl_call(buffer, 80))
return buffer;
else
return 0;
}
newdir()
{
int result = 1;
if(display_up)
at(0,0);
fflush(stdout);
dot=pwd();
if(!getdir())
result = 0;
curr=0;
top=0;
topline();
if(display_up)
todump=TRUE;
return result;
}
reload()
{
if(getdir()) {
curr=(curr>=bottom)?bottom-1:curr;
if(display_up) {
topline();
todump=TRUE;
}
return 1;
}
return 0;
}
topline()
{
if(display_up)
at(0,0);
printf("%s: %d files", dot, nentries);
nl();
}
set_quickmode(mode)
int mode;
{
if(quickmode != mode) {
quickmode = mode;
if(display_up) {
at(0,1);
header();
todump = 1;
}
}
}
redraw()
{
clear_screen();
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();
}
}
}
here_i_am()
{
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, nlines+2);
fflush(stdout);
} 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);
}
system(command)
char *command;
{
int status;
int pid;
SIGNAL (*sigint)(), (*sigquit)();
#ifdef BSD
SIGNAL (*sigtstp)();
#endif
sigint=signal(SIGINT, SIG_IGN);
sigquit=signal(SIGQUIT, SIG_IGN);
#ifdef BSD
sigtstp = signal(SIGTSTP, SIG_IGN);
#endif
end_screenmode();
cooktty();
fflush(stdout);
pid = fork();
if(pid == 0) {
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
#ifdef BSD
signal(SIGTSTP, SIG_DFL);
#endif
fflush(stdout);
execl(SHELL, SHELL, "-c", command, (char *)0);
execl("/bin/sh", "sh", "-c", command, (char *)0);
perror("/bin/sh");
exit(-77);
}
if(pid==-1) {
save_errno("browse");
status = -1;
} else
wait(&status);
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
#ifdef BSD
signal(SIGTSTP, sigtstp);
#endif
rawtty();
if(status & 0xFF)
return -(status&0xFF);
else
return (status&0xFF00)>>8;
}
addstring(ptr, buf, ip)
char *ptr, *buf;
int *ip;
{
while(*ptr)
ctlout(buf[(*ip)++] = *ptr++);
standend();
}
char
inps(buf, text, termin)
char *buf;
char *text;
char termin;
{
int i = 0;
char c, *txp;
char *s;
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 '\\':
outc(c);
fflush(stdout);
c=getch();
if( c=='\\' || c=='\b' || c=='\177' ||
c=='K'-'@' || c=='U'-'@' || c=='X'-'@' ||
c==termin || c=='\033' || c=='\n') {
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;
}
else buf[i++]='^';
}
else buf[i++]='\\';
default:
if(c=='V'-'@')
ctloutc(buf[i++] = getch());
if(s = macro(c))
addstring(s, buf, &i);
else
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;
}
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;
}
}
get_index(file)
char *file;
{
int i;
for(i = 0; i<nentries; i++)
if(strcmp(entries[i]->e_name, file) == 0)
return i;
return -1;
}
char *file_name(i)
int i;
{
if(i < 0 || i >= nentries)
return 0;
else
return entries[i]->e_name;
}
enter(dir)
char *dir;
{
if(access(dir, 5)==0 && chdir(dir)==0)
return newdir();
save_errno(dir);
return 0;
}
isdir(entry)
struct entry *entry;
{
return((entry->e_stat.st_mode&S_IFMT)==S_IFDIR);
}
getch()
{
return getchar();
}
ungetch(c)
char c;
{
ungetc(c, stdin);
}