/***
*setup.c - disked setup
*
*Copyright (c) 1991-1995, Gregg Jennings. All wrongs reserved.
* P O Box 200, Falmouth, MA 02541-0200
*
*Purpose:
* Initialization.
*
*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 15-Dec-1994 corrected Processor ID equate order
2.6 09-Nov-1994 general cleaning, comments,
2.5 04-Sep-1994 consolodated all extern references.
removed some code in setup() and startup()
and placed into functions.
2.4 18-Apr-1994 cleaned up extern defs
2.3 09-Mar-1994 hugefree() file/clusters, bump to revision
2.2 03-Feb-1994 added startup()
2.1 04-Jan-1994 added get_volume()
Notes: The startup code (startup()) is just plain confusing.
It will probably be the last to be cleaned up.
Also: the logdisk() functions return DISKIO for no errors,
less than DISKIO for warnings, and greater than DISKIO
for unrecoverable errors. I forgot this once and
totally messed things up!
*/
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <string.h>
#include <ctype.h>
#include <direct.h>
#ifdef __BORLANDC__
#include <conio.h>
#endif
#include "disked.h"
#include "diskio.h"
#include "files.h"
#include "mylib.h"
#include "alloc.h"
#include "error.h"
#include "direct.h"
#include "console.h"
/* globals referenced here
All of the DISKED configuration switches (mixed case
identifiers), all of the "start-up" variables (for
initial sector position, control switches.
Some of the DISKIO globals.
error, err_msg[] ERROR.C
enum DISKIO_RETURNS DISKIO.H
comspec[],promptvar[] DISKED.C
(probably more)
*/
/* gloabls defined here */
/* version nu. */
const char * const Version=" 2.9."
#ifdef _QC /* Compiler ID */
"MQ." /* keep track of compiler */
#elif defined(__BORLANDC__) /* for BUGZZZZ! */
"BC."
#elif defined(_MSC_VER)
"MC."
#elif defined(__WATCOMC__)
"WC."
#else
"XX." /* put others here and below */
#endif
#if defined(M_I386) || defined(__386__) /* Processor ID */
"I386"; /* note order */
#elif defined(M_I286) || defined(__286__)
"I286";
#elif defined(M_I8086) || defined(M_I86)
"I86";
#else
"x86";
#endif
/* Borland does not have such defines, I edit the EXE */
/* Watcom's WCL does not define these either! */
/* error message stuff -- for the INT 24 handler */
const char *harderr_list[] = {
"Disk is write-protected",
"Unknown unit",
"Drive not ready",
"Unknown command",
"CRC error in data",
"Bad drive-request structure length",
"Seek error",
"Unknown media type",
"Sector not found",
"Printer out of paper",
"Write fault",
"Read fault",
"General failure",
};
/* internal data */
/* copyleft stuff */
static const char * const Author="Gregg Jennings";
static const char * const Title="DISKED The DISK EDitor";
static const char * const Copyr="(c) 1989-1995, All wrongs reserved";
static const char * const Namep="DISKED";
static const char *disked_ini="DISKED.INI";
static const char *disked_sav="DISKED.SAV";
static int min_mem; /* for running with an IDE */
static int find_flag; /* find string arg */
static char set_file[67]; /* file being set-to/tracked */
/* internal functions */
static void setupmem(void);
static void set_inifile(char *arv);
static void program_args(char **argv, int drives[], unsigned int *dsk);
static void drive_status(int status);
static int getdriveinfo(int *drives, unsigned int *num);
static void do_find(void);
static void do_set(unsigned int cdisk);
static int do_files(void);
static void quit(int e);
#ifdef __WATCOMC__
int _far hhandler(unsigned deverr, unsigned doserr, unsigned _far *hdr);
#else
void _cdecl _far hhandler(unsigned deverr, unsigned doserr, unsigned _far *hdr);
#endif
/***
*setup - sets up everything
*
* args: char **argv passed to option handler
* int drives[] gets filled with system drives (boolean)
* UNIT *dsk gets set to current drive or to drive set
* by command line
*
* Return: void
*
* 2.11 23-Mar-1995 returns current drive
* 2.10 25-Nov-1994 BigScreen reference
* 2.9 09-Nov-1994 void return
* 2.8 02-Oct-1994 fixed error of setting current disk if drive arg
* 2.7 08-Apr-1994 put some code in sub-functions
* 2.6 03-Feb-1994 /s, moved stuff here (startup()) from DISKED.C
* ver 2.5 21-Jan-1994 added +|-t
* ver 2.4 03-Dec-1993 added /@
* ver 2.3 20-Nov-1993 order of options parsed
* ver 2.2 13-Nov-1993 better finding of INI file, newalloc()
* ver 2.1 19-Apr-1992 Added /?
****/
extern int setup(char **argv, int drives[], unsigned int *dsk)
{
int cdisk;
/* preset all non-init-structure globals */
write_to = FALSE; /* global booleans */
files_indexed = FALSE;
Signon = TRUE;
Save = Restore = FALSE;
BigScreen = FALSE;
byte_cnt = 0; /* global object counters */
n_files = 1;
n_dirs = 1;
find_flag = min_mem = 0; /* start-up flags */
set_sector = -1L;
dir_cluster = 0;
set_file[0] = '\0';
volume[0] = format[0] = /* others */
fatsize[0] = '\0';
memset(tagged,0,sizeof(tagged));
/* get drive info -- set current drive and get drive count */
cdisk = *dsk = getdriveinfo(drives,&max_drive);
/* initialize the world */
set_inifile(*argv);
initialize(inifile);
/* setup video stuff */
initvideo(Output);
_harderr(hhandler); /* capture INT 24 handler */
program_args(argv,drives,dsk); /* check command line parameters */
/* set disk to use if an arg */
return cdisk;
}
/***
*program_args - Check command line arguments, set global prameters etc.
*
* Args: same as for setup()
* Return: void
*
****/
static void program_args(char **argv, int drives[], unsigned int *dsk)
{
int c;
int tempd;
if (*++argv)
{
do
{
c=tolower(**argv);
if (c == '-') /* turn things off */
{
switch (*++*argv)
{
case '?': goto Help;
case 'D': Debug=FALSE; break;
case 't': Translate=FALSE; break;
case 's': Save=FALSE; break;
case 'r': Restore=FALSE; break;
case 'f': Files=FALSE; break;
case 'h': Home=FALSE; break;
default: break;
}
}
else if (c == '/') /* do/set things */
{
switch (*++*argv)
{
case 's':
++*argv;
if (**argv == '\0')
++argv;
switch(**argv)
{
case 'B':
set_sector = 0;
break;
case 'F':
set_sector = reserved_secs + 1;
break;
default:
if (isdigit(**argv))
set_sector = atoi(*argv);
if (isalpha(**argv))
strcpy(set_file,*argv);
break;
}
break;
case '@':
Signon = 0;
break;
case 'h': /* help ! */
case '?':
Help:
printc(Title); /* display (centered) logo */
printc(Version);
printc(Copyr);
disptext(com_line_text);
exit(0);
break;
case 'm': /* minimize memory */
min_mem = 1;
break;
case 'x': /* set INI file name */
++*argv;
if (**argv)
strcpy(inifile,*argv);
else if (**(argv+1))
strcpy(inifile,*++argv);
break;
case 'r': /* set Restore/Save file name */
++*argv;
if (**argv)
strcpy(savfile,*argv);
else if (**(argv+1))
strcpy(savfile,*++argv);
break;
case 'f': /* find string arg */
++*argv;
if (**argv) /* be careful of space after 'f' */
{
find_flag = 1;
strcpy(findstr,*argv);
}
else if (**(argv+1))
{
find_flag = 1;
strcpy(findstr,*++argv);
}
break;
case '5':
BigScreen = 1;
break;
default:
break;
}
}
else if (c == '+') /* turn things on */
{
switch (*++*argv)
{
case 'D': Debug=TRUE; break;
case 't': Translate=TRUE; break;
case 's': Save=TRUE; break;
case 'r': Restore=TRUE; break;
case 'f':
if (find_flag == 1)
find_flag = 2; /* index files AFTER find() */
Files = TRUE;
break;
case 'h': Home=TRUE; break;
default: break;
}
}
else if (isalpha(c)) /* disk drive letter */
{
tempd=toupper(**argv)-'@'; /* make valid */
if (drives[tempd]) /* check it */
{
*dsk=tempd; /* log it */
Restore=FALSE; /* drive spec higher precedence */
/*Save=FALSE;*/ /* than Restore */
}
}
} while (*++argv);
}
}
/***
*getdriveinfo - makes a list of all valid drives, set the number
* of drives
* RETURNS current drive
*
* 1.0 02-Sep-1994 moved from setup()
****/
static int getdriveinfo(int *drives, unsigned int *num)
{
unsigned i,tempd,cdisk;
*num = 0; /* initialize */
_dos_getdrive(&cdisk); /* get current drive */
for (i = 0; i < MAX_DRIVE; i++) /* loop to verify drives */
{
_dos_setdrive(i,&tempd); /* try and set */
_dos_getdrive(&tempd); /* see if it was set */
if (i == tempd) /* if it was set */
{
drives[i] = TRUE; /* then the drive is real */
++(*num); /* increment count */
}
else
drives[i] = FALSE;
}
_dos_setdrive(cdisk,&tempd); /* reset current disk */
return cdisk;
}
/***
*set_inifile - Form the INI filespecs.
*
* 1.1 29-Nov-1994 prompt variable string now global to work
* with MSC 8.0
*
****/
static void set_inifile(char *argv)
{
unsigned i,tempd;
char *tempc;
strcpy(comspec,getenv("COMSPEC")); /* get where COMMAND.COM is */
strcpy(promptvar,"PROMPT=");
strcat(promptvar,getenv("PROMPT")); /* change prompt for shell */
strcat(promptvar,"(DE)");
putenv(promptvar);
tempd = 1; /* for INI file test */
if ((tempc = getenv("INIT")) != NULL)
{
strcpy(savfile,tempc); /* get env dir */
strcpy(inifile,tempc);
if (inifile[strlen(inifile)-1]!='\\')
{
strcat(savfile,"\\");
strcat(inifile,"\\");
}
strcat(savfile,disked_sav);
strcat(inifile,disked_ini);
tempd = !exist(inifile);
}
if (tempd) /* if INI file not in dir */
{
if (exist(disked_ini))
{
strcpy(inifile,disked_ini);
strcpy(savfile,disked_sav);
return;
}
strcpy(savfile,argv); /* get where DISKED resides */
strcpy(inifile,argv);
i=strlen(inifile);
inifile[--i]='I';
inifile[--i]='N';
inifile[--i]='I';
i=strlen(savfile);
savfile[--i]='V';
savfile[--i]='A';
savfile[--i]='S';
}
}
/***
*startup() - login drive and do startup stuff like index files,
* set to particular spot, etc.
*
* Args: char *curdir gets set to current directory
* UNIT cdisk current disk
*
* Returns: void
*
* NOTES: The disk to use is the global 'disk' which has been
* previously set (by setup()).
*
*
* 1.1 03-Feb-1994 set_sector
* ver 1.0 22-Jan-1994
****/
extern void startup(char *ccurdir, unsigned int cdisk)
{
int c,status;
/* get current directory, and save it for exit */
_getcwd(curdir,_MAX_DIR);
_getcwd(ccurdir,_MAX_DIR);
/* login drive and if error find out what to do */
while ((status = logdisk(disk)) > DISK_OK)
{
printerror(Debug);
if (disk == cdisk) /* if disk is current disk */
exit(2); /* just quit */
print(" %c: Use current? (or Retry) ",disk+'@');
if ((c = input()) == 'y' || c == 'Y') /* use current drive ? */
disk = cdisk; /* yes, try it */
else if (tolower(c) != 'r') /* try again ? */
exit(0); /* no, quit */
output('\n');
}
/* allocate memory for sector buffers and file buffer */
setupmem();
/*
First do Special Commands which bypass normal start-up sequence
only one for now: /f{text}. Note that the order of /f and +|-f
on the command line is followed.
*/
if (find_flag) /* find text via command line */
{
do_find();
}
/* end of Special Commands */
else
{
if (Signon == TRUE)
disptext(signon_text); /* signon text */
if (Files > 0)
do_files(); /* index files */
else if (Signon == TRUE) /* use the delay of do_files() */
{ /* for the pause */
pause();
output('\n');
}
if (!Files) /* didn't index so get volume label */
get_volume(volume);
do_set(cdisk); /* find out what sector to start at */
if (!(Files && !Home && Translate)) /* display disk parameters */
dparams(curdir); /* if not dir display */
print("\n\n\t'/' for help");
}
/* Now display any errors */
if (error.num != -1) /* if error */
{
output('\n'); /* place the message */
printerror(Debug); /* before the dump */
}
drive_status(status); /* display anything weird */
if (Restore)
{
if (Display && !Verify)
print("restoring...");
if (Verify && getver(" restore",0))
getinit(savfile,INIT_RESTORE);
else
Restore = FALSE;
}
}
/***
*do_find - Search for text specified on command line.
* The complexity is due to whether or no to index the
* files before or after seaching (command line order).
*
****/
static void do_find(void)
{
int i;
rootsector(); /* set to root */
if (Display)
{
printc(Title); /* display (centered) logo */
printc(Copyr); /* instead of drive parameters */
}
if (Files && find_flag == 1) /* index files first? */
i = do_files();
else
i = 1;
if (error.num != -1) /* was there an error? */
{
output('\n');
printerror(Debug);
output('\n');
}
if (i == 0 && Verify)
getver(" find",MOV_YN);
print("\nfind %s",findstr);
if ((i = find(1,0,0)) >= 0) /* find text */
{
print("found at ");
pn(i,Radix);
}
if (Files && find_flag == 2) /* index files now? */
do_files();
}
/***
*do_set - Set to the proper starting sector. More complexity
* due to command line arguments.
*
* 0.1 19-Mar-1995 changed set file for filetrack()
****/
static void do_set(unsigned int cdisk)
{
int i,tempd;
long templ;
char tempstr[67];
if (Restore) /* if Restored */
{ /* read current sector */
readsector();
}
else if (set_sector != -1L) /* set to a sector? */
{
setsector(set_sector);
}
else if (set_file[0] != '\0') /* set to file? */
{
if ((tempd = file_start(set_file)) != 0) /* if found */
{
setcluster(tempd); /* set to first sector */
if (Files)
{
tempd = clusters[tempd];
if ((i = filetrack(gfile(tempd),tempd)) != 1)
print("file track error: %d",i);
}
}
else
rootsector(); /* not found */
}
else if (Files && !Home) /* if indexed files and not go home */
{ /* set to current directory */
strcpy(tempstr,&curdir[2]);
if ((tempd = findfile(tempstr)) != 0)
setcluster(tempd);
else
rootsector();
}
else if (cdisk == disk) /* else goto current directory */
{
set_sector = templ = cwdstart();
dir_cluster = sectortocluster(templ);
setsector(templ);
}
else
rootsector();
}
/***
*do_files - Index the files.
*
****/
static int do_files(void)
{
if (Display)
bprint(" indexing...");
files_indexed = Files = initfiles();
if (Display)
clreol();
return files_indexed;
}
/***
*setupmem -
*
****/
static void setupmem(void)
{
unsigned u;
/*
Yeah I can make it a long and get a huge pointer for a really
large buffer, but so far that large of a buffer has not been
needed. Next time Im bored...
*/
/* try and get memory */
for (u = (min_mem) ? 8192U : 65024U ; ; u -= 512U)
if ((data_buf = (unsigned char *)alloc(u,sizeof(char)))!=NULL)
break;
if (u < 512U*10U)
quit(NO_MEM);
max_bytes = u;
/****** can only alloc sector buffer if sector size is known ******/
if ((sec_buf = alloc(sec_size,sizeof(char))) == NULL)
quit(NO_MEM);
if ((save_sec = alloc(sec_size,sizeof(char))) != NULL)
if ((spare_sec = alloc(sec_size,sizeof(char))) == NULL)
freep(save_sec);
}
/***
*newdisk() - consolated disk change stuff
*
* 1.3 23-Mar-1995 tempd != disk test for 0'ing tagged
* ver 1.2 19-Jan-1994 'removable' test
****/
extern int newdisk(int tempd)
{
int i;
unsigned int temps;
temps = sec_size; /* save current sector size */
savesector(); /* and sector data */
if ((i = logdisk(tempd)) > DISK_OK)
{
restoresector();
disk_moved = 0;
return 0; /* RETURN */
}
drive_status(i);
if (temps != sec_size) /* new sector size */
{
sec_buf = newalloc(sec_buf,sec_size*sizeof(char));
if (sec_buf == NULL)
{
print("\nReallocation Failure.\n");
print("Sorry, but I am too confused to continue...\n");
exit(3);
}
save_sec = newalloc(save_sec,sec_size*sizeof(char));
spare_sec = newalloc(spare_sec,sec_size*sizeof(char));
}
_getcwd(curdir,_MAX_DIR); /* get current directory */
n_files = 1; /* setup for files */
n_dirs = 1;
if (Files) /* if to index them */
{
if (files_indexed) /* if already */
{
hugefreep(clusters); /* free them first */
hugefreep(files);
}
do_files();
}
if (!Files)
get_volume(volume);
set_sector = -1L; /* kill original start-sector */
if (Home)
rootsector();
else
{
if (log_sector >= num_sectors)
lastsector();
else
readsector();
}
return 1;
}
/***
* Handler to deal with hard error codes. Since DOS is not reentrant,
* it is not safe to use DOS calls for doing I/O within the DOS Critical
* Error Handler (int 24h) used by _harderr. Therefore, screen output and
* keyboard input must be done through the BIOS.
****/
#if defined (_MSC_VER) && (_MSC_VER > 600)
#pragma warning (disable:4100)
#endif
#ifdef __BORLANDC__
#pragma warn -par
#endif
#ifdef __WATCOMC__
int _far hhandler(unsigned deverr, unsigned doserr, unsigned _far *hdr)
#else
void _cdecl _far hhandler(unsigned deverr, unsigned doserr, unsigned _far *hdr)
#endif
{
if (doserr <= 0x0C)
error.msg = harderr_list[doserr];
error.num = doserr;
error.mod = error.func = "harderr";
_hardretn(doserr&0xff);
#ifdef __WATCOMC__
return _HARDERR_IGNORE;
#endif
}
#ifdef __BORLANDC__
#pragma warn +par
#endif
#if defined (_MSC_VER) && (_MSC_VER > 600)
#pragma warning (default:4100)
#endif
/* exit() shell */
static void quit(int e)
{
print(err_msg[e]);
exit(e);
}
/* common index files stuff */
static void drive_status(int status)
{
if (removable && status == USE_DPB) /* floppy BOOT record bad */
print("\nInvalid BOOT record. Using DPB.");
if (!removable && status == USE_BOOT) /* non-floppy no DPB available */
print("\nDPB not supported (ramdrive?)");
}