english
version "1.0"
identify "wxyz"

#: Copyright (c) 1995, 2002 by Wayne C. Gramlich.
#, All rights reserved.
#,
#, Permission to use, copy, modify, distribute, and sell this software
#, for any purpose is hereby granted without fee provided that the above
#, copyright notice and this permission are retained.  The author makes
#, no representations about the suitability of this software for any purpose.
#, It is provided "as is" without express or implied warranty.

module chunk

#: This module implements the {chunk} and {chunks} types for SVMS history
#, files.

define chunk_type			#: {chunk} representation
    enumeration
	binary				#: Raw binary bytes
	error				#: Unknown type (error)
	line				#: Characters followed by new-line
	range				#: A bunch of {chunk} ranges
    generate equal, hash, print, unsigned_convert

#: An allocated {chunk} is always a member of exactly one {version}.{chunks}
#, list.  A {chunk} chunk can be moved from one {version}.{chunks} list
#, to another one, but care must be taken to ensure that the previous
#, one is deleted.
define chunk				#: Bytes of data in file
    record
	data string			#: String of data
	data_hash unsigned		#: Hash for chunk
	offset unsigned			#: Offset into {version}.{chunks}
	resources resources		#: Parent {resources} object
	sort_key unsigned		#: Key used for sorting {chunk}'s
	type chunk_type			#: {line} or {binary} or {range}
	version version			#: Version that {chunk} is part of
    generate address_get, allocate, erase, identical, print		

define chunk_range			#: List of chunk names
    record
	count unsigned			#: Number of chunks in sequence
	indirect logical		#: {true}=>keep expanding
	offset unsigned			#: First chunk in range
	resources resources		#: Parent {resources} object
	version version			#: {version} that range is part of
    generate address_get, allocate, erase, identical, print

define chunk_ranges			#: List of chunk ranges
    record
	list vector[chunk_range]	#: List of {chunk_range}
	resources resources		#: Parent {resources} object
    generate address_get, allocate, erase, identical, print

define chunks				#: List of chunks
    record
	list vector[chunk]		#: List of {chunk}
	resources resources		#: Parent {resources} object
    generate address_get, allocate, erase, identical, print



#: {chunk} procedures:

procedure xallocate@chunk
    takes
	version version
    returns chunk

    #: This procedure will allocate and return a new {chunk} object 
    #, that refers to {version}.


procedure compare@chunk
    takes
	chunk1 chunk
	chunk2 chunk
    returns integer

    #: This procedure returns -1, 0, or 1 depending upon whether the
    #, {sort_key} field in {chunk1} is less than, equal to, or greater
    #, than the {sort_key} field in {chunk2}.  Please note that this
    #, procedure only examines the {sort_key} field and nothing else;
    #, in particular, when this procedure returns a 0, it may not mean
    #, that the two chunks are equal in terms of their contents (i.e.
    #, {equal}@{chunk}() might not return {true}.)


procedure deallocate@chunk
    takes
	chunk chunk
    returns_nothing

    #: This procedure will deallocate {chunk} and make it available for
    #, subsequent reallocation.


procedure equal@chunk
    takes
	chunk1 chunk
	chunk2 chunk
    returns logical

    #: This procedure will return {true} if {chunk1} is equal to {chunk2}
    #, and {false} otherwise.


procedure hash@chunk
    takes
	chunk chunk
    returns unsigned

    #: This procedure will return a hash value for {chunk}.


procedure move@chunk
    takes
	chunk chunk
	new_version version
    returns_nothing

    #: This procedure will move {chunk} from {chunk}.{version}.{chunks}
    #, to {new_version}.{chunks}.


procedure read@chunk
    takes
	data_in_stream data_in_stream
	version version
    returns chunk

    #: This procedure will read in a {chunk} object from {data_in_stream}
    #, and return it.


procedure remove@chunk
    takes
	chunk chunk
    returns_nothing

    #: This procedure will remove {chunk} from {chunk}.{version}.{chunks}.


procedure share@chunk
    takes
	chunk chunk
	share_table set[chunk]
    returns chunk

    #: This procedure will return a {chunk} object whose contents are
    #, equal to {chunk}.  {chunk} must be part of either the comments
    #, or data of {version}.


procedure show_prefixed@chunk
    takes
	chunk chunk
	prefix string
	out_stream out_stream
    returns_nothing

    #: This procedure will output {chunk} to {out_stream} where each
    #, line is prefixed by {prefix}.


procedure write@chunk
    takes
	chunk chunk
	data_out_stream data_out_stream
	version version
    returns_nothing

    #: This procedure will write {chunk} to {data_out_stream}.  


#: {chunk_range} procedures:

procedure xallocate@chunk_range
    takes
	version version
    returns chunk_range

    #: This procedure will allocate a new {chunk_range} for {version}.


