Newsgroups: comp.sys.hp48

[ Over a year ago, I posted a "beta" version of a backup program.  Well,
  in all that time, I never got around to releasing an official version,
  and it's about time.  As a result, here is another "beta" version,
  which will be submitted to comp.sources.hp48 in a couple of weeks or
  so.  If you have any comments, please send them now!  ]

     Here is a program to backup the ENTIRE contents (libs and all) of
an HP 48SX.  It's not perfect, it's huge (about 2900 bytes), and it's
probably inefficient.  However, it should work.

     The big advantage of these functions, over previously-released
ones, is that you only need as much memory as the largest library/port
variable to do a backup, as the libraries/port variables are saved in
separate files and not as a concatenated list in main memory.

     Note that, while these functions are easy to use, they do not work
like other backup programs.  Please read these instructions carefully
and completely.

     The code at the end of this message contains two functions: BACKUP
and RECOVER.  In order to use these functions, you need to backup to a
kermit *SERVER*; you must place the destination machine in kermit SERVER
mode to use these routines.  If you do not have a kermit that supports
SERVER mode, you CANNOT use these routines.  You must also use binary
transfer mode; if you accidentally use ASCII mode, the transfer will
take hours.  Also, the clock display must be turned off, due to the
archive bug; if the display is turned on, the clock will be turned off,
and you will be asked to redo the operation.

     You press BACKUP to archive the contents of your HP-48SX.  BACKUP
first sends all port variables/libraries to the kermit server, one by
one (it first checks to see if you have enough memory, though), and then
does an archive of main memory.  Port variables and libraries are stored
in files named like:

	Lpnnn

Where "p" is the port number (0..2), and "nnn" is a number from 1 to
however many variables are in the port.  After all port variables and
libraries have been backed up (but before the archive of main memory is
done), a file called "lfiles" is created; this file contains a
description of what port variable/library is stored in each of the
"Lpnnn" files, for example:

%%HP: T(3)A(D)F(.);
"
L01: Prt 0: Library 768:  SW-A
L02: Prt 0: Library 1644:  SWING by LennartB
L03: Prt 0: Library 968:  [Ant]: v1.0
"

(This file is basically a backup object of a string containing the
information.)  Note that, as this transfer is done in ASCII mode (all
other transfers are done in binary mode), each line is terminated by a
CRLF sequence.  Users of MSD*S systems will not notice a thing, but
users of systems like Un*x will notice a ^M at the end of each line.

     As each port object is sent to the server, a note of its type
(variable vs library) is made and is saved away (this is used to restore
the backup).  After all port objects have been saved, the flags are
saved in a variable, and an ARCHIVE is done (the ARCHIVE file name is
hard-coded to "BACKUP").  The HP-48SX will also terminate the kermit
server at the end of the backup.

     Filename collisions are a problem here.  I strongly suggest
starting the kermit server in an empty directory before starting the
backup.


     Here's a summary of the backup process:

1. Make sure the HP-48SX is using wire transfer.

2. Place kermit into SERVER mode.  ALSO, MAKE SURE THAT THE SERVER IS IN
   BINARY MODE (for those systems that make a distinction between text
   and binary modes).  If you do not, the backup will appear to work,
   but YOU WILL NOT BE ABLE TO RESTORE.  Note that you have to worry
   about binary/ascii transfer modes at BOTH ends of a kermit
   connection; while this program automatically places the HP 48SX into
   binary mode for transfers, the other end must be manually placed into
   binary mode.

3. Press BACKUP.  Have a cup of coffee while you wait.  If the suppress
   error beep flag (-56) is not set, the calculator will beep when the
   full backup is complete.


     To restore the contents of your HP-48SX, you do the following:

1. Go to the directory containing the backup files.

2. Using kermit, manually transfer the "backup" archive back to the
   HP-48SX, and RESTORE it.

3. Put kermit into server mode.

4. Go to the HP-48SX directory that contains the BACKUP and RECOVER
   functions.

5. Press RECOVER.  The calculator will transfer the rest of the files
   and place the objects into the correct ports.  That's it.


***** Known problems:

* This program backs up EVERYTHING in RAM (of course, it doesn't touch
  ROM).  It backs up *ALL* libraries, backup objects, other variables,
  etc..  You cannot tell it to not backup something, other than purging
  the object, or pulling the RAM card out of the calculator.

* This program is huge, due partly to the extensive checks that makes
  sure that enough memory is present before doing the BACKUP/RECOVER.
  Perhaps these checks should be deleted (but I like having
  user-friendly programs ...)?

* No kermit error checking is done.

* Currently, some of the constants used to estimate the minimum amount
  of RAM needed are stored in variables ("M" and "S").  Perhaps these
  should be hard-coded?

     Extract the program at the end of this message into a file called
"backup", and upload it to your HP-48SX.

     -- Darryl Okahata
	Internet: darrylo@sr.hp.com

DISCLAIMER: this message is the author's personal opinion and does not
constitute the support, opinion or policy of Hewlett-Packard or of the
little green men that have been following him all day.

===============================================================================
%%HP: T(3)A(R)F(.);
DIR
  BACKUP
    \<< DEPTH \-> d
      \<<
        IF -40 FS?
        THEN -40 CF
"Clock display disabled
Retry operation"
DOERR
        END
        IFERR PATH
'$BACKUP' DUP VTYPE
\-> p b v
          \<<
            CASE v
15 ==
              THEN
              END b
" -- Can't find
directory"
+ DOERR
            END b
