[comp.lang.icon] sh.icn : Shell Archive

TENAGLIA@mis.mcw.edu (Chris Tenaglia - 257-8765) (01/18/91)

Here's the icon shell archive utility. It's in shell archive format. I
would like comments and bug reports from unix sites. It tests out fairly
well under DOS and VMS.

Thanx,

Chris Tenaglia (System Manager) | Medical College of Wisconsin
8701 W. Watertown Plank Rd.     | Milwaukee, WI 53226
(414)257-8765                   | tenaglia@mis.mcw.edu, mcwmis!tenaglia

#!/bin/sh
# This is shar.sh, a shell archive (sh.icn 1.1)
# made Thursday, January 17, 1991  9:55 am by tenaglia@mis.mcw.edu
# Source directory /usr53/tenaglia/i/
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#    928 -rw-r--r-- sh.txt
#   7866 -rw-r--r-- sh.icn
#
# This is the icon Shell Archive Utility
#   *** The Next Generation ***
# Needs testing on unix systems.
# It seems to work fine on VMS and MS-DOS.
# Interested in your comments and/or bug reports.
# Thank you.
#
# ============== sh.txt ==============
if test X"$1" != X"-c" -a -f 'sh.txt'; then
	echo "File already exists: skipping 'sh.txt'"
else
echo "x - extracting sh.txt (Text)"
sed 's/^X//' << 'SHEOF' > sh.txt &&
X
XThis is a shell archive utility for non-unix hosts. It can extract from
Xshell archives (no overwrite checking done). It can list archives. And
Xit can create archives. No actual shell script interpretation is done.
XFor extraction it reads the important stuff and extracts the files. For
Xbuilding, it runs through an interactive dialog.
X
XExamples : sh termlib1.sh             Extracts by default
X           sh mystuff build           Builds mystuff.sh archive
X           sh mgale.sh list           Lists modules of mgale archive
X
XI've written it primarily for VMS and MS-DOS. I haven't tested the MS-DOS
Xpart yet. Also since I don't have unix out there, someone out there in
Xunixland can test it to make sure that what it builds is extractable.
X
XYours truly,
X
XChris Tenaglia (System Manager) | Medical College of Wisconsin
X8701 W. Watertown Plank Rd.     | Milwaukee, WI 53226
X(414)257-8765                   | tenaglia@mis.mcw.edu, mcwmis!tenaglia
X
SHEOF
true || echo "Restore of sh.txt failed."
set `wc -c sh.txt`;Wc_c=$1
if test "$Wc_c" != "928"; then
  echo original size 928, current size $Wc_c
fi
fi
# ============== sh.icn ==============
if test X"$1" != X"-c" -a -f 'sh.icn'; then
	echo "File already exists: skipping 'sh.icn'"
