summaryrefslogtreecommitdiff
path: root/Master/texmf-dist
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2012-03-12 23:40:01 +0000
committerKarl Berry <karl@freefriends.org>2012-03-12 23:40:01 +0000
commit09da414d5ff0230b79f8a5f7edcaa05f81e83adb (patch)
treee08f993f81230a42913b1d82ca43f6d608319d5c /Master/texmf-dist
parent6e97d979159e30694e7dab6f6697f6c6376984fa (diff)
new lua script checkcites (12mar12)
git-svn-id: svn://tug.org/texlive/trunk@25623 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist')
-rw-r--r--Master/texmf-dist/doc/support/checkcites/README101
-rw-r--r--Master/texmf-dist/doc/support/checkcites/checkcites-doc.pdfbin0 -> 219757 bytes
-rw-r--r--Master/texmf-dist/doc/support/checkcites/checkcites-doc.tex339
-rwxr-xr-xMaster/texmf-dist/scripts/checkcites/checkcites.lua673
4 files changed, 1113 insertions, 0 deletions
diff --git a/Master/texmf-dist/doc/support/checkcites/README b/Master/texmf-dist/doc/support/checkcites/README
new file mode 100644
index 00000000000..37a2b00d74c
--- /dev/null
+++ b/Master/texmf-dist/doc/support/checkcites/README
@@ -0,0 +1,101 @@
+checkcites.lua -- Version 1.0g from March 7, 2012.
+==================================================
+
+License
+-------
+
+Copyright 2012 Enrico Gregorio, Paulo Roberto Massa Cereda
+
+- Enrico dot Gregorio at univr dot it
+- cereda at users dot sf dot net
+
+This script is licensed under the LaTeX Project Public License.
+If you want to support LaTeX development by a donation, the best
+way to do this is donating to the TeX Users Group.
+
+About
+-----
+
+checkcites is a Lua script written for the sole purpose of detecting
+unused or undefined references from both LaTeX auxiliary or
+bibliography files. We use 'unused reference' to refer to the
+reference present the bibliography file -- with the '.bib'
+extension -- but not cited in the '.tex' file. The 'undefined
+reference' is exactly the opposite, that is, the items cited in the
+'.tex' file, but not present in the '.bib' file.
+
+The original idea came from a question posted in the TeX.sx community
+about how to check which bibliography entries were not used. We
+decided to write a script to check references. We opted for Lua,
+since it's a very straightforward language and it has an interpreter
+available on every modern TeX distribution.
+
+Installation
+------------
+
+1. Create a new directory named 'checkcites' inside the 'scripts'
+ directory of your TEXMF tree and copy the 'checkcites.lua' inside
+ the new directory. In TeX Live, the new directory would be:
+
+ texlive/<year>/texmf/scripts/checkcites
+
+2. Rebuild the filename databases with the proper distro tool,
+ e.g, running 'mktexlsr'.
+
+3. Create a symbolic link to the newly created script inside
+ the 'bin' directory of your TeX distro. In TeX Live, the
+ full path is:
+
+ texlive/<year>/bin/<arch>
+
+ For TeX Live:
+
+ Win32: make a copy of 'runscript.exe' inside the very same
+ location (i.e, 'bin/win32') and rename it to
+ 'checkcites.exe'.
+
+ Linux: create a symbolic link (i.e, 'ln -s') inside the 'bin'
+ directory, targeting the script set in #1. Name it
+ 'checkcites' and give it proper execute ('x') permission.
+
+Usage
+-----
+
+The script is pretty simple to use. The only requirement is a recent
+TeX distribution, such as TeX Live. Then run checkcites:
+
+$ checkcites
+
+It will print the script usage. The only required argument is the
+'.aux' file which is generated when you compile your '.tex' file.
+If your main document is named 'foo.tex', you will have a 'foo.aux'
+file too. To run the script on that file, go with:
+
+$ checkcites foo.aux
+
+checkcites allows an additional argument that will tell it how to
+behave. For example
+
+$ checkcites --unused foo.aux
+
+will make the script only look for unused references in your '.bib'
+file. The argument order doesn't matter, you can also run
+
+$ checkcites foo.aux --unused
+
+and get the same behaviour. Similarly, you can use
+
+$ checkcites --undefined foo.aux
+
+to make the script only look for undefined references in your
+'.tex' file. If you want checkcites to look for both unused and
+undefined references, go with
+
+$ checkcites --all foo.aux
+
+If no special argument is provided, --all is set as default.
+
+Official code repository
+------------------------
+
+http://github.com/cereda/checkcites
diff --git a/Master/texmf-dist/doc/support/checkcites/checkcites-doc.pdf b/Master/texmf-dist/doc/support/checkcites/checkcites-doc.pdf
new file mode 100644
index 00000000000..c99f2d71d52
--- /dev/null
+++ b/Master/texmf-dist/doc/support/checkcites/checkcites-doc.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/support/checkcites/checkcites-doc.tex b/Master/texmf-dist/doc/support/checkcites/checkcites-doc.tex
new file mode 100644
index 00000000000..e520b1085f0
--- /dev/null
+++ b/Master/texmf-dist/doc/support/checkcites/checkcites-doc.tex
@@ -0,0 +1,339 @@
+\documentclass[12pt,a4paper]{article}
+
+\usepackage[T1]{fontenc}
+\usepackage[utf8]{inputenc}
+
+\usepackage[english]{babel}
+
+\usepackage[margin=1in]{geometry}
+
+\usepackage[svgnames]{xcolor}
+\usepackage[colorlinks, linkcolor={blue}, urlcolor={blue}]{hyperref}
+
+\usepackage{tcolorbox}
+\tcbuselibrary{listings}
+
+\newcommand{\checkcites}{\texttt{checkcites}}
+\newcommand{\email}[1]{\small\texttt{#1}}
+\newcommand{\version}{Version 1.0g from March 7, 2012.}
+
+\newenvironment{infoblock}[1]
+ {\par\addvspace{\medskipamount}
+ \begin{tcolorbox}[colframe=DarkTurquoise,coltitle=black,fonttitle=\bfseries,title=#1]}
+ {\end{tcolorbox}\addvspace{\medskipamount}}
+
+\newenvironment{terminal}
+ {\par\addvspace{\medskipamount}
+ \begin{tcolorbox}[colframe=DarkTurquoise]}
+ {\end{tcolorbox}\par\addvspace{\medskipamount}}
+
+\title{The \checkcites\footnote{\version}\ \ script}
+\author{%
+ Enrico Gregorio\\\email{Enrico dot Gregorio at univr dot it}\\[3ex]
+ Paulo Roberto Massa Cereda\\\email{cereda at users dot sf dot net}%
+}
+\date{}
+
+\begin{document}
+
+\maketitle
+
+\tableofcontents
+
+\section{Introduction}
+\label{sec:intro}
+
+\checkcites\ is a Lua script written for the sole purpose of detecting
+unused or undefined references from both \LaTeX{} auxiliary or
+bibliography files. We use \emph{unused reference} to refer to the
+reference present the bibliography file --~with the \verb|.bib|
+extension~-- but not cited in the \verb|.tex| file. The
+\emph{undefined reference} is exactly the opposite, that is, the items
+cited in the \texttt{.tex} file, but not present in the \verb|.bib|
+file.
+
+The original idea came from a question posted in the
+\href{http://tex.stackexchange.com}{TeX.sx community} about
+\href{http://tex.stackexchange.com/questions/43276}{how to check which
+bibliography entries were not used}. We decided to write a script to
+check references. We opted for Lua, since it's a very straightforward
+language and it has an interpreter available on every modern \TeX\
+distribution.
+
+\begin{infoblock}{Attention!}
+\checkcites\ is known to run with the most recent \verb|texlua| and
+\verb|lua| interpreters. Unfortunately, the code is incompatible with
+interpreters prior to the Lua 5.1 language specification.
+\end{infoblock}
+
+\section{How the script works}
+\label{sec:howto}
+
+\checkcites\ uses the generated \verb|.aux| file to start the
+analysis. The first step is to extract all citations found, in the
+form of \verb|\citation{a}|. For every \verb|\citation| line found,
+\checkcites\ will extract the citations and add them to a table, even
+for multiple citations separated by commas, like
+\verb|\citation{a,b,c}|. Then the citations table has all duplicate
+values removed --~in other words, the table becomes a set. Let's call
+$A$ the set of citations.
+
+\begin{infoblock}{Attention!}
+If \verb|\citation{*}| is found, the script ends, mainly because all
+citations will be used in this case. We opted for ending the script
+instead of ignoring this step.
+\end{infoblock}
+
+At the same time \checkcites\ also looks for bibliography data, in the
+form of \verb|\bibdata{a}|. Similarly, for every \verb|\bibdata| line
+found, the script will extract the bibliography data and add them to a
+table, even if they are separated by commas, like
+\verb|\bibdata{d,e,f}|. The table has all duplicate values removed.
+
+\begin{infoblock}{Attention!}
+If no \verb|\bibdata| command is found, the script ends. There's
+nothing to do in this case.
+\end{infoblock}
+
+Now, \checkcites\ will extract all entries from the bibliography files
+found in the previous step. For every element in the bibliography data
+table, the script will look for entries like \verb|@BOOK|,
+\verb|@ARTICLE| and so forth --~we actually use pattern matching for
+this~-- and add their identifiers to a table. The script treats all
+\verb|.bib| files as if they were only one. After all files have been
+analyzed and all entries identifiers extracted, the table has all
+duplicate values removed. Let's call $B$ the set of bibliography
+entries.
+
+\begin{infoblock}{Attention!}
+If \checkcites\ cannot find a certain bibliography file --~that is, a
+\verb|.bib| file~-- the script ends. Make sure to put the correct
+name of the bibliography file in your \verb|.tex| file.
+\end{infoblock}
+
+Now we have both sets $A$ and $B$. In order to get all unused
+references in the \verb|.bib| files, we compute the set difference
+\[
+B - A = \{ x : x \in B, x \notin A \}.
+\]
+Similarly, in order to get all undefined references in the \verb|.tex|
+file, we compute the set difference
+\[
+A - B = \{ x : x \in A, x \notin B \}.
+\]
+If there are either unused or undefined references, \checkcites\ will
+print them in a list format. In Section~\ref{sec:usage} there's a more
+complete explanation on how to use the script.
+
+\section{Usage}
+\label{sec:usage}
+
+\checkcites\ is very easy to use. First of all, let's define two files
+that will be used here to explain the script usage. Here's our sample
+bibliography file \verb|example.bib|, with five fictional entries.
+
+\begin{tcblisting}{colframe=DarkTurquoise,coltitle=black,listing only,
+ title=Bibliography file, fonttitle=\bfseries,
+ listing options={columns=fullflexible,basicstyle=\ttfamily}}
+@BOOK{foo:2012a,
+ title = {My Title One},
+ publisher = {My Publisher One},
+ year = {2012},
+ editor = {My Editor One},
+ author = {Author One}
+}
+
+@BOOK{foo:2012b,
+ title = {My Title Two},
+ publisher = {My Publisher Two},
+ year = {2012},
+ editor = {My Editor Two},
+ author = {Author Two}
+}
+
+@BOOK{foo:2012c,
+ title = {My Title Three},
+ publisher = {My Publisher Three},
+ year = {2012},
+ editor = {My Editor Three},
+ author = {Author Three}
+}
+
+@BOOK{foo:2012d,
+ title = {My Title Four},
+ publisher = {My Publisher Four},
+ year = {2012},
+ editor = {My Editor Four},
+ author = {Author Four}
+}
+
+@BOOK{foo:2012e,
+ title = {My Title Five},
+ publisher = {My Publisher Five},
+ year = {2012},
+ editor = {My Editor Five},
+ author = {Author Five}
+}
+\end{tcblisting}
+
+The second file is our main \LaTeX{} document, \verb|document.tex|.
+
+\begin{tcblisting}{colframe=DarkTurquoise,coltitle=black,listing only,
+ title=Main document, fonttitle=\bfseries,
+ listing options={columns=fullflexible,basicstyle=\ttfamily}}
+\documentclass{article}
+
+\begin{document}
+
+Hello world \cite{foo:2012a,foo:2012c}, how are you \cite{foo:2012f},
+and goodbye \cite{foo:2012d,foo:2012a}.
+
+\bibliographystyle{plain}
+\bibliography{example}
+
+\end{document}
+\end{tcblisting}
+
+Open a terminal and run \verb|checkcites|:
+
+\begin{terminal}
+\begin{verbatim}
+$ checkcites
+\end{verbatim}
+\tcblower
+\begin{verbatim}
+checkcites.lua -- a reference checker script (v1.0g)
+Copyright (c) 2012 Enrico Gregorio, Paulo Roberto Massa Cereda
+
+Usage: checkcites.lua [--all | --unused | --undefined] file.aux
+
+--all Lists all unused and undefined references.
+--unused Lists only unused references in your 'bib' file.
+--undefined Lists only undefined references in your 'tex' file.
+
+If no flag is provided, '--all' is set by default.
+Be sure to have all your 'bib' files in the same directory.
+\end{verbatim}
+\end{terminal}
+
+If you don't have \checkcites\ installed with your \TeX\ distribution,
+you can run the standalone script \verb|checkcites.lua| with either
+\verb|texlua| or \verb|lua|. We recommend to use \verb|texlua|, as
+it's shipped with all the modern \TeX\ distributions:
+\begin{terminal}
+\begin{verbatim}
+$ texlua checkcites.lua
+\end{verbatim}
+\end{terminal}
+
+When you run \checkcites\ without providing any argument to it, the
+script usage will be printed, as seen in the previous output. The only
+required argument is the auxiliary file --~with the \verb|.aux|
+extension~-- which is generated when you compile your main \verb|.tex|
+file. For example, if your main document is named \verb|foo.tex|, you
+probably have a \verb|foo.aux| file too. Let's compile our sample
+document \verb|document.tex|:
+\begin{terminal}
+\begin{verbatim}
+$ pdflatex document.tex
+\end{verbatim}
+\end{terminal}
+
+After running \verb|pdflatex| on our \verb|.tex| file, there's now a
+\verb|document.aux| file in our work directory.
+
+\begin{tcblisting}{colframe=DarkTurquoise,coltitle=black,listing only,
+ title=Auxiliary file, fonttitle=\bfseries,
+ listing options={columns=fullflexible,basicstyle=\ttfamily}}
+\relax
+\citation{foo:2012a}
+\citation{foo:2012c}
+\citation{foo:2012f}
+\citation{foo:2012d}
+\citation{foo:2012a}
+\bibstyle{plain}
+\bibdata{example}
+\end{tcblisting}
+
+Now we can run \checkcites\ on the \verb|document.aux| file:
+
+\begin{terminal}
+\begin{verbatim}
+$ checkcites document.aux
+\end{verbatim}
+\tcblower
+\begin{verbatim}
+checkcites.lua -- a reference checker script (v1.0g)
+Copyright (c) 2012 Enrico Gregorio, Paulo Roberto Massa Cereda
+
+I found 4 citation(s).
+Great, there's only one 'bib' file. Let me check it.
+I found 5 reference(s).
+
+Unused reference(s) in your bibliography file(s): 2
+- foo:2012b
+- foo:2012e
+
+Undefined reference(s) in your TeX file: 1
+- foo:2012f
+\end{verbatim}
+\end{terminal}
+
+As we can see in the script output, \checkcites\ analyzed both
+\verb|.aux| and \verb|.bib| files and found two unused references in
+the bibliography file --~\verb|foo:2012b| and \verb|foo:2012e|~-- and
+one undefined reference in the document --~\verb|foo:2012f|.
+
+\checkcites\ allows a command line switch that will tell it how to
+behave. For example,
+
+\begin{terminal}
+\begin{verbatim}
+$ checkcites --unused document.aux
+\end{verbatim}
+\end{terminal}
+
+The \verb|--unused| flag will make the script only look for unused
+references in the \verb|.bib| file. The argument order doesn't matter,
+you can also run
+
+\begin{terminal}
+\begin{verbatim}
+$ checkcites document.aux --unused
+\end{verbatim}
+\end{terminal}
+
+The script will behave the same. Similarly, you can use
+
+\begin{terminal}
+\begin{verbatim}
+$ checkcites --undefined document.aux
+\end{verbatim}
+\end{terminal}
+
+The \verb|--undefined| flag will make the script only look for
+undefined references in the \verb|.tex| file. If you want \checkcites\
+to look for both unused and undefined references, run:
+
+\begin{terminal}
+\begin{verbatim}
+$ checkcites --all document.aux
+\end{verbatim}
+\end{terminal}
+
+If no special argument is provided, the \verb|--all| flag is set as default.
+
+\section{License}
+\label{sec:license}
+
+This script is licensed under the
+\href{http://www.latex-project.org/lppl/}{LaTeX Project Public
+License}. If you want to support \LaTeX{} development by a donation,
+the best way to do this is donating to the
+\href{http://www.tug.org/}{TeX Users Group}.
+
+\begin{infoblock}{Official code repository}
+\url{http://github.com/cereda/checkcites}
+\end{infoblock}
+
+\end{document}
diff --git a/Master/texmf-dist/scripts/checkcites/checkcites.lua b/Master/texmf-dist/scripts/checkcites/checkcites.lua
new file mode 100755
index 00000000000..c2271f28cc4
--- /dev/null
+++ b/Master/texmf-dist/scripts/checkcites/checkcites.lua
@@ -0,0 +1,673 @@
+#!/usr/bin/env texlua
+-- ******************************************************************
+-- checkcites.lua
+-- Copyright 2012 Enrico Gregorio, Paulo Roberto Massa Cereda
+--
+-- This work may be distributed and/or modified under the
+-- conditions of the LaTeX Project Public License, either version 1.3
+-- of this license or (at your option) any later version.
+--
+-- The latest version of this license is in
+-- http://www.latex-project.org/lppl.txt
+-- and version 1.3 or later is part of all distributions of LaTeX
+-- version 2005/12/01 or later.
+--
+-- This work has the LPPL maintenance status `maintained'.
+--
+-- The Current Maintainers of this work are the original authors.
+--
+-- This work consists of the file checkcites.lua.
+--
+-- Project page: http://github.com/cereda/checkcites
+-- ******************************************************************
+
+-- version and date, to be updated on each release/commit
+VERSION = "1.0g"
+DATE = "March 7, 2012"
+
+-- The following code adds a 'split' function to the string type,
+-- thanks to the codebase available here:
+-- http://lua-users.org/wiki/SplitJoin
+string.split = function(str, pattern)
+
+ pattern = pattern or "[^%s]+"
+
+ if pattern:len() == 0 then
+
+ pattern = "[^%s]+"
+
+ end
+
+ local parts = {__index = table.insert}
+
+ setmetatable(parts, parts)
+
+ str:gsub(pattern, parts)
+
+ setmetatable(parts, nil)
+
+ parts.__index = nil
+
+ return parts
+
+end
+
+-- In order to make our lives easier, we borrowed the following
+-- codes for implementing common set operations, available here:
+-- http://www.phailed.me/2011/02/common-set-operations-in-lua/
+function setFind(a, tbl)
+
+ for _,a_ in ipairs(tbl) do
+
+ if a_==a then
+
+ return true
+ end
+
+ end
+
+end
+
+-- This code returns a table containing the difference between
+-- the two other tables, also available here:
+-- http://www.phailed.me/2011/02/common-set-operations-in-lua/
+function setDifference(a, b)
+
+ local ret = {}
+
+ for _,a_ in ipairs(a) do
+
+ if not setFind(a_,b) then
+
+ table.insert(ret, a_)
+
+ end
+
+ end
+
+ return ret
+
+end
+
+-- Code to remove duplicates from a table array.
+function removeDuplicates(tb)
+
+ -- new table
+ local ret = {}
+
+ -- flag to spot new insertions
+ local flag
+
+ -- set local variables
+ local i
+ local k
+ local j
+ local l
+
+ -- iterate through the original table
+ for i, k in pairs(tb) do
+
+ -- at first, insert element
+ flag = true
+
+ -- iterate through the new table
+ for j, l in pairs(ret) do
+
+ -- if the element already exists
+ if k == l then
+
+ -- set flag to false, so the
+ -- new element won't be inserted
+ flag = false
+
+ end
+
+ end
+
+ -- if it's ok to insert
+ if flag then
+
+ -- insert new element
+ table.insert(ret, k)
+
+ end
+
+ end
+
+ -- return new table
+ return ret
+end
+
+-- This function opens and gets all data from the provided
+-- aux file.
+-- Return:
+-- * list of citations
+-- * list of bibfiles
+function getDataFromAuxFile(theAuxFile)
+
+ -- open a file handler
+ local fileHandler = io.open(theAuxFile,"r")
+
+ -- check if the handler is valid
+ if fileHandler then
+
+ -- create a local table for citations
+ local theCitations = {}
+
+ -- and a local reference to the bib file
+ local theBibFiles = {}
+
+ -- define local variables
+ local currentLine
+ local citation
+ local index
+ local theCitation
+ local theBibFile
+ local entry
+
+ -- now let's iterate through the lines
+ for currentLine in fileHandler:lines() do
+
+ -- if the citation matches, extract it
+ for citation in string.gmatch(currentLine, '\\citation{(.+)}') do
+
+ -- sanity check, in case it's an '*'
+ if citation ~= "*" then
+
+ -- break the citations list, in case of multiple
+ -- citations in the same \citation{}
+ local parts = string.split(citation, "[^,%s]+" )
+
+ -- for every entry in the citations list
+ for index, theCitation in pairs(parts) do
+
+ -- insert the reference
+ table.insert(theCitations, theCitation)
+
+ end
+
+ -- found a '*'
+ else
+
+ -- show message
+ print("I found a '*' citation, which means that all references will be used.\nI'm afraid I have nothing to do now.")
+
+ -- and abort the script
+ os.exit()
+
+ end
+
+ -- end of citation in current line
+ end
+
+ -- in the same current line, check if there's the
+ -- bibdata entry and extract it
+ for entry in string.gmatch(currentLine, '\\bibdata{(.+)}') do
+
+ -- break the bib files list, in case of multiple
+ -- files in the same \bibdata{}
+ local parts = string.split(entry, "[^,%s]+" )
+
+ -- for every entry in the bib files list
+ for index, theBibFile in pairs(parts) do
+
+ -- insert the file
+ table.insert(theBibFiles, theBibFile)
+
+ end
+
+ -- end of bib files in the current line
+ end
+
+ -- end of current line
+ end
+
+ -- close the file handler
+ fileHandler:close()
+
+ -- remove duplicated citations
+ theCitations = removeDuplicates(theCitations)
+
+ -- print a message about the citations
+ print("I found " .. #theCitations .. " citation(s).")
+
+ -- remove possible duplicated files
+ theBibFiles = removeDuplicates(theBibFiles)
+
+ -- if there are no bib files
+ if #theBibFiles == 0 then
+
+ -- show message
+ print("I couldn't find any bibliography files.\nI'm afraid I have nothing to do now.")
+
+ -- and abort the script
+ os.exit()
+
+ -- if there is only one bib file
+ elseif #theBibFiles == 1 then
+
+ -- show message
+ print("Great, there's only one 'bib' file. Let me check it.")
+
+ -- there are more bib files
+ else
+
+ -- show message
+ print("Oh no, I have to check more than one 'bib' file. Please wait.")
+
+ end
+
+ -- return both citations and bib files
+ return theCitations, theBibFiles
+
+ -- the file handler is invalid
+ else
+
+ -- print an error message
+ print("File '" .. theAuxFile .. "' does not exist or is unavailable. Aborting script.")
+
+ -- and abort the script
+ os.exit()
+
+ end
+
+-- end of function
+end
+
+-- This function opens and gets all data from all the available
+-- bib files.
+function getDataFromBibFiles(theBibFiles)
+
+ -- create a table to store the citations
+ local theReferences = {}
+
+ -- set local variables
+ local index
+ local theBibFile
+ local currentLine
+ local reference
+
+ -- iterate through all bib files
+ for index, theBibFile in pairs(theBibFiles) do
+
+ -- open the bib file
+ local fileHandler = io.open(theBibFile .. ".bib","r")
+
+ -- check if the handler is valid
+ if fileHandler then
+
+ -- iterate through every line of the bib file
+ for currentLine in fileHandler:lines() do
+
+ -- if a reference is found
+ for reference in string.gmatch(currentLine, '@%w+{(.+),') do
+
+ -- insert the reference
+ table.insert(theReferences, reference)
+
+ end
+
+ -- end current line
+ end
+
+ -- close the file handler
+ fileHandler:close()
+
+ -- bib file does not exist
+ else
+
+ -- error message
+ print("File '" .. theBibFile .. ".bib' does not exist. Aborting.")
+
+ -- abort script
+ os.exit()
+
+ end
+
+ -- end iteration through the bib files
+ end
+
+ -- remove duplicated references
+ theReferences = removeDuplicates(theReferences)
+
+ -- print message
+ print("I found " .. #theReferences .. " reference(s).")
+
+ -- return references
+ return theReferences
+
+-- end of function
+end
+
+-- This function show all the undefined references. It's very
+-- simple, it's a difference between two sets.
+function showUndefinedReferences(citations, references)
+
+ -- get all undefined references
+ local undefined = setDifference(citations, references)
+
+ -- print message
+ print("\nUndefined reference(s) in your TeX file: " .. #undefined)
+
+ -- if there are undefined references
+ if #undefined ~= 0 then
+
+ -- local variables
+ local index
+ local reference
+
+ -- iterate
+ for index, reference in pairs(undefined) do
+
+ -- and print
+ print("- " .. reference)
+
+ end
+
+ end
+
+-- end of function
+end
+
+-- This function show all the unused references. It's very
+-- simple, it's a difference between two sets.
+function showUnusedReferences(citations, references)
+
+-- get all undefined references
+ local unused = setDifference(references, citations)
+
+ -- print message
+ print("\nUnused reference(s) in your bibliography file(s): " .. #unused)
+
+ -- if there are unused references
+ if #unused ~= 0 then
+
+ -- local variables
+ local index
+ local reference
+
+ -- iterate
+ for index, reference in pairs(unused) do
+
+ -- and print
+ print("- " .. reference)
+
+ end
+
+ end
+
+-- end of function
+end
+
+-- This function parses the command line arguments and returns a
+-- bunch of info for us to use.
+-- Return:
+-- * an argument code
+-- * the filename
+-- * an action code
+function parseArguments(theArgs)
+
+ -- check if there are no arguments
+ if #theArgs == 0 then
+
+ -- return usage code
+ return 0, nil, nil
+
+ -- there is one argument
+ elseif #theArgs == 1 then
+
+ -- check if it's help
+ if theArgs[1] == "--help" then
+
+ -- return help code
+ return 1, nil, nil
+
+ -- check if it's version
+ elseif theArgs[1] == "--version" then
+
+ -- return version code
+ return 2, nil, nil
+
+ -- check if it's invalid
+ elseif string.sub(theArgs[1], 1, 1) == "-" then
+
+ -- return invalid code
+ return 3, nil, nil
+
+ -- it seems a clean argument
+ else
+
+ -- return it as a valid argument
+ return 4, theArgs[1], nil
+
+ -- end for one parameter
+ end
+
+ -- there are two arguments
+ elseif #theArgs == 2 then
+
+ -- check if both are valid
+ if ((theArgs[1] == "--all" or theArgs[1] == "--unused" or theArgs[1] == "--undefined") and string.sub(theArgs[2], 1, 1) ~= "-") or ((theArgs[2] == "--all" or theArgs[2] == "--unused" or theArgs[2] == "--undefined") and string.sub(theArgs[1], 1, 1) ~= "-") then
+
+ -- create an action code
+ local actionCode
+
+ -- check which one is the file name
+ if string.sub(theArgs[1], 1, 1) ~= "-" then
+
+ -- check for --all
+ if theArgs[2] == "--all" then
+
+ -- set the action code
+ actionCode = 0
+
+ -- check for --unused
+ elseif theArgs[2] == "--unused" then
+
+ -- set the action code
+ actionCode = 1
+
+ -- it's --undefined
+ else
+
+ -- set the action code
+ actionCode = 2
+
+ end
+
+ -- it's the first
+ return 4, theArgs[1], actionCode
+
+ else
+
+ -- check for --all
+ if theArgs[1] == "--all" then
+
+ -- set the action code
+ actionCode = 0
+
+ -- check for --unused
+ elseif theArgs[1] == "--unused" then
+
+ -- set the action code
+ actionCode = 1
+
+ else
+
+ -- it's --undefined
+ actionCode = 2
+
+ end
+
+ -- it's the second
+ return 4, theArgs[2], actionCode
+
+ end
+
+ else
+
+ -- return invalid code
+ return 3, nil, nil
+
+ end
+
+ else
+
+ -- more than two arguments, return usage code
+ return 0, nil, nil
+
+ end
+
+-- end of function
+end
+
+-- This function prints the script header.
+function printHeader()
+
+ -- print message
+ print("checkcites.lua -- a reference checker script (v" .. VERSION .. ")")
+ print("Copyright (c) 2012 Enrico Gregorio, Paulo Roberto Massa Cereda\n")
+
+-- end of function
+end
+
+-- This function prints the script usage
+function printUsage()
+
+ -- show message
+ print("Usage: " .. arg[0] .. " [--all | --unused | --undefined] file.aux\n")
+ print("--all Lists all unused and undefined references.")
+ print("--unused Lists only unused references in your 'bib' file.")
+ print("--undefined Lists only undefined references in your 'tex' file.\n")
+ print("If no flag is provided, '--all' is set by default.")
+ print("Be sure to have all your 'bib' files in the same directory.")
+
+-- end of function
+end
+
+function printHelp()
+
+ -- show message
+ print("checkcites.lua is a Lua script written for the sole purpose of")
+ print("detecting undefined/unused references from LaTeX auxiliary or")
+ print("bibliography files. It's very easy to use!\n")
+
+ -- print usage
+ printUsage()
+
+-- end of function
+end
+
+-- This function prints the script version.
+function printVersion()
+
+ -- print message
+ print("checkcites.lua version " .. VERSION .. " (dated " .. DATE .. ")")
+ print("You can find more information about this script in the official")
+ print("source code repository:\n")
+ print("http://github.com/cereda/checkcites\n")
+ print("checkcites.lua is licensed under the LaTeX Project Public License.")
+
+-- end of function
+end
+
+-- This function prints a message for invalid parameters.
+function printInvalid()
+
+ -- print message
+ print("Oh no, it seems you used an invalid argument.\n")
+
+ -- print usage
+ printUsage()
+
+-- end of function
+end
+
+-- This is our main function.
+function runMain(theArgs)
+
+ -- print the script header
+ printHeader()
+
+ -- set local variables
+ local argCode
+ local fileName
+ local actionCode
+
+ -- parse arguments and get the result
+ argCode, fileName, actionCode = parseArguments(theArgs)
+
+ -- check for usage
+ if argCode == 0 then
+
+ -- print usage
+ printUsage()
+
+ -- it's help
+ elseif argCode == 1 then
+
+ -- print help
+ printHelp()
+
+ -- it's version
+ elseif argCode == 2 then
+
+ -- print version
+ printVersion()
+
+ -- it's an invalid parameter
+ elseif argCode == 3 then
+
+ -- print invalid
+ printInvalid()
+
+ -- it's a valid operation
+ else
+
+ -- get data from aux
+ a, b = getDataFromAuxFile(fileName)
+
+ -- get data from bib
+ c = getDataFromBibFiles(b)
+
+ -- if there is an action code
+ if actionCode ~= nil then
+
+ -- it's --all
+ if actionCode == 0 then
+
+ -- do everything
+ showUnusedReferences(a,c)
+ showUndefinedReferences(a,c)
+
+ -- it's --unused
+ elseif actionCode == 1 then
+
+ -- only show unused
+ showUnusedReferences(a,c)
+
+ -- it's --undefined
+ else
+
+ -- only show undefined
+ showUndefinedReferences(a,c)
+
+ end
+
+ -- there's only one parameter, the file name,
+ -- so we set --all
+ else
+
+ -- show everything
+ showUnusedReferences(a,c)
+ showUndefinedReferences(a,c)
+
+ end
+
+ end
+
+-- end of function
+end
+
+-- run the main function
+runMain(arg)