Marked As: Advanced
Hello,
below you find my latest work, a script to merge folders and sub folders with a script that I hiope to be an improvement over the command "move".
Imagine the following:
You're a person that like to order things, place documents and files in categorized folders, but you have two (or more) such folder structures, of which some of the sub folders have the same name and their content should be placed together.
Example:
Sites such as
http://hobbes.nmsu.edu have an ordered file structure, where they've placed files and apps in different folders. To get the structure automatically you'd e.g. use awget or plain wget and turn on the parameter to recreate the folder structure. The result is a neat and tidy directory tree with the apps you download from hobbes.
What do you do in OS/2 to merge 2 such folders? Move each files and sub folder by hand or...? That's where this code may come in handy.
The code has been tested (somewhat), but I can't promise anything, but I want you all to:
a) Look at a section at the time (which one doesn't matter) and try to understand what it does, or is supposed to do.
b) Try to see if you can find any errors or mistakes I've made
c) See if you can improve that part, e.g. remove code that we don't need, make it more robust, add another feature or support another syntax (way to call the script).
d) Post questions, suggestions etc. about your findings.
e) There's no function to show Usage! What features does this script support? Please reply with code how to write the function
Usage, what one can type on the command line to use it.
//Jan-Erik
/* Script: Move all files in specified directory and subdirectories to destination (folder). */
currdir = strip( DIRECTORY(), 'T', '\' )
numwords = 0
CALL rxFuncAdd "SysLoadFuncs" , "RexxUtil" , "SysLoadFuncs"
CALL SysLoadFuncs
CALL SysCls
IF ARG() = 0 THEN
Return Usage()
numwords = WORDS( ARG(1) )
params = ARG(1)
IF DIRECTORY( ARG(1) ) <> '' | STREAM( ARG(1), 'C', 'QUERY EXIST' ) <> ''
THEN
DO
to = currdir
from = ARG(1)
END
ELSE DO
/* count = COUNTSTR( '..\', params ) is only available in Object REXX, see replacement below */
count = 0
strpos = POS( '..\', params )
DO WHILE strpos > 0
count = count + 1
strpos = POS( '..\', params, strpos + 1 )
END
IF count > 0 THEN
DO
currpos = POS( '..\', params )
DO i = 1 TO count
counter = 1
DO WHILE currpos + counter = POS( '..\', params, currpos + 3 )
counter = counter + 1
i = i + 1
END
strpos = 1
DO j = 1 TO counter
strpos = POS( '\', REVERSE( currdir ), strpos )
END
params = substr( params, 1, currpos - 1 )||substr( currdir, 1, LENGTH( currdir ) - strpos )||substr( params, currpos + counter * 3 )
END
END
PARSE VALUE params WITH from '"<'to'>"' /* */
IF LENGTH( to ) = 0 THEN DO
PARSE VALUE params WITH from' \'to
IF LENGTH( to ) = 0 THEN DO
PARSE VALUE params WITH from' \\'to
IF LENGTH( to ) = 0 THEN DO
PARSE VALUE params WITH from':\'to':\'rest
IF LENGTH( rest ) > 0 THEN
DO
from = from||':\'||REVERSE( SUBWORD( REVERSE( to ), 2 ) )
to = REVERSE( SUBWORD( REVERSE( to ), 1, 1 ) )||':\'||rest
END
ELSE
DO i = 1 TO numwords
to = REVERSE( SUBWORD( REVERSE( params ), 1, i ) )
from = REVERSE( SUBWORD( REVERSE( params ), i + 1 ) )
IF LENGTH( from ) > 0 THEN /* DIRECTORY can't handle UNC network paths :-( */
IF ( DIRECTORY( from ) <> '' | STREAM( from, 'C', 'QUERY EXIST' ) <> '' ) & ( DIRECTORY( to ) <> '' | STREAM( to, 'C', 'QUERY EXIST' ) <> '' ) THEN
LEAVE i
END
END
ELSE
to = '\\'||to
END
ELSE
to = currdir||'\'||to
END
ELSE to = '<'||TRANSLATE( to )'>'
END
IF LEFT( from, 1 ) = '\' & SUBSTR( from, 2, 1 ) <> '\' THEN
from = currdir||from
IF LENGTH( from ) = 0 THEN
from = currdir
from = STRIP( from, 'T', '\' )
CALL DIRECTORY currdir
IF LENGTH( to ) = 0 | params = to THEN
DO
olddir = DIRECTORY( from )
IF olddir <> '' THEN /* The directory exist, move everything from there to "here" */
to = olddir
ELSE IF STREAM( from, 'C', 'QUERY EXIST' ) <> '' THEN
to = DIRECTORY() /* The file exist, move it to this folder */
END
CALL rxBusy 'Loading, one moment please...', 0
elapsed = TIME( 'R' )
CALL processPath from, strip( to,, '"' ), 0, 1
CALL rxProgress 1, 2
CALL DIRECTORY currdir
EXIT 0
processPath: PROCEDURE EXPOSE elapsed counter_
source.path = STRIP( ARG(1),, '"' )
target.path = STRIP( ARG(2), 'T', '\' )
progress = ARG(3)
chunk = ARG(4)
SELECT
WHEN POS( '<', source.path ) > 0 THEN /* WPS Object */
DO
source.type = 1
source.path = TRANSLATE( source.path )
END
WHEN STREAM( source.path, 'C', 'QUERY EXIST' ) = 'READY:' THEN /* Existing file */
source.type = 2
WHEN DIRECTORY( source.path ) <> '' THEN /* Existing folder */
source.type = 3
OTHERWISE source.type = 0 /* Unknown / Doesn't exist */
END
IF POS( '<', ARG(2) ) > 0 THEN /* WPS Object */
target.type = 1
ELSE DO
IF POS( '\', source.path ) > 0 THEN
target.path = target.path||SUBSTR( source.path, LASTPOS( '\', source.path ) )
IF STREAM( target.path, 'C', 'QUERY EXIST' ) = 'READY:' THEN /* Already existing file */
target.type = 2 /* You're not allowed to specify the target file name! */
ELSE IF DIRECTORY( target.path ) <> '' THEN /* Already existing folder */
target.type = 3
ELSE target.type = 0 /* Unknown / Doesn't exist */
END
CALL DIRECTORY STRIP( FILESPEC( 'D', source.path ), 'T', '\' )||'\'
IF source.type = 2 & target.type > 0 THEN /* Can't move the file */
SAY ARG(2)||" already exist"
ELSE IF source.type = 3 & target.type = 2 THEN /* Can't move the folder */
SAY "Can't move the folder "||source.path||" to "||ARG(2)||" as it is a file."
ELSE IF source.type = 1 & target.type = 2 THEN /* Can't move the object */
SAY "Can't move the object "||source.path||" to "||ARG(2)||" as it is a file."
ELSE IF target.type = 2 THEN /* Can't move to a folder */
SAY "Can't move "||source.path||" to "||ARG(2)||" as it is a file."
ELSE IF SysMoveObject( source.path, STRIP( ARG(2), 'T', '\' ) ) = 0 THEN
DO
IF source.type = 1 | target.type = 1 THEN
SAY "Couldn't move "||FILESPEC( 'N', source.path )||" to "||ARG(2) /* Couldn't move the object, Improvement possible (query object path and continue) */
ELSE DO
CALL SysFileTree source.path||'\*', 'folder', 'DO'
IF target.type = 1 | target.type = 3 THEN
CALL SysFileTree source.path||'\*', 'file', 'FO'
ELSE file.0 = 0
DO j = 1 to folder.0
IF TIME( 'E' ) > 1 + elapsed THEN DO
CALL rxBusy 'Processing '||folder.j, 0
CALL rxProgress progress + ( j - 1 ) / ( folder.0 + file.0 ) * chunk, 2
elapsed = TIME( 'E' )
END
CALL processPath folder.j, target.path, progress + ( j - 1 ) / ( folder.0 + file.0 ) * chunk, chunk / ( folder.0 + file.0 )
END
DROP folder.
IF target.type = 1 | target.type = 3 THEN
DO
DO i = 1 to file.0
IF TIME( 'E' ) > 1 + elapsed THEN DO
CALL rxBusy 'Processing '||source.path, 0
CALL rxProgress progress + ( j + i - 1 ) / ( j + file.0 ) * chunk, 2
elapsed = TIME( 'E' )
END
rc = SysMoveObject( file.i, target.path )
END
DROP file.
END
END
END
ELSE CALL rxBusy FILESPEC( 'N', source.path )||' has been moved to '||ARG(2), 0
RETURN
/* part, of_total, display_on_row */
rxProgress: PROCEDURE
IF DATATYPE( ARG(1), 'N' ) THEN
DO
progress = MIN( TRUNC( 76 * ARG(1) ), 76 )
CALL rxOut LEFT( COPIES( '█', progress )||COPIES( '░', 76 - progress ), 76 )||RIGHT( TRUNC( 100 * ARG(1) )||'%', 4 ), ARG(2)
END
Return 0
rxBusy: PROCEDURE EXPOSE counter_
SELECT
WHEN counter_ = 1 THEN
CALL rxOut '/ '||ARG(1), ARG(2)
WHEN counter_ = 2 THEN
CALL rxOut '- '||ARG(1), ARG(2)
WHEN counter_ = 3 THEN
CALL rxOut '\ '||ARG(1), ARG(2)
OTHERWISE
counter_ = 0
CALL rxOut '| '||ARG(1), ARG(2)
END
counter_ = counter_ + 1
Return 0
/* text, display_on_row */
rxOut: PROCEDURE
IF DATATYPE( ARG(2), 'W' ) THEN
PARSE VALUE SysCurPos( ARG(2), 0 ) with prev_row prev_col
SAY LEFT( ARG(1), 80 )
IF DATATYPE( ARG(2), 'W' ) THEN
CALL SysCurPos prev_row, prev_col
Return 0