else
echo "x - extracting sh.icn (Text)"
sed 's/^X//' << 'SHEOF' > sh.icn &&
X##################################################################
X#                                                                #
X# SH.ICN  V1.1           01/14/91          BY TENAGLIA           #
X#                                                                #
X# PROGRAM HANDLES  UNIX SHELL ARCHIVES                           #
X# USAGE : sh archive [action] [target]                           #
X#         Where action is extract(default) list or build         #
X#         If action is list, target is ignored.                  #
X#         If action is extract (""), target is ignored           #
X#         If action id build, target is filespec to archive      #
X# NOTE :  Does not make split archives yet.                      #
X# NOTE :  Extraction doesn't check for overwrite, just does it.  #
X# NOTE :  shar 3.xx lengths include the leading X, and don't     #
X#         match here. This uses their real lengths.              #
X#                                                                #
X##################################################################
Xglobal os, files
Xprocedure main(param)
X  source := param[1]          | input("_Source:")
X  option := param[2]          | "extract"
X  target := param[3]          | "!nill"
X  work   := case option of
X    {
X    "list" : " Lister\n"
X    "build": " Builder\n"
X    default: " Extractor\n"
X    }
X  write("sh v1.1 : (Icon) Unix Shell Archive",work)
X  os     := getsys()
X  sum    := 0
X  find(".",source) | (os ~== "VMS") | (source ||:= ".sh")
X  if option == "build" then build(source)
X  (in    := open(source)) | stop(&line," : Can't open ",source)
X  while line := read(in) do
X    {
X    stuff := parse(line,'\"\'\t ')
X    if stuff[1] == "sed" & stuff[2] == "s/^X//" then
X      {
X      every i := 1 to *stuff do
X        {
X        if stuff[i] == "<<" then     { eof  := stuff[i+1] ; next }
X        if match("<<",stuff[i]) then { eof  := stuff[i][3:0] ; next }
X        if stuff[i] == ">>" then
X          {
X          name   := stuff[i+1]
X          method := "a"                # append
X          what   := "appended."
X          next
X          }
X        if match(">>",stuff[i]) then
X          {
X          name   := stuff[i][2:0]
X          method := "a"                # append
X          what   := "appended."
X          next
X          }
X        if stuff[i] == ">"  then
X          {
X          name   := stuff[i+1]
X          method := "w"                # create
X          what   := "written."
X          next
X          }
X        if match(">",stuff[i]) then
X          {
X          name   := stuff[i][2:0]
X          method := "w"                # create
X          what   := "written."
X          next
X          }
X        }
X      prog := extract(in,eof)
X      } else next
X    directory := if target == "!nill" then "" else target
X    (option == "list") |
X      (out := open(directory||name,method)) |
X        stop(&line," : Can't write ",name)
X    every stmt := !prog do
X      {
X      if option == "extract" then write(out,stmt)
X      sum +:= *stmt
X      }
X    if option == "extract"
X      then write(name," : ",sum," bytes ",what)
X      else write(name," : contains ",sum," bytes.")
X    sum := 0
X    (option == "list") | close(out)
X    }
X  close(in)
X  end
X
X#
X# This routine extracts the shell archive for a module. It returns
X# the module in a list structure.
X#
Xprocedure extract(file,eofstr)
X  lst := []
X  until match(eofstr,(str := read(file))) do
X    put(lst,str[2:0])
X  return lst
X  end
X
X#
X# This routine builds a shell archive. archive is the archive to be made.
X# The rest of this is interactive.
X#
Xprocedure build(archive)
X  username  := input("Username  :")
X  directory := input("Directory :")
X  if (os=="MS-DOS") then
X    (directory[-1] == "\\") | (directory ||:= "\\")
X  modules   := table([])
X  find(".",archive) | (archive ||:= ".sh")
X  (output   := open(archive,"w")) | stop(&line," : Can't write to ",archive)
X  comments  := ["#"] ; write("Enter Comments (blank line when done)")
X  repeat {
X  comment := input("Comment :")
X  if trim(comment) == "" then break
X  put(comments,"# " || comment) }
X  put(comments,"#")
X  begin := list()
X  put(begin,"#!/bin/sh")
X  put(begin,"# This is " || archive || ", a shell archive (sh.icn 1.1)")
X  put(begin,"# made " || &dateline  || " by " || username)
X  put(begin,"# Source directory "   || fsmap(directory))
X  put(begin,"#", "# existing files will Not be overwritten, hopefully","#")
X  put(begin,"# This shar contains:")
X  put(begin,"# length  mode       name")
X  put(begin,"# ------ ---------- ------------------------------------------")
X  namelist := []
X  repeat {
X  name := input("File (blank when done) :")
X  if trim(name) == "" then break
X  (infile := open(directory||name)) | { write("Can't open ",directory,name) ; next }
X  code := [ "# ============== " || name || " ==============",
X            "if test X\"$1\" != X\"-c\" -a -f '" || name || "'; then",
X            "	echo \"File already exists: skipping '"  || name || "'\"",
X            "else",
X            "echo \"x - extracting " || name || " (Text)\"",
X			"sed 's/^X//' << 'SHEOF' > " || name || " &&" ]
X  measure := 0
X  while text := read(infile) do
X    {
X    measure +:= *text
X    put(code,"X" || text)
X    }
X  put(code,"SHEOF")
X  put(code,"true || echo \"Restore of " || name || " failed.\"")
X  put(code,"set `wc -c " || name || "`;Wc_c=$1")
X  put(code,"if test \"$Wc_c\" != \"" || measure || "\"; then")
X  put(code,"  echo original size " || measure || ", current size $Wc_c")
X  put(code,"fi")
X  put(code,"fi")
X  close(infile)
X  put(begin,"# " || right(measure,6) || " -rw-r--r-- " || name)
X  insert(modules,name,copy(code)) ; put(namelist,name) }
X  output := open(archive,"a")
X  every write(output,!begin)
X  every write(output,!comments)
X  every file := !namelist do every write(output,!(modules[file]))
X  write(output,"#")
X  write(output,"# End of sh archive.")
X  close(output)
X  stop("sh archive written to ",archive)
X  end
X
X#
X# This routine parses a string with respect to some delimiter.
X# It returns the tokens in a list structure.
X#
Xprocedure parse(line,delims)
X  static chars
X  chars  := &cset -- delims
X  tokens := []
X  line ? while tab(upto(chars)) do put(tokens,tab(many(chars)))
X  return tokens
X  end
X
X#
X# This routine prompts for a string input. The entered string is returned.
X#
Xprocedure input(prompt)
X  writes(prompt)
X  return read()
X  end
X
X#
X# This procedure determines the os by examining &features.
X#
Xprocedure getsys()
X  files := "DIR "             # most logical initially
X  if &host == "MS-DOS" then
X    return &host
X  tmp := []
X  every feature := &features do
X    put(tmp,feature)
X  if tmp[1] ~== "VMS" then files := "ls "
X  return tmp[1]
X  end
X
X#
X# This routine maps the directory spec to unix style notation
X#
Xprocedure fsmap(spec)
X  if spec == "" then return spec
X  case os of
X    {
X    "VMS"    : { if (i := find(":",spec)) then
X                   {
X                   path := "/usr" || ord(spec[i-1]) || "/"
X                   if (x := find("[",spec)) then
X                     {
X                     y := find("]",spec)
X                     path ||:= map(spec[x+1:y],".","/") || "/"
X                     } else path ||:= spec[i+1:0] || "/"
X                   } else {
X                   if (x := find("[",spec)) then
X                     {
X                     y := find("]",spec)
X                     path := map(spec[x+1:y],".","/") || "/"
X                     } else path ||:= spec || "/"
X                   }
X                 return path
X               }
X    "MS-DOS" : { if find(":",spec) then
X                   {
X                   path := "/usr" || ord(map(spec[1])) - 96 ||
X                           (map(spec[3:0],"\\","/") | "")
X                   } else {
X                   path := map(spec,"\\","/")
X                   }
X                 (path[-1] == "/") | (path ||:= "/")
X				 return path || " (MS-DOS " || spec || ")"
X               }
X    default  : { return spec }
X    }
X  end
X
SHEOF
true || echo "Restore of sh.icn failed."
set `wc -c sh.icn`;Wc_c=$1
if test "$Wc_c" != "7866"; then
  echo original size 7866, current size $Wc_c
fi
fi
#
# End of sh archive.