[MLton] commit r4020: reran tab expansion using expand

Stephen Weeks sweeks@mlton.org
Sun, 21 Aug 2005 11:35:21 -0700


Reran the tab expansion on revision 4013, this time using the built-in
"expand" command, which correctly handles tabs that don't start at a
tab stop.  There were 257 files containing such tabs.

For the record, here's the script.

----------------------------------------------------------------------
structure List =
   struct
      open List

      fun exists (l, f) = List.exists f l
      fun map (l, f) = List.map f l
   end

structure String =
   struct
      open String

      fun hasSuffix (s, {suffix}) =
         Int.>= (size s, size suffix)
         andalso suffix = extract (s, size s - size suffix, NONE)
   end

val name = #file (OS.Path.splitDirFile (CommandLine.name ()))

fun die s =
   (TextIO.output (TextIO.stdErr, s)
    ; let open OS.Process in exit failure end)
   
val root =
   case CommandLine.arguments () of
      [dir] => dir
    | _ => die (concat ["usage: ", name, " <dir>"])

val numFiles = ref 0
val numFilesWithTabs = ref 0
val numTabs = ref 0

fun ++ x = x := 1 + !x

fun msg ss =
   if true then () else
   TextIO.output (TextIO.stdErr, concat [concat ss, "\n"])

val tab = CharVector.tabulate (8, fn _ => #" ")
   
fun replaceTabs (dir, f) =
   let
      val mode = Posix.FileSys.ST.mode (Posix.FileSys.stat f)
      val tmp = OS.FileSys.tmpName ()
      val () =
         if OS.Process.success
            = OS.Process.system (concat ["expand <", f, " >", tmp]) then
            ()
         else
            TextIO.output (TextIO.stdErr,
                           concat ["failed to expand: ",
                                   OS.Path.joinDirFile {dir = dir, file = f}])
      val () = OS.FileSys.rename {new = f, old = tmp}
      val () = Posix.FileSys.chmod (f, mode)
   in
      ()
   end

val replaceSuffixes =
   List.map
   (["c", "cm", "doc", "el", "fun", "grm", "h", "lex", "mlb", "sig", "sml",
    "tex", "txt"],
    fn s => concat [".", s])

fun shouldReplace (dir, f) =
   (dir = "./bin" andalso f <> "Makefile")
   orelse List.exists (["changelog", "README", "README.Debian", "README.kit"],
                       fn f' => f = f')
   orelse List.exists (replaceSuffixes, fn s =>
                       String.hasSuffix (f, {suffix = s}))

fun handleFile (dir, f) =
   let
      val () = ++numFiles
      val isAscii = ref true
      val hasTab = ref false
      val hasStrangeTab = ref false
      val numTabsInFile = ref 0
      val ins = TextIO.openIn f
      fun loop (filePos, column) =
	 case TextIO.input1 ins of
	    NONE => ()
	  | SOME c =>
	       if not (Char.isAscii c)
		  then isAscii := false
	       else
		  let
		     val () =
			if c = #"\t" then
                           (++numTabsInFile
                            ; hasTab := true
                            ; if 0 = column mod 8 then ()
                              else hasStrangeTab := true)
			else ()
		  in
		     loop (filePos + 1, if c = #"\n" then 0 else column + 1)
		  end
      val () = loop (0, 0)
      val () = TextIO.closeIn ins
      val fullPath = OS.Path.joinDirFile {dir = dir, file = f}
      val () =
	 if not (!isAscii) then ()
	 else if !hasTab then
            (++numFilesWithTabs
             ; (if shouldReplace (dir, f) then replaceTabs (dir, f)
                else (print (concat ["skipping ", fullPath, "\n"]))))
	 else ()
   in
      ()
   end

fun loop (dir, path) =
   let
      val () = msg ["entering ", dir]
      open OS.FileSys
      val saved = getDir ()
      val () = chDir dir
      val ds = openDir "."
      val path = OS.Path.joinDirFile {dir = path, file = dir}
      fun loop' () =
	 case readDir ds of
	    NONE => ()
	  | SOME s =>
	       let
		  val () =
		     case s of
			"." => ()
		      | ".." => ()
                      | ".svn" => ()
		      | _ =>
			   if isDir s then loop (s, path)
			   else if isLink s then ()
			   else handleFile (path, s)
	       in
		  loop' ()
	       end
      val () = loop' ()
      val () = closeDir ds
      val () = chDir saved
      val () = msg ["leaving ", dir]
   in
      ()
   end

val () = loop (root, "")

val () =
   List.app
   (fn (s, r) =>
    print (concat [s, " = ", Int.toString (!r), "\n"]))
   [("numFiles", numFiles),
    ("numFilesWithTabs", numFilesWithTabs),
    ("numTabs", numTabs)]