english
version "1.0"
identify "xyz"

#: Copyright (c) 1995, 1996, 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 project

#: This module implements four project abstractions for SVMS.
#,
#,   {project_name}
#,	A {project_name} is a project name consisting of nickname
#,	and timestamp (for good measure.)
#,   {project}
#,	A {project} represents a project.  All {project} objects have
#,	a corresponding {project_name}, but the reverse is not true.
#,	Each {project} has a corresponding root {project_directory}
#,	object.  There is a 1-to-1 correspondence between a {project}
#,	and the SVMS/p.project file.
#,   {project_directory}
#,	A {project_directory} is one directory of a project.
#,	A {project_directory} object names both the actual project
#,	directory that the user sees and the shadow project d.
#,	directory under the SVMS shadow directory tree.  A
#,	{project_directory} can have zero, one, or more
#,	sub-{project_directory}'s.  In addition, there is a
#,	1-to-1 correspondance between {project_directory} objects
#,	and p.listing files.
#,   {project_file}
#,	A {project_file} is the name of a history file within a project
#,	directory.  A {project_file} names both the actual file that
#,	the user sees and the corresponding h. history file under the
#,	SVMS shadow directory tree.
#,
#, Thus, a {project} contains a tree of {project_directory}'s, where
#, each {project_directory} contains zero, one, or more {project_file}'s.
#,
#, The code in this module automatically migrates information between
#, the p.listing files on disk and the in memory representation.  Other
#, than calling {flush}@{project}() at the end, no other effort is
#, required to keep the various p.listing files up-to-date.
#,
#, What happens if a crash occurs between updating the p.listing files?
#, First, no individual p.listing file will be corrupted because we
#, always write the new p.listing file to a temporary file and rename
#, it afterwards.  Second, the {has_open_sub_directory} flag is only
#, cleared for a directory when all of the child files and directories
#, are closed.  If a crash occurs before all of the p.listing files are
#, updated to be closed, the remaining updates will be detected and
#, deferred the next time an SVMS command is executed.

define project				#: Information about a project
    record
	current_directory_name file_name #: Current directory (from /)
	directory_table table[file_name, project_directory] #: dir. table
	file_table table[file_name, project_file] #: file table
	global global			#: Global information
	host_url string			#: Host URL (or "")
	lazy logical			#: {true}=>Fetch from parent lazily
	lazy_timestamp unsigned		#: Time of lazy bringover
	parent_project_directory file_name #: Parent project or ?? if no parent
	project_directory_name file_name #: Project directory (from /)
	project_name project_name	#: Project name for this {project}
	proxy_url string		#: URL for proxy (or "")
	resources resources		#: Associated {resources}
	root_project_directory project_directory #: Root {project_directory}
    generate address_get, allocate, erase, identical

define project_directory		#: A project directory
    record
	actual_directory_name file_name	#: Full dir. name starting from "/"
	hash unsigned			#: Hash of all {project}'s and dirs
	listing_file_name file_name	#: Assoc. p.listing file name
	modified logical		#: {true}=>assoc. p.listing out-of-date
	open_directories unsigned	#: Number of open {project_directory)'s
	open_files unsigned		#: Number of open {project_file}'s
	parent project_directory	#: Parent proj. dir. (or ?? for root)
	project project			#: Overall {project}.
	project_directorys project_directorys #: All sub-dirs
	project_file project_file	#: Corresponding {project_file}
	project_files project_files	#: {project_file}'s in dir.
	relative_directory_name file_name #: Proj. rel. dir. name ("." for ":")
	restored logical		#: {true}=>assoc. p.listing file read
	resources resources		#: Associated {resources}
	shadow_directory_name file_name	#: Full shadow dir. name from "/"
    generate address_get, allocate, erase, identical

define project_directorys		#: A list of {project_directory}'s
    record
	list vector[project_directory]	#: The list of {project_directory}'s
	resources resources		#: {resources} allocated from
    generate address_get, allocate, erase, identical, print

