diff --git a/bld/wmake/c/mexec.c b/bld/wmake/c/mexec.c index 239cafafc6..5aa0a729ea 100644 --- a/bld/wmake/c/mexec.c +++ b/bld/wmake/c/mexec.c @@ -159,6 +159,7 @@ STATIC const char * const dosInternals[] = { /* COMMAND.COM commands */ static const char * const percentCmds[] = { "ABORT", "APPEND", + "COPY", "CREATE", "ERASE", "MAKE", @@ -174,6 +175,7 @@ static const char * const percentCmds[] = { enum { PER_ABORT, PER_APPEND, + PER_COPY, PER_CREATE, PER_ERASE, PER_MAKE, @@ -197,6 +199,21 @@ STATIC NKLIST *noKeepList; /* contains the list of files that needs to be cleaned when wmake exits */ +static bool IsDotOrDotDot( const char *fname ) +/********************************************* + * return true if fname is "." or "..", false otherwise + */ +{ + return( fname[0] == '.' && ( fname[1] == NULLCHAR || ( fname[1] == '.' && fname[2] == NULLCHAR ) ) ); +} + +static bool chk_is_dir( const char *name ) +{ + struct stat s; + + return( stat( name, &s ) == 0 && S_ISDIR( s.st_mode ) ); +} + char *CmdGetFileName( char *src, char **fname, bool osname ) /**********************************************************/ { @@ -802,6 +819,146 @@ STATIC bool percentRename( char *arg ) return( rename( fn1, fn2 ) == 0 ); } +static FILE *open_file( const char *name, const char *mode ) +/**********************************************************/ +{ + FILE *fp; + + fp = fopen( name, mode ); + if( fp == NULL ) + PrtMsg( ERR | ERROR_OPENING_FILE, name ); + return( fp ); +} + +static bool close_file( FILE *fp, const char *name ) +/**************************************************/ +{ + if( fp != NULL ) { + if( fclose( fp ) ) { + PrtMsg( ERR | ERROR_CLOSING_FILE, name ); + return( false ); + } + } + return( true ); +} + +static size_t read_block( void *buf, size_t len, FILE *fp, const char *name ) +/***************************************************************************/ +{ + size_t readlen; + + readlen = fread( buf, 1, len, fp ); + if( ferror( fp ) ) + PrtMsg( ERR | READ_ERROR, name ); + return( readlen ); +} + +static size_t write_block( const void *buf, size_t len, FILE *fp, const char *name ) +/**********************************************************************************/ +{ + size_t writelen; + + writelen = fwrite( buf, 1, len, fp ); + if( ferror( fp ) ) + PrtMsg( ERR | ERROR_WRITING_FILE, name ); + return( writelen ); +} + +STATIC bool oneCopy( const char *src, const char *dst ) +/*****************************************************/ +{ + FILE *fps; + FILE *fpd; + bool ok; + char buf[FILE_BUFFER_SIZE]; + size_t len; + struct stat st; + struct utimbuf dsttimes; + + ok = false; + fps = open_file( src, "rb" ); + if( fps != NULL ) { + fpd = open_file( dst, "wb" ); + if( fpd != NULL ) { + while( (len = read_block( buf, FILE_BUFFER_SIZE, fps, src )) == FILE_BUFFER_SIZE ) { + if( len != write_block( buf, len, fpd, dst ) ) { + break; + } + } + if( len != FILE_BUFFER_SIZE ) { + ok = ( len == write_block( buf, len, fpd, dst ) ); + } + ok &= close_file( fpd, dst ); + + stat( src, &st ); + dsttimes.actime = st.st_atime; + dsttimes.modtime = st.st_mtime; + utime( dst, &dsttimes ); + /* + * copy permissions: mostly necessary for the "x" bit + * some files is copied with the read-only permission + */ + chmod( dst, st.st_mode ); + } + ok &= close_file( fps, src ); + } + return( ok ); +} + +STATIC bool processCopy( const char *src, const char *dst ) +/*********************************************************/ +{ + char buf[FILE_BUFFER_SIZE]; + pgroup2 pg; + + if( chk_is_dir( dst ) ) { + _splitpath2( src, pg.buffer, NULL, NULL, &pg.fname, &pg.ext ); + _makepath( buf, NULL, dst, pg.fname, pg.ext ); + dst = strcpy( pg.buffer, buf ); + } + return( oneCopy( src, dst ) ); +} + +STATIC bool percentCopy( char *arg ) +/*********************************** + * "%COPY" {ws}+ {ws}+ + */ +{ + char *p; + char *fn1, *fn2; + + assert( arg != NULL ); + + if( Glob.noexec ) { + return( true ); + } + /* + * Get first LFN + */ + p = CmdGetFileName( arg, &fn1, false ); + if( *p == NULLCHAR || !cisws( *p ) ) { + PrtMsg( ERR | SYNTAX_ERROR_IN, percentCmds[PER_COPY] ); + PrtMsg( INF | PRNTSTR, "First file" ); + PrtMsg( INF | PRNTSTR, fn1 ); + return( false ); + } + *p++ = NULLCHAR; /* terminate first file name */ + /* + * skip ws after first and before second file name + */ + p = SkipWS( p ); + /* + * Get second LFN as well + */ + p = CmdGetFileName( p, &fn2, false ); + if( *p != NULLCHAR && !cisws( *p ) ) { + PrtMsg( ERR | SYNTAX_ERROR_IN, percentCmds[PER_COPY] ); + return( false ); + } + *p = NULLCHAR; /* terminate second file name */ + return( processCopy( fn1, fn2 ) != 0 ); +} + STATIC bool percentCmd( const char *cmdname, char *arg ) /******************************************************* * handle our special percent commands @@ -831,6 +988,9 @@ STATIC bool percentCmd( const char *cmdname, char *arg ) case PER_APPEND: ok = percentWrite( arg, WR_APPEND ); break; + case PER_COPY: + ok = percentCopy( arg ); + break; case PER_CREATE: ok = percentWrite( arg, WR_CREATE ); break; @@ -1499,21 +1659,6 @@ STATIC bool remove_item( const char *name, const rm_flags *flags, bool dir ) return( rc == 0 ); } -static bool IsDotOrDotDot( const char *fname ) -/********************************************* - * return true if fname is "." or "..", false otherwise - */ -{ - return( fname[0] == '.' && ( fname[1] == NULLCHAR || ( fname[1] == '.' && fname[2] == NULLCHAR ) ) ); -} - -static bool chk_is_dir( const char *name ) -{ - struct stat s; - - return( stat( name, &s ) == 0 && S_ISDIR( s.st_mode ) ); -} - static bool doRM( const char *fullpath, const rm_flags *flags ) { iolist *tmp; @@ -1808,153 +1953,6 @@ STATIC RET_T handleMkdir( char *cmd ) return( RET_SUCCESS ); } -static FILE *open_file( const char *name, const char *mode ) -/**********************************************************/ -{ - FILE *fp; - - fp = fopen( name, mode ); - if( fp == NULL ) - PrtMsg( ERR | ERROR_OPENING_FILE, name ); - return( fp ); -} - -static bool close_file( FILE *fp, const char *name ) -/**************************************************/ -{ - if( fp != NULL ) { - if( fclose( fp ) ) { - PrtMsg( ERR | ERROR_CLOSING_FILE, name ); - return( false ); - } - } - return( true ); -} - -static size_t read_block( void *buf, size_t len, FILE *fp, const char *name ) -/***************************************************************************/ -{ - size_t readlen; - - readlen = fread( buf, 1, len, fp ); - if( ferror( fp ) ) - PrtMsg( ERR | READ_ERROR, name ); - return( readlen ); -} - -static size_t write_block( const void *buf, size_t len, FILE *fp, const char *name ) -/**********************************************************************************/ -{ - size_t writelen; - - writelen = fwrite( buf, 1, len, fp ); - if( ferror( fp ) ) - PrtMsg( ERR | ERROR_WRITING_FILE, name ); - return( writelen ); -} - -STATIC bool oneCopy( const char *src, const char *dst ) -/*****************************************************/ -{ - FILE *fps; - FILE *fpd; - bool ok; - char buf[FILE_BUFFER_SIZE]; - size_t len; - struct stat st; - struct utimbuf dsttimes; - - ok = false; - fps = open_file( src, "rb" ); - if( fps != NULL ) { - fpd = open_file( dst, "wb" ); - if( fpd != NULL ) { - while( (len = read_block( buf, FILE_BUFFER_SIZE, fps, src )) == FILE_BUFFER_SIZE ) { - if( len != write_block( buf, len, fpd, dst ) ) { - break; - } - } - if( len != FILE_BUFFER_SIZE ) { - ok = ( len == write_block( buf, len, fpd, dst ) ); - } - ok &= close_file( fpd, dst ); - - stat( src, &st ); - dsttimes.actime = st.st_atime; - dsttimes.modtime = st.st_mtime; - utime( dst, &dsttimes ); - /* - * copy permissions: mostly necessary for the "x" bit - * some files is copied with the read-only permission - */ - chmod( dst, st.st_mode ); - } - ok &= close_file( fps, src ); - } - return( ok ); -} - -STATIC bool processCopy( const char *src, const char *dst ) -/*********************************************************/ -{ - char buf[FILE_BUFFER_SIZE]; - pgroup2 pg; - - if( chk_is_dir( dst ) ) { - _splitpath2( src, pg.buffer, NULL, NULL, &pg.fname, &pg.ext ); - _makepath( buf, NULL, dst, pg.fname, pg.ext ); - dst = strcpy( pg.buffer, buf ); - } - return( oneCopy( src, dst ) ); -} - -STATIC RET_T handleCopy( char *arg ) -/*********************************** - * "COPY" {ws}+ {ws}+ - */ -{ - char *p; - char *fn1, *fn2; - - assert( arg != NULL ); - - if( Glob.noexec ) { - return( RET_SUCCESS ); - } - /* - * Get first LFN - * - * skip "COPY" - */ - p = arg + 4; - p = SkipWS( p ); - p = CmdGetFileName( p, &fn1, false ); - if( *p == NULLCHAR || !cisws( *p ) ) { - PrtMsg( ERR | SYNTAX_ERROR_IN, dosInternals[COM_COPY] ); - PrtMsg( INF | PRNTSTR, "First file" ); - PrtMsg( INF | PRNTSTR, fn1 ); - return( RET_ERROR ); - } - *p++ = NULLCHAR; /* terminate first file name */ - /* - * skip ws after first and before second file name - */ - p = SkipWS( p ); - /* - * Get second LFN as well - */ - p = CmdGetFileName( p, &fn2, false ); - if( *p != NULLCHAR && !cisws( *p ) ) { - PrtMsg( ERR | SYNTAX_ERROR_IN, dosInternals[COM_COPY] ); - return( RET_ERROR ); - } - *p = NULLCHAR; /* terminate second file name */ - if( processCopy( fn1, fn2 ) ) - return( RET_SUCCESS ); - return( RET_ERROR ); -} - - STATIC RET_T handleRmdir( char *cmd ) /************************************ * RMDIR {ws}+ @@ -2235,7 +2233,6 @@ STATIC RET_T shellSpawn( char *cmd, shell_flags flags ) case COM_RM: my_ret = handleRM( cmd ); break; case COM_MKDIR: my_ret = handleMkdir( cmd ); break; case COM_RMDIR: my_ret = handleRmdir( cmd ); break; - case COM_COPY: my_ret = handleCopy( cmd ); break; #if defined( __OS2__ ) || defined( __NT__ ) || defined( __UNIX__ ) || defined( __RDOS__ ) case COM_CD: case COM_CHDIR: my_ret = handleCD( cmd ); break; diff --git a/docs/doc/cmn/wmake.gml b/docs/doc/cmn/wmake.gml index c050ae4b75..802e172dbe 100644 --- a/docs/doc/cmn/wmake.gml +++ b/docs/doc/cmn/wmake.gml @@ -4506,8 +4506,6 @@ clear the screen start NT or OS/2 command processor .point command start DOS command processor -.point copy -copy or combine files, intercepted by &makcmdup .point ctty DOS redirect input/output to COM port .point d: @@ -4831,21 +4829,6 @@ The "rmdir" command may be used to delete a directory. &maksname "rmdir" command is is simplified implementation of the POSIX "rmdir" command. It handles directory names consistently with other &maksname commands. .* -.section copy command -.* -.np -.ix 'copy' 'using &makname' -The commands "copy" is intercepted by &maksname.. -It uses following syntax: -.millust begin - -copy - -.millust end -The "copy" command may be used to copy a file. -&maksname "copy" command is simplified implementation of DOS "copy" command. -It handles file names consistently with other &maksname commands. -.* .section &maksname internal commands .* .np @@ -4859,6 +4842,9 @@ It handles file names consistently with other &maksname commands. .ix '&makcmdup internal commands' '%append' .id %append .point +.ix '&makcmdup internal commands' '%copy' +.id %copy +.point .ix '&makcmdup internal commands' '%create' .id %create .point @@ -4942,6 +4928,20 @@ is a file specification and is arbitrary text. .np The +.id %copy +internal command will copy a file. +The command has the form: +.millust begin +%copy +.millust end +.pc +where +.id +and +.id +are a file specification. +.np +The .id %ren internal command will rename a file. The command has the form: