/***
*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;
}