procedure chunks_append@chunk_range
    takes
	chunk_range chunk_range
	chunks chunks
    returns_nothing

    #: This procedure will append a {chunk} object to {chunks} for
    #, each appropriate {chunk} in {chunk_range}.


procedure compare@chunk_range
    takes
	chunk_range1 chunk_range
	chunk_range2 chunk_range
    returns integer

    #: This procedure will return -1, 0, or 1 depending upon whether
    #, {chunk_range1} is less than, equal to, or greater than
    #, {chunk_range2}.


procedure deallocate@chunk_range
    takes
	chunk_range chunk_range
    returns_nothing

    #: This procedure will deallocate {chunk_range} for subsequent
    #, reallocation.


procedure equal@chunk_range
    takes
	chunk_range1 chunk_range
	chunk_range2 chunk_range
    returns logical

    #: This procedure will return {true} if {chunk_range1} is equal to
    #, {chunk_range2}.


procedure greater_than@chunk_range
    takes
	chunk_range1 chunk_range
	chunk_range2 chunk_range
    returns logical

    #: This procedure will return {true} if {chunk_range1} is greater than
    #, {chunk_range2}.


procedure less_than@chunk_range
    takes
	chunk_range1 chunk_range
	chunk_range2 chunk_range
    returns logical

    #: This procedure will return {true} if {chunk_range1} is less than
    #, {chunk_range2}.


procedure read@chunk_range
    takes
	data_in_stream data_in_stream
	history history
    returns chunk_range

    #: This procedure will read in and return a {chunk_range} object from
    #, {data_in_stream} that was written by {write}@{chank_range}().
    #, {history} is used to access the version list.


procedure write@chunk_range
    takes
	chunk_range chunk_range
	data_out_stream data_out_stream
    returns_nothing

    #: This procedure will write {chunk_range} out to {data_out_stream}.


#: {chunk_ranges} procedures:

procedure xallocate@chunk_ranges
    takes
	resources resources
    returns chunk_ranges

    #: This procedure will allocate a new {chunk_ranges} object from
    #, {resources}.


procedure append@chunk_ranges
    takes
	chunk_ranges chunk_ranges
	chunk chunk
	indirect logical
    returns_nothing

    #: This procedure will append into {chunk_ranges} creating
    #, a new {chunk_range} object to contain it if needed.

    #format@format4[address, address, logical, unsigned](debug_stream,
    #  'append@chunk_ranges(%X%, %X%, %l%) size=%d% returns\n\',
    #  chunk_ranges.address, chunk.address, indirect, list.size)



procedure chunks_convert@chunk_ranges
    takes
	chunk_ranges chunk_ranges
	chunks chunks
    returns_nothing

    #: This procedure will take a {chunks_ranges} object and expand
    #, it so that referenced chunk is appended to {chunks} in the
    #, proper order.


procedure compress@chunk_ranges
    takes
	chunk_ranges chunk_ranges
	version version
	share_table set[chunk]
    returns_nothing

    #: This procedure will compress {chunk_ranges} down to a single
    #, {chunk_range} object and return it.  Any new indirect strings
    #, are added to {version}.

    #, common sequences of lines.  Unfortunately, the algorithm is
    #, a bit opaque.

    #format@format3[address, address, unsigned](debug_stream,
    #  'compress@chunk_ranges(%X%, %X%) size=%d% returns\n\',
    #  chunk_ranges.address, version.address, list.size)



procedure deallocate@chunk_ranges
    takes
	chunk_ranges chunk_ranges
    returns_nothing

    #: This procedure will deallocate {chunk_ranges} for subsequent
    #, reallocation.


procedure read@chunk_ranges
    takes
	data_in_stream data_in_stream
	history history
    returns chunk_ranges

    #: This procedure will read in a {chunk_ranges} object that was
    #, originally writen by {write}@{chunk_ranges}().  {history} is
    #, used to access the {version} table.


procedure write@chunk_ranges
    takes
	chunk_ranges chunk_ranges
	data_out_stream data_out_stream
    returns_nothing

    #: This procedure will write {chunk_ranges} to {data_out_stream}.


#: {chunks} procedures:

procedure xallocate@chunks
    takes
	resources resources
    returns chunks

    #: This procedure will allocate a new {chunks} object from {resources}.


procedure append@chunks
    takes
	chunks chunks
	chunk chunk
    returns_nothing

    #: This procedure will append {chunk} to {chunks}.


procedure binary_extract@chunks
    takes
	contents string
	version version
    returns chunks

    #: This procedure will treat {contents} as a sequence of raw bianry
    #, bytes and return a {chunks} object that contains the data.


