home *** CD-ROM | disk | FTP | other *** search
- 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.
-