############################################################################
#
#	File:     diskpack.icn
#
#	Subject:  Program to produce packing list for diskettes
#
#	Author:   Ralph E. Griswold
#
#	Date:     June 10, 1994
#
############################################################################
#
#   This file is in the public domain.
#
############################################################################
#
#   This program is designed to produce a list of files to fit onto
#   diskettes.  It can be adapted to other uses.
#
#   This program uses a straightforward, first-fit algorithm.
#
#   The options supported are:
#
#	-s i	diskette capacity, default 360000
#	-r i	space to reserve on first diskettes, default 0
#	-n s	UNIX-style file name specification for files to
#		be packed, default "*.lzh"
#
############################################################################
#
#  Requires:  UNIX
#
############################################################################
#
#  Links:  options
#
############################################################################

link options

procedure main(argl)
   local files, disksize, reserve, firstsize, thissize, file, size, flist
   local disk, left, opts, spec, wc, used, number


   files := table()				# table of files
 
   opts := options(argl, "s+r+n:")
   disksize := \opts["s"] | 360000		# diskette size
   reserve := \opts["r"] | 0			# reserved space on 1st
   firstsize := disksize - reserve		# available space on 1st
   spec := \opts["n"] | "*.lzh"			# files to pack

   wc := open("wc " || spec, "p")		# pipe to get sizes

   every !wc ? {				# analyze wc output
      tab(upto(&digits))
      tab(many(&digits))
      tab(upto(&digits))
      tab(many(&digits))
      tab(upto(&digits))
      size := integer(tab(many(&digits)))	# 3rd field has bytes
      tab(many(' '))
      file := tab(0)				# file name
      if file == "total" then break		# exit on summary line
      files[file] := size			# add information to table
      }

   number := 0					# diskette number
   thissize := firstsize			# space on this diskette

   while *files > 0 do {			# while files remain
      number +:= 1				# next diskette
      flist := sort(files, 4)			# list of files and sizes
      disk := []				# empty diskette
      left := thissize				# space left
      used := 0					# space used
      while size := pull(flist) do {		# get largest remaining size
         file := pull(flist)			# file name
         if size < left then {			# if it fits
            put(disk, file)			# put it on disk
            left -:= size			# decrement remaining space
            used +:= size			# increment space used
            delete(files, file)			# delete file from table
            }
         }
						# if nothing on disk, can't do
      if *disk = 0 then stop("*** can't fit on disks")
						# write heading information
      write("\ndiskette ", number, ": ", used, "/", disksize - thissize + left)
      every write(!disk)			# write file names
      thissize := disksize			# space on next diskette
      }

end
