/* 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 #include #include #include #include /* 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 */ static 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" }; static 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." }; static 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." }; static 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(); }