english
version "1.0"
identify "%Z%%M% %I% %E%"

#: Copyright (c) 1993-2005 Wayne C. Gramlich.
#, All rights reserved.

module save

#: The save module provides the ability to save an object and all
#, of its children into a sharable object file.

define save_element				# One word of saved data
    variant type save_type
	characters unsigned			# Characters from a string
	object string				# An object
	read_only_address unsigned		# A read-only address
	read_write_address unsigned		# A read/write address
	routine string				# A routine
	undefined null				# Error
	unsigned unsigned			# An unsigned word
    generate allocate, erase, print
	

define save
    record
	full_name string			# Temporary string buffer
	objects vector[string]			# List of save objects
	object_table set[string]		# Set of save objects
	routines vector[string]			# List of save routines
	routine_table set[string]		# Set of save proecures
	read_only_elements vector[save_element]	# Vector of read-only elements
	read_only_table table[address, unsigned] # Read-only address table
	read_write_elements vector[save_element] # Vector of read/write elements
	read_write_table table[address, unsigned] # Read/write address table
	undefined save_element			# Unused save element
	zero address				# An address of 0
    generate address_get, allocate, erase, print

define save1[object_type]		# Helper type
    record
	zilch null			# This type is not used.
    generate allocate, erase, print



procedure characters@save
    takes
	save save
	characters unsigned
    returns save_element

    #: This procedure will return a save element containing {characters}
    #, allocated from {save}.


procedure object@save
    takes
	save save
	object_name string
	object_type string
	offset unsigned
    returns_nothing

    #: This procedure will install a reference to {object_name}@{object_type}
    #, at {offset} in {save}.


procedure read_only@save
    takes
	save save
	offset unsigned
    returns save_element

    #: This procedure will return a read/write {save_element} for the
    #, read-only elements in {save}.


procedure read_only_lookup@save
    takes
	save save
	address address
    returns unsigned

    #: This procedure will return the read-only offset associated
    #, {address} in {save}.  If there is no offset, 0 is returned.


procedure read_only_allocate@save
    takes
	save save
	address address
	amount unsigned
    returns unsigned

    #: This procedure will allocate {amount} entries for {address}
    #, in the read/only elements in {save}.  The offset of the
    #, first allocated element is returned.


procedure read_only_store@save
    takes
	save save
	index unsigned
	save_element save_element
    returns_nothing

    #: This procedure will store {save_element} into
    #, {save}.{read_only_elements} at {index}.


procedure read_write@save
    takes
	save save
	offset unsigned
    returns save_element

    #: This procedure will return a read/write {save_element} for the
    #, read/write elements in {save}.


procedure read_write_lookup@save
    takes
	save save
	address address
    returns unsigned

    #: This procedure will return the read/write offset associated
    #, {address} in {save}.  If there is no offset, 0 is returned.


procedure read_write_allocate@save
    takes
	save save
	address address
	amount unsigned
    returns unsigned

    #: This procedure will allocate {amount} words of from the
    #, read/write elements ins {save}.  If {address} is non-zero,
    #, {address} is entered into read/write table in {save}.


procedure routine@save
    takes
	save save
	routine_name string
	routine_type string
	offset unsigned
    returns_nothing

    #: This procedure will install a reference to {routine_name}@{routine_type}
    #, at {offset} in {save}.


procedure store1@save
    takes
	save save
	index unsigned
	save_element save_element
    returns_nothing

    #: This procedure will store {save_element} into
    #, {save}.{read_write_elements} at {index}.


procedure read@save1[object_type]
    takes
	directory_name string
	base_name string
	suffix string
	system system
    returns object_type

    #: This procedure will read in an object of type {object_type} from
    #, the file named {base_name} with a suffix of {suffix} from the
    #, directory named {directory_name}.  {system} is used to do file I/O.
    #, ??@{object_type} is returned if the file name can not be opened.
    

procedure read_helper@save1[object_type]
    takes
	file_name string
	symbol_name string
    returns object_type
    external save1__read_helper

    #: This is an unsafe routine that uses dlopen to slurp in the
    #, shared object file named {file_name} and returns the address
    #, of the symbol named {symbol_name}.  The user has to make sure
    #, that the types written out by {write@save1} match the type
    #, read by {read_helper@save1}.



procedure write@save1[object_type]
    takes
	directory_name string
	base_name string
	suffix string
	object object_type
	system system
    returns_nothing
    needs
	procedure save@object_type
	    takes object_type, save, unsigned
	    returns_nothing

    #: This routine will write {object} out to {file_name} as a sharable
    #, object.


procedure write_helper@save
    takes
	out_stream out_stream
	save_elements vector[save_element]
	storage_class string
	name string
    returns_nothing

    #: This procedure will write out {save_elements} to {out_stream}
    #, labeled with {storage_class} and {name}.


procedure unsigned@save
    takes
	save save
	unsigned unsigned
    returns save_element

    #: This procedure will return a save element containing {unsigned}
    #, allocated from {save}.