home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / OS2XLSP2.ZIP / OS2XLISP.DOC next >
Text File  |  1988-07-20  |  54KB  |  1,350 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.      OS2XLISP:  OS/2 Extensions to XLISP, an Object-Oriented LISP
  10.  
  11.                                    
  12.             XLISP version 2, OS/2 extensions version 1.10
  13.  
  14.                  
  15.                              June 1, 1988
  16.  
  17.  
  18.  
  19.                     OS/2 protected-mode extensions
  20.                            and documenation
  21.                                   by
  22.                            Andrew Schulman
  23.                           32 Andrews St. #2
  24.                           Cambridge MA 02139
  25.  
  26.                         (617) 876-2102 (home)
  27.  
  28.  
  29.  
  30.                                 XLISP
  31.                                   by
  32.                           David Michael Betz
  33.  
  34.  
  35.  
  36.  
  37.  
  38. INTRODUCTION
  39.  
  40.     The goal of OS2XLISP is to give users an opportunity to
  41. experiment with protected-mode/virtal-memory/multitasking
  42. programming, without investing in expensive development kits and
  43. compilers.  OS2XLISP is also a demonstration of the power of
  44. run-time dynamic linking.
  45.  
  46.     OS/2 is the new protected-mode operating system for 286 and 386
  47. machines, developed by Microsoft and IBM.
  48.  
  49.     OS2XLISP is an interpreter with access to all OS/2 system
  50. routines.  Even those programmers who already have the Microsoft
  51. software development kit should find OS2XLISP useful for interactive
  52. experimentation (no compiles!), small- to medium-size programs,
  53. incremental testing, and quick prototyping.
  54.  
  55.     Among the special features of OS2XLISP are:
  56.  
  57.     o   Access to OS/2 services, through the magic of run-time
  58.         dynamic-linking with the functions (loadmodule), (getprocaddr),
  59.         (call), and (c-call).
  60.  
  61.     o   A protected programming environment -- it is nearly impossible
  62.         to crash OS2XLISP with a GP fault, even when the user .....
  63.  
  64.     o   Virtual memory -- you can create a huge number of nodes, occupying
  65.         more than the available physical memory on your machine.
  66.  
  67.     o   High-level access to 286 protected-mode instructions
  68.         with (lar), (lsl), (verr), and (verw).
  69.  
  70.  
  71.     OS2XLISP can of course be used as "straight" XLISP.  The user
  72. can refer to "XLISP: An Object-Oriented Lisp, Version 2.0" (David
  73. M. Betz, 6 February 1988), and the article "An XLISP Tutorial" (BYTE,
  74. March 1985).  The book "The XLISP Primer" by Bonnie Fladung
  75. (Prentice-Hall, 1987) is also useful, though somewhat out of date.
  76.  
  77.     To fully tap OS/2 and 286 protected-mode resources using
  78. OS2XLISP, you do NOT need the Microsoft software development kit or
  79. the Microsoft C compiler, but you will need to invest in at least one
  80. book on OS/2: I recommend Ed Iacobucci's "OS/2 Programmer's Guide"
  81. (McGraw-Hill, 1988).
  82.  
  83.     Equipped solely only with Iacobucci's book, a file of Charles
  84. Petzold's OS/2 articles from PC MAGAZINE, and OS2XLISP, one can do a
  85. reasonable amount of OS/2 programming and experimentation.  Other
  86. useful resources are listed in the annotated bibliography.  A few
  87. "un-resources" are listed there as well.
  88.  
  89.  
  90.  
  91. GETTING STARTED
  92.  
  93.     To run OS2XLISP, you will of course need OS/2.  If OS2XLISP is invoked
  94. under MS-DOS, it will inform you of this fact and exit.
  95.  
  96.     To take advantage of virtual memory, the MEMMAN switch in your
  97. OS/2 CONFIG.SYS file must be set to SWAP,MOVE, and you must set up a
  98. SWAPPATH.  I mention this because if, like many OS/2 users, you are
  99. booting off a floppy, then the default is NOSWAP.  OS/2's default
  100. SWAPPATH is the boot-drive, and you sure don't want a floppy disk as
  101. your swap area!  You will need something like this in CONFIG.SYS:
  102.  
  103.         memman=swap,move
  104.         swappath=d:\swap
  105.  
  106. (swappath is the name of an already existing subdirectory).
  107.  
  108.     This documentation should be accompanied by:
  109.         
  110.         OS2XLISP.EXE -- executable
  111.         OS2XLCRT.EXE -- executable requiring CRTLIB.DLL
  112.         INIT.LSP     -- initialization file
  113.         XLISP.DOC    -- standard documentation for XLISP
  114.         *.LSP        -- sample programs
  115.         \SOURCE      -- subdirectory of XLISP source code in C
  116.  
  117.     OS2XLISP comes with a number of sample programs, all with the
  118. .LSP file extension.  A .LSP file can be run by including its name
  119. on the OS/2 command-line.  For example, to run the WELCOME.LSP 
  120. program:
  121.  
  122.         D:\OS2\XLISP>os2xlisp welcome
  123.  
  124.     Once inside OS2XLISP, program files can be run using the (load)
  125. function.  For example:
  126.  
  127.         > (load "welcome.lsp")
  128.  
  129. or:
  130.  
  131.         > (load 'welcome)
  132.  
  133.     To see a listing of .LSP files, you can use:
  134.  
  135.         > (system "dir d:\\os2\\xlisp\\*.lsp")
  136.  
  137. (Note that, because the backslash has special significance in XLISP,
  138. if you really want to input a backslash to OS2XLISP, you need to
  139. enter two of them.)
  140.  
  141.     Another way to see a directory listing is by invoking the (directory)
  142. function in the file DIR.LSP.  This function has been implemented using
  143. OS2XLISP's (call) function, and you may want to examine this file to see
  144. one example of calling OS/2 services from OS2XLISP.  To see a listing of
  145. .LSP files:
  146.  
  147.         > (load 'dir)
  148.         T
  149.         > (directory 'lsp)
  150.         ("WELCOME.LSP" "TAK.LSP" "STEP.LSP" "SEGS.LSP" "PP.LSP" "OVERCOM.LSP"
  151.         "OBJ.LSP" "INIT.LSP" "ENV.LSP" "ENUMDLL.LSP" "DIR.LSP")
  152.  
  153.     To exit XLISP:
  154.  
  155.         > (exit)
  156.  
  157.  
  158.  
  159. GENERAL NOTES
  160.  
  161.     While this is not meant as a tutorial on XLISP, a few explanations
  162. are in order, mostly to help you read the code fragments provided
  163. later in this documentation.
  164.  
  165.     After typing "OS2XLISP" at the OS2 prompt, OS2XLISP will start up
  166. and load the file INIT.LSP.  You will then be presented with the
  167. following user-disinterested interface:
  168.         
  169.         >
  170.  
  171. (Actually, this prompt can be changed by setting the value of the
  172. global variable *prompt*.  If *prompt* is set to a string, then OS2XLISP
  173. will use that string for the prompt; if *prompt* is set to a piece of code,
  174. then OS2XLISP will execute that code each time through its main loop.
  175. See the commented-out example at the bottom of the file INIT.LSP.  Note
  176. how the same variable can be used to "hold" a string or a piece of code --
  177. Lisp is pretty amazing, if you ask me.  End of digression.)
  178.  
  179.     OS2XLISP is waiting for an expression, which it will evaluate; it will
  180. then print the results of the evaluation.  
  181.  
  182.         > (define x (+ 444 222))
  183.         666
  184.  
  185.     You might guess that this is equivalent to the operation
  186.  
  187.         X := 444 + 222
  188.  
  189.     in other languages: set the variable X equal to the sum of 222
  190. and 444.
  191.  
  192.     Actually, in the above example, we not only set x equal to 666;
  193. 666 was also returned as the value of the expression (and XLISP printed
  194. out this return value).  We could have used the entire expression
  195. inside another one, if we wanted, in the same way that C assignment
  196. statements return a value that can be used inside other statements:
  197.  
  198.         > (define y (define x 666))
  199.         666
  200.  
  201.     To query the value of x, or any variable, just type its name:
  202.         
  203.         > x                     ; you type
  204.         666                     ; XLISP replies
  205.             
  206.     XLISP always prints a reply.  Note above that, as in assembly
  207. language, Lisp comments begin with the semicolon and go to the end of
  208. the line.
  209.  
  210.     You could also create a function that adds 222 to its input:
  211.  
  212.         > (define (add222 x)
  213.             (+ x 222))
  214.         ADD222
  215.             
  216.     Again, XLISP always prints a reply, in this case the name of the
  217. function we just created.  This function can be used just like those
  218. that come built-in with XLISP.  To use the function:
  219.  
  220.         > (add222 5)
  221.         227
  222.         > (define zero (add222 -222))
  223.         0
  224.             
  225.     Note that (define) was used, both to create variables, and to
  226. create functions.  Actually, (define) is just a macro defined in the
  227. file INIT.LSP, and conforms more to the Scheme dialect of the LISP
  228. programming language than it does to Common LISP.  You can instead
  229. use the more common (setq) for variables, and (defun) for
  230. functions. 
  231.  
  232.     The file INIT.LSP has no special status, and is simply a file of
  233. XLISP expressions.
  234.  
  235.     Anything done interactively/incrementally at the prompt can also
  236. be put into a program file.
  237.  
  238.     If you created a file OS2STUFF.LSP, you could have XLISP run
  239. the file by typing the expression
  240.  
  241.         > (load "os2stuff.lsp")
  242.             
  243. or
  244.  
  245.         > (load 'os2stuff)
  246.             
  247.     The second example also shows that when you are interested in the
  248. NAME of an XLISP symbol, rather than in its value, preface it with an
  249. apostrophe.  (This is a gross oversimplification.)
  250.  
  251.     XLISP will also run any filenames you include on the OS/2 command
  252. line, after running INIT.LSP:
  253.  
  254.         D:\OS2\XLISP>os2xlisp os2stuff
  255.             
  256.     XLISP, and XLISP program files, can send output to another
  257. file by using the (dribble) function.  Here is an example of a completely
  258. non-interactivate program, which sends 100 random 2-digit hexadecimal
  259. numbers to a file called "rand.lsp":
  260.  
  261.         ; rand.lsp
  262.         (dribble 'rand.log)                 ; open up log file
  263.         (define *integer-format* "%02X")    ; print integers in hex
  264.         (dotimes                        
  265.             (i #xff)                        ; for (i=0, i<0xFF, i++)
  266.             (print (random #xff)))          ;   printf("%02X\n", random(0xFF))
  267.         (dribble)                           ; close log file
  268.         (exit)                              ; exit back to OS/2
  269.  
  270.         ; at the OS/2 prompt
  271.         D:\OS2\XLISP>os2xlisp rand
  272.             
  273.     This silly example shows a number of other things as well:
  274.         
  275.     The format in which integers are displayed can be changed by
  276. re-defining the global variable *integer-format* (global variables
  277. are by convention designated with asterisks on either end).
  278. Actually, *integer-format* is a C printf() mask: you can even use
  279. "%Fp" to display pointers in segment:offset format.  The diplay of
  280. floating-point numbers can similarly be changed by re-defining
  281. *float-format*, and the display of two-byte numbers and character codes 
  282. can be changed by re-defining *word-format*.
  283.  
  284.     Similarly, numbers can be input in bases other than 10.  #x is
  285. used to input hexadecimal, and #b to input binary.  Most of this is
  286. explained in the standard XLISP documentation (the file XLISP.DOC).
  287.  
  288.     One way to form loops is with (dotimes).  In the above example,
  289. we begin to see why "all those parentheses" are nice: expressions can
  290. be arbitrarily nested.
  291.  
  292.     This example also shows how to get out of XLISP: the (exit)
  293. function can be used either at the prompt, or from within a program
  294. file.
  295.  
  296.     Hitting Ctrl-Break or Ctrl-C will NOT exit you back to the
  297. operating system.  In fact, either Ctrl-C or Ctrl-Break will stop the
  298. currently-running program in its tracks, and place you at a debug
  299. prompt.  You can determine the value of variables, change them, and
  300. so on. The (baktrace) function can be invoked as well:
  301.  
  302.             ;;;; ... in the middle of printing random hexadecimal numbers
  303.         72
  304.         20
  305.         46
  306.             ;;;; ... hit Ctrl-C here
  307.         break: BREAK
  308.         if continued: return from BREAK
  309.             ;;;; ... wanted to see current value of i
  310.         1> i
  311.         19
  312.         1> (baktrace)
  313.         Function: #<Subr-BAKTRACE: #22f6a42>
  314.         Function: #<Subr-PRINT: #22f651a>
  315.         Arguments:
  316.             46
  317.         Function: #<FSubr-DOTIMES: #22f6bd2>
  318.         Arguments:
  319.           (I FF)
  320.           (PRINT (RANDOM FF))
  321.         Function: #<Subr-LOAD: #22f6312>
  322.         Arguments:
  323.           RAND
  324.         NIL
  325.             ;;;; tell XLISP we want to resume the program
  326.         1> (continue)
  327.         D0
  328.         D3
  329.         ....
  330.  
  331.     The 1 displayed in the debug prompt is the current break level.  To
  332. return to a previous break level, hit Ctrl-Z.
  333.  
  334.     [[[ documentation not finished:  should note some of the issues involved
  335. in break-ins in an OS/2 interpreter.  For instance, what if code for
  336. DOSPOPUP has been executed, but user hits Ctrl-C before DOSENDPOPUP can
  337. be executed, and then throws away program rather than typing (continue)?
  338. We would still be in pop-up!  Not able to switch away to another screen
  339. group, until we invoke (call DOSENDPOPUP (word 0)). ]]]
  340.  
  341.                         *   *   *
  342.  
  343.     The following sections describe OS/2-specific features:  how to call
  344. dynamic-link functions and protected-mode instructions.  Many semi-useful
  345. code fragments are provided.
  346.  
  347.     The examples in the reference below build on each other.  The
  348. example for one function may use a variable created in an earlier
  349. example.  Keep this in mind if you jump into the middle.
  350.  
  351.     Finally, even though the access to the operating system services
  352. that OS2XLISP provides is at a low level, the examples below show how
  353. to construct high-level access. 
  354.  
  355.   
  356.  
  357. KNOWN BUGS AND LIMITATIONS
  358.  
  359.     
  360.     The functions to (save) and (restore) a workspace are not
  361. implemented in this version of OS2XLISP.  In the meantime, XLISP
  362. program files can be loaded with the (load) function, and individual
  363. functions can be saved with (savefun).
  364.  
  365.     OS2XLISP editing facilities are extremely primitive.  However,
  366. development goes very quickly if you run a text editor in a separate
  367. session, and use Alt-Esc to toggle back and forth between your editor
  368. and OS2XLISP.  An excellent EMACS editor, available for OS/2
  369. protected mode, is Epsilon from Lugaru Software. 
  370.  
  371.     (An alternative solution is provided in the file TOPLEVEL.LSP.  This
  372. dynamically links to Andrew Estes's excellent CED-link ALIAS package, which
  373. provides an intelligent replacement to the KBDSTRINGIN function.  While
  374. TOPLEVEL.LSP is far from perfect, it does let you edit your input line
  375. with the cursor keys, retrieve past lines, and so on.  It's all done in a
  376. few lines of Lisp.  Estes's ALIAS is available on the CompuServe Microsoft
  377. Systems forum (GO MSSYS), in the OS/2 data library -- get it; it will
  378. greatly improve your quality of life under OS/2.)  
  379.  
  380.     Like XLISP running under other operating systems, OS2XLISP does
  381. not transform tail recursion into goto's.  While OS2XLISP has been
  382. compiled with a large stack, OS2XLISP will fail for heavily-recursive
  383. work like Ackerman's function.  The (sp) function can be used inside
  384. recursive functions to detect stack overflow before it occurs (see the
  385. file ACK.LSP for an example).
  386.  
  387.     Those OS/2 function calls that require a pointer to object code,
  388. such as DOSCREATETHREAD, cannot be called from this version of
  389. OS2XLISP.  This is a major limitation, which will be addressed in
  390. future versions of OS2XLISP.
  391.  
  392.     In the future, I hope to turn OS2XLISP into a full-fledged
  393. Concurrent XLISP, with user-defined concurrent/asynchronous threads,
  394. using the underlying multitasking and interprocess communication
  395. resources of OS/2.
  396.  
  397.     In the meantime, multitasking XLISP programs is limited to
  398. running multiple copies of OS2XLISP, or running OS2XLISP in the
  399. background.  When multiple instances of OS2XLISP are present in
  400. memory at the same time, code is shared while each instance of
  401. OS2XLISP has its own private data.
  402.  
  403.     (The following paragraph has nothing to do with bugs or
  404. limitations, but since we're talking about multitasking...)
  405.  
  406.     When OS2XLISP is run in the background (with perhaps another copy
  407. of OS2XLISP in the foreground), your Lisp programs continue to
  408. execute.  What value is that, you ask, when you there's no output
  409. unless OS2XLISP is in the foreground?  Not so!  Running the program
  410. BACH.LSP in the background (type "(load 'bach)" and then switch away
  411. to another program with Alt-Esc) will provide an audio demonstration
  412. of OS/2 multitasking.  Running the program WELCOME.LSP in the
  413. background (start the program and then switch to another screen
  414. group) will show how OS/2 pop-ups work.
  415.  
  416.     I (Andrew Schulman) would like to hear of any other problems or
  417. suggestions regarding OS2XLISP.  Please do not bother David Betz (the
  418. author of XLISP) with problems occurring in the OS/2 implementation.
  419.  
  420.  
  421.  
  422. RUN-TIME DYNAMIC LINKING FUNCTIONS
  423.  
  424. (loadmodule <module name>)  LOAD AN OS/2 DYNAMIC LINK LIBRARY
  425.     <module name>       ASCII string
  426.     returns             if successful, handle to dynamic link library
  427.                         if failure, NIL
  428.                             
  429.     example:
  430.         > (define viocalls (loadmodule "VIOCALLS"))
  431.         1390                             
  432.         > (define presentation-manager
  433.             (loadmodule "WIN"))          ; I haven't got it! (Have you?)
  434.         NIL
  435.  
  436.     note:
  437.         The most commonly-called dynamic link modules -- DOSCALLS,
  438.         VIOCALLS, KBDCALLS, and MOUCALLS -- have been pre-loaded in
  439.         the initialization file INIT.LSP:
  440.  
  441.             (define doscalls (loadmodule "DOSCALLS"))
  442.             (define viocalls (loadmodule "VIOCALLS"))
  443.             (define kbdcalls (loadmodule "KBDCALLS"))
  444.             (define moucalls (loadmodule "MOUCALLS"))
  445.             (define crtlib (loadmodule "CRTLIB"))       ; from MSC 5.1
  446.         
  447.         (loadmodule) is equivalent to the OS/2 function DosLoadModule(),
  448.         and to the Microsoft Windows function LoadLibrary(). 
  449.  
  450.         In the event of failure, (os2-error) can be called to get the
  451.         OS/2 error code.  The most common error code is 2:  the file
  452.         modname.DLL must exist in the libpath= directory.
  453.  
  454.             
  455.  
  456. (getprocaddr <module handle> <func>)   GET ADDRESS OF DYNLINK FUNCTION
  457.     <module handle>     module handle returned by (loadmodule)
  458.     <func>              ASCII name, or "ordinal number" of OS/2 function
  459.     returns             if successful, pointer to dynlink function 
  460.                         if failure, NIL
  461.                             
  462.     examples:
  463.         > (define *integer-format* "%Fp")       ; display as segment:offset
  464.         "%Fp"
  465.         > (define vioscrolldn
  466.             (getprocaddr viocalls "VIOSCROLLDN"))    ; using ASCII name
  467.         00E7:1069
  468.         > (define dosgetinfoseg 
  469.             (getprocaddr doscalls "DOSGETINFOSEG"))
  470.         479B:0000
  471.         > (define dosgetinfoseg 
  472.             (getprocaddr doscalls 8))             ; using ordinal number
  473.         479B:0000
  474.         > (define crtlib.strlen                 ; another naming convention
  475.             (getprocaddr crtlib "_strlen"))     ; cAsE _sEnSiTiVe!
  476.         0737:1E60
  477.         > (define win-initialize
  478.             (getprocaddr
  479.                 (loadmodule "WIN")
  480.                 "WinInitialize"))               ; still waiting...
  481.         NIL
  482.             
  483.     note:
  484.         (getprocaddr) is equivalent to the OS/2 function DosGetProcAddr(),
  485.         and to the Microsoft Windows function GetProcAddress().  It is
  486.         somewhat similar to the register() function in the Windows version
  487.         of Microsoft Excel.
  488.  
  489.         The statement made by David Cortesi in his otherwise superb book,
  490.         "The Programmer's Essential OS/2 Handbook," that "It is not possible
  491.         to ask for entry points to system packages like VIOCALLS by entry
  492.         name; the names are not retained in the loaded module" (p.135) is,
  493.         fortunately, simply not true of VIOCALLS or KBDCALLS.  The above
  494.         example shows how we retrieved the address of VIOSCROLLDN by
  495.         passing OS/2 the ASCII string "VIOSCROLLDN."
  496.  
  497. <<<No longer relevant!>>>
  498.         Cortesi's statement is true, however, of the functions in the OS/2
  499.         "DOSCALLS" module (the OS/2 kernel).  These functions cannot be
  500.         accessed with their ASCII names ("a silly kind of storage economy,"
  501.         as Cortesi points out).  For instance:
  502.             > (register "DOSCALLS" "DOSGETINFOSEG")
  503.             NIL
  504.             > (register "DOSCALLS" 8)
  505.             479B:0000                   ; now it's happy!
  506.         
  507.         DOSGETPROCADDR is, itself, one of these slightly-less-accessible
  508.         functions.  Ordinal numbers for these DOSCALLS functions are supplied
  509.         in Appendix A.  For example, DOSGETPROCADDR is ordinal number 45.
  510.         Thus, for those that like this sort of thing, here is how the
  511.         getprocaddr operation can be defined in terms of itself:
  512.             (define dosgetprocaddr
  513.                 (getprocaddr doscalls 45))
  514.  
  515.         In the event of failure, (os2-error) can be called to get the
  516.         OS/2 error code.  The most common error code is 127:  the function
  517.         name or number must actually be exported from the module.
  518.             
  519.         A function's address need only be retrieved once:  the pointer is
  520.         valid unless and until its module is freed with (freemodule).
  521.             
  522.         Note carefully, in the crtlib.strlen example above, that 
  523.         (getprocaddr), just like LINK.EXE, is case sensitive!  Functions
  524.         using the Pascal calling convention have ALL CAPS names, whereas
  525.         functions using the C calling convention are in lower-case and
  526.         have a leading _underscore.  
  527.  
  528.  
  529.                     
  530. (call <proc addr> [<arg> ...])    CALL A DYNLINK FUNCTION (PASCAL CALLING)
  531.     <proc addr>         pointer returned by (getprocaddr)
  532.     <arg> ...           arguments to dynlink function:
  533.                             word, dword, far pointer
  534.                         symbol argument is directive for (call) return type:
  535.                             'short 'word 'long 'fixnum 'ptr 'str 'string
  536.                             (default is word cast to fixnum)
  537.     returns             the return value of the function; return type
  538.                             depends upon function
  539.                             
  540.     example:
  541.         > (define gdt 0)
  542.         0
  543.         > (define ldt 0)
  544.         0
  545.         > (call
  546.             (getprocaddr doscalls "DOSGETINFOSEG")
  547.             (addr gdt) (addr ldt))
  548.         0
  549.         ;;;; 0 = success:  gdt and ldt have now been "poked" by OS/2
  550.         > gdt
  551.         96
  552.         > ldt
  553.         15
  554.  
  555.         > (define (vio-scroll-dn top left bottom right char attr)
  556.             (zerop (call
  557.                 vioscrolldn                     ; procaddr
  558.                 (word top) (word left)          ; 2-byte params
  559.                 (word bottom) (word right)      ; 2-byte params
  560.                 (word #xffff)                   ; clear the area
  561.                 (addr (word                     ; 4-byte ptr to 2-byte cell
  562.                     (+ (* #x100 attr) char)))
  563.                 (word 0))))                     ; 2-byte param (VIO handle)
  564.         VIO-SCROLL-DN
  565.         > (define cls ()
  566.             (vio-scroll-dn 0 0 25 80 32 #xff))
  567.         CLS
  568.         > (cls)
  569.         ;;;; screen is cleared
  570.         T
  571.             
  572.         > (define dosselectdisk (getprocaddr doscalls "DOSSELECTDISK"))
  573.         46AB:0000
  574.         > (call dosselectdisk (word 1))         ; try to select drive A:
  575.         0                                       ; 0 = success
  576.         > (call dosselectdisk (word 25))        ; try to select drive Y:
  577.         15                                      ; error code: invalid drive
  578.             
  579.     notes:
  580.         Note that (call) takes a variable number of variable-sized
  581.         arguments.  In the above examples, the functions
  582.         DOSGETINFOSEG, VIOSCROLLDN, and DOSSELECTDISK were all invoked
  583.         through (call), even though the arguments they expect have
  584.         nothing in common.  The ability for one function to handle all
  585.         sorts of arguments is one of the areas where Lisp shines.
  586.         There is a nice match between the flexibility of OS/2 and the
  587.         flexibility of Lisp.
  588.             
  589.         For the purposes of (call), a string parameter is equivalent
  590.         to the (addr) of the string.
  591.             
  592.         (call) is not limited to calling standard OS/2 routines:  anything
  593.         in a dynamic link library can be called.  This, by the way, is why
  594.         (call) does not return a simple T/NIL.  While it is true that all
  595.         the standard OS/2 functions adhere to the convention that 0 means
  596.         success and that any other number is an error code, this is by no
  597.         means a requirement forced on dynlink functions, and therefore
  598.         (call) cannot assume that a positive numeric return value means
  599.         that the call failed.  (This is a change from previous versions
  600.         of OS2XLISP.)
  601.             
  602.         Likewise, there is no requirement that a routine exported from a
  603.         DLL return a two-byte quantity.  The optional symbol argument was
  604.         added to version 1.04 of OS2XLISP so that the user may control
  605.         what (call) returns.  
  606.         
  607.         Run-time dynamic linking means that OS2XLISP users can even
  608.         call dynlink functions that didn't exist when OS2XLISP was
  609.         compiled.  For instance:
  610.         
  611.             (define PM (loadmodule "WIN"))
  612.             (define win-initialize (getprocaddr PM "WinInitialize"))
  613.             (define HAB (call win-initialize 'ptr))  
  614.  
  615.         I haven't seen Presentation Manager, but there's every reason
  616.         why the above code fragment should work -- run-time dynamic
  617.         linking means that system services and add-ons can be invoked
  618.         without OS2XLISP.EXE having any knowledge of them.  It's all
  619.         done with ASCII strings, and nothing is hard wired.  This
  620.         resembles "string invocation" in certain programming languages.
  621.  
  622.         In fact, Lisp programs can easily interface with user-supplied
  623.         C or Pascal or assembler functions -- just put your code in a
  624.         dynamic link library, and (call) the functions from OS2XLISP.
  625.             
  626.         One real-life example:  after OS2XLISP had already been compiled,
  627.         I came across David Cortesi's GLOBENV.DLL facility, and OS2XLISP
  628.         wass able to call the GEnv routines without a hitch (see the file
  629.         GLOBENV.LSP). 
  630.             
  631.         For further examples of (call), see the sample programs that
  632.         accompany OS2XLISP.
  633.             
  634.         (call) resembles the functions (toolbox), (toolbox-16), and
  635.         (toolbox-32) in the Macintosh version of XLISP, though using
  636.         the optional symbol arguments 'word, 'long, etc., means we only
  637.         need one function for each calling convention.
  638.             
  639.  
  640.  
  641. (c-call <proc addr> [<arg> ...])    CALL A CDECL DYNLINK FUNCTION
  642.     <proc addr>         pointer returned by (getprocaddr)
  643.     <arg> ...           arguments to CDECL dynlink function:
  644.                             word, dword, far pointer
  645.     returns             the return value of the function
  646.                            
  647.     note:
  648.         The (call) function shown above handles dynlink functions that
  649.         should be called with the "pascal" calling convention (which, by
  650.         the way, has practically nothing to do with the Pascal programming
  651.         language).  Even though all the standard OS/2 dynlink routines
  652.         use the Pascal calling convention, there is no rule which requires
  653.         DLL writers to use it.  Therefore, the (c-call) function has been
  654.         provided to invoke functions with the "cdecl" calling convention.
  655.  
  656.         The latest version of the Microsoft C compiler (5.1) includes a
  657.         disk showing how the entire C standard library can be placed in
  658.         a dynamic-link library that can be called from multiple applications
  659.         or even from multi-thread applications.  The default name for this
  660.         C DLL is CRTLIB.DLL (CRT means C run-time, not cathode ray tube!).
  661.             
  662.         Aside from the promise of tiny EXE files (since the entire C
  663.         standard library resides outside the EXE), CRTLIB.DLL means that
  664.         your Lisp programs could call any C function.
  665.  
  666.     examples:
  667.         
  668.         <<< documentation not finished >>>
  669.         <<< cf. sample files READ.LSP and CRTLIB.LSP >>>
  670.             
  671.  
  672.  
  673. (freemodule <module handle>)    RELEASE AN OS/2 DYNAMIC LINK LIBRARY
  674.     <module handle>     module handle returned by (loadmodule)
  675.     returns             if successful, T
  676.                         if failure, NIL
  677.     example:
  678.         > (freemodule vio)
  679.         T                           ; success
  680.         > (freemodule 666)          ; probably not a real module handle
  681.         NIL
  682.         > (os2-error)
  683.         6                           ; error code = ERROR_INVALID_HANDLE
  684.             
  685.     note:
  686.         (freemodule) is equivalent to the OS/2 function DosFreeModule(),
  687.         and to the Microsoft Windows function FreeLibrary().
  688.             
  689.         Any pointers to functions in a dynamic-link module become invalid
  690.         when the module is freed.
  691.                             
  692.  
  693.  
  694. (os2-error)     GET LATEST OS/2 ERROR CODE
  695.     returns             latest error code
  696.  
  697.     example:
  698.         > (freemodule 666)          ; probably not a real module handle
  699.         NIL
  700.         > (os2-error)
  701.         6                           ; error code = ERROR_INVALID_HANDLE
  702.  
  703.     note:
  704.         (os2-error) returns the latest error from (loadmodule),
  705.         (getprocaddr), and (freemodule).  The number returned
  706.         is only valid if (os2-error) is called immediately after one
  707.         of these three functions generates an error.  
  708.             
  709.         The error can be further classified by calling DOSERRCLASS.
  710.  
  711.  
  712.         
  713.  
  714. POINTER MANIPULATION FUNCTIONS
  715.  
  716. (addr <node>)   GET ADDRESS OF DATA ASSOCIATED WITH AN XLISP NODE
  717.     <node>              an XLISP node
  718.     returns             address of data, depending on (type-of <node>)
  719.  
  720.     example:
  721.         > (define x 666)
  722.         666
  723.         > (type-of x)
  724.         FIXNUM
  725.         > (define *integer-format* "%Fp")   ; display as seg:off far pointer
  726.         "%Fp"
  727.         > (addr x)
  728.         024F:8410                   ; pointer to 4-byte FIXNUM
  729.         > (peek (addr x) 4)         ; peek at 4-byte area
  730.         666
  731.  
  732.         > (define x "Hello world!")
  733.         "Hello world!"
  734.         > (type-of x)
  735.         STRING
  736.         > (addr x)
  737.         024F:9448
  738.         > (peek (addr x) 0)         ; peek at ASCII string
  739.         "Hello world!"
  740.  
  741.         > (define *integer-format* "%Fp")
  742.         "%Fp"
  743.         > (addr (function car))
  744.         010F:0000
  745.  
  746.     note:
  747.         (addr) differs from the (address-of) function in standard XLISP.
  748.         Whereas (address-of) returns the address of a node, (addr) returns
  749.         the address of the data itself.  For instance, (addr string) is
  750.         equivalent to (peek (+ 4 (address-of string)) 4)
  751.             
  752.  
  753.  
  754. (peek <address> [size])     PEEK AT LOCATION IN MEMORY
  755.     <address>           far pointer to location in memory
  756.     [size]              optional argument:
  757.                             <<< NOTE!  instead of cryptic numbers, symbols
  758.                             <<< can be used instead: 'byte, 'word, 'long,
  759.                             <<< 'float, 'ptr, 'string, etc.
  760.                             1   peek at byte (default)
  761.                             2   peek at word
  762.                             4   peek at long
  763.                             8   peek at floating-point number
  764.                             0   peek at ASCII string
  765.     returns             value of [size] at <address>
  766.         
  767.     examples:
  768.  
  769.         > (define *integer-format* "%lu")     ; return to normal display
  770.         "%lu"
  771.         > (define x 666)
  772.         666
  773.         > (peek (addr x) 4)
  774.         666
  775.  
  776.         > (define pi 3.1416)
  777.         3.1416
  778.         > (peek (addr pi) 8)
  779.         3.1416
  780.         > (define *integer-format* "%02X")
  781.         "%02X"
  782.         ; print out the 8 bytes that make up the
  783.         ; IEEE floating-point representation of PI:
  784.         > (progn        ; compound statement
  785.             (dotimes
  786.                 (i 8)
  787.                 (format stdout "~A " (peek (+ (addr pi) i))))
  788.             (format stdout "\n"))
  789.         A7 E8 48 2E FF 21 09 40 
  790.         > (define dosgetenv (getprocaddr doscalls "DOSGETENV"))
  791.         46D30000
  792.         > (define envseg 0)
  793.         0
  794.         > (define cmdline 0)
  795.         0
  796.         > (call dosgetenv (addr envseg) (addr cmdline))
  797.         T
  798.         > (peek (mk-fp envseg 0) 0)     ; peek at string
  799.         "COMSPEC=D:\\OS2\\SYS\\CMD.EXE"
  800.         > (peek (mk-fp envseg cmdline) 0)
  801.         "os2xlisp"
  802.             
  803.     note:
  804.         Protected mode prevents you from peeking at a non-readable segment,
  805.         and from reading past the end of a segment.  These protections are
  806.         enforced by OS2XLISP:
  807.             
  808.             > (peek 0 0)
  809.             error: No permission to read segment - 0
  810.             > (peek (+ 20000 (addr pi)) 8)
  811.             error: Past end of segment - 25F
  812.                 
  813.         If you find the size arguments to (peek) difficult to remember,
  814.         you can write your own (peek), substituting more mneumonic
  815.         symbols:
  816.             
  817.             (define (my-peek addr size)
  818.                 (peek addr
  819.                     (cond
  820.                         ((eq 'byte size) 1)
  821.                         ((eq 'word size) 2)
  822.                         ((eq 'lword size) 4)
  823.                         ((eq 'float size) 8)
  824.                         ((eq 'str size) 0))))
  825.                             
  826.         So that the following would work:
  827.             
  828.             (peek (mk-fp envseg 0) 'str)        ; peek at string
  829.             (peek (addr pi) 'float)             ; peek at float
  830.             
  831.             
  832.  
  833. (poke <address> <value> [size])     POKE AT A LOCATION IN MEMORY
  834.     <address>           far pointer to location in memory
  835.     <value>             the value to poke into <address>
  836.     [size]              optional argument:
  837.                             1   poke at byte (default)
  838.                             2   poke at word
  839.                             4   poke at long
  840.                             8   poke at floating-point number
  841.                             0   poke at ASCII string (be careful!!)
  842.     returns             value
  843.         
  844.     example:
  845.         > (define x 666)
  846.         666
  847.         > (poke (addr x) 222 4)         ; change FIXNUM
  848.         222
  849.         > x
  850.         222
  851.             
  852.         > (poke (mk-fp envseg cmdline) "hello" 0)   ; change STRING
  853.         "hello"
  854.             
  855.     note:
  856.         Like (peek), the OS2XLISP version of (poke) enforces segment
  857.         access rules.  You cannot poke past the end of a segment, and you
  858.         can only poke into writeable segments:
  859.             
  860.             > (poke (func-addr (function car)) 666 4)  ; poke code segment
  861.             error: No permission to write seg - 271
  862.                 
  863.         Being prevented from unintentionally treating code as data
  864.         is a great boon to software development.  However, sometimes
  865.         one wants to write intentionally self-modifying code.  You are NOT
  866.         prevented from doing this under OS/2:  the DosCreateCSAlias call
  867.         lets you modify a writeable data segment, and then treat it as an
  868.         executable code segment.  (Can (call) call such code?  Need to
  869.         test it...)
  870.             
  871.  
  872.  
  873. (mk-fp <segment> <offset>   MAKE A FAR POINTER
  874.     <segment>           handle to a memory segment/selector
  875.     <offset>            offset into the memory segment
  876.     returns             the far pointer
  877.         
  878.     example:
  879.         > (define *integer-format* "%lX")
  880.         "%lX"
  881.         > envseg
  882.         1FF
  883.         > cmdline
  884.         FA
  885.         > (mk-fp envseg cmdline)    ; munge seg and off into seg:off
  886.         1FF00FA
  887.         > (peek #x1ff00fa 0)        ; enter address directly
  888.         "hello"                     ; remember? we changed it! (see poke)
  889.         > (peek (mk-fp envseg cmdline) 0)   ; same thing
  890.         "hello"
  891.             
  892.     note:
  893.         (mk-fp seg off) is equivalent to (+ (shl seg 16) off).
  894.             
  895.         Protected-mode pointers are different from real-mode
  896.         pointers.  Protected-mode pointers do not point to physical 
  897.         locations in memory, but to virtual addresses.  There is no 
  898.         segment wraparound:  an address like 0271:FFFF bears no relation
  899.         to 0272:0000, for instance.  Plastering together the segment
  900.         and offset is just a convenience for high-level languages.
  901.  
  902.  
  903.  
  904. (fp-seg <far pntr>)     EXTRACT SEGMENT PORTION OF A FAR POINTER
  905.     <far pntr>          a segment:offset pointer
  906.     returns             the segment/selector portion.
  907.         
  908.     example:
  909.         > (define envseg (fp-seg #x1ff00fa 0))
  910.         1FF
  911.         > (define _xllist (fp-seg (func-addr (function car))))
  912.         10F     ; segment for XLLIST.OBJ, which contains C function xcar()
  913.             
  914.     note:
  915.         (fp-seg fp) is equivalent to (shr fp 16).  Note that 
  916.         Microsoft's FP_SEG() macro (defined in the C #include file DOS.H)
  917.         does not operate properly with protected-mode pointers.
  918.             
  919.         A 286 protected-mode segment number is entirely different
  920.         from one in real-mode.  Segments are not a uniform 64K size; they
  921.         vary in size from 0 bytes to 64K.  Segments are possibly not
  922.         present in memory.  They may be moved around in memory.
  923.             
  924.             The segment number is actually composed of several fields:
  925.             
  926.             bit 0,1     requested protection level
  927.                 2       table indicator (global/GDT=0 local/LDT=1)
  928.                 3-15    index into table
  929.                     
  930.         For instance, segment number #x10F (271) represents a segment
  931.         with protection level 3, accessed from entry #33 in the local
  932.         descriptor table (LDT):
  933.             
  934.             > (ultoa #x10F 2)     ; display in base 2
  935.             "100001111"
  936.             > (define (seg-fields seg)
  937.                 (format stdout
  938.                     "~A ~A\tLEVEL ~A\n"
  939.                     (if (zerop (logand seg 4)) 'GDT 'LDT)
  940.                     (shr seg 3)
  941.                     (logand seg 3)))
  942.             SEG-FIELDS
  943.             > (seg-fields 271)
  944.             LDT 33  LEVEL 3
  945.                 
  946.         That only 13 bits of the 16-bit segment handle are available
  947.         for indexing into the descriptor table, means a program 
  948.         can access a maximum of 2^13 entries is each table -- hence the
  949.         famous 286 restriction of 8,192 segments.
  950.         
  951.         That the last two bits of a handle are devoted to the protection
  952.         level means that, for each entry in the two tables, there are four
  953.         synonymous handles:  one for each possible protection level.
  954.         
  955.         
  956.                 
  957. (fp-off <far pntr>)     EXTRACT OFFSET PORTION OF A FAR POINTER
  958.     <far pntr>          a segment:offset pointer
  959.     returns             the offset portion
  960.         
  961.     example:
  962.         > (define beast 666)
  963.         666
  964.         > (define beast-ptr (addr beast))
  965.         025F4312
  966.         > (fp-seg beast-ptr)
  967.         25F
  968.         > (fp-off beast-ptr)
  969.         4312
  970.             
  971.     note:
  972.         (fp-off fp) is equivalent to (- fp (shl (shr fp 16) 16)).
  973.         
  974.  
  975.  
  976. SEGMENTATION FUNCTIONS
  977.  
  978. (lsl <segment>)     SIZE (LIMIT) OF MEMORY SEGMENT
  979.     <segment>           a memory segment/selector
  980.     returns             highest legal offset in the segment (size-1)
  981.         
  982.     example:
  983.         > (define *integer-format* "%lu")         ; normal display
  984.         "%lu"
  985.         > (define seg1 (dos-alloc-seg #xffff))    ; get 65,535 bytes
  986.         623
  987.         > (define seg2 (dos-alloc-seg 5))         ; get 5 bytes
  988.         639
  989.         > (lsl seg1)
  990.         65534                   ; last legal offset within segment
  991.         > (lsl seg2)
  992.         4
  993.         
  994.     note:
  995.         (lsl) is equivalent to the 286 protected-mode instruction LSL,
  996.         and is roughly equivalent to GetHandleSize() in the Macintosh
  997.         toolbox, and to GlobalSize() in Windows programming.
  998.             
  999.         (lsl) is used internally by the (peek) and (poke) functions
  1000.         to determine if addresses are within segment bounds.
  1001.             
  1002.         Note that (lsl) returns the last legal offset within a segment;
  1003.         since offsets start at zero, this is one less than the size
  1004.         of a segment.  
  1005.             
  1006.     bug/limitation:
  1007.         The return value from (lsl) does not properly distinguish between
  1008.         a segment whose size is 1 (LSL 0) and a non-existant segment
  1009.         (also LSL 0).  Use the (lar) instruction to verify segment existance,
  1010.         then use (lsl) to determine size.
  1011.  
  1012.         
  1013.         
  1014. (lar <segment>)     ACCESS RIGHTS BYTE OF MEMORY SEGMENT
  1015.     <segment>           a memory segment/selector
  1016.     returns             286 access-rights byte:
  1017.                             bit 0       accessed
  1018.                                 1       read/write
  1019.                                 2       conform/expand-down
  1020.                                 3       code=1, data=0
  1021.                                 4       (reserved for 386)
  1022.                                 5,6     protection level
  1023.                                 7       present
  1024.                         or 0 if non-existant segment
  1025.                                     
  1026.     example:
  1027.         ; is segment code?
  1028.         > (define codep (x)
  1029.             (=
  1030.                 8
  1031.                 (logand
  1032.                     (lar x)
  1033.                     8)))
  1034.         CODEP
  1035.         > (codep seg1)              ; seg1 from entry on (lsl)
  1036.         NIL
  1037.         > (codep (fp-seg (func-addr (function car))))
  1038.         T
  1039.             
  1040.         ; is segment present in memory?
  1041.         > (define presentp (x)
  1042.             (=
  1043.                 128
  1044.                 (logand
  1045.                     (lar x)
  1046.                     128)))
  1047.         PRESENTP
  1048.         > (presentp (fp-seg (func-addr (function pprint))))
  1049.         NIL                     ; segment not present in memory
  1050.         > (pprint 'hello)       ; now use something from that segment
  1051.         ;;;; a little disk activity
  1052.         HELLO
  1053.         NIL
  1054.         > (presentp (fp-seg (func-addr (function pprint))))    ; (eval ++)
  1055.         T                       ; segment is now present in memory
  1056.             
  1057.         ; list out segments present in memory, with ring 3 protection,
  1058.         ; whose LSL is not zero
  1059.         ; requested protection level
  1060.         > (define (rpl x) (logand 3 x))
  1061.         RPL
  1062.         > (dotimes
  1063.                 (i #xffff)                       
  1064.                 (if                             ; for (i=0; i<0xFFFF; i++)
  1065.                     (and                        ;   if (
  1066.                         (presentp i)            ;       is_present(i) &&
  1067.                         (= 3 (rpl i))           ;       rpl(i)==3 &&
  1068.                         (not (zerop (lsl i))))  ;       lsl(i))
  1069.                     (format stdout              ;       printf(
  1070.                         "SEG ~A\tLSL ~A\n"      ;         "SEG %u\tLSL %u\n",
  1071.                         i (lsl i))))            ;         i, lsl(i));
  1072.         SEG 15  LSL 15
  1073.         SEG 63  LSL 1226
  1074.         SEG 79  LSL 6162
  1075.         SEG 95  LSL 9394
  1076.         SEG 99  LSL 69
  1077.         SEG 103 LSL 3
  1078.         SEG 111 LSL 15742
  1079.         SEG 127 LSL 1278
  1080.         .....
  1081.             
  1082.         ; display all global (GDT) segments visible to our program
  1083.         > (dotimes
  1084.             (i #xffff)
  1085.             (if 
  1086.                 (and
  1087.                     (zerop (logand i 4))        ; GDT selector
  1088.                     (not (zerop (lar i))))      ; legal
  1089.             ; then
  1090.                 (format stdout "SEG ~A\tSIZE ~A\tLAR ~A\n"
  1091.                     i (lsl i) (lar i))))
  1092.         SEG 96      SIZE 69     LAR 241     ; GDT info seg
  1093.         ...
  1094.         SEG 848     SIZE 481    LAR 241     ; ??
  1095.         ...
  1096.         SEG 5624    SIZE 95     LAR 251     ; ??
  1097.         ...
  1098.         SEG 17800   SIZE 0      LAR 228     ; DLL entry points
  1099.         ...
  1100.         SEG 17808   SIZE 0      LAR 228
  1101.         ...
  1102.                         
  1103.     note:
  1104.         (lar) is equivalent to the 286 protected-mode instruction LAR.
  1105.  
  1106.         This instruction is useful, not only for determining the access
  1107.         rights of a known segment, but for determining if some arbitrary
  1108.         segment number corresponds to an actual segment.  Unlike
  1109.         most 286 protected-mode instructions, LAR, LSL, VERR, and
  1110.         VERW do NOT cause segment violations (GP fault) if called with
  1111.         illegal segment numbers.  
  1112.  
  1113.         You can experiment with OS/2 memory management by overcommiting
  1114.         memory, then examining which code segments are present in memory,
  1115.         and so on.  The file OVERCOM.LSP provides a beginning for testing
  1116.         OS/2 memory overcommitment:  you can see as OS/2 "manufactures"
  1117.         memory in order to satisfy an allocation request.  This could be
  1118.         added to, using (lar) to test when segments change to being
  1119.         not-present, for example.
  1120.  
  1121.  
  1122.                                     
  1123. (verr <segment>)        VERIFY SEGMENT FOR READING PERMISSION
  1124.     <segment>           a memory segment/selector
  1125.     returns             T if readable, NIL if no permission
  1126.         
  1127.     example:
  1128.         > (verr (fp-seg (getprocaddr (loadmodule "DOSCALLS") 8)))
  1129.         NIL                 ; not allowed to read OS/2 entry point
  1130.         > (verr (fp-seg (func-addr (function pprint))))
  1131.         T                   ; are allowed to read our own code segments
  1132.             
  1133.     note:
  1134.         (verr) is equivalent to the 286 protected-mode instruction VERR.
  1135.  
  1136.  
  1137.             
  1138.             
  1139. (verw <segment>)        VERIFY SEGMENT FOR WRITING PERMISSION
  1140.     <segment>           a memory segment/selector
  1141.     returns             T if writable, NIL if no permission
  1142.         
  1143.     example:
  1144.         > (verw (fp-seg (func-addr (function pprint))))
  1145.         NIL             ; not allowed to write into our own code segment
  1146.         > (verw (fp-seg (address-of beast)))
  1147.         T               ; are allowed to write into our own data allocations
  1148.             
  1149.     note:
  1150.         (verw) is equivalent to the 286 protected-mode instuction VERW.
  1151.         
  1152.  
  1153.  
  1154. MISCELLANEOUS FUNCTIONS
  1155.  
  1156. (word <number>)     CREATE AN XLISP NODE WITH 2-BYTE INTEGER
  1157.     <number>            an XLISP 4-byte integer
  1158.     returns             the same number, stored in 2 bytes
  1159.  
  1160.     example:
  1161.         > (call dosselectdisk (word 1))         ; try to select drive A:
  1162.         T                                       ; T = success
  1163.             
  1164.     note:
  1165.         This function was introduced because many OS/2 function calls
  1166.         require a two-byte argument.  For numbers under 256, the 
  1167.         corresponding two-byte number will be displayed as a character
  1168.         code.  (word) is a kludge!
  1169.  
  1170.  
  1171.  
  1172. (smsw)      MACHINE STATUS WORD
  1173.     returns             286 machine status word:
  1174.                             bit 0       protection enable
  1175.                                 1       math coprocessor present
  1176.                                 2       no coprocessor; use emulator
  1177.                                 3       task-switch indicator
  1178.                                 4-15    reserved for 386, etc.
  1179.                                     
  1180.     example:
  1181.         > (define *integer-format* "%X")
  1182.         "%X"
  1183.         > (smsw)
  1184.         FFED
  1185.         ; is there a math coprocessor on board?
  1186.         > (logand (smsw) 2)
  1187.         0                               ; no, there isn't
  1188.             
  1189.           
  1190.  
  1191.     [[[ documentation not finished ]]]
  1192.  
  1193. (flags)     FLAGS REGISTER
  1194.     returns             286 flags register:
  1195.                             bit 0       carry flag
  1196.                                 2       parity flag
  1197.                                 4       auxiliary carry
  1198.                                 6       zero flag
  1199.                                 7       sign face
  1200.                                 8       trap (single-step) flag
  1201.                                 9       interrupt enable flag
  1202.                                 10      direction flag 
  1203.                                 11      overflow flag
  1204.                                 12,13   i/o privilege level
  1205.                                 14      nested task (iret control)
  1206.                                     
  1207.         
  1208. (ds)        DATA SEGMENT
  1209.     returns             the OS2XLISP data segment
  1210.         
  1211. (ss)        STACK SEGMENT
  1212.     returns             the OS2XLISP stack segment
  1213.     note:
  1214.         Will differ for other threads, once multi-tasking implemented
  1215.  
  1216. (sp)        CURRENT STACK POINTER
  1217.     returns             the current stack pointer
  1218.         
  1219. (shl <op1> <op2>)       ARITHMETIC SHIFT LEFT
  1220.     <op1>               the number 
  1221.     <op2>               number of shifts
  1222.     returns             <op1> shifted left <op2> times
  1223.         
  1224. (shr <op1> <op2>)       ARITHMETIC SHIFT RIGHT
  1225.     <op1>               the number 
  1226.     <op2>               number of shifts
  1227.     returns             <op1> shifted right <op2> times
  1228.         
  1229. (atol <string>)         CONVERT ASCII STRING TO LONG
  1230.     <string>            a string
  1231.     returns             long number
  1232.         
  1233. (ultoa <number> <radix>)        NUMBER CONVERTED TO STRING IN RADIX
  1234.     <number>            the number
  1235.     <radix>             base
  1236.     returns             ASCII string of number in base
  1237.  
  1238.         
  1239. STARTER FUNCTIONS
  1240.  
  1241.     [[[ need to document the functions in INIT.LSP ]]]
  1242.  
  1243. (dos-mem-avail)
  1244.  
  1245. (dos-alloc-seg), (dos-free-seg)
  1246.  
  1247. (date), (time)
  1248.  
  1249. (getpid), (getppid)
  1250.  
  1251. etc.
  1252.  
  1253.  
  1254.  
  1255. APPENDIX A -- ANNOTATED BIBLIOGRAPHY
  1256.  
  1257.     OS/2:
  1258.  
  1259.     Gordon Letwin, "Inside OS/2" (Microsoft Press, 1988).  A lot of 
  1260. Microsoft corporate propaganda on "The OS/2 Religion," "Microsoft's vision
  1261. on the future," "Microsoft's plans for the coming second industrial
  1262. revolution" (?!), and so on, but actually an excellent book.  Should be
  1263. read in conjunction with any standard textbook on operating systems, such
  1264. as Deitel's "An Introduction to Operating Systems."
  1265.  
  1266.     Ed Iacobucci, "OS/2 Programmer's Guide" (McGraw-Hill, 1988).  The
  1267. one OS/2 book to have, when you're having only one.  Very complete
  1268. reference with a few unfortunate typographical errors (e.g., layout of
  1269. the LDT info seg on p.610 has wrong offsets; reference page for
  1270. DosDevIOCtl on p.721 refers to a non-existent Appendix C; but hey!, at
  1271. $24.95, it sure beats what Microsoft is charging for development kits).
  1272. Definitely order the disk -- it not only has all the ASM code from the
  1273. back of the book, but you can get it in C as well.  I particularly
  1274. recommend his SNAKE.C for learning about multi-threaded applications.
  1275.  
  1276.     David Cortesi, "The Programmer's Essential OS/2 Handbook," M&T Books,
  1277. 1988.  Cortesi has obviously done a lot of digging in OS/2, and has come
  1278. up with a lot of information not found in Microsoft's documentation.  The
  1279. discussion of run-time dynamic linking (pp.132-137) unfortunately contains
  1280. a number of errors.  As with Iacobucci's book/disk, the Cortesi disk
  1281. contains a tremendous amount of code not found in the book -- his Pascal
  1282. code seems to be in a little better shape than his C, but all in all it's
  1283. a pretty remarkable job.  His reference section (which comes after the
  1284. index) is the best place to look up OS/2 error codes.
  1285.  
  1286.     Jeffrey Krantz, Ann Mizell, Robert Williams, "OS/2 Features,
  1287. Functions, and Applications" (Wiley, 1988).  Their code is pretty bad,
  1288. but has a good section on CONFIG.SYS settings, and a lengthy section
  1289. on run-time dynamic linking.
  1290.  
  1291.     Charles Petzold, "Programming Windows" (Microsoft Press, 1988).  Why
  1292. mention a Windows book when listing OS/2 resources?  Because Windows was
  1293. very much Microsoft's guinea pig for OS/2 -- or, Windows programmers were
  1294. the guinea pigs and Windows was the laboratory.  Anyway, much of Petzold's
  1295. book is a good introduction to OS/2 land and, in any case, it's good
  1296. preparation for Presentation Manager.  
  1297.  
  1298.     Charles Petzold, "Environments" column, PC Magazine,
  1299. 29 September 1987-.  Essential.
  1300.  
  1301.     David Cortesi, "Dynamic Linking in OS/2," Dr. Dobb's, December 1987.
  1302. Also see the responses in Dr. Dobb's, April 1988, p.14.     
  1303.         
  1304.     Microsoft Systems Journal, May 1987.
  1305.         
  1306.     PC Tech Journal, November 1987.
  1307.         
  1308.     Three "un-resources" (books to avoid because they provide nothing that
  1309. isn't already in the Microsoft documentation) are:  Judd Robbins, "Inside
  1310. OS/2" (Sybex); Kris Jamsa, "Using OS/2" (McGraw-Hill); and John Campbell,
  1311. "Inside OS/2" (Tab).  
  1312.         
  1313.     Protected mode:
  1314.  
  1315.     Ed Strauss, "Inside the 80286" (Brady, 1986).  Excellent book on
  1316. the 286; necessary even if you have a 386, because OS/2 is definitely
  1317. a 286 operating system right now (grrrr).
  1318.  
  1319.     John Crawford, Patrick Gelsinger, "Programming the 80386"
  1320. (Sybex, 1987).  This is THE 386 book, with wonderful pseudocode in C
  1321. for every instruction.
  1322.  
  1323.  
  1324.     Lisp:
  1325.         
  1326.     Guy L. Steele, Jr., "Common LISP: The Language" (Digital Press,
  1327. 1987).  The complete guide to the language.  If you know Harbison & Steele's
  1328. "C: A Reference Manual," this is same kind of thorough reference.  
  1329.  
  1330.     Deborah Tatar, "A Programmer's Guide to Common LISP" (Digital
  1331. Press, 1987).  Based on Steele.
  1332.  
  1333.     David S. Touretzky, "LISP:  A Gentle Introduction to Symbolic
  1334. Computation" (Harper & Row, 1984).  A gentle introduction to symbolic
  1335. computation.
  1336.  
  1337.     Robert Wilensky, "Common LISPcraft" (Norton, 1986).  
  1338.  
  1339.     Harold Abelson, Gerald Jay Sussman, Julie Sussman, "Structure
  1340. and Interpretation of Computer Programs" (MIT Press, 1986).  While
  1341. Abelson and Sussman describe the Scheme dialect of LISP, this may be
  1342. the best book on computer programming ever written.  Two other
  1343. books employing the Scheme dialect may also be useful to you:
  1344. Daniel P. Friedman and Matthias Felleisen, "The Little LISPer"
  1345. (MIT Press, 1987); and Michael Eisenberg, "Programming in Scheme"
  1346. (Scientific Press, 1988).  Note that David Betz has a version of
  1347. XScheme 0.7 running under OS/2.
  1348.  
  1349.  
  1350.