Metropoli BBS
VIEWER: disklib.c MODE: TEXT (ASCII)
/***
*disklib.c - disked library
*
*Copyright (c) 1991-1995, Gregg Jennings.  All wrongs reserved.
*   P O Box 200, Falmouth, MA 02541-0200
*
*Purpose:
*   Main library functions.
*
*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

   2.7   18-Mar-1995    moved find() into SEARCH.C
   2.6   15-Mar-1995    file tracking stuff
   2.7   05-Mar-1995    rewrote dparams() to show everything
   2.6   10-Sep-1994    fixed %u on num_sectors in dparams()
                         complier checks in dparams()
   2.5   02-Sep-1994    consolodated print vs printf
   2.4   18-Apr-1994    removed text to data.c
   2.3   13-Mar-1994    find() changes
   2.2   01-Feb-1994    'dir_cluster' test bug fix
   2.1   04-Jan-1994    added Translate if !Files for startup
                        added 'dir_cluster'
                        help()
*/

#include <stdio.h>
#include <ctype.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include <malloc.h>
#include <errno.h>

#include "disked.h"
#include "diskio.h"
#include "mylib.h"
#include "files.h"
#include "keys.h"
#include "error.h"
#include "dpb.h"
#include "dirent.h"
#include "console.h"

/* static functions */

static void filename(unsigned int);


/* set to track, sector, head

   Passed pointer to string, number of values, and struct of type
   Msg which holds the messages to display for each value and
   the number of digits for each value.

   Modification of get() to return immediately on an 'f' or 'b'.

   Returns a string containing the values seperated by commas
   to be converted by sscanf().

   Globals: Display, Radix.

*/

extern int set(struct Msg *str, int *t, int *s, int *h)
{
register int c,i,n;
long l;
char ts[7];

   for (i = n = 0; n < 3; n++, i = 0, str++)
   {
      if (Display)
         print(str->msg);
      while ((c = input()) != '\r' && c != ' ' && c != ',')
      {
         if (n == 0 && i == 0 && (c == 'f' || c == 'b'))
         {
            output(c);                 /* special: Fat, Boot */
            return(c);
         }
         if (c == '\b' && i != 0)      /* backspace, delete number */
         {
            output(c);                 /* in buffer */
            output(' ');               /* and on screen */
            output(c);
            --i;                       /* move pointer back */
         }
         else if (c == 0x1b || c == 3) /* ESC, ^C to abort */
            return 0;                  /* RETURN */

         else if (Radix == 16 && !isxdigit(c))
            continue;
         else if (Radix==10 && !isdigit(c))
            continue;
         else
         {
            output(c);
            ts[i++] = (char)c;         /* save and echo numbers */
            if (i == str->len)
               break;
         }
      }
      ts[i] = '\0';
      if (i)
      {
         l = strtol(ts,NULL,Radix);    /* strtol() for radix */
         if (n == 0)
            *t = (int)l;
         else if (n == 1)
            *s = (int)l;
         else
            *h = (int)l;
      }
      if (c == '\r')
         break;
      if (!Display && n < 2)
         output(',');
   }
   return 1;
}

/*  get a string for conversion to numbers

   Passed pointer to string, number of values, and struct of type
   Msg which holds the messages to display for each value and
   the number of digits for each value.

   Returns a string containing the values seperated by commas
   to be converted by sscanf().

   Globals: Display, Radix.
*/

extern int get(struct Msg *str,int *one, int *two)
{
register int t,v;
char temp[7];

   for (t = 0; t < 2; t++, str++)
   {
      if (Display)
         print(str->msg);
      if (getstr(temp,str->len,(Radix == 16) ? _HEX : _DIGIT) > 0)
      {
         v = atoi(temp);
         if (t == 0)
            *one = v;
         else
            *two = v;
      }
      else
         return 0;                     /* RETURN */

      if (!Display && t < 1)
         output(',');
   }
   return 1;
}

/* get - long version */

extern int getl(struct Msg *str, long *one, int *two)
{
register int t;
int i;
char temp[7];
long l;

   for (t = 0; t < 2; t++, str++)
   {
      if (Display)
         print(str->msg);
      if ((i = getstr(temp,str->len,(Radix == 16) ? _HEX : _DIGIT)) > 0)
      {
         l = strtol(temp,NULL,Radix);
         if (t == 0)
            *one = l;
         else
            *two = (int)l;
      }
      else if (!t && i == -3)
         print("%l",*one);          /* putlong(*one); */
      else
         return 0;
      if (!Display && t < 1)
         output(',');
   }
   return(1);
}

/* display sector header */

