--
--	Inmos Libraries
--	Copyright (C) 1988, 1989, 1990, 1991, 1993  Inmos Limited
--
--	This library is free software; you can redistribute it and/or
--	modify it under the terms of the GNU Lesser General Public
--	License as published by the Free Software Foundation; either
--	version 2 of the License, or (at your option) any later version.
--
--	This library is distributed in the hope that it will be useful,
--	but WITHOUT ANY WARRANTY; without even the implied warranty of
--	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
--	Lesser General Public License for more details.
--
--	You should have received a copy of the GNU Lesser General Public
--	License along with this library; if not, write to the Free Software
--	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
--

--** @module hostio

#COMMENT "Host i/o library, V1.5, 02/11/92"
#COMMENT "(c) Copyright INMOS Limited 1989"
#INCLUDE "hostio.inc"
#USE "splib.lib"
--{{{  so.popen.read
--* Perform a general purpose open file for reading.
--
-- This procedure performs the following actions: 1. An attempt is made
-- to open the file as given by filename ( so if there is no directory
-- part to filename the current directory will be tried ); 2. If the
-- attempt in 1 is not successful and there is no explicit directory
-- part to filename, the path is searched for the file.
--
-- @param fs from server
-- @param ts to server
-- @param filename a string with the name of the file to be opened.
--   There may be an explicit directory part to the file's name.
-- @param path.variable.name a string holding the name of a path
--   environment variable; there is a limit imposed on the number of
--   characters accepted from sp.getenv for the environment variable
--   contents: the limit is imposed by this routine and is given by 507
--   ( called path.string.size in the program text ).
-- @param open.type either spt.binary, for a file containing raw bytes
--   only or spt.text, for a file stored as text records separated by
--   newlines
-- @param full.len the number of characters in full.name if result is
--   spr.ok; undefined otherwise
-- @param full.name if result is spr.ok, [full.name FROM 0 FOR
--   full.len] is the name of the file that was successfully opened;
--   undefined otherwise.  full.name clearly should be at least as
--   large as filename.
-- @param stream.id if result is spr.ok, the identification number of
--   the stream associated with the file that was opened; undefined
--   otherwise
-- @param result spr.ok if a file was opened successfully; otherwise
--   some value indicating what went wrong: spr.bad.packet.size
--   (SIZE filename) > sp.max.openname.size or (SIZE
--   path.variable.name) > sp.max.getenvname.size spr.bad.name
--     null file name supplied spr.bad.type            invalid file
--   type specified spr.full.name.too.short (SIZE full.name) not large
--   enough to hold name of a file to open spr.buffer.overflow
--   length of environment string > 507 >=spr.operation.failed    the
--   open failed or could not read environment string - see hostio.inc
--   or iserver documentation for more details
PROC so.popen.read (CHAN OF SP fs, ts,
                    VAL []BYTE filename, path.variable.name,
                    VAL BYTE open.type,
                    INT full.len, []BYTE full.name,
                    INT32 stream.id, BYTE result)
  --{{{  history
  -- Author: G. Tozer, 17/05/88.
  -- drastically modified to create correct 'popen.file' spec. CON 21-Jul-88
  -- modified to return full.name CON 9-Aug-88
  -- Cleaned up comments and made ptr global since it has to be remembered
  -- from call to call of assemble.name SRH 29-May-90
  -- Bug fix TS/0138 to prevent the possibility of a truncated filename
  -- being used by sp.open.  Also allowed the failure results from sp.getenv
  -- to be results from this routine.  New version number is 1.1 ( it was 1.00
  -- previously ) SRH 29-May-90.
  -- Bug fix TS/0440 to check for angle brackets in possible directory
  -- specification on VAX. V1.2 SRH 25-June-90
  -- Increased the value of path.string.size from 256 ( which had been hard
  -- coded ) to 509. TS/1223. V1.3, 5-Apr-91 SRH
  -- Decreased the value of path.string.size from 509 to 507.  The value
  -- 509 had been a miscalculation on my part. TS/1293. V1.4, 10-Jun-91 SRH
  -- Abbreviation introduced for filename[i]. TS/1908.  V1.5 2-Nov-92  SRH
  --}}}

  --{{{  global declarations
  VAL path.string.size IS 507 : -- this is the limit of the number of
                                -- characters that sp.getenv can return
  INT ptr :
  --}}}

  --{{{  PROC test.for.directory
  PROC test.for.directory (VAL []BYTE filename, BOOL found.dir)
  
    -- This PROC detects if a directory spec is present in file name
    -- by looking for '<', '>', '[', ']', '\', '/', ':'
    -- (That covers VAX/VMS, IBMPC or NECPC, and SUN-Unix)
  
    IF
      IF i = 0 FOR (SIZE filename)
        VAL BYTE filename.char IS filename[i] :
        (filename.char = '<') OR (filename.char = '>') OR
        (filename.char = '[') OR (filename.char = ']') OR
        (filename.char = '/') OR (filename.char = '\') OR (filename.char = ':')
          found.dir := TRUE
      TRUE
        found.dir := FALSE
  :
  --}}}PROC test.for.directory
  --{{{  PROC concatenate
  PROC concatenate (INT length1, []BYTE string1, VAL []BYTE string2)
    --{{{  About concatenate
    -- This proc joins to strings together, by appending string2 to the end of
    -- string1. Note that if the total length of the new string would exceed
    -- SIZE string1, the string is truncated to SIZE string1 bytes.
    -- The length parameters give the respective string lengths.
    --}}}About concatenate
    IF
      (length1 < (SIZE string1)) AND ((SIZE string2) <> 0)
        INT bytes.to.copy:
        SEQ
          IF
            (length1 + (SIZE string2)) > (SIZE string1)
              bytes.to.copy := (SIZE string1) - length1
            TRUE
              bytes.to.copy := SIZE string2
          [string1 FROM length1 FOR bytes.to.copy] :=
                                             [string2 FROM 0 FOR bytes.to.copy]
          length1 := length1 + bytes.to.copy
      TRUE
        SKIP
  :
  --}}}PROC concatenate
  --{{{  PROC assemble.name
  PROC assemble.name (BOOL more.on.path,
                      VAL [path.string.size]BYTE path, VAL INT path.len,
                      VAL []BYTE filename,
                      INT full.len, []BYTE full.name)
    --{{{  What it does
    -- This assembles a filename consisting of an element from the path,
    -- followed by the filename.
    -- Returns 'more.on.path' FALSE if we've fallen off the end of the path.
    -- Note that path.len equal to zero should be taken account of.
    --}}}What it does
    INT start.ptr :
    SEQ
      full.len := 0
      --{{{  work out what the directory bit is (skipping preceding spaces)
      -- paths separated by a ';' or a space
      
      WHILE (ptr < path.len) AND ((path[ptr] = ';') OR (path[ptr] = ' '))
        ptr := ptr + 1
      
      start.ptr := ptr
      
      WHILE (ptr < path.len) AND (path[ptr] <> ';') AND (path[ptr] <> ' ')
        ptr := ptr + 1
      --}}}work out what the directory bit is (skipping preceding spaces)
      IF
        ptr = start.ptr
          more.on.path := FALSE
        TRUE
          SEQ
            more.on.path := TRUE
            concatenate (full.len, full.name,
                         [path FROM start.ptr FOR ptr - start.ptr])
            concatenate (full.len, full.name, filename)
            -- we must be careful to prevent full.name being a truncation
            -- in case the wrong file is opened; TS/0138 SRH 29/05/90
            IF
              (SIZE full.name) < ( (ptr - start.ptr) + (SIZE filename) )
                full.len := -1  -- to act as a flag of this situation
              TRUE
                SKIP
  :
  --}}}PROC assemble.name
  --{{{  main body
  IF
    (SIZE filename) > sp.max.openname.size
      result := spr.bad.packet.size
    (SIZE filename) = 0
      result := spr.bad.name
    (open.type <> spt.binary) AND (open.type <> spt.text)
      result := spr.bad.type
    (SIZE full.name) < (SIZE filename)  -- TS/0138 SRH 29/05/90
      result := spr.full.name.too.short
    TRUE
      --{{{  do some work
      SEQ
        full.len := 0
        concatenate (full.len, full.name, filename) -- this will not truncate
                                                    -- due to test above 29/05/90
        --{{{  try opening it straight off
        sp.open (fs, ts, [full.name FROM 0 FOR full.len], open.type, spm.input, stream.id, result)
        --}}}
        IF
          result = spr.ok
            SKIP
          (SIZE path.variable.name) <> 0
            BOOL found.dir:
            SEQ
              test.for.directory (filename, found.dir)
              IF
                NOT found.dir
                  --{{{  no directory in the file name - search the path
                  --{{{  variables
                  [path.string.size]BYTE path : -- the list of directories to be searched
                  INT  path.len :
                  BOOL more.on.path :
                  --}}}variables
                  SEQ
                    ptr := 0
                    --{{{  read the path environment variable
                    BYTE local.result :
                    SEQ
                      sp.getenv (fs, ts, path.variable.name, path.len, path, local.result)
                      more.on.path := (local.result = spr.ok)
                      IF  -- SRH 29/05/90
                        more.on.path
                          SKIP
                        TRUE
                          result := local.result  -- routine should now be left to terminate
                    --}}}read the path environment variable
                    WHILE (result <> spr.ok) AND more.on.path AND (full.len >= 0) -- cause
                      -- immediate termination on first occurrence of truncation of path and
                      -- filename 29/05/90
                      SEQ
                        assemble.name (more.on.path, path, path.len, filename,
                                       full.len, full.name)
                        IF
                          more.on.path AND (full.len > 0)  -- if full.len < 0 then full.name
                                                           -- contains a trucnation
                            --{{{  try opening the file
                            sp.open (fs, ts, [full.name FROM 0 FOR full.len],
                                     open.type, spm.input, stream.id, result)
                            --}}}
                          TRUE
                            SKIP
                    IF
                      full.len < 0 -- truncation occurred
                        SEQ
                          result := spr.full.name.too.short
                          full.len := 0
                      TRUE
                        SKIP
                  --}}}
                TRUE  -- there was a directory specified - no search
                  SKIP
          TRUE
            SKIP  -- leave result at whatever it is
      --}}}
  --}}}main body
:
--}}}
