-- (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: @(#)root.pp	1.9 3/13/90

root: using (predefined, root, stdenv, cload, initFindFile, findFile, unix,
  pathload, common, main, pathreadobj, load, objectIO
#ifndef CGBOOT
  , terminalInits, terminalIO, libinit, cwd, initcwd
#endif
)

process ( initport: rootinitmessageQ )

declare
  capability: polymorph;
  init: root!rootinitmessage;
  std: stdenv!stdenv;
  unix: unix!unix;
  syspath: charstring;
  defpath: charstring;
  bindir: charstring;
  pathinit: initFindFile!initFindFileFn;
  defpathfinder: findfile!findfile_func;
  syspathfinder: findfile!findfile_func;
  pathloadfile: charstring;
  pathloadinit: pathload_init_func;
  pathreadinit: pathreadobj_init_func;
  progname: charstring;
  prog: main_func;
  stdioInit: stdio_server_function;
  stdioProgName: charstring;

begin 
  block begin
    receive init from initport;	-- receive our initial connection
				--  to the world.
  on (disconnected)
    exit done;
  end block;
  
  new std;

  call init.cloader(charstring#"Load", capability);
  unwrap std.load from capability { init };
  call init.cloader(charstring#"Store", capability);
  unwrap std.store from capability { init };
--  call init.cloader(charstring#"Print", capability);
--  unwrap std.print from capability { init };
  call init.cloader(charstring#"Read Object", capability);
  unwrap std.readobj from capability { init };
  call init.cloader(charstring#"Write Object", capability);
  unwrap std.writeobj from capability { init };

  new unix;
  call init.cloader(charstring#"Access", capability);
  unwrap unix.access from capability { init };
  call init.cloader(charstring#"Unix", capability);
  unwrap unix.call from capability { init };
  call init.cloader(charstring#"Read External", capability);
  unwrap unix.r_external from capability { init };

-- set bindir, syspath, and defpath.
#define ENVIRON init.environ
#include "getpaths.pp"
 
-- create the "current working directory" process abstraction.  note that
-- when bootstrapping, absolute pathnames must be used since findfile will
-- be passed an uninit getCwd function.
#ifndef CGBOOT
  block 
    declare
      initCwd: initCwdFn;
    begin
      initCwd <- initCwdFn#( create of program#( std.load( charstring#(
        bindir | charstring#"/cwd.po" ))));
      call initCwd(init.directory, std.setCwd, std.getCwd);
  end block;
#endif

-- create the pathfinder
  pathinit <- initFindFileFn#(procedure of program#(
    std.load(charstring#(bindir | charstring#"/findfile.po"))));
  syspathfinder <- findfile_func#(pathinit(unix.access, std.getCwd, syspath));
  defpathfinder <- findfile_func#(pathinit(unix.access, std.getCwd, defpath));

-- load the pathloader
  pathloadfile <- charstring#(syspathfinder(charstring#"pathload.po", 
		  access#'read'));
  pathloadinit <- pathload_init_func#(create of 
		  program#(std.load(pathloadfile)));
  std.pathload <- load_func#(pathloadinit(std.load, syspathfinder));

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

#ifndef CGBOOT
-- Don't do this when bootstrapping, so as to keep the bootstrapped portion
-- to a minimum.


-- initialize the library output functions, libWriteObj and libStore

  block
    declare
      libWriteInit: initLibWriteObjectFn;
      libStoreInit: initLibStoreFn;
    begin

      libWriteInit <- initLibWriteObjectFn#(create of 
	  program#(std.pathLoad(charstring#"libwriteobj")));
      std.libWriteObj <- writeObject_Func#(
	  libWriteInit(std.writeObj, std.getCwd));

      libStoreInit <- initLibStoreFn#(create of 
	     program#(std.pathLoad(charstring#"libstore")));
      std.libStore <- StoreFunc#(libStoreInit(std.store, std.getCwd));

    end block; -- for libStore and libWriteObj creation      


-- load stdio.  if environment variable BLOCKINGIO is set, use the blocking
--  version of stdio so that we can run Hermes under dbx, etc.
  if boolean#( exists of e in init.environ where ( boolean#( e.variable =
	charstring#"BLOCKINGIO" ) ) ) then
    stdioProgName := charstring#"stdioblocking";
  else
    stdioProgName := charstring#"stdio";
  end if;

  stdioInit <- stdio_server_function#(create of program#(std.pathload(
	stdioProgName)));
  unix.stdio <- stdio#(stdioInit(unix.call, unix.r_external));

-- create the operating system-independent stream I/O functions for the
-- virtual terminal or I/O sources.

  block 
    declare
      initPutString: initPutStringFunc;
      initPutLine: initPutStringFunc;
      initGetString: initGetStringFunc;
      initGetChar: initGetCharFunc;
      initPutChar: initPutCharFunc;

    begin
      new std.terminal;

      initGetString <- initGetStringFunc#(create of program#(std.pathload(
	charstring#"getstring")));
      std.terminal.getString <- getStringFunc#(initGetString(unix.stdio.fgetc, 
	unix.stdio.stdin));

      initPutString <- initPutStringFunc#(create of program#(std.pathload(
	charstring#"putstring")));
      std.terminal.putString <- putStringFunc#(initPutString(unix.stdio.fputs, 
	unix.stdio.stdout));

      initPutLine <- initPutStringFunc#(create of program#(std.pathload(
	charstring#"putline")));
      std.terminal.putLine <- PutStringFunc#(initPutLine(unix.stdio.fputs, 
	unix.stdio.stdout));

      initGetChar <- initGetCharFunc#(create of program#(std.pathload(
	charstring#"getchar")));
      std.terminal.getChar <- getCharFunc#(initGetChar(unix.stdio.fgetc, 
	unix.stdio.stdin));

      initPutChar <- initPutCharFunc#(create of program#(std.pathload(
	charstring#"putchar")));
      std.terminal.putChar <- putCharFunc#(initPutChar(unix.stdio.fputc, 
	unix.stdio.stdout));

    on (others)
      print charstring#"Problems creating terminal I/O functions.";
      exit done;
  end block;

#endif

-- find the program the user wants to run and invoke it.
  progname <- charstring#( s in init.argv where ( boolean#( integer#(
	position of s) = integer#1 ) ) );
  prog <- main_func#(create of program#(std.pathload(progname)));
  call prog(init.argv, init.environ, std, unix, init.cloader);


on (InterfaceMismatch)
  print charstring#"Interfacing problems in root.";
on (load_intf.file_not_found, findfile_intf.file_not_found)
  print charstring#"File not found in root.";
on exit(done)
  
on (others)
  print charstring#"An random error has occurred in root!";

end process
