Subject: v06i001:  lib_dm - <-LIB-> version 1.5, Part01/02
Keywords: hp48 library tool building/splitting objects
Date: 6 Jul 92 01:11:00 GMT

BEGIN_DOC lib_dm.doc

Hi all,

Here's an update of <-LIB-> to version 1.5

Features:
    o   implemented as library (no. 1221), containing *37* commands
    o   building/splitting libraries and un/supported objects
    o   D->LIB/L->DIR are compatible to the USRLIB.EXE directory format
    o   fast; build an 8.5 kb library in ~32s, split it in ~22s
    o   small in size (~7kb)
    o   standalone interface to library data objects
    o   powerfull library management tools
    o   many programming tools
    o   many status commands

Changes vs. version 1.4:
      - cksum/bytes: #9CFEh/6962
      - add config message
      - reordered nearly all commands (sorry)
      - expand $ROMID range to 0..2047
      - fix bug in D->LIB regarding generation of commands which are
	legal in algebraics
      - L->DIR produced a strange $ROMID for IDs < 10, fixed
      - L->DIR generated to few variables if # visible cmds << # hidden
	cmds, fixed
      - rename ->$AR to ->ARR, improve it
      - rename LIB? to LIBp, modify it
      - rename ADR? to ADRp
      - improve PGLIB
      - add fast mode to L->DIR, D->LIB
      - add BACKUP support to OB->
      - add ->BAK, LBCRC, RNLIB, CHLID, RLIB, STLIB, ACLIB, INSTp,
	LIBSp, fEVAL
      - reviewed the documentation

Please excuse all the linguistic mistakes in this text. English is not my
native language.

Copyright Notice:
    Copyright (c), 1992, Detlef Mueller, Raymond Hellstern, Rick Grevelle.
    Permission to copy this article is granted provided that the copies are
    not made or distributed for resale (excepting nominal copying fees).
    Other permissions can be arranged by contacting Detlef Mueller via email
    at the following address:
	detlef@mwhh.hanse.de

    <-LIB-> is distributed in the hope that it will be useful, but
    WITHOUT *ANY* WARRANTY.

Installation:
    To install <-LIB->, a) download the ASC version, execute ASC->, or b)
    download the uudecoded version and recall it into the stack. Purge the
    variable which contains the orginal copy. Enter the port number (0,1,2)
    where you want to store <-LIB-> and press STO. Switch the HP48 off, then
    on again. <-LIB-> will now be installed.

Deinstallation:
    To get rid of <-LIB-> execute the following commands (assuming that the
    port where <-LIB-> is stored have R/W acess) :
	HOME                    @ switch to the home directory
	1221 DETACH             @ release library
	:&:1221 PURGE           @ search and purge library
    or
	1221 PGLIB

Note:
    In the documentation below I'll often use the abbreviation 'LID'; meaning
    'library id'. It's a number in the range 0..2047 and is part of any
    library, used to identify libraries while resolving commands, messages
    et c.

