CoCreate Modeling: Enumerating all drives on a Windows system
Even though Common Lisp has very broad functionality, sometimes you need to get a little
help from your friends to accomplish a task.
Let's say we want to enumerate all available drives on a Windows system.
Neither Common Lisp nor CoCreate Modeling's Developer's Kit have any built-in inquiries
for this purpose - but a solution can be built easily by glueing together
an external Windows shell script and a short Lisp function! The following
example will demonstrate important techniques in getting this done.
An abundance of scripting solutions is available for the Windows platform:
- Batch programming
using DOS command syntax. Highly underrated, probably because of its
heritage and its peculiar syntax, but actually
very powerful,
at least in Windows NT/2000/XP! Best of all: The command shell
is available everywhere, so no special installation
steps are necessary.
- Platform-independent scripting languages such as Perl
or Python
- UNIX-like shell scripting languages, such as ksh or bash
- Last, but not least, scripting languages supported by the
Windows Scripting Host.
In our example, we'll use the Windows Scripting Host to execute the following short script
in VBScript syntax:
set fs=CreateObject("Scripting.FileSystemObject")
for each drive in fs.drives
WScript.Echo(drive.DriveLetter)
next
In VBScript, it is possible to instantiate COM components such as the
FileSystemObject,
which provides functionality to enumerate drives, inquire
drive properties and drill into a filesystem. Exactly what we need!
Save this script into a file and then try running it using
cscript
:
c:\home\clausb\>cscript /nologo drives.vbs
A
C
D
E
Looks good! Now we have the drive information and only need to get it across
to LISP. The second part of the solution is the following LISP code:
(defun listdrives()
(let (l (s (open "| cscript /nologo drives.vbs" :direction :input)))
(prog1
(loop while (setf l (read-line s nil)) collecting (remove #\Return l))
(close s))))
The file name parameter syntax for the
open
command probably caught your eye:
The "file name" starts with a pipe (
|
) character. This means that what follows
is actually a command and not a file. With this syntax, the specified
command is executed, and its output is then piped into the LISP stream
s
from
where it can be read line by line using
read-line
.
The return value of
listdrives
is a list containing the drive letters of
all available drives. To build that list, the code above uses the
loop statement's
result accumulation capabilities (
collecting).
--
ClausBrod - 13 Feb 2005
Much nicer and shorter version of
listdrives
:
(defun listdrives()
(with-open-file (s "| cscript /nologo drives.vbs" :direction :input)
(loop for l = (read-line s nil) while l collecting (remove #\Return l))))
--
ClausBrod - 18 Feb 2009