-- (C) Copyright International Business Machines Corporation 23 January 
-- 1990.  All Rights Reserved. 
--  
-- See the file USERAGREEMENT distributed with this software for full 
-- terms and conditions of use. 
-- SCCS Info: @(#)cache.pp	1.9 1/28/92

#include "typemark.h"

cache: using (predefined, common, sysMain,main, findfile, 
  initfindfile, objectIO, load, objectCache, programCache, pathLoad,
  pathReadObj, root, unix,unixstat, CLoad, rManager, sysRManager,
  userRM, chainedRM, personalRM, cwd)
  
linking (objectCache, programCache)

process (initQ: sysMainQ)

declare
  init: sysMain;
  capability: polymorph;
  stat: statMtimeFunc;
  initCache: objectcache!initCacheFunc;
  initProgramCache: programcache!initCacheFunc;
  pathinit: initfindfile!initFindFileFn;
  defpathfinder: findfile!findfile_func;
  syspathfinder: findfile!findfile_func;
  pathloadfile: charstring;
  pathloadinit: pathload_init_func;
  pathreadinit: pathreadobj_init_func;
  args: common!charstringList;
  string: charstring;
  progname: charstring;
  prog: program;
  CLoad: CLoadFn;
  pathLoad: load_func;
  load: load_func;
  store: storeFunc;
  readObj: readobject_func;
  writeObj: writeobject_func;
  environ: environ;
  stdio: stdio;
  getCwd: getCwdFn;
  cachePathLoad: load_func;
  cachePathReadObj: readobject_func;
  chainedRM: sysRManager;
  
  -- definitions for getpaths.pp include file
  bindir: charstring;
  syspath: charstring;
  defpath: charstring;
  linkpath: charstring;
  
begin
  receive init from initQ;
  
  unwrap CLoad from polymorph#(init.rm.get
	(S("system"), S("CLoader"), S(""))) {init}; 
  unwrap pathLoad from polymorph#(init.rm.get
	(S("system"), S("pathLoad"), S(""))) {init};
  unwrap environ from polymorph#(init.rm.get
	(S("system"), S("environ"), S(""))) {init};
  unwrap stdio from polymorph#(init.rm.get
	(S("system"), S("stdio"), S(""))) {init, init(access)};
  unwrap getCwd from polymorph#(init.rm.get
	(S("system"), S("getCwd"), S(""))) {init};

  -- get file stat function 
  call CLoad(S("File Modification Time"), capability);
  unwrap stat from capability { init };

  -- get noncachine versions of read, write, load, store
  unwrap readObj from polymorph#(init.rm.get(
      S("system"), S("readObj"), S(""))) {init};
  unwrap writeObj from polymorph#(init.rm.get(
      S("system"), S("writeObj"), S(""))) {init};
  unwrap load from polymorph#(init.rm.get(
      S("system"), S("load"), S(""))) {init};
  unwrap store from polymorph#(init.rm.get(
      S("system"), S("store"), S(""))) {init};

  -- create the caching versions of the direct operations (read,
  -- write, load, store) 

  initCache <- objectCache!initCacheFunc#(procedure of program#(
      process objectCache));
  call initCache(readObj, writeObj, stat);

  initProgramCache <- programCache!initCacheFunc#(procedure of program#(
      process programCache));
  call initProgramCache(load, store, stat);

  -- now create the caching versions of the indirect operations
  -- (pathReadObj, libWriteObj, pathLoad, libStore)

  -- this figures out where to get object files, based on environment
  -- path variables
#define ENVIRON environ
#include "../../hermes/getpaths.pp"

  -- create the pathfinder
  pathinit <- initFindFileFn#(procedure of program#(
      pathLoad(S("findfile"))));
  syspathfinder <- findfile_func#(pathinit(stdio.access, getCwd, syspath));
  defpathfinder <- findfile_func#(pathinit(stdio.access, getCwd, defpath));

  -- load the pathloader
  pathloadinit <- pathload_init_func#(create of 
	program#(pathload(S("pathload"))));
  cachePathLoad <- load_func#(pathloadinit(load, syspathfinder));

  -- load the pathreader
  pathreadinit <- pathreadobj_init_func#(create of 
	program#(pathload(S("pathreadobj"))));
  cachePathReadObj <- readobject_func#(pathreadinit(readobj, defpathfinder));

  -- create a chained resource manager with the cached versions of
  -- versions the services
  block declare
    newRM: sysRManager;
    rmList: sysRmList;
    resource: polymorph;
    ac: accessFn;
  begin
    newRM <- sysRManager#((rManagerInitFn#(create of program#(
	    pathLoad(S("rmanager")))))());
    ac <- AccessFn#(create of program#(pathLoad(S("ac_none"))));
    wrap load as resource;
    call newRM.post(S("system"), S("load"), resource, 
      accessFn#(copy of ac));
    wrap store as resource;
    call newRM.post(S("system"), S("store"), 
      resource, accessFn#(copy of ac));
    wrap readObj as resource;
    call newRM.post(S("system"), S("readObj"),
      resource, accessFn#(copy of ac));
    wrap writeObj as resource;
    call newRM.post(S("system"), S("writeObj"),
      resource, accessFn#(copy of ac));
    wrap load_func#(copy of cachePathLoad) as resource;
    call newRM.post(S("system"), S("pathLoad"), 
      resource, accessFn#(copy of ac));
    wrap cachePathReadObj as resource;
    call newRM.post(S("system"), S("pathReadObj"), 
      resource, accessFn#(copy of ac));
    new rmList;
    insert newRM into rmList;
    insert sysRManager#(copy of init.rm) into rmList;
    chainedRM <- sysRManager#((chainedSysRMInitFn#(
	  create of program#(cachePathLoad(S("chainedsysrm")))))
	  (rmList, init.rm));
  end block;
  
  -- if there are following commands run by root, they will have their
  -- rm replaced with our caching version
  init.rm := chainedRM;

  -- Now invoke the user program with the chained resource manager

  args := init.argv;
  block begin
    remove string from arg in args where (boolean#(integer#(position of arg) =
	    integer#1));
    progname <- charstring#(arg in args where (boolean#(integer#(
	    position of arg) = integer#1)));
  on (notFound)
    -- no command to run... must have been invoked for side-effect of
    -- chaning RM
    return init;
    exit done;
  end block;
  
  prog <- program#(cachePathLoad(progname));
  block declare
    proc: mainFn;
    userName: charstring;
    userRM: rManager;
  begin
    -- try the program as a main program first
    proc <- mainFn#(create of prog);
    -- yup... we need to give filtered access... decide on a user name
    block begin
      inspect entry in environ where (B(entry.variable = S("USER")))
      begin
	userName := entry.value;
      end inspect;
    on (NotFound)
      block begin
	inspect entry in environ where 
	      (B(entry.variable = S("LOGNAME"))) begin
	  userName := entry.value;
	end inspect;
      on (NotFound)
	userName := S("anonymous");
      end block;
    end block;
    userRM <- rManager#(userRMFn#(create of program#
	    (pathLoad(S("userrm"))))(userName, chainedRM));
    call proc(args, init.terminal, userRM);
    
  on (InterfaceMismatch)
    -- not a main program... try it as a sysMain program
    block declare
      sysProc: sysMainFn;
    begin
      sysProc <- sysMainFn#(create of prog);
      call sysProc(args, init.terminal, chainedRM);
    end block;
  end block;
  
  return init;

on exit(done)
  
end process
