structure AuxFile:
sig
val createMissingDirectories:
{auxfile: string, outdir: string, seen: StringSet.set}
-> bool * StringSet.set
val extractBibTeXLines: {auxfile: string, outdir: string} -> string list
end =
struct
fun stripPrefix prefix s =
if String.isPrefix prefix s then
SOME (Substring.extract (s, String.size prefix, NONE))
else
NONE
fun isInput (line, outdir) =
case stripPrefix "\\@input{" line of
NONE => NONE
| SOME rest =>
let
val subauxfile = Substring.string
(Substring.takel (fn c => c <> #"}") rest)
val subauxfile_abs =
PathUtil.abspath {path = subauxfile, cwd = SOME outdir}
in
SOME {subauxfile = subauxfile, subauxfile_abs = subauxfile_abs}
end
fun createMissingDirectories {auxfile, outdir, seen} =
let
val ins = TextIO.openIn auxfile
val seen = StringSet.add (seen, auxfile)
fun go (did, seen) =
case TextIO.inputLine ins of
NONE => (TextIO.closeIn ins; (did, seen))
| SOME line =>
case isInput (line, outdir) of
NONE => go (did, seen)
| SOME {subauxfile, subauxfile_abs} =>
if FSUtil.isFile subauxfile_abs then
let
val (did', seen) =
createMissingDirectories
{auxfile = subauxfile_abs, outdir = outdir, seen = seen}
in
go (did orelse did', seen)
end
else
let
val dir =
PathUtil.join2 (outdir, PathUtil.dirname subauxfile)
in
if FSUtil.isDirectory dir then go (did, seen)
else (FSUtil.mkDirRec dir; go (true, seen))
end
in
go (false, seen)
end
(* \citation, \bibdata, \bibstyle *)
fun extractBibTeXLines' {auxfile, outdir, revLines} =
let
val ins = TextIO.openIn auxfile
fun go revLines =
case TextIO.inputLine ins of
NONE => (TextIO.closeIn ins; revLines)
| SOME line =>
case isInput (line, outdir) of
SOME {subauxfile, subauxfile_abs} =>
if FSUtil.isFile subauxfile_abs then
let
val revLines =
extractBibTeXLines'
{ auxfile = subauxfile_abs
, outdir = outdir
, revLines = revLines
}
in
go revLines
end
else
go revLines
| NONE =>
let
val isBibTeXLine =
case stripPrefix "\\" line of
SOME s =>
(case
Substring.string
(Substring.takel
(fn c => Char.isAlpha c orelse c = #"@") s)
of
"citation" => true
| "bibdata" => true
| "bibstyle" => true
| _ => false)
| NONE => false
in
if isBibTeXLine then
( if Message.getVerbosity () >= 2 then
Message.info
("BibTeX line: "
^
Substring.string
(Substring.dropr Char.isSpace (Substring.full line)))
else
()
; go (line :: revLines)
)
else
go revLines
end
in
go revLines
end
fun extractBibTeXLines {auxfile, outdir} =
List.rev
(extractBibTeXLines' {auxfile = auxfile, outdir = outdir, revLines = []})
end;