define project_file			#: A project file
    record
	actual_file_name file_name	#: Actual file name starting from "/"
	bringover_file_name file_name	#: Bringover file name
	bringover_hash unsigned		#: Bringover file hash value (or 0)
	conflict_file_name file_name	#: Conflict file name
	conflict_hash unsigned		#: Conflict file hash value (or 0)
	history_file_name file_name	#: History file name
	history_hash unsigned		#: History file hash value (or 0)
	lock_file_name file_name	#: Lock file name
	lock_hash unsigned		#: Lock file hash value (or 0)
	modified logical		#: {true}=>file contents/state changed
	parent project_directory	#: Project dir. containing file
	project project			#: {project} containing file
	project_directory project_directory #: Assoc. {project_directory} or ??
	relative_file_name file_name	#: Project relative file name
	resources resources		#: Associated {resources}
	timestamp unsigned		#: Timestamp for file
    generate address_get, allocate, erase, identical

define project_files			#: A list of {project_file}'s
    record
	list vector[project_file]	#: The list of {project_file}'s
	project_directory project_directory #: Containing {project_directory}
	resources resources		#: {resources} allocated from
    generate address_get, allocate, erase, identical, print

define project_name			#: A project name
    record
	nickname string			#: Project nickname
	resources resources		#: Associcated {resources}
	timestamp unsigned		#: Project timestamp
    generate address_get, allocate, erase, identical, print



#: {project} procedures:

procedure xallocate@project
    takes
	resources resources
    returns project

    #: This procedure will allocate a new {project} object from {resoruces}
    #, and return it.


procedure compare@project
    takes
	project1 project
	project2 project
    returns integer

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


procedure create@project
    takes
	project_name project_name
	project_directory_name file_name
	current_directory_name file_name
	refresh logical
	global global
    returns project

    #: This procedure will create and return a new {project} object
    #, refering to {project_directory_name}, {current_directory_name},
    #, {project_name}, and {global}.  If {refresh} is {true}, no
    #, p.listing file will be read.


procedure deallocate@project
    takes
	project project
    returns_nothing

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


procedure fetch1@project
    takes
	project project
	file_name file_name
    returns project_file

    #: This procedure will fetch and return the {project_file} associated
    #, it {file_name} in {project}.  If {project_file} association does
    #, not exist, ??@{project_file} is returned.


procedure find@project
    takes
	refresh logical
	global global
    returns project

    #: This procedure will find the SVMS directory and load the
    #, project information and return it.  ??@{project} is returned
    #, if no project is found, an error message is output to {errors};
    #, otherwise the the appropriate {project} is returned.  If {refresh}
    #, is {true}, no p.listing files will be read.


procedure lookup@project
    takes
	directory_name file_name
	refresh logical
	global global
    returns project

    #: This procedure will find and return the {project} associated
    #, with {directory_name}.  If no project is found, an error
    #, message is output to ??@{errors} and ??@{project} is returned.
    #, If {refresh} is {true}, no p.listing files are read.

    #, (i.e. "/SMVS"), hence we are a little parinoid:

procedure flush@project
    takes
	project project
    returns_nothing

    #: This procedure will cause all backing files for {project} to be
    #, prepared for a commit (if there are no pending errors).  If there
    #, pending errors, nothing occurs.


procedure show@project
    takes
	project project
	out_stream out_stream
    returns_nothing

    #: This procedure will dump the {project_directory} tree associated
    #, with {project} to {out_stream}.


procedure store1@project
    takes
	project project
	file_name file_name
	project_file project_file
    returns_nothing

    #: This procedure will associate {file_name} with {project_file}
    #, in {project}.


procedure print@project
    takes
	project project
	out_stream out_stream
    returns_nothing

    #: This procedure will output {project} to {out_stream}.


