#
# $Id: main.icn,v 1.4 2006-07-10 01:25:13 rparlett Exp $
#
# This file is in the public domain.
#
# Author: Robert Parlett (parlett@dial.pipex.com)
#

link options

global symbol_table, debug, all_fileargs, opts

$define SEPARATOR "### Autogenerated dependencies"

procedure main(a)
   local e, fa, lines, project, t, s

   symbol_table := SymbolTable()

   opts := options(a, "-dbg!-r!-f:-p:-xs!-xi!-help!-nb!")

   if *a = 0 | \opts["help"] then {
      usage()
      exit(0)
   }

   debug := \opts["dbg"]

   all_fileargs := []

   every e := !a do {
      if \debug then
         write("Parsing " || e)
      fa := FileArg()
      fa.init1(e) | fail
      symbol_table.add_file_arg(fa)
      put(all_fileargs, fa)
   }

   if \debug then
      symbol_table.dump()

   every a := !all_fileargs do
      a.init2() 

   every a := !all_fileargs do
      a.init3() 

   every a := !all_fileargs do
      a.init4() 
      
   if \debug then
      write("doing final checks")

   every a := !all_fileargs do {
      a.check_for_unused_imports()
      a.circle_check() 
   }

   if \opts["r"] then {
      every fa := !all_fileargs do {
         write(fa.get_dependency_string())
      }
   } else {
      lines := []
      every fa := !all_fileargs do {
         put(lines, fa.get_makefile_string(opts))
      }
      #
      # Add one for the project, if required
      #
      if project := \opts["p"] then {
         t := project || " : "
         every fa := !all_fileargs do
            t ||:= " " || convert_filename(fa.file) | err("expected a .icn file:" || fa.file)
         put(lines, t)
      }
      if s := \opts["f"] then 
         output_to(s, lines)
      else {
         if stat("makefile") then
            output_to("makefile", lines)
         else if stat("Makefile") then
            output_to("Makefile", lines)
         else
            stop("No makefile to output to", lines)
      }         
   }

   return
end

#
# Find the FileArg with the given filename, or fail.
#
procedure find_filearg(file)
   local e
   every e := !all_fileargs do {
      if e.file == file then
         return e
   }
end

#
# Output the list of lines to the file s.
#
procedure output_to(s, lines)
   local top, f, t

   # Save up to separator from existing file
   top := []
   if s == "-" then
      f := &output
   else {
      if stat(s) then {
         f := open(s, "r") | stop("Couldn't open " || s)
         while t := read(f) do {
            if t == SEPARATOR then
               break
            put(top, t)
         }
         close(f)

         if /opts["nb"] then {
            # Save file as a backup
            rename(s, s || ".bak")
         }
      }
      f := open(s, "w") | stop("Couldn't open " || s)
   }
   every write(f, !top | SEPARATOR | !lines)
   close(&output ~=== f)
end

#
# Print usage info
#
procedure usage()
   write(&errout, "usage: unideps [OPTIONS] FILE...")
   write(&errout, "")
   write(&errout, "-dbg      produce debugging info")
   write(&errout, "-r        output dependency report, nothing else")
   write(&errout, "-f        specify name of makefile; - means stdout")
   write(&errout, "-p        specify a project target name, which will")
   write(&errout, "          depend on all input files")
   write(&errout, "-xi       produce dependencies to include files outside")
   write(&errout, "          of the set of input files")
   write(&errout, "-xs       produce dependencies to files outside the")
   write(&errout, "          set of input files which contain inherited")
   write(&errout, "          superclasses.")
   write(&errout, "-nb       don't create a backup of the existing file")
   write(&errout, "          being changed")
   write(&errout, "")
   write(&errout, "unidep takes a set of .icn files as input and produces a set of")
   write(&errout, "dependencies which ensure that the set of input files will be compiled")
   write(&errout, "in the correct order.  It also produces dependencies to any files")
   write(&errout, "which have been $included, and optionally to any files outside the")
   write(&errout, "input set which contain superclass definitions.  It does not produce")
   write(&errout, "dependencies based on link statements.")
   write(&errout, "")
   write(&errout, "The output is appended to any existing makefile in the current")
   write(&errout, "directory, but this behaviour may be changed with the -f flag.")
   write(&errout, "")
   write(&errout, "Any circular dependencies are reported as errors; they should")
   write(&errout, "be corrected by using the :: operator to remove one of the")
   write(&errout, "dependencies.")
end
