home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS - Coast to Coast
/
simteldosarchivecoasttocoast.iso
/
pcmag
/
vol10n21.zip
/
PCTODAY.ZIP
/
PCTODAY.BAS
< prev
next >
Wrap
BASIC Source File
|
1991-11-01
|
16KB
|
414 lines
'********** PCTODAY.BAS - reports all files that have changed today
'
'Copyright (c) 1991 Ethan Winer
'First published in PC Magazine December 10, 1991
'
'Compile and link as follows:
'
' bc pctoday /o /s;
' link /ex pctoday , , nul , qb.lib pctoday.lib
'
'For best size, compile and link with Crescent Software's P.D.Q. like this:
'
' bc pctoday /o /s ;
' link /nod /noe /ex /pack /far /stack:8192 pctoday +
' str49152 _noread _noval _noerror , , nul, [basic7] pdq ;
DEFINT A-Z
DECLARE FUNCTION FileCount% (DirFlag)
DECLARE FUNCTION GetDir$ ()
DECLARE FUNCTION GetDrive% ()
DECLARE FUNCTION GoodDrive% (Drive%)
DECLARE FUNCTION LoadNames% (Array() AS ANY, DirFlag)
DECLARE FUNCTION ParseDate% (Work$)
DECLARE FUNCTION PDQShr% (BYVAL Value, BYVAL Bits)
DECLARE FUNCTION PDQValI% (Work$)
DECLARE FUNCTION Redirected% ()
DECLARE FUNCTION Remote% (Drive)
DECLARE FUNCTION Removable% (Drive)
DECLARE FUNCTION ScreenLines% ()
DECLARE FUNCTION TestDates% ()
DECLARE FUNCTION Trim$ (IntValue)
DECLARE SUB Display ()
DECLARE SUB SetDrive (Drive)
DECLARE SUB Interrupt (IntNumber, InRegs AS ANY, OutRegs AS ANY)
'DECLARE SUB Interrupt (IntNumber, Regs AS ANY) 'use this with P.D.Q.
TYPE RegType
AX AS INTEGER
BX AS INTEGER
CX AS INTEGER
DX AS INTEGER
BP AS INTEGER
SI AS INTEGER
DI AS INTEGER
Flags AS INTEGER
END TYPE
TYPE DTA 'used by the DOS Find First/Next services
Reserved AS STRING * 21 'reserved for use by DOS
Attribute AS STRING * 1 'the file's attribute
FileTime AS INTEGER 'the file's time
FileDate AS INTEGER 'the file's date
FileSize AS LONG 'the file's size
FileName AS STRING * 13 'the file's name
END TYPE
TYPE Names 'used by LoadNames to display full file info
FileName AS STRING * 13
FileMonth AS INTEGER
FileDay AS INTEGER
FileYear AS INTEGER
END TYPE
DIM SHARED DateSpec, Spec$, TotalFiles, Zero$, Zero, Redir, ScreenRows
DIM SHARED DOS, DTAData AS DTA, Regs AS RegType
DIM SHARED TestDate(1 TO 3)
DOS = &H21 'defining this as shared saves 64 bytes
Redir = Redirected% 'see and remember if we're being redirected
IF NOT Redir THEN 'if the program output is going to the screen
LOCATE , , 1 'turn on cursor for "--more--" prompt later
PRINT "PCTODAY 1.00 Copyright (c) 1991 Ethan Winer" 'then say hello
PRINT
END IF
Zero$ = CHR$(0) 'do this once here for smaller code
Spec$ = "*.*" + Zero$ 'used to find file/directory names
Cmd$ = UCASE$(COMMAND$) 'use a copy (UCASE$ needed w/P.D.Q. only)
ScreenRows = ScreenLines% - 1 'invoke this function just once for speed
IF INSTR(Cmd$, "/?") THEN
PRINT "Syntax: PCTODAY [D:] [/D mm-dd-yyyy] [> filename.ext]"
END
END IF
DriveSpec = INSTR(Cmd$, ":") > 0 'remember if any drive letters were given
DateSpec = INSTR(Cmd$, "/D") 'see if a date was specified
IF DateSpec THEN 'if there is a date
Temp$ = LTRIM$(MID$(Cmd$, DateSpec + 2)) 'use a copy for efficiency
ELSE 'no date given
Temp$ = DATE$ 'work from today's date
END IF
TestDate(2) = ParseDate%(Temp$) 'grab the month value
TestDate(3) = ParseDate%(Temp$) 'get the day
TestDate(1) = ParseDate%(Temp$) 'get the year
IF TestDate(1) < 100 THEN TestDate(1) = TestDate(1) + 1900 'adjust as needed
'Examine every drive (0-based drive numbers). If this drive was explicitly
'specified, or no drives were specified and this drive is a local hard disk,
'list the file.
'
Drive = GetDrive% 'save the current drive before changing it
FOR X = 0 TO 25
ThisDriveGiven = INSTR(Cmd$, CHR$(X + 65) + ":") > 0
LocalHardDrive = (NOT Removable%(X)) AND (NOT Remote%(X))
IF GoodDrive%(X) AND (ThisDriveGiven OR ((NOT DriveSpec) AND LocalHardDrive)) THEN
CALL SetDrive(X) 'change to that drive
Original$ = GetDir$ 'save current directory
CHDIR "\" 'start searching in the root
CALL Display 'display all of the files
CHDIR Original$ 'restore the directory for this drive
END IF
NEXT
CALL SetDrive(Drive) 'restore original drive
IF NOT Redir THEN PRINT TotalFiles; "File(s) Found" 'show the total files
SUB Display
STATIC NewLines 'to know when to print --more--
IF NewLines = 0 THEN NewLines = 2 'protect the copyright notice
CurrentDir$ = GetDir$ 'get directory, current drive
REDIM FArray(1 TO 1) AS Names 'establish the file names array
NumFiles = LoadNames%(FArray(), LocalZero) 'load the names and count them
TotalFiles = TotalFiles + NumFiles 'add to the accumulator
ThisDrive$ = CHR$(GetDrive% + 65) 'get the current drive
FOR X = 1 TO NumFiles 'for each file
PRINT ThisDrive$; ":"; CurrentDir$; 'print the name
IF CurrentDir$ <> "\" THEN PRINT "\";
PRINT FArray(X).FileName;
IF NOT Redir THEN 'we're printing to the screen,
PRINT " "; ' display the extra goodies
PRINT Trim$(FArray(X).FileMonth); "-";
PRINT Trim$(FArray(X).FileDay); "-";
PRINT Trim$(FArray(X).FileYear)
GOSUB DoMore 'see if it's time for --more--
ELSE
PRINT 'we are redirected, just finish
END IF ' the line with an empty PRINT
NEXT
IF NumFiles AND NOT Redir THEN 'add a blank line between
PRINT ' directories for cosmetics
GOSUB DoMore 'see if it's time for --more--
END IF
REDIM DArray(1 TO 1) AS Names 'establish the directory array
DirCount = LoadNames%(DArray(), -1) 'count dirs under this one
IF DirCount THEN 'if there are any, then
IF CurrentDir$ = "\" THEN 'if we're in the root, use a
Prefix$ = "" ' blank, otherwise use the
ELSE ' current directory
Prefix$ = CurrentDir$
END IF
FOR X = 1 TO DirCount 'for each directory,
CHDIR Prefix$ + "\" + DArray(X).FileName' change to it and
CALL Display ' invoke this routine again
NEXT
END IF
EXIT SUB
DoMore:
NewLines = NewLines + 1 'show another line was printed
IF (NewLines MOD ScreenRows) = 0 THEN 'print "--more--" if needed
PRINT "--more-- ";
WHILE LEN(INKEY$) = 0: WEND 'and wait for a keypress
PRINT
END IF
RETURN
END SUB
FUNCTION FileCount% (DirFlag) STATIC
Regs.DX = VARPTR(DTAData) 'set new DTA address
Regs.AX = &H1A00 'specify service 1Ah, set DTA service
CALL Interrupt(DOS, Regs, Regs) 'call DOS to do the real work
'CALL Interrupt(DOS, Regs) 'use this with P.D.Q.
Regs.DX = SADD(Spec$) 'the file specification address
Regs.CX = 39 'find files, also hidden/read-only
IF DirFlag THEN Regs.CX = 19 'find directories instead
Regs.AX = &H4E00 'find first matching name
Count = 0 'clear the counter
DO
CALL Interrupt(DOS, Regs, Regs) 'see if there's a match
'CALL Interrupt(DOS, Regs) 'use this with P.D.Q.
IF Regs.Flags AND 1 THEN EXIT DO 'no more files
IF DirFlag OR TestDates% THEN 'test file dates only
IF DirFlag THEN 'do they want directories?
IF ASC(DTAData.Attribute) AND 16 THEN 'is it really a directory?
IF ASC(DTAData.FileName) <> 46 THEN 'filter out "." and ".."
Count = Count + 1 'increment the counter
END IF
END IF
ELSE
Count = Count + 1 'they want regular files
END IF
END IF
Regs.AX = &H4F00 'find the next name
LOOP
FileCount% = Count 'assign the function
END FUNCTION
FUNCTION GetDir$ STATIC
Temp$ = SPACE$(65) 'DOS stores the name here
Regs.AX = &H4700 'get directory service
Regs.DX = 0 'specify the current default drive
Regs.SI = SADD(Temp$) 'show DOS where Temp$ is
CALL Interrupt(DOS, Regs, Regs) 'call DOS
'CALL Interrupt(DOS, Regs) 'use this with P.D.Q.
Zero = INSTR(Temp$, Zero$) 'find the CHR$(0) that marks the end
GetDir$ = "\" + LEFT$(Temp$, Zero - 1) 'keep just what precedes that
END FUNCTION
FUNCTION GetDrive% STATIC
Regs.AX = &H1900 'DOS service for getting default
CALL Interrupt(DOS, Regs, Regs) 'result comes back in AL
'CALL Interrupt(DOS, Regs) 'use this with P.D.Q.
GetDrive% = Regs.AX AND 255 'ignore what's in AH
END FUNCTION
FUNCTION GoodDrive% (Drive) STATIC
GoodDrive% = 0 'assume its not a valid drive
SavedDrive = GetDrive% 'first save the current drive
CALL SetDrive(Drive) 'try to change it
IF Drive = GetDrive% THEN 'if the new drive took
GoodDrive% = -1 'then it's a valid drive
CALL SetDrive(SavedDrive) 'and we need to restore the original
END IF
END FUNCTION
FUNCTION LoadNames% (Array() AS Names, DirFlag) STATIC
NumNames = FileCount%(DirFlag) 'count the names
LoadNames% = NumNames 'assign the function output
IF NumNames = 0 THEN EXIT FUNCTION 'exit if none
REDIM Array(1 TO NumNames) AS Names 'dimension the array
'---- The following code isn't really needed because we know that FileCount%
' has already set the DTA address. It is shown here merely for clarity.
'Regs.DX = VARPTR(DTAData) 'assign the new DTA address
'Regs.AX = &H1A00 'specify service 1Ah
'CALL Interrupt(DOS, Regs, Regs) 'DOS set DTA service
Regs.DX = SADD(Spec$) 'the file spec address
Regs.CX = 39 'find files, also hidden/read-only
IF DirFlag THEN Regs.CX = 19 'find directories instead
Regs.AX = &H4E00 'find first matching name
Count = 0 'clear the name counter
DO
CALL Interrupt(DOS, Regs, Regs) 'see if there's a match
'CALL Interrupt(DOS, Regs) 'use this with P.D.Q.
IF Regs.Flags AND 1 THEN EXIT DO 'no more
Valid = 0 'assume invalid
IF DirFlag OR TestDates% THEN 'this file is not recent
IF DirFlag THEN 'do they want directories?
IF ASC(DTAData.Attribute) AND 16 THEN 'is it really a directory?
IF ASC(DTAData.FileName) <> 46 THEN 'filter "." and ".."
Valid = -1 'this name is valid
END IF
END IF
ELSE
Valid = -1 'they want regular files
END IF
END IF
IF Valid THEN 'process the file if it
Count = Count + 1 ' passed all the tests
Zero = INSTR(DTAData.FileName, Zero$) 'find zero and assign name
Array(Count).FileName = LEFT$(DTAData.FileName, Zero - 1) 'assign data
Array(Count).FileMonth = PDQShr%(DTAData.FileDate AND &H1E0, 5)
Array(Count).FileDay = DTAData.FileDate AND &H1F
Array(Count).FileYear = PDQShr%(DTAData.FileDate AND &HFE00, 9) + 1980
END IF
Regs.AX = &H4F00 'find next matching name service
LOOP
END FUNCTION
FUNCTION ParseDate% (Work$) STATIC 'returns the value of the next date part
Length = LEN(Work$) 'get the length just once
FOR X = 1 TO Length 'search for "-" or "/" date separators
Char = ASC(MID$(Work$, X, 1)) 'work with the ASCII value for efficiency
IF Char = 45 OR Char = 47 OR X = Length THEN
ParseDate% = PDQValI%(Work$) 'we know PDQValI% stops on "-" or "/"
Work$ = MID$(Work$, X + 1) 'keep just what's past that for later
EXIT FOR 'all done
END IF
NEXT
END FUNCTION
FUNCTION Redirected% STATIC
Regs.AX = &H4400 'service &H44 tells if a handle is redirected
Regs.BX = 1 'handle 1 is the console output (STDOUT)
CALL Interrupt(DOS, Regs, Regs) 'DOS does the dirty work
'CALL Interrupt(DOS, Regs) 'use this with P.D.Q.
Redirected% = -1 'assume we are being redirected
IF Regs.DX AND &H80 THEN 'well, are we?
Redirected% = 0 'no
END IF
END FUNCTION
FUNCTION Remote% (Drive) STATIC 'checks if redirected network drive
Regs.AX = &H4409 'service 44 in AH, function 9 in AL
Regs.BX = Drive + 1 '0=default, 1=A, 2=B, and so forth
CALL Interrupt(DOS, Regs, Regs) 'call DOS
'CALL Interrupt(DOS, Regs) 'use this with P.D.Q.
Remote% = 0 'assume it is not a remote drive
IF Regs.DX AND 4096 THEN 'DX contains the info in bit 12
Remote% = -1 'if that bit is set it's remote
END IF
END FUNCTION
FUNCTION Removable% (Drive) STATIC 'tests if a drive is removeable
Regs.AX = &H4408 'changeable block service
Regs.BX = Drive + 1 'adjust to 1-based
CALL Interrupt(DOS, Regs, Regs) 'DOS does the hard part
'CALL Interrupt(DOS, Regs) 'use this with P.D.Q.
Removable% = Regs.AX - 1 'return -1 if removable, 0 if not
END FUNCTION
FUNCTION ScreenLines% STATIC
DEF SEG = 0 'look in low memory at the adapter type
ScreenLines% = 25 'assume 25 lines
IF PEEK(&H463) = &HB4 THEN 'it's a monchrome display, so 25 is correct
EXIT FUNCTION
END IF
Regs.AX = &H1200 'it's color, test if EGA or VGA
Regs.BX = &H10
CALL Interrupt(&H10, Regs, Regs) 'call the BIOS video interrupts
'CALL Interrupt(&H10, Regs) 'use this with P.D.Q.
IF (Regs.BX AND &HFF) = &H10 THEN 'it's a CGA
EXIT FUNCTION 'so again, 25 lines is correct
END IF
ScreenLines% = PEEK(&H484) 'this address holds the number of screen
' rows for EGA/VGA display adapters
END FUNCTION
SUB SetDrive (Drive) STATIC
Regs.AX = &HE00 'service for set-drive
Regs.DX = Drive 'drive goes in DL (A=0, B=1, etc.)
CALL Interrupt(DOS, Regs, Regs) 'call DOS to do the work
'CALL Interrupt(DOS, Regs) 'use this with P.D.Q.
END SUB
FUNCTION TestDates% STATIC
TestDates% = -1 'assume the file is new enough
Temp = DTAData.FileDate 'use a copy for readability below
DIM ThisDate(1 TO 3) 'facilitates comparing in a loop
ThisDate(1) = PDQShr%(Temp AND &HFE00, 9) + 1980 'compute the year
ThisDate(2) = PDQShr%(Temp AND &H1E0, 5) 'compute the month
ThisDate(3) = Temp AND &H1F 'isolate the day
FOR X = 1 TO 3 'cycle through comparing dates
IF ThisDate(X) < TestDate(X) THEN
TestDates% = 0 'fail if the file is older
EXIT FOR 'and leave early
ELSEIF ThisDate(X) > TestDate(X) THEN 'if the file is newer
EXIT FOR ' skip comparing and exit
END IF
NEXT
END FUNCTION
FUNCTION Trim$ (IntValue) STATIC
Trim$ = RIGHT$("0" + LTRIM$(STR$(IntValue)), 2)
END FUNCTION