#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  m3bundle.1 m3bundle.m3 m3makefile
# Wrapped by gnelson@nemesia.pa.dec.com on Wed Feb 10 12:08:37 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'm3bundle.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'m3bundle.1'\"
else
echo shar: Extracting \"'m3bundle.1'\" \(2137 characters\)
sed "s/^X//" >'m3bundle.1' <<'END_OF_FILE'
X.\" Copyright (C) 1992, Digital Equipment Corporation
X.\" All rights reserved.
X.\" See the file COPYRIGHT for a full description.
X.\"
X.\" Last modified on Tue Sep 22 08:32:25 PDT 1992 by mhb   
X.\"      modified on Tue Jul  7 13:15:26 PDT 1992 by muller
X.\"      modified on Sun Jun 21 14:04:31 PDT 1992 by gnelson
X.nh
X.TH M3BUNDLE 1
X.SH NAME
m3bundle \- package source files into M3 object
X
X.\"------------------------------------------------------------------------
X.SH SYNTAX
X.B m3bundle
X-name n -element e1 path1 [-element ei pathi]...
X
X.B m3bundle
X-FcmdFile
X
X.\"------------------------------------------------------------------------
X.SH DESCRIPTION
X
X.B m3bundle packages up arbitrary files so that their contents can be
retrieved by a Modula-3 program at runtime without accessing the file
system.  
X.B m3bundle 
works by generating an interface (.i3) and
implementation (.m3) file.  The implementation contains the bits from
the files that are being bundled; the interface provides a way to
access this information.
X
In the first form of the command above,
X
X   n        is the name of the source module to be produced by m3bundle
X   path_i   is the path name of a file to be bundled
X   e_i      is the name of the resulting text reader
X
That is, the command produces a Modula-3 interface n.i3 and module
n.m3 implementing "n".  The interface n.i3 has the form:
X
X   INTERFACE n;
X   IMPORT Bundle;
X   PROCEDURE Get(): Bundle.T;
X   END n;
X
A programmer can then use the Bundle interface to retrieve 
elements from the Bundle.T returned by Get.
X
The second form of the m3bundle command allows you to specify the
parameters in the file named cmdFile. This is needed when bundling
lots (i.e., hundreds) of files, since Unix imposes a limit on the size
of arguments to a shell command.
X
X
X.\"------------------------------------------------------------------------
X.SH AUTHOR OF OBJECT
X
Greg Nelson
X
Marc H. Brown added support for large files and revamped the internals.
X
XEric Muller added -F flag
X
X
X.\"------------------------------------------------------------------------
X.SH AUTHOR OF DOCUMENTATION
X
Greg Nelson and Paul Mcjones
X
X
END_OF_FILE
if test 2137 -ne `wc -c <'m3bundle.1'`; then
    echo shar: \"'m3bundle.1'\" unpacked with wrong size!
