home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
dirutl
/
sz15.arc
/
SZ.C
next >
Wrap
Text File
|
1989-10-21
|
20KB
|
664 lines
#pragma inline
/*
SZ.C Copyright (C) 1988 Mark Adler Pasadena, CA
All rights reserved.
Version history -
1.0 29 May 1988 First public version
1.1 4 Jun 1988 Added /F, /A
1.2 6 Nov 1988 Added /Y, /K, commas in long integers
1.3 18 Nov 1988 Fixed for Turbo C 2.0 (label needs statement)
1.4 3 Feb 1989 Display files and directories in lower case
1.5 21 Oct 1989 Catch dangling options and ignore command
SZ will determine the amount of space taken up by all the files in a
directory and its subdirectories, including system and hidden files.
The command:
sz
will give a message like:
bytes:space:floppy = 391,670 : 474k : 405k in 85 files.
which is information about the files in the current directory and its
subdirectories on the current drive. The first number is the sum of the
byte counts for all the files. The second number is the number of
kbytes (multiples of 1024) that the files actually occupy on the drive
they are on. The third number is the number of kbytes the files would
take up on a floppy drive with a blocking of 512 bytes. The last number
is the number of files included in those totals. The space taken by the
directory entries in the subdirectories is not computed or included,
since DOS does not provide this information. k values are rounded up to
the next highest value.
Using the /Y option for bYtes, SZ can display the second two values in
bytes instead of kbytes, so:
sz/y
might display this for the first example:
bytes:space:floppy = 391,670 : 485,376 : 414,208 in 85 files.
SZ will take arguments for drives and directories other than the current
one. For example:
sz a:\sys
Arguments may contain wild card characters, but note that the ambiguous
name only applies to the level in the path where it appears:
sz \dos\*.com
Multiple arguments can be used and the result will be the sum for all
the files:
sz \bin \bat \dos
SZ can list the files that it finds and produce subtotals for the
directories it processes. The option for this is "/L":
sz/l \dos
might produce the output:
directory \dos\*.*
command.com ansi.sys country.sys display.sys driver.sys
fastopen.exe fdisk.com keyb.com keyboard.sys mode.com
nlsfunc.exe printer.sys replace.exe sys.com vdisk.sys
xcopy.exe ega.cpi lcd.cpi 4201.cpi 5202.cpi
append.exe assign.com attrib.exe backup.com basic.com
basica.com chkdsk.com comp.com debug.com diskcomp.com
diskcopy.com edlin.com find.exe graftabl.com graphics.com
join.exe label.com more.com print.com recover.com
restore.com share.exe sort.exe subst.exe tree.com
basic.pif basica.pif mortgage.bas exe2bin.exe lib.exe
link.exe vdisk.asm
directory \dos\format\*.*
format.com select.com
bytes:space:floppy = 15,779 : 18k : 16k in 2 files.
bytes:space:floppy = 671,088 : 708k : 669k in 54 files.
Note the indentation of subdirectories.
SZ can try to find matches for a filename in all the directories. The
option is "/F". For example:
sz/fl \*.tex
will find and display all *.tex files anywhere on the current drive.
SZ will take options that are preceded by a slash (/). The command line
is read from left to right, processing options and file/path names as
they appear. However, options that are appended to a file/path name
take effect before that name is processed. For example, this command
would do the same thing as "sz/l \dos":
sz \dos/l
The options are:
/L - Turn on listing.
/Q - Quiet---turn off listing (default).
/N - Do not include subdirectories in total or listing.
/S - Include subdirectories (default).
/I - Ignore hidden and system files.
/H - Include hidden and system files (default).
/W - Weird---exclude "typical" files, where atypical files are
ones that are hidden, system, or read-only.
/T - Include typical files (default).
/B - Exclude backed up files.
/U - Include backed up files (default).
/F - Find a file---use the last name in to match in subdirs also.
/A - All files---use *.* in the subdirs (default).
/Y - Display values in bytes.
/K - Display space and floppy space in kbytes (defualt).
/nnn - Change the floppy blocking factor to nnn (default is 512).
/? - Display version number and list of options.
Options can be combined with or without additional slashes. For
example, these commands do the same thing:
sz /l /b \
sz /l/b \
sz/lb \
sz \/lb
What those commands do is list all the files that have not been backed
up yet and what subdirectories they are in. Examples of useful
combinations of options are:
sz /l \ List all files on the current drive.
sz /fl \name Find and list all files on the current drive
that match 'name'.
sz /lb \ List all files on the current drive that need to
be backed up.
sz /wl a: List all atypical files on A:
sz /wil \ List all read-only files on current drive
sz /nl List the files in the current directory
More complicated combinations are possible, of course. For example:
sz /n128bl d: /s \ /q a:
which lists the files that need to be backed only from the current
directory in D:, lists all the files that need to be backed on the
current drive, and adds the sizes for the files in the current directory
on A: and its subdirectories, without listing those files. For all of
this, the floppy blocking factor is 128 instead of 512. Note that
options remain in effect on a command line until contradicted. For
example, the /n turns off subdirectory searches for d:, but the /s turns
it back on again for \ and A:. The /L turns on listing for D: and \,
but the /Q turns off listing for A:. The /B and /128 is in effect for
all three.
Note that the commands:
sz \/l
sz \ /l
are different. The first lists all the files on the current drive. The
second says to compute the space for all files on the current drive but
the /L would have no effect. In this case, SZ notices the "dangling"
option before it does anything and simply ignores the entire command,
printing:
Dangling option---entire command ignored
The exception to this is if no names appear on the command line, in
which case the default name "*.*" is appended to the end of the command
line.
The last line displayed by SZ is always the grand total for all files
counted, whether it is indented or not.
If list is on (/L) and the directory level becomes more that 10 deep,
then the listing is not done for that level (or deeper levels). The
message "(level too deep---no files will be listed)" will be displayed
to indicate this.
*/
typedef unsigned long ulong;
#define IND 3 /* Indentation per level */
#define MXV 10 /* Maximum level display goes to */
/* Option flags, assigned to default values */
char lis = 0, /* List filenames as found */
sub = 1, /* Include subdirectories */
hid = 1, /* Include hidden files */
typ = 1, /* Include typical files */
bak = 1, /* Include backed up files */
fin = 0, /* Find---use same name in subdirs */
ink = 1; /* Show space, floppy in k (1024) */
unsigned flp = 512; /* Default floppy blocking */
unsigned curb; /* Blocking factor for current device */
ulong lstn; /* Last number of files displayed */
/* Structure for fnd1st(), fndnxt() */
struct find {
char rsvd[21]; /* What DOS needs to keep track of find */
char attr; /* File attribute */
unsigned time; /* Time stamp */
unsigned date; /* Date stamp */
ulong size; /* File size in bytes */
char name[13]; /* FIle name as a zero terminated string */
};
/* Send character 'c' to stdout */
void pputc(char c)
{
asm mov DL,c
asm mov AH,2
asm int 21h
}
/* Send string 's' to stdout, convert upper to lower case */
void pputs(char *s)
{
asm mov SI,s
asm cld
plp:
asm lodsb
asm test AL,AL
asm jz pfin
asm mov DL,AL
asm mov AH,2
asm int 21h
asm jmp short plp
pfin: ;
}
/* Convert the string s from upper case to lower case */
char *strlow(char *s)
{
asm mov AX,DS
asm mov ES,AX
asm cld
asm mov SI,s
asm lea DI,[SI-1]
llp:
asm inc DI
llpnoi:
asm lodsb
asm test AL,AL
asm jz lfin
asm cmp AL,'A'
asm jb llp
asm cmp AL,'Z'
asm ja llp
asm add AL,'a'-'A'
asm stosb
asm jmp short llpnoi
lfin: ;
return s;
}
/* Find first match to 'p', attribute 'a', results in 'd' */
int fnd1st(char *p, struct find *f, int a)
{
/* Set DTA to f */
asm mov DX,f
asm mov AH,1Ah
asm int 21h
/* Do find first */
asm mov DX,p
asm mov CX,a
asm mov AH,4Eh
asm int 21h
asm sbb AX,AX
return _AX;
}
/* Find next match for fnd1st() done on 'd' */
int fndnxt(struct find *f)
{
/* Set DTA to f */
asm mov DX,f
asm mov AH,1Ah
asm int 21h
/* Do find next */
asm mov AH,4Fh
asm int 21h
asm sbb AX,AX
return _AX;
}
/* Return the allocation block size for drive 'd' (0=default) */
int block(int d)
{
asm push DS
asm mov DL,d
asm mov AH,1Ch
asm int 21h
asm pop DS
asm mov AH,0
asm mul CX
return _AX;
}
/* Copy string s to string d, return end of d */
char *scpy(char *d, char *s)
{
asm mov SI,s
asm mov DI,d
asm cld
asm mov AX,DS
asm mov ES,AX
slp:
asm lodsb
asm stosb
asm test AL,AL
asm jnz slp
asm mov AX,DI
asm dec AX
return (char *) _AX;
}
/* Convert unsigned long 'n' to decimal in string 's' with commas */
char *ultod(ulong n, char *s)
{
/* Load n into SI:AX, s into DI, and the radix into BX */
asm mov DI,s
asm mov AX,n
asm mov SI,n+2
asm mov BX,10
/* Convert n into a digit string, least significant digit first */
asm mov CX,3 /* Digits before the next comma */
dlp:
/* Divide SI:AX by BX, quotient to SI:AX, remainder to DX */
asm xchg AX,SI /* SI = low n */
asm sub DX,DX /* DX:AX = high n */
asm div BX /* AX = high q, DX = temporary r */
asm xchg AX,SI /* SI = high q, DX:AX = temp r:low q */
asm div BX /* SI:AX = q, DX = r */
/* Put digit in string */
asm add DL,'0'
asm mov [DI],DL
asm inc DI
/* Do until SI:AX is zero */
asm mov DX,AX
asm or DX,SI
asm jz dfin
/* Put in comma if three digits since last comma */
asm loop dlp
asm mov byte ptr [DI],','
asm inc DI
asm mov CL,3
asm jmp short dlp
/* Terminate string */
dfin:
asm mov [DI],AL
/* Reverse the string, putting most significant digit first */
asm mov SI,s
rlp:
asm dec DI
asm cmp DI,SI
asm jna rfin
asm mov AL,[SI]
asm xchg AL,[DI]
asm mov [SI],AL
asm inc SI
asm jmp short rlp
rfin:
/* Return pointer to start of string */
asm mov AX,s
return (char *) _AX;
}
/* Print 'n' spaces to stdout */
void spaces(int n)
{
asm mov CX,n
asm jcxz infin
asm mov DL,' '
asm mov AH,2
ilp:
asm int 21h
asm loop ilp
infin: ;
}
/* Display a ulong in bytes or k depending on ink */
void shval(ulong n)
{
char s[11];
if (ink) /* If in K, go up to next K */
n = (n >> 10) + ((n & 0x3ffL) != 0);
pputs(ultod(n, s));
if (ink)
pputc('k');
}
/* Display the sizes and number of files */
void show(ulong n, ulong b, ulong h, ulong f)
{
char s[11];
pputs("bytes:space:floppy = ");
pputs(ultod(b, s));
pputs(" : ");
shval(h);
pputs(" : ");
shval(f);
pputs(" in ");
pputs(ultod(n, s));
pputs(" file");
if (n != 1)
pputc('s');
pputs(".\r\n");
}
void size(int v, char *a, ulong *nn, ulong *bb, ulong *hh, ulong *ff)
{
register char *p;
register int e;
int c, m;
char *q;
ulong n, b, h, f;
struct find d;
char s[128];
char t[128];
/* Setup */
p = scpy(s, a) - 1; /* Copy path being searched */
if (p < s || *p == '\\' || *p == ':')
scpy(p + 1, "*.*"); /* If no name, append wildcard */
else
do {
p--; /* Scan back for path delimiter */
} while (p >= s && *p != '\\' && *p != ':');
p++; /* Point past delimiter */
n = b = h = f = 0; /* Initialize sizes */
c = 0; /* File column */
/* Find matching files */
m = 0; /* No matches yet */
e = fnd1st(s, &d, 7); /* Don't look for subdirectories */
while (!e)
{
e = d.attr; /* Get attribute */
if ((bak || (e & 0x20)) && /* Exclude backed up if bak = 0 */
(typ || (e & 7)) && /* Exclude typical if typ = 0 */
(hid || !(e & 6))) /* Exclude hidden/system if hid = 0 */
{
if (lis && !m)
{
m = 1;
pputs("directory ");
pputs(strlow(s));
pputs("\r\n");
if (v > MXV)
pputs("(level too deep---no files will be listed)\r\n");
}
n++;
b += d.size;
h += ((d.size + curb - 1) / curb) * curb;
f += ((d.size + flp - 1) / flp) * flp;
if (lis && v <= MXV)
{
if (!c)
spaces(v * IND);
pputs(strlow(d.name));
c = (c + 1) % ((79 - v * IND) / 14);
if (c)
{
for (e = 0; d.name[e]; e++)
;
spaces(14 - e);
}
else
pputs("\r\n");
}
}
e = fndnxt(&d);
}
if (c)
pputs("\r\n");
/* Find matching subdirectories, if requested */
if (sub)
{
if (fin)
{
scpy(t, p); /* If find, save the name */
scpy(p, "*.*"); /* and search all subdirectories */
}
e = fnd1st(s, &d, 0x17); /* Look at everything except labels */
while (!e) /* Do all subdirectories */
{
if ((d.attr & 0x10) &&
(d.name[0] != '.' || (d.name[1] && d.name[1] != '.')))
{ /* Is subdir and not "." or ".." */
q = scpy(p, d.name); /* Overlay wildcard with found name */
*q++ = '\\'; /* Append path delimiter */
scpy(q, fin ? t : "*.*"); /* New wildcard */
size(v + 1, s, &n, &b, &h, &f); /* Do subdirectory */
}
e = fndnxt(&d);
}
}
if (lis && v <= MXV && m)
{
spaces(v * IND);
show(n, b, h, f);
lstn = n;
}
/* Update counts for caller */
*nn += n;
*bb += b;
*hh += h;
*ff += f;
}
void main(int argc, char *argv[])
{
register char *p;
register int k;
int i, m, s;
ulong n, b, h, f; /* Sizes */
char *a[64]; /* Tokens and options */
char t[64]; /* Token/~option flags */
/* Parse line into tokens and options */
m = k = 0;
for (i = 1; i < argc; i++) /* Do command line */
{
p = argv[i]; /* Next argument */
if (*p != '/') /* See if token */
{
a[k] = p++;
t[k++] = 1; /* Token */
m = 1; /* Token flag */
while (*p && *p != '/')
p++;
if (*p) /* See if options on token */
{
*p++ = '\0'; /* Terminate token string */
a[k] = a[k-1]; /* Put options appended to token */
t[k] = 1; /* BEFORE that token. */
a[k-1] = p;
t[k-1] = 0; /* Option(s) */
k++;
}
}
else
{
a[k] = ++p; /* Options start after the slash */
t[k++] = 0; /* Option(s) */
if (m)
m = -1; /* Dangling option flag */
}
}
if (m < 0)
{
pputs("Dangling option---entire command ignored\r\n");
asm mov AX,4C01h /* Exit with error */
asm int 21h
}
m = k; /* Number of tokens and options */
/* Process tokens and options */
n = b = h = f = 0; /* Initialize sizes */
s = 1; /* Haven't done a size() yet */
lstn = -1; /* Haven't shown any sizes yet */
for (i = 0; i < m; i++)
if (t[i]) /* Token */
{
s = 0; /* size() called at least once */
curb = block(a[i][1] == ':' ? (a[i][0] & 0x5f) - 'A' + 1 : 0);
size(0, a[i], &n, &b, &h, &f);
}
else /* Options */
for (p = a[i]; (k = *p) != 0; p++)
if (k == '/') {} /* Ignore extra /'s */
else if ((k &= 0x5f) == 'Q') lis = 0; /* Quiet */
else if (k == 'L') lis = 1; /* List */
else if (k == 'N') sub = 0; /* No subdirs */
else if (k == 'S') sub = 1; /* Subdirs */
else if (k == 'I') hid = 0; /* Ignore hidden */
else if (k == 'H') hid = 1; /* Show hidden */
else if (k == 'W') typ = 0; /* Weird (no typical) */
else if (k == 'T') typ = 1; /* Include typical */
else if (k == 'B') bak = 0; /* Exclude backed up */
else if (k == 'U') bak = 1; /* Include backed up */
else if (k == 'A') fin = 0; /* Use *.* in subs */
else if (k == 'F') fin = 1; /* Find file */
else if (k == 'Y') ink = 0; /* Display in bytes */
else if (k == 'K') ink = 1; /* Display in K bytes */
else if (*p < '0' || *p > '9') /* Invalid option or ? */
{
if (*p != '?')
pputs("Invalid option\r\n");
pputs("\
SZ 1.5 Copyright (C) 1988,1989 Mark Adler All rights reserved.\r\n\
Valid options are (*=default):\r\n\
/L\t- Turn on listing\r\n\
/Q\t- Turn off listing *\r\n\
/N\t- Exclude subdirectories\r\n\
/S\t- Include subdirectories *\r\n\
/I\t- Ignore hidden files\r\n\
/H\t- Include hidden files *\r\n\
/W\t- Exclude typical files\r\n\
/T\t- Include typical files *\r\n\
/B\t- Exclude backed up files\r\n\
/U\t- Include backed up files *\r\n\
/F\t- Find files\r\n\
/A\t- All files *\r\n\
/Y\t- Display in bytes\r\n\
/K\t- Display in K *\r\n\
/nnn\t- Change floppy blocking to nnn\r\n\
/?\t- Display this list\r\n");
asm mov AX,4C01h /* Exit with error */
asm int 21h
}
else /* New floppy blocking factor */
{
flp = 0;
do {
flp = 10 * flp + *p++ - '0';
} while (*p >= '0' && *p <= '9');
p--;
}
if (s) /* Haven't done any calls to size() */
{
curb = block(0);
size(0, "", &n, &b, &h, &f);
}
/* Show grand total if not already shown */
if (lstn != n)
show(n, b, h, f);
}