english version "1.0" identify "xyz" #: 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 version #: This module implements the {version} type for SVMS history files. import address character chunk data_io history file_name file_system format in_stream integer misc logical out_stream project resources set string svms system time timer unsigned vector define version #: One version in history file record chunks chunks #: Mixed file and comment chunks comments chunks #: Comments value contents chunks #: File contents creator_name string #: Creator's name executable logical #: {true}=>executable history history #: Parent history object is_binary logical #: {true}=>binary;{false}=>text max_number unsigned #: Highest delta version number min_number unsigned #: Lowest delta version number offset unsigned #: Offset number resources resources #: Parent resources object timestamp unsigned #: Version timestamp generate address_get, allocate, erase, identical, print #: {version} procedures: procedure xallocate@version takes history history returns version #: This procedure will allocate and return a {version} object #, that is part of {history}. assert history !== ?? resources :@= history.resources assert resources !== ?? project_file :@= history.project_file assert project_file !== ?? project :@= project_file.project assert project !== ?? version :@= version_allocate@(resources) #debug_stream :@= resources.global.debug_stream #format@format1[address](debug_stream, # 'allocate@version(%X%)\n\', history.address) chunks :@= version.chunks comments :@= version.comments contents :@= version.contents erase@(version) if chunks == ?? chunks := xallocate@chunks(resources) if comments == ?? comments := xallocate@chunks(resources) if contents == ?? contents := xallocate@chunks(resources) trim@(chunks, 0) trim@(comments, 0) trim@(contents, 0) version.chunks := chunks version.comments := comments version.contents := contents version.history := history version.resources := resources version.min_number := 0xffffffff # Large number version.max_number := 0 #format@format1[address](debug_stream, # 'allocate@version(%X%) returns\n\', history.address) return version procedure compare@version takes version1 version version2 version returns integer #: This procedure will return -1, 0, 1 depending upon whether #, {version1} has a name that is less than, equal to, or greater #, than the name of {version2} respectively. assert version1 !== ?? assert version2 !== ?? result :@= compare@(version1.timestamp, version2.timestamp) zero :@= integer_convert@(0) if result = zero # The minimum/maximum delta number for the version is used as #, a "tie-breaker" for sorting. result :@= compare@(version1.min_number, version2.min_number) if result = zero result :@= compare@(version1.max_number, version2.max_number) if result != zero && version1 != version2 # This is strange and we should figure out how we got here. assert false #debug_stream :@= version1.resources.global.debug_stream #format@format7[address, unsigned, unsigned, address, unsigned, unsigned, # integer](debug_stream, # 'compare@version(%X%:%d%:%d%, %X%:%d%:%d%) => %d%\n\', # version1.address, version1.timestamp, version1.number, # version2.address, version2.timestamp, version2.number, result) return result procedure deallocate@version takes version version returns_nothing #: This procedure will deallocate {version} and make it available for #, for subsequent reallocation. # Trim the {contents} and {comments} first, otherwise duplicate #, deallocation will occur when {chunks} is deallocated. assert version !== ?? resources :@= version.resources assert resources !== ?? #debug_stream :@= resources.global.debug_stream #format@format1[address](debug_stream, # 'deallocate@version(%X%)\n\', version.address) chunks :@= version.chunks comments :@= version.comments contents :@= version.contents trim@(comments, 0) trim@(contents, 0) deallocate@(contents) deallocate@(comments) deallocate@(chunks) erase@(version) version.resources := resources version_deallocate@(resources, version) #format@format1[address](debug_stream, # 'deallocate@version(%X%) returns\n\', version.address) procedure equal@version takes version1 version version2 version returns logical #: This procedure will return {true} if {version1} is the same as #, {version2} and {false} otherwise. return compare@(version1, version2) = integer_convert@(0) procedure greater_than@version takes version1 version version2 version returns logical #: This procedure will return {true} if {version1} is greater than #, {version2} and {false} otherwise. return compare@(version1, version2) > integer_convert@(0) procedure less_than@version takes version1 version version2 version returns logical #: This procedure will return {true} if {version1} is less than #, {version2} and {false} otherwise. return compare@(version1, version2) < integer_convert@(0) procedure line_comments_insert@version takes version version comments string returns_nothing #: This procedure will insert {comments} into the contents portion #, of {version}. lines_extract@(version.comments, version, comments) procedure line_contents_insert@version takes version version contents string returns_nothing #: This procedure will insert {contents} into the contents portion #, of {version}. lines_extract@(version.contents, version, contents) procedure number_manage@version takes version version number unsigned returns_nothing #: This procedure will set keep track of the minimum and maximum #, delta number for {version}. This code is provided as tie-breaker #, for sorting {version} objects when they have the same timestamp. #, See {compare}@{version}() for the details. if number > version.max_number version.max_number := number if number < version.min_number version.min_number := number procedure ranges_remove@version takes version version returns_nothing #: This procedure will remove all of the {chunk}'s of type {range} #, from {version}.{chunks}. ranges_remove@(version.chunks, version) procedure read@version takes data_in_stream data_in_stream history history returns version #: This procedure will read a version object in from {data_in_stream} #, and return it. if data_in_stream.eof return ?? buffer :@= data_in_stream.buffer resources :@= data_in_stream.resources trim@(buffer, 0) offset :@= unsigned_read@(data_in_stream) # Offset string_read@(data_in_stream, buffer) # Nickname nickname :@= read_only_copy@(buffer) trim@(buffer, 0) project_timestamp :@= timestamp_read@(data_in_stream) # Proj. TS executable :@= logical_read@(data_in_stream) # Exec. timestamp :@= timestamp_read@(data_in_stream) # TS new_line_read@(data_in_stream) # NL # Initialize the {version} object: version :@= xallocate@version(history) version.offset := offset version.executable := executable version.timestamp := timestamp version_append@(history, version) #: Read in the chunks: read@(version.chunks, data_in_stream, version) #: Read in the content {chunk_ranges}: tag_check@(data_in_stream, "D"[0]) content_chunk_ranges :@= read@chunk_ranges(data_in_stream, history) new_line_read@(data_in_stream) chunks_convert@(content_chunk_ranges, version.contents) deallocate@(content_chunk_ranges) #: Read in the comment {chunk_ranges}: tag_check@(data_in_stream, "C"[0]) comment_chunk_ranges :@= read@chunk_ranges(data_in_stream, history) new_line_read@(data_in_stream) chunks_convert@(comment_chunk_ranges, version.comments) deallocate@(comment_chunk_ranges) tag_check@(data_in_stream, "I"[0]) unsigned_read@(data_in_stream) new_line_read@(data_in_stream) verify@(version.chunks, version) verify@(version.contents, ??) verify@(version.comments, ??) return version procedure string_append@version takes version version text string returns_nothing #: This procedure will append the contents of {versin} onto the end #, of {text}. string_append@(version.chunks, text) procedure unshare@version takes version version share_table set[chunk] returns_nothing #: This procedure ensure make each {chunk} in {version}.{chunks} #, is no longer in {share_table}. unshare@(version.chunks, share_table) procedure write@version takes version version data_out_stream data_out_stream share_table set[chunk] header_timer timer verify_timer timer remove_timer timer share_timer timer bind_timer timer sort_timer timer convert_timer timer chunks_timer timer ranges_timer timer returns_nothing #: This procedure will write out {version} to {data_out_stream} using #, {buffer} as a temporary string buffer. {share_table} is used #, to detect sharable {chunk}'s. This routine must be called #, increasing {version}'s in order to work properly. # Write out "V" line: assert version !== ?? assert data_out_stream !== ?? #resources :@= data_out_stream.resources #debug_stream :@= resources.global.debug_stream #format@format1[address](debug_stream, # "write@version(%X%)\n\", version.address) current_set@(header_timer) tag_write@(data_out_stream, "V"[0]) # Tag unsigned_write@(data_out_stream, version.offset) # Offset project :@= version.history.project_file.project assert project !== ?? write@(project.project_name, data_out_stream) # Proj. name logical_write@(data_out_stream, version.executable) # Exec. timestamp_write@(data_out_stream, version.timestamp) # TS new_line_write@(data_out_stream) # NL # Get the chunks properly ordered. This is actually harder than it #, looks. We want all the {chunk}'s to show up in the history file #, in a determanisitc order. First, we make sure that we have #, identified all previously sharable {chunk}'s. Second, we want #, the {chunk}'s that are first used in this version to show up in #, "first used" order starting with the contents and then the comments. #, The range {chunk}'s are added to {version}.{chunks} later. chunks :@= version.chunks contents :@= version.contents comments :@= version.comments current_set@(verify_timer) verify@(chunks, version) verify@(contents, ??) verify@(comments, ??) current_set@(remove_timer) ranges_remove@(chunks, version) current_set@(verify_timer) verify@(chunks, version) current_set@(share_timer) share@(contents, share_table) share@(comments, share_table) current_set@(bind_timer) sort_key_reset@(contents, version) sort_key_reset@(comments, version) sort_key_index :@= 1 sort_key_index := sort_key_bind@(contents, sort_key_index, version) sort_key_index := sort_key_bind@(comments, sort_key_index, version) current_set@(sort_timer) sort@(chunks, version) # Reduce the comments and contents {chunk_ranges} to no longer than one: current_set@(convert_timer) content_chunk_ranges :@= chunk_ranges_convert@(contents, version, share_table) comment_chunk_ranges :@= chunk_ranges_convert@(comments, version, share_table) # Write out {chunks}: current_set@(chunks_timer) write@(chunks, data_out_stream, version) # Write out the contents chunk ranges: current_set@(ranges_timer) tag_write@(data_out_stream, "D"[0]) write@(content_chunk_ranges, data_out_stream) new_line_write@(data_out_stream) deallocate@(content_chunk_ranges) # Write out the comment chunk ranges: tag_write@(data_out_stream, "C"[0]) write@(comment_chunk_ranges, data_out_stream) new_line_write@(data_out_stream) deallocate@(comment_chunk_ranges) # Write out the information chunk ranges: tag_write@(data_out_stream, "I"[0]) unsigned_write@(data_out_stream, 0) new_line_write@(data_out_stream)