module SaplCollectorLinker import StdEnv, ArgEnv, Directory, File import set_return_code, linkargs import Platform, UtilIO import UtilStrictLists import SaplLinkerShared import FastString exit :: !String [String] !*World -> *World exit errors_path messages world # (err, world) = accFiles (WriteLinkErrors errors_path [ toString m \\ m <- reverse messages]) world | isNothing err = world # world = set_return_code_world (-1) world = world exit_error errors_path messages world # (err, world) = accFiles (WriteLinkErrors errors_path [ toString m \\ m <- reverse messages]) world = set_return_code_world (-1) world Start world # commandline = getCommandLine # s_commandline = size commandline # (default_dir, world) = accFiles FStartUpDir world // the path of the linker # linkoptspath = if (s_commandline >= 3 && commandline.[1] == "-I") commandline.[2] (default_dir +++ {path_separator} +++ "linkopts") # errors_path = if (s_commandline >= 5 && commandline.[3] == "-O") commandline.[4] (default_dir +++ {path_separator} +++ "linkerrs") # ((linkopts,ok,message),world) = accFiles (ReadLinkOpts linkoptspath) world | not ok = exit_error errors_path [message] world # output_dir = (fst (extractPathFileAndExtension linkopts.exe_path)) +++ "-sapl" # (ok, world) = dir_create output_dir world | not ok = exit_error errors_path ["Error: can't create directory \"" +++ output_dir +++ "\""] world # world = removeFiles output_dir world # builtin_output_dir = output_dir +++ {path_separator} +++ "_override_" # (ok, world) = dir_create builtin_output_dir world | not ok = exit_error errors_path ["Error: can't create directory \"" +++ builtin_output_dir +++ "\""] world # (ok, built_ins_dir, world) = case sapl_stdenv_dir default_dir world of (Just dir, world) = (True, dir, world) (_ , world) = (False, "", world) | not ok = exit_error errors_path ["Error: Sapl built-in modules path not found"] world # (ok, builtin_module_paths, world) = built_in_modules built_ins_dir world # messages = case ok of False = ["Warning: built-in Sapl functions in "+++ built_ins_dir +++ " not found."] _ = [] // Copy built-in modules # world = foldl (\w (i,o) = copyFile i o w) world (map (\i = (i, to_output_file_name builtin_output_dir i)) builtin_module_paths) // Generate paths of SAPL files # module_paths = map replace_extension (StrictListToList linkopts.object_paths) // Copy modules (putting them into a hiearchical directory structure indicated by // the smodule name # (messages, world) = foldl (copy_module output_dir) (messages, world) module_paths = exit errors_path messages world where // Safe directory creation: if dir_create fails, // it tries to create the directory step by step from a base directory // e.g. // base.A.B cannot be created, only base.A then base.A.B safe_dir_create basedir dir world = case dir_create dir world of (True, world) = (True, world) (False, world) = foldl fc (True, world) dirseq where fc (True, world) dir = dir_create dir world fc (False, world) _ = (False, world) dirseq = reverse (dirseq1 (size basedir + 1) []) dirseq1 start ds = if found (dirseq1 (nextdot + 1) [dir % (0, nextdot - 1):ds]) (if (start < size dir) [dir:ds] ds) where (found, nextdot) = charIndex dir start path_separator dir_create d world # ((_, path), world) = pd_StringToPath d world # (result, world) = createDirectory path world = case result of NoDirError = (True, world) AlreadyExists = (True, world) _ = (False, world) copy_module newbase (messages, w) p = case extract_module_name_and_path p w of (False, _, _, w) = (["Warning: SAPL file cannot be found: " +++ p : messages], w) (True, Just d, Just m, w) # td = targetDir (Just d) # (ok, w) = safe_dir_create newbase td w | not ok = (["Warning: cannot create directory: " +++td +++ ", " +++ p : messages], w) = (messages, copyFile p (target td m) w) (True, Nothing, Just m, w) = (messages, copyFile p (target (targetDir Nothing) m) w) (_, _, _, w) = (messages, w) where targetDir (Just d) = newbase +++ {path_separator} +++ d +++ {path_separator} targetDir Nothing = newbase +++ {path_separator} target basedir m = basedir +++ m +++ "." +++ sapl_module_name_extension // Given a file name (with path), provides the follwoing triple: // 1. whether the file exists // 2. directory part from its module name (if any) (e.g. X.Y.Z -> X/Y) // 3. top level module name (e.g. Data.Map -> Map) extract_module_name_and_path p w = case detect_module_name p w of (False, _, w) = (False, Nothing, Nothing, w) (True, Nothing, w) = (True, Nothing, Just fromPath, w) (True, Just "", w) = (True, Nothing, Just fromPath, w) (True, Just m , w) = case module_dir m of (Just d, m) = (True, Just d, Just m, w) (Nothing, m) = (True, Nothing, Just m, w) where fromPath = fst (extractPathFileAndExtension (snd (extractPathAndFile p))) // Splits module name into a directory part and a top level module name module_dir m = if isDot (Just dirPart, m % (lastDot+1,size m-1)) (Nothing, m) where (isDot, lastDot) = charIndexBackwards m (size m - 1) '.' dirPart :: String dirPart = {if (c == '.') path_separator c \\ c <-: m % (0,lastDot-1)} to_output_file_name newbase oldpath # filename = snd (extractPathAndFile oldpath) = newbase +++ {path_separator} +++ filename replace_extension f = (fst (extractPathFileAndExtension f)) +++ "." +++ sapl_module_name_extension