home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
o
/
os2xlisp.zip
/
TEMP.DOC
< prev
next >
Wrap
Text File
|
1988-06-14
|
19KB
|
468 lines
Andrew Schulman
32 Andrews St. #2
Cambridge MA 02139
(617) 876-2102 (h)
(617) 576-6920 (w)
13 June 1988
TEMP.DOC -- shortened documentation for OS2XLISP v. 1.10
OS2XLISP is a Lisp interpreter for the OS/2 operating system. It has
many special features to facilitate exploration of the OS/2 API and of
protected mode. Version 1.10 has many improvements over 1.0, including:
-- ability to call the C run-time library from Lisp programs
-- (getprocaddr) for DOSCALLS no longer requires ordinal numbers
-- (call) now works for non-Microsoft dynamic link libraries
-- structures: conversion between OS/2 structures and Lisp lists
-- better protection again GP faults
-- now runs even if stdin/stdout have been redirected
-- improved interface to (peek) and (poke)
-- macro character ^ as shorthand for (addr)
-- ability to enumerate procedures in a dynamic-link library
-- the prompt is user-definable
The following is shortened, non-user-friendly (user-hostile?)
documentation. Complete documentation is available in the file OXLDOC.ARC
which should be available mid June.
1) *** THE FILES ***
OXLEXE.ARC contains the executable file, dynamic-link library,
initialization files, shortened documentation, and one sample program
for OS2XLISP version 1.1. The component files are:
OS2XLISP.EXE -- executable
(OS2XLISP.EXE 117586 12 Jun 88 10:19a)
CRTLIB.DLL -- dynamic-link library
(CRTLIB.DLL 89310 22 Apr 88 8:03p)
INIT.LSP -- initialization file
(INIT.LSP 8328 13 Jun 88 6:09p)
STRUCT.LSP -- initialization file
(STRUCT.LSP 5262 13 Jun 88 6:17p)
BACH.LSP -- sample program
TEMP.DOC -- this file!
The other ARC files that comprise OS2XLISP version 1.1 are:
OXLSRC.ARC -- C and ASM source code
OXLDOC.ARC -- complete documentation
OXLLSP.ARC -- sample Lisp programs
2) *** REQUIREMENTS ***
As its name clearly implies, OS2XLISP requires the OS/2 operating
system. Versions of XLISP for MS-DOS, the Mac, the VAX, and so on, are
available on CompuServe in the AI EXPORT forum (GO AIE), in the Lisp
data library.
Note that OS2XLISP is NOT a bound executable -- it requires OS/2
protected mode. It will not run in the 3.x compatibility box.
The file CRTLIB.DLL must be in a directory named in the LIBPATH
statement in your OS/2 CONFIG.SYS file. Otherwise you will get:
C:\OS2\XLISP>os2xlisp
SYS1804: The system cannot find the file CRTLIB.
This dynamic-link library contains the C run-time library used by
OS2XLISP. Also, please use the CRTLIB.DLL that came with OXLEXE.ARC --
there may be other files called CRTLIB.DLL floating around. The one
you use should be 89K large.
The two initialization files, INIT.LSP and STRUCT.LSP, should be
in the directory from which you call OS2XLISP. OS2XLISP will run, but
will not behave very well, if it can't find when it starts up.
2a) *** ODDITIES OF THE DosPTrace FEATURE ***
OS2XLISP by default uses the OS/2 function DosPTrace to "catch"
GP faults. This works very nicely, and helps make OS2XLISP a stable
programming environment, but unfortunately only one invocation of
DosPTrace can be active in OS/2 at any given time, and CodeView is
built atop DosPTrace.
If CodeView is running in another session, either shut down CodeView
or invoke OS2XLISP with the -x flag:
C:\OS2\XLISP>os2xlisp -x
Otherwise, you will get the message:
PROTECT: Denied access to C:\OS2\XLISP\OS2XLISP.EXE
For the same reason, if you want to run more than one concurrent
"instance" of OS2XLISP at one time, every instance after the first will
have to be invoked with the -x flag. As you have gathered by now,
the -x flag turns off the use of DosPTrace.
On the other hand, if you want to see DosPTrace at work, invoke
OS2XLISP with the -v flag. Particularly educational if you deliberately
try to crash OS2XLISP with something like:
> (poke #xB8000000 666)
3) *** GETTING STARTED ***
By now you have gathered that to start OS2XLISP, you type its name
at the OS/2 prompt (perhaps followed by the -x or -v flag):
C:\OS2\XLISP>os2xlisp
OS2XLISP will spew out some messages (there will be even more with
the verbose -v flag!):
XLISP version 2.0, Copyright (c) 1988, by David Betz
OS/2 protected-mode extensions vers. 1.10, (c) 1988,by Andrew Schulman
; loading "init.lsp"
; loading "STRUCT.lsp"
6/13/1988 20:5:2
>
The ">" is the Lisp prompt. OS2XLISP is waiting for an expression,
which it will read and evaluate. It will print the results of the evaluation.
For instance:
> (+ 2 3)
5
Note Lisp's famous parentheses, which mark the begin and end of an
expression. Note that operators _precede_ operands. Here's another example:
> (define foo (+ 2 3)) ; 1
5
> foo ; 2
5
> (+ foo 10) ; 3
15
> (if (= 15 (+ foo 10)) ; 4
"Okay!"
; else
"Something is very wrong!")
"Okay!"
As in assembly language, comments start with a semicolon ; and go
to the end of the line. In the above example, our input expressions have
been commented so we can refer to them easily:
1 -- define the variable FOO to be the sum of 2 and 3. note how
expressions can be arbitarily nested inside expressions
2 -- to query the value of a variable, just type its name (without
parentheses)
3 -- variables can be used in expressions just as immediate values can.
4 -- if the sum of FOO and 10 is equal to 15, return the string "Okay!"
Otherwise, return the string "Something is very wrong!"
So far, we have been using Lisp as a glorified calculator -- we type
in an expression, and OS2XLISP prints out the results. We can also write
Lisp programs in ASCII text files (using your favorite protected-mode
editor -- I recommend Lugaru Software's Epsilon), and ask OS2XLISP to
evaluate the program. For instance, the two initialization files mentioned
above -- INIT.LSP and STRUCT.LSP -- are just Lisp programs. I suggest
printing out these files. But these are really just collections of useful
routines, rather than programs. This ARC contains one sample program,
BACH.LSP. To run this program:
> (load 'bach)
or:
> (load "c:\\os2\\xlisp\\bach.txt") ; note double backslashes
or from the OS/2 command line:
C:\OS2\XLISP>os2xlisp bach
I have left the most important part to the end: how to get out of
OS2XLISP:
> (exit) ; quit back to operating system
C:\OS2\XLISP>rem we're back
Note that hitting ^C or ^break will NOT get you back to OS/2: instead,
they will put you in the OS2XLISP debugger. To get out of the debugger,
hit ^Z a few times.
4) *** AN OS/2 CALCULATOR: RUN-TIME DYNAMIC LINKING ***
While it's nice having a Lisp interpreter, you're probably most
interested in how to interact with the OS/2 API from this
interpreter. Since a minute ago we used Lisp as a calculator,
inputting some expressions and immediately printing out the results,
you might be wondering: Can OS2XLISP can be used as an "OS/2
calculator" to make some OS/2 function calls and print out their
results, without having to write a "program"? Yes ma'am!
> (define vio-wrt-tty (getprocaddr viocalls "VIOWRTTTY")) ; 1
15142831 ; 2
> (define msg "Hello world!\n")
"Hello world!\n"
> (call vio-wrt-tty msg (word (length msg)) (word 0)) ; 3
Hello world!
0 ; 4
In line 1, we defined a variable called VIO-WRT-TTY (we could
have called it BINKY if we wanted, or FIDO) that contains a function
pointer to the OS/2 VioWrtTTy function. The (getprocaddr) function
takes a handle to a dynamic-link library (like VIOCALLS.DLL) and an
ASCII string naming a function presumably in that DLL. The major
OS/2 DLL's are pre-loaded in the file INIT.LSP using the (loadmodule)
function. The (getprocaddr) function returned a function pointer to
VioWrtTTy: that's 15142831 in line 2. If we wanted to see a more
sensible hexadecimal display, we could say:
> (ultoa vio-wrt-tty 16) ; display it in base 16
"E70FAF"
or we could set the XLISP global variable *integer-format* with a printf()
mask:
> (define *integer-format* "%Fp")
"%Fp"
> vio-wrt-tty
00E7:0FAF
> (define *integer-format* "%lu") ; change it back
"%lu"
In line 3, we actually call this function, using the OS2XLISP
(call) function, which takes a variable number of variable-typed
arguments. Because XLISP numbers are longs (4 bytes) by default, and
since the VioWrtTTy function expects words (2 bytes), we had to
"cast" the arguments with the (word) function. The VioWrtTTy
function printed out "Hello world!\n" and returned control to
OS2XLISP. Because the function succeeded, OS2XLISP printed out 0
(the OS/2 convention for "no error").
There's plenty more we could do with this one example. For instance,
what was that address we got back from (getprocaddr)?
> (lar (fp-seg vio-wrt-tty)) ; access rights byte
251
> (code? (fp-seg vio-wrt-tty)) ; see INIT.LSP
T
> (lsl (fp-seg vio-wrt-tty)) ; segment size
11306
In a more practical vein, note that it would be a royal pain to
have to specify the arguments to VioWrtTTy like this all the time. So
we can write a Lisp function to handle all the arguments for us:
> (define (vio-wrt-tty msg)
(call vio-wrt-tty msg (word (length msg)) (word 0) T))
VIO-WRT-TTY
> (vio-wrt-tty "Testing, testing")
Testing, testing
T
The (define) macro can be used to create functions just as easily
as it can be used to create variables. Now, (vrt-wrt-tty) can be used
as if it came "built in" to OS2XLISP. Also, note the T we put in
as the last argument to (call): this is a "retval directive" which means
that the (call) function should interpret a 0 returned from the OS/2
function as meaning success (in Lisp, T means true and NIL means false).
Many OS/2 functions require a pointer to memory, which the OS/2
function will fill with data:
> (define gdt 0)
0
> (define ldt 0)
0
> (call
(getprocaddr doscalls "DOSGETINFOSEG")
^gdt ^ldt t)
T
> gdt
96
> ldt
15
Notice that we didn't bother creating a variable for the function
pointer to DosGetInfoSeg, since we knew we were just using it once. Since
we wanted to pass pointers to the variables to OS/2, we prefaced them
with the ^ macro-character, which is short-hand for the (addr) function.
After the call, the variables are no longer zero -- OS/2 has changed these
Lisp variables, right out from under OS2XLISP's nose!
Users of previous versions of OS2XLISP: note that you no longer
need to use ordinal numbers (yuk!) to retrieve functions from the DOSCALLS
dynamic-link library: ASCII names are okay now.
What can we do with these information segments? One example is
determining our process id (PID). This information is kept in the
first two bytes of the local information segment:
> (peek (mk-fp ldt 0) 'int)
11
The 'int is another "retval directive", by the way.
If we thought we were going to be interrogating this value a lot, we
could bury the details of the (peek) in a function that take no arguments:
> (define (getpid)
(peek (mk-fp ldt 0) 'int))
GETPID
> (getpid)
11
Of course, this value will never change during the life of the
process. An example of a value that would change is the foreground
flag, kept in the int at offset 12 in the local information segment;
anything non-zero means the process is running in the foreground:
> (peek (mk-fp ldt 12) 'int)
65535
> (define (foreground?)
(not (zerop (peek (mk-fp ldt 12) 'int))))
FOREGROUND?
> (foreground?)
T
Since we're typing expressions right into OS2XLISP, naturally
(foreground?) is going to return true! Let's exercise this function a
little:
> (dotimes
(i 1000)
(princ (foreground?)))
Now, toggle in and out of OS2XLISP with Alt-Esc (I'm assuming that
you're running OS2XLISP is one session, and reading this documentation
in another protected-mode session): while OS2XLISP is in the
foreground, T is printed out, while it's churning away in the background,
it prints out NIL (which you'll see when you switch back in). This
loop runs for 1,000 iterations and then stops. If you get tired of
watching it, hit ^C, then ^Z to get out of the debugger.
Finally: see the file STRUCT.LSP for examples of how to use
structures in OS/2 API calls, and how to convert between OS/2
structures and Lisp lists using (make-struct) and (unpack-struct).
5) *** C FUNCTION CALLS FROM OS2XLISP ***
The same mechanism that lets OS2XLISP make OS/2 function calls, also
lets you Lisp programs make C run-time library calls. Well, almost the
same mechanism: Since the OS/2 API uses the Pascal function calling
convention (which, by the way, has almost nothing to do with the Pascal
programming language), we need a separate gateway for dynamic-link
functions using the C calling convention:
> (define printf (getprocaddr crtlib "_printf"))
120000664
> (c-call printf "hello world!\n")
hello world!
13
(getprocaddr), it should be noted, is cAsE _sEnSitivE! Functions
using the C calling convention should be presented in lower-case, with
a leading underscore. Note that we invoked printf with the (c-call)
function, rather than with (call). Also note that in this case, the
function does not use the 0=T non-zero=NIL convention of the OS/2 API
return values. The 13 returned by printf happens to be the number of
characters it printed out (including the newline).
Again, we can create Lisp functions to take care of the details of
(c-call) for us. In the case of printf, sprintf, fprintf, and the like,
it's a little trickier because of the variable number of arguments:
> (defmacro printf (mask &rest ,@args)
`(c-call printf ,mask ,@args))
PRINTF
> (printf "printf lives at %Fp\n" printf)
printf lives at 02AF:3F76
26
> (printf "testing, testing, %u %lu %f\n" (word 1) 2 3.0)
testing, testing, 1 2 3.000000
31
The two strange-looking lines of Lisp do all the work of passing
a variable number of variable typed arguments to (c-call) which then
passes them to the C run-time library (CRTLIB.DLL).
We can call (printf) as though it were a built-in Lisp function!
Thus, run-time dynamic linking immediately solves the problem of
"mixed language programming" in the cleanest possible way. It's also
significant that we latched onto printf() by passing in an its name
as an ASCII string -- nothing magical or mysterious about ASCII
strings! This aspect of run-time dynamic linking resembles "string
invocation" in certain high-level programming languages like ICON.
The "retval directives" we've been mentioning really become
important when making run-time dynamic links to the C standard
library. Unlike the OS/2 API functions, all of which return a
two-byte error code, the C run-time functions return all sorts of
values. Here's an example of the 'str retval directive:
> (define strtok (getprocaddr crtlib "_strtok"))
120024620
> (define (strtok string delims)
(c-call strtok string delims 'str))
STRTOK
> (strtok "this is a test" " ")
"this"
> (strtok 0 " ")
"is"
We told (c-call) to return us a string (which, by the way, should be
distinguished from a pointer to a string).
6) *** QUICK SUMMARY OF SOME OS/2-SPECIFIC FUNCTIONS ***
(loadmodule <name>) -- returns handle to dynamic-link library
(getprocaddr <dll> <proc>) -- returns function pointer to DLL routine
(freemodule <dll>) -- releases handle to DLL (hardly ever used)
(call <procaddr> [args...] [retval directive]) -- call dynamic-link routine
(c-call <procaddr> [args...] [retval directive]) -- same, for C calling conv
(math-call <procaddr> [args...]) -- for calling floating-point DLL routines
(os2-error) -- returns latest error code from above functions
(mk-fp <seg> <off>) -- make far pointer from segment/selector and offset
(fp-seg <fp>) -- extract segment/selector from far pointer
(fp-off <fp>) -- extract offset from far pointer
(word <n>) -- convert n to 2-byte quantity (word)
~n -- macro character for (word)
(lar <seg>) -- access rights byte for segment
(lsl <seg>) -- limit (size) of segment
(verr <seg>) -- verify reading rights to segment
(verw <seg>) -- verify writing rights to segment
(smsw) -- machine status word
(ds), (ss), (sp), (flags) -- what you'ld expect
(addr <node>) -- get pointer to OS2XLISP data object
^node -- macro character for (addr)
(peek <fp> [retval directive]) -- examine byte, word, long, double, or string
(poke <fp> <value> [retval directive]) -- poke in byte, word, long, dbl or str
(make-struct <template> [data]) -- returns OS/2-compatible packed structure
(unpack-struct <template> <structure>) -- return Lisp list from OS/2 structure
(enum-procs <dll>) -- enumerate functions exported from dynamic link library
7) *** A FINAL NOTE ***
If you have the C and ASM source code for OS2XLISP, you might note that
the MAKE file does not make one thing perfectly clear: your include
files have to come from \MSC\INC\MT rather than from plain old \MSC\INC.
If you don't know what \MSC\INC\MT is, you'll have to get Microsoft C 5.1
and check out the file MTDYNA.DOC.