/////////////////////////////////////////////////////////////// // IDE Demo Program // // Delivery.cpp // // Copyright (c) 1993 by Borland International // /////////////////////////////////////////////////////////////// #include #include #include #include #include // // // To take advantage of the tracing, attach the // // 'Diagnostics' StyleSheet to this node by // // selecting 'Edit node attributes' from the // // node's SpeedMenu and selecting it from the // // StyleSheets dropdown // // // DIAG_DEFINE_GROUP( IdeDeliver, 1, 1 ); // // // class Delivery // // // // class Delivery for reading command line and executing // // appropriate actions. If you wish to extend the // // functionality of this program, add a method to the // // to the Delivery class with the same prototype as // // Delivery::Copy and a corresponding entry to the static // // data member Delivery::_commands[] // // // class Arguments; class Delivery { public: // Parser/Dispatcher // void Execute( Arguments & ); protected: // Commands // void Copy ( Arguments & ); void Move ( Arguments & ); void MkDir ( Arguments & ); void Clean ( Arguments & ); void Rename ( Arguments & ); private: // Array of command methods and there text equivalents // typedef void (Delivery::*commandMethod)( Arguments & ); struct Commands { commandMethod parser; const char *cmdName; }; static Commands _commands[]; // low-level helpers.. // enum FileCmd { fcCopy, fcMove }; void FilesCopyMove( Arguments &, FileCmd ); void FilesCopyMove( const char *, const char *, FileCmd ); void FileCopy ( const char *, const char *); void FileMove ( const char *, const char *, int ); void FileRename( const char *, const char *); void FileDelete( const char *, int okToFail = 1 ); }; // // // class Arguments // // Array for holding command line arguments // // // class _BIDSCLASS Arguments : public TArray { public: Arguments( int argc, char * * argv ); // Return the Deliver command text found on command line // const char * command(); // Return the last filename on the command line. (This has // // the side-effect of limiting the number of valid source // // filenames by one.) // const char * destination(); // Return the filename at 'index'. Valid values for index // // start at 1 (one) and this method will return 0 when there // // are no more source filenames. // const char * source( int index ); private: void expandFile( char * ); const char * arg(int i); int _destinationAt; }; inline const char * Arguments::arg( int i ) { return( ((*this)[i]).c_str() ); } // PrintProgramSignature will output the program signature // void PrintProgramSignature() { static int headerHasBeenPut = 0; if( !headerHasBeenPut ) { cout << "Deliver:" << endl; headerHasBeenPut = 1; } } // // // main() // // // int main (int argc, char * argv[]) { int returnCode; try { Arguments args( argc, argv ); Delivery parser; parser.Execute( args ); returnCode = 0; } catch ( xmsg & x ) { PrintProgramSignature(); cout << "Fatal Error: " << x.why() << endl; returnCode = 2; } return returnCode; } // // // class FileSpec for manipulation file paths // // // class FileSpec { public: // ctor // FileSpec( const char * = "" ); // accessors // const char * path(); const char * drive(); const char * dir(); const char * file(); const char * ext(); void path(const char *); void drive(const char *); void dir(const char *); void file(const char *); void ext(const char *); void fileext( const char * ); long age(); // flags() returns FILENAME, WILDCARDS etc. flags found in dir.h // int flags(); // explicit splitter/merger // int split(); void merge(); // disk manipulation and polling // int exists(); int first(); int next(); // Are this and another FileSpec referring to the same drive? // int sameDrive( FileSpec & ); // Is this FileSpec really representing a directory? // int isDirectory(); void addTrailingSlash(); // Strip the trailing slash from the path() element and return // // the path(). (Calling this invalidates the use dir(), file() // // and ext()). // char * stripTrailingSlash(); private: char _path [ MAXPATH ]; char _drive[ MAXDRIVE ]; char _dir [ MAXDIR ]; char _file [ MAXFILE ]; char _ext [ MAXEXT ]; int _flags; struct ffblk _dta; }; inline FileSpec::FileSpec( const char * apath ) { path( apath ); } inline const char * FileSpec::path() { return( _path ); } inline const char * FileSpec::drive() { return( _drive ); } inline const char * FileSpec::dir() { return( _dir ); } inline const char * FileSpec::file() { return( _file ); } inline const char * FileSpec::ext() { return( _ext ); } inline int FileSpec::flags() { return( _flags ); } inline int FileSpec::exists() { return( first() ); } inline long FileSpec::age() { if( exists() ) { unsigned long date = _dta.ff_fdate; unsigned long time = _dta.ff_ftime; return( (long)( (date << 16) | time ) ); } return( -1L ); } // // // class Delivery implemenation // // // Delivery::Commands Delivery::_commands[] = { { &Delivery::Copy, "COPY" }, { &Delivery::Move, "MOVE" }, { &Delivery::MkDir, "MKDIR" }, { &Delivery::Clean, "CLEAN" }, { &Delivery::Rename,"RENAME" }, { 0 } }; void Delivery::Execute( Arguments & args ) { const char * cmdName = args.command(); int cmdNo = -1; for( int i = 0; _commands[i].cmdName; i++ ) { if( !stricmp( cmdName, _commands[i].cmdName ) ) { cmdNo = i; break; } } if( cmdNo == -1 ) throw xmsg( "Unknown command!" ); (this->*_commands[cmdNo].parser)( args ); } void Delivery::FileCopy( const char * source, const char * destination ) { TRACEX( IdeDeliver, 0, "Copy source: \"" << source << "\" => \"" << destination << "\"" ); FILE * in; FILE * out; if( (in = fopen(source, "rb")) == 0 ) throw xmsg( "Error opening source" ); if( (out = fopen(destination, "wb")) == 0 ) throw xmsg( "Error opening destination" ); register int c; while( (c = fgetc(in)) != EOF ) fputc(c,out); fclose(in); fclose(out); } void Delivery::FileMove ( const char * source, const char * destination, int sameDrive ) { if( sameDrive ) { // '1' here means it's ok for Delete to fail... // FileDelete( destination, 1 ); FileRename( source, destination ); } else { FileCopy( source, destination ); FileDelete( source ); } } void Delivery::FileDelete( const char * fileName, int okToFail ) { if( ::unlink( fileName ) && !okToFail ) throw xmsg( "Error deleting file" ); } void Delivery::FileRename( const char * oldName, const char * newName ) { if( ::rename( oldName, newName ) ) throw xmsg( "Error renaming file" ); } void Delivery::FilesCopyMove ( const char * sourceFile, const char * destinationFile, FileCmd cmd ) { FileSpec source ( sourceFile ); FileSpec destination( destinationFile ); if( !source.first() ) throw xmsg( "Can\'t find source" ); int useSourceFileName; if( destination.isDirectory() ) { destination.addTrailingSlash(); useSourceFileName = 1; } else { useSourceFileName = 0; } do { if( useSourceFileName ) { destination.file( source.file() ); destination.ext ( source.ext() ); } if( cmd == fcCopy ) { // Future: there could be a check here for the ages // // of the FileSpecs if the user had requested // // 'update' copy // FileCopy( source.path(), destination.path() ); } else { FileMove( source.path(), destination.path(), destination.sameDrive( source ) ); } } while( source.next() ); } void Delivery::FilesCopyMove( Arguments & args, FileCmd cmd ) { const char * destination = args.destination(); const char * source; int i = 1; while( (source = args.source(i++)) != 0 ) { FilesCopyMove( source, destination, cmd ); } } void Delivery::Copy ( Arguments & args ) { FilesCopyMove( args, fcCopy ); } void Delivery::Move ( Arguments & args ) { FilesCopyMove( args, fcMove ); } void Delivery::MkDir( Arguments & args ) { const char * source; int i = 1; while( (source = args.source(i++)) != 0 ) { FileSpec dirName( source ); // Future: it would be nice if this did a recursive // // makedir like XCOPY // if( ::mkdir( dirName.stripTrailingSlash() ) ) throw xmsg( "Error making directory" ); } } void Delivery::Clean( Arguments & args ) { const char * sourceFile; FileSpec source; int i = 1; while( (sourceFile = args.source(i++)) != 0 ) { source.path( sourceFile ); if( !source.exists() ) { PrintProgramSignature(); cout << "Warning DELIVER : Can\'t find " << source.path() << endl; continue; } do FileDelete( source.path() ); while( source.next() ); } } void Delivery::Rename( Arguments & args ) { if( args.GetItemsInContainer() != 3 ) throw xmsg( "Wrong number of arguments for renaming" ); FileRename( args.source(1), args.destination() ); } // // // class Arguments implementation // // // Arguments::Arguments( int argc, char * * argv ) : TArray( 10 ) { for( int i = 1; i < argc; i++ ) { char * arg = argv[i]; if( *arg == '+' ) expandFile( arg+1 ); else Add( arg ); } // Initialize to one past the last item on the command line, if // // the caller calls the destination() method, we'll crank this // // back by one. // _destinationAt = GetItemsInContainer(); } void Arguments::expandFile( char * fileName ) { // This method will open a response file and treat every text // // word found in the file as an entry on the command line // ifstream in( fileName ); if( !in.good() ) throw xmsg( "Can't open response file" ); string nextString; while( in.good() ) { in >> nextString; nextString.strip( string::Both, ' ' ); if( nextString.length() ) Add( nextString ); } } const char * Arguments::source( int index ) { if( index < 1 ) throw xmsg( "Missing source operand" ); return( index >= _destinationAt ? 0 : arg(index) ); } const char * Arguments::command() { if( !GetItemsInContainer() ) throw xmsg( "Missing command" ); return( arg(0) ); } const char * Arguments::destination() { if( GetItemsInContainer() < 3 ) throw xmsg( "Missing destination operand" ); // This controls the effictiveness of the method source() // --_destinationAt; return( arg(_destinationAt) ); } // // // class FileSpec implementation // // // int FileSpec::split() { return( _flags = ::fnsplit( _path, _drive, _dir, _file, _ext ) ); } void FileSpec::merge() { ::fnmerge( _path, _drive, _dir, _file, _ext ); } void FileSpec::path(const char *path) { strcpy( _path, path ); split(); } void FileSpec::drive(const char *drive) { strcpy( _drive, drive ); merge(); } void FileSpec::dir(const char *dir) { strcpy( _dir, dir ); merge(); } void FileSpec::file(const char *file) { strcpy( _file, file ); merge(); } void FileSpec::ext(const char *ext) { strcpy( _ext, ext ); merge(); } void FileSpec::fileext( const char *fileExt ) { char * p = (char *)(strchr(fileExt,'.')); if( !p ) p = ""; ext( p ); *p = 0; file( fileExt ); } int FileSpec::first() { if( ::findfirst( _path, &_dta, 0 ) == -1 ) return(0); fileext( _dta.ff_name ); return( 1 ); } int FileSpec::next() { if( ::findnext( &_dta ) == -1 ) return( 0 ); fileext( _dta.ff_name ); return( 1 ); } int FileSpec::sameDrive( FileSpec & other ) { if( *_drive == *other._drive ) return(1); if( !*_drive ) { _drive[0] = ::getdisk() + 'A' - 1; _drive[1] = ':'; _drive[2] = 0; } else { if( !*other._drive ) { other._drive[0] = ::getdisk() + 'A' - 1; other._drive[1] = ':'; other._drive[2] = 0; } } char s[3]; s[0] = *_drive; s[1] = *other._drive; s[2] = 0; strlwr( s ); return( s[0] == s[1] ); } int FileSpec::isDirectory() { int lastCharPos = strlen( _path ) - 1; char lastChar; if(((lastChar = _path[lastCharPos]) == '\\') || (lastChar == '/')) _path[lastCharPos] = 0; int ret = (::findfirst( _path, &_dta, FA_DIREC ) != -1 ) && ( _dta.ff_attrib & FA_DIREC ); _path[ lastCharPos ] = lastChar; return( ret ); } char * FileSpec::stripTrailingSlash() { int lastCharPos = strlen( _path ) - 1; if( (_path[lastCharPos] == '\\') || (_path[lastCharPos] == '/') ) _path[lastCharPos] = 0; return( _path ); } void FileSpec::addTrailingSlash() { int lastCharPos = strlen( _path ) - 1; if( (_path[lastCharPos] != '\\') && (_path[lastCharPos] != '/') ) { strcat( _path, "\\" ); split(); } } // End of file //