home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Black Box 4
/
BlackBox.cdr
/
batch
/
cutils10.arj
/
RMTREE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-10-17
|
16KB
|
500 lines
/*+M, RmTree.c */
/************************************************************************/
/************************************************************************/
/* */
/* COPYRIGHT (C) G. KLYNE, 1991. All rights reserved. */
/* */
/* Permission to freely distribute this software, or use it */
/* for any purpose, is granted provided that no charge is */
/* levied for its distribution and this notice is retained */
/* in all copies of the source code. */
/* */
/************************************************************************/
/************************************************************************/
/* */
/* */
/* Module name : RmTree */
/* File name : RmTree.c */
/* */
/* */
/* AMENDMENT RECORD */
/* ================ */
/* */
/* 1. V01.0A 19-Feb-1991 Graham Klyne */
/* Program initially created. */
/* */
/* */
/* PROGRAM FUNCTION */
/* ================ */
/* */
/* This program is a simple DOS utility which removes all */
/* empty subdirectories descending from a given directory. */
/* */
/* The exit code is: */
/* 0 No directory and/or file specified. */
/* 1 All subdirectories deleted. */
/* 4 Could not delete all subdirectories in directory. */
/* 6 Error in supplied path name. */
/* */
/* Any filename and extension (as opposed to directory name) on */
/* the command line is ignored: all subdirectories in the */
/* indicated directory are deleted (if possible). */
/* */
/* */
/************************************************************************/
/************************************************************************/
/*-M*/
/************************************************************************/
/* External declarations used */
/************************************************************************/
#define LINT_ARGS
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <direct.h>
#include <io.h>
#include <dos.h>
/************************************************************************/
/* External entry points declared in this module */
/************************************************************************/
/* No external entry points */
/************************************************************************/
/* Local definitions */
/************************************************************************/
#define FALSE 0
#define TRUE 1
/************************************************************************/
/* Local type declarations */
/************************************************************************/
typedef struct FileDetail_str
{
char Context[21] ; /* Search context for "FindNextFile" */
char Attributes ; /* File attributes */
short int Time ; /* Time file written HHHHHMMMMMMSSSSS */
short int Date ; /* Date file written YYYYYYYMMMMDDDDD */
long int Size ; /* File size in bytes */
char Name[13] ; /* File name and extension */
}
FileDetail, *FileDetail_ptr ;
/************************************************************************/
/* Local variable declarations */
/************************************************************************/
/* No local variables */
/*+F*/
/************************************************************************/
/* *-FindFirstFile, Find first file matching given specification */
/************************************************************************/
/*
/* This function finds the first file matching a given specification.
/*
/* PARAMETERS
/* ----------
/* ReqPath points to a string containing the ambiguous file
/* name (including drive and path) to be matched.
/* ReqAttr indicates the types of files to be located:
/* 0x01 Include read-only files.
/* 0x02 Include hidden files.
/* 0x04 Include system files.
/* 0x08 Include volume identifier file.
/* 0x10 Include directory files.
/* Any combination of the above options may be
/* specified.
/* FilAttr points to a "FileDetail" structure which receives
/* additional information about the file, and other data
/* required by subsequent calls of "FindNextFile".
/* FilSize is the size of the supplied "FilBuff" buffer.
/* FilBuff points to a buffer which receives the filename
/* (including drive and path) as a NULL-terminated
/* string.
/*
/* RESULT
/* ------
/* The result returned is FALSE if no file is found, otherwise TRUE.
/*
/* NOTES
/* -----
/* This routine assumes that the current DTA and the supplied file
/* details structure both lie in the default data segment.
/*
/* If the search is to include directories, the special files "."
/* and ".." may be returned.
/*
/*-F*/
int FindFirstFile
( const char *ReqPath, int ReqAttr,
FileDetail *FilAttr,
int FilSize, char *FilBuff )
{
union REGS InpRegs, OutRegs ;
int SaveDTA ;
int Status ;
int Length ;
int i ;
/*--------------------------------------------------------------*/
/* Copy file path to result buffer */
/*--------------------------------------------------------------*/
Status = FALSE ;
Length = strlen( ReqPath ) ;
while ( ( Length > 0 ) &&
( ReqPath[Length-1] != '\\' ) &&
( ReqPath[Length-1] != '/' ) ) Length-- ;
if ( Length+13 > FilSize )
{
printf( "RmTree: supplied path '%s' is too long\n", ReqPath ) ;
exit( 6 ) ;
}
strncpy( FilBuff, ReqPath, FilSize ) ;
FilBuff[Length] = '\0' ;
/*--------------------------------------------------------------*/
/* Save current DTA, and set new value */
/*--------------------------------------------------------------*/
InpRegs.x.ax = 0x2F00 ;
intdos( &InpRegs, &OutRegs ) ;
SaveDTA = OutRegs.x.bx ;
InpRegs.x.ax = 0x1A00 ;
InpRegs.x.dx = FP_OFF( FilAttr ) ;
intdos( &InpRegs, &OutRegs ) ;
/*--------------------------------------------------------------*/
/* Find file */
/*--------------------------------------------------------------*/
InpRegs.x.ax = 0x4E00 ;
InpRegs.x.cx = ReqAttr ;
InpRegs.x.dx = FP_OFF( ReqPath ) ;
intdos( &InpRegs, &OutRegs ) ;
if ( OutRegs.x.cflag == 0 ) Status = TRUE ;
/*--------------------------------------------------------------*/
/* Restore original DTA */
/*--------------------------------------------------------------*/
InpRegs.x.ax = 0x1A00 ;
InpRegs.x.dx = SaveDTA ;
intdos( &InpRegs, &OutRegs ) ;
/*--------------------------------------------------------------*/
/* Sort out result */
/*--------------------------------------------------------------*/
if ( Status )
{
i = 0 ;
while ( ( FilAttr->Name[i] != '\0' ) && ( i < 12 ) )
{
FilBuff[Length++] = FilAttr->Name[i++] ;
}
FilBuff[Length] = '\0' ;
}
return Status ;
} ; // End of function FindFirstFile
/*+F*/
/************************************************************************/
/* *-FindNextFile, Find next file matching given specification */
/************************************************************************/
/*
/* This function finds the next file matching a given specification,
/* following a previous call of "FindFirstFile" and possible calls
/* of this function.
/*
/* Attributes for the required files are carried over from the
/* original call of "FindFirstFile".
/*
/* PARAMETERS
/* ----------
/* ReqPath points to a string containing the ambiguous file
/* name (including drive and path) to be matched.
/* FilAttr points to a "FileDetail" structure which receives
/* additional information about the file, and other data
/* required by subsequent calls of "FindNextFile".
/* FilSize is the size of the supplied "FilBuff" buffer.
/* FilBuff points to a buffer which receives the filename
/* (including drive and path) as a NULL-terminated
/* string.
/*
/* RESULT
/* ------
/* The result returned is FALSE if no file is found, otherwise TRUE.
/*
/* NOTE
/* ----
/* This routine assumes that the current DTA and the supplied file
/* details structure both lie in the default data segment.
/*
/*-F*/
int FindNextFile
( const char *ReqPath,
FileDetail *FilAttr,
int FilSize, char *FilBuff )
{
union REGS InpRegs, OutRegs ;
int SaveDTA ;
int Status ;
int Length ;
int i ;
/*--------------------------------------------------------------*/
/* Copy file path to result buffer */
/*--------------------------------------------------------------*/
Status = FALSE ;
Length = strlen( ReqPath ) ;
while ( ( Length > 0 ) &&
( ReqPath[Length-1] != '\\' ) &&
( ReqPath[Length-1] != '/' ) ) Length-- ;
if ( Length+13 > FilSize )
{
printf( "RmTree: supplied path '%s' is too long\n", ReqPath ) ;
exit( 6 ) ;
}
strncpy( FilBuff, ReqPath, FilSize ) ;
FilBuff[Length] = '\0' ;
/*--------------------------------------------------------------*/
/* Save current DTA, and set new value */
/*--------------------------------------------------------------*/
InpRegs.x.ax = 0x2F00 ;
intdos( &InpRegs, &OutRegs ) ;
SaveDTA = OutRegs.x.bx ;
InpRegs.x.ax = 0x1A00 ;
InpRegs.x.dx = FP_OFF( FilAttr ) ;
intdos( &InpRegs, &OutRegs ) ;
/*--------------------------------------------------------------*/
/* Find file */
/*--------------------------------------------------------------*/
InpRegs.x.ax = 0x4F00 ;
intdos( &InpRegs, &OutRegs ) ;
if ( OutRegs.x.cflag == 0 ) Status = TRUE ;
/*--------------------------------------------------------------*/
/* Restore original DTA */
/*--------------------------------------------------------------*/
InpRegs.x.ax = 0x1A00 ;
InpRegs.x.dx = SaveDTA ;
intdos( &InpRegs, &OutRegs ) ;
/*--------------------------------------------------------------*/
/* Sort out result */
/*--------------------------------------------------------------*/
if ( Status )
{
i = 0 ;
while ( ( FilAttr->Name[i] != '\0' ) && ( i < 12 ) )
{
FilBuff[Length++] = FilAttr->Name[i++] ;
}
FilBuff[Length] = '\0' ;
}
return Status ;
} ; // End of function FindNextFile
/*+F*/
/************************************************************************/
/* *-RemoveTree, Remove subtree of empty directories */
/************************************************************************/
/*
/* This function removes all empty directories descending from the
/* specified directory.
/*
/* PARAMETERS
/* ----------
/* PathSiz is the size of the supplied opathname buffer.
/* PathBuf points to a buffer containing a pathname whose
/* directory is the one from which all empty
/* subdirectories are to be removed. The final
/* directory in the path must be terminated by
/* a '/' or '\' character.
/*
/* RESULT
/* ------
/* The result returned is:
/* 1 All subdirectories deleted.
/* 4 Could not delete all subdirectories in directory.
/* 6 Error in supplied path name (too long).
/*
/*-F*/
int RemoveTree( int PathSiz, char *PathBuf )
{
int Status ;
int More ;
char SubPath[144] ;
FileDetail FilAttr ;
int l ;
int r ;
/*--------------------------------------------------------------*/
/* Force filename in path to '*.*' */
/*--------------------------------------------------------------*/
l = strlen( PathBuf ) ;
while ( ( l > 0 ) &&
( PathBuf[l-1] != '\\' ) &&
( PathBuf[l-1] != '/' ) ) l-- ;
if ( l+14 >= PathSiz )
{
printf( "RmTree: path '%s' is too long\n", PathBuf ) ;
return 6 ;
}
PathBuf[l++] = '*' ;
PathBuf[l++] = '.' ;
PathBuf[l++] = '*' ;
PathBuf[l++] = '\0' ;
#if 0
printf( "RemoveTree: '%s'\n", PathBuf ) ;
#endif
/*--------------------------------------------------------------*/
/* Delete empty subdirectories in specified directory */
/*--------------------------------------------------------------*/
Status = 1 ;
More = FindFirstFile( PathBuf, 0x10, &FilAttr, 143, SubPath ) ;
while ( More )
{
#if 0
printf( "Find attr 0x%02X, file '%s'\n",
FilAttr.Attributes, SubPath ) ;
#endif
if ( ( FilAttr.Attributes & 0x10 ) &&
( FilAttr.Name[0] != '.' ) )
{
l = strlen( SubPath ) ;
SubPath[l++] = '\\' ;
SubPath[l] = '\0' ;
r = RemoveTree( 144, SubPath ) ;
if ( r == 4 ) Status = 4 ;
else
if ( r != 1 ) return r ;
SubPath[l-1] = '\0' ;
r = rmdir( SubPath ) ;
if ( r == 0 )
{
printf( "RmTree: Removed directory '%s'\n", SubPath ) ;
}
else
{
printf( "RmTree: Failed to remove directory '%s'\n",
SubPath ) ;
Status = 4 ;
}
}
More = FindNextFile( PathBuf, &FilAttr, 143, SubPath ) ;
}
return Status ;
} ; /* End of procedure RemoveTree */
/*+T*/
/************************************************************************/
/* *-main, Main Program */
/************************************************************************/
/*
/* This program deletes all empty subdirectories descending from the
/* directory indicated by a specified pathname.
/*
/*-T*/
void main( int argc, char *(argv[]), char *(envp[]) )
{
int Status ;
char FilPath[132] ;
int l ;
/*--------------------------------------------------------------*/
/* Entry point here */
/*--------------------------------------------------------------*/
Status = 0 ;
if ( argc < 2 )
{
printf( "Usage: RmTree path\n"
" Remove all empty subdirectories descending from\n"
" the indicated directory. Any filename specified\n"
" in 'path' is ignored.\n" ) ;
printf( "\n"
"Exit status: 0: no file or directory specified.\n"
" 1: all subdirectories deleted.\n"
" 4: failed to delete all subdirectories.\n"
" 6: error in supplied path.\n" ) ;
printf( "\n"
"Copyright (C) 1991 Graham Klyne. All rights reserved.\n" ) ;
exit( 0 ) ;
}
/*--------------------------------------------------------------*/
/* Copy path to local buffer */
/*--------------------------------------------------------------*/
l = strlen( argv[1] ) ;
if ( l >= 132 )
{
printf( "RmTree: supplied path '%s' is too long\n", argv[1] ) ;
exit( 6 ) ;
}
strcpy( FilPath, argv[1] ) ;
/*--------------------------------------------------------------*/
/* Delete subdirectories in specified directory */
/*--------------------------------------------------------------*/
Status = RemoveTree( 132, FilPath ) ;
if ( Status == 1 )
printf( "RmTree: All subdirectories removed\n" ) ;
else
if ( Status == 4 )
printf( "RmTree: Some subdirectories removed\n" ) ;
else
printf( "RmTree: Error with path '%s'\n", FilPath ) ;
/*--------------------------------------------------------------*/
/* Exit */
/*--------------------------------------------------------------*/
exit( Status ) ;
} ; /* End of procedure main */
/************************************************************************/
/* End of module RmTree */
/************************************************************************/