From comp.sys.handhelds Fri Feb 16 13:02:08 1990
Path: fauern!unido!mcsun!uunet!cs.utexas.edu!hellgate.utah.edu!ug.utah.edu!i-core!slack!pete
From: pete%slack.UUCP@cs.utah.edu (Pete Ashdown)
Newsgroups: comp.sys.handhelds
Subject: HPRead.c v1.3
Keywords: HPREAD
Message-ID: <1990Feb15.103847.16515@hellgate.utah.edu>
Date: 15 Feb 90 17:38:46 GMT
Lines: 602
Status: OR

Here is HPREAD v1.3 for all who have been requesting it.  It is Turbo C source
for the IBM.  I'll post the uuencoded compiled version in the next message for
people who don't have Turbo C.
---------------------------------->8 Cut Here 8<-----------------------------

/*

HPREAD
Copyright (C) 1990  Mark Adler  Pasadena, CA  All rights reserved.

This source file may be freely copied and distributed, so long as it
is not modified in any way.  No part of this program may be used in
any product for sale without the written permission of the author.

This program is user supported (shareware), which means that users
are expected to make a (modest) contribution of $5 to the author. 
The check or money order should be made out to Mark Adler, and sent
to:

        Mark Adler
        P.O. Box 60998
        Pasadena, CA 91116

The $5 entitles you to the sense of well-being that comes from
knowing that you have supported this sort of independent effort to
make your life easier, and that you are encouraging the continuing
enhancement of this program.  Feel free to send comments and
suggestions on HPREAD to the same address, whether or not you are
making the $5 contribution.

Version history -

1.0     13 Jan 1990     First public version.
1.1     14 Jan 1990     Improve error correction and correct and
                        improve the documentation.
1.2     22 Jan 1990     Defer decoding and error correction until all
                        data is received, unless the new /f option is
                        specified, in which case decode on the fly.
                        Count successfully corrected ("fixed") bytes.
                        Distinguish imbedded from trailing errors.
                        Disable interrupts during transfers, new /e
                        option enables.
                        Check compiler and memory model during compile.
1.3     31 Jan 1990     Optionally restore the timer count from the
                        real-time cmos clock (if an AT or greater) after
                        a transfer.

Thanks to Paul Dujmich and Steve Haehnichen for providing test
results on HPREAD, and to Paul for suggesting a schematic in the
documentation.


HPREAD reads data sent by infrared pulses from an HP calculator (such
as an HP-28S) to a Radio Shack $3.49 GP1U52X Infrared Receiver
(catalog #276-137).  The output pin of the receiver is connected to a
a bit of an input port on an IBM PC or compatible.  HPREAD then reads
from the specified port and bit and writes the received data to
stdout.  The data is terminated by a pause of more than three
seconds.  HPREAD also writes the number of bytes transferred and the
number of unrecoverable errors to stderr.  For example:

     C>hpread >foo
     1043 bytes transferred (17 fixed) with 0 errors

writes the file "foo" with the transferred data.  By default, HPREAD
converts any 0x04 or 0x0A characters that the HP sends into a new
line sequence (carriage return, line feed).  If the "/n" option is
specified, no translation of the data is performed.

By default, HPREAD assumes that the receiver is connected to the
parallel printer port's ERROR* line (pin 15 on the DB-25).  Some
parallel printers supply +5V power on one of the lines of the
printer-end connector.  For example, my printer (a C.Itoh 8510A)
provides +5V at 50 mA on pin 18 of the 36 pin Centronics connector
(NOT the DB-25).  This can truly minimize the external hardware for
the detector.  Just put a switch on the ERROR* line to the computer
to select either the printer's ERROR* line or the output of the
detector, and connect the power and ground of the detector to the
printer's ground and +5V lines.  (For this to work, of course, the
printer must be on.)  Schematic:

                               SPDT switch
     Printer (DB-25) pin 15 -----*      (used to go to port pin 15)
     Detector Vout (pin 1) ------*<---o------ Parallel port pin 15
     Detector GND (pin 3) ------------------- Parallel port pin 18
     Detector Vcc (pin 2) ------------------- Printer supplied +5v
     Metal case of detector ----------------- Detector GND (pin 3)

If an easy source of +5V is not available, then you only need three
more parts to supply it.  An AC adapter that puts out DC anywhere in
the range of +6V to +30V (whatever current it puts out is enough), a
0.047 uF or 0.1 uF capacitor, and a 7805 or 78L05 voltage regulator. 
You can get all of this from (you guessed it) Radio Shack.  (No, I do
not have stock in Radio Shack.  It's just it seems there are more of
them than McDonald's.)  Connect the output of the AC adapter to the
input of the voltage regulator with the capacitor across that (and
near the regulator).  Make sure to check the polarity of the AC
adapter---some put the positive lead and some put the negative lead
on the outside of the connector.  Connect the output of the regulator
to the detector's power and ground.  An output capacitor is not
needed, since the detector has a built in 5 uF capacitor for power
buffering.  Schematic:

                               SPDT switch
     Printer (DB-25) pin 15 -----*      (used to go to port pin 15)
     Detector Vout (pin 1) ------*<---o------ Parallel port pin 15
     Detector GND (pin 3) ------------------- Parallel port pin 18
     Adapter +DC--------|---Regulator In
              0.047 uF ===  Regulator Out---- Detector Vcc (pin 2)
     Adapter -DC--------|---Regulator GND---- Detector GND (pin 3)
     Metal case of detector ----------------- Detector GND (pin 3)

Wherever power comes from, be sure to connect the metal case of the
detector to ground to reduce noise in the detector.

If a different port or bit is used, then the port and bit mask (and
possibly an invert option) must be specified on the HPREAD command
line.  For example:

     C>hpread 22e2 1 /i >foo
     1043 bytes transferred (13 fixed) with 0 errors

reads the data from port 0x22e2, bit 0, with the input bit inverted.
Both the port and the mask must be specified in hexadecimal.  The bit
mask must be one of 1, 2, 4, 8, 10, 20, 40, or 80.  If there are
other operations necessary to initialize the port before it can be
used, then another program could be written to do the initialization,
or the operations could be added to this program in main() after
memory is allocated, and the program recompiled.

If a byte is received with no errors, or it is received with errors
and is correctable, then the byte is written to stdout and counted in
the bytes transferred.  If the byte required correction, then it is
also counted as a "fixed" byte.  The main use of the "fixed" count is
to judge the quality of the link.  Fixed bytes are almost certainly
good.

If a byte (or at least the illusion of start bits) is received, and
the data is in error and not correctable, then nothing is written to
stdout and the byte counts as an error.  If there are trailing
errors, i.e. errors with no good bytes that follow them, then
imbedded errors and trailing errors are counted separately.  If a
transfer results in no imbedded errors, but some trailing errors,
then the transfer may very well be good, since the trailing errors
might just be noise received while waiting for a silence of three
seconds.  For example:

519 bytes transferred (8 fixed) with 0 imbedded errors and 1 trailing error

HPREAD has been tested and works on 6 MHz 286 systems and on 8 MHz
8088 systems.  It is not known at this time whether this program will
work on 4.77 MHz 8088 systems or not.  The program utilizes the
system timer which runs at the same speed on all machines (1.193182
MHz), regardless of the processor's clock speed.  HPREAD should work
on any system faster than those mentioned above (for example, 8 MHz
8086 systems, 16 MHz 386 systems, 1000 GHz 786 systems, etc.).

There are two options for faster machines: /f (fast) does the data
decoding and error correction between bytes, and /e (enable) enables
interrupts between bytes.  /f reduces the memory requirements of the
program by 128K, and /e prevents the clock from losing (much) time by
allowing timer tick interrupts during the transfer.  If either option
is not appropriate for your machine, you will simply get errors
reported for the transfer.  Even with /e, you can still lose the
three seconds it takes to determine that the transmission is over.

If you have an AT compatible machine, then you can use the /c option
to restore the current clock from the real time battery backed-up
clock after the transfer is complete.  If /c is specified, but there
is an error reading the time from the real time clock (for example,
if it's an XT), then HPREAD will warn you that it did not set the
current clock:

     !warning: unable read the time from the real time clock

If you have an XT compatible machine with an add-on battery backed-up
clock, then that clock came with a program that sets the current
clock (typically executed from AUTOEXEC.BAT).  You can write a batch
file that executes HPREAD, and then executes the program to reset the
current clock.

If more than 32,768 (32K) bytes are sent, then only the first 32,768
bytes are written to stdout.

The command format and options can be displayed using the "/h" (help)
option.  If /h is specified, no other action is performed.

When used in a batch file, HPREAD returns the following errorlevels:

   0 - No error or /h specified.
   1 - Error in data, or data exceeded MAXFER (32,768) bytes.
   2 - Error writing data to stdout.
   3 - Could not allocate a MAXFER byte buffer, or if /f not specified,
       could not allocate a 4*MAXFER byte buffer in the far heap.
   4 - Invalid arguments.

This program was written to be compiled under Borland Turbo C 2.0
using the small or tiny models and register variables on.

*/



#ifndef __TURBOC__
#error Need Borland Turbo C to compile HPREAD
#endif
#if !defined(__SMALL__) && !defined(__TINY__)
#error Must use small or tiny models to compile HPREAD
#endif



char help[] = "HPREAD 1.3  31 Jan 1990\n\
Copyright (C) 1990  Mark Adler  Pasadena, CA  All rights reserved\n\
\n\
HPREAD reads data sent by an HP calculator to an infrared receiver\n\
connected to one bit of an input port.  The data is written to\n\
stdout, and statistics are sent to stderr.\n\
\n\
Usage:\n\
   hpread               - read from printer port ERROR* line (pin 15)\n\
   hpread PORT          - read from hexadecimal I/O port PORT, bit 3\n\
   hpread PORT MASK     - use hexadecimal mask instead of bit 3\n\
\n\
Options (can be combined after a single slash):\n\
   /i                   - invert the sense of the detector bit\n\
   /n                   - no translation of data\n\
   /c                   - restore the current clock from the real time\n\
                          battery backed-up clock\n\
   /e                   - enable interrupts between bytes\n\
   /f                   - fast machine---do correction on the fly\n\
   /h                   - show this help message\n";



#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
#include <dos.h>
#include <io.h>
#include <fcntl.h>

#define MAXFER 32768u   /* Maximum bytes in one transfer */



/* Globals */
unsigned fixed;         /* Count of bytes fixed by error correction */
int irport;             /* The (byte) port that the IR detector is
                           connected to. */
char irmask;            /* Mask for the bit the IR detector is connected
                           to (one of the following: 1, 2, 4, 8, 0x10,
                           0x20, 0x40, or 0x80). */
char irinvt;            /* 0xff if the bit is low when the detector is
                           illuminated by infrared, 0 if the bit is high
                           when illuminated. */
char introk = 0;        /* True if interrupts allowed between bytes */
char nltolf = 1;        /* True causes 0x04 to 0x0A translation on read
                           and 0x0A to 0x0D,0x0A translation on write */
char later = 1;         /* True defers decoding after transmission */
char clock = 0;         /* True restores the current clock from the real
                           time battery backed-up cmos clock */



long hpread(void)
/* Read a byte frame from the IR port.  Interrupts should be disabled
   when this routine is called.  The low 27 bits of the returned value
   is set to 27 ones and zeros for the occurence or not of pulses in the
   27 half-bit times.  If no pulses occur for three seconds, then zero
   is returned.

   Macros used:

   IRON - expression that is true if IR is on
   TIMR - used by wait to get the high byte of the tiny tick count
   WAIT - wait one "tick" and increment k
   LOW  - wait until IR goes off while counting ticks
   HIGH - wait until IR goes on, counting ticks and rejecting noise
*/
{
  register int j, k;
  int i;
  long h;
  unsigned char *p, t[53];

  #define IRON ((inportb(irport) ^ irinvt) & irmask)
  #define TIMR {outportb(67,0);inportb(64);_AX=inportb(64);}
  #define WAIT {do TIMR while(j==_AX); j=_AX; k++;}
  #define LOW(d) {do{WAIT if(!IRON)break;}while(k<d);}
  #define HIGH(d) {do{WAIT if(IRON){WAIT if(IRON)break;}}while(k<d);}


  /* Wait up to three seconds for a pulse */
  #define TIMEOUT 27965         /* ((14318180/12)/128)*3 */
  k = j = 0;                    /* Initial j doesn't really matter */
  LOW(TIMEOUT)
  HIGH(TIMEOUT)
  if (k >= TIMEOUT)
    return 0;


  /* Read pulses until 25 or 26 half-bit times have passed, or more than
     ten half-bit times have passed with no pulses.
     Mystery numbers (S=111,1=10,0=01,X=00,Y=11):
     k < 11 --- for worst case SYY10, SY1X0, or S1XX0 cases, all of
                whose high+low times are ten half-bit times.
     LOW(34) --- for worst case SYY1 = 8 high half-bit times,
     HIGH(42) --- for worst case ten total half-bit times (see k < 11),
     LOW(6) --- since last pulse should be less than one half-bit time.
  */
  p = t;                        /* Where to put times */
  i = 0;                        /* Half-bit times so far */
  do {                          /* Do loop for each high+low piece */
    k = 0;                      /* Initialize tick count */
    LOW(34)                     /* Wait for pulse to go low */
    *p++ = k<2 ? 1 : (k+2)>>2;  /* Time high rounded to half-bits */
    HIGH(42)                    /* Wait for start of next pulse */
    k++;  k++;  k >>= 2;        /* Time high+low rounded */
    *p++ = k;
    i += k;                     /* Update total time in half-bits */
  } while (k < 11 && i < 25);   /* Do until pause or enough data */
  if (k < 11 && i < 27)         /* If got a final bit, then put it in */
  {
    *p++ = 1;
    *p++ = 0;                   /* (This is fixed by next statement) */
  }
  p[-1] += 27-i;                /* Adjust last entry to make total=27 */
  *p = 0;                       /* Terminate list */
  LOW(6)                        /* Wait for last pulse to end */


  /* Copy data into half-bit time slots */
  p = t;
  h = 0;
  do {
    j = *p++;                   /* Length of pulse in half-bit times */
    k = *p++;                   /* Time from this pulse to next one */
    do {
      h <<= 1;
      if (j)                    /* One's for pulse, zero's for quiet */
      {
        *((char *)&h) |= 1;     /* (Trick compiler into optimizing) */
        j--;
      }
    } while (--k);
  } while (*p);


  /* Return the half-bit time slots (can't be zero) */
  return h;
}



int hpfix(long h)
/* Do all possible error corrections on the data in h.  Return either
   the corrected byte, or -1 if there were uncorrectable errors.  The
   low 24 bits of h is assumed to be 24 half-bit times with ones and
   zeros for pulses or not in each bit.  This is the h returned by
   hpread(), but note that the three start bits are ignored.  The global
   'fixed' is incremented if the byte is good, but required correction.
*/
{
  register int e, j;
  int d, i;
  char g;

  /* Parity bits */
  #define H1 0x878
  #define H2 0x4e6
  #define H3 0x2d5
  #define H4 0x18b

  /* Macro to get the parity of a word (zero if even, non-zero if odd.
     The instructions emitted are: xor al,ah // jpo $+2 // sub ax,ax. */
  #define parity(w) (_AX=w,__emit__(0x30,0xe0,0x7b,0x02,0x29,0xc0),_AX)


  /* Convert h into a data word and an erasure word */
  d = e = 0;                    /* d is the data, e the erasures */
  for (j = 1; j < 4096; j<<=1)  /* Examine the 12 full-bit times */
  {
    g = (char)h;
    h >>= 1;
    if (((char)h ^ g) & 1)      /* If it is 10 or 01, */
    {                           /*  then it's a good bit (10 is 1), */
      if ((char)h & 1)
        d |= j;
    }
    else
      e |= j;                   /*  otherwise, it is an erasure. */
    h >>= 1;
  }


  /* Correct as many errors as possible */
  g = e != 0;                   /* Remember if there were errors */
  while (e)
  {
    i = e;                      /* Set i to the erasures to be fixed */
    do {
      j = ((i-1) & i) ^ i;      /* Make j the first one in i */
      if (((H1 ^ j) & e) == 0)  /* If we can, fix j using H1 */
        {if (parity(H1 & d)) d |= j; e ^= j; break;}
      if (((H2 ^ j) & e) == 0)  /* If we can, fix j using H2 */
        {if (parity(H2 & d)) d |= j; e ^= j; break;}
      if (((H3 ^ j) & e) == 0)  /* If we can, fix j using H3 */
        {if (parity(H3 & d)) d |= j; e ^= j; break;}
      if (((H4 ^ j) & e) == 0)  /* If we can, fix j using H4 */
        {if (parity(H4 & d)) d |= j; e ^= j; break;}
      i ^= j;                   /* None worked, try next bit */
    } while (i);
    if (i == 0)                 /* If no bits corrected, give up */
      break;
  }


  /* If there are still erasures or parity errors, then return error */
  if (e || parity(H1 & d) || parity(H2 & d) || parity(H3 & d) ||
      parity(H4 & d))
    return -1;


  /* Got a good byte---return it */
  if (g)
    fixed++;                    /* If had errors, update fixed */
  return d & 0xff;              /* Strip parity bits */
}



void err(int n, char *m)
/* Exit with return code n after printing message m to stderr */
{
  fputs(m, stderr);
  exit(n);
}



void main(int argc, char *argv[])
/* Read a stream of bytes from the HP and write them to stdout.  See
   comments above for the command format. */
{
  register int r;
  register unsigned i;
  unsigned j, e, t;
  long h;
  char *b;
  long huge *d, huge *p;
  union REGS g;


  /* Initialize irport to the first printer's status port, set irmask to
     the ERROR* line (pin 15 on the DB-25), and the bit is input as
     presented, so it must be inverted since the detector output is
     active low. */
  irport = *((int far *)MK_FP(0, 0x408)) + 1;
  irmask = 8;
  irinvt = 0xff;


  /* Process arguments */
  j = 0;                        /* Count of non-option arguments */
  for (i = 1; i < argc; i++)
    if (argv[i][0] != '/')      /* Non-option */
      if (j == 0)               /* First non-option arg */
        if (sscanf(argv[i], "%x", &irport) != 1)
          err(4, "?invalid argument---use HPREAD /H for help\n");
        else
          j++;
      else if (j == 1)          /* Second non-option arg */
        if (sscanf(argv[i], "%x", &e) != 1)
          err(4, "?invalid argument---use HPREAD /H for help\n");
        else
        {
          irmask = (char) e;
          j++;
        }
      else                      /* Third non-option arg */
        err(4, "?invalid argument---use HPREAD /H for help\n");
    else                        /* Option(s) */
      for (r = 1; argv[i][r]; r++)
        switch (argv[i][r] & 0x5f)
        {
        case 'C': clock = 1; break;
        case 'E': introk = 1; break;
        case 'F': later = 0; break;
        case 'H': err(0, help); break;
        case 'I': irinvt = 0; break;
        case 'N': nltolf = 0; break;
        default:
          err(4, "?invalid argument---use HPREAD /H for help\n");
        }
        

  /* Allocate memory for data */
  if ((b = malloc(MAXFER)) == NULL ||
      (later && (p = d = farcalloc(MAXFER, sizeof(long))) == NULL))
    err(3, "!not enough memory---aborting HPREAD\n");


  /* Read bytes until timeout or MAXFER bytes exceeded */
  t = e = i = 0;
  while (i < MAXFER)
  {
    disable();                  /* Disable interrupts during hpread() */
    if ((h = hpread()) == 0)    /* Read a frame---if timeout, */
      break;                    /*  then done. */
    if (introk)                 /* If allowed, enable interrupts */
      enable();                 /*  between bytes. */
    if (later)                  /* If decoding deferred, */
    {                           /*  just save the half-bit pulses */
      *p++ = h;
      i++;
    }
    else                        /*  else, do the work between bytes */
      if ((r = hpfix(h)) == -1) /* Try to correct errors, if any */
        t++;                    /* If failure, skip the byte and */
      else                      /*  update the trailing error count. */
      {
        b[i++] = nltolf && r==4 ? 10 : r;       /* Save good byte */
        e += t;                 /* Update the main error count and */
        t = 0;                  /*  reset the trailing error count */
      }
  }
  enable();                     /* Re-enable interrupts */


  /* Restore the timer count from the real-time cmos clock (if any).
     Uses the 0x1a interrupt with AH=2 to get the cmos clock time.  If
     the machine has an XT compatible BIOS (and therefore, no AT
     compatible clock), then AH will come back as 1.  If the machine is
     AT compatible, then AH will come back as 0 and carry will be either
     clear if it got the time, or set if there was an error reading the
     clock.  It is necessary to use emitted code here to control the
     carry flag before doing the interrupt. */
  if (clock)
  {
    _AH = 2;
    /* Code emitted is: clc, int 1ah, sbb al,al */
    __emit__(0xf8,0xcd,0x1a,0x18,0xc0);
    if (_AX == 0)
    {
      /* Compute the new timer value (18.207 ticks = 1 second) */
      j = _CX;
      r = _DH;
      #define bcd(a) (((a) & 0x0f) + 10*(((a) >> 4) & 0x0f))
      h = ((bcd(r) + 60L*(bcd(j) + 60L*bcd(j >> 8)))*18207+500)/1000;

      /* Set the new timer value */
      g.x.dx = (unsigned int) h;
      g.x.cx = (unsigned int) (h >> 16);
      g.h.ah = 1;
      int86(0x1a, &g, &g);
    }
    else
      fputs("!warning: unable read the time from the real time clock\n",
            stderr);
  }


  /* If deferred, then do the decoding and error correction */
  if (later)
  {
    p = d;
    j = 0;
    for (; i; i--)
      if ((r = hpfix(*p++)) == -1)      /* Try to correct errors */
        t++;                    /* If failure, skip the byte and */
      else                      /*  update the trailing error count. */
      {
        b[j++] = nltolf && r==4 ? 10 : r;       /* Save good byte */
        e += t;                 /* Update the main error count and */
        t = 0;                  /*  reset the trailing error count */
      }
    i = j;
  }


  /* Summarize activity */
  fprintf(stderr,
    "%u byte%s transferred (%u fixed) with %u %serror%s",
    i, i==1 ? "" : "s", fixed,
    e, t ? "imbedded " : "", e==1 ? "" : "s");
  if (t)
    fprintf(stderr, " and %u trailing error%s\n",
            t, t==1 ? "" : "s");
  putc('\n', stderr);


  /* Write data to stdout */
  if (!nltolf)                  /* If no translation, write in binary */
    setmode(stdout->fd, O_BINARY);
  if (fwrite(b, i, 1, stdout) != 1)
    err(2, "?error writing transferred data to stdout\n");
  if (e || i == MAXFER)
    exit(1);
  else
    exit(0);
}

From comp.sys.handhelds Thu Mar 15 15:35:43 1990
Path: fauern!unido!mcsun!uunet!snorkelwacker!bloom-beacon!bloom-beacon!athena.mit.edu!chekmate
From: chekmate@athena.mit.edu (Adam Kao)
Newsgroups: comp.sys.handhelds
Subject: routines to enter HP48 machine language programs
Message-ID: <1990Mar14.183918.15326@athena.mit.edu>
Date: 14 Mar 90 18:39:18 GMT
Sender: news@athena.mit.edu (News system)
Reply-To: chekmate@athena.mit.edu (Adam Kao)
Organization: Massachusetts Institute of Technology
Lines: 242
Status: OR

=====================================================================

NOTE1: This is being posted for me by a friend, since I have no usenet
       or email access right now.  If you want to respond to something
       in this article, you'll have to use (gasp) regular mail.  Hurry
       up while it's still $.25.


NOTE2: All of the SYSEVAL addresses contained in these routines are
       valid for the HP48SX Version A only.


In a previous article, Alonzo Gariepy posted information on using the 
memory scanning utility built into the HP48 to enter machine language
programs.  The three routines below provide a similar capability, without
having to use the memory scanner.  They are adapted from routines that
I have been using on the HP28S.  The main routine, STR->OBJ, takes a string
of hex digits and returns the object whose representation is those digits.
This can be used to create just about anything you want, including 
machine language routines.  Some examples are shown below.

I have provided a little documentation on the SYSEVALs used, but I am
assuming some familiarity with how HP28/HP48 objects are represented, 
and with the machine code of the Saturn CPU.


Dave Kaffine
33 Agassiz Ave.
Belmont, MA  02178
(617) 484-3393


==================================================================


RVRS  [2022h]  75.5 bytes    ; Reverses the characters in a string

<<   -> s 
     << ""                           ; Start with empty string on stack
        s SIZE 1 FOR x               ; Loop from end to beginning
           s x x SUB +               ;  and add each character
        -1 STEP
     >>
>>


SYSRCL  [6E80h]  54 bytes
                            ; Given an address (as a binary integer), 
                            ;   puts the object at that address
                            ;   on the stack without evaluating it.
                            ;   Can also be used with other data types - see
                            ;   detailed description below.
                            ;   NOTE: For the most part, this should not be
                            ;         dangerous until you try to do something
                            ;         with the recalled item.

<< #4003h SYSEVAL              ; <2h>  (short integer - prolog 02911)
   #56B6h SYSEVAL              ; described below
   DROP                        ; DROPs boolean value
>>

The routine at 056B6 works as follows:

    2:  COMP    ==>     2: Object     or    
    1:  <Nh>            1: TRUE              1: FALSE

The routine ignores the type of the object in level 2.  It assumes that
COMP consists of a series of objects, one after another (e.g. a list).
Each list object either consists of a known prolog and the associated data for
that object type, or is a 5-nibble address that is assumed to point to
some data object.  The routine locates the Nth object and puts it on the
stack as follows: If the Nth object in the list starts with a prolog, a
pointer to the object within the list is put on the stack.  If the Nth
object in the list is an address pointing to an actual object, that address
is copied to the stack.  If N is out of range, a FALSE value is put on the
stack, otherwise a TRUE value is put on the stack (FALSE and TRUE are
special objects used by internal routines.  They are displayed as 
"External").

Some notes:  This routine works well with lists, but since the prolog of
the level 2 object is not checked, it gives interesting results with other
data types.  For example, with a binary integer argument:

             Binary integer                      <-- Increasing addresses
           MSB-------------LSB   length  prolog (ignored)
           b bbbbb bbbbb aaaaa   00015   02A4E   <-- Level 2
                          \       \      
                           \       \-- 1st object
                            \
                             \-- 2nd object (interpreted as an address
                                  unless aaaaa = known prolog)

So, if the level one argument has the value 2 (as in the SYSRCL routine),
and the level 2 argument is # aaaaah, the address aaaaa will be put on the
stack, which is the same as RCLing the object located at address aaaaa.

(BTW,  #18CEAh SYSEVAL   converts a real number to a short integer type, and
       #18DBFh SYSEVAL   converts the other way)


Example using SYSRCL:

       #1AB67h  SYSRCL         ==>              +      




STR->OBJ  [C2h]  169 bytes 
                      ;  STRing to OBJect :  This takes a string that is
                      ;    the sequence of nibbles that represent an object
                      ;    you want to create, and translates it into
                      ;    a new string that, when stored in memory,
                      ;    contains a nibble sequence that matches the digits
                      ;    in the original string.  It then uses SYSRCL
                      ;    (see explanation of how that works above,
                      ;    and see additional notes below) to bring the
                      ;    desired object to the stack.

<< RCLF SWAP 64 STWS
   -> s
       << ""                          ; Start with empty string
          1 s SIZE FOR x              ; Loop through string by pairs of
              "#"                     ;   characters
              s x DUP 1 + SUB         ; Get pair of digits (single digit
              RVRS                    ;   at end handled correctly)
              + "h" + OBJ->           ; Swap order, make binary integer
              B->R CHR +              ;  make into character and append
          2 STEP                      ; Loop by 2
       >>
    'obj' STO                         ; Store result so it won't move
    obj SYSRCL                        ; RCL desired object to stack
    NEWOB                             ; Make it a private copy
    SWAP STOF                         ; Clean up
>>

More notes about the routine at 056B6:

This time we're calling it with a "string" as the composite type.
Let's assume the string starts at address sssss.
                                          
      String (constructed to look like a program)
                           5th char    1st 
                             |           |  length    String prolog
      ... xx xx xx xx xx xx 23 61 E0 2D 9D  LLLLL     02A2C : sssss
                                    \       \
                                     \       \-- Object 1
                                      \
                                       \-- Object 2 - starts with 02D9D,
                                           the prolog for a program, so
                                           object consists of entire
                                           program.

SYSRCL  will RCL the program by placing the address (sssss+10) on the
stack.  Unfortunately, this address is not a 'good' address, since it
doesn't point to a 'real' object, it points inside of an object that is not
normally considered a composite type.  This means that if the string gets
moved (e.g. as a result of garbage collection), the address on the stack
will NOT be updated properly!!  That is the reason STR->P stores the
string in the global variable obj first (it must be a global variable - local
variables do not make copies of their contents) so its position won't be
affected by garbage collection.  After calling SYSRCL, NEWOB is used to 
make a separate copy of the item on the stack, so that the string it was 
derived from can be deleted safely.  Note that this program does not depend
upon being in the HOME directory - it does create one global variable called
'obj', but it doesn't matter where in memory 'obj' gets stored.



Here are some examples of the above routines in use:


Start with a simple, relatively safe example:

      Keystrokes                            Results
    -------------------------------------------------------
    "D9D20E163276BA193632B2130"       ==>   "..."
    DUP  BYTES                        ==>   #A0BDh 30
    DROP2                             ==>   "..."
    STR->OBJ                          ==>   <<  +  >>

Try it out - see if it's real.

    3 5 ROT                           ==>   3 5 << + >>
    EVAL                              ==>   8

!!!
          


Now for a more complicated example:

PEEK  [A1BCh]  50 bytes

      1: # aaaaah      ==>       1: # ddddddddddddddddh

      dddddddddddddddd is 16 nibbles of data from address aaaaa.
      The least significant nibble of data is from address aaaaa,
      the most significant is from aaaaa + F.


    D9D20                       ; Begin program
    E1632                       ; << 
      BB691                     ;  B->R  - make sure arg is binary integer,
      B9691                     ;  R->B  - and force new storage for it.
      CCD20                     ;  In-line code prolog
        03000                   ;  48 nibbles (includes these 5 nibbles)
          147      C=DAT1  A    ;    C -> level 1 object
          137      CD1EX        ;    D1 -> level 1 object, 
          06       RSTK=C       ;      save old D1 on stack
          179      D1=D1+  10   ;    D1 -> data of lvl 1 binary integer
          147      C=DAT1  A    ;    C = 5 nibs from binary (addr to PEEK)
          137      CD1EX        ;    D1 = PEEK addr, C -> lvl 1 data area
          15BF     A=DAT1  16   ;    peek 16 nibs into A
          137      CD1EX        ;    D1 -> lvl 1 data area
          159F     DAT1=A  16   ;    Replace binary data with peeked data
          07       C=RSTK       ;    Get old D1
          137      CD1EX        ;    and restore
          142      A=DAT0  A    ;    End every
          164      D0=D0+  5    ;      routine
          808C     PC=(A)       ;        this way.
    93632                       ; >>
    B2130                       ; End program

To enter this, do the following:
    "D9D20E1632BB691B                    ; Direct copy of sequence of
     9691CCD200300014                    ; nibbles above (NOTE: Do not
     7137061791471371                    ; put any extra characters in - 
     5BF137159F071371                    ; there are no spaces or newline
     42164808C93632B2                    ; characters)
     130"
     DUP  BYTES                          ; ==>  #1412h, 88
     DROP2
     STR->OBJ                            ; ==>  << B->R  R->B  Code >>
     'PEEK'    STO                       ;
     'PEEK'    BYTES                     ; ==>  #A1BCh, 50


Now test it out:
     #0  PEEK                ==>         # 8001FDAD801B9632h


That's all for now.  Enjoy!

From comp.sys.handhelds Mon Mar 19 10:56:09 1990
Path: fauern!unido!mcsun!uunet!microsoft!alonzo
From: alonzo@microsoft.UUCP (Alonzo GARIEPY)
Newsgroups: comp.sys.handhelds
Subject: HP 48: machine code
Message-ID: <53609@microsoft.UUCP>
Date: 16 Mar 90 21:40:48 GMT
Reply-To: alonzo@microsoft.UUCP (Alonzo GARIEPY)
Organization: Microsoft Corp., Redmond WA
Lines: 156
Status: OR

The biggest problem with using the memory scanner to enter machine
code is that it can be difficult to find the correct location.
Unlike the HP 28, this first variable has no fixed position.

	*	*	*	*	*

A BETTER WAY TO ENTER MACHINE CODE 

Here is an HP 48 version of Rick Grevelle's scheme for creating CODE 
objects.  Note that these particular SYSEVAL addresses may not work 
on future HP 48 rom revisions (but the new ones will be easy to find 
when the time comes).

Below I have reproduced Rick's original text modified to work on the
HP 28.

------------------------------------------------------------------------

Alonzo,
      I have found the solution to the code problem. You can now
code quickly and painlessly with less chance of error by using a
machine subroutine from the ROM. It allows for easy documentation
of user written machine programs and eleminates the problem of check
sums not being able to differentiate between system objects. The ROM
address of the machine routine that allows you to do this is [#5193h].
According to [Alonzo's] ROM map: [05193]  +_1string2string. This is a bit
over simplified in that the routine will allow binary integers to be
used as well as strings. I discovered that the routine works by using
the prolog of the object in level 1 to determine the the object type
after the addition. What this means is, if level 2 contains a binary
integer and level 1 a null string, or any string, the prolog for the
binary integer [#2A4Eh] is discarded for that of the string [#2A2Ch].
Here I will use PIG as an example. I think you'll agree that there is
no contest between using this approach to enter and run machine programs
and any of the other previous ones.

Enter PIG as follows:  PIGS  [7243]

                      { #3012310003B02DCCh
                        #1631641961031341h
                        #3117451961031765h
                        #C808461241231h  }

Now you are ready to enter the program that will turn the binary
integers into executable form.

           ->SYS  [6453] 
           <<  
	      " "  +  LIST->  2  SWAP      ; Intialize null string
              START #5193h  SYSEVAL        ; Begin code loop
              NEXT  #4003h  SYSEVAL        ; End loop, set pointer
              #56B6h SYSEVAL DROP          ; End program, get object
	   >> 

Rick Grevelle
------------------------------------------------------------------------

Rick's example PIG does no error checking, so it is a little too dangerous.
Applying ->SYS to Dave Kaffine's PEEK, you would use the array:

PEEKS  [7619]

{ #B196BB2361E02D9D
  #410003002DCC1969
  #1731741971607317
  #173170F951731FB5
  #2B23639C80846124
  #031
}

PEEKS ->SYS 'PEEK' STO

gives you

PEEK  [A1BC]
<< B->R R->B Code >>

	*	*	*	*	*

EASY ENTRY OF HEXADECIMAL INTEGER ARRAYS

1)  First I'll show you how to enter hexadecimal integers more easily.

Create the program HINT in your HOME directory.  *a designates the
greek alpha character (alpha-shift blue-shift A).

	HINT  [F654] 
	<<
	    "" { "# h" *a V 3 }
	    IFERR INPUT OBJ->
	    THEN DROP DROP END
	>>

Run this program and you'll see it makes entering hex integers easy.
The IFERR stuff allows you press ON to abort entry without getting
extraneous stuff on the stack.

To make this program really useful, bind it to the EEX key (or any
other key) in USER mode.  Since I rarely use exponential notation,
the EEX key is ideal for me.  To do the binding, type:

	'HINT' 53.1 ASN

To enter user mode type:

	gold-shift USR

Now, to enter a binary number, just press EEX first.  It will put
the # h on the command line, put you in alpha entry mode and position
the cursor.  Press ENTER when you have entered the number.

2)  Now, here's how to enter binary arrays

Enter each binary number on the stack.  For the PEEK program, you
would type the first integer with

	EEX B 1 9 6 B B 2 3 6 1 E 0 2 D 9 D ENTER

Type the remaining integers the same way.

Once you have them all on the stack, press up arrow.  Continue to 
press up arrow until you reach the first integer (#B196BB2361E02D9Dh).
Now press ->LIST.  The stack editor will package the 6 integers on
the stack into a LIST.  Now type

	'PEEKS' STO

Check that you have typed everything correctly with:

	'PEEKS' BYTES

The answer should be:  [7619]

	*	*	*	*	*

Don't get frustrated by all the ways of entering machine code.  The
important thing is to understand what is going on in each case.  My
HP 28 processor notes can help with this.  These methods are mainly
for those who want to program in machine code.  If you just want to
use such programs, your best bet is to load them into your HP 48 in
binary mode using the serial port.  Following is a uuencoded version
of the PEEK program above.  

-----------------------cut here------------------------------------
begin 600 peek
M2%!(4#0X+4&=+>!A([N6L6D9S"T``P!!%W-@<1ET,1>U'W-1^7`Q%R1AA("<
%8R,K,0`X
`
end
-----------------------and here------------------------------------

In the next posting is a SYSEVAL based PEEK that doesn't even need
machine code.

Alonzo Gariepy
alonzo@microsoft

From comp.sys.handhelds Fri Mar 30 14:03:55 1990
Path: fauern!ira.uka.de!sol.ctr.columbia.edu!lll-winken!uunet!jarthur!spectre.ccsf.caltech.edu!tybalt.caltech.edu!madler
From: madler@tybalt.caltech.edu (Mark Adler)
Newsgroups: comp.sys.handhelds
Subject: Shorter APPT, APDIR (this is a LONG message)
Message-ID: <1990Mar29.201324.3810@spectre.ccsf.caltech.edu>
Date: 29 Mar 90 20:13:24 GMT
Sender: news@spectre.ccsf.caltech.edu
Organization: California Institute of Technology, Pasadena
Lines: 610
Status: OR

After getting the Appointment application (APPT and APDIR) from the
HP bulletin board and kermiting it over to my calculator, I found
that I didn't have much memory left.  With a few other things loaded
in as well (the stopwatch, some of my own things), I started thinking
about buying more memory for the thing.  Then I looked at the
programs in APDIR, and decided it was really a ploy to make me get
more memory.  It almost worked too!

Without changing the functionality whatsoever, I reduced the size of
APDIR from 13714 bytes to 8173.5 bytes.  I did this by rewriting
parts of the programs, putting them all in one directory, and
combining some programs (and even fixing a bug or two here and
there).  It is even a little faster now.  The thing really deserves a
total rewrite, and I estimate it could be made faster and more
functional in less than 5 or 6K bytes.  But, alas, I don't have time
for that. Anyway, here is the shortened version, first APPT and then
APDIR.

Mark Adler
madler@tybalt.caltech.edu

%%HP: T(3)A(R)F(.);
@ Store as 'APPT'
@ 'APPT' BYTES should give CRC #5470h, and length 83.5.
\<<
  APDIR
  RCLF 'flags' STO MYFLGS STOF
  CNTL
  flags STOF HOME 2 MENU
\>>

%%HP: T(3)A(R)F(.);
@ Store as 'APDIR'
@ 'APDIR' BYTES should give CRC #B8C7h, and length 8173.5.
@ Note that if APPT is run, APDIR changes.

DIR

CNTL
@ Main function---called by APPT (not in APDIR)
@ Setup and process keystrokes at top (calendar) level.
\<<
  DEPTH \->LIST 'STACK' STO             @ save stack
  DATE 'DSTR' STO                       @ set date to current date
  REFRESH                               @ put up calendar
  DO                                    @ process keys until ...
    -1 WAIT DOKEY
  UNTIL
    IP 16 ==                            @  menu key F.
  END
  DROP2 STACK OBJ\-> DROP               @ restore stack
\>>


REFRESH
@ called by CNTL, DOKEY (5)
@ Put up calendar display and menu.
\<<
  @ SETUP
  { "FIND" "GOTO" "ADD" "UPLD" "APPTS" "Stop" } MENU DSTR SETUP2
  MNTH LCD\->
  @ HLIT
  Dy ADR + 7 / FP 7 * 3 * 6 * 1 - 'COL' STO
  Dy ADR + 7 / IP 1 + 8 * 1 - 'ROW' STO
  DUP COL R\->B ROW R\->B 2 \->LIST COL 12 + R\->B ROW 8 + R\->B
  2 \->LIST SUB NEG COL R\->B ROW R\->B 2 \->LIST SWAP REPL
  DUP \->LCD
\>>


DOKEY
@ called by CNTL
@ Execute the keystroke on the stack for the calendar menu, update DSTR.
\<<
  { 11.1 { DROP SRCMAIN REFRESH 11.1 }
    12.1 { DROP GOTO REFRESH 12.1 }
    13.1 { CLEAR DSTR TIME 100 * IP 100 / "" 0 4 \->LIST
           BEG 1 CF REFRESH 13.1 }
    14.1 { DROP OVERALL REFRESH 14.1 }
    15.1 { APPTS REFRESH 15.1 }
    36.1 DYPL 34.1 DYMIN 35.1 NWEEK 25.1 PWEEK
    95.1 MOPL 85.1 MOMIN 95.2 YRPLS 85.2 YRMIN
    91.3 OFF
  }
  DUP2 SWAP POS
  IF DUP THEN
    1 + GET EVAL
  ELSE
    DROP2
  END
  Yr OBJ\-> 10000 / Dy + 100 / Mo + 'DSTR' STO
\>>


SRCMAIN
@ called by DOKEY
@ FIND key: find an appointment and go to that date.
\<<
  @ GTSTR
  DROP2 { } MENU "Type search string\010Then press ENTER."  SRCSTR
  \Ga 2 \->LIST INPUT 'SRCSTR' STO
  CLLCD "Searching" 2 DISP
  @ GTALN
  DSTR FINDALARM 'NXTALRM' STO
  @ SRCALRM
  0 'ENDALRM' STO 0 'FNDALRM' STO
  DO
    NXTALRM
    IFERR RCLALARM THEN
      1 'ENDALRM' STO
    ELSE
      @ CHKALRM
      1 GETI TIME TSTR 1 12 SUB 4 DISP DROP 3 GETI SWAP DROP
      DUP TYPE 2 ==
      IF THEN
        SRCSTR POS
      ELSE
        DROP 0
      END
      IF THEN
        1 'FNDALRM' STO
      ELSE
        DROP
      END
    END
    NXTALRM 1 + 'NXTALRM' STO
  UNTIL
    ENDALRM FNDALRM OR
  END
  @ ENDPROC
  IF ENDALRM THEN
    CLEAR CLLCD "No appointment found\010\010Press a top row key." 3 DISP
    -1 WAIT DROP
  ELSE
    1 GET 'DSTR' STO
  END
\>>


GOTO
@ called by DOKEY
@ GOTO key: goto the entered date.
\<<
  DROP2 { } MENU "Type date (MM.DDYYYY):\010Then press ENTER."
  DSTR \->STR -1 2 \->LIST INPUT OBJ\-> 'DSTR' STO
\>>


YRMIN
@ called by DOKEY
@ left - key: go back one year.
\<<
  ROT DROP2 DSTR .000001 - RDOSCR
\>>

YRPLS
@ called by DOKEY
@ left + key: go forward one year.
\<<
  ROT DROP2 DSTR .000001 + RDOSCR
\>>

MOMIN
@ called by DOKEY
@ - key: go back one month.
\<<
  ROT DROP2 DSTR DUP IP 1 - SWAP 100 * FP 100 / .01 + + DUP
  IF 1 < THEN
    .000001 - 12 +
  END
  RDOSCR
\>>

MOPL
@ called by DOKEY
@ + key: go forward one month.
\<<
  ROT DROP2 DSTR DUP IP 1 + SWAP 100 * FP 100 / .01 + + DUP
  IF 13 > THEN FP
    1.000001 +
  END
  RDOSCR
\>>

PWEEK
@ called by DOKEY
@ down key: go forward one week (but stay in month).
\<<
  IF Dy 7 > THEN
    SWAP HLIT2 Dy 7 - 'Dy' STO RC HLIT2 DUP \->LCD SWAP
  ELSE
    400 .2 BEEP
  END
\>>

NWEEK
@ called by DOKEY
@ up key: go back one week (but stay in month).
\<<
  IF Dy DSTR LMNTH 6 - < THEN
    SWAP HLIT2 7 Dy + 'Dy' STO RC HLIT2 DUP \->LCD SWAP
  ELSE
    400 .2 BEEP
  END
\>>

DYMIN
@ called by DOKEY
@ left key: go back one day (but stay in month).
\<<
  IF Dy 1 > THEN
    SWAP HLIT2 Dy 1 - 'Dy' STO RC HLIT2 DUP \->LCD SWAP
  ELSE
    400 .2 BEEP
  END
\>>

DYPL
@ called by DOKEY
@ right key: go forward one day (but stay in month).
\<<
  IF Dy DSTR LMNTH < THEN
    SWAP HLIT2 1 Dy + 'Dy' STO RC HLIT2 DUP \->LCD SWAP
  ELSE
    400 .2 BEEP
  END
\>>


OVERALL
@ called by DOKEY
@ UPLD key: dump a range of appointments to I/O device.
\<<
  @ GDATES
  "Enter Start Date\010(MM.DDYYYY)\010Then press ENTER" DSTR
  \->STR -1 2 \->LIST INPUT OBJ\-> 'SDAT' STO
  "Enter End Date\010(MM.DDYYYY)\010Then press ENTER" DSTR
  \->STR -1 2 \->LIST INPUT OBJ\-> 'ENDAT' STO
  "\010"
  @ RAPPTS
  SDAT FINDALARM DUP 'NXTALRM' STO
  SDAT DFLIP 'SDAT' STO
  ENDAT DFLIP 'ENDAT' STO
  CLLCD
  "Finding appointments" 1 DISP
  WHILE
    @ GDALRM
    IFERR RCLALARM THEN
      DROP 0
    ELSE
      DUP 1 GET DFLIP DUP SDAT \>= SWAP ENDAT \<= AND
      IF THEN
        1
      ELSE
        DROP 0
      END
    END
  REPEAT
    @ MKSTR
    DUP 1 GETI 3 ROLLD GET TSTR 1 19 SUB "  " + SWAP 3 GET DUP
    IF TYPE 2 == THEN
      +
    ELSE
      DROP "Control Alarm" +
    END
    + "\010" + NXTALRM 1 + DUP 'NXTALRM' STO
  END
  'APPTSTR' STO
  @ TOPC
  CLLCD
  "The data is ready.\010Press the appropriate\010key when you are\010ready."
  1 DISP { "SEND" "" "" "" "" "ABRT" } MENU
  DO
    -1 WAIT
    IF DUP 11.1 == THEN
      DROP 'APPTSTR'
      IFERR CLLCD SEND THEN
        DROP CLLCD
        "I/O Problem\010Check configuration\010and retry." 1 DISP
      ELSE
        CLLCD "Successful transfer" 1 DISP
      END
      3 WAIT 16.1
    END
  UNTIL
    16.1 ==
  END
  CLEAR
\>>

DFLIP
@ called by OVERALL (3)
@ Change MM.DDYYYY to YYYYMMDD for numerical comparisons.
\<<
  100 * DUP IP SWAP FP 100000000 * +
\>>


APPTS
@ called by DOKEY
@ APPTS key: show appointments for selected day, allow operations.
\<<
  3 DROPN
  IF
    @ FAPPTS
    DSTR FINDALARM DUP
    IF THEN
      @ ALRM\->
      'NXTALRM' STO
      DO
        NXTALRM
        IFERR RCLALARM THEN
          DROP DSTR 1 + 1 \->LIST
        ELSE
          OBJ\-> DROP NXTALRM 5 \->LIST NXTALRM 1 + 'NXTALRM' STO
        END
      UNTIL
        DUP 1 GET DSTR \=/
      END
      DROP
    ELSE
      DROP
    END
    DEPTH
  THEN
    DEPTH ROLL
    @ APS\->MS
    DEPTH 1 SWAP
    START
      @ OAL\->MSG
      DUP 5 GET SWAP DUP 3 GET SWAP 2 GET DUP IP DUP
      IF 10 < THEN
        "0" SWAP +
      END
      ":" + SWAP FP 100 * IP DUP
      IF NOT THEN
        DROP "00"
      END
      + " " + SWAP + SWAP 2 \->LIST
      DEPTH ROLL
    NEXT
    @ PSTMSG
    PG
    DO
      -1 WAIT
      @ DOK5 and DOKX
      { 91.3 OFF
        25.1 { DROP DEPTH ROLL PG 25.1 }
        35.1 { DROP DEPTH ROLLD PG 35.1 }
        11.1 \<<
          DROP 2 GETI SWAP DROP DUP RCLALARM SWAP DELALARM DUP BEG
          IF 1 FC? THEN
            STOALARM
          ELSE
            DROP
          END
          1 CF 16.1
        \>>
        12.1 { DROP 2 GETI SWAP DROP
          # 18CEAh SYSEVAL # E402h SYSEVAL # 3244h SYSEVAL
          # E80Dh SYSEVAL # 172Bh SYSEVAL DROP2 12.1 }
        13.1 { DROP 2 GET DELALARM 16.1 }
        14.1 { DROP DSTR TIME 100 * IP 100 / "" 0 4 \->LIST BEG 1 CF 16.1 }
        15.1 \<<
          DROP
          @ PRVW
          CLLCD DUP 1 GET DUP SIZE 7 SWAP SUB DUP SIZE 1 SWAP
          FOR x
            DUP 1 22 SUB x 22 / 1 + DISP
            IF DUP SIZE 22 > THEN
              DUP SIZE 23 SWAP SUB
            END
          22 STEP
          DROP { "" "" "" "" "" "RTRN" } MENU -1 WAIT DROP
          PG 15.1
        \>>
      }
      IF DEPTH 7 > THEN
        { 25.2 { DROP 1 5 START DEPTH ROLL NEXT PG 25.2 }
          35.2 { DROP 1 5 START DEPTH ROLLD NEXT PG 35.2 }
        } +
      END
      DUP2 SWAP POS
      IF DUP THEN
        1 + GET EVAL
      ELSE
        DROP2
      END
    UNTIL
      16.1 ==
    END
    CLEAR
  ELSE
    @ NOAPPTS
    DO
      @ NOHEAD
      DSTR TIME TSTR 1 12 SUB "     " SWAP + "   NO APPTS YET FOR"
      CLLCD 1 DISP 3 DISP
      @ SETNO
      { "" "" "" "ADD" "" "RTN" } MENU
      -1 WAIT
      @ DOK3
      CASE
        DUP 91.3 == THEN OFF END
        DUP 14.1 == THEN DROP DSTR 8 "" 0 4 \->LIST BEG 16.1 END
      END
    UNTIL
     16.1 ==
    END
  END
\>>

PG
@ called by APPTS (5)
@ Put the (first 5) appointments on the stack in the display,
@  and show the menu.
\<<
  @ MHEAD
  DSTR TIME TSTR 1 12 SUB "     " SWAP + "Appts and meetings for"
  CLLCD 1 DISP 2 DISP
  @ SETU3
  { "EDIT" "ACK" "DEL" "ADD" "VIEW" "RTN" } MENU
  DEPTH 5 MIN
  @ POSTX
  \-> d \<<
    1 d FOR i
      DUP 1 GET i 2 + DISP DEPTH ROLL
    1 STEP
    1 d START
      DEPTH ROLLD
    NEXT
    @ TSK1
    LCD\-> DUP { # 0h # Fh } { # 87h # 17h } SUB NEG
    { # 0h # Fh } SWAP REPL \->LCD
  \>>
\>>


BEG
@ called by DOKEY, APPTS
@ ADD or EDIT key: edit a new or existing appointment.
\<<
  DO
    @ RFSH
    CLLCD 1
    GETI "Date " SWAP + 1 DISP
    GETI "Hour " SWAP + 2 DISP
    GETI "Msg. " SWAP + 3 DISP
    DROP "Press a softkey first" 5 DISP
    @ SETU4
    { "DATE" "TIME" "MSG" "RPT" "SET" "ABRT" } MENU
    -1 WAIT
    @ DOK4
    { 91.3 OFF
      11.1 { DROP DATTE 11.1 }
      12.1 { DROP HOUR 12.1 }
      13.1 { DROP MSSG 13.1 }
      14.1 { REPEET 14.1 }
      15.1 { DROP STOALARM DROP 1 SF 15.1 }
      16.1 { 1 CF SWAP DROP }
    }
    DUP2 SWAP POS
    IF DUP THEN
      1 + GET EVAL
    ELSE
      DROP2 1000 .2 BEEP
    END
  UNTIL
    DUP 15.1 == SWAP 16.1 == OR
  END
\>>

MSSG
@ called by BEG
@ MSG key: change text message for appointment.
\<<
  { } MENU 3 GETI SWAP DROP \Ga 2 \->LIST
  "Message:\010Then press ENTER." SWAP INPUT 3 SWAP PUT
\>>

HOUR
@ called by BEG
@ TIME key: change time for appointment.
\<<
  { } MENU 2 GETI SWAP DROP \->STR -1 2 \->LIST
  "Hour (HH.MM):\010Then press ENTER." SWAP INPUT OBJ\-> 2 SWAP PUT
\>>

DATTE
@ called by BEG
@ DATE key: change date for appointment.
\<<
  DO
    { } MENU 1 GETI SWAP DROP \->STR -1 2 \->LIST 
    "Date (MM.DDYYYY):\010Then press ENTER." SWAP INPUT OBJ\->
  UNTIL
    DUP DUP DUP IP DUP 0 > SWAP 13 < AND SWAP FP 100 * IP 32 < AND
    SWAP 100 * FP 10000 * 1990 \>= AND DUP
    IF NOT THEN
      SWAP DROP CLLCD
      "Bad date. The rules:\010\0100 < MM < 13\0100 < DD < 32\0101990 \<= YYYY\010\010Press a top row key"
      1 DISP -1 WAIT DROP
    END
  END
  1 SWAP PUT
\>>

REPEET
@ called by BEG
@ RPT key: change repeat specification for appointment.
@ (Note: this function expects no number to be entered if NONE will
@  be pressed on the next menu.)
\<<
  { } MENU
  "Repeat #. Then ENTER."  "" INPUT OBJ\->
  { "Week" "Day" "Hour" "Min" "Sec" "None" } MENU
  "Now press repeat unit" 3 DISP -1 WAIT
  { 11.1 4954521600
    12.1 707788800
    13.1 29491200
    14.1 491520
    15.1 8192
  }
  DUP ROT POS
  IF DUP THEN
    1 + GET *
  ELSE
    DROP2 0                             @ this assumes no input
  END
  SWAP DROP 4 SWAP PUT
\>>

RDOSCR
@ called by YRMIN, YRPLS, MOMIN, MOPL
@ Change current date and display the new month.
\<<
  SETUP2 MNTH LCD\-> RC HLIT2 DUP \->LCD SWAP
\>>

HLIT2
@ called by RDOSCR, PWEEK (2), NWEEK (2), DYMIN (2), DYPL (2)
@ Toggle the highlighting of the current date in the calendar.
\<<
  COL R\->B ROW R\->B 2 \->LIST DUP2
  COL 12 + R\->B ROW 8 + R\->B 2 \->LIST
  SUB NEG REPL
\>>

RC
@ called by RDOSCR, PWEEK, NWEEK, DYMIN, DYPL
@ Update ROW and COL for the current date in the calendar.
\<<
  Dy ADR + 7 / FP 126 * 1 - 'COL' STO
  Dy ADR + 7 / IP 1 + 8 * 1 - 'ROW' STO
\>>

SETUP2
@ called by REFRESH, RDOSCR
@ Set DSTR, update Mo, Dy, Yr, Day1, and ADR.
\<<
  DUP 'DSTR' STO DUP
  @ MMYY
  DUP IP 'Mo' STO
  FP 100 * DUP IP 'Dy' STO
  FP 10000 * \->STR 'Yr' STO
  DUP
  @ DFRST
  DUP IP SWAP FP 100 * FP 1 + 100 / + TIME TSTR 1 3 SUB 'Day1' STO
  @ CADR
  { "SUN" "MON" "TUE" "WED" "THU" "FRI" "SAT" } Day1 POS 2 - 'ADR' STO
\>>

MNTH
@ called by REFRESH, RDOSCR
@ Put the current month in the display.
\<<
  @ HEADR
  { "January " "February " "March " "April " "May " "June "
    "July " "August " "September " "October " "November " "December " }
  Mo GET Yr + "  " SWAP + 1 DISP
  DSTR LMNTH Day1
  @ MN
  \-> n d \<<
  "                   1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31"
  { "SAT" "FRI" "THU" "WED" "TUE" "MON" "SUN" } d POS 3 * 2 -
  n 3 * 17 + SUB
  2 7 FOR i
    DUP i 2 - 21 * 1 + DUP 19 + SUB i DISP
  NEXT
  DROP
  \>>
\>>

LMNTH
@ called by NWEEK, DYPL, MNTH
@ Compute the number of days in the month.
\<<
  DUP IP SWAP 100 * FP 100 / .01 + + DUP 1 + DUP
  IF 13 > THEN
    FP 1.000001 +
  END
  DDAYS
\>>


SRCSTR ""                               @ used in CHKALRM, GETSTR

MYFLGS {  # 90400000FF0h # 0h  }        @ used by APPT (not in APDIR)

END @ APDIR

From comp.sys.handhelds Wed Apr  4 11:09:36 1990
Path: fauern!unido!mcsun!uunet!jarthur!bgribble
From: bgribble@jarthur.Claremont.EDU (Bill Gribble)
Newsgroups: comp.sys.handhelds
Subject: hp48 terminal emulator: here it is!
Keywords: slow as a pig with gland problems.
Message-ID: <5783@jarthur.Claremont.EDU>
Date: 3 Apr 90 18:00:19 GMT
Organization: Harvey Mudd College, Claremont, CA 91711
Lines: 210
Status: OR

Well, here it is: my humble effort at an hp48 terminal emulator.  It works,
  but that's about it.  I'm still (as I posted yesterday) looking for faster
  screen display routines, since this version loses text when it's sent
  in blocks of more than about 20 characters - i.e., all the time.

I know it's functional because I used it to upload itself to this computer;
  kermit is much more functional when you skip the pc step in the
  ftp-to-unix <=> zmodem-to-pc <=> kermit-to-calc cycle, and it's pretty
  impressive to see a 'username>' prompt on a calculator screen. 

Features:  semi-functional kermit shell: it receives right, but there's
  an unknown (and moronic, I'm sure)  bug in the send program.  Invocation:
  orange-shift backspace to send (it'll prompt you for a filename and do zip),
  blue-shift backspace to receive.  In general, blue-shift is for SHIFT, 
  orange shift is CNTRL. They're both toggles: once to start, again to enter 
  normal text.  The alpha key sends a serial break.  DEL quits the program 
  and cleans trash.
    
I haven't actually implemented the XON/XOFF flow control I mentioned
  yesterday; that's version 1.1, I guess.  Other needs: punctuation marks;
  they're destined to be shifted numbers.  Faster text display: I'm trying
  out a few different things today.  

Sorry the thing is such a beast; I put it in one program to speed up 
  the upload/edit/download/etc., so it takes twice as much memory
  when it runs.  Easy to change, but editing the thing on the 48 is 
  REALLY slow, so I'm doing the big revisions on the computer now that
  I fixed my cable.

Have fun; any advice/suggestions are appreciated.

                                        Bill.

=============================================================================  
=====   Bill Gribble           Internet: bgribble@jarthur.claremont.edu =====
=====   Harvey Mudd College              wgribble@hmcvax.claremont.edu  =====
=====   Claremont, CA 91711    Bitnet:   wgribble@hmcvax.bitnet         =====
=====   (714) 621-8000 x2045                                            =====
=============================================================================

=============================================================================

TERM 1.0: hp48 terminal emulator.  
Bill Gribble.

 BYTES: 2181
CHKSUM: # 2A05h

%%HP: T(3)A(R)F(.);
\<<
  \<<
    IF DUP NUM 31 \<=
    THEN
      IF DUP NUM 8
==
      THEN string
DUP SIZE 1 - 1 SWAP
SUB 'string' STO
DROP ""
      END
      IF DUP NUM 13
==
      THEN 'string'
empt STO+ DROP ""
      END
    END 'string'
SWAP STO+ string 7
DISP
    IF string SIZE
21 \>=
    THEN LCD\-> {
# 0d # 8d } {
# 131d # 55d } SUB
# 131d # 64d BLANK
{ # 0d # 0d } 3
ROLL GOR \->LCD ""
'string' STO
    END
  \>>
  \<<
    IF DUP NUM 128
<
    THEN
      IF DUP NUM 13
==
      THEN 10 CHR +
      END XMIT
    ELSE DUP NUM
'nm' STO
      IF nm 128 ==
      THEN
        IF 27 FS?
        THEN 27 CF
26 CF
        ELSE 26 CF
27 SF
        END
      ELSE
        IF nm 129
==
        THEN
          IF 26 FS?
          THEN 26
CF 27 CF
          ELSE 26
SF 27 CF
          END
        ELSE
          IF nm 130
==
          THEN SBRK
empt wrt
"   -- Break sent --"
wrt
          ELSE
            IF nm
132 ==
            THEN
krm
            ELSE
              IF nm
131 ==
              THEN
quit
              ELSE
IF nm 133 ==
THEN RECV
END
              END
            END
          END
        END
      END
    END
  \>>
  \<< 13 CF 14 CF
    DO BUFLEN KEY
DUP
      IF 0 \=/
      THEN 13 SF
DROP 'k' STO
      ELSE DROP
      END
      IF DROP 0 \=/
      THEN 14 SF
      END
    UNTIL 13 FS? 14
FS? OR
    END
    IF 13 FS?
    THEN
      IF 27 FS?
      THEN 2
      ELSE
        IF 26 FS?
        THEN 1
        ELSE 3
        END
      END 'keys'
SWAP GET k k SUB
snd DROP
    END
    IF 14 FS?
    THEN BUFLEN
DROP
      IF DUP 20 >
      THEN DROP 21
      END SRECV
DROP wrt
    END term2
  \>> {
"..........ABCDEF....GHIJKL....MNOPQR....STUVWX....YZ\v/\GS.....\.V789......\<)456*.....\x-123-......0. +"
"..............	..............\v/\.S.....\.V.........\<).........\x-................."
"..........abcdef....ghijkl....mnopqr....stuvwx....yz\v/.....\.V789......\<)456*.....\x-123-......0. +"
}
"                      "
  \<< 19 CHR XMIT
DROP empt wrt
"File: " wrt 0 \-> q
    \<< ""
      DO
        DO KEY
        UNTIL
        END
        IF DUP 51
SAME
        THEN 1 'q'
STO+
        ELSE keys 1
GET SWAP DUP SUB
DUP wrt +
        END
      UNTIL q
      END
    \>> DROP 17 CHR
XMIT DROP STR\-> SEND
  \>>
  \<< { k nm string
krm empt keys term2
snd wrt quit }
PURGE CLOSEIO
  \>> 'quit' STO
'krm' STO 'empt'
STO 'keys' STO
'term2' STO 'snd'
STO 'wrt' STO CLLCD
"" 'string' STO
OPENIO 13 CF 14 CF
27 CF term2
\>>

From comp.sys.handhelds Mon Apr  9 09:06:59 1990
Path: fauern!unido!mcsun!uunet!samsung!brutus.cs.uiuc.edu!jarthur!nntp-server.caltech.edu!piglet!madler
From: madler@piglet.caltech.edu (Mark Adler)
Newsgroups: comp.sys.handhelds
Subject: A quicker quicksort on the HP-48SX
Message-ID: <1990Apr5.192150.15199@laguna.ccsf.caltech.edu>
Date: 5 Apr 90 19:21:50 GMT
Sender: heather@laguna.ccsf.caltech.edu (Heather Sherman)
Organization: California Institute of Technology, Pasadena
Lines: 109
Status: OR


With Alonzo's helpful comments about what operations are fast on the
HP-48SX, and why, I wrote a quicksort program faster than Alonzo's.
The speed increase comes from a different strategy (not putting the
sublists on the bottom of the stack), tighter inner loops (index
bounds do not have to be checked), a median approach to selecting the
middle element, and a final insertion sort pass to sort short
subfiles.

I tested three sorts: QSORT, ASORT, and SORT where QSORT is Alonzo's
original, ASORT is QSORT modified to stop at sublists of length 24 or
less and then do an insertion sort, and SORT is my version.  (SORT
stops at sublists of length 20---the values 20 and 24 minimize the
execution times of the respective sorts.)  They were all tested on
lists of 500 reals and 50 reals (generated using RAND) with about 18K
free before the list was made, and with lastargs turned off (flag -55
set).  The list was stored in a global and then recalled to the
stack, as per Alonzo's suggestion.  The test for 50 elements were
done for 10 different random lists each and the number that follows
is the standard deviation for the tests.  The times are in min:sec or
just seconds:

sort       500     50

QSORT     3:55  10.37 (0.71)
ASORT     3:35   7.85 (0.68)
SORT      2:45   7.13 (0.31)

SORT can be modified to use a different comparison operator than ">"
by changing the occurences of "IF DUP2 >" to "IF DUP2 GT", "PICK >"
to "PICK GT", and "PICK <" to "PICK SWAP GT" in QPART, and "PICK >"
to "PICK GT" in SORT, where GT is a program or expression that
returns zero if stack entry 2 is less than or equal to stack entry
one, or non-zero otherwise.

Mark Adler
madler@tybalt.caltech.edu

Here are the programs:

%%HP: T(3)A(R)F(.);
@ SORT crc #DBF1h length 112.5
@ Use QPART to do a quicksort up to subfiles of length 20, and then do
@ one pass of an insertion sort to sort the subfiles.
\<< OBJ\-> \-> n                        @ put list on stack
  \<< n 2 QPART                         @ do quicksort
      2 n FOR j                         @ do insertion sort
        j ROLL j 2 +                    @ get element j
        WHILE                           @ assuming [1]..[j-1] is sorted,
          DUP2 PICK >                   @  find where element j goes
        REPEAT
          1 -
        END
        2 - ROLLD                       @ put element j there
      NEXT
      n \->LIST                         @ convert back to list
  \>>
\>>

%%HP: T(3)A(R)F(.);
@ QPART crc #16E0h length 389
@ Given a partition of the stack, split it into two partitions so that
@ all the entries in the first one are less than or equal to the entries
@ in the second one, and then call this routine recusively for each of
@ those partitions.  If a partition is 20 or fewer elements, then do
@ nothing and end the recursion.  A final pass of an insertion sort will
@ sort the remaining short partitions more efficiently.
\<<
  IF DUP2 - 18 > THEN                   @ sort if more than 20 elements
    @ sort the portion of the stack from level l to level r (after
    @  l and r are pulled off the stack).
    \-> r l \<<                         @ (l is really l+1)
      @ sort [l], [m], [r] so that [l] >= [m] >= [r] where they are
      @  picked from the start, middle, and end of the sublist.
      r l + 2 / FLOOR ROLL              @ (FLOOR needed since l is l+1)
      l ROLL
      IF DUP2 > THEN SWAP END
      l ROLLD r ROLL
      IF DUP2 > THEN
        r
      ELSE
        SWAP r ROLLD l ROLL
        IF DUP2 > THEN SWAP END
        l
      END
      ROLLD
      @ start sorting inside [l], [r].
      r 3 + SWAP l 3 +
      @ put [m] in list so that [i] >= [m] >= [j] for i < j.
      WHILE                             @ stack is i+4,[m],j+4,list...
        WHILE 1 + DUP2 PICK < REPEAT END        @ now [m] >= [i]
        SWAP ROT
        WHILE 1 - DUP2 PICK > REPEAT END        @ now [j] >= [m]
        ROT DUP2 >                      @ until j <= i
      REPEAT                            @ stack is i+4,j+4,[m],list...
        DUP2 ROLL OVER ROLL             @ swap [i], [j]
        4 PICK 1 + ROLLD OVER ROLLD
        4 ROLLD SWAP DROP               @ stack is i+4,[m],j+4,list...
      END
      DROP 2 - SWAP OVER ROLLD          @ put [m] after [j]
      @ sort the sublists [j+2..r] and [l..j] by calling this program
      @  recursively.
      r SWAP DUP 'r' STO 1 + QPART
      r 2 - l QPART
    \>>
  ELSE
    DROP2                               @ not sorting---trash r and l
  END
\>>

From comp.sys.handhelds Tue Apr 10 17:51:33 1990
Path: fauern!unido!mcsun!uunet!samsung!usc!apple!dan
From: dan@Apple.COM (Dan Allen)
Newsgroups: comp.sys.handhelds
Subject: RPL Code for Lists/Sets
Keywords: RPL,HP-48SX,lists,sets,set operations
Message-ID: <40175@apple.Apple.COM>
Date: 10 Apr 90 07:42:23 GMT
Distribution: comp.sys.handhelds
Organization: Apple Computer Inc, Cupertino, CA
Lines: 226
Status: OR


                    LIST and SET Operations for the HP-48SX
                         By Dan Allen, 10 April 1990

LIST PROCESSING
  The HP-48SX supports lists of objects as a built-in data type.  Several 
functions are provided for working on lists:

    Function     Operation
    --------     ---------
    +            Concatenates two lists into one list
    SIZE         Returns the number of elements in a list
    POS          Checks if an element is in a list
    SUB          Returns a subset of a list as a list
    GET          Returns the nth element of a list
    PUT          Replaces the nth element of a list

Other than direct editing of a list, there is no way to add elements to a list 
other than by appending elements to the front or back of a list through the + 
operator, and there is no way to delete elements of a list.
  Here are a few list operations that extend the functionality of the HP-48SX.  
Ideally these should be in a future machine; in the meantime they should be 
written in assembly language for better efficiency.
  The first two functions are CAR and CDR, named after the LISP functions of 
the same bizarre but historically interesting names.  Common LISP also has the 
functions FIRST and REST which are exactly the same as CAR and CDR, which 
return the first and remaining parts of a list.  The second pair of functions 
are INS and DEL, which allow inserting and deleting specific elements of a 
list.
  These routines handle invalid arguments quietly, i.e., deleting the 5th 
element of a 4 element list does nothing; it returns the 4 element list 
unchanged, without any error mentioned.  Similar handling of invalid 
conditions is done by the other routines as well.

LISTS AS SETS
  A list supports an ordering of its elements and can have duplicate members.  
Sets are not ordered and can only have one occurance of a given object.  With 
these restrictions, a list can be used as a set with various functions 
designed to support set operations.  Such functions are provided here, with 
many of the operations also being valid on lists as well.
  ADJOIN allows items to be added to a set.  ADJOIN makes sure that no 
duplicate entries are allowed in the list, thus enforcing one of the rules of 
sets.
  MEMBER tests set membership, that is, it checks to see if an object is 
included in a set (or list).  It only searches the top level.  It returns a 
CDR-like list beginning with the item found, or the empty list { } if the 
object is not found.
  UNION and INTERSECT implement set union and intersection, while DIFF and 
SDIFF are set difference and symmetric difference.  If the lists given are not 
sets (that is, they contain duplicates), duplicates may appear in the results.  
These four operations are the main arithmetic operations for sets, with the 
following similarities to arithmetic and boolean operations:

   ARITHMETIC            BOOLEAN            SET OPERATION
   ----------            -------            -------------
   addition (+)          OR (inclusive)     union
   subtraction (-)       AND NOT            difference
   multiplication (*)    AND                intersection
   division (/)          XOR                symmetric difference

EXAMPLES

{ 1 2 3 } CAR  -->  1                 { } CAR  -->  { }
{ 1 2 3 } CDR  -->  { 2 3 }           { } CDR  -->  { }

{ 1 2 3 } 1 0 INS  -->  { 0 1 2 3 }   { 1 2 } 9999 48 INS  -->  { 1 2 48 }
{ 1 2 3 } 2 DEL  -->  { 1 3 }         { 1 2 } 9999 DEL  -->  { 1 2 }

{ 1 2 3 } 2 MEMBER  -->  { 2 3 }      { 1 2 3 } 4 MEMBER  -->  { }
{ 1 2 } 3 ADJOIN  -->  { 1 2 3 }      { 1 2 3 } 3 ADJOIN  -->  { 1 2 3 }

{ 1 2 } { 3 4 } UNION --> {1 2 3 4}   { 1 2 } { 1 2 } UNION  -->  { 1 2 }
{ 1 2 } { 3 4 } INTERSECT --> { }     { 1 2 } { 2 3 } INTERSECT  -->  { 2 }
{ 1 2 } { 3 4 } DIFF --> { 1 2 }      { 1 2 } { 2 3 } DIFF  -->  { 1 }
{ 1 2 } { 3 4 } SDIFF --> {1 2 3 4}   { 1 2 } { 2 3 } SDIFF  -->  { 1 3 }

  Comments are bracketed by @ signs.  With minor changes, most of these 
programs should run on the HP-28.  Here then are some useful list and set 
operations for the HP-48SX:

CAR   @ Extracts the first object of a list as an atomic entity @
<<    @ USAGE:  list CAR  -->  list   @
  IFERR 1 GET
  THEN DROP       @ CAR of an empty list is the empty list @
  END  
>>

CDR   @ Returns the tail (all but 1st object) of a list as a list @
<<    @ USAGE:  list CDR  -->  list   @
  OBJ->
  IF DUP
  THEN 1 - ->LIST SWAP DROP
  ELSE DROP { }   @ CDR of an empty list is the empty list @
  END
>>

INS   @ Inserts an object as the nth element of list @
<<    @ USAGE:  list integer obj INS  -->  list   @
  -> list n x
  <<
    list 1 n 1 - SUB x + list n list SIZE SUB +
  >>
>>

DEL   @ Deletes the nth element of list @
<<    @ USAGE:  list integer DEL  -->  list   @
  -> list n
  <<
    list 1 n 1 - SUB list n 1 + list SIZE SUB +
  >>
>>

MEMBER  @ Checks if obj is a member of list at the top level @
<<      @ USAGE:  list obj MEMBER  -->  list   @
  -> list obj
  <<
    list obj
    IF POS DUP 0 >
    THEN list SWAP list SIZE SUB
    ELSE DROP { }
    END
  >>
>>

ADJOIN  @ Adds an object to a list, preventing duplicates @
<<      @ USAGE:  list obj ADJOIN  -->  list   @
  -> list obj
  <<
    IF list obj MEMBER SIZE
    THEN list
    ELSE list obj +
    END
  >>
>>

UNION  @ Returns the set union of two lists (c = a OR b) @
<<     @ USAGE:  list list UNION  -->  list   @
  OVER -> a b c  @ efficiency tip: put smallest list on top of stack @
  <<
    IF a SIZE 0 == b SIZE 0 == OR
    THEN a b +  @ if either list is empty then concatenate lists @
    ELSE        @ step through the second list's elements @
      b 1 1 b SIZE
      START
        GETI DUP c SWAP
        IF POS
        THEN DROP
        ELSE 'C' SWAP STO+  @ adding appropriate new elements @
        END
      NEXT
      DROP2 C
    END
  >>
>>

INTERSECT  @ Returns the set intersection of two lists (c = a AND b) @
<<         @ USAGE:  list list INTERSECT  -->  list   @
  { } -> a b c  @ efficiency tip: put smallest list on top of stack @
  <<
    IF a SIZE 0 == b SIZE 0 == OR
    THEN c
    ELSE
      b 1 1 b SIZE
      START
        GETI DUP a SWAP
        IF POS
        THEN 'C' SWAP STO+
        ELSE DROP
        END
      NEXT
      DROP2 C
    END
  >>
>>

DIFF  @ Returns the set difference of two lists (c = a AND NOT b) @
<<    @ USAGE:  list list DIFF  -->  list   @
  { } -> a b c
  <<
    IF a SIZE 0 == THEN c
    ELSE IF b SIZE 0 == THEN a
      ELSE
        a 1 1 a SIZE
        START
          GETI DUP b SWAP
          IF POS
          THEN DROP
          ELSE 'C' SWAP STO+
          END
        NEXT
        DROP2 C
      END
    END
  >>
>>

SDIFF  @ Returns the set symmetric difference between two lists (c = a XOR b) 
@
<<     @ USAGE:  list list SDIFF  -->  list   @
  { } -> a b c   @ Efficiency note: this is O(n^2) and could be improved @
  <<
    IF a SIZE 0 == THEN b         @ if a is empty, then return b @
    ELSE IF b SIZE 0 == THEN a    @ if b is empty, then return a @
      ELSE                        @ else loop through both lists @
        a 1 1 a SIZE     
        START
          GETI DUP b SWAP
          IF POS
          THEN DROP
          ELSE 'C' SWAP STO+
          END
        NEXT
        DROP2
        b 1 1 b SIZE
        START
          GETI DUP a SWAP
          IF POS
          THEN DROP
          ELSE 'C' SWAP STO+
          END
        NEXT
        DROP2 C
      END
    END
  >>
>>

From comp.sys.handhelds Tue Apr 17 13:39:31 1990
Path: fauern!unido!mcsun!sunic!uupsi!rpi!zaphod.mps.ohio-state.edu!usc!jarthur!nntp-server.caltech.edu!piglet!madler
From: madler@piglet.caltech.edu (Mark Adler)
Newsgroups: comp.sys.handhelds
Subject: My last post on sorting (sure) for the HP-48SX
Message-ID: <1990Apr11.045126.5737@laguna.ccsf.caltech.edu>
Date: 11 Apr 90 04:51:26 GMT
Sender: news@laguna.ccsf.caltech.edu
Organization: California Institute of Technology, Pasadena
Lines: 146
Status: OR


Here posted are somewhat improved versions of SORT and QPART.  These
represent about a 2% increase in speed from the previous version (I
couldn't resist even such a trivial improvement).  The change was
simply to test the size of the list before calling QPART, both from
SORT, and from the two places in QPART itself.  The comments are also
a little more complete.  Enjoy.

Mark Adler
madler@tybalt.caltech.edu


%%HP: T(3)A(R)F(.);
@ SORT crc #10B7h length 141
@
@ by Mark Adler  10 Apr 1990
@
@ Use QPART to do a quicksort up to subfiles of length 20, and then do
@ one pass of an insertion sort to sort the subfiles.  See the comments
@ in QPART.
@
@ The sort will be fastest if the list being sorted was recalled from a
@ global variable.  This avoids garbage collection on the objects in
@ the list when they are on the stack.  It will also speed the sort to
@ disable last args with a "-55 SF".
@
@ To sort objects other than reals or strings, change the ">" in
@ "PICK >" to the appropriate code and modify QPART in the same way
@ (see the comments in QPART).
@
\<< OBJ\-> DUP \-> n                    @ put list on stack
  \<< 
    @
    @ if size > 20, do quicksort
    @
    IF DUP 20 > THEN 2 QPART n END      @ partition is [1] to [n]
    @
    @ do insertion sort on what remains
    @
    2 SWAP FOR j                        @ starting with j=2, insert [j]
      j ROLL j 2 +                      @ [1]..[j-1] is sorted, get [j]
      WHILE DUP2 PICK > REPEAT 1 - END  @ find where [j] goes
      2 - ROLLD                         @ put [j] there
    NEXT
    n \->LIST                           @ convert back to list
  \>>
\>>


%%HP: T(3)A(R)F(.);
@ QPART crc #7BCCh length 419.5
@
@ by Mark Adler  10 Apr 1990
@ 
@ Given a partition of the stack, pick an entry in the partition and
@ split the partition into two partitions such that all the entries in
@ the first one are less than the entry picked, and all the entries in
@ the second one are greater than the entry picked, and the entry is
@ placed between them.  Then call this routine recursively for each of
@ those partitions, unless the partition is 20 entries or less.  A
@ final pass of an insertion sort should be done to sort the remaining
@ short partitions.  The value of 20 was determined experimentally on
@ test cases of lists of random reals.
@
@ The entry for partitioning is picked using the median method, which
@ picks the median value of the entries at the beginning, middle, and
@ end of the list.  This makes the sort fast for already sorted lists,
@ and greatly reduces the probability of the sort taking order n^2
@ time.  It also reduces the total number of comparisons, speeding the
@ sort somewhat.  Most importantly, an additional step of sorting the
@ first and last elements of the list (which adds one compare) allows
@ the inner loops of the algorithm to not have to check for the bounds
@ of the partition.  This special-purpose three element sort does not
@ cost extra, since the outer two elements would have to have been
@ compared and swapped anyway if they were in the wrong place.
@
@ The arguments to QPART are two integers specifying the stack levels
@ to partition.  The arguments refer to the stack after the arguments
@ are removed from the stack.  The integer in the first level minus 1
@ is the starting level, and the integer in level 2 is the ending level
@ to partition.  So, for example, to partition the stack levels 1
@ through n, the calling sequence would be "n 2 QPART".  Since QPART
@ does not check the partition size on entry, the calling routine
@ should do that and avoid calling QPART for sizes of 20 or less.
@
@ The algorithm can be modified to sort objects besides reals and
@ strings by replacing the ">" in the "IF DUP2 >"'s and in the "PICK >"
@ and replacing the "<" in the "PICK <" with the appropriate code for
@ the object.  The routine can be generalized (at a speed penalty) by
@ replacing said ">"'s with "GT" and the said "<" with "SWAP GT" and
@ defining a function "GT" that does the job before doing the sort.
@
\<<
  @ sort the partition of the stack from level l-1 to level r (after
  @  l and r are pulled off of the stack).
  \-> r l \<<
    @
    @ sort [l-1], [m], [r] so that [l-1] >= [m] >= [r] where m points
    @  to the middle of the partition.
    @
    r l + 2 / FLOOR ROLL                @ get [m]
    l ROLL                              @ get [l-1]
    IF DUP2 > THEN SWAP END             @ sort [m], [l-1]
    l ROLLD r ROLL                      @ put back new [l-1]; get [r]
    IF DUP2 > THEN                      @ if [r], [m] sorted,
      r                                 @  then just put [r] back
    ELSE
      SWAP r ROLLD l ROLL               @ else sort [r], [m]; get [l-1]
      IF DUP2 > THEN SWAP END           @  and re-sort [m] and [l-1]
      l                                 @ put [l-1] back
    END
    ROLLD
    @
    @ start sorting inside [l-1], [r] since [l-1] and [r] are already
    @ sorted.  put [m] in list so that [i] >= [m] >= [j] for i < j.
    @
    r 3 + SWAP                          @ i = l-1 (loop begins "1 +")
    l 3 +                               @ j = r-1 (since m pulled out)
    WHILE                               @ stack is i+4,[m],j+4,list...
      WHILE 1 + DUP2 PICK < REPEAT END  @ now [m] >= [i]
      SWAP ROT
      WHILE 1 - DUP2 PICK > REPEAT END  @ now [j] >= [m]
      ROT DUP2 >                        @ until j <= i
    REPEAT                              @ stack is i+4,j+4,[m],list...
      DUP2 ROLL OVER ROLL               @ swap [i], [j]
      4 PICK 1 + ROLLD OVER ROLLD
      4 ROLLD SWAP DROP                 @ stack is i+4,[m],j+4,list...
    END
    DROP 2 - SWAP OVER ROLLD            @ put [m] after [j]
    @
    @ sort the partitions [j+2..r] and [l-1..j] by calling this program
    @  recursively, but only if the partition has length > 20.  The
    @  stack is j+2,list...
    @
    IF r DUP2 - -18 < THEN              @ check top partition
      SWAP DUP 'r' STO 1 + QPART r      @ save j+2 in r
    ELSE
      DROP
    END                                 @ j+2 left on stack
    IF 2 - l DUP2 - 18 > THEN           @ check bottom partition
      QPART
    ELSE
      DROP2
    END                                 @ leave the list on the stack
  \>>
\>>

From comp.sys.handhelds Tue Apr 17 13:40:05 1990
Path: fauern!unido!mcsun!uunet!jarthur!nntp-server.caltech.edu!piglet!madler
From: madler@piglet.caltech.edu (Mark Adler)
Newsgroups: comp.sys.handhelds
Subject: Re: My last post on sorting (sure) for the HP-48SX
Message-ID: <1990Apr16.194958.22624@laguna.ccsf.caltech.edu>
Date: 16 Apr 90 19:49:58 GMT
References: <1990Apr11.045126.5737@laguna.ccsf.caltech.edu> <54098@microsoft.UUCP>
Sender: news@laguna.ccsf.caltech.edu
Organization: California Institute of Technology, Pasadena
Lines: 147
Status: OR


Oops on OPOS.  Here is a corrected version of OPOS---the last one
didn't work for elements that belonged on the end of the list.

Also included here is an improved QPART using Alonzo's code for
swapping [i] and [j] more efficiently.  (I see that Alonzo can't
resist small tweaks either.)

Mark Adler
madler@tybalt.caltech.edu


%%HP: T(3)A(R)F(.);
@ OPOS crc #DEh length 142
@
@ by Mark Adler  16 Apr 1990
@
@ Ordered POS: the arguments are a list in level 2 and the element to
@ locate in level 1.  The result is the location in level 2 and a
@ boolean in level 1 which is true if the element is in the list.  The
@ location has the range 1..n+1, where n is the number of entries in
@ the list.  n+1 indicates the element belongs at the end of the list
@ (the boolean is always false in this case).  It is assumed that the
@ input list is ordered so that the first entry is less than or equal
@ to the second entry, the second is less than or equal to the third,
@ etc.
@
@ OPOS uses SRCH to find where in the list the element goes.  SRCH
@ uses the ">" operation to compare elements, but this can be changed
@ in SRCH---see the comments in SRCH.  The ">" in this routine would
@ also have to be changed in the same way.
@
\<<
  SWAP OBJ\-> \-> n
  \<<
    n 1 + ROLL n SRCH                   @ do search
    3 - \-> k j                         @ save k, index
    \<<
      IF j DUP THEN                     @ if j not past end,
        PICK k > NOT                    @  see if k in list
      END
      n 1 + ROLLD n DROPN               @ trash list
      n j - 1 +                         @ compute location
      SWAP                              @ return index, boolean
    \>>
  \>>
\>>


%%HP: T(3)A(R)F(.);
@ QPART crc #156h length 412
@
@ by Mark Adler  16 Apr 1990
@ 
@ Given a partition of the stack, pick an entry in the partition and
@ split the partition into two partitions such that all the entries in
@ the first one are less than the entry picked, and all the entries in
@ the second one are greater than the entry picked, and the entry is
@ placed between them.  Then call this routine recursively for each of
@ those partitions, unless the partition is 20 entries or less.  A
@ final pass of an insertion sort should be done to sort the remaining
@ short partitions.  The value of 20 was determined experimentally on
@ test cases of lists of random reals.
@
@ The entry for partitioning is picked using the median method, which
@ picks the median value of the entries at the beginning, middle, and
@ end of the list.  This makes the sort fast for already sorted lists,
@ and greatly reduces the probability of the sort taking order n^2
@ time.  It also reduces the total number of comparisons, speeding the
@ sort somewhat.  Most importantly, an additional step of sorting the
@ first and last elements of the list (which adds one compare) allows
@ the inner loops of the algorithm to not have to check for the bounds
@ of the partition.  This special-purpose three element sort does not
@ cost extra, since the outer two elements would have to have been
@ compared and swapped anyway if they were in the wrong place.  Thanks
@ to Alonzo Gariepy for an improved swap of [i] and [j].
@
@ The arguments to QPART are two integers specifying the stack levels
@ to partition.  The arguments refer to the stack after the arguments
@ are removed from the stack.  The integer in the first level minus 1
@ is the starting level, and the integer in level 2 is the ending level
@ to partition.  So, for example, to partition the stack levels 1
@ through n, the calling sequence would be "n 2 QPART".  Since QPART
@ does not check the partition size on entry, the calling routine
@ should do that and avoid calling QPART for sizes of 20 or less.
@
@ The algorithm can be modified to sort objects besides reals and
@ strings by replacing the ">" in the "IF DUP2 >"'s and in the "PICK >"
@ and replacing the "<" in the "PICK <" with the appropriate code for
@ the object.  The routine can be generalized (at a speed penalty) by
@ replacing said ">"'s with "GT" and the said "<" with "SWAP GT" and
@ defining a function "GT" that does the job before doing the sort.
@
\<<
  @ sort the partition of the stack from level l-1 to level r (after
  @  l and r are pulled off of the stack).
  \-> r l \<<
    @
    @ sort [l-1], [m], [r] so that [l-1] >= [m] >= [r] where m points
    @  to the middle of the partition.
    @
    r l + 2 / FLOOR ROLL                @ get [m]
    l ROLL                              @ get [l-1]
    IF DUP2 > THEN SWAP END             @ sort [m], [l-1]
    l ROLLD r ROLL                      @ put back new [l-1]; get [r]
    IF DUP2 > THEN                      @ if [r], [m] sorted,
      r                                 @  then just put [r] back
    ELSE
      SWAP r ROLLD l ROLL               @ else sort [r], [m]; get [l-1]
      IF DUP2 > THEN SWAP END           @  and re-sort [m] and [l-1]
      l                                 @ put [l-1] back
    END
    ROLLD
    @
    @ start sorting inside [l-1], [r] since [l-1] and [r] are already
    @ sorted.  put [m] in list so that [i] >= [m] >= [j] for i < j.
    @
    r 3 + SWAP                          @ i = l-1 (loop begins "1 +")
    l 3 +                               @ j = r-1 (since m pulled out)
    WHILE                               @ stack is i+4,[m],j+4,list...
      WHILE 1 + DUP2 PICK < REPEAT END  @ now [m] >= [i]
      SWAP ROT
      WHILE 1 - DUP2 PICK > REPEAT END  @ now [j] >= [m]
      ROT DUP2 >                        @ until j <= i
    REPEAT                              @ stack is i+4,j+4,[m],list...
      DUP2 SWAP ROLL SWAP ROLLD         @ swap [i] and [j]
      DUP2 ROLL OVER ROLLD
      DROP ROT SWAP                     @ stack is i+4,[m],j+4,list...
    END
    DROP 2 - SWAP OVER ROLLD            @ put [m] after [j]
    @
    @ sort the partitions [j+2..r] and [l-1..j] by calling this program
    @  recursively, but only if the partition has length > 20.  The
    @  stack is j+2,list...
    @
    IF r DUP2 - -18 < THEN              @ check top partition
      SWAP DUP 'r' STO 1 + QPART r      @ save j+2 in r
    ELSE
      DROP
    END                                 @ j+2 left on stack
    IF 2 - l DUP2 - 18 > THEN           @ check bottom partition
      QPART
    ELSE
      DROP2
    END                                 @ leave the list on the stack
  \>>
\>>

From comp.sys.handhelds Tue Apr 17 13:41:06 1990
Path: fauern!unido!mcsun!uunet!jarthur!usc!zaphod.mps.ohio-state.edu!tut.cis.ohio-state.edu!ucbvax!EN.ECN.PURDUE.EDU!wscott
From: wscott@EN.ECN.PURDUE.EDU (Wayne H Scott)
Newsgroups: comp.sys.handhelds
Subject: Poly roots
Message-ID: <9004120510.AA12975@en.ecn.purdue.edu>
Date: 12 Apr 90 05:10:34 GMT
Sender: daemon@ucbvax.BERKELEY.EDU
Lines: 111
Status: OR


This file is set up to be downloaded into a HP48sx but it should work just
fine with a HP28.

%%HP: T(3)A(R)F(.);

@ The following is a set of programs that I developed to find the roots of 
@ polynomials.  However as a bonus I also created a program to reduce any
@ polynomial into its quadric factors.
@ 
@ The first program is FCTP. (factor polynomial)
@ When it is passed the cooeficients of a polynomial in a list it returns the
@ factor of that polynomal.  ex:
@ 
@ 1: { 1 -17.8 99.41 -261.218 352.611 -134.106 }
@ FCTP
@ 3: { 1 -4.2 2.1 }
@ 2: { 1 -3.3 6.2 }
@ 1: { 1 -10.3 }
@ 
@ This tells us that X^5-17.8*X^4+99.41*X^3-261.218*X^2+352.611*X-134.106
@ factors to (X^2-4.2*X+2.1)*(X^2-3.3*X+6.2)*(X-10.3)
@ 
@ Neat!
@ 
@ The next program is RT. (Roots)
@ If given a polynmoial it return its roots.  ex:
@ 
@ 1: { 1 -17.8 99.41 -261.218 352.611 -134.106 }
@ RT
@ 5: 3.61986841536
@ 4: .58013158464
@ 3: (1.65, 1.8648056199)
@ 2: (1.65, -1.8648056199)
@ 1: 10.3
@ 
@ Very Useful!
@ 
@ These programs use the BAIRS program which performs Bairstow's method of
@ quadratic factors and QUD with does the quadratic equation.
@ 
@ Have Fun!
@ _____________________________________________________________________________
@ Wayne Scott            | INTERNET:   wscott@en.ecn.purdue.edu
@ Electrical Engineering | BITNET:     wscott%ea.ecn.purdue.edu@purccvm
@ Purdue University      | UUCP:      {purdue, pur-ee}!en.ecn.purdue.edu!wscott
@ _____________________________________________________________________________
@				"To iterate is human.  To recurse, divine."

DIR
  FCTP
\<<
   IF DUP SIZE 3 > THEN 
        BAIRS
        FCTP
   END
\>>

RT
\<< DUP SIZE \-> n
   \<<
      IF n 3 > THEN 
        BAIRS
        \-> A B \<< A RT B RT \>>
      ELSE
        IF n 2 > THEN 
           QUD
        ELSE
           LIST\-> DROP NEG SWAP DROP
        END
      END
   \>>
\>>

BAIRS
\<< LIST\-> 1 - 1 1 \-> n R S
   \<< n 3 + 1 2 \->LIST 0 CON DUP \-> B C
      \<<
          DO 
            3 n 3 +
            FOR J
               'B' J n 6 + J - PICK R 'B' J 1 - GET * + S 'B' J 2 - GET * + PUT 
               'C' J 'B' J GET R 'C' J 1 - GET * + S 'C' J 2 - GET * + PUT
            NEXT
            'C' n 1 + GET SQ 'C' n 2 + GET 'C' n GET * - \-> DEN
              \<< 'B' n 3 + GET 'C' n GET * 'B' n 2 + GET 'C' n
                   1 + GET * - DEN / DUP R + 'R' STO 
                   'C' n 2 + GET 'B' n 2 + GET * 'C' n 1 + GET 
                   'B' n 3 + GET * - DEN / DUP S + 'S' STO
              \>>
          UNTIL ABS .000000001 < SWAP ABS .000000001 < AND
          END 
          n 1 + DROPN 
          1 R NEG S NEG 3 \->LIST 
          3 n 1 +
          FOR J 
            'B' J GET
          NEXT n 1
          - \->LIST
        \>>
      \>>
\>>
  
QUD
\<< LIST\-> \->ARRY DUP 1 GET / ARRY\->
    DROP ROT DROP SWAP
    2 / NEG DUP SQ ROT
    - \v/ DUP2 + 3 ROLLD -
\>>

END

From comp.sys.handhelds Tue Apr 17 13:41:21 1990
Path: fauern!unido!mcsun!uunet!samsung!sdd.hp.com!elroy.jpl.nasa.gov!decwrl!ucbvax!EN.ECN.PURDUE.EDU!wscott
From: wscott@EN.ECN.PURDUE.EDU (Wayne H Scott)
Newsgroups: comp.sys.handhelds
Subject: POLY ROOTS version 2
Message-ID: <9004150431.AA01064@en.ecn.purdue.edu>
Date: 15 Apr 90 04:31:34 GMT
Sender: daemon@ucbvax.BERKELEY.EDU
Lines: 209
Status: OR


This is poly version 2.

The first version of the polynomial root finder that I posted was slow and it 
only worked on a 48sx without changes.  I have totally rewritten the solver
and now the main routine, BAIRS, is 3.8 times faster and 1/2 its previous size!

In addition, routines to do polynomal multiplication and division are now 
included.  Have fun!

This file is set up to be downloaded into a HP48sx but the programs should 
work just fine on a HP28. 

Please inform me of any bugs.

%%HP: T(3)A(R)F(.);

@ The following is a set of programs that I developed to find the roots of 
@ polynomials.  However as a bonus I also created a program to reduce any
@ polynomial into its quadratic factors.
@ 
@ The first program is FCTP. (factor polynomial)
@ When it is passed the cooeficients of a polynomial in a list it returns the
@ factor of that polynomal.  ex:
@ 
@ 1: { 1 -17.8 99.41 -261.218 352.611 -134.106 }
@ FCTP
@ 3: { 1 -4.2 2.1 }
@ 2: { 1 -3.3 6.2 }
@ 1: { 1 -10.3 }
@ 
@ This tells us that X^5-17.8*X^4+99.41*X^3-261.218*X^2+352.611*X-134.106
@ factors to (X^2-4.2*X+2.1)*(X^2-3.3*X+6.2)*(X-10.3)
@ 
@ Neat!
@ 
@ The next program is RT. (Roots)
@ If given a polynmoial it return its roots.  ex:
@ 
@ 1: { 1 -17.8 99.41 -261.218 352.611 -134.106 }
@ RT
@ 5: 3.61986841536
@ 4: .58013158464
@ 3: (1.65, 1.8648056199)
@ 2: (1.65, -1.8648056199)
@ 1: 10.3
@ 
@ Very Useful!
@
@ Another program that is included is PMUL to multiply two polys. ex:
@
@ 2: { 1 5 -7 }
@ 1: { 1 -5 }
@ PMUL
@ 1: { 1 0 -32 35 }
@
@ Unfortunatly PMUL will not work on a 28 as is.  When someone fixes this
@ send me a copy.
@
@ But wait theres more!  A program called PDIV is yours free just for trying 
@ this set of programs. Can you guess what it does?
@
@ 2: { 1 0 -32 36 }
@ 1: { 1 5 -7 }
@ PDIV
@ 2: { 1 -5 }
@ 1: { 0 1 }
@
@ This means that (X^3-32*X+35) / (X^2+5*X-7) = X-5 with remander 0*X+1 
@ 
@ These programs use the BAIRS program which performs Bairstow's method of
@ quadratic factors and QUD with does the quadratic equation.
@
@ Have Fun!
@ _____________________________________________________________________________
@ Wayne Scott            | INTERNET:   wscott@en.ecn.purdue.edu
@ Electrical Engineering | BITNET:     wscott%ea.ecn.purdue.edu@purccvm
@ Purdue University      | UUCP:      {purdue, pur-ee}!en.ecn.purdue.edu!wscott
@ _____________________________________________________________________________
@				"To iterate is human.  To recurse, divine."

DIR
  FCTP
\<<
   IF DUP SIZE 3 > THEN 
        DUP
	BAIRS
	SWAP OVER PDIV DROP
        FCTP
   END
\>>

RT
\<< DUP SIZE \-> n
   \<<
      IF n 3 > THEN 
	DUP
        BAIRS
	SWAP OVER PDIV DROP
        \-> A B \<< A RT B RT \>>
      ELSE
        IF n 2 > THEN 
           QUD
        ELSE
           LIST\-> DROP NEG SWAP /
        END
      END
   \>>
\>>

@ This program peforms polynomial multiplication by doing a convolution.

PMUL
\<< DUP2 SIZE SWAP SIZE \-> A B nB nA
    \<< { } 2 nB
       START
	  0 +
       NEXT
       DUP 'A' STO+ SWAP 'A' STO+	@ pad a with zeros
       A OBJ\-> \->ARRY B OBJ\-> DROP
       2 nB
       FOR J		@ reverse B
	 J ROLL
       NEXT
       3 nA nB +
       START
	 0
       NEXT
       nA nB 1 - 2 * + \->ARRY 		@and pad with zeros
       2 nA nB +
       START
	 DUP2 DOT 	@ do dot product and then rotate B
	 3 ROLLD OBJ\-> SWAP nA nB 1 - 2 * + 1 + ROLLD \->ARRY
       NEXT
       DROP2
       nA nB + 1 - \->LIST	@ put dot products into list
   \>>
\>>

@ This program is based on a program by LOZAN@TAUNOS.BITNET (Eliel Louzoun)
PDIV
\<<
   DUP SIZE 3 ROLLD LIST\-> \->ARRY SWAP LIST\-> \->ARRY \-> c b a
   \<<
     a b
     WHILE OVER SIZE 1 GET c \>= REPEAT
       DIVV
     END
     DROP \-> d 
     \<<
       a SIZE 1 GET c 1 - - \->LIST 
       d ARRY\-> LIST\-> DROP \->LIST
     \>>
  />>
/>>

@ BAIR is described by the following code.  A(3) to A(n+3) is the polynomal
@ and the result is { 1 -R -S }
@
@ R = S = 1       ; inital guess
@ B(1) = B(2) = C(1) = C(2) = 0
@ DO
@   FOR J = 3 TO n + 3 
@     B(J) = A(J) + R*B(J-1) + S*B(J-2)
@     C(J) = B(J) + R*C(J-1) + S*C(J-2)
@   NEXT J
@   DEN = C(n+1)*C(n+1) - C(n+2)*C(n)
@   DELR = (B(n+3)*C(n) - B(n+2)*C(n+1))/DEN
@   DELS = (C(n+2)*B(n+2) - C(n+1)*B(n+3))/DEN
@   R = R + DELR
@   S = S + DELS
@ UNTIL ABS(DELR) + ABS(DELS) < tol

BAIRS
\<< LIST\-> 1 1 \-> n R S
  \<<
    DO 
      0 n 1 + PICK 0 0 0 4 PICK 5 n + 7 
      FOR J 
        J PICK R 7 PICK * + S 8 PICK * + 7 ROLL DROP DUP 6 ROLLD
	R 3 PICK * + S 4 PICK * + 5 ROLL DROP 
      -1 STEP 
      3 PICK SQ 3 PICK 6 PICK * - 
				@ change 'X' STO+ to X + 'X' STO on a HP-28
      6 PICK 6 PICK * 5 PICK 9 PICK * - OVER / DUP 'R' STO+
      4 PICK 9 PICK * 8 PICK 7 PICK * - ROT / DUP 'S' STO+
    UNTIL R\->C ABS .000000001 < 7 ROLLD 6 DROPN
    END 
    n DROPN 1 R NEG S NEG 3 \->LIST
  \>>
\>>

QUD
\<< LIST\-> \->ARRY DUP 1 GET / ARRY\->
    DROP ROT DROP SWAP
    2 / NEG DUP SQ ROT
    - \v/ DUP2 + 3 ROLLD - 		@ \v/ is square root
\>>

DIVV		@ subroutine used by PDIV
\<<
   DUP 1 GET \-> a b c
   \<<
      a 1 GET c / DUP b * a SIZE RDM a SWAP - ARRY\-> 1 GETI 1 - PUT 
      \->ARRY SWAP DROP b
   \>>
\>>

END

From comp.sys.handhelds Tue Apr 17 13:41:54 1990
Path: fauern!unido!mcsun!uunet!cs.utexas.edu!usc!apple!dan
From: dan@Apple.COM (Dan Allen)
Newsgroups: comp.sys.handhelds
Subject: RPL Code for Lists/Sets, Rev 2
Keywords: RPL,HP-48SX,lists,sets,set operations
Message-ID: <40185@apple.Apple.COM>
Date: 10 Apr 90 17:09:32 GMT
References: <40175@apple.Apple.COM>
Distribution: comp.sys.handhelds
Organization: Apple Computer Inc, Cupertino, CA
Lines: 225
Status: OR


                    LIST and SET Operations for the HP-48SX
                         By Dan Allen, 10 April 1990
                                Revision 2

LIST PROCESSING
  The HP-48SX supports lists of objects as a built-in data type.  Several 
functions are provided for working on lists:

    Function     Operation
    --------     ---------
    +            Concatenates two lists into one list
    SIZE         Returns the number of elements in a list
    POS          Checks if an element is in a list
    SUB          Returns a subset of a list as a list
    GET          Returns the nth element of a list
    PUT          Replaces the nth element of a list

Other than direct editing of a list, there is no way to add elements to a list 
other than by appending elements to the front or back of a list through the + 
operator, and there is no way to delete elements of a list.
  Here are a few list operations that extend the functionality of the HP-48SX.  
Ideally these should be in a future machine; in the meantime they should be 
written in assembly language for better efficiency.
  The first two functions are CAR and CDR, named after the LISP functions of 
the same bizarre but historically interesting names.  Common LISP also has the 
functions FIRST and REST which are exactly the same as CAR and CDR, which 
return the first and remaining parts of a list.  The second pair of functions 
are INS and DEL, which allow inserting and deleting specific elements of a 
list.
  These routines handle invalid arguments quietly, i.e., deleting the 5th 
element of a 4 element list does nothing; it returns the 4 element list 
unchanged, without any error mentioned.  Similar handling of invalid 
conditions is done by the other routines as well.

LISTS AS SETS
  A list supports an ordering of its elements and can have duplicate members.  
Sets are not ordered and can only have one occurance of a given object.  With 
these restrictions, a list can be used as a set with various functions 
designed to support set operations.  Such functions are provided here, with 
many of the operations also being valid on lists as well.
  ADJOIN allows items to be added to a set.  ADJOIN makes sure that no 
duplicate entries are allowed in the list, thus enforcing one of the rules of 
sets.
  MEMBER tests set membership, that is, it checks to see if an object is 
included in a set (or list).  It only searches the top level.  It returns a 
CDR-like list beginning with the item found, or the empty list { } if the 
object is not found.
  UNION and INTERSECT implement set union and intersection, while DIFF and 
SDIFF are set difference and symmetric difference.  If the lists given are not 
sets (that is, they contain duplicates), duplicates may appear in the results.  
These four operations are the main arithmetic operations for sets, with the 
following similarities to arithmetic and boolean operations:

   ARITHMETIC            BOOLEAN            SET OPERATION
   ----------            -------            -------------
   addition (+)          OR (inclusive)     union
   subtraction (-)       AND NOT            difference
   multiplication (*)    AND                intersection
   division (/)          XOR                symmetric difference

EXAMPLES

{ 1 2 3 } CAR  -->  1                 { } CAR  -->  { }
{ 1 2 3 } CDR  -->  { 2 3 }           { } CDR  -->  { }

{ 1 2 3 } 1 0 INS  -->  { 0 1 2 3 }   { 1 2 } 9999 48 INS  -->  { 1 2 48 }
{ 1 2 3 } 2 DEL  -->  { 1 3 }         { 1 2 } 9999 DEL  -->  { 1 2 }

{ 1 2 3 } 2 MEMBER  -->  { 2 3 }      { 1 2 3 } 4 MEMBER  -->  { }
{ 1 2 } 3 ADJOIN  -->  { 1 2 3 }      { 1 2 3 } 3 ADJOIN  -->  { 1 2 3 }

{ 1 2 } { 3 4 } UNION --> {1 2 3 4}   { 1 2 } { 1 2 } UNION  -->  { 1 2 }
{ 1 2 } { 3 4 } INTERSECT --> { }     { 1 2 } { 2 3 } INTERSECT  -->  { 2 }
{ 1 2 } { 3 4 } DIFF --> { 1 2 }      { 1 2 } { 2 3 } DIFF  -->  { 1 }
{ 1 2 } { 3 4 } SDIFF --> {1 2 3 4}   { 1 2 } { 2 3 } SDIFF  -->  { 1 3 }

  Comments are bracketed by @ signs.  With minor changes, most of these 
programs should run on the HP-28.  Here then are some useful list and set 
operations for the HP-48SX:

CAR   @ Extracts the first object of a list as an atomic entity @
<<    @ USAGE:  list CAR  -->   obj   @
  IF DUP SIZE THEN 1 GET END  @ CAR of empty list is an empty list @
>>

CDR   @ Returns the tail (all but 1st object) of a list as a list @
<<    @ USAGE:  list CDR  -->  list   @
  OBJ->
  IF DUP
  THEN 1 - ->LIST SWAP DROP
  ELSE DROP { }   @ CDR of an empty list is the empty list @
  END
>>

INS   @ Inserts an object as the nth element of list @
<<    @ USAGE:  list integer obj INS  -->  list   @
  -> list n x
  <<
    list 1 n 1 - SUB x + list n list SIZE SUB +
  >>
>>

DEL   @ Deletes the nth element of list @
<<    @ USAGE:  list integer DEL  -->  list   @
  -> list n
  <<
    list 1 n 1 - SUB list n 1 + list SIZE SUB +
  >>
>>

MEMBER  @ Checks if obj is a member of list at the top level @
<<      @ USAGE:  list obj MEMBER  -->  list   @
  -> list obj
  <<
    list obj
    IF POS DUP 0 >
    THEN list SWAP list SIZE SUB
    ELSE DROP { }
    END
  >>
>>

ADJOIN  @ Adds an object to a list, preventing duplicates @
<<      @ USAGE:  list obj ADJOIN  -->  list   @
  -> list obj
  <<
    IF list obj MEMBER SIZE
    THEN list
    ELSE list obj +
    END
  >>
>>

UNION  @ Returns the set union of two lists (c = a OR b) @
<<     @ USAGE:  list list UNION  -->  list   @
  OVER -> a b c  @ efficiency tip: put smallest list on top of stack @
  <<
    IF a SIZE 0 == b SIZE 0 == OR
    THEN a b +  @ if either list is empty then concatenate lists @
    ELSE        @ step through the second list's elements @
      b 1 1 b SIZE
      START
        GETI DUP c SWAP
        IF POS
        THEN DROP
        ELSE 'c' SWAP STO+  @ adding appropriate new elements @
        END
      NEXT
      DROP2 c 
    END
  >>
>>

INTERSECT  @ Returns the set intersection of two lists (c = a AND b) @
<<         @ USAGE:  list list INTERSECT  -->  list   @
  { } -> a b c  @ efficiency tip: put smallest list on top of stack @
  <<
    IF a SIZE 0 == b SIZE 0 == OR
    THEN c
    ELSE
      b 1 1 b SIZE
      START
        GETI DUP a SWAP
        IF POS
        THEN 'c' SWAP STO+
        ELSE DROP
        END
      NEXT
      DROP2 c
    END
  >>
>>

DIFF  @ Returns the set difference of two lists (c = a AND NOT b) @
<<    @ USAGE:  list list DIFF  -->  list   @
  { } -> a b c
  <<
    IF a SIZE 0 == THEN c
    ELSE IF b SIZE 0 == THEN a
      ELSE
        a 1 1 a SIZE
        START
          GETI DUP b SWAP
          IF POS
          THEN DROP
          ELSE 'c' SWAP STO+
          END
        NEXT
        DROP2 c
      END
    END
  >>
>>

SDIFF  @ Returns the set symmetric difference between two lists (c = a XOR b) 
@
<<     @ USAGE:  list list SDIFF  -->  list   @
  { } -> a b c   @ Efficiency note: this is O(n^2) and could be improved @
  <<
    IF a SIZE 0 == THEN b         @ if a is empty, then return b @
    ELSE IF b SIZE 0 == THEN a    @ if b is empty, then return a @
      ELSE                        @ else loop through both lists @
        a 1 1 a SIZE     
        START
          GETI DUP b SWAP
          IF POS
          THEN DROP
          ELSE 'c' SWAP STO+
          END
        NEXT
        DROP2
        b 1 1 b SIZE
        START
          GETI DUP a SWAP
          IF POS
          THEN DROP
          ELSE 'c' SWAP STO+
          END
        NEXT
        DROP2 c
      END
    END
  >>
>>

From comp.sys.handhelds Tue Apr 17 13:42:55 1990
Path: fauern!unido!mcsun!uunet!snorkelwacker!think!zaphod.mps.ohio-state.edu!sdd.hp.com!hp-pcd!hpcvra!prestonb
From: prestonb@hpcvra.CV.HP.COM (Preston Brown)
Newsgroups: comp.sys.handhelds
Subject: Re: Transfer HP28 -> HP48SX via IR
Message-ID: <21580062@hpcvra.CV.HP.COM>
Date: 12 Apr 90 16:45:24 GMT
References: <312@unlisys.UUCP>
Organization: Hewlett-Packard Co., Corvallis, OR, USA
Lines: 172
Status: OR


# Okay here it is again.  This is the HP program INPRT that allows
# the 48SX to read printer output from the 28 or any other product
# that prints to the HP IR printer.
#
# This is a binary program that you must download to run.  If you
# are downloading it directly form a unix machine you must say:
# set file type binary
# in the unix kermit before downloading it.


# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Preston Brown <prestonb@hpcvda> on Wed Mar 14 09:54:17 1990
#
# This archive contains:
#	inprt		inprt.txt	
#

LANG=""; export LANG
PATH=/bin:/usr/bin:$PATH; export PATH


rm -f /tmp/uud$$
(echo "begin 777 /tmp/uud$$\n \nend" | uudecode) >/dev/null 2>&1
if [ -f /tmp/uud$$ ]
then
	rm -f /tmp/uud$$
	unpacker=uudecode
else
	echo Compiling unpacker for non-ascii files
	pwd=`pwd`; cd /tmp
	cat >unpack$$.c <<-'EOF'
	#include <stdio.h>
	#define DEC(c)	(((c) - ' ') & 077)
	main()
	{
		int n;
		char dest[128], a,b,c,d;

		scanf("begin %o ", &n);
		gets(dest);

		if (freopen(dest, "w", stdout) == NULL) {
			perror(dest);
			exit(1);
		}

		while ((n=getchar()) != EOF && (n=DEC(n))!=0)  {
			while (n>0) {
				a = DEC(getchar());
				b = DEC(getchar());
				c = DEC(getchar());
				d = DEC(getchar());
				if (n-- > 0) putchar(a << 2 | b >> 4);
				if (n-- > 0) putchar(b << 4 | c >> 2);
				if (n-- > 0) putchar(c << 6 | d);
			}
			n=getchar();
		}
		exit(0);
	}
	EOF
	cc -o unpack$$ unpack$$.c
	rm unpack$$.c
	cd $pwd
	unpacker=/tmp/unpack$$
fi

echo x - inprt '[non-ascii]'
$unpacker <<'@eof'
begin 666 inprt
M2%!(4#0X+4*=+="$&!6*P=P">@6 OWD&^#YA@/3X!FC0.O00 .Y$@Y$O 8E?
M$0$(^/B]&Q"1^'E;H"\!+#1@!89?#@'8JF6 'V<6\0L!$/0(B!74^(\;@%\.
M 1& ;R94^)MG$,$-J$[@A,U7 T(#<P52JSFMD+,%.W6], 2  +<;U8*A WJT
M40TYO]%WDQ"AQPB][^ 31P@1[!; $W]=$<%,/@'1&<1A@4_' )02OQ  08^ 
M6 I,#0B8I<!5$-2V]<;P<"PQ%3620@!P Z)SA:#@M)CS\1;YX),-ZG3)#U-F
M-9#*_ZRI^<R?.F!5!L.?JOE<!C-@934 4_:LF<KOO8C;?B010D<7(G'4CKOH
M+7%$%[+HW8Z+V^Z]&$)W)'$D$4+GO8C;WHZ[Z$T7(G&TZ-V.*W%$%Q)"=R2!
MV^Z]F,K_K E39C4P8%4&H_G,GUH&,V#%GZKY_*R9RF\U %.F<P2 D2,Y+P\#
MQX*QHU,ZMW-*7_,@0!V*)3^P LJG.TAP.$+X=R44?U!"Z@@HQ 0 :DR[44=*
M5O)JQ'28;[EAM6&Q8:UAJ6&E8:%AG6&9895AD6&-88EAA6&!87UA>6&W8;-A
MKV&K8:=AHV&?89MAEV&388]ABV&'88-A?V%[87=A'6$9815A$6$-80EA!6$!
M8?U@^6#U8/%@[6#I8.5@X6"/8(M@AV"#8']@>V!W8'-@;V!K8&=@8V!?8%M@
M5V!38--@SV#+8,=@PV"_8+M@MV"S8*^ !@ (*-&B)FI>_%%'2E8(.KUS(( &
M5 @,D!,5.X4%2D^_:E[\44=*5A$(V#N'!@4ZS<47=11U%'5D.HX&)P@,$Q)(
M8+:/!CHE,/%PBH $]3GQ<'Q0CH &@E,"   +H3 3$O;WYMJ !]$%W*DK\1H!
MP$X344=*5O,3&N0!!S.AH.8$$'6D9"4_L:'FQ1]UI&0% *)3"Z=S2E\ <""_
MC3$B RPJ4!  (/?7@X2%AH>(B8J+C(V.M7^PJ[M_?W^RLW]_?W]_?W^ P,+(
MRLO.S[1@7JA^V=NCK]W]L,?GT?&AOZ2CI:=FHN+J]/OAZ?/ZX.CR^>3K]OS%
M[MC&Y>WXYL3LUMS)[]_4P</CT/#-S-/2U?53<]I9_][^M[6VOBV\O:JZJYZ[
*L:#Y(S,B RLQ -S)
 
end
@eof

chmod 666 inprt

echo x - inprt.txt '[non-ascii]'
$unpacker <<'@eof'
begin 666 inprt.txt
M#0H-"B @(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @24Y04E0N5%A4
M($9I;&4-"@T*(" @(" @(" @(" @(" @(" @(" H8RD@($AE=VQE='0M4&%C
M:V%R9"!#;VUP86YY+" Q.3DP#0H-"@T*3U9%4E9)15<-"BTM+2TM+2TM#0H-
M"E1H92!)3E!25"!A<'!L:6-A=&EO;B!R96%D<R!I;F9R87)E9" H25(I('!R
M:6YT97(@;W5T<'5T(&9R;VT@9&EF9F5R96YT#0I(97=L971T+5!A8VMA<F0@
M8V%L8W5L871O<G,@:6YT;R!T:&4@2% @-#@@<W1A8VLN("!)3E!25"!A<W-U
M;65S('1H870@=&AE#0II;F-O;6EN9R!B>71E<R!W;W5L9"!P<FEN="!W:71H
M('1H92!2;VUA;B X(&-H87)A8W1E<B!S970@;VX@86X@2% @.#(R-# -"G!R
M:6YT97(L(&%N9"!I="!R96UA<',@=&AE<V4@8GET97,@=&\@=&AE($A0(#0X
M(&-H87)A8W1E<B!S970@*$E33R X.#4Y#0I,871I;B Q*2X-"@T*#0I04D]#
M14154D4-"BTM+2TM+2TM+0T*#0I4:&5S92!A<F4@=&AE('-T97!S(&9O<B!T
M<F%N<V9E<G)I;F<@25(@<')I;G1E<B!O=71P=70@=&\@=&AE($A0(#0X.@T*
M#0H@,2X@(%1R86YS9F5R('1H92!)3E!25"!F:6QE(&9R;VT@>6]U<B!C;VUP
M=71E<B!T;R!T:&4@2% @-#@N("A5<V4@8FEN87)Y( T*(" @("!I9B!Y;W4G
M<F4@=')A;G-F97)R:6YG($E.4%)4(&9R;VT@=&AE($A0(#0X+BD@5&AE('M)
M3E!25'T@;65N=2!L86)E; T*(" @("!W:6QL("!S:&]W('5P(&EN('EO=7(@
M2% @-#@@5D%2(&UE;G4N#0H-"B R+B @3&EN92!U<"!T:&4@8V%L8W5L871O
M<G,N(" H4V5E(")!;&EG;FUE;G0@26YS=')U8W1I;VYS(B!B96QO=RXI#0H-
M"B S+B @4')E<W,@>TE.4%)4?2!O;B!T:&4@2% @-#@N(" H24Y04E0@=&5R
M;6EN871E<R!I;B Q,"!S96-O;F1S(&EF(&YO($E2#0H@(" @(&]U='!U="!I
M<R!R96-E:79E9"XI#0H-"B T+B @17AE8W5T92!T:&4@<')I;G0@8V]M;6%N
M9"!O;B!T:&4@;W1H97(@8V%L8W5L871O<BX-"@T*(#4N("!297!E870@<W1E
M<',@,B!T:')O=6=H(#0@87,@;F5E9&5D('1O('1R86YS9F5R(&%D9&ET:6]N
M86P@;W5T<'5T+@T*#0I215-53%13#0HM+2TM+2TM#0H-"E=H96X@=&AE('1R
M86YS9F5R(&ES(&-O;7!L971E+"!T:&4@2% @-#@@<F5T=7)N<R!T:&4@<F5C
M96EV960@9&%T82!T;R!T:&4-"G-T86-K(&EN('1H92!F;W)M(&]F(&$@<W1R
M:6YG('1O(&QE=F5L(#(@86YD(&$@9FQA9R!T;R!L979E;" Q+B @268@=&AE
M(&9L86<-"FES(# L('5N8V]R<F5C=&%B;&4@=')A;G-F97(@97)R;W)S('=E
M<F4@9&5T96-T960[(&EF('1H92!F;&%G(&ES(#$L('1H97)E#0IS=&EL;"!M
M87D@8F4@;6ES<VEN9R!B>71E<RX@5&AE(#$@;65A;G,@=&AA="!E86-H(&)Y
M=&4@=&AA="!W87,@9&5T96-T960@=V%S#0IR96-E:79E9"!C;W)R96-T;'DN
M("!9;W4@<VAO=6QD('-T:6QL(&-H96-K('1H92!R96-E:79E9"!D871A('-I
M;F-E('1H97)E#0IM87D@8F4@82!L:6YE9F5E9"!I;B!S=')I;F=S+"!N86UE
M<RP@97AP<F5S<VEO;G,L(&5T8RX@;6]R92!T:&%N(#(T#0IC:&%R86-T97)S
M(&QO;F<N($EF('1H92!F;&%G(&ES(# L(&5A8V@@8GET92!T:&%T('=A<R!N
M;W0@8V]R<F5C=&%B;&4@:7,@82!G<F%Y#0IB;&]T("AC:&%R86-T97(@;G5M
M8F5R(#$R-RD@:6X@=&AE(&QE=F5L(#(@<W1R:6YG+@T*#0H-"D%,24=.345.
M5"!)3E-44E5#5$E/3E,-"BTM+2TM+2TM+2TM+2TM+2TM+2TM+2T-"@T*5&AE
M('1R86YS;6ET=&EN9R!C86QC=6QA=&]R)W,@3$5$(&UU<W0@8F4@86QI9VYE
M9"!W:71H('1H92!(4" T."=S('!H;W1O+0T*=')A;G-I<W1O<BP@=VAI8V@@
M:7,@;&]C871E9"!A="!T:&4@=&]P(&5N9"!O9B!T:&4@2% @-#@L(&EN(&QI
M;F4@=VET:"!T:&4-"F9I<G-T(%0@:6X@=&AE($A%5TQ%5%0@<&%R="!O9B!T
M:&4@2$573$545"U004-+05)$(&QO9V\N("!4:&4@8V%L8W5L871O<G,-"G-H
M;W5L9"!B92!N;R!M;W)E('1H86X@,"XU(&EN8VAE<R H,2XS(&-M*2!A<&%R
M="!F;W(@=&AE('1R86YS;6ES<VEO;BX@($%L<V\L#0IO=&AE<B!A;&EG;FUE
M;G0@:7-S=65S(&%P<&QY('1O('-E=F5R86P@8V%L8W5L871O<G,L(&%S(&9O
M;&QO=W,Z#0H-"B @;R @1F]R('1H92!(4" T,3H@(%1H92!)4B!P<FEN=&5R
M(&UO9'5L92!S:&]U;&0@8F4@:6X@;VYE(&]F('1H92!T;W -"B @(" @<&]R
M=',L(&%N9"!T:&4@<VAI;GD@(DE2(&-O;F4B(&EN('1H92!C96YT97(@;V8@
M=&AE(&UO9'5L92!S:&]U;&0@8F4@#0H@(" @(&%L:6=N960@=VET:"!T:&4@
M2% @-#@G<R!S;6%L;"!T<FEA;F=U;&%R(&EN9&EC871O<B!A8F]V92!T:&4@
M9&ES<&QA>2X-"@T*("!O("!&;W(@=&AE($A0(#(W4RP@2% @,3="+"!A;F0@
M2% @-#)3.B @5&AE(&-A;&-U;&%T;W(@;75S="!B92!R86ES960@,"XS#0H@
M(" @(&EN8VAE<R H,"XW-2!C;2DN(%1H92!C96YT97(@;V8@=&AE($Q%1" H
M=VAI8V@@:7,@;&]C871E9"!A="!T:&4@=&]P(&5N9" -"B @(" @;V8@=&AE
M(&-A;&-U;&%T;W(@:6X@;&EN92!B971W965N('1H92!%(&%N9"!7(&]F($A%
M5TQ%5%0I('-H;W5L9"!B92 -"B @(" @86QI9VYE9"!W:71H('1H92!(4" T
M."=S('-M86QL('1R:6%N9W5L87(@:6YD:6-A=&]R(&%B;W9E('1H92!D:7-P
M;&%Y+@T*#0H@(&\@($9O<B!T:&4@2% @,C@L($A0(#$X0RP@86YD($A0+3$Y
M0CH@($IU<W0@;&EN92!U<"!T:&4@8V%L8W5L871O<B=S($Q%1" -"B @(" @
M=VET:"!T:&4@2% @-#@G<R!S;6%L;"!T<FEA;F=U;&%R(&EN9&EC871O<B!A
38F]V92!T:&4@9&ES<&QA>2X-"F%L
 
end
@eof

chmod 666 inprt.txt

rm -f /tmp/unpack$$
exit 0

From ryoder Thu Apr 19 10:27:44 1990
~Date: Thu, 19 Apr 90 00:06:10 -0500
~From: ryoder@en.ecn.purdue.edu (Robert W Yoder)
To: wscott
Status: OR

This is pretty simple stuff, but what the heck.
I prefer to keep them in vectors, but they could be easily modified for lists.

These are a few routines for manipulating polynomials in vector form
where [ 1 -2 1 ] represents 'X^2-2*X+1'.


Evaluation of polynomial vectors.

input level 2: vector                 [ 1 2 1]
input level 1: value of variable             5

output level 1: value of function           36

EVPLY
<< OVER SIZE 1 GET -> a r n
   << a 1 GET
      2 n FOR i r * a i GET + NEXT
   >>
>>


Derivative of polynomial vectors.

input level 1: vector                 [ 1 2 1]

output level 1: derivative of vector   [ 2 2 ]

DDX[4784]
<< -> a
   << a SIZE 1 GET
      -> s
      << 1 s 1 - FOR n s n - a n GET * NEXT
         s 1 -
         DUP
         1
         IFTE
         ->ARRY
>> >> >>


Newton's Method for finding root

input level 2: vector                   [ 1 2 1]
input level 1: estimate of root                0

output level 2: vector                  [ 1 2 1]
output level 1: closer estimate of root       .5

NWT[62EF]
<< -> a r
   << a r a r EVPLY a DDX r EVPLY / -
   >>
   ROUN  ;optional, but improves convergence to true value
>>

From comp.sys.handhelds Thu Apr 26 12:20:56 1990
Path: fauern!ira.uka.de!sol.ctr.columbia.edu!cica!iuvax!mailrus!cs.utexas.edu!usc!samsung!munnari.oz.au!goanna!dmh
From: dmh@goanna.cs.rmit.OZ.AU (Darren Hosking)
Newsgroups: comp.sys.handhelds
Subject: 48SX machine code screen inverter
Message-ID: <3125@goanna.cs.rmit.OZ.AU>
Date: 26 Apr 90 01:46:15 GMT
Organization: Comp Sci, RMIT, Melbourne, Australia
Lines: 59
Status: OR


Here is my first machine code program. It simply inverts (reverse video) the
entire stack display (except for the menu keys).

I have included the uuencoded binary which (once uudecoded) can be downloaded
and run "as is" (set translation to 0 in the I/O setup menu).

Checksum: #9F33h Bytes: 38.5
begin 644 i
I2%!(4#0X+4',+=`#`#$&-L27<#&&@$)\`1!D[T$41LPE#Q=C01)&",@`
`
end

If you can't load the above for some reason you can use the following:

%%HP: T(3);
{
# 3606310003D02DCCh
# 7C428086317097C4h
# CC461441EF641001h
# 0846124163170F25h
# C8h
}

Place the above list in stack level 1 and run:

The ->SYS program was written by Rick Grevelle.
It expects a list of hex integers and converts them into an object.

\->SYS
   \<<
      " "  +  LIST\->  2 SWAP
      START #5193h  SYSEVAL
      NEXT  #4003h  SYSEVAL
      #56B6h SYSEVAL DROP
   \>>

Then store this in I.

Running I standalone causes the current stack display to be momentarily inverted
and then restored so you will need to use it in a program to make the inverted
screen persist (eg freeze). The following program expects the screen invert
program to be stored in I and simply calls I and freezes the display until
the next key press.

IN
\<< I 3 FREEZE \>>

As usual with machine code hacking, make sure you have backed up
(or written down :-) anything you don't want to lose before attempting the
above incase anything goes wrong.

	dmh

Darren Hosking				ACSnet: dmh@goanna.oz	 
Department Of Computer Science		ARPA:   dmh%goanna.oz.au@uunet.uu.net
RMIT					CSNET:  dmh%goanna.oz.au@australia
GPO Box 2476V				UUCP:   ...!uunet!goanna.oz.au!dmh
Melbourne Vic., Australia 3001

From comp.sys.handhelds Thu Apr 26 12:23:58 1990
Path: fauern!sun1.ruf.uni-freiburg.de!ira.uka.de!sol.ctr.columbia.edu!lll-winken!elroy.jpl.nasa.gov!ncar!cruff
From: cruff@ncar.ucar.edu (Craig Ruff)
Newsgroups: comp.sys.handhelds
Subject: Saturn (HP48 CPU) disassembler part 1 of 2
Message-ID: <7124@ncar.ucar.edu>
Date: 26 Apr 90 01:02:43 GMT
Reply-To: cruff@ncar.UCAR.EDU (Craig Ruff)
Organization: Scientific Computing Division/NCAR, Boulder CO
Lines: 1074
Status: OR

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	README
#	Makefile
#	Makefile.mac
#	append.c
#	capture.c
#	cvt.c
#	dis48.c
#	dis48.h
#	disasm.c
#	dobj.c
# This archive created: Wed Apr 25 19:00:04 1990
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'README'" '(1410 characters)'
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
XThis shar archive contains a rudimentary disassembler for the Saturn CPU used
Xin the HP48SX (and other HP handhelds), as well as some utility routines.
XThe programs that can be built are:
X
X	dis48		- disassemble a specified range
X	trace		- trace and disassemble starting at an address
X	dobj		- disassemble object (incomplete)
X
X	cvt		- convert a memory upload (via memory scanner)
X			  to binary file useable by dis48 and trace
X	capture		- Macintosh C program to capture memory upload
X			  (for use by cvt) from an HP48 in memory scan
X			  mode when the SPC key is pressed
X
X	Makefile	- Unix makefile
X	Makefile.mac	- Macintosh MPW makefile
X
XThe programs dis48, trace and dobj share most of the other files.
XThe output is similar to the mnemonics used by Alonzo Gariepy with the
Xfollowing (macro defined) modifications:
X
X	Hexadecimal numbers have a '$' prefixed.
X
X	Immediate values have a '#' prefixed.
X
X	PC-relative instructions have the format:
X
X		pc+offset (absolute addr)
X
X
XNote that most illegal instructions are probably not noticed.
XAll of these programs are quick hacks, and can undoubtedly stand improvements.
X
XThe output (on stdout) of the trace program, when started at address 0 results
Xin approximately 80 pages of code discovered by tracing branch and calls
Xas far as possible without emulating the CPU.  The error output (on stderr)
Xis a list of addresses that are the targets of call instructions.
SHAR_EOF
if test 1410 -ne "`wc -c < 'README'`"
then
	echo shar: "error transmitting 'README'" '(should have been 1410 characters)'
fi
fi
echo shar: "extracting 'Makefile'" '(330 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
XOBJS =	append.o disasm.o get.o instr.o instr1.o instr8.o
X
Xdis48:	dis48.o $(OBJS)
X	cc -o dis48 dis48.o $(OBJS)
X	
Xtrace:	trace.o $(OBJS)
X	cc -o trace trace.o $(OBJS)
X
Xdobj:	dobj.o obj.o $(OBJS)
X	cc -o dobj dobj.o obj.o $(OBJS)
X
Xdis48.o trace.o dobj.o obj.o $(OBJS):	dis48.h
X
Xcvt:	cvt.o
X	cc -o cvt cvt.o
X
Xclean:
X	rm -f $(OBJS) dis48
SHAR_EOF
if test 330 -ne "`wc -c < 'Makefile'`"
then
	echo shar: "error transmitting 'Makefile'" '(should have been 330 characters)'
fi
fi
echo shar: "extracting 'Makefile.mac'" '(1379 characters)'
if test -f 'Makefile.mac'
then
	echo shar: "will not over-write existing file 'Makefile.mac'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile.mac'
XOBJS =	append.c.o disasm.c.o get.c.o instr.c.o instr1.c.o instr8.c.o obj.c.o
X
XCOptions = -sym on
X
Xdis48	D	main.c.o {OBJS}
X	Link -d -sym on -o dis48 -t MPST -c 'MPS ' 6
X		main.c.o {OBJS} 6
X		"{Libraries}"Stubs.o 6
X		"{CLibraries}"CRuntime.o 6
X		"{CLibraries}"StdCLib.o 6
X		"{CLibraries}"CInterface.o 6
X		"{Libraries}"Interface.o 6
X		"{Libraries}"ToolLibs.o
X
Xmain.c.o q.c.o {OBJS}	D	dis48.h
X
Xclean D
X	Delete -i {OBJS}
X	
Xq	D	q.c.o {OBJS}
X	Link -d -sym on -o q -t MPST -c 'MPS ' 6
X		q.c.o {OBJS} 6
X		"{Libraries}"Stubs.o 6
X		"{CLibraries}"CRuntime.o 6
X		"{CLibraries}"StdCLib.o 6
X		"{CLibraries}"CInterface.o 6
X		"{Libraries}"Interface.o 6
X		"{Libraries}"ToolLibs.o
X
X
Xcapture	D	capture.c.o
X	Link -d -o capture -t MPST -c 'MPS ' 6
X		capture.c.o 6
X		"{Libraries}"Stubs.o 6
X		"{CLibraries}"CRuntime.o 6
X		"{CLibraries}"StdCLib.o 6
X		"{CLibraries}"CInterface.o 6
X		"{Libraries}"Interface.o 6
X		"{Libraries}"ToolLibs.o
X
Xcvt	D	cvt.c.o
X	Link -d -o cvt -t MPST -c 'MPS ' 6
X		cvt.c.o 6
X		"{Libraries}"Stubs.o 6
X		"{CLibraries}"CRuntime.o 6
X		"{CLibraries}"StdCLib.o 6
X		"{CLibraries}"CInterface.o 6
X		"{Libraries}"Interface.o 6
X		"{Libraries}"ToolLibs.o
X
Xt	D	t.c.o {OBJS}
X	Link -d -o t -t MPST -c 'MPS ' 6
X		t.c.o {OBJS} 6
X		"{Libraries}"Stubs.o 6
X		"{CLibraries}"CRuntime.o 6
X		"{CLibraries}"StdCLib.o 6
X		"{CLibraries}"CInterface.o 6
X		"{Libraries}"Interface.o 6
X		"{Libraries}"ToolLibs.o
X
SHAR_EOF
if test 1379 -ne "`wc -c < 'Makefile.mac'`"
then
	echo shar: "error transmitting 'Makefile.mac'" '(should have been 1379 characters)'
fi
fi
echo shar: "extracting 'append.c'" '(3292 characters)'
if test -f 'append.c'
then
	echo shar: "will not over-write existing file 'append.c'"
else
sed 's/^X//' << \SHAR_EOF > 'append.c'
X#include "dis48.h"
X
Xchar *
X#ifdef ANSI
XAppend16(char *buf, int n)
X#else
XAppend16(buf, n)
Xchar	*buf;
Xint	n;
X#endif
X{
X	if (++n > 9) {
X		APPEND_CHAR(buf, '1');
X		n -= 10;
X	}
X	
X	APPEND_BDIGIT(buf, n);
X	TERMINATE(buf);
X	return(buf);
X}
X
Xchar *
X#ifdef ANSI
XAppendAddr(char *buf, NAddr addr)
X#else
XAppendAddr(buf, addr)
Xchar	*buf;
XNAddr	addr;
X#endif
X{
X	int	mask, shift;
X	
X	APPEND_HEXMARK(buf);
X	for (mask = 0xf0000, shift = 16; mask != 0; mask >>= 4, shift -= 4)
X		APPEND_CHAR(buf, hex[(addr & mask) >> shift]);
X	
X	TERMINATE(buf);
X	return(buf);
X}
X
Xchar *
X#ifdef ANSI
XAppendRAddr(char *buf, NAddr pc, int disp, int n, int offset)
X#else
XAppendRAddr(buf, pc, disp, n, offset)
Xchar	*buf;
XNAddr	pc;
Xint	disp;
Xint	n;
Xint	offset;
X#endif
X{
X	int	sign;
X	
X	sign = 1 << (n * 4 - 1);
X	if (disp & sign)
X		disp |= ~(sign - 1);
X		
X	pc += disp;
X	target = pc;
X	buf = AppendStr(buf, "pc");
X	if (disp < 0) {
X		APPEND_CHAR(buf, '-');
X		disp = -disp - offset;
X	} else {
X		APPEND_CHAR(buf, '+');
X		disp += offset;
X	}
X		
X	buf = AppendAddr(buf, disp);
X	buf = AppendStr(buf, " (");
X	buf = AppendAddr(buf, pc);
X	APPEND_CHAR(buf, ')');
X	TERMINATE(buf);
X	return(buf);
X}
X
Xchar *
X#ifdef ANSI
XAppendField(char *buf, Nybble fn)
X#else
XAppendField(buf, fn)
Xchar	*buf;
XNybble	fn;
X#endif
X{
X	while (*buf != '\0')
X		buf++;
X		
X	APPEND_CHAR(buf, '.');
X	switch (fn) {
X	case 1: APPEND_CHAR(buf, 'x'); /* fall through */
X	case 0: APPEND_CHAR(buf, 'p'); break;
X	case 2:
X	case 3:
X		APPEND_CHAR(buf, 'x');
X		if (fn == 3)
X			break;
X			
X		/* fall through */
X	case 4: APPEND_CHAR(buf, 's'); break;
X	case 5: APPEND_CHAR(buf, 'm'); break;
X	case 6: APPEND_CHAR(buf, 'b'); break;
X	case 7: APPEND_CHAR(buf, 'w'); break;
X	case 0xf: APPEND_CHAR(buf, 'a'); break;
X	default: APPEND_CHAR(buf, '?'); break;
X	}
X	
X	APPEND_TAB(buf);
X	TERMINATE(buf);
X	return(buf);
X}
X
Xchar *
X#ifdef ANSI
XAppendHexNyb(char *buf, char *mem, NAddr *addr, int n)
X#else
XAppendHexNyb(buf, mem, addr, n)
Xchar	*buf;
Xchar	*mem;
XNAddr	*addr;
Xint	n;
X#endif
X{
X	int	i;
X	Nybble	t[16];
X	
X	APPEND_HEXMARK(buf);
X	for (i = 0; i < n; i++)
X		t[i] = GetNybble(mem, (*addr)++);
X	
X	while (--i >= 0)
X		APPEND_CHAR(buf, hex[t[i]]);
X
X	TERMINATE(buf);
X	return(buf);
X}
X
Xchar *
X#ifdef ANSI
XAppendDecInt(char *buf, int n)
X#else
XAppendDecInt(buf, n)
Xchar	*buf;
Xint	n;
X#endif
X{
X	int	i;
X	char	b[9];
X	
X	if (n < 0) {
X		APPEND_CHAR(buf, '-');
X		n = -n;
X	}
X	
X	for (i = 0; n != 0; i++, n /= 10)
X		b[i] = n % 10 + '0';
X	
X	while (--i >= 0)
X		APPEND_CHAR(buf, b[i]);
X
X	TERMINATE(buf);
X	return(buf);
X}
X
Xchar *
X#ifdef ANSI
XAppendImmNyb(char *buf, char *mem, NAddr *addr, int n)
X#else
XAppendImmNyb(buf, mem, addr, n)
Xchar	*buf;
Xchar	*mem;
XNAddr	*addr;
Xint	n;
X#endif
X{
X	APPEND_IMMMARK(buf);
X	return(AppendHexNyb(buf, mem, addr, n));
X}
X
X#define NSTBIT	4
Xchar	*StBitStr[NSTBIT] = {"xm", "sb", "sr", "mp"};
X
Xchar *
X#ifdef ANSI
XAppendStBits(char *buf, int n)
X#else
XAppendStBits(buf, n)
Xchar	*buf;
Xint	n;
X#endif
X{
X	int	i;
X	char	*p, *q;
X	
X	for (p = buf, i = 0; i < NSTBIT; i++)
X		if (n & (1 << i)) {
X			if (p != buf) {
X				APPEND_COMMA(p);
X			}
X			
X			/* p = AppendStr(p, StBitStr[i]); */
X			q = StBitStr[i];
X			while (*p = *q++)
X				p++;
X		}
X	
X	TERMINATE(p);
X	return(p);
X}
X
Xchar *
X#ifdef ANSI
XAppendStr(char *buf, char *str)
X#else
XAppendStr(buf, str)
Xchar	*buf;
Xchar	*str;
X#endif
X{
X	while (*buf = *str++)
X		buf++;
X	
X	return(buf);
X}
SHAR_EOF
if test 3292 -ne "`wc -c < 'append.c'`"
then
	echo shar: "error transmitting 'append.c'" '(should have been 3292 characters)'
fi
fi
echo shar: "extracting 'capture.c'" '(1634 characters)'
if test -f 'capture.c'
then
	echo shar: "will not over-write existing file 'capture.c'"
else
sed 's/^X//' << \SHAR_EOF > 'capture.c'
X#include <stdio.h>
X#include <fcntl.h>
X#include <errno.h>
X#include <Errors.h>
X#include <Devices.h>
X#include <Serial.h>
X
X#define BSIZE	102400
X
Xmain(int argc, char **argv)
X{
X	short	ref;
X	short	config;
X	int	count;
X	int	fd;
X	OSErr	err;
X	char	*buf, *buf2, *malloc();
X	
X	if ((buf = malloc(BSIZE)) == NULL) {
X		fprintf(stderr, "malloc failed\n");
X		exit(1);
X	}
X	
X	if ((buf2 = malloc(BSIZE)) == NULL) {
X		fprintf(stderr, "malloc (2) failed\n");
X		goto free1;
X	}
X	
X	if ((err = RamSDOpen(sPortA)) != noErr) {
X		fprintf(stderr, "RAMSDOpen = %d\n", err);
X		goto free2;
X	}
X	
X	if ((err = OpenDriver("\P.AIn", &ref)) != noErr) {
X		fprintf(stderr, "OpenDriver = %d\n", err);
X		goto free2;
X	}
X	
X	config = baud9600 | stop10 | noParity | data8;
X	if ((err = SerReset(ref, config)) != noErr) {
X		fprintf(stderr, "SerReset = %d\n", err);
X		goto done;
X	}
X	
X	if ((err = SerSetBuf(ref, (Ptr) buf, BSIZE)) != noErr) {
X		fprintf(stderr, "SerSetBuf = %d\n", err);
X		goto done;
X	}
X	
X	fprintf(stderr, "Ready\n");
X	count = BSIZE;
X	if ((err = FSRead(ref, &count, (Ptr) buf2)) != noErr)
X		fprintf(stderr, "FSRead = %d\n", err);
X	
X	fprintf(stderr, "Read %d bytes\n", count);
X	if ((err = SerSetBuf(ref, (Ptr) nil, 0)) != noErr)
X		fprintf(stderr, "SerSetBuf (2) = %d\n", err);
X		
Xdone:
X	if ((err = CloseDriver(ref)) != noErr)
X		fprintf(stderr, "CloseDriver = %d\n", err);
X
X	RamSDClose(sPortA);
X	if ((fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC)) < 0) {
X		fprintf(stderr, "open = %d\n", errno);
X		goto free2;
X	}
X	
X	if (write(fd, buf2, count) != count)
X		fprintf(stderr, "write = %d\n", errno);
X		
X	(void) close(fd);
Xfree2:	
X	free(buf2);
Xfree1:
X	free(buf);
X	exit(0);
X}
SHAR_EOF
if test 1634 -ne "`wc -c < 'capture.c'`"
then
	echo shar: "error transmitting 'capture.c'" '(should have been 1634 characters)'
fi
fi
echo shar: "extracting 'cvt.c'" '(1630 characters)'
if test -f 'cvt.c'
then
	echo shar: "will not over-write existing file 'cvt.c'"
else
sed 's/^X//' << \SHAR_EOF > 'cvt.c'
X#include "dis48.h"
X#include <errno.h>
X
Xvoid
X#ifdef ANSI
XStuffNybble(char *mem, NAddr addr, Nybble n)
X#else
XStuffNybble(mem, addr, n)
Xchar	*mem;
XNAddr	addr;
XNybble	n;
X#endif
X{
X	char	t;
X	
X	t = mem[addr >> 1] & ((addr & 1) ? 0x0f : 0xf0);
X	n &= 0xf;
X	if (addr & 1)
X		n <<= 4;
X		
X	mem[addr >> 1] = t | n;
X}
X
X#define SIZE	262144
X
X#ifdef ANSI
Xmain(int argc, char **argv)
X#else
Xmain(argc, argv)
Xint	argc;
Xchar	**argv;
X#endif
X{
X	char	*p;
X	int	n;
X	FILE	*fp;
X	NAddr	addr, a;
X	char	buf[25];
X	char	*mem, *malloc();
X	
X	if ((mem = malloc(SIZE)) == NULL) {
X		fprintf(stderr, "malloc failed\n");
X		exit(1);
X	}
X	
X	argc--;
X	argv++;
X	addr = NOADDR;
X	while (argc > 0) {
X		if ((fp = fopen(argv[0], "r")) == NULL) {
X			fprintf(stderr, "fopen: %s %d\n", argv[0], errno);
X			continue;
X		}
X		
X		while (fread(buf, sizeof(char), sizeof(buf), fp) != NULL) {
X			if (sscanf(buf, "%*c%5x:", &a) != 1) {
X				fprintf(stderr, "Format bad '%s'\n", buf);
X				break;
X			}
X			
X			if (addr == NOADDR)
X				addr = a;
X				
X			else if (a != addr)
X				fprintf(stderr, "\nAddr mismatch %x '%s'\n",
X						addr, buf);
X						
X			for (n = 16, p = &buf[7]; --n >= 0; p++, addr++) {
X				if ((*p >= '0') && (*p <= '9'))
X					*p -= '0';
X					
X				else if ((*p >= 'A') && (*p <= 'F'))
X					*p -= 'A' - 10;
X					
X				else {
X					fprintf(stderr, "Bad char '%c'\n", *p);
X					break;
X				}
X				
X				StuffNybble(mem, addr, *p);
X			}
X		}
X		
X		fclose(fp);
X		argc--;
X		argv++;
X	}
X	
X	if ((fp = fopen("dump.out", "w")) == NULL) {
X		fprintf(stderr, "fopen dump.out\n");
X		exit(1);
X	}
X	
X	if (fwrite(mem, sizeof(char), SIZE, fp) != SIZE)
X		fprintf(stderr, "fwrite\n");
X		
X	fclose(fp);
X	exit(0);
X}
SHAR_EOF
if test 1630 -ne "`wc -c < 'cvt.c'`"
then
	echo shar: "error transmitting 'cvt.c'" '(should have been 1630 characters)'
fi
fi
echo shar: "extracting 'dis48.c'" '(1374 characters)'
if test -f 'dis48.c'
then
	echo shar: "will not over-write existing file 'dis48.c'"
else
sed 's/^X//' << \SHAR_EOF > 'dis48.c'
X#include "dis48.h"
X#include <fcntl.h>
X
X#ifdef notdef
Xvoid
XStuffNybble(char *mem, NAddr addr, Nybble n)
X{
X	char	t;
X	
X	t = mem[addr >> 1] & ((addr & 1) ? 0x0f : 0xf0);
X	n &= 0xf;
X	if (addr & 1)
X		n <<= 4;
X		
X	mem[addr >> 1] = t | n;
X}
X#endif
X
X#define NSIZE 524288
X#define BSIZE (NSIZE / 2)
X
XBitmap	completed;
Xint	dopause = 0;
X
X#ifdef ANSI
Xmain(int argc, char **argv)
X#else
Xmain(argc, argv)
Xint	argc;
Xchar	**argv;
X#endif
X{
X	char	*p;
X	int	n;
X	int	s, e;
X	char	buf[80];
X	char	*mem, *malloc();
X	
X	if ((argc > 1) && !strcmp(argv[1], "-p"))
X		dopause = 1;
X		
X	if ((mem = malloc(BSIZE)) == NULL) {
X		fprintf(stderr, "malloc failed\n");
X		exit(1);
X	}
X	
X	if ((completed = malloc(BITS(NSIZE))) == NULL) {
X		fprintf(stderr, "malloc failed\n");
X		goto done;
X	}
X	
X	memset(completed, 0, BITS(NSIZE));
X	if ((n = open("rom", O_RDONLY)) < 0) {
X		fprintf(stderr, "open failed\n");
X		goto done2;
X	}
X	
X	if (read(n, mem, BSIZE) <= 0/* != BSIZE*/) {
X		fprintf(stderr, "read failed\n");
X		close(n);
X		goto done2;
X	}
X	
X	(void) close(n);
X	while (1) {
X		printf("start?\n");
X		if (fgets(buf, sizeof(buf), stdin) == NULL)
X			break;
X			
X		if (sscanf(buf, "%x", &s) != 1)
X			break;
X			
X		printf("end?\n");
X		if (fgets(buf, sizeof(buf), stdin) == NULL)
X			break;
X			
X		if (sscanf(buf, "%x", &e) != 1)
X			break;
X			
X		Disassemble(mem, s, e, stdout);
X	}
Xdone2:
X	free(completed);
Xdone:	
X	free(mem);
X	exit(0);
X}
SHAR_EOF
if test 1374 -ne "`wc -c < 'dis48.c'`"
then
	echo shar: "error transmitting 'dis48.c'" '(should have been 1374 characters)'
fi
fi
echo shar: "extracting 'dis48.h'" '(1489 characters)'
if test -f 'dis48.h'
then
	echo shar: "will not over-write existing file 'dis48.h'"
else
sed 's/^X//' << \SHAR_EOF > 'dis48.h'
X#include <stdio.h>
X
Xtypedef char		Nybble;
Xtypedef unsigned int	NAddr;
X
X#define NOADDR		0xffffffff
X
Xextern char	hex[];
X
X#ifdef ANSI
Xint	GetInt(char *mem, NAddr *addr, int n);
XNybble	GetNybble(char *mem, NAddr addr);
X
Xchar	*Append16(char *buf, int n);
Xchar	*AppendAddr(char *buf, NAddr addr);
Xchar	*AppendRAddr(char *buf, NAddr pc, int disp, int n, int offset);
Xchar	*AppendField(char *buf, Nybble fn);
Xchar	*AppendDecInt(char *buf, int n);
Xchar	*AppendHexNyb(char *buf, char *mem, NAddr *addr, int n);
Xchar	*AppendImmNyb(char *buf, char *mem, NAddr *addr, int n);
Xchar	*AppendStBits(char *buf, int n);
Xchar	*AppendStr(char *buf, char *str);
X#else
Xint	GetInt();
XNybble	GetNybble();
X
Xchar	*Append16();
Xchar	*AppendAddr();
Xchar	*AppendRAddr();
Xchar	*AppendField();
Xchar	*AppendDecInt();
Xchar	*AppendHexNyb();
Xchar	*AppendImmNyb();
Xchar	*AppendStBits();
Xchar	*AppendStr();
X#endif
X
Xtypedef char	*Bitmap;
X
X#define BITS(s)		((s) /  8)
X#define BITSET(m, b)	m[b >> 3] |= (1 << (b & 7))
X#define BITCLR(m, b)	m[b >> 3] &= ~(1 << (b & 7))
X#define BITTEST(m, b)	(m[b >> 3] & (1 << (b & 7)))
X
Xextern Bitmap	completed;
X
Xtypedef enum {other, branch, call, jump, ujump}	IType;
X
Xextern IType	itype;
Xextern NAddr	target;
X
X#define APPEND_BDIGIT(x, d)	*(x)++ = (d) + '0'
X#define APPEND_CHAR(x, c)	*(x)++ = (c)
X#define APPEND_COMMA(x)		*(x)++ = ','; *(x)++ = ' '
X#define APPEND_HEXMARK(x)	*(x)++ = '$'
X#define APPEND_IMMMARK(x)	*(x)++ = '#'
X#define APPEND_TAB(x)		*(x)++ = '\t'
X#define TERMINATE(x)		*(x) = '\0'
SHAR_EOF
if test 1489 -ne "`wc -c < 'dis48.h'`"
then
	echo shar: "error transmitting 'dis48.h'" '(should have been 1489 characters)'
fi
fi
echo shar: "extracting 'disasm.c'" '(3672 characters)'
if test -f 'disasm.c'
then
	echo shar: "will not over-write existing file 'disasm.c'"
else
sed 's/^X//' << \SHAR_EOF > 'disasm.c'
X#include "dis48.h"
X
X#ifdef ANSI
XNAddr	Instruction(char *mem, NAddr addr, char *istr);
X#else
XNAddr	Instruction();
X#endif
X
Xtypedef struct tlist {
X	struct tlist	*next;
X	NAddr		addr;
X} TList;
X
XTList	*tlist = NULL;
XTList	*tfree = NULL;
X
Xvoid
X#ifdef ANSI
XTListPut(NAddr addr)
X#else
XTListPut(addr)
X#endif
X{
X	TList	*p;
X	char	*malloc();
X	
X	if (BITTEST(completed, addr))
X		return;
X		
X	if (addr >= 0x80000) {
X		fprintf(stderr, "%05x: out of range\n", addr);
X		return;
X	}
X	
X	if ((p = tfree) != NULL)
X		tfree = p->next;
X	else {
X		if ((p = (TList *) malloc(sizeof(TList))) == NULL) {
X			fprintf(stderr, "malloc TList failed\n");
X			exit(1);
X		}
X	}
X	
X	p->addr = addr;
X	p->next = tlist;
X	tlist = p;
X}
X
XNAddr
X#ifdef ANSI
XTListGet(void)
X#else
XTListGet()
X#endif
X{
X	TList	*p;
X	
X	if ((p = tlist) == NULL)
X		return(NOADDR);
X		
X	tlist = p->next;
X	p->next = tfree;
X	tfree = p;
X	return(p->addr);
X}
X
XIType	itype;
XNAddr	target;
X
Xchar	*itypestr[] = {"other", "branch", "call", "jump", "ujump"};
X
Xvoid
X#ifdef ANSI
XDisassemble(char *mem, NAddr start, NAddr end, FILE *fp)
X#else
XDisassemble(mem, start, end, fp)
Xchar	*mem;
XNAddr	start;
XNAddr	end;
XFILE	*fp;
X#endif
X{
X	NAddr	addr, next;
X	int	i, nybs;
X	char	*p;
X	char	buf[40];
X	char	istr[40];
X	extern int dopause;
X	
X	if (end == NOADDR) {
X		TListPut(start);
X		while ((addr = TListGet()) != NOADDR) {
X			start = addr;
X			if (BITTEST(completed, start)) {
X				/*fprintf(stderr, "%05x: completed\n", addr);*/
X				continue;
X			}
X			
X			if (start >= 0x80000) {
X				fprintf(stderr, "%05x: out of range\n", addr);
X				continue;
X			}
X			
X			/*fprintf(stderr, "%05x: start\n", addr);*/
X			do {
X				itype = other;
X				target = NOADDR;
X				next = Instruction(mem, addr, istr);
X#ifdef notdef
X				nybs = next - addr;
X				p = AppendAddr(buf, addr);
X				APPEND_CHAR(p, ':');
X				APPEND_TAB(p);
X				for (i = 7; (i > 0) && (nybs > 0); i--, nybs--)
X					APPEND_CHAR(p,
X						hex[GetNybble(mem, addr++)]);
X				
X				APPEND_TAB(p);
X				fprintf(stderr, "%.*s %s", p - buf, buf, istr);
X				fprintf(stderr, "\t%s %05x\n", itypestr[itype],
X						target);
X						
X				while (nybs > 0) {
X					fputc('\t', stderr);
X					for (i = 7; (i > 0) && (nybs > 0);
X						i--, nybs--)
X						fputc(hex[GetNybble(mem,
X								addr++)], fp);
X				
X					fputc('\n', stderr);
X				}
X#endif notdef
X
X				switch (itype) {
X				case call:
X					fprintf(stderr, "%05x: call\n",
X							target);
X					/* fall through*/
X					
X				case branch:
X					if (target != NOADDR)
X						TListPut(target);
X						
X					break;
X					
X				case jump:
X					/*printf("%05x: jumps to %05x\n", addr,
X							target);*/
X					TListPut(target);
X					itype = ujump;
X					break;
X					
X				case ujump:
X					/*printf("%05x: unresolved jump\n",
X							addr);*/
X					break;
X				}
X				
X				addr = next;
X				if (BITTEST(completed, addr))
X					break;
X					
X			} while (itype != ujump);
X			
X			end = next - 1;
X			/*fprintf(stderr, "%05x: end\n", end);*/
X			while (start <= end) {
X				BITSET(completed, start);
X				start++;
X			}
X			
X			if (dopause && (fgets(buf, sizeof(buf), stdin) == NULL))
X				break;	
X		}
X		
X		return;
X	}
X	
X	for (addr = start; addr < end; addr = next) {
X		itype = other;
X		target = NOADDR;
X		next = Instruction(mem, addr, istr);
X		nybs = next - addr;
X		p = AppendAddr(buf, addr);
X		APPEND_CHAR(p, ':');
X		APPEND_TAB(p);
X		for (i = 7; (i > 0) && (nybs > 0); i--, nybs--)
X			APPEND_CHAR(p, hex[GetNybble(mem, addr++)]);
X		
X		APPEND_TAB(p);
X		fprintf(fp, "%.*s %s\n", p - buf, buf, istr);
X		while (nybs > 0) {
X			p = AppendAddr(buf, addr);
X			APPEND_CHAR(p, ':');
X			APPEND_TAB(p);
X			for (i = 7; (i > 0) && (nybs > 0); i--, nybs--)
X				APPEND_CHAR(p, hex[GetNybble(mem, addr++)]);
X		
X			fprintf(fp, "%.*s\n", p - buf, buf);
X		}
X	}
X}
SHAR_EOF
if test 3672 -ne "`wc -c < 'disasm.c'`"
then
	echo shar: "error transmitting 'disasm.c'" '(should have been 3672 characters)'
fi
fi
echo shar: "extracting 'dobj.c'" '(989 characters)'
if test -f 'dobj.c'
then
	echo shar: "will not over-write existing file 'dobj.c'"
else
sed 's/^X//' << \SHAR_EOF > 'dobj.c'
X#include "dis48.h"
X#include <fcntl.h>
X
Xvoid
X#ifdef ANSI
XStuffNybble(char *mem, NAddr addr, Nybble n)
X#else
XStuffNybble(mem, addr, n)
Xchar	*mem;
XNAddr	addr;
XNybble	n;
X#endif
X{
X	char	t;
X	
X	t = mem[addr >> 1] & ((addr & 1) ? 0x0f : 0xf0);
X	n &= 0xf;
X	if (addr & 1)
X		n <<= 4;
X		
X	mem[addr >> 1] = t | n;
X}
X
X#define NSIZE 524288
X#define BSIZE (NSIZE / 2)
X
XBitmap	completed;
Xint	dopause = 0;
X
X#ifdef ANSI
Xmain(int argc, char **argv)
X#else
Xmain(argc, argv)
Xint	argc;
Xchar	**argv;
X#endif
X{
X	char	*p;
X	int	n;
X	NAddr	a;
X	char	buf[80];
X	char	mem[80];
X
X	while (1) {
X		fprintf(stderr, "?\n");
X		if (fgets(buf, sizeof(buf), stdin) == NULL)
X			break;
X			
X		for (a = 0, p = buf; (*p != '\n') && (*p != '\0'); a++, p++) {
X			if ((*p >= '0') && (*p <= '9'))
X				*p -= '0';
X			
X			else if ((*p >= 'A') && (*p <= 'F'))
X				*p -= 'A' - 10;
X				
X			else if ((*p >= 'a') && (*p <= 'f'))
X				*p -= 'a' - 10;
X				
X			StuffNybble(mem, a, *p);
X		}
X			
X		Object(mem, 0, buf);
X		printf("%s\n", buf);
X	}
X	
X	exit(0);
X}
SHAR_EOF
if test 989 -ne "`wc -c < 'dobj.c'`"
then
	echo shar: "error transmitting 'dobj.c'" '(should have been 989 characters)'
fi
fi
exit 0
#	End of shell archive
-- 
Craig Ruff      	NCAR			cruff@ncar.ucar.edu
(303) 497-1211  	P.O. Box 3000
			Boulder, CO  80307

From comp.sys.handhelds Thu Apr 26 12:24:14 1990
Path: fauern!sun1.ruf.uni-freiburg.de!ira.uka.de!sol.ctr.columbia.edu!lll-winken!elroy.jpl.nasa.gov!ncar!cruff
From: cruff@ncar.ucar.edu (Craig Ruff)
Newsgroups: comp.sys.handhelds
Subject: Saturn (HP48 CPU) disassembler part 2 of 2
Message-ID: <7125@ncar.ucar.edu>
Date: 26 Apr 90 01:03:22 GMT
Reply-To: cruff@ncar.UCAR.EDU (Craig Ruff)
Organization: Scientific Computing Division/NCAR, Boulder CO
Lines: 1521
Status: OR

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	get.c
#	instr.c
#	instr1.c
#	instr8.c
#	obj.c
#	trace.c
# This archive created: Wed Apr 25 18:59:31 1990
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'get.c'" '(441 characters)'
if test -f 'get.c'
then
	echo shar: "will not over-write existing file 'get.c'"
else
sed 's/^X//' << \SHAR_EOF > 'get.c'
X#include "dis48.h"
X
XNybble
X#ifdef ANSI
XGetNybble(char *mem, NAddr addr)
X#else
XGetNybble(mem, addr)
Xchar	*mem;
XNAddr	addr;
X#endif
X{
X	char	n;
X	
X	n = mem[addr >> 1];
X	if (addr & 1)
X		n >>= 4;
X		
X	return(n & 0xf);
X}
X
Xint
X#ifdef ANSI
XGetInt(char *mem, NAddr *addr, int n)
X#else
XGetInt(mem, addr, n)
Xchar	*mem;
XNAddr	*addr;
Xint	n;
X#endif
X{
X	int	i, t;
X	
X	for (i = 0, t = 0; i < n; i++)
X		t |= GetNybble(mem, (*addr)++) << (i * 4);
X		
X	return(t);
X}
SHAR_EOF
if test 441 -ne "`wc -c < 'get.c'`"
then
	echo shar: "error transmitting 'get.c'" '(should have been 441 characters)'
fi
fi
echo shar: "extracting 'instr.c'" '(4940 characters)'
if test -f 'instr.c'
then
	echo shar: "will not over-write existing file 'instr.c'"
else
sed 's/^X//' << \SHAR_EOF > 'instr.c'
X#include "dis48.h"
X
Xchar	hex[] = "0123456789ABCDEF";
X
Xchar	*InStr0[16] = {
X	"retsetxm", "ret", "retsetc", "retclrc", "sethex", "setdec",
X	"push.a\t\tc", "pop.a\t\tc", "clr.x\t\tst", "move.x\t\tst, c",
X	"move.x\t\tc, st", "swap.x\t\tc, st", "inc.1\t\tp", "dec.1\t\tp",
X	"AND/OR", "reti"
X};
X
Xchar	*OpStr0[8] = {
X	"b, a", "c, b", "a, c", "c, d", "a, b", "b, c", "c, a", "d, c"
X};
X
Xchar	*InStr9[8] = {"eq", "ne", "z", "nz", "gt", "lt", "ge", "le"};
X
Xchar	*OpStr9[4] = {"a, b", "b, c", "c, a", "d, c"};
X
Xchar	*OpStraf[16] = {
X	"b, a", "c, b", "a, c", "c, d", "a, a", "b, b", "c, c", "d, d",
X	"a, b", "b, c", "c, a", "d, c", "b, a", "c, b", "a, c", "c, d"
X};
X
X#ifdef ANSI
Xchar	*Instr1(char *mem, NAddr *addr, char *out);
Xchar	*Instr8(char *mem, NAddr *addr, char *out);
X#else
Xchar	*Instr1();
Xchar	*Instr8();
X#endif
X
XNAddr
X#ifdef ANSI
XInstruction(char *mem, NAddr addr, char *out)
X#else
XInstruction(mem, addr, out)
Xchar	*mem;
XNAddr	addr;
Xchar	*out;
X#endif
X{
X	Nybble	n;
X	Nybble	fn;
X	char	*p;
X	char	c;
X	int	disp, pc;
X	
X	switch (n = GetNybble(mem, addr++)) {
X	case 0:
X		if ((n = GetNybble(mem, addr++)) != 0xe) {
X			p = AppendStr(out, InStr0[n]);
X			if ((n < 4) || (n == 0xf))
X				itype = ujump;
X				
X			break;
X		}
X		
X		fn = GetNybble(mem, addr++);
X		n = GetNybble(mem, addr++);
X		p = AppendStr(out, (n < 8) ? "and" : "or");
X		p = AppendField(p, fn);
X		APPEND_TAB(p);
X		p = AppendStr(p, OpStr0[n & 7]);
X		break;
X		
X	case 1:
X		p = Instr1(mem, &addr, out);
X		break;
X		
X	case 2:
X		p = AppendStr(out, "move.1\t\t");
X		p = AppendImmNyb(p, mem, &addr, 1);
X		APPEND_COMMA(p);
X		APPEND_CHAR(p, 'p');
X		break;
X		
X	case 3:
X		p = AppendStr(out, "move.p");
X		fn = GetNybble(mem, addr++);
X		p = Append16(p, fn);
X		APPEND_TAB(p);
X		if ((p - out) < 8)
X			APPEND_TAB(p);
X			
X		p = AppendImmNyb(p, mem, &addr, fn + 1);
X		APPEND_COMMA(p);
X		APPEND_CHAR(p, 'c');
X		break;
X		
X	case 4:
X	case 5:
X		pc = addr;
X		disp = GetInt(mem, &addr, 2);
X		if (disp == 2) {
X			p = AppendStr(out, "nop3");
X			break;
X		}
X		
X		p = AppendStr(out, (disp == 0) ? "retc" : "brc");
X		APPEND_CHAR(p, (n == 4) ? 's' : 'c');
X		if (disp != 0) {
X			APPEND_TAB(p);
X			APPEND_TAB(p);
X			p = AppendRAddr(p, pc, disp, 2, 1);
X		} else
X			target = NOADDR;
X		
X		itype = branch;
X		break;
X	
X	case 6:
X		pc = addr;
X		disp = GetInt(mem, &addr, 3);
X		if ((disp == 3) || (disp == 4)) {
X			p = AppendStr(out, "nop");
X			APPEND_BDIGIT(p, disp + 1);
X			if (disp == 4)
X				addr++;
X				
X			break;
X		}
X			
X		p = AppendStr(out, "jump.3\t\t");
X		p = AppendRAddr(p, pc, disp, 3, 1);
X		itype = jump;
X		break;
X		
X	case 7:
X		pc = addr + 3;
X		disp = GetInt(mem, &addr, 3);
X		p = AppendStr(out, "call.3\t\t");
X		p = AppendRAddr(p, pc, disp, 3, 4);
X		itype = call;
X		break;
X		
X	case 8:
X		fn = GetNybble(mem, addr);	/* peek! */
X		if ((fn != 0xa) && (fn != 0xb)) {
X			p = Instr8(mem, &addr, out);
X			break;
X		}
X		
X		/* fall through */
X	case 9:
X		if (n == 8) {
X			c = (fn == 0xa) ? 0 : 1;
X			fn = 0xf;
X			addr++;
X			
X		} else {
X			fn = GetNybble(mem, addr++);
X			c = (fn < 8) ? 0 : 1;
X			fn &= 7;
X		}
X
X		n = GetNybble(mem, addr++);
X		pc = addr;
X		disp = GetInt(mem, &addr, 2);
X		p = AppendStr(out, (disp == 0) ? "ret" : "br");
X		p = AppendStr(p, InStr9[((n >> 2) & 3) + 4 * c]);
X		p = AppendField(p, fn);
X		if ((p - out) < 8)
X			APPEND_TAB(p);
X			
X		if ((c == 0) && (n >= 8)) {
X			APPEND_CHAR(p, (n & 3) + 'a');
X			
X		} else {
X			p = AppendStr(p, OpStr9[n & 3]);
X		}
X		
X		if (disp != 0) {
X			APPEND_COMMA(p);
X			p = AppendRAddr(p, pc, disp, 2, 3);
X		} else
X			target = NOADDR;
X		
X		itype = branch;
X		break;
X		
X	default:
X		switch (n) {
X		case 0xa:
X			fn = GetNybble(mem, addr++);
X			c = (fn < 8) ? 0 : 1;
X			fn &= 7;
X			disp = 0xa;
X			break;
X			
X		case 0xb:
X			fn = GetNybble(mem, addr++);
X			c = (fn < 8) ? 0 : 1;
X			fn &= 7;
X			disp = 0xb;
X			break;
X			
X		case 0xc:
X		case 0xd:
X			fn = 0xf;
X			c = n & 1;
X			disp = 0xa;
X			break;
X			
X		case 0xe:
X		case 0xf:
X			fn = 0xf;
X			c = n & 1;
X			disp = 0xb;
X			break;
X		}
X		
X		n = GetNybble(mem, addr++);
X		pc = 0;
X		switch (disp) {
X		case 0xa:
X			if (c == 0) {
X				if (n < 0xc) {
X					p = "add";
X				
X				} else {
X					p = "dec";
X					pc = 1;
X				}
X				
X			} else {
X				if (n < 4) {
X					p = "clr";
X					pc = 1;
X					
X				} else if (n >= 0xc) {
X					p = "swap";
X				
X				} else {
X					p = "move";
X					if (n < 8)
X						n -= 4;
X				}
X			}
X			
X			break;
X			
X		case 0xb:
X			if (c == 0) {
X				if (n >= 0xc) {
X					p = "subn";
X				
X				} else if ((n >= 4) && (n <= 7)) {
X					p = "inc";
X					pc = 1;
X					n -= 4;
X				
X				} else {
X					p = "sub";
X				}
X				
X			} else {
X				pc = 1;
X				if (n < 4)
X					p = "sln";
X					
X				else if (n < 8)
X					p = "srn";
X					
X				else if (n < 0xc)
X					p = "neg";
X					
X				else
X					p = "not";
X			}
X			
X			break;
X		}
X		
X		p = AppendStr(out, p);
X		p = AppendField(p, fn);
X		if ((p - out) < 9)
X			APPEND_TAB(p);
X			
X		if (pc == 1)
X			APPEND_CHAR(p, (n & 3) + 'a');
X		
X		else
X			p = AppendStr(p, OpStraf[n]);
X			
X		break;
X	}
X	
X	TERMINATE(p);
X	return(addr);
X}
SHAR_EOF
if test 4940 -ne "`wc -c < 'instr.c'`"
then
	echo shar: "error transmitting 'instr.c'" '(should have been 4940 characters)'
fi
fi
echo shar: "extracting 'instr1.c'" '(2403 characters)'
if test -f 'instr1.c'
then
	echo shar: "will not over-write existing file 'instr1.c'"
else
sed 's/^X//' << \SHAR_EOF > 'instr1.c'
X#include "dis48.h"
X
Xchar	*OpStr1[8] = {
X	"a, @d0", "a, @d1", "@d0, a", "@d1, a",
X	"c, @d0", "c, @d1", "@d0, c", "@d1, c"
X};
X
Xchar *
X#ifdef ANSI
XInstr1(char *mem, NAddr *addr, char *out)
X#else
XInstr1(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	Nybble	n;
X	Nybble	fn;
X	char	*p;
X	char	c;
X	
X	switch (n = GetNybble(mem, (*addr)++)) {
X	case 0:
X	case 1:
X		p = AppendStr(out, "move.w\t\t");
X		fn = GetNybble(mem, (*addr)++);
X		c = (fn < 8) ? 'a' : 'c';
X		fn = (fn & 7) + '0';
X		if (n == 0)
X			APPEND_CHAR(p, c);
X		else {
X			APPEND_CHAR(p, 'r');
X			APPEND_CHAR(p, fn);
X		}
X		
X		APPEND_COMMA(p);
X		if (n == 0) {
X			APPEND_CHAR(p, 'r');
X			APPEND_CHAR(p, fn);
X			
X		} else
X			APPEND_CHAR(p, c);
X		
X		break;
X		
X	case 2:
X		p = AppendStr(out, "swap.w\t\t");
X		n = GetNybble(mem, (*addr)++);
X		APPEND_CHAR(p, (n < 8) ? 'a' : 'c');
X		APPEND_COMMA(p);
X		APPEND_CHAR(p, 'r');
X		APPEND_BDIGIT(p, n & 7);
X		break;
X	
X	case 3:
X		n = GetNybble(mem, (*addr)++);
X		p = AppendStr(out, (n & 2) ? "swap" : "move");
X		APPEND_CHAR(p, '.');
X		APPEND_CHAR(p, (n < 8) ? 'a' : '4');
X		APPEND_TAB(p);
X		APPEND_TAB(p);
X		APPEND_CHAR(p, (n & 4) ? 'c' : 'a');
X		APPEND_COMMA(p);
X		APPEND_CHAR(p, 'd');
X		APPEND_BDIGIT(p, n & 1);
X		break;
X		
X	case 4:
X	case 5:
X		p = AppendStr(out, "move");
X		fn = GetNybble(mem, (*addr)++);
X		if (n == 4) {
X			APPEND_CHAR(p, '.');
X			APPEND_CHAR(p, (fn < 8) ? 'a' : 'b');
X			APPEND_TAB(p);
X		
X		} else {
X			n = GetNybble(mem, (*addr)++);
X			if (fn < 8)
X				p = AppendField(p, n);
X				
X			else {
X				APPEND_CHAR(p, '.');
X				p = Append16(p, n);
X				APPEND_TAB(p);
X			}
X		}
X		
X		if ((p - out) < 8)
X			APPEND_TAB(p);
X			
X		p = AppendStr(p, OpStr1[fn & 7]);
X		break;
X	
X	case 6:
X	case 7:
X		p = AppendStr(out, "add.a\t\t");
X		APPEND_IMMMARK(p);
X		p = Append16(p, GetNybble(mem, (*addr)++));
X		APPEND_COMMA(p);
X		APPEND_CHAR(p, 'd');
X		APPEND_BDIGIT(p, n & 1);
X		break;
X		
X	default:
X		c = (n < 0xc) ? '0' : '1';
X		if ((n & 3) == 0) {
X			p = AppendStr(out, "sub.a\t\t");
X			APPEND_IMMMARK(p);
X			p = Append16(p, GetNybble(mem, (*addr)++));
X		
X		} else {
X			p = AppendStr(out, "move.");
X			switch (n & 3) {
X			case 1: n = 2; break;
X			case 2: n = 4; break;
X			case 3: n = 5; break;
X			}
X			
X			APPEND_BDIGIT(p, n);
X			APPEND_TAB(p);
X			APPEND_TAB(p);
X			p = AppendImmNyb(p, mem, addr, n);
X		}
X		
X		APPEND_COMMA(p);
X		APPEND_CHAR(p, 'd');
X		APPEND_CHAR(p, c);
X		break;
X	}
X	
X	TERMINATE(p);
X	return(p);
X}
SHAR_EOF
if test 2403 -ne "`wc -c < 'instr1.c'`"
then
	echo shar: "error transmitting 'instr1.c'" '(should have been 2403 characters)'
fi
fi
echo shar: "extracting 'instr8.c'" '(6547 characters)'
if test -f 'instr8.c'
then
	echo shar: "will not over-write existing file 'instr8.c'"
else
sed 's/^X//' << \SHAR_EOF > 'instr8.c'
X#include "dis48.h"
X
Xchar	*InStr80[16] = {
X	"out.s\t\tc", "out.x\t\tc", "in.4\t\ta", "in.4\t\tc", "uncnfg",
X	"config", "move.a\t\tid, c", "shutdn", NULL, "add.a\t\tp+1, c", "reset",
X	"buscc", NULL, NULL, "sreq", NULL
X};
X
Xchar	*InStr808[16] = {
X	"inton", NULL, NULL, "buscb", NULL, NULL, NULL, NULL, NULL, NULL,
X	NULL, NULL, "jump.a\t\t@a", "buscd", "jump.a\t\t@c", "intoff"
X};
X
Xchar *
X#ifdef ANSI
XInstr80(char *mem, NAddr *addr, char *out)
X#else
XInstr80(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	Nybble	n;
X	Nybble	fn;
X	char	*p;
X	char	c;
X	NAddr	pc;
X	int	disp;
X	
X	n = GetNybble(mem, (*addr)++);
X	if ((p = InStr80[n]) != NULL)
X		return(AppendStr(out, p));
X		
X	switch (n) {
X	case 8:
X		fn = GetNybble(mem, (*addr)++);
X		if ((p = InStr808[fn]) != NULL) {
X			if ((n == 0xc) || (n == 0xe))
X				itype = ujump;
X				
X			return(AppendStr(out, p));
X		}
X			
X		switch (fn) {
X		case 1:
X			n = GetNybble(mem, (*addr)++);
X			p = AppendStr(out, (n == 0) ? "rsi" : "???");
X			break;
X			
X		case 2:
X			p = AppendStr(out, "move.p");
X			n = GetNybble(mem, (*addr)++);
X			p = Append16(p, n);
X			APPEND_TAB(p);
X			if ((p - out) < 8)
X				APPEND_TAB(p);
X				
X			p = AppendImmNyb(p, mem, addr, n + 1);
X			p = AppendStr(p, ", a");
X			break;
X			
X		case 4:
X		case 5:
X		case 8:
X		case 9:
X			p = AppendStr(out, (fn & 1) ? "setb\t\t" : "clrb\t\t");
X			p = AppendImmNyb(p, mem, addr, 1);
X			p = AppendStr(p, (fn & 8) ? ", c" : ", a");
X			break;
X			
X		case 6:
X		case 7:
X		case 0xa:
X		case 0xb:
X			c = (fn < 0xa) ? 'a' : 'c';
X			pc = *addr + 1;
X			n = GetNybble(mem, (*addr)++);
X			disp = GetInt(mem, addr, 2);
X			p = AppendStr(out, (disp == 0) ? "ret" : "br");
X			p = AppendStr(p, (fn & 1) ? "bs\t\t" : "bc\t\t");
X			APPEND_IMMMARK(p);
X			APPEND_HEXMARK(p);
X			APPEND_CHAR(p, hex[n]);
X			APPEND_COMMA(p);
X			APPEND_CHAR(p, c);
X			if (disp != 0) {
X				APPEND_COMMA(p);
X				p = AppendRAddr(p, pc, disp, 2, 5);
X			} else
X				target = NOADDR;
X			
X			itype = branch;
X			break;
X		}
X		
X		break;
X		
X	case 0xc:
X	case 0xf:
X		p = AppendStr(out, (n == 0xc) ? "move" : "swap");
X		p = AppendStr(p, ".1\t\tp, c, ");
X		p = AppendImmNyb(p, mem, addr, 1);
X		break;
X		
X	case 0xd:
X		p = AppendStr(out, "move.1\t\tc, ");
X		p = AppendImmNyb(p, mem, addr, 1);
X		p = AppendStr(p, ", p");
X		break;
X	}
X	
X	return(p);
X}
X
Xchar	*InStr81b[8] = {
X	NULL, NULL, "jump.a\t\ta", "jump.a\t\tc", "move.a\t\tpc, a",
X	"move.a\t\tpc, c", "swap.a\t\ta, pc", "swap.a\t\tc, pc"
X};
X
Xchar	OpChr81[4] = {'a', 'b', 'c', 'd'};
X
Xchar *
X#ifdef ANSI
XInstr81(char *mem, NAddr *addr, char *out)
X#else
XInstr81(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	Nybble	n;
X	Nybble	fn;
X	char	*p;
X	char	c;
X	
X	switch (n = GetNybble(mem, (*addr)++)) {
X	case 0: case 1: case 2: case 3:
X		p = AppendStr(out, "rln.w\t\t");
X		APPEND_CHAR(p, OpChr81[n & 3]);
X		break;
X		
X	case 4: case 5: case 6: case 7:
X		p = AppendStr(out, "rrn.w\t\t");
X		APPEND_CHAR(p, OpChr81[n & 3]);
X		break;
X		
X	case 8:
X		fn = GetNybble(mem, (*addr)++);
X		n = GetNybble(mem, (*addr)++);
X		p = AppendStr(out, (n < 8) ? "add" : "sub");
X		p = AppendField(p, fn);
X		if ((p - out) < 9)
X			APPEND_TAB(p);
X			
X		fn = GetNybble(mem, (*addr)++);
X		APPEND_IMMMARK(p);
X		p = Append16(p, fn);
X		APPEND_COMMA(p);
X		APPEND_CHAR(p, OpChr81[n & 3]);
X		break;
X		
X	case 9:
X		p = AppendStr(out, "srb");
X		p = AppendField(p, GetNybble(mem, (*addr)++));
X		if ((p - out) < 9)
X			APPEND_TAB(p);
X			
X		APPEND_CHAR(p, OpChr81[GetNybble(mem, (*addr)++) & 3]);
X		break;
X	
X	case 0xa:
X		fn = GetNybble(mem, (*addr)++);
X		n = GetNybble(mem, (*addr)++);
X		p = AppendStr(out, (n == 2) ? "swap" : "move");
X		p = AppendField(p, fn);
X		if ((p - out) < 9)
X			APPEND_TAB(p);
X			
X		fn = GetNybble(mem, (*addr)++);
X		c = (fn < 8) ? 'a' : 'c';
X		fn = (fn & 7) + '0';
X		if (n == 1) {
X			APPEND_CHAR(p, 'r');
X			APPEND_CHAR(p, fn);
X		} else
X			APPEND_CHAR(p, c);
X			
X		APPEND_COMMA(p);
X		if (n == 1)
X			APPEND_CHAR(p, c);
X		else {
X			APPEND_CHAR(p, 'r');
X			APPEND_CHAR(p, fn);
X		}
X		
X		break;
X		
X	case 0xb:
X		n = GetNybble(mem, (*addr)++);
X		p = AppendStr(out, ((n < 2) || (n > 7)) ? "???" : InStr81b[n]);
X		itype = ujump;
X		break;
X		
X	case 0xc: case 0xd: case 0xe: case 0xf:
X		p = AppendStr(out, "srb.w\t\t");
X		APPEND_CHAR(p, OpChr81[n & 3]);
X		break;	
X	}
X	
X	return(p);
X}
X
Xchar *
X#ifdef ANSI
XInstr8(char *mem, NAddr *addr, char *out)
X#else
XInstr8(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	Nybble	n;
X	Nybble	fn;
X	char	*p;
X	char	c;
X	int	disp, pc;
X
X	switch (fn = GetNybble(mem, (*addr)++)) {
X	case 0:
X		p = Instr80(mem, addr, out);
X		break;
X		
X	case 1:
X		p = Instr81(mem, addr, out);
X		break;
X	
X	case 2:
X		p = AppendStr(out, "clrb\t\t");
X		p = AppendStBits(p, GetNybble(mem, (*addr)++));
X		break;
X		
X	case 3:
X		n = GetNybble(mem, (*addr)++);
X		pc = *addr;
X		disp = GetInt(mem, addr, 2);
X		p = AppendStr(out, (disp == 0) ? "retbc\t\t" : "brbc\t\t");
X		p = AppendStBits(p, n);
X		if (disp != 0) {
X			APPEND_COMMA(p);
X			p = AppendRAddr(p, pc, disp, 2, 3);
X		} else
X			target = NOADDR;
X		
X		itype = branch;
X		break;
X	
X	case 4:
X	case 5:
X		p = AppendStr(out, (fn == 4) ? "clrb\t\t" : "setb\t\t");
X		p = AppendImmNyb(p, mem, addr, 1);
X		p = AppendStr(p, ", st");
X		break;
X		
X	case 6:
X	case 7:
X		c = (fn == 6) ? 'c' : 's';
X		n = GetNybble(mem, (*addr)++);
X		pc = *addr;
X		disp = GetInt(mem, addr, 2);
X		p = AppendStr(out, (disp == 0) ? "retb" : "brb");
X		APPEND_CHAR(p, c);
X		APPEND_TAB(p);
X		APPEND_TAB(p);
X		APPEND_IMMMARK(p);
X		APPEND_HEXMARK(p);
X		APPEND_CHAR(p, hex[n]);
X		p = AppendStr(p, ", st");
X		if (disp != 0) {
X			APPEND_COMMA(p);
X			p = AppendRAddr(p, pc, disp, 2, 3);
X		} else
X			target = NOADDR;
X		
X		itype = branch;
X		break;
X	
X	case 8:
X	case 9:
X		n = GetNybble(mem, (*addr)++);
X		pc = *addr;
X		disp = GetInt(mem, addr, 2);
X		p = AppendStr(out, (disp == 0) ?  "ret" : "br");
X		p = AppendStr(p, (fn == 8) ? "ne" : "eq");
X		p = AppendStr(p, "\t\tp, ");
X		APPEND_IMMMARK(p);
X		APPEND_CHAR(p, hex[n]);
X		if (disp != 0) {
X			APPEND_COMMA(p);
X			p = AppendRAddr(p, pc, disp, 2, 3);
X		} else
X			target = NOADDR;
X		
X		itype = branch;
X		break;
X	
X	case 0xc:
X	case 0xe:
X		pc = *addr;
X		if (fn == 0xe)
X			pc += 4;
X			
X		disp = GetInt(mem, addr, 4);
X		p = AppendStr(out, (fn == 0xc) ? "jump" : "call");
X		p = AppendStr(p, ".4\t\t");
X		p = AppendRAddr(p, pc, disp, 4, (fn == 0xc) ? 2 : 6);
X		itype = (fn == 0xc) ? jump : call;
X		break;
X		
X	case 0xd:
X	case 0xf:
X		p = AppendStr(out, (fn == 0xd) ? "jump" : "call");
X		p = AppendStr(p, ".a\t\t");
X		pc = GetInt(mem, addr, 5);
X		p = AppendAddr(p, pc);
X		itype = (fn == 0xd) ? jump : call;
X		target = pc;
X		break;
X	}
X
X	return(p);	
X}
SHAR_EOF
if test 6547 -ne "`wc -c < 'instr8.c'`"
then
	echo shar: "error transmitting 'instr8.c'" '(should have been 6547 characters)'
fi
fi
echo shar: "extracting 'obj.c'" '(8947 characters)'
if test -f 'obj.c'
then
	echo shar: "will not over-write existing file 'obj.c'"
else
sed 's/^X//' << \SHAR_EOF > 'obj.c'
X#include "dis48.h"
X
X#ifdef ANSI
Xchar	*Real(char *mem, NAddr *addr, char *out);
Xchar	*Complex(char *mem, NAddr *addr, char *out);
Xchar	*String(char *mem, NAddr *addr, char *out);
Xchar	*Array(char *mem, NAddr *addr, char *out);
Xchar	*List(char *mem, NAddr *addr, char *out);
Xchar	*GlobalName(char *mem, NAddr *addr, char *out);
Xchar	*LocalName(char *mem, NAddr *addr, char *out);
Xchar	*Program(char *mem, NAddr *addr, char *out);
Xchar	*Algebraic(char *mem, NAddr *addr, char *out);
Xchar	*BinaryInt(char *mem, NAddr *addr, char *out);
Xchar	*Graphic(char *mem, NAddr *addr, char *out);
Xchar	*Tagged(char *mem, NAddr *addr, char *out);
Xchar	*Unit(char *mem, NAddr *addr, char *out);
Xchar	*Xlib(char *mem, NAddr *addr, char *out);
Xchar	*Directory(char *mem, NAddr *addr, char *out);
Xchar	*Library(char *mem, NAddr *addr, char *out);
Xchar	*Backup(char *mem, NAddr *addr, char *out);
Xchar	*Command(char *mem, NAddr *addr, char *out);
Xchar	*Address(char *mem, NAddr *addr, char *out);
Xchar	*LongReal(char *mem, NAddr *addr, char *out);
Xchar	*LongComplex(char *mem, NAddr *addr, char *out);
Xchar	*LinkedArray(char *mem, NAddr *addr, char *out);
Xchar	*Character(char *mem, NAddr *addr, char *out);
Xchar	*Code(char *mem, NAddr *addr, char *out);
Xchar	*LibraryData(char *mem, NAddr *addr, char *out);
X#else
Xchar	*Real();
Xchar	*Complex();
Xchar	*String();
Xchar	*Array();
Xchar	*List();
Xchar	*GlobalName();
Xchar	*LocalName();
Xchar	*Program();
Xchar	*Algebraic();
Xchar	*BinaryInt();
Xchar	*Graphic();
Xchar	*Tagged();
Xchar	*Unit();
Xchar	*Xlib();
Xchar	*Directory();
Xchar	*Library();
Xchar	*Backup();
Xchar	*Command();
Xchar	*Address();
Xchar	*LongReal();
Xchar	*LongComplex();
Xchar	*LinkedArray();
Xchar	*Character();
Xchar	*Code();
Xchar	*LibraryData();
X#endif
X
Xstruct objfunc {
X	NAddr	addr;
X#ifdef ANSI
X	char	*(*func)(char *mem, NAddr *addr, char *out);
X#else
X	char	*(*func)();
X#endif
X} objects[] = {
X	{0x02933, Real},
X	{0x02977, Complex},
X	{0x02a2c, String},
X	{0x029e8, Array},	/* Real */
X	{0x029e8, Array},	/* Complex */
X	{0x02a74, List},
X	{0x02e48, GlobalName},
X	{0x02e6d, LocalName},
X	{0x02d9d, Program},
X	{0x02ab8, Algebraic},
X	{0x02a4e, BinaryInt},
X	{0x02b1e, Graphic},
X	{0x02afc, Tagged},
X	{0x02ada, Unit},
X	{0x02e92, Xlib},
X	{0x02a96, Directory},
X	{0x02b40, Library},
X	{0x02b62, Backup},
X	{0x02e92, Command},	/* Function */
X	{0x02e92, Command},
X	{0x02911, Address},
X	{0x02955, LongReal},
X	{0x0299d, LongComplex},
X	{0x02a0a, LinkedArray},
X	{0x029bf, Character},
X	{0x02dcc, Code},
X	{0x02b88, LibraryData},
X	{0, NULL}
X};
X
XNAddr
X#ifdef ANSI
XObject(char *mem, NAddr addr, char *out)
X#else
XObject(mem, addr, out)
Xchar	*mem;
XNAddr	addr;
Xchar	*out;
X#endif
X{
X	NAddr		n;
X	NAddr		a;
X	struct objfunc	*op;
X	
X	a = addr;
X	n = GetInt(mem, &a, 5);
X	for (op = objects; op->addr != 0; op++)
X		if (op->addr == n)
X			break;
X			
X	if (op->addr == 0) {
X		(void) AppendStr(out, "Unknown Object");
X		return(addr);
X	}
X	
X	(*op->func)(mem, &a, out);
X	return(a);
X}
X
Xchar *
X#ifdef ANSI
XNumber(char *mem, NAddr *addr, char *out, int fl, int xl)
X#else
XNumber(mem, addr, out, fl, xl)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
Xint	fl;
Xint	xl;
X#endif
X{
X	int	fi, xi;
X	Nybble	s, ip, xs;
X	Nybble	x[5];
X	Nybble	f[14];
X	
X	for (xi = 0; xi < xl; xi++)
X		x[xi] = GetNybble(mem, (*addr)++);
X		
X	xs = GetNybble(mem, (*addr)++);
X	
X	for (fi = 0; fi < fl; fi++)
X		f[fi] = GetNybble(mem, (*addr)++);
X		
X	ip = GetNybble(mem, (*addr)++);
X	s = GetNybble(mem, (*addr)++);
X	APPEND_CHAR(out, (s == 0) ? '+' : '-');
X	APPEND_CHAR(out, hex[ip]);
X	APPEND_CHAR(out, '.');
X	while (--fi >= 0)
X		APPEND_CHAR(out, hex[f[fi]]);
X	
X	APPEND_CHAR(out, 'E');
X	APPEND_CHAR(out, (xs == 0) ? '+' : '-');
X	while (--xi >= 0)
X		APPEND_CHAR(out, hex[x[xi]]);	
X		
X	TERMINATE(out);
X	return(out);
X}
X
Xchar *
X#ifdef ANSI
XReal(char *mem, NAddr *addr, char *out)
X#else
XReal(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(Number(mem, addr, out, 11, 2));
X}
X
Xchar *
X#ifdef ANSI
XComplex(char *mem, NAddr *addr, char *out)
X#else
XComplex(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	APPEND_CHAR(out, '(');
X	out = Number(mem, addr, out, 11, 2);
X	APPEND_COMMA(out);
X	out = Number(mem, addr, out, 11, 2);
X	APPEND_CHAR(out, ')');
X	return(out);
X}
X
Xchar *
X#ifdef ANSI
XLongReal(char *mem, NAddr *addr, char *out)
X#else
XLongReal(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(Number(mem, addr, out, 14, 4));
X}
X
Xchar *
X#ifdef ANSI
XLongComplex(char *mem, NAddr *addr, char *out)
X#else
XLongComplex(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	APPEND_CHAR(out, '(');
X	out = Number(mem, addr, out, 14, 4);
X	APPEND_COMMA(out);
X	out = Number(mem, addr, out, 14, 4);
X	APPEND_CHAR(out, ')');
X	return(out);
X}
X
Xchar *
X#ifdef ANSI
XString(char *mem, NAddr *addr, char *out)
X#else
XString(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	int	n;
X	int	lim;
X	char	c;
X	NAddr	a;
X	
X	n = GetInt(mem, addr, 5) - 5;
X	out = AppendStr(out, "String(");
X	out = AppendDecInt(out, n);
X	out = AppendStr(out, ") ");
X	lim = (n > 16) ? 16 : n;
X	a = *addr;
X	out = AppendHexNyb(out, mem, &a, lim);
X	if (lim < n)
X		out = AppendStr(out, "...");
X	
X	out = AppendStr(out, " \"");
X	lim /= 2;
X	a = *addr;
X	while (--lim >= 0) {
X		c = GetInt(mem, &a, 2);
X		if ((c < ' ') || (c > '~'))
X			c = '.';
X			
X		APPEND_CHAR(out, c);
X	}
X	
X	APPEND_CHAR(out, '"');
X	TERMINATE(out);
X	*addr += n;
X	return(out);
X}
X
Xchar	*
X#ifdef ANSI
XArray(char *mem, NAddr *addr, char *out)
X#else
XArray(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(out);
X}
X
Xchar	*
X#ifdef ANSI
XList(char *mem, NAddr *addr, char *out)
X#else
XList(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(out);
X}
X
Xchar	*
X#ifdef ANSI
XGlobalName(char *mem, NAddr *addr, char *out)
X#else
XGlobalName(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(out);
X}
X
Xchar	*
X#ifdef ANSI
XLocalName(char *mem, NAddr *addr, char *out)
X#else
XLocalName(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(out);
X}
X
Xchar	*
X#ifdef ANSI
XProgram(char *mem, NAddr *addr, char *out)
X#else
XProgram(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(out);
X}
X
Xchar	*
X#ifdef ANSI
XAlgebraic(char *mem, NAddr *addr, char *out)
X#else
XAlgebraic(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(out);
X}
X
Xchar	*
X#ifdef ANSI
XBinaryInt(char *mem, NAddr *addr, char *out)
X#else
XBinaryInt(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	int	n;
X	
X	out = AppendStr(out, "BinInt(");
X	n = GetInt(mem, addr, 5);
X	n -= 5;
X	out = AppendDecInt(out, n);
X	out = AppendStr(out, ") ");
X	out = AppendHexNyb(out, mem, addr, n);
X	TERMINATE(out);
X	return(out);
X}
X
Xchar *
X#ifdef ANSI
XGraphic(char *mem, NAddr *addr, char *out)
X#else
XGraphic(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(out);
X}
X
Xchar *
X#ifdef ANSI
XTagged(char *mem, NAddr *addr, char *out)
X#else
XTagged(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(out);
X}
X
Xchar *
X#ifdef ANSI
XUnit(char *mem, NAddr *addr, char *out)
X#else
XUnit(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(out);
X}
X
Xchar *
X#ifdef ANSI
XXlib(char *mem, NAddr *addr, char *out)
X#else
XXlib(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(out);
X}
X
Xchar *
X#ifdef ANSI
XDirectory(char *mem, NAddr *addr, char *out)
X#else
XDirectory(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(out);
X}
X
Xchar *
X#ifdef ANSI
XLibrary(char *mem, NAddr *addr, char *out)
X#else
XLibrary(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(out);
X}
X
Xchar *
X#ifdef ANSI
XBackup(char *mem, NAddr *addr, char *out)
X#else
XBackup(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(out);
X}
X
Xchar *
X#ifdef ANSI
XCommand(char *mem, NAddr *addr, char *out)
X#else
XCommand(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(out);
X}
X
X
Xchar	*
X#ifdef ANSI
XAddress(char *mem, NAddr *addr, char *out)
X#else
XAddress(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	out = AppendStr(out, "Address(5) ");
X	out = AppendHexNyb(out, mem, addr, 5);
X	TERMINATE(out);
X	return(out);
X}
X
Xchar	*
X#ifdef ANSI
XLinkedArray(char *mem, NAddr *addr, char *out)
X#else
XLinkedArray(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(out);
X}
X
Xchar	*
X#ifdef ANSI
XCharacter(char *mem, NAddr *addr, char *out)
X#else
XCharacter(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	int	c;
X	NAddr	a;
X	
X	out = AppendStr(out, "Character(2) ");
X	a = *addr;
X	out = AppendHexNyb(out, mem, addr, 2);
X	out = AppendStr(out, " '");
X	c = GetInt(mem, &a, 2);
X	if ((c < ' ') || (c > '~'))
X		c = '.';
X	
X	APPEND_CHAR(out, c);
X	APPEND_CHAR(out, '\'');
X	TERMINATE(out);
X	return(out);
X}
X
Xchar	*
X#ifdef ANSI
XCode(char *mem, NAddr *addr, char *out)
X#else
XCode(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(out);
X}
X
Xchar	*
X#ifdef ANSI
XLibraryData(char *mem, NAddr *addr, char *out)
X#else
XLibraryData(mem, addr, out)
Xchar	*mem;
XNAddr	*addr;
Xchar	*out;
X#endif
X{
X	return(out);
X}
SHAR_EOF
if test 8947 -ne "`wc -c < 'obj.c'`"
then
	echo shar: "error transmitting 'obj.c'" '(should have been 8947 characters)'
fi
fi
echo shar: "extracting 'trace.c'" '(1301 characters)'
if test -f 'trace.c'
then
	echo shar: "will not over-write existing file 'trace.c'"
else
sed 's/^X//' << \SHAR_EOF > 'trace.c'
X#include "dis48.h"
X#include <fcntl.h>
X
X#define NSIZE 524288
X#define BSIZE (NSIZE / 2)
X
XBitmap	completed;
Xint	dopause = 0;
X
X#ifdef ANSI
Xmain(int argc, char **argv)
X#else
Xmain(argc, argv)
Xint	argc;
Xchar	**argv;
X#endif
X{
X	char	*p;
X	int	n;
X	int	s, e;
X	char	buf[80];
X	char	*mem, *malloc();
X	
X	if ((argc > 1) && !strcmp(argv[1], "-p"))
X		dopause = 1;
X		
X	if ((mem = malloc(BSIZE)) == NULL) {
X		fprintf(stderr, "malloc failed\n");
X		exit(1);
X	}
X	
X	if ((completed = malloc(BITS(NSIZE))) == NULL) {
X		fprintf(stderr, "malloc failed\n");
X		goto done;
X	}
X	
X	memset(completed, 0, BITS(NSIZE));
X	if ((n = open("rom", O_RDONLY)) < 0) {
X		fprintf(stderr, "open failed\n");
X		goto done2;
X	}
X	
X	if (read(n, mem, BSIZE) != BSIZE) {
X		fprintf(stderr, "read failed\n");
X		close(n);
X		goto done2;
X	}
X	
X	(void) close(n);
X	fprintf(stderr, "start?\n");
X	if (fgets(buf, sizeof(buf), stdin) == NULL)
X		goto done2;
X		
X	if (sscanf(buf, "%x", &s) != 1)
X		goto done2;
X		
X	Disassemble(mem, s, NOADDR, stdout);
X	for (s = 0; s < 0x80000;) {
X		while (!BITTEST(completed, s))
X			s++;
X			
X		e = s;
X		while (BITTEST(completed, e) && (e < 0x80000))
X			e++;
X		
X		e--;
X		printf("\n");
X		/*fprintf(stderr, "S: %05x E: %05x\n", s, e);*/
X		Disassemble(mem, s, e, stdout);
X		s = ++e;
X	}
X	
Xdone2:
X	free(completed);
Xdone:	
X	free(mem);
X	exit(0);
X}
SHAR_EOF
if test 1301 -ne "`wc -c < 'trace.c'`"
then
	echo shar: "error transmitting 'trace.c'" '(should have been 1301 characters)'
fi
fi
exit 0
#	End of shell archive
-- 
Craig Ruff      	NCAR			cruff@ncar.ucar.edu
(303) 497-1211  	P.O. Box 3000
			Boulder, CO  80307

From comp.sys.handhelds Mon Apr 30 13:13:20 1990
Path: fauern!ira.uka.de!snorkelwacker!usc!samsung!uunet!microsoft!alonzo
From: alonzo@microsoft.UUCP (Alonzo GARIEPY)
Newsgroups: comp.sys.handhelds
Subject: Re: Saturn (HP48 CPU) disassembler part 1 of 2
Message-ID: <54338@microsoft.UUCP>
Date: 29 Apr 90 23:16:08 GMT
References: <7124@ncar.ucar.edu>
Reply-To: alonzo@microsoft.UUCP (Alonzo GARIEPY)
Organization: Microsoft Corp., Redmond WA
Lines: 48
Status: OR

Various people are working on assemblers and disassemblers for
the Saturn processor used in the HP 28 and HP 48.  I have been
called on to clarify and coordinate information about syntax,
errata, and extensions to the mnemonics in my processor notes.

There is some small benefit to be had from standardizing the
format of input and output files for these utilities.  As a
start, here are a few point of note:

1.	This standard set of mnemonics is called "Babel".  This is
	because of the questionable nature of defining a set of
	mnemonics completely unlike those used by HP internally.

2.	I have written an assembler/disassembler in Prolog which I
	will not be releasing because it is too primitive, too slow,
	and too difficult to maintain.  This program has been used
	successfully to find a significant number of errors in other
	assemblers and disassemblers.

3.	At some point, I may write a version of this in portable C.

4.	Tokens beginning with a digit are decimal numbers.  Tokens
	beginning with a # are hex numbers.

5.	Indirection through a register is indicated by putting an @ sign
	before the register.

6.	My program uses the same format for input and output files.  This
	is convenient since it is both an assembler and disassembler.  The
	format of each line is as follows:

#address: #hexcode	label:	inst.field arg,arg     ; comment

	The address and hexcode are optional/ignored during assembly
	and everything to the right is ignored during disassembly.
	If all fields are present, one can do an assemble/disassemble
	pass to check consistency.

7.	The pseudo-op for embedding data in the instruction stream is:

	DATA.field #number

	where field is any of the field types supported by the assembler
	and is used to determine the number of nibbles stored, zero extending
	number if necessary.

Alonzo Gariepy
alonzo@microsoft

From comp.sys.handhelds Wed May  9 10:18:59 1990
Path: fauern!unido!mcsun!uunet!cs.utexas.edu!usc!ucsd!ucbvax!ndsuhp.UUCP!hernes
From: hernes@ndsuhp.UUCP
Newsgroups: comp.sys.handhelds
Subject: less for the '48
Message-ID: <9005072046.AA15468@plains.NoDak.edu>
Date: 7 May 90 20:46:43 GMT
Sender: daemon@ucbvax.BERKELEY.EDU
Distribution: inet
Organization: The Internet
Lines: 133
Status: OR

Hi all,

The following progs form a simple string viewer for the '48.
There are two main progs.  One STR->GROB takes a long string,
breaks it at either a newline ot at 22 characters, then converts
it into a grob.  This has the benefit that you can view any of the
three different character sizes, or you can upload it and look at it
on a pc, or mix it with graphics, etc.....
The other program is probably a little more useful,  'Less' takes a string
from the stack, breaks it up as described above, then views one 'page' at
a time.  It was written to be easy to expand.  Currently, the only functions
supported are page up, page down, line up, line down, quit, go to top, and
go to end.  The default key-bindings are set for B-F and right shift B & C.
The key-bindings can be changed, or added simply by changing the key number
in the CASE statement, or by adding a "OVER (new-key-number-here) SAME OR" to
the test-clause in the CASE statement.

---
Eric L. Hernes I.
=======================

Here are the progs:

%%HP: T(3)A(D)F(.);
STR\->GROB
\<< SPLIT DEPTH \->LIST
\-> A
  \<< # 83h A SIZE 8
* R\->B BLANK A 1
SWAP SIZE
    FOR I A I GET 2
\->GROB # 0h I 1 - 8
* R\->B 2 \->LIST SWAP
GOR
    NEXT
  \>>
\>>


%%HP: T(3)A(D)F(.);
LL
\<< DUP 7 + SUB 1 7
  FOR ln DUP ln
    IFERR GET
    THEN DROP DROP
"~"
    END ln DISP
  NEXT 1 FREEZE 2
FREEZE DROP
\>>



%%HP: T(3)A(D)F(.);
SPLIT
\<<
  WHILE DUP SIZE 22
> OVER "
" POS OR
  REPEAT DUP "
"
POS DUP DUP
    IF 22 \<= AND
    THEN OVER SWAP
1 SWAP DUP 4 ROLLD
1 - SUB 3 ROLLD 1 +
OVER SIZE SUB
    ELSE DROP DUP 1
22 SUB SWAP 23 OVER
SIZE SUB
    END
  END DUP "" ==
  IF
  THEN DROP
  END
\>>




%%HP: T(3)A(D)F(.);
Less
\<< SPLIT DEPTH \->LIST
1 RCLMENU RCLF \-> A
L men FLAG
  \<< 64 SF -49 -50
CF CF
    WHILE 64 FS?
    REPEAT A L LL L
6 + A SIZE / 100 *
IP DUP 100 < SWAP
\->STR "%" + "END"
IFTE { "P\|v" "P\|^"
"\|v" "\|^" "QUIT" } +
TMENU -1 WAIT
      CASE  DUP
12.1 SAME
        THEN DROP L
DUP 7 + A SIZE < 7
* + 'L' STO
        END DUP
13.1 SAME
        THEN DROP L
7 - DUP 1 \>= SWAP 1
IFTE 'L' STO
        END DUP
14.1 SAME
        THEN DROP L
DUP 1 + A SIZE < +
'L' STO
        END DUP
15.1 SAME
        THEN DROP L
DUP 1 - 0 > - 'L'
STO
        END DUP
16.1 SAME
        THEN DROP
FLAG STOF 64 CF men
MENU
        END DUP
12.3 SAME
        THEN DROP A
SIZE 6 - 'L' STO
        END DUP
13.3 SAME
        THEN DROP 1
'L' STO
        END
      END
    END
  \>>
\>>

From comp.sys.handhelds Mon May 14 10:59:27 1990
Path: fauern!ira.uka.de!snorkelwacker!tut.cis.ohio-state.edu!ucsd!rutgers!njin!princeton!notecnirp!mg
From: mg@notecnirp.Princeton.EDU (Michael Golan)
Newsgroups: comp.sys.handhelds
Subject: HP48SX  10 stack levels viewer
Message-ID: <26913@princeton.Princeton.EDU>
Date: 13 May 90 05:55:37 GMT
Sender: news@princeton.Princeton.EDU
Reply-To: mg@princeton.Princeton.EDU (Michael Golan)
Organization: Dept. of Computer Science, Princeton University
Lines: 43
Status: OR

The following program let you view 10 levels of your stack. It is written
for speed, so it does not right align. I am not sure this is even good,
as the font is really small.
You must have at least one item on the stack. Running this program erases
the current PICT. Press "ON" to return to the normal stack. You can see
the output again by pressing the left-cursor (graph) key.

VSTK: #4475d 119.5

%%HP: T(3)A(D)F(.);
@ 
@ VSTK - View stack (10 lines). Written by Michael Golan, version 1.0 5/1/90
@ input: non empty stack. (unmodifed by command)
@
@ Output: display PICT with 10 levels of the stack. Press ON to return to
@         stack (text) mode
@
@ Algorithm comments:
@ destroy current PICT. Left justify stack values, because of speed.
@ uses small font, so 'a' and 'A' looks the same.
@ ->GROB on strings remove "", but if you tag it 1st, it works fine
@
@ BYTES: #4475d 119.5

\<< ERASE                               @ erase current PICT
    DEPTH 10 MIN                        @ find no. of levels to display
    1 SWAP
    FOR L 
      L PICK                            @ get stack level L
      L \->TAG                          @ tag it with stack level
      1 \->GROB                         @ make a graphic of it
      PICT
      # 0d 
      10.3 L - 6 * R\->B                @ Y coordinate: (10-L)*6-2
      2 \->LIST ROT                     @ get coordinates into REPL format
      REPL                              @ put in PICT
    NEXT 
    { } PVIEW                           @ display it till 'ON' pressed
\>>

Enjoy
 Michael Golan
 mg@princeton.edu

From comp.sys.handhelds Wed May 16 00:08:31 1990
Path: fauern!unido!mcsun!uunet!jarthur!usc!ucsd!ucbvax!ndsuhp.UUCP!hernes
From: hernes@ndsuhp.UUCP
Newsgroups: comp.sys.handhelds
Subject: hp-48 clean-up programs
Message-ID: <9005152123.AA24267@plains.NoDak.edu>
Date: 15 May 90 21:23:15 GMT
Sender: daemon@ucbvax.BERKELEY.EDU
Distribution: inet
Organization: The Internet
Lines: 30
Status: OR


Someone asked for programs that "cleaned" up the stuff in the hp.
The following program purges all of the variables used in the current
equation.  It is easy and painless to run, just press the PURGEQ button,
(or alternatively, bind it to a key, for example, the user-purge, key).

PURGEQ
%%HP: T(3)A(D)F(.);
\<< DEPTH \->LIST \-> a
  \<< EQ DUP TYPE
    IF 5 SAME
    THEN EVAL
    END
    WHILE DEPTH
    REPEAT DUP TYPE
      CASE DUP 6
SAME
        THEN DROP
PURGE
        END 9 SAME
        THEN OBJ\->
DROP DROP
        END DROP
      END
    END a OBJ\-> DROP
  \>>
\>>

Eric L. Hernes I.
hernes@ndsuhp.uucp => H,E,R,N,E,S,at,N,D,S,U,H,P,dot,U,U,C,P

From comp.sys.handhelds Wed May 16 00:08:50 1990
Path: fauern!unido!mcsun!uunet!snorkelwacker!think!zaphod.mps.ohio-state.edu!sol.ctr.columbia.edu!emory!mephisto!prism!gt3398b
From: gt3398b@prism.gatech.EDU (DELANO,ANDREW DOUGLAS)
Newsgroups: comp.sys.handhelds
Subject: INCO ON THE 48sx
Message-ID: <9331@hydra.gatech.EDU>
Date: 15 May 90 19:24:25 GMT
Organization: Georgia Institute of Technology
Lines: 161
Status: OR



I just finished converting the game INCO to work on the 48sx.  It is a
simple little game, but it does'nt take up much memory, and I like it.
I got the 28s copy from the ftp site funic.funet.fi.  I had to add one
program of my own (K->STR) and make a few minor changes.  It works great
on the 48 and is in ready to download form.  NOTE!!: Joachim Isaksson
wrote this program for the 28s, and all credit for it should go to him.
All I have done is convert it to work on the 48sx.  I have included 
Joachim's original instructions followed by the program in ready to
download form.  My thanks to Joachim for creating this fun little
game that helps me get through some of my boring classes.

                               Andy Delano
________________________________________________________________________________  
I have just finished a little game for the HP28, but as I have no write access
to the comp.sys.handhelds I thought I'd send it to somebody who can check it
out and 'News' it if it's any good. Feel free to make a better version, as this
one is no 'masterpiece'. 

						Joachim Isaksson
					      (d89-jin@sm.luth.se)

Instructions and program following...

-------------------------------------------------------------------------------

The game of 'INCO'

This is a game based on a 'simple' idea. When you enter a number and press the
'INCO' button the HP28 will start with a 3 by 3 array containing only nines,
mixing it the number of times you entered by picking a row and a column in
which it will decrease all numbers by one. It will then display the resulting
array and your objective is to get the array containing only nines back by
pressing a digit, thereby increasing all numbers in the row/column you picked.
(Hard to explain, but you'll soon pick up the idea)
It isn't very well programmed, but I haven't had my HP28 for more than 3 weeks
so I hope I am excused. If anyone makes a better version, please post it to me
or even better to the net.


%%HP: T(3)A(D)F(.);
DIR
  INCO
    \<< \-> dif
      \<< CLLCD { 3 3
} 9 CON 1 dif
        FOR j RAND
9 * 1 + IP \->ARR -
        NEXT \->ADJ 0
SWAP
        DO SWAP 1 +
SWAP DUP \->DSP 0
          DO DROP
            DO
            UNTIL
KEY
            END
          UNTIL
K\->STR DUP DUP "1" \>=
SWAP "9" \<= AND
          END STR\->
\->ARR + \->ADJ 100 .01
BEEP
        UNTIL DUP {
3 3 } 9 CON SAME
        END \->DSP
10000 .01 BEEP \->STR
"   Well done "
SWAP + " Moves" + 4
DISP 0 FREEZE
      \>>
    \>>
  \->DSP
    \<< \->STR
"         " \-> arr
spc
      \<< spc arr 4 8
SUB + 1 DISP spc
arr 15 19 SUB + 2
DISP spc arr 26 30
SUB + 3 DISP "" 4
DISP
      \>>
    \>>
  \->ARR
    \<< DUP 1 - 3 MOD
1 + SWAP 9 SWAP - 3
/ 1 + IP \-> y x
      \<< { 3 3 } 0
CON 1 3
        FOR j { x j
} 1 PUT { j y } 1
PUT
        NEXT
      \>>
    \>>
  \->ADJ
    \<< ARRY\-> DROP 1
9
      FOR j 9 ROLL
10 MOD
      NEXT { 3 3 }
\->ARRY
    \>>
  K\->STR
    \<<
      CASE
        IF DUP 82
==
        THEN DROP
"1"
        END
        IF DUP 83
==
        THEN DROP
"2"
        END
        IF DUP 84
==
        THEN DROP
"3"
        END
        IF DUP 72
==
        THEN DROP
"4"
        END
        IF DUP 73
==
        THEN DROP
"5"
        END
        IF DUP 74
==
        THEN DROP
"6"
        END
        IF DUP 62
==
        THEN DROP
"7"
        END
        IF DUP 63
==
        THEN DROP
"8"
        END
        IF DUP 64
==
        THEN DROP
"9"
        END
      END
    \>>
END
-- 
DELANO,ANDREW DOUGLAS
Georgia Institute of Technology, Atlanta Georgia, 30332
uucp:	  ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!gt3398b
Internet: gt3398b@prism.gatech.edu

From comp.sys.handhelds Thu May 31 11:14:34 1990
Path: fauern!unido!mcsun!uunet!tut.cis.ohio-state.edu!uc!norge.unet.umn.edu!fin
From: fin@norge.unet.umn.edu (Craig A. Finseth)
Newsgroups: comp.sys.handhelds
Subject: Browser Routines for the HP-48SX [long message]
Message-ID: <1834@uc.msc.umn.edu>
Date: 24 May 90 20:59:05 GMT
References: <1833@uc.msc.umn.edu>
Sender: news@uc.msc.umn.edu
Organization: Univ Netw Serv, Univ of Minn
Lines: 630
Status: OR

>>> This code is for a general-purpose list browser (test routine follows).

>>> I will be posting a set of astronomy routines and alamanc in a
week or so.  They use this browser, so if they sound interesting, save
this.

Craig A. Finseth			fin@unet.umn.edu [CAF13]
University Networking Services		+1 612 624 3375 desk
University of Minnesota			+1 612 626 1002 FAX
130 Lind Hall, 207 Church St SE, Minneapolis MN 55455-0134, U.S.A.

------------------------------------------------------------

The HP-48SX Browser Instructions and Commented Listing
Version 1.1, 23 May 1990
Copyright (c) 1990 by Jeff Brown, free for personal non-commercial use.
Formatted for monofont (e.g. Courier type for Postscript/Macintosh users)

Contents:

	Purpose of the Browser
	Parts of the Browser Display
	Browser Keys
	Applications of the Browser
	How to Use the Browser
	Advanced Use of the Browser
	Technical Details of the Browser
	Areas for Improvement
	Browser Commented Listing
	Browser Variables
	Browser Downloadable Listing


PURPOSE OF THE BROWSER

The browser provides a clean, intuitive way for users to browse the
contents of a list and select an item.

If you have used the catalog function of the Solver or Plotter, you
have already used a kind of browser.  The browser is not an
application.  It is a user interface tool to be used by your
applications.  At about 1,800 bytes, it is small enough to be used
even in 32K machines.

The Browser is a simple to incorporate but powerful programming tool. 
Your users will find it an intuitive and convenient way to choose from
among data items or options.

Your program calls the browser with a message and a list on the stack. 
The browser displays your message and list to the user.  It manages
keys and the display, permitting the user to scroll and page through
the list until he finds the appropriate item.  When the user selects
an item, the browser returns its current state, the selected item and
the item's position to the stack.

Using the results from a browse, you can change or edit items at the
user's request or choose different execution paths.  Since the browser
returns its state, you can accept the user's choice, take action and
return the user to browsing where he last left off.  This permits some
fairly flashy applications.

The browser is very simple to operate but it can be used in so many
ways, it takes a bit of explaining.  If you wish to just give it a
try, skip to the 'How to Use the Browser' section.


PARTS OF THE BROWSER DISPLAY

Description           Example HP-48 display       Display Line Used
-----------------     ----------------------     -----------------
Prompt message ->     Select a company:           Line 1

               ->      Apple
              |        Compaq
List pane   --|       >Hewlett-Packard            Lines 2-6
              |        IBM
               ->      Zenith 

Scroll bar     ->     <--------####-------->      Line 7

The prompt message is your message to the user indicating what is
being browsed and what you expect the user to do.

The list pane is a scrolling window onto your list.  There is always a
current item in the window.  This item is displayed with a cursor in
front of it.

The scroll bar graphically represents the location of the list pane
within the list. A block of box characters (called a 'thumb')
representing the pane moves along the scroll bar as the user scrolls
through the list. The size of the thumb represents the portion of the
list visible in the pane. The larger the list, the smaller the thumb.

Note: the box characters of the thumb are represented here as '#'
since there is no ASCII box character.


BROWSER KEYS

Prefix       Key               Function
-----------  ----------        ---------------------------------------
             Up arrow          scroll up one item
Left-shift   Up arrow          scroll up one page (five items)
Right-shift  Up arrow          go to top of list
             Down arrow        scroll down one item
Left-shift   Down arrow        scroll down one page (five items)
Right-shift  Down arrow        go to bottom of list
             Enter             accept current item
             Backspace         cancel browsing without choosing

The left arrow key functions identically to the up arrow and the right
arrow key functions identically to the down arrow.


APPLICATIONS OF THE BROWSER

	- Address or phone number lists
	- Inspectors that let the user delve into the structure of
	  objects.
	- Presentation of program options

For a good real-live application of the browser, refer to the Almanac program and Astronomy Directory by Craig Finseth and Lauren Nelson.


HOW TO USE THE BROWSER

The browser takes two arguments from the stack.  The simplest way to
call the browser is to put the following arguments on the stack:

	Level 2: your message to the user (string)
	Level 1: the list to be browsed (list or name)

The browser will take care of the user interaction and return the
following results to the stack:

	Level 2: state of the browser (list)
	Level 1: acceptance information (a list) consisting of:

		- item selected (type depends on the object),
		- position of the item in the list (real number),
		- 0 if user cancelled or keycode (51.1) if user
		  accepted (real number)

Example:

Peter Palmer, proprietor of Palmer's Polygonal Pies, wishes to record
customer orders using his trusty HP-48SX.  Since pie names are long
and descriptive, it would be best to select the pies from a list.

To build a program which takes orders, Peter stores the available
types of pies in a variable:

	{ "Triangular Treacle" "Raspberry Rhombus" "Pentagonal Plum"
	"Hexagon Hash" "Strawberry Septagon"  "Octagonal Orange Mousse"
	"Nonpareil Nonagon" "Decagonal Delight"} 'pies' STO

Next, he writes a little program that takes pie orders.  A fragment
that gets the user's choice of pie looks like this:

	"Select a Pie:" pies BROWSE 1 GET 

This invokes the browser:

	Select a pie:
	>Triangular Treacle
	 Raspberry Rhombus
	 Pentagonal Praline
	 Hexagon Hash
	 Strawberry Septagon
	##############------->

After the user chooses a pie, the 1 GET retrieves the description of
the user's chosen pie.  Peter's program could also add the choice to
an order list or use the position of the choice (2 GET) to look up
pricing information from a price list.


ADVANCED USE OF THE BROWSER

If you wish to have the browser start at a particular position in the
list or if you need to specially format your list items for display,
there is an alternate way to call the browser:

	Level 2: a list consisting of:

		- Your message (string)
		- Current item in list (real number)
		- Lines off-screen above the list pane (real number)
		- Procedure used to format your list items (program)

	Level 1: the list to be browsed (list or name)

The list in level 2 is the same format as that returned to level 2
when the browser ends.  This is a brief run-down of its parts:

	1) Your message to the user

	2) The current item (the list position pointed to by the cursor).

	3) The lines off-screen tells the browser how far down in the
	list its window should start (if the current item is not visible
	in this area, the list pane will be moved far enough in the
	appropriate direction to include it).

	4) The browser will run your program object on each list item
	prior to displaying it.  Your program object should take an item
	(extracted from your list by the browser and placed in level 1)
	and format it for display by the browser.  The browser will call
	this code every time it draws an item in the display so keep it
	fast and simple.

This approach is very powerful because you can start the browser in
any position and format its items any way you like.  The list is
returned to you (updated to match the user's actions) when the browser
ends.  This enables you to take the user's response, carry out
appropriate actions and return to browsing the list in the same
position the user left off.  

One use of this is to browse hierarchically, that is, browse a list of
lists, returning to the proper place every time the user pops up a
level.  To do this, just keep a list containing your list path and a
matching list containing browser state lists.  When the users pops up
a level, just discard the last item in each list and call the browser
with the new last item.  For example a program for selecting people to
receive mailings might work like this:

Select a company:
 Apple
 Compaq
>Hewlett-Packard	User selects company, presses enter
 IBM
 Zenith 
######################

	Select a division:
	 Boise
	>Corvallis
	 Phoenix		User selects division, presses enter
	 Palo Alto
	 Santa Clara 
	<-###############---->

		Select an Employee:
		 Sanders, John
		 Terpack, Daniel
		 Vogel, Eric		User selects employee (presses enter)
		 West, Carmen		(repeat as needed then press backspace)
		>Wickes, William 
		<-------------------#>

	Select a division:
	 Boise
	>Corvallis
	 Phoenix		User is returned to the division browser
	 Palo Alto		(with list pane and current item unchanged)
	 Santa Clara 
	<-###############---->


TECHNICAL DETAILS OF THE BROWSER

The original version of the browser was a collection of three main
program objects and about two dozen state variables and key handling
objects.  To eliminate the need for a separate browser directory, I
have compressed the whole thing into a single program object (with
considerable loss of readability).

The browser has four logical parts:

	Browse - sets things up for browsing

	MainLoop - waits for key events and hands them off to handlers.

	DrawView - draws the browser after key events change it.

	Key handlers - interpret the meaning of various keys.
     

BROWSE

This initialization code is run when the browser is called.  It
extracts the input parameters and puts them in temporary variables. 
It also calculates the size of the thumb.  When Browse finishes setup,
it flows into the main loop.

MAINLOOP

The main loop is wrapped around the DrawView procedure and the key
handlers.  It loops, drawing the browser and handling keys until the
user accepts an item or aborts the browsing process.

DRAWVIEW

DrawView checks the current state of the browser and uses one of three
methods to draw the browser's visible parts on the screen.

If the list pane is above the current item (the user scrolled down) it
redraws the pane from the bottom up.

If the list pane is below the current item (the user scrolled up) it
redraws the pane from the top down.

If the current and previous items are both in the pane (the user moved
the cursor within the visible region) only the current and previous
items are redrawn.

Originally, I simply drew the lines of the browser from the top down,
every time.  Performance was so slow that when scrolling down, the
display gave the impression that it was scrolling up.  This came about
because the user pressed the down arrow key but saw the top lines of
the display changing first.  To remedy this, I determine which way the
user scrolled and redraw the lines from that direction.  This gives a
satisfying sense of scrolling in the proper direction.

To further improve performance, DrawView checks to see if the cursor
has moved out of or into the visible region.  If it has not, only the
previous item and the current item are redrawn.  This cuts drawing
time in half.

I decided to implement the scroll bar fairly early in development. 
Browsing a large list can be disorienting. People need to know where
they are in a list and how much progress they are making with each
keystroke. They use the cursor keys differently in large lists than
they do in small lists so constant visual feedback is very valuable.


AREAS FOR IMPROVEMENT

Speed is not as snappy as it ought to be.  Limited redraws take about
0.8 seconds, full redraws take 1.5 seconds.  The code needs to run
about four times faster.  An assembly language version would improve
this.  Since my Saturn assembly skills are a bit rusty, I will leave
this to others for the time being.

I have not tried bit-wise scrolling of the list pane.  It is
conceivable that this might be faster than re-drawing the entire pane
on some occasions.

The scroll bar is a bit cheesy in that it is horizontal and the list
is displayed vertically.  This was a practical necessity since there
isn't enough vertical resolution to do it vertically.  Ideally, I
would do a vertical bit-mapped scroll bar.  This would have enough
resolution (48 pixels) for the job.  Again, assembly language might be
the only practical solution.

Originally, I planned to take a menu key list and display it so you
could add user-defined features to the browser, but this was torpedoed
by HP's method of handling menus.  There is no supported way to
display a menu and retain program control. A program must halt for the
menu to appear. In short, I can't display your menu and give you back
keycodes when the user presses menu keys. To further exacerbate matters, I can't get rid of the potentially confusing menus already displayed or use the extra line for more items.  Ideas, anyone?

I may do some experimentation with binary searches on ordered lists. 
This would permit an 'alpha mode' for the browser so users could press
a letter key and instantly jump to that part of the list.

Some applications may want several items from a single browse. Features to permit selection of multiple items (by creating contiguous or non-contiguous selections) before accepting would be useful if user 
interface issues could be resolved. 

Features for range selection and Cut/Copy/Paste would be great for
interactive list editing.  This would be a dream for editing programs.


BROWSER COMMENTED LISTING

/* browse  L2: msg | {msg c brOS fmtP} L1: list | name of list */

\<<
"by Jeff Brown (612) 646-2478" DROP
"v1.1" DROP
DUP
IF TYPE 6 == THEN		/* if it is a name, get its value */
	EVAL
END
DUP				/* list */
SIZE				/* listL */
DUP 5 MIN			/* brL */
DUP2
158 CHR				/* loop to build thumb */
\-> l b t
\<<
""
1
b l / 22 * 0 RND
FOR i
t +
NEXT
\>>				/* thumb */
"\<---------------------\->"	/* scrB */
6 ROLL DUP
IF TYPE 5 ==
THEN LIST\-> DROP		/* msg c brOS fmtP */
     ELSE 1 0 \<< \>> {}
END
3 PICK				/* p */
\<<220 0.125 BEEP\>>		/* eBeep */
134 CHR				/* cursChr */
1				/* full */
1				/* continue */
1				/* j */
CLLCD
\-> list listL brL thumb scrB msg c brOS fmtP p eBeep cursChr
full continue j

\<<
Msg 1 DISP

WHILE continue 1 ==
REPEAT

/* drawView */

     1 DUP 'j' STO brL		/* loop limits */
     CASE
	  c brOs s THEN		/* user moved above pane */
	       c 1 - 'brOs' STO
	       1 'full' STO
	  END
	  c brOs brL + > THEN	/* user moved below pane */
	       DROP2 c brL - 'brOs' STO
	       1 'full' STO
	       brL 1 -1 'j' STO	/* set new loop limits */
	  END
     END
     IF full 1 == THEN		/* full redraw is needed */
	  0 'full' STO
	  FOR i
	       IF i c brOs - = THEN 
		    " " list brOs i + GET fmtP EVAL 
		    \->STR + i 1 + DISP
	       ELSE
		    cursChr list brOs i + GET fmtP EVAL 
		    \->STR + i 1 + DISP
	       END
	  J STEP
	  c 'p' STO
	  scrB brOs listL / 22 * .5 + 0 RND thumb REPL 7 DISP
     ELSE DROP2
	  " " list p GET fmtP EVAL \->STR + p brOs - 1 + DISP
	  cursChr list c GET fmtP EVAL \->STR + c brOs - 1 + DISP
     END
     3 FREEZE

/* mainLoop */

0 WAIT \-> k
     \<<
     IF k FP .3 > THEN k .3 - 'k' STO END
     CASE k IP DUP 35 == SWAP 36 == OR THEN	/* a down key*/
	       IF c listL == THEN 
		    eBeep EVAL
		    ELSE listL			/* bottom of list */
		    c DUP DUP 'p' STO
		    brL + listL MIN		/* page dn/last item */
		    SWAP 1 +			/* item down */
		    k FP 10 * ROLL
		    'c' STO DROP2		/* choose by keycode */
	       END
	  END
	  k IP DUP 25 == SWAP 34 == OR THEN	/* an up key */
	       IF c 1 == THEN
		    eBeep EVAL
		    ELSE 1			/* top of list */
		    c DUP DUP 'p' STO
		    brL - 1 MAX			/* page up/1st item */
		    SWAP 1 -			/* item up */
		    k FP 10 * ROLL		/* choose by keycode */
		    'c' STO DROP2
	       END
	  END
	  k 51.1 == THEN			/* enter */
	       list c GET c 0 'continue' STO
	  END
	  k 15.1 == THEN			/* cancel */
	       0 DUP 'continue' STO
	  END
     END
     \>>
END
{} msg + c + brOS + fmtP +
3 ROLLD
\>>


BROWSER VARIABLES

continue	boolean		Should waitLoop continue?
full		boolean		Should drawView do entire pane?
cursChr		char		The cursor character
brL		integer		Length (in lines) of list pane
brOs		integer		Items above list pane
c		integer		Position of current item in list
p		integer		Position of previous item in list
msg		string		The prompt message
listL		integer		Number of items in List
list		list		The list being browsed
scrB		sring		22 character image of the scroll bar
thumb		string		The text image for the thumb
j		integer		Loop increment value (-1 or 1)


BROWSER DOWNLOADABLE LISTING

Checksum: #3e2h
Size: 1751
------------------------------------------------------------
%%HP: T(3)A(D)F(.);
\<< "v1.1" DROP DUP
  IF DTAG TYPE 6 ==
  THEN EVAL
  END DUP SIZE DUP
5 MIN DUP2 158 CHR
\-> l b t
  \<< "" 1 b l / 22 *
0 RND
    FOR i t +
    NEXT
  \>>
"\<---------------------\->"
6 ROLL DUP
  IF DTAG TYPE 5 ==
  THEN LIST\-> DROP
  ELSE 1 0
    \<<
    \>>
  END 3 PICK
  \<< 220 .125 BEEP
  \>> 134 CHR 1 1 1
CLLCD \-> list listL
brL thumb scrB msg
c brOs fmtP p eBeep
cursChr full
continue j
  \<< msg 1 DISP
    WHILE continue
1 ==
    REPEAT 1 DUP
'j' STO brL
      CASE c brOs \<=
        THEN c 1 -
'brOs' STO 1 'full'
STO
        END c brOs
brL + >
        THEN DROP2
c brL - 'brOs' STO
1 'full' STO brL 1
-1 'j' STO
        END
      END
      IF full 1 ==
      THEN 0 'full'
STO
        FOR i
          IF i c
brOs - \=/
          THEN " "
list brOs i + GET
fmtP EVAL \->STR + i
1 + DISP
          ELSE
cursChr list brOs i
+ GET fmtP EVAL
\->STR + i 1 + DISP
          END j
        STEP c 'p'
STO scrB brOs listL
/ 22 * .5 + 0 RND
thumb REPL 7 DISP
      ELSE DROP2
" " list p GET fmtP
EVAL \->STR + p brOs
- 1 + DISP cursChr
list c GET fmtP
EVAL \->STR + c brOs
- 1 + DISP
      END 3 FREEZE
0 WAIT \-> k
      \<<
        IF k FP .3
>
        THEN k .3 -
'k' STO
        END
        CASE k IP
DUP 35 == SWAP 36
== OR
          THEN
            IF c
listL ==
            THEN
eBeep EVAL
            ELSE
listL c DUP DUP 'p'
STO brL + listL MIN
SWAP 1 + k FP 10 *
ROLL 'c' STO DROP2
            END
          END k IP
DUP 25 == SWAP 34
== OR
          THEN
            IF c 1
==
            THEN
eBeep EVAL
            ELSE 1
c DUP DUP 'p' STO
brL - 1 MAX SWAP 1
- k FP 10 * ROLL
'c' STO DROP2
            END
          END k
51.1 ==
          THEN list
c GET c k 0
'continue' STO
          END k
55.1 ==
          THEN "" 0
DUP DUP 'continue'
STO
          END
        END
      \>>
    END { } msg + c
+ brOs + fmtP + 4
ROLLD 3 \->LIST
  \>>
\>>

From comp.sys.handhelds Mon Jun 11 10:50:08 1990
Path: fauern!unido!mcsun!uunet!snorkelwacker!usc!jarthur!nntp-server.caltech.edu!piglet!madler
From: madler@piglet.caltech.edu (Mark Adler)
Newsgroups: comp.sys.handhelds
Subject: Re: HP 48SX Library Builder
Summary: Uuencoded USRLIB1.EXE for the IBM---long message...
Message-ID: <1990Jun8.160144.12673@laguna.ccsf.caltech.edu>
Date: 8 Jun 90 16:01:44 GMT
References: <25590009@hpcvra.CV.HP.COM> <55090@microsoft.UUCP>
Sender: news@laguna.ccsf.caltech.edu
Organization: California Institute of Technology, Pasadena
Lines: 1201
Status: OR


begin 644 usrlib1.exe
M35I5`&H`_0,@`>@`__]M#``(F*$4`+<%'@````$`"@`N"P@`+@LN`@``&0(`
M``<"``#Z`0``XP$``#@!```C`0``$0$```0!``#M````O@```'X````\````
M"0````L`*@`Q`"H`:0`J`),`*@"D`"H`TP`J`",!*@!2`2H`>0$J`(\!*@"Q
M`2H`]0$J`#X"*@#Z`BH`$`,J``P`+@L.`"X+$``N"Q(`+@L4`"X+.``N"SH`
M+@L\`"X+/@`N"T0`+@M*`"X+3``N"U``+@M2`"X+5``N"U8`+@M8`"X+6@`N
M"Y(`+@N4`"X+E@`N"Y@`+@N:`"X+G``N"YX`+@N@`"X+H@`N"Z0`+@L``2X+
M,0,J`)X#*@#,`RH`W@,J`/X#*@`4!"H`+`0J`#X$*@!U!"H`B@0J`)P$*@"F
M!"H`V@0J`!@%*@`H!2H`,P4J`'L%*@")!2H`I@4J`+T%*@#-!2H`Y04J`/P%
M*@`4!BH`+`8J`(,&*@"4!BH`I@8J`+<&*@#+!BH`WP8J`/,&*@`$!RH`$@<J
M`#$'*@!N!RH`C0<J`*$'*@"U!RH`R0<J`-D'*@#M!RH`_0<J`!8(*@`T""H`
M3`@J`&H(*@!_""H`G0@J`+,(*@#+""H`]0@J``L)*@`C"2H`0`DJ`%@)*@!V
M"2H`K`DJ`,$)*@#9"2H`]@DJ``X**@`L"BH`6PHJ`'@**@"-"BH`PPHJ`.\*
M*@`!"RH`&0LJ`$0+*@!6"RH`;@LJ`)$+*@">"RH`L`LJ`-8+*@`&#"H`&PPJ
M`#,,*@!0#"H`,@$N"S0!+@LV`2X+.`$N"SP!+@M8`2X+7@$N"V@!+@MN`2X+
M=@$N"WX!+@N"`2X+B`$N"XP!+@N0`2X+E@$N"Z`!+@NB`2X+I`$N"Z8!+@NN
M`2X+L@$N"[@!+@N\`2X+Q@$N"\@!+@O*`2X+X`$N"^(!+@M[#"H`F0PJ`+H,
M*@#,#"H`X`PJ`/L,*@`*#2H`5PTJ`(L-*@"R#2H`PPTJ`-8-*@#Y#2H`'PXJ
M`$H.*@!<#BH`<@XJ`(8.*@"6#BH`IPXJ`-<.*@#J#BH`%`\J`#$/*@!S#RH`
MD@\J`+(/*@#'#RH`WP\J`/P/*@`4$"H`,A`J`&,0*@`B`BX+)@(N"RP"+@LP
M`BX+-`(N"SH"+@L^`BX+%P`_`3H`/P%[`#\!O0`_`<X`/P'C`#\![@`_`6L!
M/P&*`3\!S@$_`>$!/P$C`C\!7`(_`7H"/P&B`C\!P0(_`>$"/P'T`C\!+@,_
M`40#/P%0`S\!<@,_`7X#/P%``BX+0@(N"V`"+@MB`BX+9`(N"V8"+@MH`BX+
M:@(N"W("+@MT`BX+>`(N"WP"+@N$`BX+A@(N"XP"+@NV`BX+N@(N"P(#+@L$
M`RX+!@,N"P@#+@L:`RX+'`,N"R8#+@N3`S\!)P0_`3D$/P%-!#\!7P0_`7L$
M/P&3!#\!T00_`?@$/P$@!3\!-`4_`4X%/P%X!3\!?P4_`:@%/P'1!3\!V`4_
M`0`&/P$I!C\!,`8_`5@&/P&!!C\!B`8_`;`&/P'5!C\!YP8_`?X&/P$%!S\!
M.`<_`4P'/P%K!S\!D`<_`:0'/P'#!S\!`0@_`0\(/P$Y"#\!30@_`6P(/P'#
M"#\!X`@_`5@)/P%T"3\!B0D_`=L)/P'I"3\!`0H_`1@*/P$P"C\!2`H_`9\*
M/P&Q"C\!Z0H_`1(+/P$E"S\!.0L_`4T+/P%="S\!<0L_`8$+/P&7"S\!P0L_
M`=<+/P$`##\!%0P_`4(,/P%7##\!>@P_`8\,/P&>`RX+I`,N"ZH#+@NR`RX+
MM`,N"[@#+@NZ`RX+O`,N"[X#+@O``RX+P@,N"]0#+@O8`RX+V@,N"]P#+@OX
M`RX+``0N"P8$+@L0!"X+%`0N"QH$+@L>!"X+(@0N"R@$+@LN!"X+N0P_`?(,
M/P$'#3\!*@T_`3\-/P%H#3\!F0T_`;8-/P'5#3\!XPT_`1T./P$T#C\!8PX_
M`8X./P&9#C\!K0X_`<H./P'?#C\!]@X_`0$//P$5#S\!*P\_`4X//P%C#S\!
MC0\_`<0//P''$#\!ZQ`_`001/P$O$3\!41$_`7(1/P&,$3\!H!$_`?H1/P$,
M$C\!3!(_`:82/P'8$C\!ZA(_`2,3/P$S$S\!11,_`5H3/P$X!"X+0`0N"T0$
M+@M*!"X+3@0N"V`$+@N(!"X+L@0N"_H$+@L:!2X+<1,_`8,3/P&?$S\!L!,_
M`=,3/P'M$S\!_Q,_`1<4/P%$%#\!5A0_`604/P&$%#\!D!0_`;`4/P'"%#\!
MW10_`5$5/P%@%3\!<14_`945/P&E%3\!U!4_`?P5/P$G%C\!-A8_`5@6/P&,
M%C\!;`4N"Q$`J`(;`*@")0"H`LD`J`+4`*@"`@&H`BD!J`(V`:@":@&H`OT!
MJ`(O`Z@"4`.H`KH#J`(2!*@"'@2H`CX$J`)0!*@":02H`A$%J`(=!:@"/06H
M`D\%J`*1!:@"90:H`L0&J`('!Z@";0>H`L4'J`+S!Z@"OPFH`@P*J`(U"J@"
M2`JH`LX%+@O0!2X+Z@4N"^P%+@ON!2X+\`4N"_(%+@OT!2X+]@4N"_@%+@OZ
M!2X+_`4N"_X%+@L`!BX+`@8N"P0&+@L&!BX+"`8N"PH&+@LJ!BX++`8N"RX&
M+@M.!BX+4`8N"U(&+@M4!BX+5@8N"U@&+@M:!BX+7`8N"UX&+@M@!BX+8@8N
M"V0&+@MF!BX+:`8N"VH&+@N<`-`(I`#0")X&+@L3`$\#-@!/`TP`3P-B`$\#
M>`!/`XX`3P.D`$\#N@!/`]``3P/<`$\#\0!/`P,!3P,>`4\#4`%/`UX!3P.6
M`4\#O0%/`]\!3P/G`4\#_`%/`P\"3P-*`D\#R`<N"^0'+@OL!RX+[@<N"Q((
M+@LB""X+)`@N"S`(+@M8""X+7@@N"U("3P-^`D\#EP)/`ZH"3P/#`D\#ZP)/
M`S$#3P-<`T\#C@-/`^D#3P/U`T\#&@1/`SL$3P/=!$\#'@5/`SD%3P.(!4\#
MHP5/`_$%3P,,!D\#(@9/`RT&3P-'!D\#8`9/`W`&3P-X!D\#?09/`X(&3P.'
M!D\#C`9/`Y$&3P.6!D\#J@9/`V`(+@MB""X+9`@N"WX(+@N`""X+@@@N"X0(
M+@N&""X+C`@N"XX(+@N4""X+E@@N"YP(+@N>""X+$0"Z`T<`N@-L`+H#?P"Z
M`^0`N@,3`;H#6@&Z`[(!N@/K`;H#^0&Z`QH"N@,H`KH#20*Z`U<"N@-X`KH#
MA@*Z`ZL"N@.Y`KH#V@*Z`^@"N@,)`[H#%P.Z`S@#N@-:`[H#SP.Z`R4$N@._
M!+H##`6Z`T`%N@-T!;H#O@6Z`_(%N@,F!KH#S@:Z`^,&N@/M!KH#*0>Z`SD'
MN@-/![H#G0>Z`]\'N@,0"+H#K@BZ`\L(N@/]"+H#$@FZ`T`)N@/@""X+X@@N
M"^0(+@OF""X+Z`@N"^H(+@OL""X+[@@N"_`(+@OR""X+]`@N"_8(+@OX""X+
M^@@N"_P(+@O^""X+``DN"P()+@L$"2X+!@DN"P@)+@L*"2X+#`DN"PX)+@L0
M"2X+$@DN"Q0)+@L6"2X+&`DN"TP)+@N>"2X+H`DN"Z()+@ND"2X+R@DN"\P)
M+@L-`&0$0@!D!&X`9`32`&0$-@%D!)H!9`2L`60$S@DN"]@)+@O:"2X+W`DN
M"^8)+@OH"2X+Z@DN"^P)+@OV"2X+^`DN"_H)+@O\"2X+!@HN"P@*+@O!`60$
MVP%D!/\!9`0H`F0$.@)D!&D"9`23`F0$L@)D!,X"9`3M`F0$^P)D!`X#9`0@
M`V0$+`-D!`T`EP0@`)<$1`"7!%\`EP2=`)<$JP"7!,L`EP3;`)<$#P&7!"@!
MEP18`9<$:@&7!)$!EP2B`9<$^0&7!"L"EP1!`I<$D0*7!-@"EP1[`Y<$_0.7
M!/,$EP0+!9<$3`67!&`%EP2X!9<$PP67!"@*+@LJ"BX+>@HN"WP*+@M^"BX+
M@`HN"X(*+@N$"BX+A@HN"X@*+@NH"BX+J@HN"ZP*+@NN"BX+L`HN"[(*+@O(
M"BX+_`HN"_X*+@L`"RX+=@:7!)D&EP2@!I<$O0:7!-H&EP0O!Y<$/0>7!%T'
MEP2C!Y<$[0>7!`X(EP0C")<$6`B7!,@(EP0P"9<$>PF7!*\)EP3@"9<$/@J7
M!+X*EP00"Y<$-PN7!'P+EP2?"Y<$L@N7!,0+EP3A"Y<$00R7!'0,EP2'#)<$
MNPR7!,T,EP3>#)<$`PV7!#`++@LR"RX+-`LN"SH++@L\"RX+/@LN"T`++@M"
M"RX+1`LN"T8++@M("RX+2@LN"TP++@M."RX+4`LN"U(++@M4"RX+5@LN"U@+
M+@M:"RX+7`LN"UX++@M@"RX+8@LN"XP++@N."RX+D`LN"Z8++@NH"RX+O@LN
M"\`++@O""RX+Q`LN"\8++@O("RX+R@LN"\P++@O."RX+T`LN"](++@O4"RX+
MU@LN"P(,+@LF#9<$=0V7!)T-EP3I#9<$&`Z7!$(.EP1I#I<$Q`Z7!`P/EP11
M#Y<$90^7!'P/EP2P#Y<$Y`^7!/D/EP0M$)<$81"7!'40EP2I$)<$W1"7!/$0
MEP0E$9<$61&7!(@1EP2=$9<$[!&7!/@1EP0$#"X+!@PN"P@,+@L*#"X+#`PN
M"PX,+@L0#"X+$@PN"Q0,+@L6#"X++`PN"RX,+@LP#"X+2`PN"TH,+@M,#"X+
M8@PN"V0,+@MF#"X+>@PN"WP,+@N.#"X+D`PN"Y(,+@N4#"X+E@PN"Y@,+@ML
M(=`('P"W!3\`MP5'`+<%CP"W!90`MP69`+<%M@"W!;P`MP7``+<%U0"W!=H`
MMP4$(M`(_`&W!78"MP6*`K<%T`*W!=D"MP4Y!;<%'P:W!6@&MP5)!K<%OP:W
M!:X&MP62!K<%:@FW!44)MP6S"+<%,0BW!:<'MP5M![<%%P>W!>`&MP4&`"X+
M/B+0"#@BT`B@(]`(1PJW!0L,MP7F"[<%Q@NW!5@+MP5."[<%0`NW!3(+MP54
M#+<%60VW!68/MP54#[<%%0^W!0,/MP59#K<%#`ZW!?8-MP7A#;<%RP^W!0D0
MMP4!%;<%[!2W!9H,+@O'&+<%41BW!>47MP6G%[<%0!NW!=(>MP4K'[<%=R"W
M!:,@MP5;(K<%MR*W!9LBMP6`(K<%WB/0".(CT`CF(]`(ZB/0".XCT`A;);<%
M226W!3DEMP4#);<%\"2W!=XDMP5<*+<%,RBW!=PGMP75)[<%EB>W!2XGMP44
M)[<%HB:W!3@FMP45)K<%_"6W!7DJMP4'*K<%W2BW!3HKMP4.*[<%N"NW!8TK
MMP7&)=`(PB70"+XET`BZ)=`(MB70"+(ET`BN)=`(JB70"*8ET`BB)=`(GB70
M")HET`B6)=`(DB70"(XET`B*)=`(AB70"((ET`A^)=`(>B70"'8ET`AR)=`(
M;B70"&HET`AF)=`(8B70"%XET`A:)=`(5B70"%(ET`A.)=`(2B70"$8ET`A"
M)=`(/B70"#HET`@V)=`(,B70"```````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````58OLN`@`FI8"MP575H,^N@`!=7JAN``Y1@9^
M/HOXT>?1Y\1>"";$&2:*!XA&^`K`="B84+A"`!Y0FNHLMP6#Q`8+T'05BSZX
M`-'GT>?$7@@FQ!DF@'\!`'4*N/__7E^+Y5W+D+A%`!Y0BSZX`-'GT>?$7@@F
M_W$")O\QFLHCMP6#Q`@+P'4'_P:X`.O-D(L^N`#1Y]'GQ%X()L09BSZZ`":*
M`9B+\(X&*"8FB38$`(/^.G0<5O]V#O]V#)KJ++<%@\0&B4;\B5;^"]!T`^F@
M`(,^M@``=&:+QHA&^,9&^0K$7@@F_W<")O\WFO0CMP6#Q`10Q%X()O]W`B;_
M-[@"`%"::AZW!8/$"+A(`!Y0FO0CMP6#Q`10N%T`'E"X`@!0FFH>MP6#Q`BX
M`@!0C4;X%E"X`@!0FFH>MP6#Q`C_!KH`BSZZ`(O'BSZX`-'GT>?$7@@FQ!F+
M^":`.0!U"O\&N`#'!KH``0"X/P!>7XOE7<O_1OS$7OPF@#\Z=`/IXP"+'KH`
MBSZX`-'GT>>+P\1>"";$.8O8)H!Y`0!T'HL^N`#_!K@`T>?1Y\1>"":+`2:+
M40(#!KH`0.F2`/\&N`"AN``Y1@9_<(,^M@``=)2+QHA&^,9&^0K$7@@F_W<"
M)O\WFO0CMP6#Q`10Q%X()O]W`B;_-[@"`%"::AZW!8/$"+AR`!Y0FO0CMP6#
MQ`10N)0`'E"X`@!0FFH>MP6#Q`BX`@!0C4;X%E"X`@!0FFH>MP6#Q`CI*_^+
M/K@`_P:X`-'GT>?$7@@FBP$FBU$"C@8J)B:C```FB18"`,<&N@`!`.LYD/\&
MN@"+/KH`B\>+/K@`T>?1Y\1>"";$&8OX)H`Y`'4*QP:Z``$`_P:X`(X&*B8K
MP":C`@`FHP``B\9>7XOE7<M5B^RX!`":E@*W!<1>!B:*1Q:8)0(`=#;$7@8F
MBT<4C@8L)B8#!KX`F;D,`)H>,+<%C@8N)HE&_(E6_B:AP`"9BT[\BU[^`\$3
MT^LXZS:.!C`F)J&^`,1>!B:+3Q0KP4B9N0P`FAXPMP6.!C(FB4;\B5;^)J'`
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
M(#(N,B`@("AC*2!#;W!Y<FEG:'0@2&5W;&5T="U086-K87)D($-O;7!A;GD@
M,3DY,`HJ*BH@4')E;&EM:6YA<GD@5F5R<VEO;B`J*BH`,#$R,S0U-C<X.3!!
M0D-$148P,3(S-#4V-S@Y86)C9&5F````````````````````````````````
M`````````````````$U3(%)U;BU4:6UE($QI8G)A<GD@+2!#;W!Y<FEG:'0@
M*&,I(#$Y.#DL($UI8W)O<V]F="!#;W)P$``O+0`M+0`Z(&EL;&5G86P@;W!T
M:6]N("TM(``Z(&EL;&5G86P@;W!T:6]N("TM(``Z(&]P=&EO;B!R97%U:7)E
M<R!A;B!A<F=U;65N="`M+2``.B!O<'1I;VX@<F5Q=6ER97,@86X@87)G=6UE
M;G0@+2T@``$``0`!`````````````````````````````````````````'8B
MS`@`````@B+,"```````````````````````````````````````````````
M`````````!$I```C`````````````````#,I```E`````````````````%4I
M```E)0```````````````'<I``!#)0```````````````)TI``!#)24`````
M`````````+\I``!#2%(``````````````.@I``!!4E)9``````````````HJ
M``!,3DM!4E)9`````````"PJ```D`````````````````$XJ``!(6%,`````
M`````````'0J``![`````````````````)8J``!$25(``````````````+@J
M``!$3U-934(``````````-HJ``!53DE4`````````````/PJ``!404<`````
M`````````!XK``!'4D]"`````````````$`K``!,24(``````````````&(K
M``!"04L``````````````(@K``!$3T585#```````````*HK``!$3T585#$`
M`````````,PK``!$3T585#(``````````.XK``!$3T585#,``````````!`L
M``!$3T585#0``````````)TM```Z.@```````````````,PM``!#3T1%````
M`````````$@N``!)1````````````````&TN``!,04T``````````````)(N
M``!23TU05%(``````````"LQ```[`````````````````'N5`0!X05-2````
M`````````)N5`0!X4DP``````````````+N5`0!X4DQ"`````````````-N5
M`0!X4E(``````````````/N5`0!X4E)"`````````````!N6`0!X4TP`````
M`````````#N6`0!X4TQ"`````````````%N6`0!X4U(``````````````'N6
M`0!X4U)"`````````````)N6`0!X4CY"`````````````+N6`0!X0CY2````
M`````````-N6`0!X0T].5D525````````!N7`0!X559!3````````````$^7
M`0!X/E5.250``````````'&7`0!X54)!4T4``````````*67`0!X549!0U0`
M`````````/>7`0!X5$E-10```````````!*8`0!X1$%410```````````"V8
M`0!X5$E#2U,``````````$B8`0!X5U-,3T<``````````&.8`0!X04-+04Q,
M`````````'Z8`0!X04-+`````````````)Z8`0!X4T541$%410```````+Z8
M`0!X4T545$E-10```````-Z8`0!X0TQ+041*`````````/Z8`0!X4U1/04Q!
M4DT``````"B9`0!X4D-,04Q!4DT``````$B9`0!X1DE.1$%,05)-`````'*9
M`0!X1$5,04Q!4DT``````)*9`0!X5%-44@```````````+*9`0!X1$1!65,`
M`````````-*9`0!X1$%412L```````````6A`0!X0U)$25(``````````"6A
M`0!X4$%42````````````$"A`0!X2$]-10```````````%NA`0!X55!$25(`
M`````````)2A`0!X5D%24P```````````*^A`0!X5%9!4E,``````````-FA
M`0!X0EE415,``````````+RB`0!X3D573T(```````````.C`0!X2TE,3```
M`````````!ZC`0!X3T9&`````````````#FC`0!X1$]%4E(``````````&VC
M`0!X15)2,````````````(BC`0!X15)23@```````````*.C`0!X15)230``
M`````````+ZC`0!X159!3````````````/ZC`0!X249410```````````,VD
M`0!X2494`````````````"ZE`0!X4UE3159!3````````(2E`0!X1$E34```
M`````````*2E`0!X1E)%15I%`````````,2E`0!X0D5%4````````````.2E
M`0!X/DY530````````````2F`0!X3$%35````````````!^G`0!X5T%)5```
M`````````%BH`0!X0TQ,0T0``````````'.H`0!X2T59`````````````+NH
M`0!X0T].5````````````-BH`0!X/0```````````````)6I`0!X3D5'````
M`````````!^J`0!X04)3`````````````&ZJ`0!X0T].2@```````````+VJ
M`0!X4$D``````````````-^J`0!X34%84@````````````&K`0!X34E.4@``
M`````````".K`0!X0T].4U1!3E1E`````$6K`0!X:0```````````````&>K
M`0!X*P```````````````-VL`0!X3D5'3D5'``````````FM`0!X+0``````
M`````````.ZM`0!X*@````````````````6O`0!X+P```````````````"VP
M`0!X7@```````````````(6Q`0!R<&Y84D]/5````````,JQ`0!X6%)/3U0`
M`````````'BR`0!X24Y6`````````````-NR`0!X05)'`````````````"JS
M`0!X4TE'3@```````````'2S`0!X4U%25````````````":T`0!X4U$`````
M`````````*RT`0!X4TE.``````````````6U`0!X0T]3`````````````%ZU
M`0!X5$%.`````````````+>U`0!X4TE.2`````````````:V`0!X0T]32```
M`````````%6V`0!X5$%.2````````````*2V`0!X05-)3@```````````"^W
M`0!X04-/4P```````````)RW`0!X051!3@```````````.NW`0!X05-)3D@`
M`````````#"X`0!X04-/4T@``````````**X`0!X051!3D@```````````6Y
M`0!X15A0`````````````$^Y`0!X3$X``````````````,:Y`0!X3$]'````
M`````````#VZ`0!X04Q/1P```````````(RZ`0!X3$Y0,0```````````,*Z
M`0!X15A030````````````*[`0!X1D%#5````````````$&[`0!P<F5&04-4
M`````````&V[`0!X25```````````````*.[`0!X1E```````````````-F[
M`0!X1DQ/3U(```````````^\`0!X0T5)3````````````$6\`0!X6%!/3@``
M`````````'&\`0!X34%8`````````````..\`0!X34E.`````````````%6]
M`0!X4DY$`````````````-&]`0!X5%).0P```````````$V^`0!X34]$````
M`````````)R^`0!X34%.5````````````,B^`0!X1#Y2`````````````/2^
M`0!X4CY$`````````````!Z_`0!X/DA-4P```````````#Z_`0!X2$U3/@``
M`````````%Z_`0!X2$U3*P```````````'Z_`0!X2$U3+0```````````)Z_
M`0!X4DY230```````````+Z_`0!X0TY230```````````-Z_`0!X1$54````
M`````````/Z_`0!X1$]4`````````````![``0!X0U)/4U,``````````#[`
M`0!X4E-$`````````````&#``0!X)0```````````````-?``0!X)50`````
M`````````$G!`0!X)4-(`````````````+G!`0!X4D%.1````````````-3!
M`0!X4D1:`````````````/;!`0!X0T]-0@```````````#;"`0!X4$5230``
M`````````'3"`0!X4T8``````````````-7"`0!X0T8``````````````!/#
M`0!X1E,_`````````````&##`0!X1D,_`````````````)G#`0!X1$5'````
M`````````+3#`0!X4D%$`````````````,_#`0!X1U)!1````````````.K#
M`0!X1DE8`````````````![$`0!X4T-)`````````````%+$`0!X14Y'````
M`````````(;$`0!X4U1$`````````````*'$`0!X1E,_0P```````````"#%
M`0!X1D,_0P```````````%G%`0!X0DE.`````````````'3%`0!X1$5#````
M`````````(_%`0!X2$58`````````````*K%`0!X3T-4`````````````,7%
M`0!X4U174P```````````/[%`0!X4D-74P```````````!G&`0!X4D-,1@``
M`````````'_&`0!X4U1/1@```````````(/'`0!X/DQ)4U0``````````)['
M`0!X4CY#`````````````,K'`0!X4D4``````````````!G(`0!X24T`````
M`````````%S(`0!X4U5"`````````````.K(`0!X4D503````````````%K)
M`0!X3$E35#X``````````([)`0!X0SY2`````````````+C)`0!X4TE:10``
M`````````+3*`0!X4$]3``````````````O+`0!X/E-44@```````````";+
M`0!X4U12/@```````````$;+`0!X3E5-`````````````&;+`0!X0TA2````
M`````````(;+`0!X5%E010```````````"C.`0!X5E194$4``````````./.
M`0!X15$^`````````````'O/`0!X3T)*/@````````````G0`0!X/D%24ED`
M`````````)+0`0!X05)263X``````````-_0`0!X4D1-`````````````(;1
M`0!X0T].`````````````-S2`0!X241.`````````````)+3`0!X5%).````
M``````````?4`0!X4%54`````````````-_5`0!X4%5420```````````,;7
M`0!X1T54`````````````,?8`0!X1T5420````````````;=`0!X5CX`````
M`````````&;>`0!X/E8R`````````````,+>`0!X/E8S`````````````$K@
M`0!X24Y$15```````````'[@`0!X4$U)3@```````````)[@`0!X4$U!6```
M`````````+[@`0!X05A%4P```````````.C@`0!X0T5.5%(``````````";A
M`0!X4D53`````````````%#A`0!X*D@``````````````'#A`0!X*E<`````
M`````````)#A`0!X1%)!5P```````````*OA`0!X05543P```````````,;A
M`0!X1%)!6````````````.'A`0!X4T-!3$4```````````'B`0!X4$1)30``
M`````````"OB`0!X1$503D0``````````%_B`0!X15)!4T4``````````'KB
M`0!X4%@^0P```````````)KB`0!X0SY06````````````+KB`0!X1U)!4$@`
M`````````-7B`0!X3$%"14P``````````/#B`0!X4%9)15<``````````!KC
M`0!X4$E83TX``````````$3C`0!X4$E83T9&`````````&[C`0!X4$E8/P``
M`````````)CC`0!X3$E.10```````````,+C`0!X5$Q)3D4``````````.SC
M`0!X0D]8`````````````!;D`0!X0DQ!3DL``````````#;D`0!X4$E#5```
M`````````%;D`0!X1T]2`````````````.3D`0!X1UA/4@```````````'+E
M`0!X3$-$/@```````````(WE`0!X/DQ#1````````````*WE`0!X/D=23T(`
M`````````-+E`0!X05)#``````````````;F`0!X5$585````````````"'F
M`0!X6%).1P```````````$'F`0!X65).1P```````````&'F`0!X1E5.0U1)
M3TX``````('F`0!X0T].24,``````````*'F`0!X4$],05(``````````,'F
M`0!X4$%204U%5%))0P```.'F`0!X5%)55$@```````````'G`0!X4T-!5%1%
M4@```````"'G`0!X2$E35$]'4D%-`````$'G`0!X0D%2`````````````&'G
M`0!X4T%-10```````````(/G`0!X04Y$``````````````GH`0!X3U(`````
M`````````(_H`0!X3D]4`````````````/;H`0!X6$]2`````````````'+I
M`0!X/3T``````````````)WJ`0!X(S\``````````````+[K`0!X/```````
M`````````%WL`0!X/@```````````````/SL`0!X/#T_`````````````)OM
M`0!X/CT_`````````````#CN`0!X3TQ$4%)4`````````%/N`0!X4%(Q````
M`````````&[N`0!X4%)35$,``````````(GN`0!X4%)35````````````*3N
M`0!X0U(``````````````+_N`0!X4%)605(``````````$/O`0!X1$5,05D`
M`````````&/O`0!X4%),0T0``````````'[O`0!R<&Y$15(``````````-+O
M`0!X1$52`````````````#/Q`0!X4D-%40```````````$[Q`0!X4U1%40``
M`````````&[Q`0!X4D]/5````````````-3Q`0!R<&Y)3E1'`````````"/R
M`0!X24Y414=204P``````,GR`0!X4U5-`````````````%3S`0!R<&Y72$52
M10```````//S`0!X5TA%4D4```````````#U`0!X455/5$4``````````%WU
M`0!R<&Y!4%!,60```````,7U`0!X05!03%D``````````$#V`0!X1D-.05!0
M3%D``````);Y`0!#3TU03$581%5-35D``*[Y`0!03TQ!4D1534U9`````,3Y
M`0!X+3Y1`````````````.GY`0!X+3Y14$D``````````%GZ`0!X34%40TA5
M4````````(WZ`0!X34%40TA$3@```````.OZ`0!X1D]2355.250``````%W[
M`0!X4%)%1$E6`````````(?[`0!X1%50`````````````*+[`0!X1%50,@``
M`````````+W[`0!X4U=!4````````````-C[`0!X1%)/4````````````//[
M`0!X1%)/4#(```````````[\`0!X4D]4`````````````"G\`0!X3U9%4@``
M`````````$3\`0!X1$505$@``````````&3\`0!X1%)/4$X``````````'_\
M`0!X1%503@```````````)K\`0!X4$E#2P```````````+7\`0!X4D],3```
M`````````-#\`0!X4D],3$0``````````.O\`0!X0TQ%05(```````````O]
M`0!X4U1/4TE'34$``````"O]`0!X0TQ324=-00```````$;]`0!X4D-,4TE'
M34$``````&']`0!X4TE'34$K`````````(O]`0!X4TE'34$M`````````*;]
M`0!X3E-)1TU!`````````,']`0!X0T]24@```````````-S]`0!X0T]6````
M`````````/?]`0!X4U5-6````````````!+^`0!X4U5-60```````````"W^
M`0!X4U5-6#(``````````$C^`0!X4U5-63(``````````&/^`0!X4U5-6%D`
M`````````'[^`0!X34%84TE'34$``````)G^`0!X345!3@```````````+3^
M`0!X34E.4TE'34$``````,_^`0!X4T1%5@```````````.K^`0!X5$]4````
M``````````7_`0!X5D%2`````````````"#_`0!X3%(``````````````'K_
M`0!X4%)%1%8``````````)K_`0!X4%)%1%D``````````+K_`0!X4%)%1%@`
M`````````-K_`0!X6$-/3````````````/K_`0!X64-/3````````````!H`
M`@!X55100P```````````#H``@!X55103@```````````%H``@!X55101@``
M`````````'H``@!X55105````````````)H``@!X4TE'34%#3TP``````,0`
M`@!X4T-,4TE'34$``````/,``@!X4TE'34%,24Y%``````X!`@!X0DE.4P``
M`````````#,!`@!X0D%24$Q/5````````&<!`@!X2$E35%!,3U0``````(P!
M`@!X4T-!5%)03$]4`````+$!`@!X3$E.1DE4`````````-8!`@!X3$]'1DE4
M`````````/L!`@!X15A01DE4`````````"`"`@!X4%=21DE4`````````%X"
M`@!X0D535$9)5````````,X"`@!X4TE.5@```````````$T#`@!X4TY%1P``
M`````````,P#`@!X4T-/3DH``````````$L$`@!X4U1/*P```````````#@%
M`@!X4U1/+0````````````P&`@!X4U1/+P```````````%,'`@!X4U1/*@``
M`````````/0(`@!X24Y#4@```````````*H)`@!X1$5#4@```````````!4*
M`@!X0T],0U0``````````$D*`@!X15A004X``````````'T*`@!X4E5,15,`
M`````````),*`@!X25-/3````````````+,*`@!X455!1````````````-,*
M`@!X4TA/5P```````````"`+`@!X5$%93%(``````````$`+`@!X4D-,````
M`````````,T,`@!X4U1/`````````````&4-`@!X1$5&24Y%`````````/X.
M`@!X4%521T4``````````*H/`@!X345-`````````````-D/`@!X3U)$15(`
M`````````/P0`@!X0TQ54U(``````````%T1`@!X5$U%3E4``````````)81
M`@!X345.50```````````.$1`@!X4D-,345.50```````/P1`@!X4%9!4E,`
M`````````#H2`@!X4$=$25(``````````%H2`@!X05)#2$E610```````#P3
M`@!X4D535$]210```````'\3`@!X34521T4``````````-$3`@!X1E)%10``
M`````````"T4`@!X3$E"4P```````````$@4`@!X051404-(`````````'P4
M`@!X1$5404-(`````````'4>`@!X6$U)5````````````)4>`@!X4U)%0U8`
M`````````+4>`@!X3U!%3DE/`````````-4>`@!X0TQ/4T5)3P```````/`>
M`@!X4T5.1````````````"0?`@!X2T=%5````````````&(?`@!X4D5#3@``
M`````````)8?`@!X4D5#5@```````````+8?`@!X1DE.25-(`````````-$?
M`@!X4T525D52`````````.P?`@!X0TM330````````````P@`@!X0D%51```
M`````````"P@`@!X4$%22519`````````$P@`@!X5%)!3E-)3P```````&P@
M`@!X2T524DT``````````(<@`@!X0E5&3$5.`````````*(@`@!X4U1)344`
M`````````,(@`@!X4T)22P```````````-T@`@!X4$M4`````````````,HD
M`@!X24Y0550``````````/0D`@!X05-.`````````````!0E`@!X4U1/2T59
M4P```````$@E`@!X1$5,2T594P```````(8E`@!X4D-,2T594P```````+XE
M`@!X+3Y404<``````````#,F`@!X1%1!1P```````````,,N`@!X248`````
M`````````/HN`@!X5$A%3@```````````+4O`@!X14Q310```````````-4O
M`@!X249%3D0``````````.LO`@!X04Q'+3X``````````#,P`@!X5TA)3$4`
M`````````%TP`@!X4D5014%4`````````,,P`@!X1$\``````````````.TP
M`@!X54Y424P```````````,Q`@!X4U1!4E0``````````*`Q`@!X4U1!4E16
M05(``````$PR`@!X3D585````````````(`S`@!X4U1%4````````````-\S
M`@!X249%4E(``````````'(T`@!X2$%,5````````````)PT`@!X4TE,14Y4
M)P```````,$T`@!X4E!.+3X``````````/XU`@!X/CY!0DY$`````````!XV
M`@!X/#P``````````````#DV`@!X/CX``````````````%0V`@!X)P``````
M`````````'DV`@!X14Y$5$E#`````````)0V`@!X5TA)3$5%3D0``````+DV
M`@!X14Y$1$\``````````!\W`@!X15)25$A%3@```````(TW`@!X0T%310``
M`````````*@W`@!X5$A%3D-!4T4``````!,X`@!X1$E2`````````````"0X
M`@!X4%)/35!4`````````+2B`@`E,````````````````,FB`@`E,0``````
M`````````-ZB`@`E,@```````````````/.B`@`E,P````````````````BC
M`@`E-````````````````!VC`@`E-0```````````````#*C`@`E-@``````
M`````````$>C`@`E-P```````````````%RC`@`E.````````````````'&C
M`@`E.0```````````````(:C`@`E+3$``````````````)NC`@`E+3(`````
M`````````+"C`@`E+3,``````````````,6C`@`E+30``````````````-JC
M`@`E+34``````````````.^C`@`E+38```````````````2D`@`E+3<`````
M`````````!FD`@`E+3@``````````````"ZD`@`E+3D`````````````````
M``````````````````````````````````#D`0``S`@`````````````````
M````````````````````````````````````````````````````````````
M````````````````````````JB$[0U]&24Q%7TE.1D\`````````````````
M`````````````````!0`@8&!`0$`````````````````````````````````
M1B+,"$,```````````````````#_____$#L``````!8"`A@-"0P,#`<(%A;_
M$@T2`O\```0XS`@```0XS`@!```````````````"`0`````````````"`@``
M``````````"$`P`````````````"!```````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M``````````````````````````````$```(`````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M`````````%HCS`@````````````````H;G5L;"D`*&YU;&PI`"LM(",`````
M```````````````````````@````````D`*W!9`"MP60`K<%D`*W!9`"MP4`
M`````0$Z(``*``!%<G)O<B`P``!.;R!S=6-H(&9I;&4@;W(@9&ER96-T;W)Y
M``````!!<F<@;&ES="!T;V\@;&]N9P!%>&5C(&9O<FUA="!E<G)O<@!"860@
M9FEL92!N=6UB97(```!.;W0@96YO=6=H(&-O<F4`4&5R;6ES<VEO;B!D96YI
M960`````1FEL92!E>&ES=',`0W)O<W,M9&5V:6-E(&QI;FL`````26YV86QI
M9"!A<F=U;65N=```5&]O(&UA;GD@;W!E;B!F:6QE<P````!.;R!S<&%C92!L
M969T(&]N(&1E=FEC90``````36%T:"!A<F=U;65N=`!297-U;'0@=&]O(&QA
M<F=E``!297-O=7)C92!D96%D;&]C:R!W;W5L9"!O8V-U<@!5;FMN;W=N(&5R
M<F]R`#PDS`A$),P(123,"%\DS`A@),P(823,"&(DS`AC),P(=23,"(<DS`B7
M),P(F"3,")DDS`BI),P(NR3,"+PDS`B]),P(OB3,",HDS`C<),P(W23,"-XD
MS`C?),P(\"3,"/$DS`@%)<P(!B7,"`<ES`@()<P(("7,""$ES`@B)<P((R7,
M""0ES`@R)<P(0R7,"$0ES`AB)<P()0```+X`O@"^````````````````````
M`````/P%MP7+",L(S`C,",P(S`C,"`I,:6)R87)Y($1E8V]M<&EL871I;VXN
M("!(96%D97(Z(`#,",P(S`C,""5C``#,""5C``#,",P("@#,",P(S`C,",P(
MS`@@8V]N9FEG````(&UE<W-A9V5S````(&AA<V@``````$Q)0B`E,#-8("(E
M<R(E<R5S)7,*``#,",P(S`C,",P(S`C,",P(S`C,"$QO<W,@;V8@;V)J96-T
M('-Y;F-H<F]N:7-M(&)E='=E96X@<&%S<V5S.B`E<R5S`$YA;64@;75S="!N
M;W0@97AC965D(#$V(&-H87)A8W1E<G,Z("5S)7,``,P("D5N=')Y.B`E,#5L
M6"!83$E"("4P,U@@)3`S;%@@)2TQ,G,@)6,@)6,@)7,E<PH`S`C,",P(S`@*
M`,P(+0```"`E<R5L>"XE,"IL>"4P.&QX925L>`#,""`E<P#,""`E,#5L6```
MS`@@)6,`S`@@)3`S6`#,""`E,#-8`,P((@#,""5C``#,""(`S`@@`,P()5@`
M`,P(?0`[`"`E<P#,",P(S`C,""!%3D0``,P()P#,""5C``#,""<`S`@H)7,I
M/"TM`,P(S`C,"",@)3`U;%@@1T545$A%34531P``S`C,"$ME>7=O<F0@8V%N
M;F]T(')E<V]L=F4@=&\@82!D:7)E8W1O<GDZ("5S)7,`6$Q)0B`E,#-L6"`E
M,#-L6```S`@G`,P()6,``,P()P#,""<`S`@E8P``S`@G`,P(S`C,"`I$96-O
M;7!I;&4@;V8@)7,Z($AE861E<CH@``#,",P(S`C,",P(S`@*("5S``#,",P(
M"@#,"```S`@@)7,@``#,",P()7,*`,P(0D%+(&]B:F5C="!D;V5S(&YO="!C
M;VYT86EN(&1I<F5C=&]R>0H``,P("@#,"$YE960@96ET:&5R($)!2R!O9B!A
M(&1I<F5C=&]R>2!O<B!A(&1I<F5C=&]R>0H``$1I<F5C=&]R>2!I<R!E;7!T
M>2X*``#,",P(S`C,"`I%;G1R>3H@)7,E<PHE<P#,",P()%)/34E$``#,""1#
M3TY&24<`)$U%4U-!1T4``"1-15-304=%```D5DE324),10``)%9)4TE"3$4`
M`"1(241$14X`)$A)1$1%3@`D5D%24P`D5D%24P`D5$E43$4``$]B:F5C="!I
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
9('!O:6YT97(@87-S:6=N;65N=`T*`/___V5D
`
end

From comp.sys.handhelds Mon Jun 11 10:50:23 1990
Path: fauern!unido!mcsun!uunet!aplcen!uakari.primate.wisc.edu!zaphod.mps.ohio-state.edu!usc!jarthur!nntp-server.caltech.edu!piglet!madler
From: madler@piglet.caltech.edu (Mark Adler)
Newsgroups: comp.sys.handhelds
Subject: Re: HP 48SX Library Builder
Summary: USRLIB.MAN manual (not uuencoded) for USRLIB1.EXE---long message ...
Message-ID: <1990Jun8.160428.12752@laguna.ccsf.caltech.edu>
Date: 8 Jun 90 16:04:28 GMT
References: <25590009@hpcvra.CV.HP.COM> <55090@microsoft.UUCP>
Sender: news@laguna.ccsf.caltech.edu
Organization: California Institute of Technology, Pasadena
Lines: 658
Status: OR









                    Instructions for MS-DOS program "USRLIB"

       *****************************************************************
                                     NOTICE

       Hewlett-Packard is making the current preliminary version 2.2 of
       USRLIB.EXE available to customers free of charge to help them in
       HP 48SX application development, under the following conditions:

       * The program USRLIB.EXE and the documentation file USRLIB.MAN are
       provided "as is," and are subject to change without notice.
       Hewlett-Packard Company make no warranty of any kind with regard
       to the software or documentation, including, but not limited to,
       the implied warranties of merchantability and fitness for a
       particular purpose.  Hewlett-Packard Company shall not be liable
       for any error or for incidental or consequential damages in
       connection with the furnishing, performance, or use of this
       software and documentation.

       * The program and documentation are copyrighted by Hewlett-
       Packard.  Customers may freely reproduce and distribute this
       material.  Sale of this material is prohibited without prior
       written permission of Hewlett-Packard Company.

       * The HP Customer Support department does not support the current
       version.  Questions, comments, defect reports, etc. should be
       directed to the Library Development conference on the HP
       Calculator Bulletin Board System.  All responses from Hewlett-
       Packard will normally be provided through that conference.

       * Software converted into libraries by USRLIB.EXE should be tested
       and qualified in its library form.  Discrepancies between the
       execution of the libraries and the execution of the original
       source directory contents should be reported via the Bulletin
       Board.

       Revised versions of the software and documentation will be posted
       on the Bulletin Board as they become available.  In particular,
       future versions will include less cryptic error messages, and
       better documention of the output listing information provided by
       the program.

       Version 2.2 of the program USRLIB.EXE is a preliminary version of
       this software.  Software compiled into libraries using this
       program should be thoroughly tested in its library form prior to
       any reproduction or distribution to end users.

       *****************************************************************






                                   -1-











       1.  INTRODUCTION


       USRLIB.EXE is an MS-DOS executable file that creates an HP 48
       library object from an HP 48 directory.  A library is similar to a
       directory in that both are collections of named objects.  However,
       a directory normally resides in main RAM memory and is intended
       for continuous modification and execution, whereas a library
       contains objects intended for execution only, and can be used from
       ROM as readily as from RAM.  A directory's objects are organized
       in a linked list requiring a sequential search for access; a
       library contains an address table that provides rapid execution
       access to its individual objects.


       1.1  Glossary of Terms

       Directory           HP48 directory object containing zero or more
                           variables.

       Variable            A named object contained within a directory,
                           accessed by means of a global name.

       Library             HP 48 library object containing zero or more
                           library commands.  Libraries include a text
                           title, a Library ID number, and optional
                           message tables and configuration code that is
                           executed at system halts.

       Library command     A named object within a library, which is the
                           library analog of a directory's variable.

       Global name         HP 48 global name object, execution of which
                           executes the object in the corresponding
                           (global) variable.

       XLIB name           HP 48 XLIB name object, execution of which
                           executes the corresponding library command.
                           An XLIB name plays the role for libraries that
                           a global name plays for directories.

       Library ID          A number in the range 0-7FFh that uniquely
                           identifies a library, and is used as an
                           argument for HP 48 commands that deal with
                           libraries as objects.  The following ranges
                           are defined for the ID numbers:








                                   -2-











                                  ID Range                    Purpose
                              Hex        Decimal

                             0 - 100       0 - 256
                           101 - 200     257 - 512   HP ROM-Based Applications
                           201 - 300     513 - 768   HP RAM-Based Applications
                                                     Non-HP Applications
                                                     (numbers permanently
                                                     assigned by HP)
                           301 - 600    769 - 1536
                           601 - 6FF   1537 - 1792
                           700 - 7FF   1792 - 2047   HP 48SX Command Line Use



       1.2  The Source Directory

       USRLIB uses an HP 48 directory object as the source file to define
       the output library.  The source directory may contain any number
       of variables, each of which is converted to a library command in
       the output library (unless specified otherwise; see $VARS,
       $VISIBLE and $HIDDEN, below).  The objects in the variables are
       translated as necessary so that any global names in the objects
       that correspond to variables in the source directory are converted
       to XLIB names.

       The source directory may contain subdirectories, but in that case
       the resulting library will not reflect the structure of the
       directory since a library structure is "flat."  If separate
       subdirectories contain variables with the same name, the uses of
       those names within the library will be correct, but the duplicated
       names will also be duplicated in the LIBRARY menu.  The names of
       the subdirectories themselves are not translated to library
       commands, and any use of those names in any of the other variables
       will result in an error during execution of USRLIB.

       The directory may also include the following special variables:


       $ROMID      Contains a real or binary number object representing
                   the Library ID that is to be given to the library.
                   This can be overridden by specifying -r<romid> on the
                   command line.  The ID should be in the range 769 -
                   1792 (301h - 6FFh).

                   The -r option must be specified from the command line
                   if no $ROMID is used.


       $TITLE      Contains a string to be used as the name of the
                   library.  This can be overridden by specifying -t<title>
                   on the command line.  The first (up to) 5 characters



                                   -3-











                   of the title are used for the LIBRARY menu label; the
                   first 22 characters are displayed by REVIEW.


       $CONFIG     Contains an object to be executed at configuration
                   time.  If no $CONFIG variable is present, no
                   configuration entry will be generated.  In the current
                   version of USRLIB, $CONFIG is also translated to a
                   library command; to prevent this, it $CONFIG should be
                   declared as hidden (see below).

                   Note: 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.


       $MESSAGE    Contains a list of names of variables that contain
                   strings to be combined into a message table. The
                   message numbers correspond to the list positions.

                   If no $MESSAGE is present, no message table will be
                   generated.


       $VISIBLE    Contains a list of names of variables to be converted
                   to user-accessible library commands.

                   By default, all variables will be translated to
                   library commands.  When the $VISIBLE list is present,
                   only the names in this list are used as XLIB name
                   table entries in the library. An empty list is
                   allowed, meaning that no XLIB name entries are
                   created.


       $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 library user.

                   When the $HIDDEN list is present, those names listed
                   are not entered in the library XLIB name table.  If
                   both $VISIBLE and $HIDDEN are present, only the
                   $HIDDEN list will be used.


       $VARS       Contains a list of variables that should remain RAM-
                   based, i.e., the stored objects are not included in
                   the library, and no XLIB name entries are made for
                   their names.  All other variables in the source



                                   -4-











                   directory names are included as library commands.

       Multiple instances are permitted of the declaration variables
       $VARS, $HIDDEN, and $VISIBLE variables, in various subdirectories
       of the source directory.  A particular variable is declared as a
       RAM variable, hidden, etc., if its name is entered in any of the
       relevant declaration variables anywhere in the current path
       defined by the variable's location. That is, a variable XXX found
       in any subdirectory will be hidden if XXX is in a list stored in
       $HIDDEN in the top level of the source directory; but YYY in the
       top level will not be hidden even if YYY is present in a $HIDDEN
       list in a subdirectory.

       Not all program objects that execute correctly from global
       variables are directly convertible into libraries.  In general, no
       checks can be made for such errors, and USRLIB does not attempt to
       do so.  Here are some known pitfalls:

          o Since a library cannot be modified, no library command may be
            the target of a STO or PUT operation.

          o 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' EVAL 5 GETI

            or better yet

                                      A 5 GETI

            XLIB names are not valid as formal variables in algebraics,
            or as the independent variable for plotting or solving.
            Names intended to be used as such should be declared as
            global using $VARS or the -v option.

          o ->STR applied to a global name that is converted to a
            ``hidden'' library command (see $HIDDEN) returns a null
            string.

          o Embedded directories (entered as DIR...END) within lists and
            programs are not translated except for their first object.







                                   -5-











       1.3  Library Creation

       The process of library creation and activation can be summarized
       as follows.

         1.  Develop an application consisting of any number of programs
             and other objects, and collect these in one single-level
             directory in the HP 48.

         2.  Using Kermit binary transfer, send the directory to a PC.

         3.  Execute USRLIB, using the directory as the source file.  In
             this step, you also assign a library ID and a library title
             to the output library.

         4.  Transfer the USRLIB output library object back to the HP 48,
             to a variable in any convenient directory.

         5.  Recall the library object from the variable to which it was
             transferred, and then store it in a RAM port (:n:x STO,
             where n is the port number, and x is any number).  After
             storing the library, you can purge the original copy in the
             variable to save memory.

         6.  Turn the HP 48 off, then on.  This adds the new library to
             the system library table, and gives the library a chance to
             execute its own configuration program, if any.  (The HP 48
             will execute a system halt automatically at this stage, so
             you should save any stack objects or PICT first if you wish
             to recover them.)  The LIBRARY menu will now contain a menu
             entry labeled with the library's ID number in the PORTn
             submenu.

         7.  Activate the directory in which you wish the library's
             commands to be accessible, then execute nnn ATTACH, where
             nnn is the library ID.  Any number of libraries can be
             attached to the HOME directory; subdirectories may have one
             library attached to each.  The main LIBRARY menu will now
             contain a menu key labeled by the library's title.

       To remove a library, activate its associated directory and execute
       nnn DETACH.  Then execute :n:ID PURGE to remove the library from
       port n.  (You will notice a brief jump in the display when you
       execute the PURGE.  This is normal and harmless.)










                                   -6-











       2.  Instructions

       (In the following, <bold> text represents user-supplied text.  Text
       appearing in brackets [ ] denotes optional entries. In actual
       entries, the [ ] should not be used.)

       Syntax:
               USRLIB [-options] <dirfile> [ <libfile> [ <sumfile> ] ]


       <dirfile>   is the name of the source file, which must contain a
                 binary image of an HP48 directory or a backup object
                 containing a directory.

       <Libfile>   is a file to contain the output library object.

       <sumfile>   This is a textual summary of the names that were
                 translated.  The following information is given for each
                 object:  user name, type, offset into the <libfile> file,
                 XLIB numbers, whether it can be used in an algebraic,
                 and whether it is visible.

                 Similarly, a list of message numbers and messages and a
                 summary of the space requirements is given.

       <Sumfile> and the optional <listfile> (see OPTIONS below) may be
       redirected to stdout by using '-' for the output file name.


       2.1  Options

       The following options may be included in the USRLIB command line:


       -d<listfile>  <listfile> will contain a text listing of the contents
                   of each object in the input directory.


       -h<header>    Use <header> for the library object header (for file
                   transfer).


       -l<listfile>  <listfile> will contain a text listing of the contents
                   of each object in the output library. Occurrances of
                   "ID'name'<--" indicate translation of an name (ID)
                   into an XLIB or a message table reference.


       -r<romid>     Set decimal Library ID (see $ROMID above).





                                   -7-











       -t<title>     Use <title> for the library title (see $TITLE above).


       -v<name>      Declare <name> as a RAM variable name (see $VARS above).


       2.2  Restrictions

         1.  The total library output file cannot be larger than 128K
             bytes.

         2.  Message strings must be less than 64K bytes each.


       2.3  Error Messages

       In the following, words shown in parentheses within the quoted
       error messages represent values that indicate source-specific
       quantities. (path) represents the path within the source directory
       to the variable causing the error, in the form name1/name2/... ,
       where the names are the subdirectoy names (on the HP 48SX, the
       path would be a list { name1 name2 ... }).


       2.3.1  General Errors

       "Cannot allocate memory"  --memory is constantly being allocated
       for various compiler needs.

       "Unexpected EOF on input"  --EOF was hit when more nibbles were
       expected.

       "Can't malloc for decomp"  --can't get memory to create decompile
       information.


       2.3.2  Initialization/First Pass Errors

       "USRLIB: Cannot open"  --The source file can not be opened.

       "USRLIB: - not legal for input"  -- "-" (stdin) can't be used for
       input.

       "Cannot alloc 128K bytes for image"  --Insufficient memory for the
       library image.

       "ROMID must be in range 769 - 1792"

       "Must have either -r romid or $ROMID"  --no library ID was
       specified.




                                   -8-











       "Need either BAK of a directory or a directory"

       "BAK object does not contain directory"

       "Directory is empty"

       "Object is not a string: (path)/$TITLE"

       The next three messages may occur when ROMID is specified in the
       variable $ROMID.

       "Illegal Real value for (path)/$ROMID: (value)"

       "Illegal Binary value for (path)/$ROMID: (value)"

       "Object not Real or Binary: (path)/$ROMID"

       The next two messages may occur when a $CONFIG variable (or two)
       are specified.

       "Object not program: (path)/$CONFIG"

       "$CONFIG redefined: (path)/$CONFIG"

       The next two messages may occur any time a string (variable name
       or message) isread.

       "Variable name or message too long (>65535)"

       "Out of memory: trying to malloc for string"

       The next three messages may occur when a name list is being read.
       The $MESSAGE, $VISIBLE, $HIDDEN, and $VARS variables are all name
       lists.

       "Object is not a list: (path)/name"

       "Non-ID found in list:  (path)/name"

       "Out of memory: (path)/name"

       The next three messages occur during creation of and addition to
       internal name tables, and are variations of insufficient memory
       errors.

       "Cannot malloc id table"

       "Cannot malloc id entry: (path)/(name)"

       "Cannot malloc id entry: (path)/(name)"




                                   -9-











       2.3.3  Interim/Second Pass Errors

       "Message object not found: (name)"

       "Loss of object synchronism between passes: (path)/(name)"  --
       (path)/(name) is replaced with the object where out-of-sync was
       discovered.

       "Name must not exceed 16 characters: (path)/(name)"  --library
       object names are limited to 16 characters.

       "Keyword cannot resolve to a directory: (path)/(name)"  --
       Subdirectory names cannot be included in other directory objects'
       definitions.

       The next two messages may occur as message objects (indicated in
       the $MESSAGE list) are being converted into a message table.

       "Message object is not a string: (path)/(name)"

       "Multiple definitions for message (path)/(name)"


       2.3.4  Clean-up/Write File Phase Errors

       "Library image length is 0.
        LIB FILE NOT WRITTEN!"

       "Max image size is 256K nibbles ... image is (value) nibbles.
        LIB FILE NOT WRITTEN!"

       "Unsucessful write to library file"  --unknown error writing to library file.






















                                   -10-

From comp.sys.handhelds Mon Jun 18 13:52:13 1990
Path: fauern!sun1.ruf.uni-freiburg.de!ira.uka.de!snorkelwacker!usc!cs.utexas.edu!uunet!zephyr.ens.tek.com!tekfdi!videovax!bill
From: bill@videovax.tv.tek.com (William K. McFadden)
Newsgroups: comp.sys.handhelds
Subject: Re: Assorted HP48 questions
Message-ID: <5850@videovax.tv.tek.com>
Date: 13 Jun 90 19:24:58 GMT
References: <8815@hacgate.UUCP>
Reply-To: bill@videovax.tv.tek.com (William K. McFadden)
Organization: Tektronix TV Measurement Systems, Beaverton OR
Lines: 86
Status: O

In article <8815@hacgate.UUCP> ferris@tcville.HAC.COM () writes:
>I have the distinct impression, and I have a sinking feeling that it is
>because it is correct, that for an object to be globally accessable,
>it must reside in the HOME directory.  If this is indeed true, it is
>unfortunate there isn't a path variable the user can create.

Some time ago, jc@atcmp.nl (Jan Christiaan van Winkel) posted a method of
getting around this.  What you do is create a { HOME LIB } directory and use a
program called 'SVC' (service call) to call it.  The SVC program resides in
your home directory.  It is true that the LIB directory gets full of lots of
programs, but I think it is better than having them cluttering the HOME
directory.  Anyway, here is the program (with some improvements I've made):

SVC  (Bytes #1C7Fh 49)

<< PATH			;get current path
   SWAP			;get program name in level 1
   { HOME LIB } EVAL	;go to LIB directory (HOME LIB by itself also works,
			;but bombs in debug mode, i.e., single stepping)
   RCL			;recall library routine to stack
   SWAP EVAL		;go back to original directory
   EVAL			;execute library routine
>>

To use this routine from a program, you put the library routine's arguments on
the stack, followed by the name of the routine in single quotes.  Then call
SVC.  For example:

6.133990
'DOW'
SVC

Which returns "Wednesday" to the stack.  Notice also that SVC returns to the
original directory before executing the library routine.  Hence it will use
that directory's environment.

>The situation
>in which this creates the most trouble is having a program in a lower
>directory assigned to a key.  When in another directory and in USER mode,
>pressing that key places on the stack the name of the program, which EVALs
>to only itself.

Instead of assigning 'DOW' to a key, you would assign << 'DOW' SVC >> to the
key, making it globally accessible.  However, this forces you to put DOW in the
LIB directory.  If this is not desirable you could instead assign to the key
<< PATH HOME DIR1 DIR2 .. DIRn DOW EVAL >>, where HOME .. DIRn is the path to
the program (DOW in this example).  If you wanted the program to reside in the
other directory but execute in the current one, you could use << PATH HOME
DIR1 DIR2 .. DIRn 'DOW' RCL SWAP EVAL EVAL >>.  In effect, you would assign a
custom version of the SVC program to the key.  These ideas could also be
extended to control alarms that execute a program in another directory but
leave the calculator in the original directory when finished.

>Is there a _system provided_ way to make a key assignment
>inactive when not in the directory that the object assigned to that key
>resides?  What this boils down to is having different key assignments for
>each directory. Is this possible?

Other than using menu keys, I don't know of a way to unassign a key when you
leave the directory.  I suppose you could use TYPE or IFERR to detect the
existance of a program and evaluate it if it's there or execute the default
function if it isn't.  For example, << IFERR 'DOW' RCL EVAL THEN DROP SIN
END >> would execute DOW if it exists, otherwise would execute SIN (or whatever
the default function is for that key).

>I have noticed when using the BYTES command, that 100% of the time, the
>number of bytes returned is _lower_ than the amount specified either in
>the manual or by other people when keying their programs.  The checksums
>match, but the byte count is lower. I have revision D of the ROMs, and
>I've been wondering if HP came up with a different way to store objects
>that is less space consuming. Now I certainly won't pass up more
>efficient data compactions!

This, too, puzzled me at first.  I discovered you can get two different answers
depending on what you supply to the BYTES command.  For example, 'SVC' BYTES
returns #1C7Fh 49, but 'SVC' RCL BYTES returns #1C7Fh 41.5.  The difference is
the first call to BYTES included the program name in its count, and the second
didn't.  I have seen programs posted to the net both ways, but I believe the
HP48 I/O firmware uses the first version.

Happy programming!
-- 
Bill McFadden    Tektronix, Inc.  P.O. Box 500  MS 58-639  Beaverton, OR  97077
bill@videovax.tv.tek.com,     {hplabs,uw-beaver,decvax}!tektronix!videovax!bill
Phone: (503) 627-6920       "The biggest difference between developing a missle
component and a toy is the 'cost constraint.'" -- John Anderson, Engineer, TI

From comp.sys.handhelds Mon Jun 18 13:55:03 1990
Path: fauern!unido!mcsun!uunet!tut.cis.ohio-state.edu!ucsd!usc!hacgate!tcville.HAC.COM!ferris
From: ferris@tcville.HAC.COM
Newsgroups: comp.sys.handhelds
Subject: HP48 Directory Traversal
Message-ID: <8949@hacgate.UUCP>
Date: 18 Jun 90 05:46:38 GMT
Sender: news@hacgate.UUCP
Reply-To: ferris@tcville.HAC.COM ()
Organization: Hughes Aircraft Co., El Segundo, CA
Lines: 58
Status: O


I have vastly enjoyed programming with my HP48, and have been
aided immensely by the posts from this newsgroup. To start
what I hope will be the first of many contributing posts I
hope to make, here is a brief program to traverse the directories
in your HP48.

As written, it does nothing. However, I have indicated that point
to modify to slip in the action you wish to occur at each 
directory (such as purge all system created variables, add variables
you want in each directory, accumulate a system wide listing, etc).

Also, as written, it scans all directories from the current one on
down. Comments point out where to add a HOME command to make the
program always start at the HOME directory and scan down from there.

This program calls itself recursively, so must reside in the HOME
directory, with the same that it calls itself in the code, which
is TRAVERSE. If you change the name, also change the name in the
code.

%%HP: T(3)A(D)F(.);
@ Store as 'TRAVERSE' in the HOME directory
@ BYTES returns 1: 6E96h  2: 157.5
@
@ TRAVERSE is a directory traversal program
@ It must be stored in the HOME directory as it calls itself
@ recursively while visiting all RAM directories.
@
@ Mark Ferris		ferris@tcville.HAC.COM
@ version 1.0	6/14/90
\<<
 DEPTH
  IF 0 \=/			@ if stack is not empty, assume the current
  THEN DUP RCL TYPE		@ directory list is on the stack
    IF 15 ==
@ at this point, have located a directory. It's name
@ is on level 1 of the stack.
@ Replace the HALT instruction with whatever you want to do
@ in the directory
    THEN HALT EVAL VARS OBJ\-> 1 SWAP
      FOR x TRAVERSE
      NEXT
    ELSE DROP
    END
@ Add the command HOME prior to VARS if
@ you want TRAVERSE to always traverse your entire
@ directory, otherwise it will start at the
@ current directory
  ELSE VARS OBJ\-> 1 SWAP	@ else (if stack is empty)
    FOR x TRAVERSE		@ program just started execution
    NEXT HOME			@ begin traversal at the current
  END				@ directory
\>>

Mark Ferris                         smart:    ferris@tcville.edsg.hac.com
Image and Signal Processing Lab     dumb:     ferris%tcville@hac2arpa.hac.com
Hughes Aircraft Co., EDSG           uucp:     hacgate!tcville!ferris

From comp.sys.handhelds Tue Jun 19 11:10:01 1990
Path: fauern!unido!mcsun!sunic!liuida!isy!lysator.liu.se!howard
From: howard@lysator.liu.se (M V Howard)
Newsgroups: comp.sys.handhelds
Subject: HP48SX database system
Keywords: The Ultimate in personal databases :-) ??
Message-ID: <81@lysator.liu.se>
Date: 18 Jun 90 18:14:54 GMT
Sender: news@isy.liu.se (Lord of the News)
Distribution: comp
Organization: Lysator Computer Club, Linkoping University, Sweden
Lines: 288
Status: O


%%HP: T(3)A(R)F(.);
DIR
@
@ DATABASE -- A collection of programs which form a personal database for the
@             HP-48SX. Originally written by W.A.C Mier-Jedrzejowicz for
@             the HP-28 (in the book Customize Your HP-28, see below),
@             ported to the HP-48SX and extended by M.V. Howard.
@
@ Instructions:
@
@ There are two ways of using the programs in this package:
@
@   1) Use it as a straight forward HP-48SX program package, moving to
@      one of your DATABASE directories and then pressing CST. To quit,
@      press VAR and move to whatever directory you want to. Uncool.
@
@   2) Take full advantage of the powerful commands available in the
@      HP-48SX and create an environment (seperate from all others) in
@      which to manipulate your databases. Gives you frostbite :-)
@
@ To use the first option, load this file into your HP-48SX. That's it.
@
@ For the second option, a little more preparation is needed. After having
@ loaded this file (calling it, say, DBASE) create a variable DPATH in your
@ HOME directory containing the PATH to the directory NOTES (created when
@ loading this file). Then move the program DBSTART (in this file) to your
@ HOME directory. Next, enter the following on your HP-48SX:
@
@ 2: << DBSTART >>
@ 1: 25.3
@ ASN (blue-shift-CST)
@
@ This assignes the DATABASE auto start program to blue-shift-up-arrow
@ (the key labelled LIBRARY. I use this key because it doesn't have any
@ standard blue-shifted function. If you want another key instead, simply
@ enter a different keycode).
@ When ever you wish to use your database, simply press blue-shift-up-arrow
@ and the program will start automatically, moving you to the DATABASE
@ directory NOTES, but also remembering where you started from, so that when
@ you select QUIT to exit DATABASE, you will automatically be moved back
@ to the directory you started from.
@
@ I have had great use of these programs hand hope that you will find them
@ worthwhile too. The only problem is that I use them so much, I'm going
@ to have to buy a second RAM card soon... ;-)
@
@ If you have any complaints, suggestions, flames or love letters, please
@ email them to me. I will reply to any and all email, provided they
@ offer positive critisism, thoughts, ideas and/or comments. Abuse will
@ be forwarded to /dev/null...
@ The rest you can send to  howard "at" lage.lysator.liu.se
@
@ A big thanks to W.A.C. Mier-Jedrzejowicz for the original programs
@ which appeared in the book Customize Your HP-28. Without that, this
@ would never have been written. If your are interested in getting the
@ book (and I highly recommend it, to both 28/48SX owners) you can get
@ it from EduCALC (CA, USA) or from Mr Mier-Jedrzejowicz (to contact him
@ see the documentation).

  DBSTART
  \<<
    "Entering DATABASE
-- Use QUIT to exit"
    1 DISP 1 FREEZE
    PATH HOME 'DBP' STO
    DPATH EVAL 1 MENU
  \>>

  ADD
  \<<
    DUP DROP RCLF SWAP -56 CF
    IF DUP TYPE 5 ==
    THEN
      \->STR "{" SWAP + STR\->
    END
    IFERR 'NOTEL' RCL
    THEN
      DROP { }
    END
    + 'NOTEL' STO STOF
    1 'POSL' STO
    CURR
  \>>

  FIND
  \<<
    'OBJL' STO 0
    'POSL' STO cont
  \>>

  cont
  \<<
    NOTEL POSL 1
    + OVER SIZE SUB DUP
    OBJL POS
    IF DUP
    THEN 
      'POSL'
      STO+ DROP
      OBJL POSL
    ELSE
      DROP
      SRCH
    END
  \>>

  SRCH
  \<<
    IF DUP SIZE OBJL TYPE 2 == AND
    THEN
      1 1
      DO DROP
        GETI
        IFERR OBJL POS
        THEN 0
        END
      UNTIL OVER 1 == OR DUP END
      IF THEN
        1 -
        IF DUP NOT
        THEN
          DROP
          DUP SIZE
        END
        SWAP OVER GET SWAP
      ELSE
        DROP2 OBJL 0
      END
    ELSE
      DROP
      OBJL 0
    END
    'POSL'
    IF OVER
    THEN
      STO+
    ELSE
      STO
    END
    POSL DROP
    DISPL
  \>>

  CURR
  \<< 
    NOTEL POSL
    GET DISPL
  \>>

  repl
  \<<
    NOTEL POSL
    ROT PUT DUP 'NOTEL'
    STO POSL GET DISPL
  \>>

  EDIT
  \<<
    NOTEL POSL
    GET
  \>>

  ADDL
  \<<
    NOTEL SWAP +
    'NOTEL' STO
    NOTEL SIZE 'POSL' STO
    CURR
  \>>

  DEL
  \<<
    NOTEL 1 POSL
    1 - SUB NOTEL POSL
    1 + OVER SIZE SUB +
    'NOTEL' STO
  \>>

  prev
  \<<
    POSL 1 - DUP
    IF 1 <
    THEN
      DROP NOTEL SIZE
    END DUP
    'POSL' STO NOTEL
    SWAP GET DISPL
  \>>

  next
  \<<
    NOTEL DUP
    SIZE POSL 1 + DUP 3
    PICK
    IF >
    THEN DROP 1 END
    DUP
    'POSL' STO SWAP
    DROP GET DISPL
  \>>

  DISPL
  \<<
    CLLCD 1 DISP
    3 FREEZE
  \>>

  CRDB
  \<<
    CLEAR
    "Enter name: " ""
    INPUT DUP
    \-> N
    \<<
      UPDIR
      N "\<< UPDIR "
      N OBJ\-> "\>>" + +
      OBJ\->
      2 \->LIST
      1 \->LIST
      BASME SWAP + 'BASME' STO
    \>>
    OBJ\-> DUP
    CRDIR EVAL
    { "DUMMY" } 1 ""
    'OBJL' STO
    'POSL' STO
    'NOTEL' STO
    CURR
  \>>

  CST
  { prev next CURR { "FIND" \<< FINME TMENU CURR \>> }
                   { "ADD"  \<< ADDME TMENU CURR \>> }
		   { "EDIT" \<< EDIME TMENU CURR \>> }

                   { "BASES" \<< BASME TMENU \>> }
                   { "" \<< \>> }
                   { "" \<< \>> }
                   { "" \<< \>> }
                   { "" \<< \>> }
                   { "QUIT"  \<< "QUIT selected. Popping
back to old dir"
                                  1 DISP 1 FREEZE
                                  DBP EVAL
                              \>> }
  }

  FINME
  { FIND cont { "EDIT" \<< EDIME TMENU CURR \>> }
              { "" \<< \>> }
              { "" \<< \>> }
              { "TOP"  \<< 1 MENU CURR \>> }
  }

  ADDME
  { ADD ADDL CRDB { "EDIT" \<< EDIME TMENU CURR \>> }
                  { "FIND" \<< FINME TMENU CURR \>> }
                  { "TOP"  \<< 1 MENU CURR \>> }
  }

  EDIME
  { EDIT repl DEL { "ADD"  \<< ADDME TMENU CURR \>> }
                  { "FIND" \<< FINME TMENU CURR \>> }
                  { "TOP"  \<< 1 MENU CURR \>> }
  }

  BASME
  {
    { "EMAIL" \<< UPDIR EMAIL 1 MENU \>> }
    { "NOTES" \<< UPDIR EMAIL 1 MENU \>> }
    { "PHONE" \<< UPDIR PHONE 1 MENU \>> }
    { "FTP"   \<< UPDIR FTP   1 MENU \>> }
  }

  NOTES
    DIR
      NOTEL { "DUMMY" }
      POSL 1
      OBJL ""
    END
END
--
Programming isn't a science,         | EMAIL: howard@lage.lysator.liu.se
it's an art.                         |        howard@lysator.liu.se
Why is it called common sense,       |        Martin_Howard.d89.lith@xns.liu.se
when so few possess it ?             |

From comp.sys.handhelds Tue Jun 19 11:10:14 1990
Path: fauern!unido!mcsun!sunic!liuida!isy!lysator.liu.se!howard
From: howard@lysator.liu.se (M V Howard)
Newsgroups: comp.sys.handhelds
Subject: HP48SX database system part II
Keywords: The Manual
Message-ID: <82@lysator.liu.se>
Date: 18 Jun 90 18:18:02 GMT
Sender: news@isy.liu.se (Lord of the News)
Distribution: comp
Organization: Lysator Computer Club, Linkoping University, Sweden
Lines: 201
Status: O




    HP-48SX DATABASE system usage
  ---------------------------------

This is the usage documentation file. For notes on installation see the
program file.


Menus
-----
To start DATABASE either move one of your database directories or press
the "hot key" combination (as explained in the program file). You will be
presented with a menu (also known as the TOP menu):

   PREV NEXT CURR FIND ADD EDIT

PREV - Displays the previous entry in your current database.
NEXT - Displays the next entry in your current database.
CURR - Displays the current entry in your current database (useful after
       some meny selections, because all don't update the display).
FIND - Move to the FIND submenu.
ADD  - Move to the ADD submenu.
EDIT - Move to the EDIT submenu.

Pressing NXT (that's the HP-48SX key labelled NXT, *NOT* a soft-menu key)
will display the next line of the TOP menu:

   BASES                    QUIT

BASES - Lets you select another database as the current one from the soft
        keys.

QUIT  - If you entered the DATABASE system via the "hot key", this is the
        way to leave, popping you back to your old directory.

When moving to the TOP meny from any submenu, or when starting DATABASE,
the current entry in the current (or default) database will be displayed.
However, due to the way the HP-48SX's display works, the display will
switch to the stack view when NXT or PREV [orange-shift-NXT] (HP-48SX
keyboard functions) are used to see the next line of the TOP menu.


The FIND submenu
----------------
Selecting FIND from the TOP menu, or from any submenu other than the FIND
submenu itself, will display the following menu (the FIND submenu):

   FIND  CONT  EDIT           TOP

FIND - Find an entry in the current database.
CONT - Continue a search for an entry in the current database.
EDIT - Move to the EDIT submenu.
TOP  - Move to the TOP menu.

When moving to the FIND submenu, the current entry in the current database
is displayed.


The ADD submenu
---------------

Selecting ADD from the TOP menu, or from any submenu other than the ADD
submenu itself, will display the following menu (the ADD submenu):

   ADD ADDL CRDB EDIT FIND TOP

ADD  - Add an entry to the current database (make the new entry the first).

       NOTE: All entries are strings. Unpredictable results may occur if
             you try to enter other objects.
             Strings may contain carrige returns (blue-shift-decimal point)
             to create multi-line entries.

ADDL - Add an entry (make the new entry the last. This is useful for entries
       which won't be searched for very often. If many such entries were
       placed first, the time it would take to search for more commonly
       used entries would be drastically longer).
CRDB - Create a new database and move to it. This is an interactive command.
       It prompts your for a name (which will appear in the BASES menu) for
       the new database. To do this, press the Alpha key first, enter a name
       and then press ENTER. The new database will be selected as the
       current one and the first (and only) default, dummy entry will be
       displayed.
EDIT - Move to the EDIT submenu. Useful after CRDB to edit (or more commonly
       to replace) the dummy entry in a new database.
FIND - Move to the FIND submenu.  TOP - Move to the TOP menu.

When moving to the ADD submenu, the current entry in the current database
is displayed.


The EDIT submenu
----------------
Selecting EDIT from the TOP menu, or from any submenu other than the EDIT
submenu itself, will display the following menu (the ADD submenu):

   EDIT REPL DEL ADD FIND TOP

EDIT - Place (a copy of) the current entry on the stack.
REPL - Replace the current entry with the entry on the first
       level of the stack.
DEL  - Delete the current entry.
ADD  - Move to the ADD submenu.
FIND - Move to the FIND submenu.
TOP  - Move to the TOP menu.

When moving to the EDIT submenu, the current entry in the current database
is displayed.

Usually, the sequence for editing an entry is the following:

1) Select the entry you wish to edit with NEXT, PREV, FIND and/or CONT.
2) Move to the EDIT submenu. The current entry will remain in the display.
3) Select EDIT. This will place a copy of the entry on the stack.
4) Hit the down arrow. This will let you edit the string on the first
   level of the stack (ie. a copy of the current entry).
5) To discard, simply press DROP. Select TOP to move to the TOP menu and
   see the unmodified current entry.
6) To replace the current entry with the modified entry (on the first level
   of the stack) select REPL from the menu. This will display the current
   entry (which is now the one you were previously editing).

After having created a new database the following is suggested:

1) Select EDIT submenu from the ADD submenu (in which CRDB appears).
2) Enter a string which you want as the first entry and place it in
   the first level of the stack.
3) Select REPL from the EDIT submenu. This will replace the dummy entry in
   the new database with your new one.


The BASES submenu
-----------------

This will display the currently available databases. If there are more than
six, you will have to use NXT and PREV (HP-48SX keyboard functions) to see
all of them. Pressing the corresponding soft-key for a database will move
you to that database and display the current entry.


A note on the current entry
---------------------------
Each database has a unique current entry. This is the entry which you last
viewed, searched or edited. This will be remembered when you leave the 
DATABASE system, so that next time you enter the same database you will be
positioned at the same entry as last time.
   This entry will be displayed almost all of the time, to ensure that the
user knows which entry is being acted upon. However, due to the way the
HP-48SX works, this display will occasionally be lost. If this should happen
and you are unsure which entry is the current one, simply abort any current
editing and move to the TOP menu. This will redisplay the current entry.
Most of the time, however, this should not pose a problem.


Bugs, errors and room for improvment
------------------------------------
The system can't handle zero length databases. If you DELete the dummy entry
in a newly created database, it will crash when trying to display the current
entry. Use REPL to replace the dummy entry with a valid one.

CRDB needs a name that is a valid directory name on the HP-48SX, i.e. names
such as SIN, HOME, IP etc. will not work.

Currently you can't delete a database once it's created. To do this, press
VAR, UPDIR, put the name of the database's directory on the stack and use
PGDIR.


Final words
-----------
I hope that you find these programs as useful as I do (I use them daily).
However, no program is perfect (few even bug-free !!) so if you have any
comments or suggestions for improvements, please email them to me at the
following addresses:

         howard@lage.lysator.liu.se            --> Good
         howard@lysator.liu.se                 --> Not so good
         Martin_Howard.d89.lith@xns.liu.se     --> Downright bad !

These programs are a continuation of the example database in the book
Customize Your HP-28 by W.A.C. Mier-Jedrzejowicz. If you wish to get hold
of a copy contact EduCALC, CA, USA or Mr Mier-Jedrzejowicz, perhaps via
the HPCC Handhelds & Portables Club, Geggs Lodge, Hempton Road, Deddington,
Oxfordshire, OX5 4QG, ENGLAND or via email one of the following:

         UMAPD51@VAXA.CC.IC.AC.UK
	 umapd51@cc.ic.ac.uk



Martin V. Howard
Linkoping, Sweden, June 18


--
Programming isn't a science,         | EMAIL: howard@lage.lysator.liu.se
it's an art.                         |        howard@lysator.liu.se
Why is it called common sense,       |        Martin_Howard.d89.lith@xns.liu.se
when so few possess it ?             |

From comp.sys.handhelds Mon Jun 25 18:49:39 1990
Path: fauern!unido!mcsun!uunet!tut.cis.ohio-state.edu!uc!norge.unet.umn.edu!fin
From: fin@norge.unet.umn.edu (Craig A. Finseth)
Newsgroups: comp.sys.handhelds
Subject: Almanac Program for the HP-48SX [long message] [at last!]
Message-ID: <1998@uc.msc.umn.edu>
Date: 24 Jun 90 01:44:25 GMT
References: <22609@boulder.Colorado.EDU>
Sender: news@uc.msc.umn.edu
Distribution: comp.sys.handhelds
Organization: Univ Netw Serv, Univ of Minn
Lines: 1147
Status: O


	NOTE:  This program requires the separately supplied BROWSER
	routine.  For those of you who haven't already seen it, I will
	follow this posting with a repost of the browser.

------------------------------------------------------------
Written by: Lauren Nelson, Craig Finseth
When: 23 June 1990
What: Astronomy routines

ALMANAC	ALMANAC program.  See below
G->JD	Converts a date in y.md format to a Julian day number.
JD->G	Converts a Julian day number to a date in y.md format.
JD	Returns the current time as a Julian day number.
LSIDT	Continuously displays the local sidereal time.
SETUP	Initialize or modify ASPAR.

ADATE	Format a HP-48 date into a string as per the HP-41.
ASOK	Checks whether ASPAR is present and calls SETUP if not.
ASPAR	AStronomy PARameters. See below.
ATIME	Format a HP-48 time in h.ms format into a string as per HP-41.
deltaDAYS  Returns the number of days between two dates in y.md format.
ELEV	Returns the elevation entry from ASPAR.  Ensures that ASPAR is present.

GTDIF	Returns the Greenwich time difference entry from ASPAR. 
	Ensures that ASPAR is present.
->h$	Format a HP-48 angle in h.ms format into a string.
JD->LSIDT  Converts a Julian day number with fractions to the local sidereal time.
JDOW	Converts a Julian day number to the string form of its day of the week.
LAT	Returns the latitude entry from ASPAR in decimal degrees. Ensures
	that ASPAR is present.
LONG	Returns the longitude entry from ASPAR in decimal degrees. Ensures
	that ASPAR is present.

OBJECTS	Directory of astronomical object information.  These items
	must be set manually.  They are:

	SolarSystem	Contains names and special RA/decl flags for
			selected solar system objects.
	BrightStars	Contains names and RA/decl data for selected
			bright stars.
	Messier		Contains names and RA/decl data for selected
			Messier objects.

P->R	Polar to Rectangular coordinate conversion.
R->P	Rectangular to Polar coordinate conversion.
YMD->	Converts a date in y.md format to HP-48SX format.
->YMD	Converts a date in HP-48SX format to y.md format.
YMD$	Converts a date in y.md format to string form.

->degree$  Format a HP-48 angle in d.ms format into a string.


General notes:

Julian day numbers: Many of these routines use Julian day numbers. 
These routines assume that the Julian to Gregorian calendar switch was
made in October 1582.  They also assume that there is no year 0.

YY.MMDD Format: Many of these routines use this format for dates.  This
format allows for direct representation of negative years.  They also allow
for representing time as a fractional day of the month.

------------------------------------------------------------
ASPAR:  AStronomy PARameters

This data object is contains the basic astronomical observation
parameters.  It is a list with four entries:

	Greenwich Mean Time Difference: The difference between your
	local time and GMT in h.ms form.  Positive for time zones west
	of Greenwich.

	Longitude: Your longitude in d.ms format.

	Latitude: Your latitude in d.ms format.

	Elevation: Your height above mean sea level (MSL) in meters.

These values can be accessed directly, or through interface procedures
(GTDIF, LONG, LAT, ELEV).  All uses of ASPAR should be prefaced with a
call to ASOK to ensure that ASPAR exists.  If you use these interface
procedures, this call is handled for you.

------------------------------------------------------------
Detailed Interfaces:

ALMANAC	Directory.

G->JD	Stack Input:	date in YY.MMDD format
	Stack Output:	corresponding Julian day number
	Calls:		JD->G

JD->G	Stack Input:	Julian day number
	Stack Output:	corresponding date in YY.MMDD format

JD	Stack Input:	none
	Stack Output:	current time as a Julian day number fraction to
			4 decimal places
	Calls:		G->JD, GTDIF, ->YMD

LSIDT	Stack Input:	none
	Stack Output:	none
	Calls:		ATIME, GTDIF, LONG

	Continual display of the local time and the local sidereal time. 
	Exits when any key is pressed.

SETUP	Stack Input:	none
	Stack Output:	none
	Global Input:	ASPAR
	Global Output:	ASPAR
	Calls:		BROWSE

ADATE	Stack Input:	date in HP-48 format
	Stack Output:	date formatted into a string as per HP-41

ASOK	Stack Input:	none
	Stack Output:	none
	Global Input:	ASPAR
	Calls:		SETUP

	Checks whether ASPAR is present and performs some minimal
verfification of its integrity.   If ASPAR is not present or not
intact, it calls SETUP.

ASPAR	AStronomy PARameters.  See above.

ATIME	Stack Input:	time in HH.MMSS format
	Stack Output:	time formatted into a string as per HP-41

deltaDAYS  Stack Input:	date1 in YY.MMDD format
			date2 in YY.MMDD format
	Stack Output:	number of days between the dates
	Calls:		G->JD

ELEV	Stack Input:	none
	Stack Output:	height value from ASPAR
	Global Input:	ASPAR
	Calls:		ASOK

GTDIF	Stack Input:	none
	Stack Output:	Greenwich mean time difference value from
			ASPAR in decimal hours
	Global Input:	ASPAR
	Calls:		ASOK

->h$	Stack Input:	angle in h.ms format
	Stack Output:	angle formatted into a string

JD->LSIDT  Stack Input:	Julian day number and fraction
	Stack Output:	local sidereal time for that instant
	Calls:		GTDIF, JD->G, LONG, YMD->

JDOW	Stack Input:	Julian day number
	Stack Output:	day of week for that date in string format

LAT	Stack Input:	none
	Stack Output:	latitude value from ASPAR in decimal degrees
	Global Input:	ASPAR
	Calls:		ASOK

LONG	Stack Input:	none
	Stack Output:	longitude value from ASPAR in decimal degrees
	Global Input:	ASPAR
	Calls:		ASOK

OBJECTS	Directory.

P->R	Stack Input:	radius
			angle
	Stack Output:	x coordinate w/tag
			y coordinate w/tag

	Polar to rectangular coordinate conversions.  You would have
	thought that HP would include this.

R->P	Stack Input:	x coordinate
			y coordinate
	Stack Output:	radius w/tag
			angle w/tag

	Rectangular to polar coordinate conversions.  You would have
	thought that HP would include this.

YMD->	Stack Input:	date in YY.MMDD format
	Stack Output:	corresponding date in the current format
	Calls:		->YMD

->YMD	Stack Input:	date in the current HP-48 format
	Stack Output:	corresponding date in YY.MMDD format

YMD$	Stack Input:	date in YY.MMDD
	Stack Output:	date formatted into a string
	Calls:		ATIME

->degree$  Stack Input:	angle in d.ms format
	Stack Output:	angle formatted into a string

============================================================
ALMANAC Directory

NOW	Set the date/time to the now.
THING	Select an object and display its alt/az.
SUN	Display the Sun's alt/az.
MOON	Display the Moon's alt/az.
RISE	Calculate the rise and set times for the object whose
	alt/az was last calculated.
WHEN	Prompts for the observation date and time.

ASOBJECT  Variable: Current object.  Set by THING.
C->AA	Transform RA/decl coordinates to alt/az.
DECL	Variable: Declination.  Set by FIG.
E->C	Transform ecliptical coordinatess to RA/decl coordinates.
FIGC	Figure alt/az for the specified object.
FIGT	Figure the Century Time.

MNalphadelta  Figure the RA and decl for the Moon.
OTJD	Variable: The Julian date/time that the observation is for.
	Set with STOT
RA	Variable: Right ascension.  Set by FIG.
SETOT	Set the observation time.
SNalphadelta  Figure the RA and decl for the Sun.


Note: The formulae used in this program have been approximated for
late 20th century use.  More exact formulae may be created by
consulting the references.  These objects are affected by these
approximations:

	E->C
	FIGT
	MNalphadelta
	SNalphadelta
	OBJECTS:BrightStars
	OBJECTS:Messier	


Basic operation:

1) Run SETUP to initialize ASPAR.

2) Press NOW or enter a date using WHEN.

3) Press THING and select an object, or press SUN or MOON.

4) If desired, press RISE to see the rise and set times.

You may add additional objects by adding to the existing objects in
the OBJECTS directory, or by creating new object lists (they will
automatically be picked up by THING).  If you wish to add objects
whose RA/decl vary, you need to define and use special flag RAs (93,
94, ...), add them to FIG, and create procedures to calculate the
RA/decl.

In future versions, we will replace the RA and decl constants and flag
information with a procedure that returns these values.

------------------------------------------------------------
Data Types:

what			name used	range			type
			in program

object			N		selected list		string

observer latitude			-90 (S) to +90 (N)	D.MS
observer longitude			-180 (E) to +180 (W)	D.MS

right ascension		RA, alpha	0 to 23.5959		H.MS
declination		DECL, delta	0 to 359.5959		D.MS

altitude				-90 (nadir) to +90 (zenith)	D.MS
azimuth					0 (N) to +359.59.59 	D.MS
					 (E=90, S=180, W=270)
ecliptical (celestial)
	longitude	lambda		0 to +359.59.59	 	decimal degrees
ecliptical (celestial)
	latitude	beta		-90 to +90		decimal degrees



Object List:

The object lists in the OBJECTS directory are lists of lists.  Each
sublist has an object name, its right ascention, and its declination
as:

	{ { N1 RA1 decl1 } { N2 RA2 decl2 } ... }

An object with a declination of +91 is assumed to be the Sun.  An
object with a declination of +92 is assumed to be the Moon.


------------------------------------------------------------
Detailed Interfaces:

NOW	Stack Input:	none
	Stack Output:	none
	Calls:		SETOT, ->YMD

THING	Stack Input:	none
	Stack Output:	object
			object's altitude
			object's azimuth
	Global Input:	OBJECTS directory
	Global Output:	ASOBJECT
	Calls:		BROWSE (separately supplied), FIGC

SUN	Stack Input:	none
	Stack Output:	none
	Screen:		"Sun"
			Sun's altitude
			Sun's azimuth
	Global Output:	ASOBJECT
	Calls:		FIGC, ->degree$

MOON	Stack Input:	none
	Stack Output:	none
	Screen:		"Moon"
			Moon's altitude
			Moon's azimuth
	Global Output:	ASOBJECT
	Calls:		FIGC, ->degree$

RISE	Stack Input:	none
	Stack Output:	none
	Screen:		oject name
			object's rising time
			object's rising azimuth
			object's setting time
			object's setting azimuth
	Global Input:	ASOBJECT, DECL, OTJD, RA
	Global Output:	OTJD
	Calls:		ATIME, G->JD, GTDIF, JD->G, LAT, LONG, YMD->,
			->YMD, ->degree$

	Figure an object's rise and set times.  It uses the last
object whose altitude and azimuth were computed (i.e., the last
invocation of THING, SUN, or MOON).

WHEN	Stack Input:	none
	Stack Output:	none
	Calls:		SETOT

	Prompts for observation date and time.

ASOBJECT  Variable.

C->AA	Stack Input:	RA
			decl
	Stack Output:	az w/tag
			alt w/tag
	Global Input:	OTJD
	Calls:		JD->LSIDT, LAT

	Applies correction for atmospheric refraction for altitudes
starting at -.55 degrees.

DECL	Variable.

E->C	Stack Input:	ecliptical longitude
			ecliptical latitude
	Stack Output:	RA
			decl
	Calls:		R->P

FIGC	Stack Input:	list containing object, RA, decl
	Stack Output:	object
			azimuth w/tag
			altitude w/tag
	Global Input:	ASOBJECT
	Global Output:	DECL, RA
	Calls:		C->AA, MNalphadelta, SNalphadelta

	Figure the altitude and azimuth for the specified object.
	Also record the object's right ascension and declination.

FIGT	Stack Input:	none
	Stack Output:	Century Time
	Global Input:	OTJD

MNalphadelta  Stack Input:	none
	Stack Output:	Moon's RA
			Moon's declination
	Calls:		E->C, FIGT

OTJD	Variable.

RA	Variable.

SETOT	Stack Input:	date in YY.MMDD format
	Stack Output:	none
	Global Output:	OTJD
	Calls:		G->JD, GTDIF

SUNalphadelta	Stack Input:	none
	Stack Output:	Sun's RA
			Sun's declination
	Calls:		FIGT, R->P

------------------------------------------------------------
References:

Hirshfeld, Alan and Sinnott, Roger W., "Sky Catalogue 2000.0," 2
volumes, Cambridge University Press, Cambridge, UK, 1982.

Meeus, Jean, "Astronomical Formulae for Calculators, Second Edition,"
Willmann-Bell, Inc., Richmond, VA, 1982.

"The Concise Planetary Ephemeris for 1950 to 2000 A.D.," The Hieratic
Publishing Co., Medford, MA, 1977.


Checksum: #ce35h
Size: 9830.5
------------------------------------------------------------
%%HP: T(3)A(D)F(.);
DIR
  ALMANAC
    DIR
      NOW
        \<< TIME DATE
\->YMD SETOT
        \>>
      THING
        \<< PATH
OBJECTS {
"    Select a Class"
1 0
          \<<
          \>> } VARS
BROWSE SWAP DROP
OBJ\-> DROP SWAP DROP
          IF 0 ==
          THEN
UPDIR DROP
          ELSE {
"  Select an Object"
1 0
            \<< 1 GET
            \>> }
SWAP BROWSE SWAP
DROP OBJ\-> DROP SWAP
DROP
            IF 0 ==
            THEN
UPDIR DROP
            ELSE
UPDIR SWAP EVAL
'ASOBJECT' STO FIGC
            END
          END
        \>>
      SUN
        \<< { "Sun"
91 0 } 'ASOBJECT'
STO FIGC 4 RND \->\^o$
"Alt: " SWAP + SWAP
4 RND \->\^o$ "Az: "
SWAP + CLLCD 3 DISP
2 DISP 1 DISP 7
FREEZE
        \>>
      MOON
        \<< { "Moon"
92 0 } 'ASOBJECT'
STO FIGC 4 RND \->\^o$
"Alt: " SWAP + SWAP
4 RND \->\^o$ "Az: "
SWAP + CLLCD 3 DISP
2 DISP 1 DISP 7
FREEZE
        \>>
      RISE
        \<< OTJD DUP
GTDIF 24 / - \-> P O
          \<< RCLF
DEG 0 3
            FOR I
-.009
              IF
ASOBJECT 1 GET DUP
"Sun" SAME SWAP
"Moon" SAME OR
              THEN
.0045 -
              END
LAT SIN DECL HMS\->
SIN * - LAT COS
DECL HMS\-> COS * /
ACOS 15 / RA HMS\->
SWAP DUP2 - 3 ROLLD
+ 1.002738 6.66452
LONG 15 / - SWAP
GTDIF * + O JD\->G
YMD\-> 1.012 DDAYS
15.218442 / - DUP
ROT SWAP - 24 MOD
1.002738 / 3 ROLLD
- 24 MOD 1.002738 /
O JD\->G YMD\-> \->YMD
              IF I
2 <
              THEN
ROT DROP SWAP
              ELSE
SWAP DROP SWAP
              END
              IF I
2 MOD 1 ==
              THEN
DUP \->HMS 4 RND
ATIME
IF I 1 ==
THEN "RISE"
ELSE "SET"
END \->TAG I 1 + DISP
              END
240000 / + G\->JD
GTDIF 24 / + 'OTJD'
STO FIGC ROT
              IF I
0 ==
              THEN
CLLCD 1 DISP
              ELSE
DROP
              END
DROP
              IF I
2 MOD 1 ==
              THEN
2 RND \->\^o$ DUP "'"
POS 1 SWAP SUB
"Az: " SWAP + I 2 +
DISP
              ELSE
DROP
              END
            NEXT 7
FREEZE STOF P
'OTJD' STO
          \>>
        \>>
      WHEN
        \<<
"ENTER Observation"
10 CHR +
"time in h.min sec"
+ 10 CHR +
"local, 24 hr. form."
+ { "" V } INPUT
OBJ\->
"ENTER Observation"
10 CHR +
"date as year.mo day"
+ { "" V } INPUT
OBJ\-> SETOT
        \>>
      ASOBJECT {
"\Gg Ori:Bellatrix"
5.2507 6.2059 }
      C\->AA
        \<< HMS\-> SWAP
HMS\-> 15 * SWAP \-> \Ga
\Gd
          \<< OTJD
JD\->LSIDT HMS\-> 15 *
\Ga - \-> H
            \<< RCLF
DEG H SIN H COS LAT
SIN * \Gd TAN LAT COS
* - SWAP R\->C ARG
180 + 360 MOD LAT
SIN \Gd SIN * LAT COS
\Gd COS * H COS * +
ASIN DUP
              IF
-.55 >
              THEN
DUP 3.4 + 1.6 SWAP
/ .017130621 - +
              END
\->HMS "Alt" \->TAG
SWAP \->HMS "Az" \->TAG
SWAP ROT STOF
            \>>
          \>>
        \>>
      DECL 6.2059
      E\->C
        \<<
23.4392911 \-> \Gl \Gb \Ge
          \<< RCLF
DEG \Gl SIN \Ge COS * \Gb
TAN \Ge SIN * - \Gl COS
SWAP R\->P SWAP DROP
15 / \->HMS \Gb SIN \Ge
COS * \Gb COS \Ge SIN *
\Gl SIN * + ASIN \->HMS
ROT STOF
          \>>
        \>>
      FIGC
        \<< ASOBJECT
OBJ\-> DROP DUP2 DROP
          IF 91 ==
          THEN
DROP2 SN\Ga\Gd
          END
          IF DUP2
DROP 92 ==
          THEN
DROP2 MN\Ga\Gd
          END DUP2
'DECL' STO 'RA' STO
C\->AA
        \>>
      FIGT
        \<< OTJD
2415020 - 36525 /
        \>>
      MN\Ga\Gd
        \<< FIGT \-> T
          \<<
270.434164
481267.8831 T * +
360 MOD 358.475833
35999.0498 T * +
296.104608
477198.8491 T * +
350.737486
445267.1142 T * +
11.250889
483202.0251 T * + \->
LP M MP D F
            \<< RCLF
DEG LP 6.28875 MP
SIN * + 1.274018 D
2 * MP - SIN * +
.658309 D 2 * SIN *
+ 5.128189 F SIN *
.280606 MP F + SIN
* + .277693 MP F -
SIN * + E\->C ROT
STOF
            \>>
          \>>
        \>>
      OTJD
2448066.37273
      RA 5.2507
      SETOT
        \<< G\->JD SWAP
HMS\-> GTDIF + 24 / +
'OTJD' STO
        \>>
      SN\Ga\Gd
        \<< RCLF DEG
FIGT \-> T
          \<<
279.69668
36000.76892 T * +
.0003025 T SQ * +
358.47583
35999.04975 T * +
.00015 T SQ * -
.0000033 T 3 ^ * -
\-> L M
            \<<
1.91946 .004789 T *
- .000014 T SQ * -
M SIN * .020094
.0001 T * - M 2 *
SIN * + .000293 M 3
* SIN * + 23.452294
.0130125 T * -
.00000164 T SQ * -
.000000503 T 3 ^ *
+ 259.18 1934.142 T
* - DUP COS .00256
* ROT + \-> C \GW \Ge
              \<< L C
+ .00569 .00479 \GW
SIN * - - \-> SLA
\<< \Ge COS SLA SIN *
SLA COS SWAP R\->P
SWAP DROP 15 / \->HMS
\Ge SIN SLA SIN *
ASIN \->HMS
\>>
              \>>
            \>>
          \>> ROT
STOF
        \>>
    END
  G\->JD
    \<< DUP DUP IP
SWAP ABS FP 100 *
DUP IP SWAP FP 100
* 4 ROLL 0 0 0 0 \->
Y M D J M1 Y1 C B
      \<<
        IF M 2 \<=
        THEN Y 1 -
'Y1' STO M 12 +
'M1' STO
        ELSE Y 'Y1'
STO M 'M1' STO
        END
        IF J
1582.1015 \>=
        THEN 2 Y1
100 / IP - Y1 400 /
IP + 'B' STO
        END
        IF Y 0 \<=
        THEN .75
'C' STO 1 'Y1' STO+
        END 365.25
Y1 * C - IP 30.6001
M1 1 + * IP + D +
1720994.5 + B + DUP
J SWAP JD\->G
        IF \=/
        THEN DROP J
# D01h DOERR
        END
      \>>
    \>>
  JD\->G
    \<< DUP
      IF 0 <
      THEN
"Negative Julian Day"
DOERR
      END .5 + DUP
IP DUP ROT FP SWAP
1867216.25 -
36524.25 / IP 3
PICK
      IF 2299161 <
      THEN DROP
SWAP
      ELSE DUP 4 /
IP - 1 + ROT +
      END 1524 +
DUP 122.1 - 365.25
/ IP DUP 365.25 *
IP DUP 4 PICK SWAP
- 30.6001 / IP SWAP
4 ROLL SWAP - SWAP
DUP 30.6001 * IP
ROT SWAP - 4 ROLL +
SWAP DUP
      IF 13.5 <
      THEN 1 -
      ELSE 13 -
      END DUP
      IF 2.5 >
      THEN ROT 4716
-
      ELSE ROT 4715
-
      END DUP
      IF 0 \<=
      THEN 1 -
      END SWAP ROT
100 / + 100 / SWAP
DUP SIGN SWAP ABS
ROT + *
    \>>
  JD
    \<< GTDIF TIME
HMS+ 4 RND HMS\-> 24
/ DUP FP 10000 /
SWAP IP DATE SWAP
DATE+ \->YMD SWAP +
G\->JD
    \>>
  LSIDT
    \<< 6.66452 LONG
15 / - GTDIF
1.002738 * + .0002
+ RCLF 3 FIX CLLCD
"Local Siderial Time."
5 DISP
"Local Time." 1
DISP SWAP \-> a
      \<<
        DO a DATE
1.012 DDAYS
15.21842 / - \-> Y
          \<<
            WHILE
              IF 0
KEY ==
              THEN
TIME .00005 HMS+
DUP HMS\-> DUP 4 TRNC
              ELSE
0 0
              END 0
\=/
            REPEAT
SWAP 4 TRNC ATIME 2
DISP 1.002738 * Y +
24 MOD \->HMS 4 TRNC
RCLF SWAP -41 SF
ATIME 6 DISP STOF
            END
          \>>
        UNTIL 0 ==
        END
      \>> DROP STOF
    \>>
  SETUP
    \<< { :GMT: 0
:EST: 5 :EDT: 4
:CST: 6 :CDT: 5
:MST: 7 :MDT: 6
:PST: 8 :PDT: 7
:AST: 9 :ADT: 8 } \->
TZ
      \<< { } ASPAR
DUP TYPE
        IF 5 \=/ SWAP
SIZE 4 \=/ OR
        THEN :GMT:
0
        ELSE ASPAR
1 GET
        END {
"SELECT A TIME ZONE"
} TZ ROT POS + 0 +
        \<<
        \>> + TZ
BROWSE 1 GET SWAP
DROP
      \>> +
"ENTER Your longitude"
10 CHR +
"as deg . min sec"
+ { } ":Long.:"
      IFERR ASPAR 2
GET DTAG
      THEN ""
      END + + -8 +
V + INPUT OBJ\-> +
"ENTER Your latitude."
10 CHR +
"as deg . min sec"
+ { } ":Lat.:"
      IFERR ASPAR 3
GET DTAG
      THEN ""
      END + + -7 +
V + INPUT OBJ\-> +
"ENTER Your altitude"
10 CHR +
"in meters." + { }
":ELEV.:"
      IFERR ASPAR 4
GET DTAG OBJ\-> DROP
      THEN ""
      END + + -7 +
V + INPUT OBJ\-> '1_m
' \->UNIT "ELEV."
\->TAG + 'ASPAR' STO
    \>>
  ADATE
    \<< DUP 1 TSTR 1
10 SUB SWAP 100 *
FP 10000 * +
    \>>
  ASOK
    \<< ASPAR DUP
TYPE
      IF 5 \=/ SWAP
SIZE 4 \=/ OR
      THEN SETUP
      END
    \>>
  ASPAR { :CDT: 5
:Long.: 93.104213
:Lat.: 44.57546
:ELEV.: '278.9_m' }
  ATIME
    \<< HMS\-> \->HMS
      IF -41 FC?
      THEN 24 MOD
      END DUP SIGN
SWAP ABS DUP IP
SWAP DUP DUP 4 TRNC
- 10000 * SWAP FP
1.1 SWAP
      IF -41 FC?
      THEN 4 PICK +
      END TSTR -41
      IF FS?
      THEN 17 22
SUB SWAP DUP
        IF 0 ==
        THEN DROP
        ELSE \->STR
          IF DUP
"E" POS 0 ==
          THEN DUP
DUP "." POS SWAP
SIZE SUB +
          ELSE DROP
          END
        END
      ELSE DUP 14
21 SUB " " + SWAP
22 22 SUB + "M" +
SWAP DROP
      END SWAP
      IF -41 FS?
      THEN \->STR DUP
1 SWAP "." POS 1 -
DUP
        IF 1 <
        THEN DROP
OVER SIZE
        END SUB
SWAP +
      ELSE DROP
      END SWAP
      IF 0 <
      THEN "-" SWAP
+
      END
    \>>
  \GdDAYS
    \<< G\->JD SWAP
G\->JD -
    \>>
  ELEV
    \<< ASOK ASPAR 4
GET
    \>>
  GTDIF
    \<< ASOK ASPAR 1
GET HMS\->
    \>>
  \->h$
    \<< RCLF STD SWAP
HMS\-> \->HMS DUP FP
\->STR SIZE DUP 4
      IF \<=
      THEN DROP 4
FIX
      ELSE 1 - FIX
      END \->STR DUP
"." POS SWAP OVER
"h" REPL DUP 3 PICK
2 + OVER SIZE SUB 1
"m" REPL ROT 3 +
DUP 4 ROLLD SWAP
REPL "s" + SWAP 2 +
OVER OVER OVER SIZE
DUP2
      IF \>=
      THEN 4 DROPN
      ELSE SUB 1
"." REPL SWAP 1 +
SWAP REPL
      END SWAP STOF
    \>>
  JD\->LSIDT
    \<< GTDIF 24 / -
\-> J
      \<< 1.002738
6.66452 LONG 15 / -
OVER GTDIF * + J
JD\->G YMD\-> 1.012
DDAYS 15.218442 / -
SWAP J *JD\->G 10000 *
FP 24 * * + 24 MOD
\->HMS
      \>>
    \>>
  JDOW
    \<< 0 RND 1 + 7
MOD
"SUNMONTUEWEDTHUFRISAT"
SWAP DUP 3 * 1 +
SWAP 1 + 3 * SUB
    \>>
  LAT
    \<< ASOK ASPAR 3
GET HMS\->
    \>>
  LONG
    \<< ASOK ASPAR 2
GET HMS\->
    \>>
  OBJECTS
    DIR
      SolarSystem {
{ "Sun" 91 0 } {
"Moon" 92 0 } }
      BrightStars {
{ "\Ga Tau:Aldebaran"
4.3555 16.3033 } {
"\Gb Per:Algol" 3.081
40.5721 } {
"\Ga Aql:Altair"
19.5046 8.5206 } {
"\Ga Sco:Antares"
16.2924 -26.2555 }
{ "\Ga Boo:Arcturus"
14.1539 19.1057 } {
"\Gg Ori:Bellatrix"
5.2507 6.2059 } {
"\Ga Ori:Betelguese"
5.551 7.2426 } {
"\Ga Car:Canopus"
6.2357 -45.5651 } {
"\Ga Aur:Capella"
5.1641 45.5953 } {
"\Ga Cyg:Deneb"
20.4125 45.1649 } {
"\Gb Tau:Elnath"
5.2617 28.3627 } {
"\Ga PsA:Fomalhaut"
22.5738 -29.372 } {
"\Gs Cet:Mira" 2.1921
60.291 } {
"\Ga UMi:Polaris"
2.315 89.1551 } {
"\Gb Gem:Pollux"
7.4518 28.0134 } {
"\Ga CMi:Procyon"
7.3918 5.133 } {
"\Ga Leo:Regulus"
10.0822 11.5802 } {
"\Gb Ori:Rigel"
5.1432 -8.1206 } {
"\Ga Sgr:Rukbat"
19.2353 -40.3658 }
{ "\Ga CMa:Sirius"
6.4508 -16.4258 } {
"\Ga Vir:Spica"
13.2511 -11.0941 }
{ "\Ga Lyr:Vega"
18.3656 38.4701 } {
"\Ga Cen" 14.3935
-60.5013 } {
"\Gt Cet" 1.4404
-15.5615 } }
      Messier { {
"M1:Crab Nebula"
5.34 22.01 } {
"M31:Andromeda" .43
41.16 } {
"M42:Orion Nebula"
5.35 -5.27 } {
"M45:Pleiades" 3.47
24.07 } }
    END
  P\->R
    \<< DUP2 COS *
"x" \->TAG 3 ROLLD
SIN * "y" \->TAG
    \>>
  R\->P
    \<< R\->C DUP ABS
"r" \->TAG SWAP ARG
"\<)" \->TAG
    \>>
  YMD\->
    \<< 4 TRNC
      IF -42 FC?
      THEN \->YMD
\->YMD 100 /
      ELSE DUP IP
SWAP FP 100 * DUP
IP SWAP FP 100 *
SWAP ROT 10000 / +
100 / +
      END
    \>>
  \->YMD
    \<< DUP IP SWAP
FP 100 * DUP IP
SWAP FP 10000 *
      IF -42 FC?
      THEN ROT ROT
      ELSE SWAP ROT
      END 100 / +
100 / +
    \>>
  YMD$
    \<< DUP SIGN SWAP
ABS DUP IP SWAP DUP
DUP 4 TRNC - 10000
* SWAP FP 1.1 SWAP
TSTR -41
      IF FS?
      THEN 17 22
      ELSE 16 21
      END SUB SWAP
RCLF SWAP STD DUP
      IF 0 ==
      THEN DROP
      ELSE ROT "  "
+ SWAP 24 * \->HMS 4
RND ATIME + SWAP
      END STOF +
SWAP
      IF 0 <
      THEN "-" SWAP
+
      END 1 2
      START DUP ":"
POS "/" REPL
      NEXT
    \>>
  \->\^o$
    \<< RCLF STD SWAP
HMS\-> \->HMS DUP FP
\->STR SIZE DUP 4
      IF \<=
      THEN DROP 4
FIX
      ELSE 1 - FIX
      END \->STR DUP
"." POS SWAP OVER
"\^o" REPL DUP 3 PICK
2 + OVER SIZE SUB 1
"'" REPL ROT 3 +
DUP 4 ROLLD SWAP
REPL 34 CHR + SWAP
2 + OVER OVER OVER
SIZE DUP2
      IF \>=
      THEN 4 DROPN
      ELSE SUB 1
"." REPL SWAP 1 +
SWAP REPL
      END SWAP STOF
    \>>
END

From comp.sys.handhelds Mon Jun 25 18:49:48 1990
Path: fauern!unido!mcsun!uunet!tut.cis.ohio-state.edu!uc!norge.unet.umn.edu!fin
From: fin@norge.unet.umn.edu (Craig A. Finseth)
Newsgroups: comp.sys.handhelds
Subject: Browser Routines for the HP-48SX [long message] [repost]
Message-ID: <1999@uc.msc.umn.edu>
Date: 24 Jun 90 01:46:37 GMT
Sender: news@uc.msc.umn.edu
Distribution: comp.sys.handhelds
Organization: Univ Netw Serv, Univ of Minn
Lines: 631
Status: O


>>> This code is for a general-purpose list browser (test routine follows).

>>> I will be posting a set of astronomy routines and alamanc in a
week or so.  They use this browser, so if they sound interesting, save
this.

Craig A. Finseth			fin@unet.umn.edu [CAF13]
University Networking Services		+1 612 624 3375 desk
University of Minnesota			+1 612 626 1002 FAX
130 Lind Hall, 207 Church St SE, Minneapolis MN 55455-0134, U.S.A.

------------------------------------------------------------

The HP-48SX Browser Instructions and Commented Listing
Version 1.1, 23 May 1990
Copyright (c) 1990 by Jeff Brown, free for personal non-commercial use.
Formatted for monofont (e.g. Courier type for Postscript/Macintosh users)

Contents:

	Purpose of the Browser
	Parts of the Browser Display
	Browser Keys
	Applications of the Browser
	How to Use the Browser
	Advanced Use of the Browser
	Technical Details of the Browser
	Areas for Improvement
	Browser Commented Listing
	Browser Variables
	Browser Downloadable Listing


PURPOSE OF THE BROWSER

The browser provides a clean, intuitive way for users to browse the
contents of a list and select an item.

If you have used the catalog function of the Solver or Plotter, you
have already used a kind of browser.  The browser is not an
application.  It is a user interface tool to be used by your
applications.  At about 1,800 bytes, it is small enough to be used
even in 32K machines.

The Browser is a simple to incorporate but powerful programming tool. 
Your users will find it an intuitive and convenient way to choose from
among data items or options.

Your program calls the browser with a message and a list on the stack. 
The browser displays your message and list to the user.  It manages
keys and the display, permitting the user to scroll and page through
the list until he finds the appropriate item.  When the user selects
an item, the browser returns its current state, the selected item and
the item's position to the stack.

Using the results from a browse, you can change or edit items at the
user's request or choose different execution paths.  Since the browser
returns its state, you can accept the user's choice, take action and
return the user to browsing where he last left off.  This permits some
fairly flashy applications.

The browser is very simple to operate but it can be used in so many
ways, it takes a bit of explaining.  If you wish to just give it a
try, skip to the 'How to Use the Browser' section.


PARTS OF THE BROWSER DISPLAY

Description           Example HP-48 display       Display Line Used
-----------------     ----------------------     -----------------
Prompt message ->     Select a company:           Line 1

               ->      Apple
              |        Compaq
List pane   --|       >Hewlett-Packard            Lines 2-6
              |        IBM
               ->      Zenith 

Scroll bar     ->     <--------####-------->      Line 7

The prompt message is your message to the user indicating what is
being browsed and what you expect the user to do.

The list pane is a scrolling window onto your list.  There is always a
current item in the window.  This item is displayed with a cursor in
front of it.

The scroll bar graphically represents the location of the list pane
within the list. A block of box characters (called a 'thumb')
representing the pane moves along the scroll bar as the user scrolls
through the list. The size of the thumb represents the portion of the
list visible in the pane. The larger the list, the smaller the thumb.

Note: the box characters of the thumb are represented here as '#'
since there is no ASCII box character.


BROWSER KEYS

Prefix       Key               Function
-----------  ----------        ---------------------------------------
             Up arrow          scroll up one item
Left-shift   Up arrow          scroll up one page (five items)
Right-shift  Up arrow          go to top of list
             Down arrow        scroll down one item
Left-shift   Down arrow        scroll down one page (five items)
Right-shift  Down arrow        go to bottom of list
             Enter             accept current item
             Backspace         cancel browsing without choosing

The left arrow key functions identically to the up arrow and the right
arrow key functions identically to the down arrow.


APPLICATIONS OF THE BROWSER

	- Address or phone number lists
	- Inspectors that let the user delve into the structure of
	  objects.
	- Presentation of program options

For a good real-live application of the browser, refer to the Almanac program and Astronomy Directory by Craig Finseth and Lauren Nelson.


HOW TO USE THE BROWSER

The browser takes two arguments from the stack.  The simplest way to
call the browser is to put the following arguments on the stack:

	Level 2: your message to the user (string)
	Level 1: the list to be browsed (list or name)

The browser will take care of the user interaction and return the
following results to the stack:

	Level 2: state of the browser (list)
	Level 1: acceptance information (a list) consisting of:

		- item selected (type depends on the object),
		- position of the item in the list (real number),
		- 0 if user cancelled or keycode (51.1) if user
		  accepted (real number)

Example:

Peter Palmer, proprietor of Palmer's Polygonal Pies, wishes to record
customer orders using his trusty HP-48SX.  Since pie names are long
and descriptive, it would be best to select the pies from a list.

To build a program which takes orders, Peter stores the available
types of pies in a variable:

	{ "Triangular Treacle" "Raspberry Rhombus" "Pentagonal Plum"
	"Hexagon Hash" "Strawberry Septagon"  "Octagonal Orange Mousse"
	"Nonpareil Nonagon" "Decagonal Delight"} 'pies' STO

Next, he writes a little program that takes pie orders.  A fragment
that gets the user's choice of pie looks like this:

	"Select a Pie:" pies BROWSE 1 GET 

This invokes the browser:

	Select a pie:
	>Triangular Treacle
	 Raspberry Rhombus
	 Pentagonal Praline
	 Hexagon Hash
	 Strawberry Septagon
	##############------->

After the user chooses a pie, the 1 GET retrieves the description of
the user's chosen pie.  Peter's program could also add the choice to
an order list or use the position of the choice (2 GET) to look up
pricing information from a price list.


ADVANCED USE OF THE BROWSER

If you wish to have the browser start at a particular position in the
list or if you need to specially format your list items for display,
there is an alternate way to call the browser:

	Level 2: a list consisting of:

		- Your message (string)
		- Current item in list (real number)
		- Lines off-screen above the list pane (real number)
		- Procedure used to format your list items (program)

	Level 1: the list to be browsed (list or name)

The list in level 2 is the same format as that returned to level 2
when the browser ends.  This is a brief run-down of its parts:

	1) Your message to the user

	2) The current item (the list position pointed to by the cursor).

	3) The lines off-screen tells the browser how far down in the
	list its window should start (if the current item is not visible
	in this area, the list pane will be moved far enough in the
	appropriate direction to include it).

	4) The browser will run your program object on each list item
	prior to displaying it.  Your program object should take an item
	(extracted from your list by the browser and placed in level 1)
	and format it for display by the browser.  The browser will call
	this code every time it draws an item in the display so keep it
	fast and simple.

This approach is very powerful because you can start the browser in
any position and format its items any way you like.  The list is
returned to you (updated to match the user's actions) when the browser
ends.  This enables you to take the user's response, carry out
appropriate actions and return to browsing the list in the same
position the user left off.  

One use of this is to browse hierarchically, that is, browse a list of
lists, returning to the proper place every time the user pops up a
level.  To do this, just keep a list containing your list path and a
matching list containing browser state lists.  When the users pops up
a level, just discard the last item in each list and call the browser
with the new last item.  For example a program for selecting people to
receive mailings might work like this:

Select a company:
 Apple
 Compaq
>Hewlett-Packard	User selects company, presses enter
 IBM
 Zenith 
######################

	Select a division:
	 Boise
	>Corvallis
	 Phoenix		User selects division, presses enter
	 Palo Alto
	 Santa Clara 
	<-###############---->

		Select an Employee:
		 Sanders, John
		 Terpack, Daniel
		 Vogel, Eric		User selects employee (presses enter)
		 West, Carmen		(repeat as needed then press backspace)
		>Wickes, William 
		<-------------------#>

	Select a division:
	 Boise
	>Corvallis
	 Phoenix		User is returned to the division browser
	 Palo Alto		(with list pane and current item unchanged)
	 Santa Clara 
	<-###############---->


TECHNICAL DETAILS OF THE BROWSER

The original version of the browser was a collection of three main
program objects and about two dozen state variables and key handling
objects.  To eliminate the need for a separate browser directory, I
have compressed the whole thing into a single program object (with
considerable loss of readability).

The browser has four logical parts:

	Browse - sets things up for browsing

	MainLoop - waits for key events and hands them off to handlers.

	DrawView - draws the browser after key events change it.

	Key handlers - interpret the meaning of various keys.
     

BROWSE

This initialization code is run when the browser is called.  It
extracts the input parameters and puts them in temporary variables. 
It also calculates the size of the thumb.  When Browse finishes setup,
it flows into the main loop.

MAINLOOP

The main loop is wrapped around the DrawView procedure and the key
handlers.  It loops, drawing the browser and handling keys until the
user accepts an item or aborts the browsing process.

DRAWVIEW

DrawView checks the current state of the browser and uses one of three
methods to draw the browser's visible parts on the screen.

If the list pane is above the current item (the user scrolled down) it
redraws the pane from the bottom up.

If the list pane is below the current item (the user scrolled up) it
redraws the pane from the top down.

If the current and previous items are both in the pane (the user moved
the cursor within the visible region) only the current and previous
items are redrawn.

Originally, I simply drew the lines of the browser from the top down,
every time.  Performance was so slow that when scrolling down, the
display gave the impression that it was scrolling up.  This came about
because the user pressed the down arrow key but saw the top lines of
the display changing first.  To remedy this, I determine which way the
user scrolled and redraw the lines from that direction.  This gives a
satisfying sense of scrolling in the proper direction.

To further improve performance, DrawView checks to see if the cursor
has moved out of or into the visible region.  If it has not, only the
previous item and the current item are redrawn.  This cuts drawing
time in half.

I decided to implement the scroll bar fairly early in development. 
Browsing a large list can be disorienting. People need to know where
they are in a list and how much progress they are making with each
keystroke. They use the cursor keys differently in large lists than
they do in small lists so constant visual feedback is very valuable.


AREAS FOR IMPROVEMENT

Speed is not as snappy as it ought to be.  Limited redraws take about
0.8 seconds, full redraws take 1.5 seconds.  The code needs to run
about four times faster.  An assembly language version would improve
this.  Since my Saturn assembly skills are a bit rusty, I will leave
this to others for the time being.

I have not tried bit-wise scrolling of the list pane.  It is
conceivable that this might be faster than re-drawing the entire pane
on some occasions.

The scroll bar is a bit cheesy in that it is horizontal and the list
is displayed vertically.  This was a practical necessity since there
isn't enough vertical resolution to do it vertically.  Ideally, I
would do a vertical bit-mapped scroll bar.  This would have enough
resolution (48 pixels) for the job.  Again, assembly language might be
the only practical solution.

Originally, I planned to take a menu key list and display it so you
could add user-defined features to the browser, but this was torpedoed
by HP's method of handling menus.  There is no supported way to
display a menu and retain program control. A program must halt for the
menu to appear. In short, I can't display your menu and give you back
keycodes when the user presses menu keys. To further exacerbate matters, I can't get rid of the potentially confusing menus already displayed or use the extra line for more items.  Ideas, anyone?

I may do some experimentation with binary searches on ordered lists. 
This would permit an 'alpha mode' for the browser so users could press
a letter key and instantly jump to that part of the list.

Some applications may want several items from a single browse. Features to permit selection of multiple items (by creating contiguous or non-contiguous selections) before accepting would be useful if user 
interface issues could be resolved. 

Features for range selection and Cut/Copy/Paste would be great for
interactive list editing.  This would be a dream for editing programs.


BROWSER COMMENTED LISTING

/* browse  L2: msg | {msg c brOS fmtP} L1: list | name of list */

\<<
"by Jeff Brown (612) 646-2478" DROP
"v1.1" DROP
DUP
IF TYPE 6 == THEN		/* if it is a name, get its value */
	EVAL
END
DUP				/* list */
SIZE				/* listL */
DUP 5 MIN			/* brL */
DUP2
158 CHR				/* loop to build thumb */
\-> l b t
\<<
""
1
b l / 22 * 0 RND
FOR i
t +
NEXT
\>>				/* thumb */
"\<---------------------\->"	/* scrB */
6 ROLL DUP
IF TYPE 5 ==
THEN LIST\-> DROP		/* msg c brOS fmtP */
     ELSE 1 0 \<< \>> {}
END
3 PICK				/* p */
\<<220 0.125 BEEP\>>		/* eBeep */
134 CHR				/* cursChr */
1				/* full */
1				/* continue */
1				/* j */
CLLCD
\-> list listL brL thumb scrB msg c brOS fmtP p eBeep cursChr
full continue j

\<<
Msg 1 DISP

WHILE continue 1 ==
REPEAT

/* drawView */

     1 DUP 'j' STO brL		/* loop limits */
     CASE
	  c brOs s THEN		/* user moved above pane */
	       c 1 - 'brOs' STO
	       1 'full' STO
	  END
	  c brOs brL + > THEN	/* user moved below pane */
	       DROP2 c brL - 'brOs' STO
	       1 'full' STO
	       brL 1 -1 'j' STO	/* set new loop limits */
	  END
     END
     IF full 1 == THEN		/* full redraw is needed */
	  0 'full' STO
	  FOR i
	       IF i c brOs - = THEN 
		    " " list brOs i + GET fmtP EVAL 
		    \->STR + i 1 + DISP
	       ELSE
		    cursChr list brOs i + GET fmtP EVAL 
		    \->STR + i 1 + DISP
	       END
	  J STEP
	  c 'p' STO
	  scrB brOs listL / 22 * .5 + 0 RND thumb REPL 7 DISP
     ELSE DROP2
	  " " list p GET fmtP EVAL \->STR + p brOs - 1 + DISP
	  cursChr list c GET fmtP EVAL \->STR + c brOs - 1 + DISP
     END
     3 FREEZE

/* mainLoop */

0 WAIT \-> k
     \<<
     IF k FP .3 > THEN k .3 - 'k' STO END
     CASE k IP DUP 35 == SWAP 36 == OR THEN	/* a down key*/
	       IF c listL == THEN 
		    eBeep EVAL
		    ELSE listL			/* bottom of list */
		    c DUP DUP 'p' STO
		    brL + listL MIN		/* page dn/last item */
		    SWAP 1 +			/* item down */
		    k FP 10 * ROLL
		    'c' STO DROP2		/* choose by keycode */
	       END
	  END
	  k IP DUP 25 == SWAP 34 == OR THEN	/* an up key */
	       IF c 1 == THEN
		    eBeep EVAL
		    ELSE 1			/* top of list */
		    c DUP DUP 'p' STO
		    brL - 1 MAX			/* page up/1st item */
		    SWAP 1 -			/* item up */
		    k FP 10 * ROLL		/* choose by keycode */
		    'c' STO DROP2
	       END
	  END
	  k 51.1 == THEN			/* enter */
	       list c GET c 0 'continue' STO
	  END
	  k 15.1 == THEN			/* cancel */
	       0 DUP 'continue' STO
	  END
     END
     \>>
END
{} msg + c + brOS + fmtP +
3 ROLLD
\>>


BROWSER VARIABLES

continue	boolean		Should waitLoop continue?
full		boolean		Should drawView do entire pane?
cursChr		char		The cursor character
brL		integer		Length (in lines) of list pane
brOs		integer		Items above list pane
c		integer		Position of current item in list
p		integer		Position of previous item in list
msg		string		The prompt message
listL		integer		Number of items in List
list		list		The list being browsed
scrB		sring		22 character image of the scroll bar
thumb		string		The text image for the thumb
j		integer		Loop increment value (-1 or 1)


BROWSER DOWNLOADABLE LISTING

Checksum: #3e2h
Size: 1751
------------------------------------------------------------
%%HP: T(3)A(D)F(.);
\<< "v1.1" DROP DUP
  IF DTAG TYPE 6 ==
  THEN EVAL
  END DUP SIZE DUP
5 MIN DUP2 158 CHR
\-> l b t
  \<< "" 1 b l / 22 *
0 RND
    FOR i t +
    NEXT
  \>>
"\<---------------------\->"
6 ROLL DUP
  IF DTAG TYPE 5 ==
  THEN LIST\-> DROP
  ELSE 1 0
    \<<
    \>>
  END 3 PICK
  \<< 220 .125 BEEP
  \>> 134 CHR 1 1 1
CLLCD \-> list listL
brL thumb scrB msg
c brOs fmtP p eBeep
cursChr full
continue j
  \<< msg 1 DISP
    WHILE continue
1 ==
    REPEAT 1 DUP
'j' STO brL
      CASE c brOs \<=
        THEN c 1 -
'brOs' STO 1 'full'
STO
        END c brOs
brL + >
        THEN DROP2
c brL - 'brOs' STO
1 'full' STO brL 1
-1 'j' STO
        END
      END
      IF full 1 ==
      THEN 0 'full'
STO
        FOR i
          IF i c
brOs - \=/
          THEN " "
list brOs i + GET
fmtP EVAL \->STR + i
1 + DISP
          ELSE
cursChr list brOs i
+ GET fmtP EVAL
\->STR + i 1 + DISP
          END j
        STEP c 'p'
STO scrB brOs listL
/ 22 * .5 + 0 RND
thumb REPL 7 DISP
      ELSE DROP2
" " list p GET fmtP
EVAL \->STR + p brOs
- 1 + DISP cursChr
list c GET fmtP
EVAL \->STR + c brOs
- 1 + DISP
      END 3 FREEZE
0 WAIT \-> k
      \<<
        IF k FP .3
>
        THEN k .3 -
'k' STO
        END
        CASE k IP
DUP 35 == SWAP 36
== OR
          THEN
            IF c
listL ==
            THEN
eBeep EVAL
            ELSE
listL c DUP DUP 'p'
STO brL + listL MIN
SWAP 1 + k FP 10 *
ROLL 'c' STO DROP2
            END
          END k IP
DUP 25 == SWAP 34
== OR
          THEN
            IF c 1
==
            THEN
eBeep EVAL
            ELSE 1
c DUP DUP 'p' STO
brL - 1 MAX SWAP 1
- k FP 10 * ROLL
'c' STO DROP2
            END
          END k
51.1 ==
          THEN list
c GET c k 0
'continue' STO
          END k
55.1 ==
          THEN "" 0
DUP DUP 'continue'
STO
          END
        END
      \>>
    END { } msg + c
+ brOs + fmtP + 4
ROLLD 3 \->LIST
  \>>
\>>

From comp.sys.handhelds Fri Jun 29 11:11:43 1990
Path: fauern!sun1.ruf.uni-freiburg.de!ira.uka.de!sol.ctr.columbia.edu!cica!tut.cis.ohio-state.edu!zaphod.mps.ohio-state.edu!sdd.hp.com!hp-pcd!hpcvia!scottb
From: scottb@hpcvia.CV.HP.COM (Scott_Burke)
Newsgroups: comp.sys.handhelds
Subject: Re: HP-48SX MENUS and WAIT
Message-ID: <31210036@hpcvia.CV.HP.COM>
Date: 28 Jun 90 22:19:55 GMT
References: <2024@uc.msc.umn.edu>
Organization: Hewlett-Packard Co., Corvallis, Oregon
Lines: 50
Status: O

Okay, here is a test-menu program that displays what I mentioned in a
previous note.

It is a polite program, in that it preserves user flags and the last
menu displayed before it was executed; these are standard techniques
if you don't want to muck up the user's settings every time he/she
uses your code.  You can take it a step further and preserve the stack,
but since this code doesn't really do too much on the stack, I haven't
worried about it.

The program displays a message and a menu, and then waits for one key-
press.  It returns which key was pressed, in the form rc.p, where r is
row, c is column, and p is plane (1 - not shifted, 2 - left-shifted, 
etc.)  It traps the ATTN key, and returns 91.1 for that key.

The listing is just typed in, and is not downloadable.

<<
  RCLF RCLMENU -> lastflags lastmenu	@ save flags and menu
  <<
    -55 SF				@ no LASTARGS; see note 1
    { "A" "B" "C" "D" "E" "F" } TMENU	@ build temp menu list

    CLLCD				@ clear screen
    "TEST-MENU PROGRAM" 3 DISP		@ display program msg.

    ERR0				@ clear ERRN,ERRM; note 2
    IFERR
      -1 WAIT				@ get keypress, show menu
    THEN
      IF ERRN # 0d ==			@ if it was an ATTN press,
      THEN 91.1				@ return the key location
      ELSE ERRN DOERR			@ else propagate the error
      END
    END

    lastmenu MENU lastflags STOF	@ restore flags and menu
  >>
>>

note 1:  -1 WAIT leaves -1 on the stack if LASTARGS (flag -55) is clear
         default is clear, because LASTARGS can be useful; however, it
         is a pain in this situation, because you would have to check 
         if ERRN==0 and then DROP the -1.

note 2:  ERRN and ERRM contain the last error number and message, but
         if the error/abort signal is an ATTN press, it does NOT change
         ERRN and ERRM, but leaves them set to whatever the last error
         was.  Therefore, if you clear them, you know you got an ATTN
         if ERRN is #0d.

From comp.sys.handhelds Mon Jul  2 10:17:45 1990
Path: fauern!unido!mcsun!uunet!decwrl!bacchus.pa.dec.com!shlump.nac.dec.com!deland.enet.dec.com!edp
From: edp@deland.enet.dec.com (Eric Postpischil (Always mount a scratch monkey.))
Newsgroups: comp.sys.handhelds
Subject: Re: HP48 thinks -3 in binary is zero!
Message-ID: <12994@shlump.nac.dec.com>
Date: 1 Jul 90 15:41:06 GMT
References: <576@cbnewsb.ATT.COM>
Sender: newsdaemon@shlump.nac.dec.com
Reply-To: edp@deland.enet.dec.com (Eric Postpischil (Always mount a scratch monkey.))
Organization: Digital Equipment Corporation
Lines: 191
Status: O


> I was shocked to discover that adding #5h and -3 yields #5h!

> Upon further inquiry, it turns out that << -3 R->B >>  produces #0h.

> I can't think of any justification for this.  It is also a royal
> pain to get around it.  I can't simply convert the binary to a real
> number before doing the arithmetic, because it is a huge number
> (related to the number of clock ticks since the year zero, just like the
> output of TICKS....) and precision would be lost.  I guess my best
> bet is to use << +/- STO- >> if the argument is negative.  Sigh.

Since your adjustment is small even though OFFSET is large, you can
convert the adjustment to binary prior to doing the arithmetic.  Use <<
MA + R->B MA - 'OFFSET' STO+ >> where MA is the maximum adjustment you
might supply (or the largest integer you can specify without losing
precision, 10E10).

You can also use the timekeeping routines below.


				-- edp


Here's a set of timekeeping routines that compensate for inaccuracy in the
48's clock.  (They could also be used to keep sidereal time.)

In a list called CLKDAT (clock data), there are, in order:

	o The value of TICKS at the start of some reference period.

	o The cumulative number of ticks added to the clock since then.

	o The difference between true time and clock time as a fraction
	  of the number of elapsed clock ticks (called "accuracy factor").

The following routines are provided:

KICK	Called with no arguments to update the clock by the correct
	number of ticks.

ADJT	Called with a unit object specifying an amount of time by which
	to change the time zone or system.  E.g., call ADJT with -1_h
	on the stack to change from Daylight Savings to Standard Time.

ADJC	Called to adjust the clock by a specified number of ticks.  Once
	the clock is set exactly with ADJC, EXACT should be called or the
	data will be lost when KICK is next called.

EXACT	Uses the cumulative number of ticks added to the clock, by KICK
	and by ADJC, to compute a new accuracy factor.

SCHEDULE
	Schedules an alarm at 4 a.m. to call KICK daily.

CANCEL
	Cancels the alarm.

RESET	Set a new reference time and discard cumulative ticks added.
	Keep the old accuracy factor until a new one is computed.

To use these timekeeping routines:

	o Set the time with the built-in functions.
	o Make the clock as exact as desired with CLKADJ.
	o Execute RESET (no arguments).
	o After using RESET, do not use the built-in time adjustment commands.
	o Let time pass.
	o Make the clock as exact as desired with ADJC.  (ADJC takes as an
	  argument a number of ticks, just as CLKADJ does.)
	o Execute EXACT.
	o Execute SCHEDULE.

Every night at 4 a.m., KICK will update the clock.

After the initial setting, you can update the accuracy factor by again
adjusting the clock with ADJC and executing EXACT.  If your calculator's
environment changes, you can establish a new reference time by making the clock
exact and executing RESET.  This keeps the current accuracy factor but resets
the reference time, so the next execution of EXACT will base the new accuracy
factor on the time elapsed since RESET.

To change time zones or systems, use ADJT.

o If you call ADJC by accident, call KICK to correct it.
o If you call ADJT by accident, call it again with the negation of the
argument.
o If you call EXACT by accident, you are out of luck unless you have another
  copy of your accuracy factor.  If so, replace it in CLKDAT.

KICK makes the clock correct by computing the number of ticks to add to the
clock to make it correct now:

    (accuracy factor)*(TICKS - reference time - added ticks) - added ticks

Because this calculation is used rather than simply adding a fixed number
of ticks at regular intervals, KICK can be called at any time, at frequent
or infrequent intervals.  Updating the clock daily keeps it close to the
correct time.  You can change the time of the alarm and the repeat interval
in the SCHEDULE routine.  (Be sure not to set a time that is skipped over.
E.g., if you set the KICK alarm for 3 a.m. and also have an alarm that adds
1 hour to the clock at 2 a.m. for the change to Daylight Savings Time, then
the clock will go from slightly after 2 a.m. to slightly after 3 a.m., and
the KICK alarm will not be executed or scheduled for the next day.)

SCHEDULE uses AO (alarm object) as the object for the alarm to execute.  This
object discards its argument, gets the current path, executes an object called
JOB, restores the current path, and turns the calculator off.  If an error
occurs, the error message is left in the stack before shutting the calculator
off.  If a variable called JOB does not exist when SCHEDULE is executed, it is
created as a list specifying the current directory and the KICK program.  If
you would like to add additional routines to be executed, add them to the list
in JOB.  JOB is created in the home directory but can be moved to any port.  If
you need to make more complicated changes, like removing the call to OFF,
execute CANCEL, change the AO variable, and call SCHEDULE.

KICK can be modified to adjust the clock so that it will be correct at some
time in the future.  E.g., you could arrange it so that KICK runs at 4 a.m.
and adds the number of ticks needed to make the clock correct at 4 p.m.  By
doing this, the clock is early part of the day and late part of the day,
instead of only early or only late.  This cuts in half the frequency with
which KICK must be executed to keep the clock within a specified distance
of the correct time.

To make this modification to KICK, add the number of ticks to the number
in stack level one just after the call to PA.  For example, to adjust KICK
to prepare the clock to be correct in 12 hours, put

	353894400 +

after the call to PA in KICK.

Here are the variables needed.  I keep them in a directory called TIMEKEEP,
but you can place them anywhere without needing any changes.  I have typed
these in by hand but used the indicated type-2 translation codes.  Since I
did them by hand, I did them individually so errors can be tracked down.

CDP	@ Clock Data Put	CRC #AF13h 52.5 @
%%HP: T(2);
\<< \-> V L \<< 'CLKDAT' L V PUT \>> \>>

CDG	@ Clock Data Get	CRC #4B28h 29.5 @
%%HP: T(2);
\<< 'CLKDAT' SWAP GET \>>

PA	@ PreAmble		CRC #D892h 56 @
%%HP: T(2);
\<< RCLF 64 STWS 2 CDG TICKS 1 CDG - OVER - B\->R \>>

AO	@ Alarm Object		CRC #3405h 51 @
%%HP: T(2);
\<< IFERR DROP PATH :&: JOB RCL EVAL EVAL THEN ERRM END OFF \>>

RESET	@ Reset Reference Time	CRC #4B82h 33 @
%%HP: T(2);
\<< TICKS 1 CDP 0 2 CDP \>>

CLKDAT	@ Clock Data		CRC #57E6h 23 @
%%HP: T(2);
{ #0 0 0 }

CANCEL	@ Cancel Alarm		CRC #CE1h 141.5 @
%%HP: T(2);
\<< RCLF -55 SF IERR 1 \-> I \<< WHILE I RCLALARM IF 3 GET 'AO'
RCL SAME THEN I DELALARM 1 ELSE 'I' INCR END REPEAT END \>> THEN
END STOF \>>

SCHEDULE	@ Schedule Alarm	CRC #D5E2h 132.5 @
%%HP: T(2);
\<< CANCEL PATH HOME IF :&: JOB VTYPE 0 < THEN DUP 'KICK' +
:&: JOB STO END EVAL DATE 1 DATE+ 4 'AO' RCL 707788800 4 \->LIST
STOALARM DROP \>>

EXACT	@ Compute Accuracy Factor	CRC #F256h 29.5 @
%%HP: T(2);
\<< PA / 3 CDP STOF \>>

ADJC	@ Adjust Clock			CRC #2BEFh 35.5 @
%%HP: T(2);
\<< DUP 2 CDG + 2 CDP CLKADJ \>>

ADJT	@ Adjust Time			CRC #BF52h 69.5 @
%%HP: T(2);
\<< 1_s CONVERT UVAL 8192 * DUP 1 CDG + 1 CDP CLKADJ \>>

KICK	@ Kick Clock			CRC #D931h 47 @
%%HP: T(2);
\<< PA 3 CDG * 0 RND SWAP - ADJC STOF >>


				-- edp                 

From comp.sys.handhelds Tue Jul  3 10:21:26 1990
Path: fauern!unido!mcsun!uunet!cs.utexas.edu!uwm.edu!ux1.cso.uiuc.edu!iuvax!noose.ecn.purdue.edu!en.ecn.purdue.edu!ryoder
From: ryoder@ecn.purdue.edu (Robert W Yoder)
Newsgroups: comp.sys.handhelds
Subject: Routh-Hurwitz
Keywords: Routh-Hurwitz
Message-ID: <1990Jul2.163652.4190@ecn.purdue.edu>
Date: 2 Jul 90 16:36:52 GMT
Organization: Purdue University Engineering Computer Network
Lines: 245
Status: O

The following is the response I received from Paul Dujmich after I sent him a
Routh-Hurwitz program I had written.  I had never posted it because I had not
gotten around to adding the necessary code to cover the special cases.  He
expanded it to cover those cases, so here it is.

Robert Yoder
ryoder@ecn.purdue.edu

--------------------------------------------------------------------------------
Bob

I took the liberty of modifying your basic Routh program for the purpose of
adding special case checking. Most of the special case code is in a separate
subroutine I call "ARYCHK". It was just easier to do it this way.
The new code checks for left-most column zero, as well as zeroes all the
way across a row (premature termination). I believe these two are the
only special cases to worry about. I have tested the new version on my
homework problems, which I had worked out by hand. They included all the
special case conditions mentioned above. The program produced accurate
results for every polynomial that was tried.
One note is in order.
For left-most zero, we use the epsilon method, replacing the 0 with epsilon,
a very small number approaching zero.Then we take the limit of the term,
as epsilon approaches 0. In the program, I use  +/- 1E-50 to represent
epsilon. This works fine, but produces slightly different numbers in the
finished array (compared to the limit method). But, we really don't care
about the actual values anyway, all we care about is the sign changes, and
the program has been correct in every case tested. For zeroes all the way
across a row, I do the accepted method of forming a new Aux polynomial
from the coefficients in the row just above the row of zeroes. Then I take
the derivative of the Aux polynomial, and use the new coefficients to
replace the row of zeroes. This has also worked flawlessly for every thing
that was tried.

Please feel free to post this version on net.handhelds if you want. I'm sure
there are other EE/BSET people who would like to have it. Thanks again for
your reply to my posting, and for your original program. It sure was a lot
easier not having to start from scratch. Well anyway, here's the updated
version.


Thanks Again

Paul
pauld@fs1.ece.cmu.edu

============================================================================
%%HP: T(3)A(R)F(.);
@ PROGRAM NAME:  ROUTH
@ DATE:          6-30-90
@ PURPOSE:       Does Routh-Hurwitz Stability Testing
@ ARGUMENTS:     1. An array in level 2 containing coefficients of the
@                   characteristic polynomial from the transfer function.
@                2. The ORDER of the characteristic polynomial in level 1
@ NOTE: This program requires "ARYCHK", a subroutine that checks for special
@       cases, to operate.


@Routh-Hurwitz  Program
@This program tests the characteristic polynomial of a transfer function
@for stability. The program expects an array as input, which is made up of
@the coefficients of the characteristic polynomial. The array must be in stack
@level 2 when the program is executed. The program also expects the ORDER of
@the characteristic polynomial in level 1.
@The program outputs a Routh-Hurwitz array as it's output.
@The stability of the system being tested can be obtained
@by examining the left-most column of the output array. If all elements in the
@left-most column of the array are of the same sign, the system is STABLE, and
@all of the polynomial roots are in the left-half plane of the complex plane.
@If there are any sign changes within these elements, then the system is
@UNSTABLE, and the polynomial has roots in the RIGHT HALF PLANE of the complex
@plane, or
@it has roots on the IMAGINARY AXIS of the complex plane. The NUMBER of sign
@changes within the left-most array elements give the number of roots in the
@right half plane. The program tests each input array for the following
@SPECIAL CASES, and applies a fix, so that the array may be completed:
@            Special Case 1. Zero in left-most array element
@            Special Case 2. Zeroes all the way across a row


\-> ord             @load in polynomial ORDER

\<< DUP             @make copy of input array on stack
    SIZE            @return dimensions of input array {2 2} on stack
    LIST\->         @dump the array dimensions from list to stack
                    @ 2   (rows)
                    @ 2   (columns)
                    @ 2   (there were 2 elements in the list)
    DROP            @throw away the #elements in list, don't need it
    'cols' STO      @save # columns of input array
    DROP            @drop off # columns from stack
    cols 3 *        @new # of rows = 3* original # columns
    cols            @orig number of columns
    2 \->LIST       @put last 2 elements in a list
    RDM             @redimension input array to size specified by list
    'a' STO         @save the redimensioned array
    3 'r' STO       @start calculating at row 3
    1 CF            @clear flag 1 in case it is set

@**************** calculate # of coefficients in orig array  *************

ord 1 +             @increment polynomial order to get # coefficients
'coef' STO          @save it

@************** Check row 2 of input array for special cases ***************

CLEAR                 @clear stack
3 'r' STO
ARYCHK                @check row 2 of the input array for special cases
                      @if they exist-fix them.

@********************** main DO LOOP ****************************************
3 'r' STO           @start calculating at row 3
  DO
     1 cols 1 -     @set up FOR loop for 1 less than number of columns
     FOR c
         a          @put array on stack
         r          @put current row on stack
         c          @put current column within current row on stack
         2 \->LIST  @make a list of last 2

         @************* array element calculation ************************
         '(a(r-1,1)*a(r-2,c+1)-a(r-2,1)*a(r-1,c+1))/a(r-1,1)'
         EVAL
         PUT        @put the calculated element back into the array
         'a' STO    @save the updated array
     NEXT
     1 'r' STO+     @increment to next row
     ARYCHK         @check for special cases
UNTIL 1 FS?         @run DO loop until flag 1 is set
END
a                   @ put array on stack
r 1 - cols 2 \->LIST
RDM                 @ redimension the array
{ a cols r s cnt coef hc pwr}  @list of variables to nuke
PURGE               @nuke them
1 CF                @clear flag 1
\>>
=============================================================================
%%HP: T(3)A(R)F(.);
@ PROGRAM NAME:  ARYCHK  (subroutine for Routh-Hurwitz Program)
@ DATE:          6-30-90
@ PURPOSE:       checks a row of a Routh-Hurwitz array for special cases
@ARGUMENTS:      Variable 'r' must exist and contain the row of the Routh-
                 @Hurwitz array (+1) to be checked.

\<<
     IF 'a(r-1,1)==0'                     @if leftmost element of last row == 0
               THEN
                   IF 'r-1 > coef'        @normal valid array termination
                           THEN 1 SF          @set the flag

                          @special case checking
                            ELSE 0 'cnt' STO        @clear cnt
                            1 cols                  @FOR loop goes from 1 to
                                                    @ # columns
                            FOR c
                                'a(r-1,c)' EVAL     @count # valid array
                                                    @elements in row where 0
                                                    @occurred
                                0 \=/               @element !=0?
                                'cnt' STO+          @if yes, then valid
                            NEXT
                            IF 'cnt==0'             @the whole row had 0's

                               @premature termination of array (all 0's in row)
                                  THEN
                                     coef r 2 -  -  @calculate first power of
                                                    @S for new polynomial
                                     'pwr' STO      @save it
                                     1 cols         @FOR loop goes from 1 to
                                                    @width of a column
                                     FOR c
                                         'a(r-2,c)'
                                         EVAL       @get term coefficient
                                         "*S^"
                                         +          @add it to string
                                         pwr        @get the exponent
                                         +          @add it to string
                                         "'"
                                         SWAP
                                         +          @make algebraic object
                                                    @ inside a string
                                         OBJ\->     @remove string quotes
                                                    @object is now algebraic
                                         1 'S' STO
                                         'S'        @variable of differentiation
                                         \.d        @take the derivative
                                         EVAL       @evaluate at S = 1
                                         a SWAP     @put array on stack
                                         r 1 - c 2 \->LIST @elem to change
                                         SWAP
                                         PUT        @correct the element
                                         'a' STO    @save updated array
                                         pwr 2 -    @decrement exponent by 2
                                         'pwr' STO  @save new power
                                         IF pwr 0 < @if exponent < 0 then
                                                    @terminate the FOR loop
                                            THEN cols 1 +
                                                 'c' STO
                                         END
                                     NEXT
                                     'S' PURGE      @ done with S for now

                              @zero in left-most column only
                                ELSE 0 'cnt' STO    @clear cnt
                                     1 coef         @FOR loop goes from 1 to
                                                    @ # of coefficients
                                     FOR c
                                          'a(c,1)'   @count the number of left
                                          EVAL       @most elements that are
                                          0 <        @negative
                                          'cnt' STO+ @cnt has total
                                     NEXT
                                     coef 2 /        @find half #coefficients
                                     IP              @only the integer part
                                     'hc' STO        @save it in hc
                                     IF 'cnt > hc'   @more than 1/2 the
                                                     @coefficients are negative
                                       THEN  a       @get array
                                             r 1 - 1 2
                                             \->LIST    @array element to change
                                             -1.E-50    @make it neg
                                             PUT        @put in array
                                             'a' STO    @save changed array
                                       ELSE  a          @get array
                                             r 1 - 1 2  @select element
                                             \->LIST
                                             1.E-50   @make it pos
                                             PUT      @put in array
                                             'a' STO  @save changed array
                                     END

                            END
                   END

     END
   \>>
==============================================================================

-- 
--------------------------------------------------------------------------------
Robert Yoder

Internet: ryoder@ecn.purdue.edu

