home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / dirtools.zip / DIRTREE.CMD < prev    next >
OS/2 REXX Batch file  |  2000-08-23  |  15KB  |  521 lines

  1. /* 05 Mar 1999. Daniel Hellerstein (danielh@econ.ag.gov)
  2.                  DirTree ver 1.02 
  3.   Sort (and display) all files in a directory tree by filename 
  4.  
  5.    You may freely use this utility,
  6.    You may also find the 3 procedures used here to be useful.
  7.    These are:
  8.         resolve_filename: return a fully qualified filename, given                    
  9.                           a relative filename and directory information
  10.         StemSort: sort a stem variable (using a bubble sort)
  11.         dir_exists: detects whether a directory exists
  12.  
  13. Standard disclaimer:
  14.   This program, and it's included procedures, may be
  15.   freely used, but you use them at your own risk.
  16.  
  17. */
  18.  
  19. parse arg dirfile astuff
  20.  
  21. if dirfile='?' then do
  22. say 'DirTree: A utility to list all files in a directory tree, sorted by '
  23. say '         name, size, and/or date. '
  24. say
  25. say "Usage: x:>DIRTREE directory\file_pattern [-options]  "
  26. say
  27. say " Where: directory = directory tree to list (default is current directory) "
  28. say "       file_pattern = a file pattern (* is the default)"
  29. say " Options include:"
  30. say "      -Onds = Sort by n(ame), d(ate), and/or s(ize) "
  31. say "              The  default is to sort by name only"
  32. say "      -D =    Decending sort (default is ascending) "
  33. say '      -CT =   Count of files with this "filename"'
  34. say '              List first (as determined by sort position) such file'
  35. say '  -SHORT,-LONG,-VERYLONG = Style of display '
  36. say '  -SUMMARY = Display  summary (#files/#bytes); do NOT display matching files '
  37.  
  38. say 
  39. say "Examples: x:>dirtree \archive1\*.zip -Ond -D "
  40. say "          x:>dirtree * -summary "
  41.  
  42. say
  43. say "Or, enter DIRTREE at a command prompt (with no arguments) to be prompted. "
  44. exit
  45. end
  46.  
  47. /*---   Load REXX libraries ----- */
  48. /* Load up advanced REXX functions */
  49. foo=rxfuncquery('sysloadfuncs')
  50. if foo=1 then do
  51.   call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
  52.   call SysLoadFuncs
  53. end
  54.  
  55. foo=rxfuncquery('rexxlibregister')
  56. if foo=1 then do
  57.  call rxfuncadd 'rexxlibregister','rexxlib', 'rexxlibregister'
  58.  call rexxlibregister
  59. end
  60. gotrexxlib=rxfuncquery('rexxlibregister')
  61.  
  62. sortorder=''
  63. isdescend=0
  64. docount=0
  65. dolong=0
  66. filler=' "" '
  67. lmxdate=14
  68. dosummary=0
  69.  
  70. if dirfile<>'' then do 
  71.   if dirfile='*' then dirfile='*.*'
  72.  
  73.   if pos('.',dirfile)>0 then do  /* a filename also specified ? */
  74.      ii=max(lastpos('\',dirfile),lastpos(':',dirfile))
  75.      if ii=0 then do                   /* no path info */
  76.          adir=''
  77.          filename=dirfile
  78.      end /* do */
  79.      else do
  80.          adir=left(dirfile,ii-1)
  81.          filename=substr(dirfile,ii+1)
  82.      end /* do */
  83.   end /* do */
  84.   else do                      /* no filename specified */
  85.      filename='*.*'
  86.      adir=dirfile
  87.   end
  88.   astuff=translate(astuff)
  89.   if pos('-D',astuff)>0 then isdescend=1
  90.   if pos('-CT',astuff)>0 then docount=1
  91.   if pos('-LONG',astuff)>0 then dolong=1
  92.   if pos('-VERYLONG',astuff)>0 then dolong=2
  93.   if pos('SHORT',astuff)>0  then dolong=-1
  94.   if pos('SUM',astuff)>0 then dosummary=1
  95.  
  96.   if dolong=-1  then do
  97.     filler='    '
  98.     lmxdate=8
  99.   end
  100.   parse var astuff . '-O' sortorder .
  101.  
  102.   adir=resolve_filename('',adir,,1)
  103.   if adir='' then do
  104.      say "No such directory: "adir
  105.      exit
  106.   end 
  107.   say "Searching in: "adir
  108.   say "         for: "filename
  109. end /* do */
  110. else do                        /* from keyboard */
  111.   say "DirTree: sort files by names across a directory tree."
  112.   call charout," Starting directory: "
  113.   parse pull adir
  114.   adir=resolve_filename('',adir,,1)
  115.   if adir='' then do
  116.      say "No such directory: "adir
  117.      exit
  118.   end 
  119.   call charout, " Files to find (default=*): "
  120.   parse pull filename
  121.   if filename='' then filename='*'
  122.  
  123.   call charout,' Summary stats only (Y=yes)?'
  124.   pull dosummary
  125.   if dosummary<>'Y' then do
  126.      call charout,' Sort order string; d=date, s=size,n=name (i.e.; nd or ds):'
  127.      pull sortorder
  128.      call charout,' Descending order (1), or Ascending (ENTER) :'
  129.      pull isdescend
  130.   end
  131.   else do
  132.        dosummary=1
  133.   end 
  134. end
  135.  
  136. /* ready to rumble */
  137. if dir_exists(adir)=0 then do
  138.       say "No such directory: "adir
  139.       exit
  140. end /* do */
  141.  
  142. if dosummary=1  then do               /* just # files, # bytes, and # dirs? */
  143.    foo=dir_summary(adir||filename)
  144.    exit
  145. end 
  146.  
  147.  
  148. if sortorder='' then sortorder='N'
  149. oo=sysfiletree(adir||filename,'fils','FTS')
  150.  
  151. /* grab the files */
  152. lmxname=0; lmxsize=0
  153. do mm=1 to fils.0
  154.    parse var fils.mm  date.mm size.mm . aa
  155.    nam.mm=translate(filespec("n",aa)); path.mm=filespec('p',aa)
  156.    lmxsize=max(length(size.mm),lmxsize)
  157.    lmxname=max(length(nam.mm),lmxname)
  158.    if left(date.mm,2)<80 then
  159.       date.mm='20'||date.mm
  160.    else
  161.      date.mm='19'||date.mm
  162. end /* do */
  163. say "# of matching files= " fils.0
  164.  
  165. srtx.=''
  166. do ll2=1 to fils.0
  167.   do ll=1 to length(sortorder)
  168.      atype=substr(sortorder,ll,1)
  169.      select
  170.         when atype='N' then
  171.             srtx.ll2=srtx.ll2||left(nam.ll2,lmxname+1,' ')
  172.         when atype='S' then
  173.             srtx.ll2=srtx.ll2||right(size.ll2,lmxsize+1,'0')
  174.         when atype='D' then
  175.             srtx.ll2=srtx.ll2||left(date.ll2,15,' ')
  176.         otherwise
  177.             nop
  178.      end  /* select */
  179.   end /* do */
  180.   srtx.ll2=srtx.ll2||right(ll2,7,' ')
  181.  
  182. end /* do */
  183. srtx.0=fils.0
  184. say "Sorting by " sortorder " ... "
  185.  
  186.  
  187. /* use rexxlib sort, if available */
  188. if gotrexxlib=0 then do
  189.    foo=arraysort('srtx',,,,,,'I')
  190. end 
  191. else do
  192.   call stemsort 'srtx.',1 
  193. end
  194.  
  195.  
  196. kk=words(srtx.1)
  197.  
  198. oldname='..'
  199. oldsize='..'
  200. olddate='..'
  201. oldpath='..'
  202.  
  203. j1=1 ; j2=srtx.0 ; j3=1
  204. if isdescend=1  then do
  205.    j1=srtx.0; j2=1; j3=-1
  206. end /* do */
  207.  
  208.  
  209. /* Now write the output, using filename, date or time (optional), and path */
  210. ict=0
  211. do mm=j1 to j2 by j3
  212.    ith=strip(word(srtx.mm,kk))
  213.    a2=left(nam.ith,lmxname)
  214.    if a2=oldname then do                        /*always list filename */
  215.        a2=left(filler,lmxname,' ')
  216.        ict=ict+1
  217.    end
  218.    else do                      /* new name */
  219.        oldname=a2
  220.        if docount=1 then say '('ict') 'tmpline
  221.       ict=1
  222.     end
  223.    if pos('S',sortorder)>0 then do                      /* size is optional */
  224.       if oldsize<>size.ith then do
  225.         a3=right(strip(size.ith,'l','0'),lmxsize)
  226.         oldsize=size.ith
  227.       end
  228.       else do
  229.         a3=right(filler,lmxsize)
  230.       end
  231.       a2=a2||' '||a3
  232.    end
  233.    if pos('D',sortorder)>0 then do                      /*date is optional */
  234.       if olddate<>date.ith then do
  235.         a3=substr(date.ith,3)
  236.         parse var a3 yr '/' mo '/' day '/' hr '/' min
  237.         a3=yr'-'mo'-'day
  238.         if dolong<>-1 then a3=a3||' 'hr':'min
  239.         olddate=date.ith
  240.       end
  241.       else do
  242.         a3=right(filler,lmxdate)
  243.       end
  244.       a2=a2||' '||a3
  245.    end
  246.    
  247.    if dolong=-1 & ict>1 & length(path.ith)>length(oldpath) then do         /* shorten path? */
  248.       icc=compare(translate(oldpath),translate(path.ith))
  249.       icc2=lastpos('\',oldpath,icc)
  250.       showpath=copies(' ',icc2-1)||substr(path.ith,icc2)
  251.       oldpath=path.ith
  252.    end
  253.    else do
  254.        oldpath=path.ith
  255.        showpath=path.ith
  256.    end /* do */
  257.         
  258.    select
  259.      when dolong=2 then  a2=a2||' 'fils.ith
  260.      when dolong=1 then a2=a2||' '||strip(word(fils.ith,4))
  261.      otherwise a2=a2||' 'showpath
  262.    end
  263.    
  264. /* either write line, or retain (and write with count later) */
  265.  
  266.    if docount=1 then do
  267.       if ict=1 then tmpline=a2
  268.    end
  269.    else do
  270.       say a2 
  271.    end
  272. end /* do */
  273. if docount=1 then say '('ict') 'tmpline
  274.  
  275. exit
  276.  
  277.  
  278. /*     ************************************************               */
  279. /* the following procedures might prove useful in other contexts....  */
  280. /*      *************************************************              */
  281.  
  282. /* this simple sort procedure is courtesy of Stan Irish, and
  283. was obtained from comp.lang.rexx
  284. Usage:
  285.    call StemSort 'stemname.',column
  286. where
  287.     stemname = The name of a stem variable containing an "array" to
  288.                sort.   
  289.                   stemname.0 MUST be set to the number of elements
  290.                   in the array!
  291.     column   = (optional) the column number (the character number of
  292.                values in (stemname.) to sort from. 
  293.                If not specified, sort from column 1.
  294.  
  295. No value is returned, but 'stemname.' is sorted in place.
  296.  
  297. */
  298.  
  299.  
  300. StemSort:
  301.   !stem = arg(1)
  302.   call StemSortProc !stem,arg(2)
  303.   return 0
  304.  
  305. StemSortProc:Procedure expose (!stem)
  306. /* returns:  nothing
  307.  Uses:     xxx = value(stemname.i) to get element values
  308.        and  rc  = value(stemname.i,xxx) to set element values
  309. */
  310.  
  311.   sortstem = arg(1)
  312.   If datatype(arg(2)) = 'NUM' then SortColumn = arg(2)
  313.   Else SortColumn = 1
  314.  
  315.   d = value(sortstem||0) % 2              /* d is a distancemeasurement     */
  316.   do while d > 0
  317.     do until finished             /* start of mini-bubblesort loop   */
  318.       finished = 1
  319.       do i=1 to value(sortstem||0)-d
  320.         j = i+d           /* we now compare and swap items i and i+d */
  321.         if substr(value(sortstem||i),SortColumn) >substr(value(sortstem||j),SortColumn) then
  322.           do
  323.             temp = value(sortstem||i)
  324.             rc = value(sortstem||i,value(sortstem||j))
  325.             rc = value(sortstem||j,temp)
  326.             finished = 0
  327.           end
  328.       end
  329.     end                           /* end of mini-bubblesort loop     */
  330.     d = d%2
  331.   end
  332.   RETURN ''
  333.  
  334.  
  335. /* --------------------------------------------------------------------*/
  336. /* Resolve a filename into a fully qualified file.
  337.    This will take  a variety of filenames; including such forms as:
  338.    FOO.BAR, E:FOO.BAR,  XYZ\FOO.BAR, and E:ABC\FOO.BAR
  339.  
  340.    Returns the fully qualified filename; or (if nocheck<>1,
  341.    a '' if this filename does not exist.
  342.  
  343. Usage:
  344.   filename=resolve_filename(a_filename,a_directory,default_ext,nocheck)
  345. where
  346.   a_filename = a filename  to use
  347.                a_filename can contain "path information". If this
  348.                is relative path information, then the path information
  349.                from a_filename will be appended to the a_directory.
  350.  a_directory = a directory, or a relative directory, to use.
  351.                If a relative directory, a_directory will be converted
  352.                to a fully qualified directory before path information
  353.                from a_filename is appended.
  354.  default_ext = add this extension to a_filename, if a_filename does not
  355.                have a period (a .) in it
  356.     nocheck  = If 1, do NOT verify the existence of this file
  357. and
  358.   filename   = a fully qualified filename, or a '' (signifying "no such
  359.                file)
  360.  
  361.  
  362. Hint: if you do not specify a filename, then resolve_filename will
  363.       check for the existence of a directory (rather then an explicit
  364.       file within the directory
  365. */
  366.  
  367. resolve_filename:procedure
  368.  
  369. parse arg afile,adir,defext,nocheck
  370. afile=strip(afile) ; adir=strip(adir)
  371.  
  372. curdir0=directory()
  373. curdir=curdir0'\'
  374.  
  375. if adir='' then adir=curdir     /* no adir specified, use current */
  376.  
  377. if right(adir,1)<>'\' & right(adir,1)<>':' then adir=adir'\'
  378.  
  379. usedrive=filespec('D',adir)
  380. usedrive0=usedrive
  381.  
  382. if usedrive='' then usedrive=filespec('D',curdir) /* no drive in adir, use current*/
  383.  
  384. usepath=filespec('P',adir)
  385. if left(usepath,1)<>'\' then do    /* relative to current usedrive path */
  386.    foo=directory(usedrive)'\'
  387.    foo2=directory(curdir0)
  388.    usepath=filespec('p',foo)||usepath
  389. end /* do */
  390. oldfile=filespec('n',afile)
  391.  
  392. /* a hack, but what the heck.. */
  393. do forever
  394.   if pos('\\',usepath)=0 then leave
  395.   parse var usepath a1 '\\' a2
  396.   if length(a1)=0 then 
  397.      usepath='\'
  398.   else
  399.      usepath=a1'\'
  400.   if a2='' then leave
  401.   usepath=usepath||a2
  402. end
  403. select
  404.   when substr(afile,2,2)=":\" then do /* if 2-3 = :\, then use afile as is */
  405.      usefile=afile
  406.   end /* do */
  407.  
  408.   when substr(afile,2,1)=':' then do    /* relative file name on drive */
  409.        
  410.       if usedrive0='' then do            /* perhaps use usepath? */
  411.           usefile=left(afile,2)||usepath||oldfile
  412.       end               /* otherwise, use afile as is */
  413.       else do
  414.          usefile=afile
  415.       end /* do */
  416.   end
  417.   when left(afile,1,1)='\' then do      /* attach adir drive */
  418.       usefile=usedrive||afile
  419.   end
  420.   otherwise do
  421.       usefile=usedrive||usepath||afile
  422.   end
  423. end
  424.  
  425. if pos('.',afile)=0 & defext<>'' then usefile=usefile||'.'||strip(defext,'l','.')
  426.  
  427. /* a hack, but what the heck.. */
  428. do forever
  429.   if pos('\\',usefile)=0 then leave
  430.   parse var usefile a1 '\\' a2
  431.   usefile=a1'\'
  432.   if a2='' then leave
  433.   usefile=a1||a2
  434. end
  435.  
  436. if nocheck=1 then return usefile
  437.  
  438. if afile='' then do                     /* check for existence of directory*/
  439.    isit=dir_exists(bfile)
  440.    if isit=0 then return ''
  441.    return afile
  442. end
  443.  
  444. file=stream(usefile,'c','query exists')  /* check for existence of a file */
  445. return bfile
  446.  
  447.  
  448. /*************************************************/
  449. /* Check for the existence of a directory. Correctly identifies
  450.    empty directories.
  451. Usage:
  452.    flag=dir_exists(a_directory)
  453. where
  454.    flag=1 if a_directory exists (it might be an empty directory )
  455.    flag=0 if it doesn't exist
  456. */
  457. dir_exists:procedure 
  458. parse arg adir
  459.  
  460. adir=strip(adir)
  461. adir=strip(adir,'t','\')
  462. nowdir=directory()
  463. nowdrive=filespec('d',nowdir'\')
  464. nowpath=filespec('p',nowdir'\')
  465. adr=filespec('d',adir)
  466. if adr='' then do
  467.    if abbrev(adir,'\')=0 then 
  468.        adir=nowdrive||nowpath||adir
  469.    else
  470.        adir=nowdrive||adir
  471. end /* do */
  472.  
  473. foo=sysfiletree(adir,goo,'D')
  474. if  goo.0>0  then return 1
  475. return 0
  476.  
  477.  
  478. /* summary of this directory tree */
  479. dir_summary:procedure
  480. parse arg todo
  481. oo=sysfiletree(todo,'fils','FTS')
  482. CALL CHAROUT,'>> '||translate(todo)
  483. if length(todo)>40 then say ' '
  484. call charout, " : # files=" fils.0
  485. isz=0
  486. do m=1 to fils.0
  487.    isz=isz+word(fils.m,2)
  488. end 
  489. call charout," ("||addcomma(isz)||")"
  490.  
  491. oo=sysfiletree(todo,'fils2','DTS')
  492. call charout,"; # directories= "fils2.0
  493. say
  494. EXIT
  495.  
  496. /************/
  497. /* ADD COMMAS TO A NUMBER */
  498. addcomma:procedure
  499. parse arg aval,ndec
  500. parse var aval p1 '.' p2
  501.  
  502. if ndec='' then do
  503.    p2=''
  504. end
  505. else do
  506.    p2='.'||left(p2,ndec,'0')
  507. end /* do */
  508.  
  509. plen=length(p1)
  510. p1new=''
  511. do i=1 to 10000 while plen>3
  512.    p1new=','right(p1,3)||p1new
  513.    p1=delstr(p1,plen-2)
  514.    plen=plen-3
  515. end /* do */
  516.  
  517. return p1||p1new||p2
  518.  
  519.  
  520.  
  521.