Command Quick Reference
(in order of appearance in the LIBRARY <-LIB-> menu):

    Page 1:
	D->LIB  (               --> lib         )       make library
	L->DIR  ( %             --> dir         )       split library
	MCFG    (               -->             )       make config program
	ML->D   (               --> prg         )       make libdat-> handler
	MD->L   (               --> prg         )       make ->libdat handler
	OB->    ( ob            --> ?           )       split object

    Page 2:
	->DIR   ( meta          --> dir         )       make directory
	->PRG   ( meta          --> prg         )       make program
	->XLIB  ( % % | # #     --> xlib        )       make XLIB
	->ARR   ( meta          --> arry        )       make array
	->ALG   ( meta          --> alg         )       make algebraics
	->LD    ( {} %          --> libdat      )       make library data

    Page 3:
	->BAK   ( ob $          --> bak         )       make backup
	ADRp    ( ob            --> ob #        )       get address of object
	$romid  (               --> id          )       get id '$ROMID'
	$visible (              --> id          )       get id '$VISIBLE'
	$title  (               --> id          )       get id '$TITLE'
	$config (               --> id          )       get id '$CONFIG'

    Page 4:
	$vars   (               --> id          )       get id '$VARS'
	$hidden (               --> id          )       get id '$HIDDEN'
	$message (              --> id          )       get id '$MESSAGE'
	LBCRC   ( lib | bak     --> lib' | bak' )       recalculate CRC
	RNLIB   ( lib $         --> lib'        )       rename library
	CHLID   ( lib %         --> lib'        )       change LID

    Page 5:
	RHASH   ( %             --> C#          )       get hash table
	RLINK   ( %             --> C#          )       get link table
	RCFG    ( %             --> prg         )       get config code
	RMSG    ( %             --> arry        )       get message table
	RPORT   ( %             --> ob ...      )       recall port
	RLIB    ( %             --> lib % ...   )       recall library(s)

    Page 6:
	PGLIB   ( % | :%:%      -->             )       purge library
	STLIB   ( lib %         -->             )       store library
	ACLIB   ( :%:%          -->             )       activate library
	LIBp    ( %             --> $           )       get library layout
	INSTp   (               --> {}          )       get installed LIDs
	LIBSp   (               --> {}          )       get available LIDs

    Page 7:
	fEVAL   ( ob            --> ?           )       fast EVAL

Detailed Command description
(in order of appearance in the LIBRARY <-LIB-> menu):

    D->LIB      (                       --> lib                         )
	Dir to lib; assembles a library from the objects of the current
	directory. The creation process is controlled by a few variables
	with reserved names (see 'Control Variables' below). This control
	interface is adapted from USRLIB.EXE, so I recommend you to read
	USRLIB.DOC also. Both files are provided by HP in the self-
	extracting archive TOOLS.EXE (MesS-DOS), availabe on several ftp
	sites.
	If you set flag -13 before running D->LIB, it'll switch off the
	screen while working (for saving time and batteries).

    L->DIR      ( %LID                  --> dir                         )
		( XLIB                  --> obj                         )
	Lib to dir; if the argument is a LID then L->DIR assembles a
	directory containing all commands of this library as variables. The
	necessary control variables (see below) are also generated. L->LIB
	may be used to recreate the library. If the argument is a XLIB
	(a named or unnamed library command) then L->DIR recalls its object
	from the associated library onto the stack.
	If you set flag -13 before running L->DIR on a library, it'll switch
	off the screen while working (for saving time and batteries).

	Note: You cannot use L->DIR to split <-LIB->, this should prevent
	users from a memory lost. If you are conform with the internals of
	your HP48, use 'ROMPTR@' to extract single routines from <-LIB->,
	but beware of starting the routines in RAM, most of them will crash
	your calc when running standalone !

    MCFG        (                       -->                             )
	Make config; stores a configuration program into a variable named
	'$CONFIG' to the current directory. This configuration program will
	attach the generated library to the home directory at warmstarts
	(ON-C etc.)
	'$ROMID' must exist in the current directory.

    ML->D       (                       --> prg                         )
	Generates a program with the following interface:
		( {}                    --> lib_data                    )

	The list can contain anything. The program checks for argument count
	and type and may error with:
	    #201 - To Few Arguments
	    #202 - Bad Argument Type

	'$ROMID' must exist in the current directory.

    MD->L       (                       --> prg                         )
	Generates a program with the following interface:
		( lib_data              --> {}                          )
	The program checks for argument count, type and correct LID and may
	error with:
	    #201 - To Few Arguments
	    #202 - Bad Argument Type
	    #203 - Bad Argument Value

	'$ROMID' must exist in the current directory.

      Note: Store the programs generated by ML->D and MD->L into variables
      in your source directory and use use them as an interface to generate/
      resolve data associated to the resulting library (see 'An Example'
      below).

    OB->        ( prg                   --> ob1 .. obn %n               )
		( xlib                  --> %LID %objno                 )
		( arry                  --> ob1 .. obn { %di .. %d1 }   )
		( alg                   --> ob1 .. obn %n               )
		( dir                   --> ob1 id .. obn id %n         )
		( lib_data              --> {} %LID                     )
		( backup                --> ob $                        )
		( any_other             --> dispatch to OBJ->           )
	OB-> is an extension to the built-in OBJ->. Just try it.

    ->DIR       ( ob1 id1 .. obn idn %n --> dir                         )
    ->PRG       ( ob1 .. obn %n         --> prg                         )
    ->XLIB      ( %LID %objno           --> XLIB                        )
		( #LID #objno           --> XLIB                        )
    ->ARR       ( ob1 .. obn %n         --> arry                        )
		( ob1 .. obn { %di .. %d1 } --> arry                    )
    ->ALG       ( ob1 .. obn %n         --> prg                         )
    ->LD        ( {} %LID               --> lib_data                    )
    ->BAK       ( ob $                  --> backup                      )
	Functions to reverse OB->.
	About ->ARR:
	   Generates arrays of any type and any dimension (eg. a four
	   dimensional array of libraries :-).
	   %di * .. * %d1 must be = n, ob1 .. obn must be of the same type.
	   All possible parameter errors are trapped.

    ADRp        ( ob                    --> ob #addr                    )
	Get address of ob.

	Note: The data stack is a stack of pointer to objects. ADR? simply
	returns the value from the top element (about the 'p', see 'LIBSp'
	below).

    $romid
    $visible
    $title
    $config
    $vars
    $hidden
    $message    (                       --> '$XXX'                      )
	These commands just put a control variable identifier onto the stack.

    LBCRC       ( lib                   --> lib'                        )
		( backup                --> backup'                     )
	Recalculates the CRC of a library or backup, usefull if you have
	patched it (modifying the body of a library or backup invalidates
	the included CRC).

    RNLIB       ( lib $                 --> lib'                        )
	Renames a library (changes title).

    CHLID       ( lib %                 --> lib'                        )
	Change LID; this program allows you to change the LID of a library
	if it's not splittable.

	Note 1: If you're using the Config Suppressor, LID 4, you may
	change it's LID to 14 without any problem, because Simone already
	uses LID 4 for the KEEPER library. Sorry, I didn't know that :-(

	Note 2: Mostly the LID is also hardcoded in the config code - this
	can generally not be changed by CHLID. You have to attach the library
	manually after a warmstart. Also a library contains its LID coded
	in a field above any visible command (the error handling system
	identifies the command that causes an error using this field (the
	sys-RPL commands 'CKn' copies this values to the appropriate
	location)). These fields are also not changed by CHLID (maybe I'll
	add it in the next update (if any)).
	If HP is listening: You should redefine the stack frame during
	config time in the successor of the HP48. Having the LID of the
	actual library being configed on the stack (as a %) would allow
	any config code using this value for autoattachment. This would
	make changing of LIDs easy. :-)

    RHASH       ( %LID                  --> C#                          )
	Recall hash table; get a pointer to the hash table of a library.

    RLINK       ( %LID                  --> C#                          )
	Recall link table; get a pointer to the link table of a library.

    RCFG        ( %LID                  --> ob                          )
	Recall config code; get a pointer to the config code of a library.

    RMSG        ( %LID                  --> arry                        )
	Recall message table; get a pointer to the message table of a
	library.

      Note: RHASH, RLINK, RCFG and RMSG don't error if the library associated
      to %LID didn't contain the requested item, they leave the stack
      unchanged in that case.

    RPORT       ( %port                 --> ob1 .. obn                  )
	Recalls pointers to all objects of a given port (0/1/2) onto the
	stack, ignoring the R/W status of that port.

    RLIB        ( :%port:%LID           --> lib                         )
		( %LID                  --> libn %portn ...             )
	Recall lib; the 1st case recalls a library from a given port, the
	2nd case searches ports 0,1,2 for libraries with %LID, returning
	all found libraries and the ports where they resides.

	Note: This command actually returns pointer to libraries (like
	RPORT), if you recall a lib and try to purge it while it's on
	the stack, you'll get a 'Object in use' error. Execute NEWOB or
	store it into a variable first.

    PGLIB       ( :%port:%LID           -->                             )
		( %LID                  -->                             )
	Purge lib; the 1st case works like :%port: %LID PURGE, in the 2nd
	case the ports are searched in order 0,1,2 for a library with %LID.
	The difference to PURGE: if the found library is attached to the home
	directory, it's detached before purging. Also if there is a inactive
	library with the same LID in any other port, it becomes active and
	is attached to the HOME directory.

    STLIB       ( lib %port             -->                             )
	Store lib into port; there're a few differences to STO:
	    - The library is installed full; a warmstart isn't neccessary
	      and thus not initiated at the next power cycle. All warmstart
	      volatile variables (stack, PICT) remains intact.
	    - The library last stored is visible to the HP48 (in case of
	      having a library with the same LID installed in another port).
	    - If flag 1 is clear, the library is attached simply to the
	      home directory.
	    - If flag 1 is set, the config code of the library is executed
	      under warmstart conditions.
	      This is usefull for testing a config code.

    ACLIB       ( :%port:%LID           -->                             )
	Activate library. Using STO you can install libraries with the same
	LID on different ports, but only one will be visible to the HP48 at
	the time. During warmstarts the ports are searched in order 2,1,0
	(most cases), ei. the library residing in the port with the highest
	number will be active. ACLIB allows you to switch to any other
	library with the same LID at runtime, the effect is immediate. ACLIB
	1st detaches the LID from HOME, sets the new priority and than a)
	attaches the LID to HOME again if flag 1 is clear, or b) runs the
	library config code if flag 1 is set (like STLIB).

      Note: A typical work cycle for testing an update of a library (LID x),
      which previous version is stored in port 1 or 2 (n) might be:
	- create the update, put it on the stack then 0 STLIB
	- x MENU, testing .....
	- oops, command failed. But need it now: :n:x ACLIB VAR x MENU
	- use old command then back to update: :0:x ACLIB VAR x MENU
	- testing .....
	- want to save update: :0:x RLIB NEWOB or 'xyz' STO
	- ditch away new version: :0:x PGLIB or old version: :n:x PGLIB
	- ...
      A similar cycle, but only port 0 available:
	- create the update, put it on the stack
	- get old version, purge it from port 0, change LID, store it back
	  and store update:
	  x RLIB DROP NEWOB x PGLIB 800 CHLID 0 STLIB 0 STLIB
	- x MENU ....
	- oops, ... 800 MENU ....
	- ditch away update, recall old version, purge old version, change
	  old version to original LID and store it back:
	  x PGLIB 800 RLIB DROP NEWOB x CHLID 0 STLIB
	- ...

    LIBp        ( %LID                  --> $                           )
	Returns a detailed layout of a library. The map starts with the
	title (if exist), followed by the 1st and last address of the lib
	and the LID. The remainder lists the contens of the lib, one line
	of information for each XLIB entry. Structure of a line:

	    1st last  xn name  typ
	    ||| ||||  || ||||  +++- Type of the object
	    ||| ||||  || ++++------ Name of the object (if it's a visible cmd)
	    ||| ||||  ++----------- XLIB number of the object
	    ||| ++++--------------- Last relative address of the object
	    +++-------------------- Offset to startaddr. of the object

	The list is sorted by address. Try 1221 LIBp or 2 LIBp.

	Note: If you find unexpected 'holes' between two XLIBS (> 10 nibbs)
	or XLIBS embedded in other XLIBS, the library wasn't generated using
	USRLIB.EXE or D->LIB.

    INSTp       (                       --> { %LIDn .. %LID1 }          )
	Returns a list of all libraries attached to the current directory,
	{ } if none.

	Note: You can PURGE libraries even if they are attached to a
	subdirectory. INSTp can be used to find such zombies.

    LIBSp       (                       --> { %LID1 .. %LIDn }          )
	Returns a list of all libraries currently installed on your HP48.


      Note: The '?' prefix denotes normally returning of a flag in RPL,
      the JARGON file, v2.9.9, 01 APR 1992 states:
	3. The `-P' convention: ------------------------ Turning a word into
	a question by appending the syllable `P'; from the LISP convention of
	appending the letter `P' to denote a predicate (a boolean-valued
	function).  The question should expect a yes/no answer, though it
	needn't.  (See {T} and {NIL}.)

	At dinnertime:
	   Q: "Foodp?"
	   A: "Yeah, I'm pretty hungry." or "T!"

	At any time:
	   Q: "State-of-the-world-P?"
	   A: (Straight) "I'm about to go home."
	   A: (Humorous) "Yes, the world has a state."

      so I used 'p' for general information questions ;-)

    fEVAL               ( obj           --> ?                           )
	Works like EVAL, but switches the display off 1st. Speeds up
	evaluation ~11%. In case of an error or the obj have fineshed
	execution, the display is switched on again. Not very usefull,
	if obj prompts for input...

Control Variables:
    The library creation process is controlled by some variables with
    reserved names (multiple occurences of these names are ignored, but
    only the contens of the 1st one found in the source directory is
    used for the library creation process) :

    $ROMID
	Contains a real or binary number representing the LID that is to be
	given to the library. If you want to release your developed software
	to the world, make shure that your choosen LID is not used by others.
	The LID must be in the range 0..2047.

    $TITLE
	Contains a string to be used as the name of the library. The first
	few characters of the title are used for the LIBRARY menu label; the
	first 22 characters are displayed by REVIEW.
	If $TITLE is absent or contains a null string, no title is generated
	and the resulting library is not shown in the LIBRARY menu.

    $CONFIG
	Contains a program to be executed at configuration time. The
	configuration code can generally NOT be written in user-accessible
	commands. Simple programs such as
		\<< 123 ATTACH \>>
	are OK, but more complicated programs should take care to leave the
	stack unchanged, and be sure NOT TO ERROR ! I recommend to use MCFG
	to generate a configuration program.

    $MESSAGE
	Contains a list of strings to be combined into a message table. The
	message numbers correspond to the list positions. In user-RPL you can
	generate errors with own messages in the following manner:
		#32001h DOERR
		 |||++-- Message number (here 1)
		 +++---- LID            (here #320h = 800)
	In this example DOERR will generate an error, using the first message
	from the message table of a library with the LID 800.

	Note: The message list structure is NOT compatible to USRLIB.EXE.

    $VISIBLE
	Contains a list of names of variables to be converted to user-
	accessible, named library commands. By default, all variables will be
	translated to named library commands. When the $VISIBLE list is
	present, only the names in this list are included in the library hash
	table. An empty list is OK, meaning that no hash table is generated.

    $HIDDEN
	Contains a list of names of variables that are to be converted to
	null-named objects in the library, and so hidden from the user. When
	the $HIDDEN list is present, those names listed are not entered in
	the library hash table. If both $VISIBLE and $HIDDEN are present,
	only $HIDDEN will be used.

    $VARS
	Contains a list of variables that should remain RAM-based - the
	stored objects are not included in the library, and no XLIB pointers
	are made to substitute their names. All other variables in the source
	directory are included in the library.

	Note: You should add all subdirectory names of the source directory
	to the list.

    $ROMID must exist in the current directory, all other control variables
    are optional - you can generate libraries containing only a configuration
    program or a message table. All control variables are internally handled
    by D->LIB to be RAM-based.

Error Messages:
    Along with the 'normal' error messages like 'Insufficient Memory' you can
    get one of the following messages by some of the commands:

    "Missing $ROMID"
	'$ROMID' is not defined in the current directory. You MUST create
	a variable named '$ROMID' and store a LID into it.

    "$ROMID Not Real/Binary"
	'$ROMID' doesn't contain a real or binary object.

    "$ROMID Out of Range"
	a) The value of '$ROMID' is > 2047.
	b) A real > 2047 was passed to CHLID.

	Note: Negative reals are mapped to 0.

    "$CONFIG Not a Program"
	Because the stack must not change during warmstarts, '$CONFIG'
	must contain a program.

	Note: Use 1 ->PRG to embedd CODE, IDs or XLIBs into a program.

    "$HIDDEN Not a List"
    "$VISIBLE Not a List"
    "$VARS Not a List"
    "$MESSAGE Not a List"
	$XXX must contain a list.

    "Found ID Name>16 Chars"
	D->LIB have found a visible command identifier which is > 16 chars
	in size.

    "Found 0-ID"
	D->LIB have found a visible command identifier with the size 0.

Things to Notice:
    +---------------------------------------------------+
    | HP 48 Resource Allocation Guideline: Library ID's |
    +---------------------------------------------------+
    | 0000 - 0256  Take-over libraries; do not use!     |
    | 0257 - 0512  HP ROM-based libraries; do not use!  |
    | 0513 - 0768  HP RAM-based libraries; do not use!  |
    | 0769 - 1536  3rd Party (assigned by HP)           |
    | 1537 - 1791  3rd Party (assigned by HP)           |
    | 1792 - 2047  Command-line; do not use!            |
    +---------------------------------------------------+

    The library stucture is 'flat', so don't try to include subdirectories in
    a library, it can end up in a memory lost.

    Not all program objects that execute correctly from global variables are
    directly convertible into libraries. Here are some pitfalls:
	- Since a library cannot be modified, no library command may be the
	  target of a STO or PUT operation.
	- XLIB names are not usable in all contexts in which global names are
	  valid arguments. This can cause constructs that reference a named
	  object to fail. For example,
		'A' 5 GETI
	  where A is a list will not work when A is converted to an XLIB
	  name. Instead use
		A 5 GETI
	- XLIB names are not valid as formal variables in algebraics, or as
	  the independent variable for plotting or solving.
	- \->STR applied to a global name that is converted to a 'hidden'
	   library command (see $HIDDEN) returns a null string.

    If any visible command starts with the seqence '\<< \->' or '\->' it's
    marked in the library as a valid command for algebraics. If you press
    its associated softkey in ALG entry mode, you'll get 'name()'.

    Multiple occurences of variable names results in an incorrect library
    because only the contens of the 1st one is picked up.

    D->LIB needs ~(1.2 * size_of_source_directory) bytes to be free to
    generate a library.

    The time D->LIB needs for doing a job depends mainly on the total number
    of commands included in the resulting library. Eg. Raymond runs D->LIB
    on a ~60kb directory containing ~300 variables; D->LIB needs ~45min on
    a rev A HP48 to build the library (not in FAST-mode).

    Reassembling a splitted library may be dangerous if the original library
    wasn't generated using USRLIB.EXE or D->LIB. There is no guarantee that
    the result will work probably - even if no code changes are done.

    USRLIB.EXE generates a link table entry for the configuration program;
    if you split such a library with L->DIR, you'll get the configuration
    code twice, the 1st one stored in $CONFIG, the 2nd one stored in a
    variable of the generated directory. Purge the variable before using
    D->LIB. You also can use LIB? to see the second reference to the config
    code.

    I didn't find informations about library data objects, so I take a close
    look at the HP EQLIB card (thanks to Raymond for borrowing me one) and
    adapt the methods to create/resolve library data objects.
    In the HP EQLIB card (and in <-LIB->), a library data object is some sort
    of composite, has the prologue DOEXT0, and a body which is a sequence of
    objects and object pointers, the last of which is an object pointer whose
    pointee is the primitive code object SEMI. The body also includes a
    length field (indicating the length of the body) and the LID of the
    library which have generated the data:
		+-----------------------+
		|      -> DOEXT0        | Prologue Address
		+-----------------------+
		|     Length Field      | Body          Library
		|     ------------      |               Data
		|         LID           |               Object
		|     ------------      |
		|        Object/        |
		|    Object Pointer     |
		|       Sequence        |
		|     ------------      |
		|       -> SEMI         |
		+-----------------------+

    Note: Converting such an object to a list is very simple, just change
    DOEXT0 to DOLIST and the length field to DOBINT. But there is no
    guarantee, that existing libraries (which generates library data)
    are using this structure; using OB-> (or the program generated by
    MD->L) on such an object may cause a memory lost.

*****************************************************************************
*    I'll maintain this tool, so feel free to mail me any comments,         *
*    error descriptions, ideas of improvement, questions, information,      *
*    suggestions et c. :-)                                                  *
*****************************************************************************

Listings (sys-RPL in HP terminology) of the generated programs (#LID is
generated using the LID value stored in $ROMID):

    Program created by MCFG :
	::  #LID TOSRRP
	;

    Program created by ML->D :
	ASSEMBLE
	>HCOMP  EQU     #052C6  ( { .. } ob --> { ob .. } ); near >TCOMP
	RPL
	::  CK1NOLASTWD
	    CK&DISPATCH1
	    list
	    ::  #LID >HCOMP             ( --> { #rid ... } )
		DUP OSIZE #5-           ( --> {} #sz )
		CODE                    ( {} #sz --> LibDat )
	*       CPU                             A       C       D1
			GOSBVL  =POP#           sz
			GOSBVL  =SAVPTR
			C=DAT1  A                       &{}
			D1=C                                    &{}
			LC(5)   =DOEXT0                 LD
			DAT1=C  A
			D1=D1+  5                               &1st elem (#)
			DAT1=A  A
			GOVLNG  =GETPTRLOOP
		ENDCODE
	    ;
	;

    Program created by MD->L :
	::  CK1NOLASTWD
	    CK&DISPATCH1
	    #AF                         ( *Libaray data* )
	    ::  #LID SWAP TOTEMPOB      ( --> #rid ld )
		CODE
	*       CPU                             A       C       D1
			GOSBVL  =SAVPTR
			A=DAT1  A               &ld
			D1=A                                    &ld
			LC(5)   =DOLIST                 {}-prol
			DAT1=C  A
			D1=D1+  5                               &len
			LC(5)   =DOBINT                 #-prol
			DAT1=C  A
			GOVLNG  =GETPTRLOOP
		ENDCODE
		DUP CDRCOMP             ( #rid {} --> #rid {} {}-1st )
		SWAP CARCOMP            ( --> #rid {}-1st #rid' )
		ROT #<>case SETSIZEERR
	    ;
	;

Credits:
    1) Rick Grevelle
	L->DIR and DIR-> (in OB->) are basing on RCLIB, ->DIR and DIR->
	(in OUT->) of the HACKIT library. He send me a new version of
	->DIR (complete ML), which is very fast, uses less memory and
	handles 0-IDs correctly.
	Also thanks for many suggestions and exiting talks.
    2) Joseph K. Horn
	Thanks for suggestions, the `HP 48 Resource Allocation Guideline:
	Library ID's` and SORTLS (I used the kernel of it in LIBp to sort
	the listing by address).
    3) Simone Rapisarda
	Thanks for many suggestions, leading to some of the advanced
	commands since version 1.5.
    4) Romain Desplats, Georg Hoppen
	Thanks for suggestions and for testing all the beta releases.
    4) Chris Spell
	Thanks for sorting this chaos :-)
    5) W. C. Wickes, HP Corvallis
	Thanks for the HP48, the RPL tools and the ASC stuff.

Happy programing,
	8-Detlef.

END_DOC

A little example, assumes <-LIB-> is installed already:

BEGIN_RPL xmpl_dm.dir
%%HP: T(3);
DIR
  SETUP
    \<< CLLCD

	"Creating:\010Workspace" 1 DISP
	VARS
	'\Gt' DUP CRDIR EVAL
	LIST\-> 2 SWAP
	START
	    DUP RCL SWAP STO
	NEXT
	DROP

	"Variables" 2 DISP
	MCFG
	MD\->L 'ld\->' STO
	ML\->D '\->ld' STO

	"Library" 2 DISP
	D\->LIB

	"Cleanup\010\010\010\010" 1 DISP
	UPDIR '\Gt' PGDIR
	UPDIR

	"Installing library" 1 DISP
	IFERR :0: 888 PGLIB THEN
	    DROP
	END
	0 STLIB

	"Creating info" 1 DISP
	:0: 888 RLIB
	888 LIBp
	888 MENU

	"Press 'Write',\010then 'Read' \031\010\010\010\010" 1 DISP
	3 FREEZE
    \>>

  $ROMID   888

  $TITLE   "XMPL  :0.0\169XYZ'92"

  $VISIBLE
  {     Read Write
  }

  $MESSAGE
  {     "Can't find MYpar"
	"MYpar is invalid"
	"Canceled"
  }

  Read
    \<< IFERR 'MYpar' RCL THEN
	    DROP
	    # 37801h DOERR
	END
	IFERR ld\-> THEN
	    DROP
	    # 37802h DOERR
	END
	LIST\-> DROP
	CLLCD 1 DISP
	3 FREEZE
    \>>

  Write
    \<< "Edit your text:"
	{ 0 \Ga }
	IFERR
	    'MYpar' RCL
	    ld\->
	    LIST\-> DROP
	THEN
	    DROP
	    "8-) 3-) |-} ;-\254"
	END
	+
	IFERR INPUT THEN
	    DROP2
	    # 37803h DOERR
	END
	1 \->LIST
	\->ld 'MYpar' STO
    \>>
END
END_RPL
