dos_compilers/Microsoft QuickC v2/SAMPLES/FILEDEMO.C
2024-07-02 06:32:02 -07:00

494 lines
13 KiB
C

/* FILEDEMO.C - Performs various file operations using DOS functions which
* are invoked from QuickAssembler procedures. FILEDEMO demonstrates how
* to interface C and QuickAssembler procedures, which in turn demonstrate
* various assembly-language instructions, DOS calls, and BIOS interrupts.
*
* FILEDEMO.EXE is built from the following files:
* FILEDEMO.C - Main program
* FILE.ASM - QuickAssembler procedures for FILEDEMO
* COMMON.ASM - QuickAssembler procedures shared by other example programs
* DEMO.INC - Assembly include file with macros and structure declarations
* DEMO.H - C include file with prototypes and structure declarations
*
* Procedures: ClearBox ChangeDrive GetDiskSize
* GetVidConfig GetVer GetCurDir
* GetCurDisk CopyFile DelFile
* MakeDir RemoveDir ChangeDir
* GetAttribute SetAttribute RenameFile
* GetFileTime FindFirst FindNext
* UniqueFile OpenFile CloseFile
* ReadFile SetCurPos StrCompare
* StrFindChar ReadCharAttr
*/
#include "demo.h"
#include <string.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
/* Function prototypes */
char *get_spec( int n );
int list_dir( char *spec, int disp_attr );
void press( void );
/* Constants */
#define MAXSEARCH 80
#define MAXSPEC 64
#define BUFFSIZE 40 * 1024
/* Global variable */
struct file_info file; /* Structure for FindFirst info */
main()
{
static char source[64]; /* Buffer for source file/path */
static char text[MAXSEARCH]; /* Pointer to buffer for search text */
static char date_time[19]; /* Receive file date and time */
int err, mode, handle, len; /* Codes, file handle, bytes read */
int row, col, ch; /* Cursor coordinates, kb character */
int i, j, attr; /* Index variables, file attribute */
int disp_attr; /* Display attribute */
char *spec, *ptr, *buffer; /* File spec, char match, read buffer */
long dsize, disk_use; /* Disk size and usage */
struct disk_stat disk; /* Structure for disk size params */
char copy_msg[] =
{
"Files can be copied or moved in 2 different modes:\n" \
" 0 - overwrite target file if it exists\n" \
" 1 - abort if target file exists\n\n" \
"Mode 1 is supported only with DOS versions 3.0 or higher.\n"
};
char move_msg[] =
{
"Quick Move uses DOS function 56h (Rename File) to effectively " \
"move a file from\none directory to another directory on the " \
"same drive. It copies the entry\nfrom the source directory to " \
"the target directory, but does not physically\ncopy the file.\n\n" \
"Source and target specifications must be given in full, " \
"including filenames,\neven if the names are the same."
};
char grep_msg[] =
{
"The Find Text option uses the StrFindChar and StrCompare procedures " \
"to locate\na text string within specified files, like Unix's " \
"\"grep\" command. Find Text\nis limited to case-sensitive searches " \
"within the current directory.\n\nEnter the desired search string " \
"without quotation marks. When specifying the\nfilename, use " \
"wildcard characters to expand the search to a group of files --\n" \
"for example, \"*.*\" searches all files within the current " \
"directory, \"*.bat\"\nlimits the search to batch files, and so forth."
};
char attr_msg[] =
{
"\t\t\t1 normal \n" \
"\t\t\t2 read-only \n" \
"\t\t\t3 hidden \n" \
"\t\t\t4 system \n" \
"\t\t\t volume \n" \
"\t\t\t subdirectory\n" \
"\t\t\t5 archive \n"
};
GetVidConfig();
ReadCharAttr( &disp_attr );
clear_scrn( disp_attr, 0, 24 );
SetCurPos( 8, 0 );
puts( "Welcome to QuickAssembler's FILEDEMO program.\n\n\nThis program " \
"is meant to encourage experimentation while demonstrating how " \
"to\naccess DOS from QuickAssembler procedures. As a safety " \
"precaution, however,\nwe suggest you DO NOT experiment with " \
"files that cannot easily be replaced." );
press();
do
{
/* Display current drive and directory */
clear_scrn( disp_attr, 0, 24 );
SetCurPos( 0, 0 );
printf( "Current Directory: %c:\\", (char) (GetCurDisk() + 'A') );
GetCurDir( source );
puts( source );
/* Display DOS version */
SetCurPos( 1, 0 );
printf( "DOS Version: %2.1f", ( (float) GetVer() ) / 100 );
/* Display disk statistics for current drive */
SetCurPos( 0, 58 );
GetDiskSize( 0, &disk );
dsize = (long)disk.bytes * disk.sects * disk.total;
disk_use = (long)(disk.total - disk.avail) * disk.bytes * disk.sects;
printf( "Disk Size: %6lu K", dsize / 1024 );
SetCurPos( 1, 58 );
printf( "Disk Use: %6lu K", disk_use / 1024 );
/* Display menu and poll for key press */
clear_scrn( disp_attr, 2, 23 );
SetCurPos( 5, 0 );
puts( " \t *** QuickAssembler File " \
"Demonstration Program ***" );
SetCurPos( 7, 0 );
puts( " \tA List Directory \t\tH Get/Set File Attribute" );
puts( " \tB Copy File \t\tI Get File Date and Time" );
puts( " \tC Move File \t\tJ Rename File" );
puts( " \tD Make Subdirectory \t\tK Delete File" );
puts( " \tE Remove Subdirectory \t\tL Create Unique File" );
puts( " \tF Change Default Drive \t\tM Quick Move" );
puts( " \tG Change Directory \t\tN Find Text" );
printf( "\n\n\tSelect an option, or press ESC to quit: " );
ch = getch();
switch( (ch = toupper( ch )) )
{
/* List first 60 files in specified directory */
case 'A':
err = list_dir( get_spec( 1 ), disp_attr );
if( !err )
press();
break;
/* Copy or Move File according to requested mode:
* 0 = overwrite target
* 1 = abort if target exists
* If Move requested, delete source file after copy.
*/
case 'B':
case 'C':
clear_scrn( disp_attr, 2, 17 );
SetCurPos( 9, 0 );
puts( copy_msg );
mode = -1;
while( (mode < 0) || (mode > 1) )
{
SetCurPos( 16, 0 );
printf( "Enter copy mode: " );
mode = (int) (getche() - '0');
}
spec = get_spec( 2 ); /* Get source */
strcpy( source, spec ); /* Save in buffer */
spec = get_spec( 3 ); /* Get target */
err = CopyFile( mode, source, spec );
if( (ch == 'C') && !err )
err = DelFile( source );
break;
/* Make Directory */
case 'D':
err = MakeDir( get_spec( 1 ) );
break;
/* Remove Directory */
case 'E':
err = RemoveDir( get_spec( 1 ) );
break;
/* Change Default Drive */
case 'F':
SetCurPos( 18, 0 );
printf( "Enter new drive letter: " );
ch = getch();
ch = toupper( ch );
ChangeDrive( ch );
err = 0;
break;
/* Change Directory */
case 'G':
err = ChangeDir( get_spec( 1 ) );
break;
/* Get and Set File Attributes */
case 'H':
strcpy( source, get_spec( 3 ) );
if( (err = GetAttribute( source )) != -1 )
{
attr = err;
if( !attr )
attr_msg[6] = '*';
else
attr_msg[6] = ' ';
for( j = 1, i = 27; j <= 32; j <<= 1, i+= 21 )
{
attr_msg[i] = ' ';
if( attr & j )
attr_msg[i] = '*';
}
err = 0;
clear_scrn( disp_attr, 2, 17 );
SetCurPos( 7, 0 );
puts( attr_msg );
printf( "\n\nToggle attribute bits by selecting 1-5, " \
"or any other key to exit: " );
mode = (int)( getch() - '0' );
if( (mode > 0) && (mode < 6) )
{
switch( --mode )
{
case 0:
attr = 0;
break;
case 1:
case 2:
case 3:
attr = attr ^ (1 << (--mode) );
break;
case 4:
attr = attr ^ 32;
}
err = SetAttribute( attr, source );
}
}
break;
/* Get File Date and Time */
case 'I':
if( (handle = OpenFile( 0, get_spec( 3 ) )) == -1 )
err = 1;
else
err = 0;
if( !err )
{
if( !(err = GetFileTime( handle, date_time )) )
{
clear_scrn( disp_attr, 2, 17 );
SetCurPos( 12, 10 );
printf( "File's date and time stamp: %s", date_time );
CloseFile( handle );
press();
}
}
break;
/* Rename File */
case 'J':
strcpy( source, get_spec( 2 ) );
err = RenameFile( source, get_spec( 3 ) );
break;
/* Delete File */
case 'K':
err = DelFile( get_spec( 3 ) );
break;
/* Create File with Unique Name */
case 'L':
strcpy( source, get_spec( 1 ) );
handle = UniqueFile( 0, source ); /* Normal file attr = 0 */
if( handle >= 0 )
{
printf( "\n\nDOS creates file %s", source );
press();
err = 0;
}
else err = 1;
break;
/* Quick Move from one directory to another */
case 'M':
clear_scrn( disp_attr, 2, 17 );
SetCurPos( 8, 0 );
puts( move_msg );
strcpy( source, get_spec( 2 ) );
err = RenameFile( source, get_spec( 3 ) );
break;
/* Search files for specified text */
case 'N':
clear_scrn( disp_attr, 2, 17 );
buffer = (char *) malloc( BUFFSIZE + 1 );
if( buffer == NULL )
{
SetCurPos( 12, 26 );
puts( "Insufficient memory for option" );
err = 1;
break;
}
SetCurPos( 7, 0 );
puts( grep_msg );
SetCurPos( 18, 0 );
printf( "Enter search text: " );
GetStr( text, MAXSEARCH );
/* Find first data file. */
if( err = FindFirst( 0, get_spec( 3 ), &file ) )
{
clear_scrn( disp_attr, 2, 17 );
SetCurPos( 12, 24 );
puts( "No files found matching specification" );
}
/* If file found, initialize screen coordinates and
* open file for reading.
*/
else
{
clear_scrn( disp_attr, 2, 17 );
row = 6;
col = 0;
do
{
if( (handle = OpenFile( 0, file.name )) != -1 )
{
/* If file opened successfully, read a block
* of BUFFSIZE bytes. If end-of-file encountered
* (number of bytes read not equal to BUFFSIZE)
* or read error, set error flag to break loop.
* Terminate block with a NULL to make it an
* ASCIIZ string.
*/
err = 0;
while( !err )
{
len = ReadFile( handle, BUFFSIZE, buffer );
if( (len == 0) || (len != BUFFSIZE) )
++err;
ptr = buffer;
*( ptr + len ) = 0;
/* Search block for first character in text */
while( spec = StrFindChar( text[0], ptr, 0 ) )
{
/* If initial character found, compare
* remaining characters in search text.
* If all characters match, display file
* name and break out of loop.
*/
ptr = StrCompare( ++spec, &text[1],
(strlen( text ) - 1) );
if( !ptr )
{
SetCurPos( row++, col );
puts( file.name );
if( row == 16)
{
row = 6;
col += 20;
}
err = 1;
break;
}
}
}
CloseFile( handle );
}
else
{
err = 1;
break;
}
} while( !FindNext( &file ) );
if( (row == 6) && (col == 0) )
{
SetCurPos( 12, 22 );
puts( "Text not found in specified file(s)" );
}
press();
err = 0;
}
free( buffer ); /* Free allocated block */
break;
default:
continue;
}
if( err )
{
clear_scrn( disp_attr, 24, 24 );
SetCurPos( 24, 0 );
printf( "*** Error ***\a" );
press();
}
} while( ch != ESCAPE ); /* Exit if ESC key pressed */
clear_scrn( disp_attr, 0, 24 ); /* Clear screen before exit */
SetCurPos( 23, 0 ); /* and set cursor to bottom */
return( 0 );
}
/* get_spec - Prompts for file or path specifications.
*
* Params: n - Prompt number
*
* Return: Pointer to specification
*/
char *get_spec( int n )
{
static char spec[MAXSPEC];
switch( n )
{
case 1:
SetCurPos( 18, 0 );
printf( "Enter path: " );
break;
case 2:
SetCurPos( 18, 0 );
printf( "Enter source file: " );
break;
case 3:
SetCurPos( 20, 0 );
printf( "Enter target file: " );
break;
}
GetStr( spec, MAXSPEC );
return spec;
}
/* list_dir - Lists specified directory by invoking DOS function 4Eh (Find
* First Matching Entry), then DOS function 4Fh (Find Next Matching Entry).
*
* Params: spec - Pointer to path specification
*
* Return: err - Error code returned from FindFirst procedure:
* 0 = successful 1 = error
*/
int list_dir( char *spec, int disp_attr )
{
int row, col;
int err, end;
clear_scrn( disp_attr, 2, 23 );
strcat( spec, "\\*.*" );
err = FindFirst( 16, spec, &file ); /* Find directories, normal files */
if( !err )
{
for( end = 0, col = 0; (col < 80) && (end == 0); col += 22 )
{
for( row = 5; (row < 20) && (end == 0); row++ )
{
SetCurPos( row, col );
puts( file.name );
end = FindNext( &file );
}
}
}
return err;
}
/* press - Prompt for keyboard signal to continue.
*
* Params: None
*/
void press( void )
{
SetCurPos( 24, 49 );
printf( ". . . press a key to continue" );
SetCurPos( 24, 47 );
getch();
}