# pathmap.icn: Encapsulates the PathMap file for webstyler.icn. #-- $ifndef __PATHMAP_ICN__ $define __PATHMAP_ICN__ $define PATH_MAP_REVISION "$Revision: 1.6 $" $define PATH_MAP_DATE "$Date: 1996/10/10 18:12:34 $" #================================================================ # Class PathMap: Each instance encapsulates an entire path map # file. #---------------------------------------------------------------- # pathMap := Path_Map_New ( fileName, log ) # [ if fileName names a valid path map file -> # returns a new pathMap object representing that file with fields: # .rootURL := the specified root URL # .shortPathMap := table, maps shortPath |-> fullPath # | else -> # log +:= error message(s) # fails # ] #-- # string := Path_Map_Root_URL ( pathMap ) [ returns pathMap.rootURL ] #-- # string := Path_Map_Expand_Short_Name ( pathMap, s ) # [ if s has the form "spath/sfile" and spath is in pathMap.shortPathMap -> # return pathMap.shortPathMap[spath] || "/" || sfile # | else if s has the form "spath/sfile" and spath is not in # pathMap.shortPathMap -> # fail # | else -> # return s # ] #-- # string := Path_Map_Version ( pathMap ) [ returns RCS keywords ] #-- record pathMapTag ( # One path map object log, # The associated error logging object; see log.icn fileName, # The name of the input file rootURL, # The root URL for the web shortPathMap, # Table, maps shortPath |-> fullPath scan ) # The input scan object; see scan.icn #================================================================ # Private parts #---------------------------------------------------------------- $define PATH_MAP_WHITE_SET ' \t' # Whitespace cset for path map files # - - - P a t h _ M a p _ N e w - - - procedure Path_Map_New ( fileName, log ) local pathMap #-- 1 -- #-[ pathMap := a pathMap object with: # .log := log # .fileName := fileName # .shortPathMap := an empty table #-] pathMap := pathMapTag ( ); pathMap.log := log; pathMap.fileName := fileName; pathMap.shortPathMap := table ( ); #-- 2 -- #-[ if pathMap.fileName points to a valid path map file -> # pathMap.rootURL := first line of the file # pathMap.shortPathMap +:= entries that map shortPath |-> fullPath, # for the 2nd and succeeding lines # | else -> # pathMap.log +:= error message(s) # pathMap.rootURL := # pathMap.shortPathMap := #-] Path_Map_Read ( pathMap ); #-- 3 -- #-[ if log contains no errors -> # return pathMap # | else -> fail #-] if Log_Error_Count ( log ) = 0 then return pathMap else fail; end # --- Path_Map_New --- # - - - P a t h _ M a p _ R e a d - - - #-[ if pm.fileName points to a valid path map file -> # pm.rootURL := the first line of the file # pm.shortPathMap := entries that map each short path name field # to the full name field, for the remaining lines # returns pm # | else -> # pm.log +:= error message(s) # pm.rootURL := # pm.shortPathMap := # fails #-] procedure Path_Map_Read ( pm ) $define URL_PREFIX "http:/" # A real URL should start with this #-- 1 -- pm.scan := &null; #-- 2 -- #-[ if pm.fileName can be opened for reading -> # pm.scan := a scan object at the first line, or at EOF if empty # | else -> I #-] pm.scan := Scan_Open ( pm.fileName, pm.log ); #-[ if pm.scan is &null -> # pm.log +:= error, can't open (pm.fileName) # fail # | else -> I #-] if / pm.scan then return Log_Error ( pm.log, "Can't open the path map file `", pm.fileName, "' for reading." ); #-[ if subject looks nothing like a URL -> # pm.log +:= error, first line should look like a URL # pm.rootURL := anything # | else -> # pm.rootURL := current subject #-] pm.rootURL := trim ( tab ( 0 ) ); if not match ( URL_PREFIX, pm.rootURL ) then return Scan_Error ( pm.scan, "The first line of the path map file must be a URL starting with `", URL_PREFIX, "...'." ); #-[ pm.scan := pm.scan advanced to next line, if any #-] Scan_Next_Line ( pm.scan ); #-[ pm.shortPathMap +:= entries from pm.scan # pm.log +:= error message(s) from any invalid lines in # pm.scan #-] while not ( Scan_End_File ( pm.scan ) ) do { #-[ if current subject is a valid path map line -> # pm.shortPathMap +:= entry mapping subject's short path field # to its full path field # | else -> # pm.log +:= scan error(s) on pm.scan #-] Path_Map_Build ( pm ); #-[ pm.scan := pm.scan advanced to next line, if any # ] Scan_Next_Line ( pm.scan ); } #-[ if pm.log has any errors -> fail # | else -> return pm #-] if Log_Error_Count ( pm.log ) = 0 then return pm else fail; end # --- Path_Map_Read --- # - - - P a t h _ M a p _ B u i l d - - - #-[ if current subject is a valid path map line -> # pm.shortPathMap +:= entry mapping subject's short path field to # its full path field # return pm # | else -> # pm.log +:= scan error message(s) # fail #-] procedure Path_Map_Build ( pm ) #-- 1 -- #-[ short := &null # full := &null #-] local short, full #-- 2 -- #-[ if there is a white space character in the subject -> # short := text up to but not including the first whitespace # pm.scan := pm.scan advanced up to the first whitespace # | else -> I #-] short := tab ( upto ( PATH_MAP_WHITE_SET ) ); #-- 3 -- #-[ if short is non-null and nonempty -> I # | else -> # pm.log +:= pm.scan error # fail #-] if ( / short ) | ( ( * short ) = 0 ) then return Scan_Error ( pm.scan, "Each path map line must start with the short pathname." ); #-- 4 -- #-[ subject := # full := remainder of subject with whitespace trimmed on both ends # pm.scan := pm.scan advanced to end of line #-] tab ( many ( PATH_MAP_WHITE_SET ) ); full := trim ( tab ( 0 ) ); #-- 5 -- #-[ if full exists and is nonempty -> I # | else -> # pm.log +:= pm.scan error, missing full path # fail #-] if ( / full ) | ( ( * full ) = 0 ) then return Scan_Error ( pm.scan, "Each path map line must have a full path after the whitespace." ); #-- 6 -- #-[ if pm.shortPathmap[short] exists -> # pm.log +:= pm.scan error, duplicate short path # fail # | else -> # pm.shortPathMap +:= entry that maps short |-> full #-] if \ pm.shortPathMap[short] then return Scan_Error ( pm.scan, "This short path is a duplicate" ); pm.shortPathMap[short] := full; #-- 7 -- return pm; end # --- Path_Map_Build --- # - - - P a t h _ M a p _ R o o t _ U R L - - - procedure Path_Map_Root_URL ( pathMap ) return pathMap.rootURL; end # --- Path_Map_Root_URL --- # - - - P a t h _ M a p _ E x p a n d _ S h o r t _ N a m e - - - #-[ if s has the form "spath/sfile" and spath is in pathMap.shortPathMap -> # return pathMap.shortPathMap[spath] || "/" || sfile # | if s has the form "spath/sfile" and spath is not in # pathMap.shortPathMap -> # fail # | else -> # return s #-] procedure Path_Map_Expand_Short_Name ( pm, s ) #-- 1 -- #-[ ( shortPath, filePart, fullPath ) := &null #-] local shortPath # The part of s up to but not incl. the first slash local filePart # The part of s from the slash onward local fullPath # The full path for this shortPath #-- 2 -- #-[ if there is a slash in s -> # shortPath := characters from s to but not including first slash # filePart := characters from s from slash to end # | else -> return s #-] s ? { #-- Dissect s if not ( shortPath := tab ( upto ( '/' ) ) ) then return s; # E.g., files in the root directory filePart := tab ( 0 ); } #-- Dissect s #-- 3 -- #-[ if shortPath is not in pm.shortPathMap -> fail # | else -> # fullPath := pm.shortPathMap[shortPath] #-] if not ( fullPath := \ pm.shortPathMap[shortPath] ) then fail; #-- 4 -- return fullPath || filePart; end # --- Path_Map_Expand_Short_Name --- # - - - P a t h _ M a p _ V e r s i o n - - - procedure Path_Map_Version ( pathMap ) return "PathMap " || RCS_Extract ( PATH_MAP_REVISION ) || " " || RCS_Extract ( PATH_MAP_DATE ); end # --- Path_Map_Version --- $endif