procedure refresh@project
    takes
	project project
	delete logical
	no_action logical
	verbose logical
	timer timer
    returns_nothing

    #: This procedure will refresh all of the p.listing files in {project}.
    #, If {delete} is {true}, any extraneous files that are encountered
    #, in the shadow directories are deleted.  If {no_action} is {true},
    #, no actual refreshing occurs; just reporting occurs.  If {verbose}
    #, is {true}, additional messages are output.


procedure restore@project
    takes
	project project
    returns_nothing

    #: This procedure will read in a project from {file_name} and return it.


procedure save@project
    takes
	project project
    returns_nothing

    #: This procedure will cause {project} to save itself to disk.
    #, {true} is returned if any errors occur; otherwise {false} is returned.


procedure svms_directory_find@project
    takes
	directory_name file_name
    returns file_name

    #: This procedure will search for a directory containing an SVMS
    #, directory starting from {directory_name} and working towards root.
    #, The SVMS directory name is returned.  If no such directory
    #, containing an SVMS sub-directory is found, ??@{file_name} is
    #, returned.

    #,  'svms_directory_find(%ds%)=>??\n\', original_directory_name)


#: {project_directory} procedures:

procedure create@project_directory
    takes
	project project
	parent project_directory
	base_name string
	refresh logical
    returns project_directory

    #: This procedure will create and return an initialized {project_directory}
    #, object.  If {parent} is ?? and {base_name} is empty, a root
    #, {project_directory} object for {project} is returned; otherwise,
    #, the {base_name} sub-directory of {parent} is created and returned.
    #, If {refresh} is {true}, restorationg of directory state from p.listing
    #, files is supressed.


procedure deallocate@project_directory
    takes
	project_directory project_directory
    returns_nothing

    #: This procedure will deallocate {project_directory} for subsequent
    #, reallocation.  Any nested {project_directory}'s and {project_file}'s
    #, are deallocated as well.
    

procedure directory_create@project_directory
    takes
	project_directory project_directory
	create logical
	duplicates_ok logical
    returns logical

    #: This procedure will create a directory for {project_directory}.
    #, If {create} is {true}, the corresponding actual directory is
    #, is created as well.  If {duplicates_ok} is {true}, no error
    #, message is generated if the directory already exists.  Any
    #, errors are recorded into {errors}.  {true} is returned if
    #, any errors have occured.


procedure expand@project_directory
    takes
	project_directory project_directory
	slice_project_files project_files
	open_only logical
    returns_nothing

    #: This procedure will add all of the {project_files} contained
    #, in {project_directory} and its sub-directorys to the end of
    #, {slice_project_files}.  If {open_only} is {true}, only the open
    #, project files will be appended; otherwise all are appended.


procedure parse@project_directory
    takes
	directory_name file_name
	project project
    returns project_directory

    #: This procedure will parse {directory_name} into {project_directory}
    #, in {project} and return it.  ?? is returned if any errors
    #, occur during parsing.  


procedure refresh@project_directory
    takes
	project_directory project_directory
	delete logical
	no_action logical
	verbose logical
	timer timer
    returns unsigned

    #: This procedure will update the p.listing file for {directory_name}.


procedure relative_parse@project_directory
    takes
	directory_name file_name
	project project
    returns project_directory

    #: This procedure will parse {directory_name} (which must be relative)
    #, into {project_directory} in {project} and return it.  ?? is returned
    #, if any errors occur during parsing.  


procedure restore@project_directory
    takes
	project_directory project_directory
    returns_nothing

    #: This procedure will restore the contents of {project_directory}
    #, from its p.listing file (if it exists).


procedure print@project_directory
    takes
	project_directory project_directory
	out_stream out_stream
    returns_nothing

    #: This procedure will print {project_directory} to {out_stream}.


procedure root_create@project_directory
    takes
	project project
	refresh logical
    returns project_directory

    #: This procedure will create and return the root {project_directory}
    #, for {project}.  If {refresh} is {true}, no p.listing files will be
    #, read.


