home *** CD-ROM | disk | FTP | other *** search
- /* recursive directory tool
-
- needs v37.
-
- Universal directory lister. called with no arguments, by just typing
- "d", it lists the current directory. template:
-
- DIR,REC/S,WIDTH/K/N,COL/K/N,SIZE/S,NOSORT/S,NOFILES/S,NODIRS/S,FULL/S,NOANSI/S,
- TARGET/K,DO/K/F
-
- DIR specifies an optional path to the dir you wish to list.
- may contain standard wildcard patterns like #?~[]%() etc.
- REC specifies that subdirectories should be listed recursively.
- WIDTH <num> max width of one line of output. if not present, D will
- infer this from the current width of the console.
- NOTE: currently it just takes WIDTH=77 as default. does anyone
- have code that gets the width from the console?
- COL <num> where n=1..10, by default, D will try and fit as many
- columns as allowed by WIDTH.
- SIZE reports the size of each dir as it is being listed. note that
- combined with REC gives sizes of whole dir (sub-)trees.
- NOSORT by default, dirs are sorted before display. disable this with
- the NOSORT switch.
- NOFILES displays just dirs
- NODIRS displays just files
- FULL lists full path instead of just filename
- NOANSI doesn't use ansi display codes while printing
- TARGET <dir> specifies a target directory for use with DO. should
- end in either "/" or ":"
- DO <comline> specifies a commandline for automatic script generation.
- note that this uses up the rest of D's commandline.
-
- something should be said on the script feature: it enables you
- to perform repetitive tasks on whole dirs, or dir-trees. existing
- utilities that enabled you to do such tasks where mostly not
- flexible enough; d enables you to use the REC keyword in combination
- with scripts, allows for variable extensions: use <file>.o if
- the original name was <file>.s, and the spec. of a target:
- resulting files from the operation are placed in another dir, which
- can be a complete mirror image of another dir-tree. makedir
- statements are inserted if target: is empty.
-
- following format codes may be used in <commandline>:
-
- %s is file (filename+path)
- %f is file WITHOUT extension
- %r is file without extension, but with leading <dir> replaced by
- <target> (usefull if <commandline> allows for an outputfile)
- %> or %< %>> etc. prevents the shell from thinking ">" is a redirection
- for D, instead of <commandline>
-
- a complex example:
- you wish to have a complete ascii reference of the emodules:
- directory, recursively, and with the resulting .txt files
- as a mirror-image directory structure somewhere else.
-
- 1> D >ram:script emodules: REC TARGET=t:mods/ DO showmodule %>%r.txt %s
- 1> execute ram:script
-
- will do that for you.
- for any file like "emodules:exec/io.m" D will make a line like:
- "showmodule >t:mods/exec/io.txt emodules:exec/io.m"
-
- other examples: D >mydirlist dh0: WIDTH=100 SIZE REC NOANSI
- D docs: DO type >prt: %s
- D asm: TARGET=obj: DO genam %s -o%r.o
- D emodules: REC TARGET=ram: DO showmodule %>%r.txt %s
-
- */
-
- OPT OSVERSION=37
-
- CONST MAXPATH=250
-
- ENUM ER_NONE,ER_BADARGS,ER_MEM,ER_UTIL,ER_ITARG,ER_COML
- ENUM ARG_DIR,ARG_REC,ARG_WIDTH,ARG_COL,ARG_SIZE,ARG_NOSORT,ARG_NOFILES,
- ARG_NODIRS,ARG_FULL,ARG_NOANSI,ARG_TARGET,ARG_COMMAND,NUMARGS
-
- MODULE 'dos/dosasl', 'dos/dos', 'utility', 'intuition/intuitionbase',
- 'intuition/intuition', 'graphics/gfxbase', 'graphics/text'
-
- RAISE ER_MEM IF New()=NIL, /* set common exceptions: */
- ER_MEM IF String()=NIL, /* every call to these functions will be */
- ERROR_BREAK IF CtrlC()=TRUE /* automatically checked against NIL, */
- /* and the exception ER_MEM is raised */
-
- DEF dir,command,target,
- recf=FALSE,col=3,calccolf=TRUE,comf=FALSE,sizef=FALSE,sortf=TRUE,filesf=TRUE,
- fullf=FALSE,ansif=TRUE,dirsf=TRUE,dirw[100]:STRING,
- rdargs=NIL,work[250]:STRING,work2[250]:STRING,dirno=0,
- prtab[25]:LIST,prcopy[25]:LIST,workdir[250]:STRING,
- consolewidth=0
-
- PROC main() HANDLE
- DEF args[NUMARGS]:LIST,templ,x,lock,fib:fileinfoblock,s
- IF (utilitybase:=OpenLibrary('utility.library',37))=NIL THEN Raise(ER_UTIL)
- FOR x:=0 TO NUMARGS-1 DO args[x]:=0
- templ:='DIR,REC/S,WIDTH/K/N,COL/K/N,SIZE/S,NOSORT/S,NOFILES/S,NODIRS/S,' +
- 'FULL/S,NOANSI/S,TARGET/K,DO/K/F'
- rdargs:=ReadArgs(templ,args,NIL)
- IF rdargs=NIL THEN Raise(ER_BADARGS) /* initialise flags */
- IF args[ARG_SIZE] THEN sizef:=TRUE /* from command line args */
- consolewidth:=Bounds(IF args[ARG_WIDTH] THEN Long(args[ARG_WIDTH]) ELSE findconsolewidth(),1,1000)
- IF args[ARG_COL] THEN (calccolf:=FALSE) BUT col:=Long(args[ARG_COL])
- col:=Bounds(col,1,100)
- IF args[ARG_NOSORT] THEN sortf:=FALSE
- IF args[ARG_NOANSI] THEN ansif:=FALSE
- IF args[ARG_NOFILES] THEN filesf:=FALSE
- IF args[ARG_NODIRS] THEN dirsf:=FALSE
- IF args[ARG_REC] THEN recf:=TRUE
- IF args[ARG_FULL] THEN fullf:=TRUE
- target:=args[ARG_TARGET]
- command:=args[ARG_COMMAND]
- IF command THEN comf:=TRUE
- IF target
- x:=target+StrLen(target)-1
- IF (x<target) OR ((x[]<>":") AND (x[]<>"/")) THEN Raise(ER_ITARG)
- ENDIF
- IF comf
- sortf:=FALSE /* read and convert commandline for scripts */
- col:=1
- filesf:=FALSE
- dirsf:=FALSE
- IF command[]=0 THEN Raise(ER_COML)
- s:=command
- WHILE x:=s[]++
- IF x="%"
- x:=s[]
- SELECT x
- CASE "s"; ListAdd(prtab,[1],1) /* %s = fullpath */
- CASE "f"; ListAdd(prtab,NEW [work],1); s[]:="s" /* %f = work */
- CASE "r"; ListAdd(prtab,NEW [work2],1); s[]:="s" /* %r = work2 */
- DEFAULT; s[-1]:=" "
- ENDSELECT
- ENDIF
- ENDWHILE
- ENDIF
- dir:=args[ARG_DIR]
- IF dir THEN StrCopy(dirw,dir,ALL)
- lock:=Lock(dirw,-2)
- IF lock /* if yes, the prob. dir, else wildcard */
- IF Examine(lock,fib) AND (fib.direntrytype>0)
- AddPart(dirw,'#?',100)
- ENDIF
- UnLock(lock)
- ENDIF
- recdir(dirw)
- Raise(ER_NONE)
- EXCEPT
- IF rdargs THEN FreeArgs(rdargs)
- IF utilitybase THEN CloseLibrary(utilitybase)
- SELECT exception
- CASE ER_BADARGS; PrintF('Bad Arguments for D!\n')
- CASE ER_MEM; PrintF('No mem!\n')
- CASE ER_COML; PrintF('No commandline specified\n')
- CASE ER_ITARG; PrintF('Illegal target\n')
- CASE ER_UTIL; PrintF('Could not open "utility.library" v37\n')
- CASE ERROR_BREAK; PrintF('User terminated D\n')
- CASE ERROR_BUFFER_OVERFLOW; PrintF('Internal error\n')
- DEFAULT; PrintFault(exception,'Dos Error')
- ENDSELECT
- ENDPROC
-
- PROC recdir(dirr) HANDLE
- DEF er,i:PTR TO fileinfoblock,size=0,anchor=NIL:PTR TO anchorpath,fullpath,
- flist=NIL,first,entries=0,ascii,w,x,y,z,flist2=NIL,
- isfirst=0,maxfilename=1,maxfilesize=-1,lcol
- anchor:=New(SIZEOF anchorpath+MAXPATH)
- anchor.breakbits:=4096
- anchor.strlen:=MAXPATH-1
- er:=MatchFirst(dirr,anchor) /* collect all strings */
- WHILE er=0
- fullpath:=anchor+SIZEOF anchorpath
- i:=anchor.info
- ascii:=IF fullf THEN fullpath ELSE i.filename
- IF i.direntrytype>0
- StringF(work,'\s\l\s[30] ',IF ansif THEN '\e' ELSE '',ascii)
- ELSE
- StringF(work,'\l\s[30] \r\d[8]',ascii,i.size)
- IF i.size>maxfilesize THEN maxfilesize:=i.size
- ENDIF
- x:=StrLen(ascii)
- IF x>maxfilename THEN maxfilename:=x
- IF IF i.direntrytype>0 THEN dirsf ELSE filesf
- first:=String(EstrLen(work))
- StrCopy(first,work,ALL)
- flist:=Link(first,flist)
- INC entries
- ENDIF
- IF i.direntrytype<0 THEN size:=size+i.size
- IF (i.direntrytype<0) AND comf /* execute commandline */
- ListCopy(prcopy,prtab,ALL)
- IF comf THEN MapList({x},prcopy,prcopy,`IF x=1 THEN fullpath ELSE x)
- StrCopy(work,fullpath,ALL)
- x:=InStr(work,'.',0)
- IF x<>-1 THEN SetStr(work,x) /* find f% */
- IF target
- StrCopy(work2,target,ALL)
- x:=work; y:=dirw /* was dirr */
- WHILE x[]++=y[]++ DO NOP
- DEC x
- StrAdd(work2,x,ALL) /* find r% */
- ELSE
- StrCopy(work2,work,ALL)
- ENDIF
- IF isfirst++=0
- StrCopy(workdir,work2,ALL) /* see if makedir is needed */
- SetStr(workdir,PathPart(work2)-work2)
- x:=Lock(workdir,-2)
- IF x THEN UnLock(x) ELSE PrintF('makedir \s\n',workdir)
- ENDIF
- Flush(stdout); VfPrintf(stdout,command,prcopy); Flush(stdout)
- PrintF('\n')
- ENDIF
- IF recf AND (i.direntrytype>0) /* do recursion(=tail) */
- x:=StrLen(fullpath)
- IF x+5<MAXPATH THEN CopyMem('/#?',fullpath+x,4)
- size:=size+recdir(fullpath)
- fullpath[x]:=0
- ENDIF
- er:=MatchNext(anchor)
- ENDWHILE
- IF er<>ERROR_NO_MORE_ENTRIES THEN Raise(er)
- MatchEnd(anchor)
- Dispose(anchor)
- anchor:=NIL
- maxfilesize:=IF maxfilesize>=0 THEN sillylog10(maxfilesize) ELSE 0
- lcol:=Bounds(IF calccolf THEN consolewidth+1/(maxfilesize+maxfilename+2) ELSE col,1,100)
- flist:=Link(String(1),flist)
- IF entries>2 AND sortf THEN flist:=sort(flist)
- IF comf=FALSE /* display dir */
- IF dirno THEN PrintF('\n')
- PrintF(IF ansif THEN '\e[1mDirectory of: "\s"\e[0m\n' ELSE 'Directory of: "\s"\n',dirr)
- ENDIF
- first:=flist
- x:=entries/lcol /* put dirlist in columns */
- IF x*lcol<entries THEN INC x
- FOR z:=1 TO x
- first:=Next(first)
- flist2:=first
- FOR y:=1 TO lcol
- IF flist2
- w:=maxfilename
- IF flist2[]="\e"
- flist2[w+1]:=0
- IF ansif THEN PutStr('\e[1;32m')
- PrintF('\s \s',flist2+1,flist2+40-maxfilesize)
- IF ansif THEN PutStr('\e[0;31m')
- ELSE
- flist2[w]:=0
- PrintF('\s \s',flist2,flist2+39-maxfilesize)
- ENDIF
- flist2:=Forward(flist2,x)
- IF y<>lcol THEN PrintF(' ')
- ENDIF
- ENDFOR
- PrintF('\n')
- CtrlC()
- ENDFOR
- IF sizef THEN PrintF('BYTE SIZE: \d\n',size)
- DisposeLink(flist)
- INC dirno
- EXCEPT /* nested exception handlers! */
- IF anchor THEN MatchEnd(anchor)
- Raise(exception) /* this way, we call _all_ handlers in the recursion */
- ENDPROC size /* and thus calling MatchEnd() on all hanging anchors */
-
- PROC sort(flist)
- DEF sortdone,prev,first,next,nnext
- REPEAT
- sortdone:=TRUE /* sort dirlist */
- prev:=first:=flist
- WHILE first:=Next(first)
- IF next:=Next(first)
- IF Stricmp(first,next)>0
- nnext:=Next(next)
- Link(prev,first:=Link(next,Link(first,nnext)))
- sortdone:=FALSE
- ENDIF
- ENDIF
- prev:=first
- ENDWHILE
- CtrlC()
- UNTIL sortdone
- ENDPROC flist
-
- PROC findconsolewidth()
- DEF ib:PTR TO intuitionbase,gb:PTR TO gfxbase,w,fw
- ib:=intuitionbase
- gb:=gfxbase
- Forbid()
- w:=ib.activewindow.width
- fw:=gb.defaultfont.xsize
- Permit()
- ENDPROC Bounds(w-24/fw,5,250)
-
- PROC sillylog10(n) IS IF n<10 THEN 1 ELSE sillylog10(Div(n,10))+1
-