procedure chunk_ranges_convert@chunks
    takes
	chunks chunks
	version version
	share_table set[chunk]
    returns chunk_ranges

    #: This procedure will convert {chunks} into a corresponding
    #, {chunk_ranges} object.  Any needed indirect {chunk}'s will
    #, be added to {version}.


procedure deallocate@chunks
    takes
	chunks chunks
    returns_nothing

    #: This procedure will deallocate {chunks} and make it available for
    #, subsequent reallocation.  If {chunks}.{size} is non-zero, {chunks}
    #, must be a {version}.{chunks} object.

    #format@format1[address](debug_stream,
    #  'deallocate@chunks(%X%) returns\n\', chunks.address)



procedure lines_extract@chunks
    takes
	chunks chunks
	version version
	contents string
    returns_nothing

    #: This procedure will treat {contents} as a sequence of lines and
    #, generate a sequence of shared {chunk} objects and append them to
    #, the end of {chunks}.  Any new shared {chunk} objects will be part
    #, of {version}.  {global} provides a few useful global values.


procedure fetch1@chunks
    takes
	chunks chunks
	index unsigned
    returns chunk

    #: This procedure will return the {index}'th {chunk} object in {chunks}.


procedure is_sorted@chunks
    takes
	chunks chunks
	version version
    returns logical

    #: This procedure will validate that each {chunk} that is in {version}
    #, in {chunks} is properly ordered by the {sort_key} field.  {true}
    #, is returned if everything is properly sorted and {false} otherwise.


procedure ranges_remove@chunks
    takes
	chunks chunks
	version version
    returns logical

    #: This procedure will remove any range {chunk}'s from {chunks}
    #, that are part of {version}.  {true} is removed if at least
    #, one {chunk} is removed.


procedure read@chunks
    takes
	chunks chunks
	data_in_stream data_in_stream
	version version
    returns_nothing

    #: This procedure will read in a sequence of chunks from {in_stream}


procedure show@chunks
    takes
	chunks chunks
	out_stream out_stream
    returns_nothing

    #: This procedure will output {chunks} ot {out_stream}.  Each {chunk} in
    #, {chunks} must be of type {line}.


procedure show_prefixed@chunks
    takes
	chunks chunks
	prefix string
	out_stream out_stream
    returns_nothing

    #: This procedure will output {chunks} to {out_stream} where each
    #, line is prefixed by {prefix}.


procedure share@chunks
    takes
	chunks chunks
	share_table set[chunk]
    returns_nothing

    #: This procedure will force each {chunk} in {chunks} to be sharable
    #, via {share_table}.


procedure size_get@chunks
    takes
	chunks chunks
    returns unsigned

    #: This procedure will return the size of {chunks}.


procedure sort@chunks
    takes
	chunks chunks
	version version
    returns_nothing

    #: This procedure will sort {chunks} based on the {sort_key} field
    #, in each {chunk}.  Each {chunk} in {chunks} must be a member of
    #, {version}.


procedure sort_key_bind@chunks
    takes
	chunks chunks
	start_offset unsigned
	version version
    returns unsigned

    #: This procedure will take each {chunk} in {chunks} that is a member
    #, {version} and assign its {sort_key} field a value starting at
    #, at {start_offset} and incrementing by one.  The last assigned
    #, value (plus one) is returned.  This procedure requires that
    #, {sort_key_reset}@{chunks}() be called on {chunks} beforehand.


procedure sort_key_reset@chunks
    takes
	chunks chunks
	version version
    returns_nothing

    #: This procedure will reset the {sort_key} field for each {chunk} in
    #, {chunks} that is a member of {version} to zero.


procedure store1@chunks
    takes
	chunks chunks
	index unsigned
	chunk chunk
    returns_nothing

    #: This procedure will store {chunk} into the {index}'th slot in {chunks}.


procedure string_append@chunks
    takes
	chunks chunks
	text string
    returns_nothing

    #: This procedure will take the contents of {chunks} and append them
    #, to the end of {text}.


procedure trim@chunks
    takes
	chunks chunks
	size unsigned
    returns_nothing

    #: This procedure will trim {chunks} to have a size of {size}


procedure unshare@chunks
    takes
	chunks chunks
	share_table set[chunk]
    returns_nothing

    #: This procedure will ensure that each {chunk} in {chunks} is no
    #, longer in {share_table}.


procedure verify@chunks
    takes
	chunks chunks
	version version
    returns_nothing

    #: This procedure will verify that each {chunk} in {chunks} matches
    #, {version} (if {version} is no equal to ??@{version}) and has the
    #, correct offset.  A fatal assertion error occurs if any problem is
    #, encountered.  This procedure is used for debugging.


procedure write@chunks
    takes
	chunks chunks
	data_out_stream data_out_stream
	version version
    returns_nothing

    #: This procedure will write {chunks} to {data_out_stream}.