EVAL p 'OPATH' STO
          \>> CLLCD
"CHECKING MEM REQ."
4 DISP MEMCHK
'NEEDED' STO RCLF
'FLAGS' STO { } DUP
DUP 'PV2' STO 'PV1'
STO 'PV0' STO -35
SF OPENIO 0 2
          FOR p p
            IFERR
PVARS
            THEN
DROP { } ""
            END
            IF TYPE
0 ==
            THEN
OBJ\->
              IF
DUP 0 >
              THEN
1 SWAP
FOR i CLLCD "Port "
p + C$ 3 : " + OVER
+ C$ 1 " + 4 DISP
  IF DUP OBJ\-> DROP
TYPE 0 \=/
  THEN DUP \->STR
  ELSE DUP OBJ\->
DROP
  END p PVNAME STO+
RCL p i FNAME SWAP
OVER STO DUP SEND
CLLCD "Wait ..." 4
DISP
  IF DUP VTYPE 15
==
  THEN PGDIR
  ELSE PURGE
  END
NEXT
              ELSE
DROP
              END
            ELSE
DROP
            END
          NEXT
CLLCD
"Writing file list ..."
4 DISP -35 CF NLIST
:IO: LFILES DUP ROT
SWAP STO DUP SEND
PURGE CLLCD
"Archiving main mem ..."
4 DISP
":IO: BACKUP" OBJ\->
ARCHIVE FINISH DONE
        THEN
          IF ERRN 1
\=/
          THEN
CLLCD
"ABORTING ..." 4
DISP d CLEANUP
          END ERRN
DOERR
        END
      \>>
    \>>
  RECOVER
    \<< DEPTH \-> d
      \<<
        IF -40 FS?
        THEN -40 CF
"Clock display disabled
Retry operation"
DOERR
        END
        IFERR PATH
'$BACKUP' DUP VTYPE
\-> p b v
          \<<
            CASE v
15 ==
              THEN
              END b
" -- Can't find
directory"
+ DOERR
            END b
EVAL p 'OPATH' STO
          \>>
          IF NEEDED
M + MEM >
          THEN
OPATH EVAL 1 DOERR
          END -35
SF OPENIO 0 2
          FOR p p
PVNAME RCL OBJ\->
            IF DUP
1 \>=
            THEN 1
SWAP
              FOR i
CLLCD \-> n
\<< p i FNAME DUP
KGET DUP RCL DUP
  IF n TYPE 0 ==
  THEN 0 p \->TAG STO
  ELSE n OBJ\-> STO
  END CLLCD
"Wait ..." 4 DISP
  IF TYPE 15 ==
  THEN PGDIR
  ELSE PURGE
  END
\>>
              NEXT
            ELSE
DROP
            END
          NEXT
FLAGS STOF FINISH
DONE
        THEN
          IF ERRN 1
\=/
          THEN
CLLCD
"ABORTING ..." 4
DISP d CLEANUP
          END ERRN
DOERR
        END
      \>>
    \>>
  $BACKUP
    DIR
      PV0 { 968
1644 768 }
      PV1 { }
      PV2 { }
      FLAGS {
# 90400000FF0h # 0h
}
      NEEDED
11139.5
      MEMCHK
        \<< 0 0 \-> sz
n
          \<< 0 2
            FOR p p
              IFERR
PVARS
              THEN
DROP { } ""
              END
              IF
TYPE 0 ==
              THEN
OBJ\->
IF DUP 0 >
THEN DUP 'n' STO+ 1
SWAP
  START RCL BYTES
SWAP DROP
    IF DUP sz >
    THEN 'sz' STO
    ELSE DROP
    END
  NEXT
ELSE DROP
END
              ELSE
DROP
              END
            NEXT
            IF sz
DUP M + n S * + MEM
> n 35 * MEM > OR
            THEN
DROP p EVAL 1 DOERR
            END
          \>>
        \>>
      M 300
      S 10
      PVNAME
        \<< "'PV"
SWAP + "'" + OBJ\->
        \>>
      FNAME
        \<< "'L" ROT
+ SWAP + "'" + OBJ\->
        \>>
      CLEANUP
        \<< \-> d
          \<<
            IFERR
'$BACKUP'
              IF
DUP VTYPE 15 ==
              THEN
EVAL VARS OBJ\-> 1
SWAP
FOR i
  IF DUP \->STR 2 2
SUB NUM 76 ==
  THEN PURGE
  ELSE DROP
  END
NEXT
              END
DEPTH d - DROPN
EXIT
            THEN d
CLEANUP
            END
          \>>
        \>>
      DONE
        \<< CLLCD
"DONE" 1 DISP 1
FREEZE EXIT
        \>>
      EXIT
        \<<
          IF -56
FC?
          THEN 1400
.1 BEEP
          END
CLOSEIO FLAGS STOF
-40 CF OPATH
'OPATH' PURGE EVAL
        \>>
      NLIST
        \<< "
" \-> r
          \<< 0 2
            FOR p p
PVNAME RCL OBJ\->
              IF
DUP 0 >
              THEN
1 SWAP
FOR i r p i FNAME
\->STR DUP SIZE 1 - 2
SWAP SUB + ": Prt "
+ p + ": " +
  IF SWAP DUP TYPE
0 ==
  THEN p \->TAG RCL
  ELSE SWAP "Var "
+ SWAP
  END + "
" + 'r'
STO
NEXT
              ELSE
DROP
              END
            NEXT r
          \>>
        \>>
    END
END