/***
*dirent.c - disked disk directory maintenence.
*
*Copyright (c) 1993-1995, Gregg Jennings. All wrongs reserved.
* P O Box 200, Falmouth, MA 02541-0200
*
*Purpose:
* Handles the displaying and editing of directory sectors.
*
*Notice:
* This progam may be freely used and distributed. Any distrubution
* with modifications must retain the above copyright statement and
* modifications noted.
* No pulp-publication, in whole or in part, permitted without
* permission (magazines or books).
*******************************************************************************/
/*
Versions:
1.3 13-Nov-1993 more use of structures, cleaned up changedir()
1.2 14-Jan-1994 =0 bug fix in changedir()
1.1 13-Nov-1993 Started structures
1.0 June 1993
Release Notes:
This is all "Brute Force" code. Written in a couple a days after
I wanted to arange all my directories is a certain non-sorted way
easier than a touch program.
*/
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
#include "mylib.h" /* getnum() */
#include "keys.h"
#include "dirent.h" /* DosTime, DosDate, dDIR */
#include "console.h" /* input, output, cursor stuff */
/* NO globals referenced here */
/* NO globals defined here */
#define isexten(c) ( (c>0x7f) && (c<255) )
static int command(int c);
static int text(int len, unsigned char *b);
static int attrib(unsigned char *b);
static int dostime(DosTime time, DosTime *t);
static int dosdate(DosDate date, DosDate *d);
static int pdirent(dDIR *);
/* ...filename.txt...ttri...hh:mm:ss...mm/dd/yy...1234567...1234567 */
static char
*dir_header=" File Attr Time Date Cluster Size\n";
/* display directory */
extern void dumpdir(unsigned char *buf, int sec_size)
{
int i;
dDIR *dir = (dDIR *)buf;
output('\n');
output('\n');
print(dir_header); /* print header */
for (i = 0; i < sec_size; i+=sizeof(dDIR),dir++) /* and each entry */
{
output('\n');
put(3,' ');
pdirent(dir);
}
output('\n');
}
/* change dir command structure */
/* ...filename.txt...ttri...hh:mm:ss...mm/dd/yy...1234567...1234567 */
struct fields {
int beg; /* starting column */
int end; /* ending column */
int (*inp)(); /* function to do the change */
} field[] = {
{4,7, command},
{9,16, text},
{18,20,text},
{24,28,attrib},
{32,33,dostime},
{43,44,dosdate},
};
/***
*changedir() - edit directory entry(s) in sector buffer
*
* ver 1.1 fixed =0 bug
****/
#define NUMFIELDS (sizeof(field)/sizeof(struct fields)-1)
#define LASTENTRY ((int)(sec_size/sizeof(dDIR))-1)
extern int changedir(unsigned char *buf,int sec_size)
{
int i;
unsigned int a,x;
unsigned int *b;
unsigned int c;
unsigned int n;
int o; /* offset into buffer (dDIR pointer) */
int r;
int p; /* absolute position */
int f; /* field in */
get_cursor(&a,&x);
print("\n\n %s",dir_header);
i = r = 0;
for (;;)
{
c = f = 0; /* start off at command function */
p = field[f].beg;
print("\n%03d ",i+1);
o = i*sizeof(dDIR);
r = pdirent((dDIR *)(buf+o));
get:
set_cursor(a,p);
switch (f)
{
case 0: /* command */
c = (*field[f].inp)(r); /* arg: entry type */
break;
case 1: /* file name */
c = (*field[f].inp)(8,buf+o); /* args: length, char* */
break;
case 2: /* file extension */
c = (*field[f].inp)(3,buf+o+8); /* args: length, char* */
break;
case 3: /* attribute */
c = (*field[f].inp)(buf+o+11); /* arg: int* */
break;
case 4: /* time */
b=(unsigned int *)(buf+o+0x16); /* arg: DosTime* */
c = (*field[f].inp)(*b,b);
break;
case 5: /* date */
b=(unsigned int *)(buf+o+0x18); /* arg: DosDate* */
c = (*field[f].inp)(*b,b);
break;
}
/* deal with key returned from functions */
switch (c) /* convert scancodes to ASCII */
{
case RIGHT: /* next field */
case CRIGHT:
c = '\t';
break;
case SHTAB: /* previous field */
case CLEFT:
case LEFT:
c = 0x7f;
break;
case DOWN: /* next entry */
c = '\r';
break;
case UP: /* previous entry */
c = '\b';
break;
default:
c &= 0xff; /* convert to ASCII */
break;
}
/* ASCII */
switch (c)
{
case 0x7f: /* previous field */
if (f > 0)
p = field[--f].beg;
break;
case '\t': /* next field */
if (f < NUMFIELDS)
p = field[++f].beg;
break;
case '\r':
case ' ': /* next entry */
if (i == LASTENTRY) /* if at end */
{ /* wrap */
i = 0;
print("\n\n %s",dir_header); /* redisplay header */
}
else
i++;
continue; /* redisplay entry */
break;
case '\b': /* previous entry */
if (i == 0) /* if at beginning */
{ /* wrap */
i = LASTENTRY;
print("\n\n %s",dir_header); /* redisplay header */
}
else
i--;
continue;
break;
case '=': /* select entry */
output(c);
if (getnum(sec_size/sizeof(dDIR),&n,10) > 0 && n > 0)
i = n-1;
continue;
break;
case '/':
case '?':
print("\n\n\tCR/SP next file");
print("\n\tBS previous file");
print("\n\tTAB next field");
print("\n\tSHTAB previous field");
print("\n\t=n goto file n");
print("\n\t'C' goto filename");
print("\n\t.|ESC exit\n");
continue;
break;
case '.':
case ESC:
output('\n');
return 0;
break;
default:
if (isalnum(c)) /* letter? */
{
int j;
c = toupper(c);
for (j = i+1; ;j++)
{
if (j > LASTENTRY)
j = 0;
if (*(buf+(j*sizeof(dDIR))) == c)
break;
if (j == i)
break;
}
if (j != i)
{
i = j;
continue;
}
}
break;
}
goto get;
}
}
static int command(int c)
{
int i;
i = scankey();
if (c < 1 && (i==RIGHT || i==TAB))
i = 0;
return i;
}
/***
*text() -- edit a text entry (filename/ext)
*
* can enter ALL printable characters including '.' and ' '
****/
static int text(int len, unsigned char *buf)
{
int c;
int i;
for (i=0;;)
{
c=scankey();
if (c==RIGHT)
{
if (i==len-1)
break;
curright();
++i;
continue;
}
if (c==LEFT || c==BACKSP)
{
if (!i)
break;
--i;
curleft();
continue;
}
if (c==RETURN || c==TAB || c==SHTAB || c==DOWN || c==UP)
break;
if (c==ESCAPE)
return(0);
if (c>0x352f) continue;
c&=0xff;
if (isgraph(c) || isexten(c))
{
*(buf+i)=(char)c;
i++;
output(c);
if (i==len)
{
c=RIGHT;
break;
}
}
}
return(c);
}
/***
*attrib() - toggle filename attributes, except for dir
*
****/
static int attrib(unsigned char *buf)
{
int i;
int b,c,p,d;
byte isvol;
/* 01234 */
/* RHSDA */
isvol = (byte)(*buf&8);
b=d=p=0; /* no need to set d,b but it gets rid of */
/* MSC warning C4701 */
for (;;)
{
i=scankey();
if (i==RETURN || i==TAB || i==SHTAB || i==DOWN || i==UP)
break;
if (i==ESCAPE)
{
i=0;
break;
}
if (i==RIGHT)
{
if (p==4) /* end */
break;
curright();
++p;
continue;
}
if (i==LEFT || i==BACKSP)
{
if (p==0)
break;
--p;
curleft();
continue;
}
if ( !isvol && p!=3 && (i&0xff)==' ')
{
if (p==0)
{
b=1;
d='R';
}
else if (p==1)
{
b=2;
d='H';
}
else if (p==2)
{
b=4;
d='S';
}
else if (p==4)
{
b=0x20;
d='A';
}
if (*buf&b)
{
c='_';
*buf&=~b;
}
else
{
c=d;
*buf|=b;
}
output(c);
curleft();
}
}
return(i);
}
static int dostime(DosTime time, DosTime *t)
{
int i;
int h,m,s;
unsigned int r,x;
int c,p;
/* 01234567 */
/* hh:mm:ss */
get_cursor(&r,&x);
c = x; /* set starting column */
p = c; /* set the working column pointer */
h = time.hours; /* set the working values */
m = time.minutes;
s = time.seconds;
for (;;)
{
set_cursor(r,p);
i=scankey();
if (i==TAB || i==RETURN || i==SHTAB || i==DOWN || i==UP)
return(i);
if (i==ESCAPE)
{
i=0;
break;
}
if (i==LEFT || i==BACKSP)
{
if (p==c && i==LEFT)
return(i);
if (p==c && i==BACKSP)
continue;
if (p==c+3 || p==c+6)
p-=2;
else
p--;
continue;
}
right:
if (i==RIGHT)
{
if (p==c+7)
return(i);
if (p==c+1 || p==c+4)
p+=2;
else
p++;
continue;
}
i&=0xff;
if (isdigit(i))
{
output(i);
i=i-'0'; /* convert ascii to bin */
/* based on column, */
/* calculate new time with the */
/* number input */
if (p==c)
h=(i*10)+(h%10);
else if (p==c+1)
h=i+((h/10)*10);
else if (p==c+3)
m=(i*10)+(m%10);
else if (p==c+4)
m=i+((m/10)*10);
else if (p==c+6)
s=(i*10)+(s%10);
else if (p==c+7)
s=i+((s/10)*10);
time.hours = h;
time.minutes = m;
time.seconds = s;
*t = time;
i = RIGHT;
goto right;
}
}
return i;
}
/***
*dosdate() - edit date field
*
* ver 1.1 fixed right arrow at last number from wrapping
****/
static int dosdate(DosDate date, DosDate *dt)
{
int i;
int m,d,y;
unsigned int r,x;
int c,p;
/* 01234567 */
/* mm/dd/yy */
get_cursor(&r,&x);
c = x;
p = c;
m = date.month;
d = date.day;
y = date.year+80;
for (;;)
{
set_cursor(r,p);
i=scankey();
if (i==TAB || i==RETURN || i==SHTAB || i==DOWN || i==UP)
break;
if (i==ESCAPE)
return 0;
if (i==LEFT || i==BACKSP)
{
if (p==c && i==LEFT)
return(i);
if (p==c && i==BACKSP)
continue;
if (p==c+3 || p==c+6)
p-=2;
else
p--;
continue;
}
right:
if (i==RIGHT)
{
if (p==c+7)
continue;
if (p==c+1 || p==c+4)
p+=2;
else
p++;
continue;
}
i&=0xff;
if (isdigit(i))
{
output(i);
i=i-'0';
if (p==c)
m=(i*10)+(m%10);
else if (p==c+1)
m=i+((m/10)*10);
else if (p==c+3)
d=(i*10)+(d%10);
else if (p==c+4)
d=i+((d/10)*10);
else if (p==c+6)
y=(i*10)+(y%10);
else if (p==c+7)
y=i+((y/10)*10);
if (y>80)
y-=80;
else
y=0;
date.month = m;
date.day = d;
date.year = y;
y += 80;
*dt = date;
i=RIGHT;
goto right;
}
}
return i;
}
/***
*pdirent() - print directory entry
*
* Returns: 0 unused, 1 normal, -1 for directory or erased
*
* 1.2 11/12/94 references a dDIR structure, can't edit '.' dirs
* v1.1 removed superfluous pointer
****/
static int pdirent(dDIR *dir)
{
int i,r;
unsigned char c;
r = 1;
if (dir->name[0] == 0)
{
print(" unused");
r = 0;
}
else
{
/* set can't edit return flag */
if (dir->name[0] == 0xE5 || dir->name[0] == '.')
r = -1;
/* check for bad chars in case and non-dir sector is displayed */
for (i = 0; i < 8; i++)
{
c = dir->name[i];
if (isspace((int)c) || c==255 || !c || c==7 || c==8)
output(' ');
else
output(c);
}
output('.');
for (i = 0; i < 3; i++)
{
c = dir->ext[i];
if (isspace((int)c) || c==255 || !c || c==7 || c==8)
output(' ');
else
output(c);
}
print(" ");
if (dir->attr.volume)
print(" Vol ");
else
{
output(dir->attr.rdonly ? 'R' : '_');
output(dir->attr.hidden ? 'H' : '_');
output(dir->attr.system ? 'S' : '_');
output(dir->attr.subdir ? 'D' : '_');
output(dir->attr.archiv ? 'A' : '_');
}
print(" %02d:%02d:%02d",dir->time.hours,dir->time.minutes,dir->time.seconds);
print(" %02d/%02d/%02d",dir->date.month,dir->date.day,dir->date.year+80);
print(" % 7u",dir->start);
if (!dir->attr.subdir)
print(" % 7lu",dir->size);
}
return r;
}