procedure save@project_directory
    takes
	project_directory project_directory
    returns_nothing

    #: This procedure will cause a p.listing file to be created for
    #, {project_directory}.


procedure show@project_directory
    takes
	project_directory project_directory
	out_stream out_stream
	indent unsigned
    returns_nothing

    #: This procedure will show the contents of {project_directory} to
    #, {out_stream} indented by {indent}.


procedure show_no_newline@project_directory
    takes
	project_directory project_directory
	out_stream out_stream
	indent unsigned
    returns_nothing

    #: This procedure will output {project_directory} to {out_stream} indented
    #, by {indent} indentation units.  No trailing newline is output.


#: {project_directorys} procedures:

procedure xallocate@project_directorys
    takes
	resources resources
    returns project_directorys

    #: This procedure will allocate a new {project_directorys} object
    #, from {resources} and return it.


procedure append@project_directorys
    takes
	project_directorys project_directorys
	project_directory project_directory
    returns_nothing

    #: This procedure will append {project_directory} to the end of
    #, {project_directorys}.


procedure deallocate@project_directorys
    takes
	project_directorys project_directorys
    returns_nothing

    #: This procedure will deallocate {project_directorys} for
    #, subsequent reuse.


procedure fetch1@project_directorys
    takes
	project_directorys project_directorys
	index unsigned
    returns project_directory

    #: This procedure will return the {index}'th {project_directory} from
    #, {project_directorys}.


procedure save@project_directorys
    takes
	project_directorys project_directorys
    returns_nothing

    #: This procedure will cause p.listing files to be generated
    #, for each {project_directory} in {project_directorys}.


procedure show@project_directorys
    takes
	project_directorys project_directorys
	out_stream out_stream
	indent unsigned
    returns_nothing

    #: This procedure will output {project_directorys} to {out_stream}
    #, indented by {indent} indentation stops.


procedure size_get@project_directorys
    takes
	project_directorys project_directorys
    returns unsigned

    #: This procedure will return the size of {project_directorys}


procedure truncate@project_directorys
    takes
	project_directorys project_directorys
	new_size unsigned
    returns_nothing

    #: This procedure will make {project_directorys} have a size
    #, {new_size}.


#: {project_file} procedures:

procedure compare@project_file
    takes
	project_file1 project_file
	project_file2 project_file
    returns integer

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


procedure create@project_file
    takes
	parent project_directory
	base_name string
    returns project_file

    #: This procedure will create and return a new {project_file} object
    #, that refers to the {base_name} file in {project_directory}.


procedure deallocate@project_file
    takes
	project_file project_file
    returns_nothing

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


procedure directory_create@project_file
    takes
	project_file project_file
	create logical
	duplicates_ok logical
    returns logical

    #: This procedure will create a directory for {project_file}.
    #, If {create} is {true}, the corresponding actual directory is
    #, is created as well.  If {duplicates_ok} is {true}, no error
    #, message is generated if the directory already exists.  Any
    #, errors are recorded into {errors}.  {true} is returned if
    #, any errors have occured.


procedure equal@project_file
    takes
	project_file1 project_file
	project_file2 project_file
    returns logical

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


procedure format@project_file
    takes
	project_file project_file
	out_stream out_stream
	format string
	offset unsigned
    returns logical

    #: This procedure will output {project_file} to {out_stream} using
    #, the formating characters in {format} starting at {offset} until
    #, a terminating '%' is encountered.  See the {format} module
    #, to find out more about formatted output.


procedure hash@project_file
    takes
	project_file project_file
    returns unsigned

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


procedure lock_read@project_file
    takes
	project_file project_file
    returns unsigned

    #: This procedure will write out an l. file for {project_file}.


procedure lock_write@project_file
    takes
	project_file project_file
    returns_nothing

    #: This procedure will write out an l. file for {project_file}.


procedure lock_remove@project_file
    takes
	project_file project_file
    returns_nothing

    #: This procedure will remove the lock file associated with {project_file}.