extern void header(void)
{
register unsigned int i,j;

   print("\nSector %lu",log_sector);

   i = sectortocluster(log_sector);
   j = clustersector(log_sector)+1;

   if (log_sector > (dword)data_sector)
   {
      if (Radix == 10)
         print(", Cluster %u:%u",i,j);
      else
         print(", Cluster %x:%x",i,j);
   }
   else
   {  unsigned sector = (word)log_sector;
      if (sector < reserved_secs)
      {
         print("  BOOT");
         if (reserved_secs > 1)
            print(" %d:%d",sector+1,reserved_secs);
      }
      else if (sector >= reserved_secs && sector <= secs_fat)
         print("  FAT 1 %d:%d %d-BIT",
            sector-reserved_secs+1,secs_fat,fat_size);
      else if (num_fats > 1 && sector > secs_fat
         && sector <= (secs_fat*num_fats))
            print("  FAT 2 %d:%d %d-BIT",
               (sector-reserved_secs-secs_fat)+1,secs_fat,fat_size);
      else if (sector >= dir_sector && sector <= data_sector)
         print("  ROOT %d:%d",(sector-dir_sector)+1,dir_sectors);
   }
   if (!Logical)
      print(" (t%u,h%u,s%u)",track,head,sector);

   if (diskio_error)
      print(" <BAD>");
   if (Files > 0 && n_files)
      filename(i);
}

static void filename(unsigned int i)
{
   if (log_sector > (dword)data_sector && i < num_clusters)
   {
      if (clusters[i] > 0 && (unsigned)clusters[i] <= n_files)
      {
         output(' ');
         print(gfile(clusters[i]));
         if (files[clusters[i]].dir)
            print(" <DIR>");
      }
   }
}

/* display disk drive info

   Serial No:               Drive Size:              Root Sector:
   Buffer Size:             Sectors:                 Data Sector:
   DOS Version:             Sector Size:             Reserved Sectors:
   Number of Drives:        Clusters:                Hidden Sectors:
   Current Drive:           Cluster Size:            Tracks:
   Media:                   Secs/Cluster:            Heads:
   Volume:                  Number FATs:             Sectors:
   Serial ID:               Secs/FAT:                Sector Size:
   Current Dir:
*/

extern void dparams(char *drivedir)
{
   print("\n");

   print("\n Serial No:%s",Version);
   print("\t  Drive Size: %lu",drive_size);
   print("\t  Root Sector: %u",dir_sector);

   print("\n Buffer Size: %u",max_bytes);
   print("\t  Sectors: 0-%lu",num_sectors-1);
   print("\t  Data Sector: %u",data_sector);

#if defined(_MSC_VER)
   print("\n DOS Version: %d.%d.%d",_osmajor,_osminor,_osmode);
#elif defined(__WATCOM__)
   print("\n DOS Version: %d.%d.%d",_osmajor,_osminor,_osmode);
#else
   print("\n DOS Version: %d.%d",_osmajor,_osminor);
#endif
   print("\t  Sector Size: %u",sec_size);
   print("\t  Reserved Sectors: %u",reserved_secs);

   print("\n Number of Drives: %u",max_drive);
   print("\t  Clusters: 2-%u",num_clusters);
   print("\t  Hidden Sectors: %lu",hidden_secs);

   print("\n Current Drive: %c:",disk+'@');
   print("\t  Cluster Size: %u",cluster_size);
   print("\t  Tracks: 0-%u",max_track);

   print("\n Media: %s",format);
   print("\t  Sectors/Cluster: %u",secs_cluster);
   print("\t  Heads: 0-%u",max_head-1);

   print("\n Volume: %-11.11s", (volume[0]=='\0') ? "?" : volume);
   print("\t  Number FATs: %u",num_fats);
   print("\t  Sectors: 1-%u",max_sector);

   print("\n Serial ID:");
   print("\t\t  Sectors/FAT: %u",secs_fat);
   print("\t  Sector Size: %u",sec_size);

   print("\n Current Dir: %s",&drivedir[2]);
}

/*
   Read the next sector, display, continue.  Checks console for
   speed control and abort.
   pass: direction, forward or backward. value, number of sectors

   ver 1.1     9/91  added +1 to kbhit loop to correct '0' bug
*/

extern void range(int val)
{
register int i;
static int speed=4*50;
int io;
int c='4',b='4';

   for (;;)
   {
      if ((io = movesector(val)) != DISK_OK)
      {
         output('\n');
         printerror(Debug);
         if (io == DISK_NREADY)        /* door open! */
            break;
      }
      dumpsector();
      for (i = 0; i < speed; i++)      /* loop in wait */
         if (kbhit())
            c = input();
      if (isdigit(c))                  /* reset speed, the same if c */
      {
         speed = ((c-'0')*50+1);       /*  did not change */
         b = c;
      }
      else if (c == ' ')
      {
         input();
         c = b;
      }
      else
         break;
   }
}

