# topic.icn: Object to represent one topic in a plan; see plan.icn. #-- $ifndef __TOPIC_ICN__ $define __TOPIC_ICN__ $define TOPIC_REVISION "$Revision: 1.7 $" $define TOPIC_DATE "$Date: 1996/02/18 19:59:07 $" #================================================================ # Class Topic: Each instance encapsulates one node of the tree of # topics within a Plan object. #---------------------------------------------------------------- # topic := Topic_New ( plan, title, shortName, path, depth, # parent, birthOrder ) # [ returns a new topic with: # .plan := plan # .title := title # .shortName := shortName # .path := path # .depth := depth # .parent := parent # .birthOrder := birthOrder # .childList := &null # .linkVarList := &null # ] #-- # plan := Topic_Plan ( topic ) [ returns topic.plan ] #-- # string := Topic_Title ( topic ) [ returns topic.title ] #-- # string := Topic_Short_Name ( topic ) [ returns topic.shortName ] #-- # string := Topic_Path ( topic ) [ returns topic.path ] #-- # integer := Topic_Depth ( topic ) [ returns topic.depth ] #-- # topic := Topic_Parent ( topic ) # [ if topic has a parent -> # return topic.parent # | else -> # fail # ] #-- # integer := Topic_Birth_Order ( topic ) [ returns topic.birthOrder ] #-- # Topic_Add_Child ( topic, child ) # [ topic := topic with child added as its new last child topic # ] #-- # integer := Topic_N_Children ( topic ) [ returns number of children ] #-- # topic := Topic_Gen_Children ( topic ) # [ generates the children of topic in ascending birth order ] #-- # topic := Topic_Nth_Child ( topic, n ) # [ if topic has at least n children -> # returns the child for which .birthOrder = n # | else -> fails # ] #-- # string := Topic_Relative_Path ( fromTopic, toTarget ) # [ returns the pathname (and optional anchor) which, when used # in the fromTopic's directory, points to the output file and # anchor of the toTarget # ] #-- # Topic_Add_Linkvar ( topic, linkvar ) # [ adds the linkvar object to topic.linkvarList #-- # linkVar := Topic_Gen_Linkvars ( topic ) # [ generates a sequence of linkvar objects in the order they were # added to topic.linkvarList # ] #-- # integer := Topic_N_Linkvars ( topic ) # [ returns the number of linkvar objects in topic.linkvarList # ] #-- # string := Topic_Version ( topic ) # [ returns the RCS revision keywords ] #================================================================ record topicTag ( # Topic object layout plan, # Points to the containing plan object title, # This topic's title string shortName, # The "dir/basename" short name string of this topic path, # Path, relative to the file tree root depth, # Depth in tree, integer, root=1 parent, # Parent topic, or &null for the root topic birthOrder, # Our child number relative to the parent childList, # &null, or a list of child topics linkvarList ) # List of linkVar objects (q.v.) # - - - T o p i c _ N e w - - - procedure Topic_New ( # Returns a new topic object plan, # The plan object that holds this topic tree title, # The topic's title string shortName, # The topic's short name string, "dir/basename" path, # The full pathname to the file, less extension depth, # Our depth in the tree, where root = 1 parent, # Parent topic, or &null for the root topic birthOrder ) # Our child number relative to the parent #-- local topic # Result to be returned topic := topicTag(); topic.plan := plan; topic.title := title; topic.shortName := shortName; topic.path := path; topic.depth := depth; topic.parent := parent; topic.birthOrder := birthOrder; return topic; end # --- Topic_New --- # - - - T o p i c _ P l a n - - - procedure Topic_Plan ( topic ) return topic.plan; end # - - - T o p i c _ T i t l e - - - procedure Topic_Title ( topic ) return topic.title; end # - - - T o p i c _ S h o r t _ N a m e - - - procedure Topic_Short_Name ( topic ) return topic.shortName; end # - - - T o p i c _ P a t h - - - procedure Topic_Path ( topic ) return topic.path; end # - - - T o p i c _ D e p t h - - - procedure Topic_Depth ( topic ) return topic.depth; end # - - - T o p i c _ P a r e n t - - - procedure Topic_Parent ( topic ) return \ topic.parent; # Fails if .parent is &null end # - - - T o p i c _ B i r t h _ O r d e r - - - procedure Topic_Birth_Order ( topic ) return topic.birthOrder; end # - - - T o p i c _ A d d _ C h i l d - - - procedure Topic_Add_Child ( topic, child ) #-- # If this is the first child, set up the .childList. In any case, # add the new child to the end of the .childList. #-- / topic.childList := []; put ( topic.childList, child ); return topic; end # - - - T o p i c _ N _ C h i l d r e n - - - procedure Topic_N_Children ( topic ) #-- # Returns the number of children. Returns zero if no children have # ever been added. #-- return ( * \ topic.childList ) | 0; end # - - - T o p i c _ G e n _ C h i l d r e n - - - procedure Topic_Gen_Children ( topic ) #-- # Generates the child topics within this topic. #-- every suspend ( ! \ topic.childList ); fail; end # - - - T o p i c _ N t h _ C h i l d - - - procedure Topic_Nth_Child ( topic, n ) #-- # Returns the nth child of the given topic, or fails if there # aren't that many. #-- return ( \ topic.childList ) [ n ]; end # - - - T o p i c _ R e l a t i v e _ P a t h - - - procedure Topic_Relative_Path ( fromTopic, toTarget ) #-- # Returns a pathname which, when used in fromTopic's file, points to # the toTarget's file and optional anchor. # # Each topic's .path field should have the syntax: # d1 / d2 / ... / dn / f # where there may be zero or more directories d[i]. # 1. First find the largest sequence of directories d1, d2, ..., dc # that is a prefix of both fromTopic's and toTopic's paths. # fromTopic.path: d1 / d2 / ... / dc / a1 / a2 / ... / aj / fa # toTopic.path: d1 / d2 / ... / dc / b1 / ... / bk / fb # 2. Form the two lists that remain when these prefixes are removed: # a1 / a2 / ... / aj / fa # b1 / ... / bk / fb # 3. The result consists of: # a. One "../" for each a1, a2, ..., aj; this gets us up to # the lowest directory that is a parent of fromTopic and toTopic. # b. The sequence "b1/b2/.../bk/fb". # c. The suffix ".html". # d. The anchor from toTarget, if there is one. # Examples: # fromTopic.path toTopic.path result # -------------- ------------ ------ # here/old here/new new.html # here/old here/there/new there/new.html # foo/x/y/z/a foo/ear/danke/b ../../../ear/danke/b.html #-- local fromList # List of fromTopic path elements local toList # List of toTopic path elements local result # Result to be returned #-- 1 -- #-[ fromList := list of strings a1, a2, ..., am, fa from fromTopic path # toList := list of strings b1, b2, ..., bn, fb from toTopic path # result := ""; #-] fromList := Topic_Build_Dir_List ( fromTopic ); toList := Topic_Build_Dir_List ( Target_Topic ( toTarget ) ); result := ""; #-- 2 -- #-[ fromList := elements of fromList not in common prefix # toList := elements of toList not in common prefix #-] while ( ( * fromList ) > 1 ) & ( ( * toList ) > 1 ) & ( fromList[1] == toList[1] ) do { pop ( fromList ); pop ( toList ); } #-- 3 -- #-[ result ||:= one "../" for each element of fromList but last || # all elements of toList except the last, each # followed by a slash || last element of toList || ".html" #-] every 1 to ( ( * fromList ) - 1 ) do result ||:= "../"; every result ||:= toList [ 1 to ( ( * toList ) - 1 ) ] || "/"; result ||:= toList[-1] || ".html"; result ||:= Target_Anchor ( toTarget ); # Fails if no anchor #-- 4 -- return result; end # --- Topic_Relative_Path --- # - - - T o p i c _ B u i l d _ D i r _ L i s t - - - #-[ returns a list of strings [ s1, s2, ..., sn ] consisting of the # elements of the topic.path string separated by slashes #-] procedure Topic_Build_Dir_List ( topic ) local result # Result list to be returned local nextSlash # Location of the next slash result := []; topic.path ? { #-- Dissect the path while ( nextSlash := find ( "/" ) ) do { #-- Process the next directory put ( result, tab ( nextSlash ) ); # Remove dir, add to result list move ( 1 ); # Skip over the slash } #-- Process the next directory put ( result, tab ( 0 ) ); # Put the rest at end of list } #-- Dissect the path return result; end # --- Topic_Build_Dir_List --- # - - - T o p i c _ A d d _ L i n k v a r - - - procedure Topic_Add_Linkvar ( topic, linkvar ) / topic.linkvarList := []; # Start a list if there wasn't one put ( topic.linkvarList, linkvar ); end # --- Topic_Add_Linkvar --- # - - - T o p i c _ G e n _ L i n k v a r s - - - procedure Topic_Gen_Linkvars ( topic ) every suspend ( ! \ topic.linkvarList ); fail; end # --- Topic_Gen_Linkvars --- # - - - T o p i c _ N _ L i n k v a r s - - - procedure Topic_N_Linkvars ( topic ) return ( * \ topic.linkvarList ) | 0; end # --- Topic_N_Linkvars --- # - - - T o p i c _ V e r s i o n - - - procedure Topic_Version ( topic ) return "Topic " || RCS_Extract ( TOPIC_REVISION ) || " " || RCS_Extract ( TOPIC_DATE ); end # --- Topic_Version --- $endif