Metropoli BBS
VIEWER: dirent.c MODE: TEXT (ASCII)
/***
*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;
}
[ RETURN TO DIRECTORY ]