/***
*dumpsector() - display sector buffer (front-end)
*
*  2.4 25-Nov-1994   BigScreen reference
*  2.3 01-Apr-1994   no '\n' if !Partial
*  2.2 01-Feb-1994   (dir_cluster && ) addtition
*  2.1 04-Jan-1994   added Translate if !Files for startup
****/

extern void dumpsector(void)
{
int i;
word sector;

   i = sectortocluster(log_sector);
   sector = (word)log_sector;

   if (Partial)
      output('\n');
   header();
   if (Translate)
   if (  (Files && clusters[i] > 0 && files[clusters[i]].dir)
      || (sector >= dir_sector && sector <= data_sector)
      || (dir_cluster && sectortocluster(log_sector) == dir_cluster)
      )
   {
      dumpdir(sec_buf,sec_size);
      return;
   }
   if (!Ascii)
   {
      if (BigScreen)
         dump(sec_buf,0,sec_size,sec_size,Radix);
      else if (Partial)
         dump(sec_buf,0,sec_size,128,Radix);
      else
         dumpf(sec_buf,sec_size,Radix);
   }
   else
      view(sec_buf,0,sec_size,NOPAUSE,Radix);
   if (Partial || Ascii)
      output('\n');
}

/***
*  display databuffer, displaying all non-printable
*  characters enclosed in <>
*
*  Another complicated, horrible looking function.
*
*  0.1   15-Mar-1995    ft_track
****/

view(
register unsigned char *buffer,    /* array of data */
unsigned int bfptr,                /* index into array */
unsigned int bufend,               /* size of array */
int pause,
int base)
{
register int c;
int length;
int p,n,nn,np;

   p = n = nn = np = 0;
   output('\n');
   if (pause)
   {
      length = 21;
      if (ft_track)
      {
         long l = filebytes();
         if (base == 10)
            print("%ld:\n",(long)bfptr + l);
         else
            print("%lx:\n",(long)bfptr + l);
      }
      else
      {
         if (base == 10)
            print("%u:\n",bfptr);
         else
            print("%x:\n",bfptr);
      }
   }
   else
   {
      length=sec_size;
      output('\n');
   }
   do
   {
      c = (int)buffer[bfptr++];
      if (bfptr > bufend)
      {
         bfptr = 0;
         break;
      }
      if (p > 75)
      {
         p = 0;
         ++n;
         ++nn;
         ++np;
      }
      if (!isprint(c) && !isspace(c))
      {
         if (Strip)           /* do we strip? */
            continue;
         if (Mask)            /* do we mask ? */
            c&=0x7f;
         else if (Convert)    /* do we convert? */
         {
            print("<%02x>",c);
            p+=4;
            continue;
         }
      }
      if (c==7 || c==255 || c==0 || c==8)
         continue;
      if (c=='\n')
      {
         n++;
         ++nn;
         p=0;
      }
      if (c!='\r')
      {
         output(c);
         p++;
      }
   } while (n<length);

   if (pause)
   {
      output('\n');
      pnlz(bfptr,(getlen(bfptr,base)),base);
      output(':');
   }
   return(bfptr);
}

/* lame attempt to display BOOT parameters */

void dumpboot(byte *buf)
{
struct BOOT b;
int i;

   memcpy(&b,buf,sizeof(struct BOOT));
   output('\n');
   switch(b.jump[0])
   {
      case 0xeb:
              print("JMP SHORT ");
              puthex(b.jump[1]);
              break;
      case 0xe9:
              print("JMP ");
              puthex(b.jump[1]);output(':');puthex(b.jump[2]);
              break;
      case 0xff:
      case 0xea:
              print("JMP other ");
              break;
      default:
              print("unknown");
   }
   output('\n');
   print("OEM name:\t\t\t");
   for (i=0;i<8;i++)
           print("%02X",b.name[i]);
   print("\nbytes per sector:                    %04X\n",b.sec_size);
   print("sectors per allocation unit:         %02X\n",b.secs_cluster);
   print("reserved sectors:                    %04X\n",b.reserved_secs);
   print("number of FATs:                      %02X\n",b.num_fats);
   print("number of root dir entries:          %04X\n",b.dir_entries);
   print("number of sectors in logical image:  %04X\n",b.num_sectors);
   print("media descriptor:                    %02X\n",b.media_desc);
   print("number of FAT sectors:               %04X\n",b.secs_fat);
   print("sectors per track:                   %04X\n",b.secs_track);
   print("number of heads:                     %04X\n",b.num_heads);
   print("number of hidden sectors:            %04X\n",b.hidden_sectors);
   print("high order number of hidden sectors: %04X\n",b.large_sectors);
   print("number of logical sectors:           %08X\n",b.total_sectors);

}

