home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / cmdpk164.zip / xcp.cmd < prev    next >
OS/2 REXX Batch file  |  1998-01-10  |  15KB  |  495 lines

  1. /*  This is CommandPak's xcp command.                       */
  2. /*  (w) 1998 Ulrich Möller                                  */
  3.  
  4. '@echo off'
  5.  
  6. /*  to do: SIMPLE_BACKUP_SUFFIX env var
  7.            "-S" for suffix setting */
  8.  
  9. call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
  10. call SysLoadFuncs
  11.  
  12. /* The following messages have not yet been moved into XHELPxxx.MSG and will thus
  13.    always be displayed in English. Language support might be added in a later release. */
  14.  
  15. nl = '0d0a'x
  16. err = '<HTML><I>Error in xcp:</I> '
  17. errhlp = 'Type <A HREF="">xcp -h</A> for help.'
  18. nofilesMsg = err||'File(s) not found. '||errhlp
  19. unknownoptionMsg = err||'Unknown option (<B>-%a</B>). '||errhlp
  20. errorMsg1 = err||'Using these options is not allowed with two file specifications. '||errhlp
  21. errorMsg2 = err||'You must give two file specifications here. '||errhlp
  22. errorMsgFiles = err||'You have not specified any files. '||errhlp
  23. errorMsgTest = err||'The "test" option must be used with other options. '||errhlp
  24. errorMsgForce = err||'The "force" option can only be used when moving files. '||errhlp
  25. errorMsgInteractive = err||'The "interactive" option can presently not be used with the options you have specified. '||errhlp
  26. invwcMsg = err||'Invalid wildcard usage. '||errhlp
  27. checkingMsg = "Checking" /* argument will be added automatically */
  28. procMsg = "Processing" /* argument will be added automatically */
  29. replacedMsg = '  Replaced invalid characters in .LONGNAME:'
  30. longDelMsg = "  .LONGNAME for %a deleted (contained %b)"
  31. skipMsg = '  Skipped deleting .LONGNAME; contains important characters'
  32. inuseMsg = "  Could not remove .LONGNAME for %a; file seems to be in use"
  33. backedupMsg = "    Backed up %a to %b"
  34. copyMsg = "  Copying %a to %b"
  35. replaceMsg = "    %a exists."nl"      (R)eplace (B)ackup original (S)kip replace_(A)ll? "
  36. interactMsg = "    Is this OK? (Y)es (N)o (A)ll "
  37. dontWorryMsg = "Don't worry, this was test mode only. Nothing was modified."
  38. interruptMsg = "xcp was interrupted externally."
  39.  
  40. invalidChars = '\/:*?"<>|,+=[];'
  41.  
  42. signal on halt; trace off
  43.  
  44. parse arg args
  45.  
  46. alwaysReplace = 0
  47. old. = ""
  48. new. = ""
  49. deletelong = 0
  50. verbose = 0
  51. quiet = 0
  52. test = 0
  53. debug = 0
  54. movealso = 0
  55. force = 0
  56. interactive = 0
  57. backup = 0
  58. FAT=0
  59.  
  60. /* first process arguments/options */
  61. do while (args \= "")
  62.     parse value args with opt1 args
  63.     if debug then Say "  Parsing" opt1
  64.     if (substr(opt1, 1, 1)="-") | (substr(opt1, 1, 1)="/") then do
  65.         do optcount = 2 to length(opt1) by 1
  66.             optchar = substr(opt1, optcount, 1)
  67.             if debug then Say "    Subparsing" optchar
  68.             select
  69.                 when (optchar="D") then do
  70.                     Say "Debug messages turned on."
  71.                     debug = 1
  72.                     verbose = 1
  73.                     test = 1
  74.                 end
  75.                 when (optchar="d") then
  76.                     deletelong = 1
  77.                 when (optchar="t") then do
  78.                     test = 1
  79.                     verbose = 1
  80.                 end
  81.                 when (optchar="8") then
  82.                     FAT = 1
  83.                 when (optchar="b") then do
  84.                     backup = 1
  85.                     interactive = 0
  86.                     force = 0
  87.                 end
  88.                 when (optchar="f") then do
  89.                     force = 1
  90.                     interactive = 0
  91.                     backup = 0
  92.                 end
  93.                 when (optchar="i") then do
  94.                     interactive = 1
  95.                     force=0
  96.                 end
  97.                 when (optchar="v") then do
  98.                     verbose = 1
  99.                     quiet = 0
  100.                 end
  101.                 when (optchar="q") then do
  102.                     quiet = 1
  103.                     verbose = 0
  104.                 end
  105.                 when (optchar="h") | (optchar = "?") then do
  106.                     'call xhelp xcp'
  107.                     exit
  108.                 end
  109.             otherwise do
  110.                 'call xhelp "'strReplace(unknownoptionMsg, "%a", optchar)'"'
  111.                 exit
  112.             end
  113.             end /* select */
  114.         end /* do */
  115.     end /* if */
  116.     else
  117.         if old.complete = "" then
  118.             old.complete = opt1
  119.         else new.complete = opt1
  120. end /* do while */
  121.  
  122. if (old.complete = "") then do
  123.     'call xhelp "'errorMsgFiles'"'
  124.     exit
  125. end
  126.  
  127. /* now collect files */
  128. if debug then
  129.     say "Collecting files"
  130.  
  131. files.0 = 0
  132. curdir = directory()
  133. if (directory(old.complete) \= "") then do
  134.     files.1 = old.complete
  135.     files.0 = 1
  136. end
  137. else if (old.complete = "..") then do
  138.     files.1 = ".."
  139.     files.0 = 1               /* these are funny bugs in SysFileTree */
  140. end
  141. else do
  142.     rc = SysFileTree(old.complete, files, "FO", '*--*-')
  143.                                /* Attribs: 'ADHRS' */
  144.     if debug then Say "  "files.0 "file(s) found"
  145.     if files.0 = 0 then do
  146.         'call xhelp "'nofilesMsg'"'
  147.         exit
  148.     end
  149. end
  150. call directory(curdir)
  151.  
  152. renMode = 0
  153. moveMode = 0
  154. extMode = 0
  155. wildcards = 0
  156.  
  157. do
  158.     if debug then say "Entering mode analysis for old.spec"
  159.     old.path = filespec('drive', old.complete)||filespec('path', old.complete)
  160.     old.spec = filespec('name', old.complete)
  161.     if debug then do
  162.         say '  old.path:  "'old.path'"'
  163.         say '  old.spec:  "'old.spec'"'
  164.     end
  165. end
  166.  
  167. if (new.complete = "") then do /* no second spec given: assume current dir */
  168.     new.complete = "."
  169. end
  170.  
  171. if (new.complete \= "") then do
  172.     /* second spec given: seems to be rename/move mode. */
  173.     if debug then say "Entering mode analysis for newspec"
  174.  
  175.     if (new.complete \= "\") & (substr(new.complete, 2) \= ":\") & (right(new.complete, 1) = "\") then new.complete = strip(new.complete, 't', '\')
  176.     curdir = directory()
  177.     if (directory(new.complete) \= "") then do
  178.         /* second spec is dir only --> just move, no rename */
  179.         moveMode = 1
  180.         new.path = new.complete
  181.         renMode = 0
  182.         new.spec = ""
  183.     end
  184.     else do
  185.         new.path = filespec('drive', new.complete)||filespec('path', new.complete)
  186.         new.spec = filespec('name', new.complete)
  187.  
  188.         if (new.path \= "") then do
  189.             moveMode = 1
  190.             if (new.path \= "\") & (substr(new.path, 2) \= ":\") & (right(new.path, 1) = "\") then new.path = strip(new.path, 't', '\')
  191.         end
  192.         else do
  193.             moveMode = 1
  194.             new.path = directory()
  195.         end
  196.         if (new.spec \= "") then do
  197.             renMode = 1
  198.         end
  199.         /* second spec is */
  200.     end
  201.     call directory curdir
  202.  
  203.     if debug then do
  204.         if renMode then say "  -> Copy mode enabled; renaming to" new.spec
  205.         if moveMode then say "  -> Copy mode enabled; moving to" new.path
  206.         if extMode then say "  -> Extended mode enabled"
  207.     end
  208.  
  209.     if extMode then do
  210.         'call xhelp "'errorMsg1'"'
  211.         exit
  212.     end
  213. end
  214.  
  215. if renMode then do
  216.     /* now evaluate wildcards */
  217.     if (pos('*', new.spec) \= 0) | (pos('?', new.spec) \= 0) then do
  218.             wildcards = 1
  219.             if debug then say "Evaluating wildcards"
  220.             old.wild.pos = pos('*', old.spec)
  221.             new.wild.pos = pos('*', new.spec)
  222.  
  223.             if (old.wild.pos = 1) then
  224.                 if (pos('*', substr(old.spec, old.wild.pos+1)) > 0) then call invwc
  225.                 else if (new.wild.pos = 1) then
  226.                     if (pos('*', substr(new.spec, new.wild.pos+1)) > 0) then call invwc
  227.                     else do
  228.                         old.wild.sub = translate(substr(old.spec, old.wild.pos+1))
  229.                         new.wild.sub = substr(new.spec, new.wild.pos+1)
  230.                     end
  231.                 else call invwc
  232.             else if (old.wild.pos = length(old.spec)) then
  233.                 if (new.wild.pos = length(new.spec)) then do
  234.                     old.wild.sub = translate(substr(old.spec, 1, old.wild.pos-1))
  235.                     new.wild.sub = substr(new.spec, 1, new.wild.pos-1)
  236.                 end
  237.                 else call invwc
  238.             else call invwc
  239.         if debug then do
  240.             say '  old.wild.sub:   "'old.wild.sub'"'
  241.             say '  new.wild.sub:   "'new.wild.sub'"'
  242.         end
  243.     end /* wildcards */
  244. end
  245.  
  246.  
  247. /* now work on file list */
  248. if debug then say "Entering file processing"nl
  249.  
  250. do i = 1 to files.0
  251.     oldName = files.i
  252.     oldnameonly = filespec('name', oldname)
  253.  
  254.     if (deleteLong) then
  255.         call deleteLongname oldname
  256.  
  257.     /* check which mode we're in */
  258.     select
  259.         when (moveMode) then do    /* move: when different directory specified */
  260.             /* first compose new name */
  261.             if renMode then
  262.                 newNameOnly = getNewName(oldname)
  263.             else
  264.                 newNameOnly = filespec('name', oldname)
  265.  
  266.             if (FAT) then
  267.                 newNameOnly = makeFAT(newNameOnly)
  268.  
  269.             if (right(new.path, 1) \= "\") then
  270.                 moveTo = new.path||'\'
  271.             else moveTo = new.path
  272.             newName = moveTo||newNameOnly
  273.  
  274.             /* now check if copying is allowed; confirm if neccessary */
  275.             moveOK = 1
  276.             if (verbose | interactive) then
  277.                 say strReplace(strReplace(copyMsg, '%a', oldname), '%b', newname)
  278.             else if (\quiet) then say oldname
  279.  
  280.             if (stream(newName,'c','query exist') \= "") then do
  281.                 if (force) then
  282.                     'del' newName
  283.                 else if (backup) then
  284.                     call backupFile newName
  285.                 else do
  286.                     resp = queryExists(strReplace(replaceMsg, '%a', newName))
  287.                     if (resp = "R") then
  288.                         'del' newName
  289.                     else if (resp = "B") then
  290.                         call backupFile newName
  291.                     else
  292.                         moveOK = 0
  293.                 end
  294.             end
  295.             else
  296.                 if (interactive) then
  297.                     moveOK = (queryYN(interactMsg))
  298.  
  299.             /* finally, copy file */
  300.             if (moveOK) then
  301.                 if (\test) then do
  302.                     'copy' oldname newname ">NUL"
  303.                     /* 'del' oldname '/N' */
  304.                 end
  305.                 else if debug then do
  306.                     Say '    -- copy' oldname newname
  307.                     /* Say '    -- del' oldname */
  308.                 end
  309.         end
  310.  
  311.         when renMode then do
  312.         /* rename only */
  313.             newNameOnly = getNewName(files.i)
  314.  
  315.             if (FAT) then
  316.                 newNameOnly = makeFAT(newNameOnly)
  317.  
  318.             call copyFile oldname newNameOnly
  319.         end
  320.  
  321.         otherwise ;
  322.     end /* select */
  323. end /* do files.i */
  324.  
  325. if (test) then say dontWorryMsg
  326.  
  327. exit
  328.  
  329. getNewName:
  330.     _oldname = arg(1)
  331.     if (wildcards) then
  332.         _newname = strReplace(filespec('name', _oldname), old.wild.sub, new.wild.sub)
  333.     else
  334.         _newname = new.spec
  335. return _newName
  336.  
  337. makeFAT: procedure expose debug
  338.     _old = arg(1)
  339.     _p = pos(".", _old)
  340.     _p2 = _p
  341.     if _p2 > 8 then _p2=8
  342.     if (_p > 0) then do
  343.         _new = left(_old, _p2-1)||"."||substr(_old, _p+1, 3)
  344.     end
  345.     else _new = left(_old, 8)
  346.     if debug then
  347.         say "    makeFAT:" _old "-->" _new
  348. return _new
  349.  
  350. deleteLongname:
  351.     realname = arg(1)
  352.     rc = SysGetEA(realname, ".LONGNAME", "longname_")
  353.     longname = substr(longname_, 5)
  354.  
  355.     if (longname \= "") then
  356.         if ((\invalidName(longname)) | force) then do
  357.             if \test then
  358.                 call SysPutEA realname, ".LONGNAME", ""
  359.  
  360.             if (\quiet) then do
  361.                 rc = SysGetEA(realname, ".LONGNAME", "longname2")
  362.                 if ((longname2 \= "") & \test & \quiet) then
  363.                     Say strReplace(inuseMsg, '%a', realname)
  364.                 else
  365.                     if (\quiet) then
  366.                         Say strReplace(strReplace(longDelMsg, '%b', longname), '%a', realname)
  367.             end
  368.         end
  369.         else
  370.             if \quiet then
  371.                 Say skipMsg
  372. return
  373.  
  374. copyFile:
  375.     if (deleteLong) then
  376.         call deleteLongname oldname
  377.  
  378.     if (filespec("NAME", oldname) \= newNameOnly) then do
  379.         if (verbose | interactive) then
  380.             say strReplace(strReplace(copyMsg, '%a', oldname), '%b', newNameOnly)
  381.  
  382.         renOK = \interactive
  383.         if (interactive) then
  384.             renOK = queryYN(interactMsg)
  385.  
  386.         if (renOK) then
  387.             if (\test) then
  388.                 'copy' oldname newNameOnly
  389.             else if debug then
  390.                 Say '    -- copy' oldname newNameOnly
  391.     end
  392. return
  393.  
  394.  
  395. backupFile:
  396.     oldfile = arg(1)
  397.     oldfile2 = oldfile
  398.     ext = ""
  399.     p = lastpos(".", oldfile)
  400.     if (p > 0) then do
  401.         ext = substr(oldfile, p)
  402.         oldfile2 = left(oldfile, p-1)
  403.     end
  404.     p = lastpos("!", oldfile2)
  405.     if (p > 0) then do
  406.         if datatype(substr(oldfile2, p+1)) = "NUM" then do
  407.             bak = substr(oldfile2, p+1)+1
  408.             oldfile2 = left(oldfile2, p-1)
  409.         end
  410.         else bak = 1
  411.     end
  412.     else bak = 1
  413.  
  414.     newfile = filespec('name', oldfile2)
  415.     do while (stream(moveTo||newfile"!"bak||ext,'c','query exist') \= "")
  416.         bak = bak+1
  417.     end
  418.  
  419.     if (verbose) then say strReplace(strReplace(backedupMsg, '%b', newfile"!"bak||ext), '%a', oldfile)
  420.     'ren' oldfile newfile"!"bak||ext
  421. return
  422.  
  423.  
  424. strReplace:
  425.     parse arg str, old, new
  426.     p = pos(translate(old), translate(str))
  427.     if (p > 0) then
  428.         return left(str, p-1)||new||substr(str,p+length(old))
  429.     else
  430.         return str
  431.  
  432. invwc:
  433.     'call xhelp "'invwcMsg'"'
  434.     exit
  435.  
  436. lowercase:
  437.     return translate(arg(1), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
  438.  
  439. invalidName:
  440.     invalid = 0
  441.     do i9 = 1 to length(longname)
  442.         if (pos(substr(longname, i9, 1), invalidChars) \= 0) then
  443.             invalid = 1
  444.         if invalid then leave
  445.     end
  446. return invalid
  447.  
  448. queryYN:
  449.     if \alwaysReplace then do
  450.         call charout , arg(1)
  451.         key = ''
  452.         do until pos(key,"YNA") > 0
  453.            key = translate(SysGetKey("NOECHO"))
  454.         end /* do */
  455.         Say key
  456.         if (key = "A") then
  457.             alwaysReplace = 1
  458.      end
  459.      if (alwaysReplace) then key = "Y"
  460. return (translate(key) = "Y")
  461.  
  462. queryExists:
  463.     if \alwaysReplace then do
  464.         call charout , arg(1)
  465.         key = ''
  466.         do until pos(key,"RBSA") > 0
  467.            key = translate(SysGetKey("NOECHO"))
  468.         end /* do */
  469.         Say key
  470.         if (key = "A") then
  471.             alwaysReplace = 1
  472.      end
  473.      if (alwaysReplace) then key = "R"
  474. return key
  475.  
  476. halt:
  477.   "call xhelp -f abortMsg xcp"
  478.   exit
  479.  
  480.  
  481.  
  482.  
  483.  
  484.  
  485.  
  486.  
  487.  
  488.  
  489.  
  490.  
  491.  
  492.  
  493.  
  494.  
  495.