HP Forums

Full Version: (50g) FNINVARS: Object finder for couch hackers
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
SCENARIO #1: Ever write a nifty program, then try to find it in your 50g a few weeks later, but you forgot what you named it? (This happens to me all the time, and I bet it happens to all inveterate couch hackers, especially those of us with aging memories.)

SCENARIO #2: Ever want to purge a program that you don't THINK you need any more, but you're afraid that something ELSE in memory might need it? (This happens to me a lot too, resulting in VARS getting bloated with unneeded programs).

This program, FNINVARS (Find In VARS), helps in these situations. Just put any object on the stack, either by itself or in a list, and then run FNINVARS. A list will be returned containing the names of all the programs in HOME which contain that object. If FNINVARS is in a subdirectory, it will search the VARS of that subdirectory.

You can search for any object, such as a command, or a global name, or a number... anything that you remember putting in that program you're looking for. Just like a Google search, the more unique the object is, the more useful the search result will be.

While FNINVARS is running, the object it is searching for is displayed at the top of the screen, as well as a countdown as it searches through VARS. Making it run faster by rewriting it in System RPL is left as an exercise for couch hackers. ;-)

Example 1: I recently wrote a program that uses the →Q function, but I can't remember what I called it.
{→Q} FNINVARS --> list of all programs in HOME which call the →Q function.

Example 2: Can I safely purge my old 'BOOFAR' program?
'BOOFAR' FNINVARS --> list of all the programs which call 'BOOFAR'.

Note: FNINVARS does not search for specific compound objects. For example, if you input { { 1 2 3 } } as the search object, FNINVARS will return a list of all programs which contain ANY list, regardless of its contents. The same is true for any compound object.

N.B. This program uses the →S2 command from Library 256, which is built into your HP 50g but by default is not attached. If you don't keep Library 256 attached, then be sure to do 256 ATTACH before compiling this program. Once it's properly compiled and stored, it will continue to work even if Library 256 is not attached.

%%HP: T(3)A(R)F(.);
  END -92. CF \->S2
  WHILE "\010  " "\010" SREPL
  POS SUB SREV "\010" + "Searching for:"
  OVER + 1. DISP \-> S2
  \<< VARS 1
    \<< ENDSUB NSUB - R\->I 3. DISP
        IF DUP RCL \->S2
          WHILE "\010  " "\010" SREPL
          END S2 POS NOT
        THEN DROP
    \>> DOSUBS
BYTES: 305.5 #6E26h
I wrote this programme to find a string in the variables of a directory:

    LAM O
      FPTR 4 2
      LAM O
    ROMPTR E8 10
nice entry!

Yes I forget a lot!
(10-11-2017 05:36 AM)Joe Horn Wrote: [ -> ]BYTES: 305.5 #6E26h

I have this program (I think the exact same) already in my 50g, so to confirm it's the exact same, I did 'FNINVARS' BYTES, which produces [318. #6E26], a difference of 12.5 bytes. Checksums match, so I'm confidant the code is the same.

Recalling the object itself on the stack as an argument to BYTES produces a smaller size (this does not include the name field, which is included when done using the global VAR name), and doing so does yield a smaller size, but the difference is not what I expected.

The AUR states:

"If the argument is a global name, then the size represents the name and its contents, while the checksum represents the contents only. The size of the name alone is (3.5 + n), where n is the number of characters in the name."

Since the name FNINVARS is 8 bytes, the difference should be 11.5 bytes, vs. the 12.5 I'm getting.

The same pattern is true for other VARs, so this isn't unique to this program.

I'm sure it's a simple thing, but anyone know why these are different?
(10-11-2017 06:50 PM)rprosperi Wrote: [ -> ]I'm sure it's a simple thing, but anyone know why these are different?

When given a global ID as an argument, the BYTES command on a rev. 2.15 50g calls the internal code for VARSIZE, a SysRPL command. VARSIZE is where the discrepancy comes in, as it very specifically adds a constant 9 nibbles (4.5 bytes) to the memory used by the characters of the global ID to sum up the final byte count. I'm not sure if other O/S versions are the same, but that's where the "4.5 + n chars" comes into play, at least on that system.

I would be inclined to call that a bug, as the size of a global identifier is definitely "3.5 + n chars". The only reason I can think of adding anything in addition to the global ID size would be if you wanted to include the stack pointer as well, but that would be an additional 2.5 bytes, not 1. So that wouldn't explain the difference.

For the curious, here's the code of the VARSIZE command (with some comments added). Even if you're not all that familiar with SysRPL, you can probably follow along with what it's doing:
   DUP                       ( DUPs the global ID given as the argument )
   @                         ( SysRPL version of RCL, which also returns TRUE if successful or FALSE if not )
   NOTcase SETNONEXTERR      ( essentially "raise non-existent error if RCL didn't work" )
   OCRC                      ( returns size, checksum )
   SWAPROT                   ( guess )
   ID>$                      ( converts the duplicated ID from above into a string )
   LEN$                      ( returns the length of the converted string in chars )
   #2*                       ( converts char count to nibbles used )
   #+                        ( adds char count nibbles to size of object )
   # 9                       ( System Binary 9 -- why 9 instead of 7?? )
   #+                        ( add the 9 to the accumulated size )
   UNCOERCE                  ( convert the System Binary size [in nibbles] to a real number )
   %2                        ( real 2 constant )
   %/                        ( divide by 2 to convert nibbles to bytes )
Both the 48SX and 48GX do the same thing, returning "4.5 + n chars" for a VAR whose name is n chars long.

Interestingly, both the 48SX Programmers Reference and 48GX AUR say:

"If the argument is a global name, then the size represents the name and its contents, while the checksum represents the contents only. The size of the name alone is (3.5 + 2 x n), where n is the number of characters in the name."

It seems unlikely that all these manuals are incorrect... presumably the older ones were corrected by the 50g AUR, yet that one does not agree with these simple observations either.

Ideas anyone?
Several years ago when Joe Horn shared the FNINVARS program, I was also looking for a similar tool to report which libraries a program is using. After some (!) attempts and much patience from Joe, I came up with the following, somewhat brute force program, FLIBS, to do this:


%%HP: T(3)A(R)F(.);
  THEN "Not a program object!" DOERR
    WHILE "
 " "
  { } SWAP
      DUPDUP "
29E20" POS DUP
      6. + DUP 2. + SUB
      ROT OVER "00" + H\->A B\->R R\->I \->STR + UNROT
29E20" SWAP + "
  3. DROPN

Note this program requires TOHEX (I believe written by Joe):


%%HP: T(3)A(R)F(.);
    END A\->H

which in turn requires DCOD, which I assume most folks have.

To use FLIBS to examine program PROG, recall your RPL program to the stack and run FLIBS;


The result is a list of the (decimal) library numbers utilized in the program.

The above dependency explanation is a perfect example of why such tools are so essential in RPL.

There almost has to be a better way to convert the format of the found library numbers for output, but in those early days of exploring RPL, I was pleased that even this ugly sequence worked OK.
Reference URL's