void help(void)
{
int c;

   print(" Dir Boot Fat ?");
   c = (int)(char)input();
   if (c == 'd')
      disptext(dir_help);
   else if (c == 'b')
      print(" not yet");
   else if (c == 'f')
      print(" not yet");
}

/***
*  Display data in a HEX-ASCII format, starting at buf, ending at
*  bufend.  Returns the number of bytes displayed.  bufend _must_
*  be a multiple of 128
*
*    unsigned char *buffer;  - array of data
*    unsigned int bfptr;     - index into array
*    unsigned int bufend;    - size of array
*    unsigned int len;       - number of bytes to display
*    int base;
*
*  0.2   15-Mar-1995    ft_track
*  0.1   15-Feb-1995    Filter
****/

int dump(unsigned char *buffer, unsigned int bfptr, unsigned int bufend,   \
         unsigned int len, int base)
{
register unsigned int c;
unsigned int l,n;
register int b;

   if (bfptr > bufend)
      bfptr = 0;
   if (len > bufend)
      len = bufend;
   n = bfptr;
   for (l = 0; l < len; l+=16)
   {
      if (ft_track)
      {
         long l = filebytes();
         if (base == 10)
            print("\n%08ld: ",(long)bfptr + l);
         else
            print("\n%06lx: ",(long)bfptr + l);
      }
      else
         print((base==10)?"\n%0*d: ":"\n%0*x: ",getlen(bufend,base),bfptr);

      for (b = 0; b < 16; b++)
      {
         c = buffer[bfptr];
         output( ((c>>=4) > 9) ? (c+0x57) : (c+'0'));
         c=buffer[bfptr];
         output( ((c&=0xf) > 9) ? (c+0x57) : (c+'0'));
         output(' ');
         if (++bfptr == bufend)
         {
            bfptr = 0;
            break;
         }
      }
      for (b = 0; b < 16; b++)
      {
          c = buffer[n];
          if (Filter)
             output( (c>=' ' && c<=0xfe) ? (c) : ('.'));
          else
          {
             charout( (c != 0 && c != 255) ? (c) : ('.'));
             curright();
          }
          if (++n == bufend)
          {
              n = 0;
              if (l < (len-16))
                 output('\n');
              break;
          }
      }
   }
   return bfptr;
}

/***
*dumpf   -  Display sector contents to the screen in HEX/ASCII.
*
*  Notes:   This fills the entire screen width, and for the output()
*           function, a CR/LF is automatically performed.  If Filter
*           is OFF, the charout() function (which uses the BIOS) does
*           not do this.
*
*  0.2   15-Mar-1995    ft_track
*  0.1   15-Feb-1995    Filter
****/

void dumpf(register unsigned char *buffer, int size, int base)
{
register int c;
int i,j;
int ptr;

   output('\n');
   for (ptr = i = 0; i < size; i += 24)
   {
#if 0                                        /* for this dump, file tracking */
      if (ft_track)                          /* offset display messes things */
      {                                      /* up */
         long l = filebytes();
         if (base == 10)
            print("%08ld: ",(long)i + l);
         else
            print("%06lx: ",(long)i + l);
      }
      else
#endif
         print((base==10)?"%0*d: ":"%0*x: ",getlen(size,base),i);

      for (j = 1; j <= 24; j++)
      {
         c = buffer[ptr];
         output( ((c>>=4) > 9) ? (c+0x57) : (c+'0'));
         c = buffer[ptr];
         output( ((c&=0xf) > 9) ? (c+0x57) : (c+'0'));
         if (++ptr >= size)
         {
            output(' ');
            j = 9;
            break;
         }
         if (j%8 == 0)
            output(' ');
      }
      ptr -= (j-1);
      for (j = 1; j <= 24; j++)
      {
         c = buffer[ptr];
         if (Filter)
            output( (c<' ' || c>0xfe) ? ('.') : (c));
         else
         {
            charout( (c != 0 && c != 255) ? (c) : ('.'));
            if (j < 24)
               curright();
            else
               output('\n');
         }
         if (++ptr >= size)
            break;
      }
   }
}

/* command prompt */

int prompt(int n, int base)
{
unsigned int key;

   output('\n');
   output('(');
   pnlz(n,(base==16)?4:5,base);
   output(')');
   if (byte_cnt==max_bytes)
      charouta(' ',15);

   if (ft_track)
      output('t');

   if (Files && n_files>1)
      output(15);
   else
      output('*');
   bdos(0x0c,0,0);
   key=scankey();
   if (! ((key&0xff)==0 || key>0x3920 || key<0x011B))
      key&=0xff;
   if (key<' ')
   {
      output('^');
      output(key+'@');
   }
   else if (key<0xff)
      output(key);
   return key;
}
[ RETURN TO DIRECTORY ]