procedure print@project_file
    takes
	project_file project_file
	out_stream out_stream
    returns_nothing

    #: This procedure will print {project_file} to {out_stream}.


procedure restore@project_file
    takes
	data_in_stream data_in_stream
	project_directory project_directory
    returns project_file

    #: This procedure will read in one {project_file} record from
    #, {data_in_stream} and return the corresponding {project_file} object
    #, where {project_directory} is the containing project directory.


procedure save@project_file
    takes
	project_file project_file
	data_out_stream data_out_stream
    returns_nothing

    #: This procedure will save one record corresponding to {project_file}
    #, to {data_out_stream}.


procedure show@project_file
    takes
	project_file project_file
	out_stream out_stream
	indent unsigned
    returns_nothing

    #: This procedure will show the contents of {project_file} to
    #, {out_stream} indented by {indent}.


#: {project_files} procedures:

procedure xallocate@project_files
    takes
	resources resources
    returns project_files

    #: This procedure will allocate and return a new {project_files} object
    #, from {resources}.


procedure append@project_files
    takes
	project_files project_files
	project_file project_file
    returns_nothing

    #: This procedure will append {project_file} to {project_files}.


procedure create@project_files
    takes
	project_directory project_directory
    returns project_files

    #: This procedure will allocate and return a {project_files} object
    #, whose containing {project_directory} is {project_directory}.



procedure deallocate@project_files
    takes
	project_files project_files
    returns_nothing

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


procedure fetch1@project_files
    takes
	project_files project_files
	index unsigned
    returns project_file

    #: This procedure will returnt the {index}'th {project_file} from
    #, {project_files}.


procedure save@project_files
    takes
	project_files project_files
	data_out_stream data_out_stream
    returns_nothing

    #: This procedure will cause a each {project_file} in {project_files}
    #, to be saved to {data_out_stream}.


procedure show@project_files
    takes
	project_files project_files
	out_stream out_stream
	indent unsigned
    returns_nothing

    #: This procedure will output {project_files} to {out_stream}
    #, indented by {indent} indentation stops.


procedure size_get@project_files
    takes
	project_files project_files
    returns unsigned

    #: This procedure will return the size of {project_files}


procedure sort@project_files
    takes
	project_files project_files
    returns_nothing

    #: This procedure will sort {project_files}.


procedure truncate@project_files
    takes
	project_files project_files
	new_size unsigned
    returns_nothing

    #: This procedure will truncate {project_files} to contain only
    #, {new_size} {project_file}'s.


procedure unique@project_files
    takes
	project_files project_files
    returns_nothing

    #: This procedure will cull {project_files} so that all files are unique.


#: {project_name} procedures:

procedure xallocate@project_name
    takes
	resources resources
    returns project_name

    #: This procedure will allocate and return an empty {project_name} object
    #, allocated from {resources}.


procedure create@project_name
    takes
	nickname string
	timestamp unsigned
	resources resources
    returns project_name

    #: This procedure will allocate a {project_name} object from {resources}
    #, and initialize it to contain {nickname} and {timestamp}.


procedure compare@project_name
    takes
	project_name1 project_name
	project_name2 project_name
    returns integer

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


procedure deallocate@project_name
    takes
	project_name project_name
    returns_nothing

    #: This procedure will deallocate {project_name} for subsequent
    #, reallocation.  This deallocation routine does not get upset
    #, {project_name} is already deallocated.


procedure equal@project_name
    takes
	project_name1 project_name
	project_name2 project_name
    returns logical

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


procedure hash@project_name
    takes
	project_name project_name
    returns unsigned

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


procedure read@project_name
    takes
	data_in_stream data_in_stream
    returns project_name

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


procedure share@project_name
    takes
	project_name project_name
    returns project_name

    #: This procedure will return a single sharable copy of {project_name}.


procedure write@project_name
    takes
	project_name project_name
	data_out_stream data_out_stream
    returns_nothing

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