fi
# end of 'm3bundle.1'
fi
if test -f 'm3bundle.m3' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'m3bundle.m3'\"
else
echo shar: Extracting \"'m3bundle.m3'\" \(9963 characters\)
sed "s/^X//" >'m3bundle.m3' <<'END_OF_FILE'
X(* Copyright (C) 1992, Digital Equipment Corporation           *)
X(* All rights reserved.                                        *)
X(* See the file COPYRIGHT for a full description.              *)
X
X(* File: m3bundle.m3                                           *)
X(* Last modified on Thu Sep 24 15:27:34 PDT 1992 by kalsow     *)
X
X(* This module implements the "M3Bundle" command.  See its manpage
X   for details. *)
X
MODULE m3bundle EXPORTS Main;
X
IMPORT Rd, Wr, FileStream, Params, Thread, Fmt, Stdio, Text;
X<* FATAL Wr.Failure, Rd.Failure, Thread.Alerted *>
X
CONST 
X  MaxLineWidth = 75;   (* for readability *)
X  MaxBlock     = 2000; (* C limits on a TEXT constant *)
X
TYPE
X  ElementList = REF ARRAY OF Element;
X  Element = RECORD
X    name   : TEXT;
X    path   : TEXT;
X    base   : TEXT;
X    length : INTEGER;
X    blocks : INTEGER;
X  END;
X
VAR
X  elts   := NEW (ElementList, 20);
X  n_elts := 0;
X  module : TEXT := NIL;
X  wr     : Wr.T := NIL;
X  max_blocks := 0;
X
X(*--------------------------------------------------------- element sizes ---*)
X
PROCEDURE GetElementSizes (): BOOLEAN =
X  VAR rd: Rd.T;  ok := TRUE;
X  BEGIN
X    FOR i := 0 TO n_elts-1 DO
X      WITH z = elts[i] DO
X        TRY
X          rd := FileStream.OpenRead (z.path);
X          z.length := Rd.Length (rd);
X          z.blocks := (z.length + MaxBlock - 1) DIV MaxBlock;
X          z.base   := "E" & Fmt.Int (i);
X          max_blocks := MAX (max_blocks, z.blocks);
X          Rd.Close (rd);
X        EXCEPT Rd.Failure =>
X          wr := Stdio.stderr;
X          Out (Params.Get(0), ": cannot read file: ", z.path, "\n");
X          ok := FALSE;
X        END;
X      END;
X    END;
X    RETURN ok;
X  END GetElementSizes;
X
X(*------------------------------------------------------------- interface ---*)
X
CONST Intf =
X  "(* Generated by m3bundle; see its manpage. *)\n\n" &
X  "IMPORT Bundle;\n\n" &
X  "PROCEDURE Get(): Bundle.T;\n\n";
X
PROCEDURE WriteInterface () =
X  BEGIN
X    wr := FileStream.OpenWrite (module & ".i3");
X    Out ("INTERFACE ", module, ";\n");
X    Out (Intf, "END ", module, ".\n");
X    Wr.Close (wr);
X  END WriteInterface;
X
X(*---------------------------------------------------------------- module ---*)
X
CONST Mod_0 = 
X  "(* Generated by m3bundle; see its manpage. *)\n" &
X  "\n" &
X  "IMPORT Bundle, BundleRep, Text;\n";
X
CONST Mod_1 =
X  "IMPORT Thread, Wr, TextWr;\n";
X
CONST Mod_2 =
X  "\n" &
X  "TYPE T = Bundle.T OBJECT OVERRIDES get := LookUp END;\n" &
X  "\n" &
X  "VAR bundle: T := NIL;\n" &
X  "\n" &
X  "PROCEDURE Get(): Bundle.T =\n" &
X  "  BEGIN\n" &
X  "    IF (bundle = NIL) THEN bundle := NEW (T) END;\n" &
X  "    RETURN bundle;\n" &
X  "  END Get;\n" &
X  "\n" &
X  "PROCEDURE LookUp (<*UNUSED*> self: T;  element: TEXT): TEXT = \n" &
X  "  BEGIN\n" &
X  "    FOR i := 0 TO LAST (Names)-1 DO\n" &
X  "      IF Text.Equal (Names[i], element) THEN\n";
X
CONST Mod_3 =
X  "        IF Elements[i] = NIL THEN Elements[i] := GetElt (i) END;\n";
X
CONST Mod_4 =
X  "        RETURN Elements[i];\n" &
X  "      END;\n" &
X  "    END;\n" &
X  "    RETURN NIL;\n" &
X  "  END LookUp;\n" &
X  "\n";
X
CONST Mod_5 =
X  "PROCEDURE GetElt (n: INTEGER): TEXT =\n" &
X  "  <*FATAL Thread.Alerted, Wr.Failure *>\n" &
X  "  VAR wr := TextWr.New ();\n" &
X  "  BEGIN\n" &
X  "    CASE n OF\n";
X
CONST Mod_6 =
X  "    ELSE (*skip*)\n" &
X  "    END;\n" &
X  "    RETURN TextWr.ToText (wr);\n" &
X  "  END GetElt;\n" &
X  "\n";
X
CONST Mod_7 =
X  "\n" &
X  "BEGIN\n" &
X  "END ";
X
PROCEDURE WriteModule () =
X  BEGIN
X    wr := FileStream.OpenWrite (module & ".m3");
X    Out ("MODULE ", module, ";\n", Mod_0);
X    IF (max_blocks > 1) THEN Out (Mod_1) END;
X    Out (Mod_2);
X    IF (max_blocks > 1) THEN Out (Mod_3) END;
X    Out (Mod_4);
X    WriteNames ();
X    WriteElements ();
X    IF (max_blocks > 1) THEN
X      Out (Mod_5);
X      WriteGetElt ();
X      Out (Mod_6);
X    END;
X    WriteLiterals ();
X    Out (Mod_7, module, ".\n");
X    Wr.Close (wr)
X  END WriteModule;
X
PROCEDURE WriteGetElt () =
X  BEGIN
X    FOR i := 0 TO n_elts-1 DO
X      WITH z = elts[i] DO
X        IF (z.blocks > 1) THEN
X          Out ("    | ", Fmt.Int (i), " =>\n");
X          FOR j := 0 TO z.blocks-1 DO
X            Out ("        Wr.PutText (wr, ", BlockName (z.base, j), ");\n");
X          END;
X        END;
X      END;
X    END;
X  END WriteGetElt;
X
PROCEDURE WriteNames () =
X  VAR name: TEXT;
X  BEGIN
X    Out ("CONST Names = ARRAY [0..", Fmt.Int (n_elts), "] OF TEXT {\n");
X    FOR i := 0 TO n_elts-1 DO
X      IF (i > 0) THEN Out (",\n") END;
X      name := elts[i].name;
X      Out ("  \"");
X      FOR j := 0 TO Text.Length (name) - 1 DO
X        EVAL OutChar (Text.GetChar (name, j));
X      END;
X      Out ("\"");
X    END;
X    IF (n_elts > 0) THEN Out (",\n") END;
X    Out ("  NIL\n};\n\n");
X  END WriteNames;
X
PROCEDURE WriteElements () =
X  BEGIN
X    IF (max_blocks > 1)
X      THEN Out ("VAR Elements :=");
X      ELSE Out ("CONST Elements =");
X    END;
X    Out (" ARRAY [0..", Fmt.Int (n_elts), "] OF TEXT {\n");
X    FOR i := 0 TO n_elts-1 DO
X      IF (i > 0) THEN Out (",\n") END;
X      WITH z = elts[i] DO
X        IF (z.length <= 0) THEN
X          Out ("  \"\"");
X        ELSIF (z.blocks <= 1) THEN
X          Out ("  ", BlockName (z.base, 0));
X        ELSE (* fill it in at runtime by calling GetElt *)
X          Out ("  NIL (* ", BlockName (z.base, 0), " .. ");
X          Out (BlockName (z.base, z.blocks-1), " *)");
X        END;
X      END;
X    END;
X    IF (n_elts > 0) THEN Out (",\n") END;
X    Out ("  NIL\n};\n\n");
X  END WriteElements;
X
PROCEDURE WriteLiterals () =
X  VAR rd: Rd.T;
X  BEGIN
X    FOR i := 0 TO n_elts-1 DO
X      WITH z = elts[i] DO
X        rd := FileStream.OpenRead (z.path);
X        WriteLiteral (rd, z.base);
X        Rd.Close (rd);
X      END;
X    END;
X  END WriteLiterals;
X
PROCEDURE WriteLiteral (rd: Rd.T;  base: TEXT) =
X  <*FATAL Rd.EndOfFile*>
X  VAR width, bytes, blocks := 0;  ch: CHAR;
X  BEGIN
X    WHILE NOT Rd.EOF (rd) DO
X      IF (bytes = 0) THEN
X        (* start a new block *)
X        Out ("CONST ", BlockName (base, blocks), " = \n   \"");
X        INC (blocks);
X        width := 4;
X      ELSIF (width = 0) THEN
X        (* start a new line *)
X        Out (" & \"");
X        width := 4;
X      END;
X
X      (* write a character *)
X      ch := Rd.GetChar (rd);
X      INC (width, OutChar (ch));
X      INC (bytes);
X
X      IF (bytes >= MaxBlock) THEN
X        (* finish this block *)
X        Out ("\";\n\n");
X        bytes := 0;
X        width := 0;
X      ELSIF (width >= MaxLineWidth) THEN
X        (* finish this line *)
X        Out ("\"\n");
X        width := 0;
X      END;
X    END;
X
X    IF (width > 0) THEN (* finish the last string *) Out ("\"") END;
X    IF (bytes > 0) THEN (* finish the last block *)  Out (";\n\n") END;
X  END WriteLiteral;
X
PROCEDURE BlockName (base: TEXT;  block: INTEGER): TEXT =
X  BEGIN
X    IF (block = 0) THEN RETURN base END;
X    RETURN base & "_" & Fmt.Int (block - 1);
X  END BlockName;
X
X(*-------------------------------------------------- command line parsing ---*)
X
PROCEDURE ParseCommandLine (): BOOLEAN =
X  VAR next := 0;
X  PROCEDURE NextParam (): TEXT =
X    BEGIN
X      INC (next);
X      RETURN Params.Get (next);
X    END NextParam;
X  BEGIN
X    IF ParseOptions (NextParam) THEN RETURN TRUE END;
X    wr := Stdio.stderr;
X    Out ("usage: ", Params.Get (0), " -name n [-element e path] ...\n");
X    RETURN FALSE;
X  END ParseCommandLine;
X    
PROCEDURE ParseOptions (next_arg: PROCEDURE (): TEXT): BOOLEAN =
X  VAR arg: TEXT;
X  BEGIN
X    LOOP
X      arg := next_arg ();
X      IF (arg = NIL) THEN
X        RETURN TRUE;
X      ELSIF Text.Equal (arg, "-name") THEN
X        module  := next_arg ();
X        IF (module = NIL) THEN RETURN FALSE END;
X      ELSIF Text.Equal (arg, "-element") THEN
X        IF (n_elts > LAST (elts^)) THEN ExpandElts () END;
X        WITH z = elts[n_elts] DO
X          z.name := next_arg ();
X          z.path := next_arg ();
X          IF (z.name = NIL) OR (z.path = NIL) THEN RETURN FALSE END;
X        END;
X        INC (n_elts);
X      ELSIF Text.Equal (Text.Sub (arg, 0, 2), "-F") THEN
X        IF NOT ParseOptionFile (Text.Sub (arg, 2, LAST (CARDINAL))) THEN
X          RETURN FALSE;
X        END;
X      ELSE
X        RETURN FALSE;
X      END;
X    END;
X  END ParseOptions;
X
PROCEDURE ParseOptionFile (name: TEXT): BOOLEAN =
X  <* FATAL Rd.EndOfFile *>
X  VAR f := FileStream.OpenRead (name);  b: BOOLEAN;
X  PROCEDURE NextLine (): TEXT =
X    BEGIN
X      IF Rd.EOF (f) THEN RETURN NIL END;
X      RETURN Rd.GetLine (f);
X    END NextLine;
X  BEGIN
X    b := ParseOptions (NextLine);
X    Rd.Close(f);
X    RETURN b;
X  END ParseOptionFile;
X
PROCEDURE ExpandElts () =
X  VAR new := NEW (ElementList, 2 * NUMBER (elts^));
X  BEGIN
X    FOR i := 0 TO LAST (elts^) DO new[i] := elts[i] END;
X    elts := new;
X  END ExpandElts;
X
X(*--------------------------------------------------------- low-level I/O ---*)
X
PROCEDURE Out (a, b, c, d: TEXT := NIL) =
X  BEGIN
X    IF (a # NIL) THEN Wr.PutText (wr, a) END;
X    IF (b # NIL) THEN Wr.PutText (wr, b) END;
X    IF (c # NIL) THEN Wr.PutText (wr, c) END;
X    IF (d # NIL) THEN Wr.PutText (wr, d) END;
X  END Out;
X
PROCEDURE OutChar (ch: CHAR): INTEGER =
X  (* writes 'ch' as a literal and returns the output width *)
X  BEGIN
X    IF (ch = '\\') THEN
X      Wr.PutText (wr, "\\\\");
X      RETURN 2;
X    ELSIF (ch = '\n') THEN
X      Wr.PutText (wr, "\\n");
X      RETURN 2;
X    ELSIF (ch = '\'') THEN
X      Wr.PutText (wr, "\\\'");
X      RETURN 2;
X    ELSIF (ch = '\"') THEN
X      Wr.PutText (wr, "\\\"");
X      RETURN 2;
X    ELSIF (ch < ' ') OR (ch > '~') THEN
X      Wr.PutChar (wr, '\\');
X      PutC (ORD(ch) DIV 64);
X      PutC (ORD(ch) MOD 64 DIV 8);
X      PutC (ORD(ch) MOD 8);
X      RETURN 4;
X    ELSE
X      Wr.PutChar (wr, ch);
X      RETURN 1;
X    END;
X  END OutChar;
X
PROCEDURE PutC (i: INTEGER) =
X  BEGIN
X    Wr.PutChar (wr, VAL(ORD('0') + i, CHAR));
X  END PutC;
X
X(*------------------------------------------------------------- main body ---*)
X
BEGIN
X  IF ParseCommandLine () AND GetElementSizes () THEN
X    WriteInterface ();
X    WriteModule ();
X  END;
XEND m3bundle. 
END_OF_FILE
if test 9963 -ne `wc -c <'m3bundle.m3'`; then
    echo shar: \"'m3bundle.m3'\" unpacked with wrong size!
fi
# end of 'm3bundle.m3'
fi
if test -f 'm3makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'m3makefile'\"
else
echo shar: Extracting \"'m3makefile'\" \(560 characters\)
sed "s/^X//" >'m3makefile' <<'END_OF_FILE'
X/* Copyright (C) 1992, Digital Equipment Corporation                         */
X/* All rights reserved.                                                      */
X/* See the file COPYRIGHT for a full description.                            */
X/*                                                                           */
X/* Last modified on Thu Sep 10 09:16:47 PDT 1992 by mhb                     */
X/*      modified on Tue Feb 11 22:04:30 PST 1992 by gnelson                 */
X
ManPage        (m3bundle,1)
implementation (m3bundle)
Program        (m3bundle)
X
END_OF_FILE
if test 560 -ne `wc -c <'m3makefile'`; then
    echo shar: \"'m3makefile'\" unpacked with wrong size!
fi
# end of 'm3makefile'
fi
echo shar: End of shell archive.
exit 0
