3

Scenario

I have a bunch of standalone PSTricks files. Each of those files can be compiled by latex-dvips-ps2pdf-pdfcrop-pdftops to produce a PDF image. I have made a batch file to do latex-dvips-ps2pdf-pdfcrop-pdftops.

In my main input file, I will iterate through the PSTricks files. For each iteration, I check whether or not the corresponding PDF exists. If the corresponding PDF already exists, I check whether or not its time stamp is newer than that of its .tex file. Otherwise I will invoke \immediate\write18 mybatch.bat filename.tex to produce or re-produce the corresponding PDF file.

Question

Can (La)TeX compare the time stamps of two external files? Providing the complete working source code for my scenario above is preferred. :-)

Note: Actually I can make an external script to iterate through the PSTricks files and invoke this script only once from within the main input file. But I am interested in creating the hybrid solution.

4 Answers 4

8

I wrote the filemod package just for this task which I also need for the upcoming version of standalone. It requires pdf(La)TeX or Lua(La)TeX but doesn't work with Xe(La)TeX.

Basic Usage:

\Filemodcmp{<file 1>}{<file 2>}{<1 is newer>}{<2 is newer>}

There is also a fully expandable version called \filemodcmp and also macros to find the newest or oldest file from a given list.

4
  • Does it work with latex? Commented Jun 16, 2011 at 0:52
  • This seems very useful. Is this going to make it into the upcoming TexLive 2011 release in July? Commented Jun 16, 2011 at 2:40
  • @xport: It works with LaTeX and plainTeX, that's why I wrote (La)TeX. Commented Jun 16, 2011 at 6:48
  • @Peter: It is already in TeXLive 2010. TeXLive normally adds new CTAN packages within a week, except if it is frozen, which is the case now. However, the package is already out for a few month. Of course, if you talk about pre-packed and never updated versions of TeXLive like the one which comes with Ubuntu than you will need to wait for TL 2011. Commented Jun 16, 2011 at 6:53
7
\def\comparetimestamp#1#2{%
  \ifnum\pdfstrcmp{\pdffilemoddate{#1}}{\pdffilemoddate{#2}}<0
    \message{#1 is older than #2}%
  \fi}

Change the \message line to what you need. Not usable with XeLaTeX, only with (pdf)latex. It may give problems if there's a change in the time zone (for example when changing to or from DST) between runs, but this should not be a problem.

4
  • Very nice idea to use \pdfstrcmp for the comparison. I actually parsed the \pdffilemoddate to a date and time integer value which I compared in two steps... Commented Jun 15, 2011 at 23:25
  • @Martin: It has the same drawback as parsing the date, when the time zone changes, say from +01'00' to +02'00'.
    – egreg
    Commented Jun 16, 2011 at 8:29
  • I know, but in one compiler run the same time zone for all files should be returned, shouldn't it? Commented Jun 16, 2011 at 9:14
  • @Martin: not when the Daylight Saving Time starts or ends. That's twice a year, and only in one occasion the clock goes back. Not really a problem, I believe: the change happens when people usually are sleeping.
    – egreg
    Commented Jun 16, 2011 at 9:26
2

You could use luatex. ConTeXt wrapper mtxrun provides one such implementation based on timestamps

mtxrun --iftouched=file.tex,file.pdf --direct pdflatex file 

and one based on md5 sum

mtxrun --ifchanged=file.tex --direct pdflatex file

which creates a md5 sum for file.tex and run the command only if the md5 sum has changed. See the source code of mtxrun.lua for implementation. The relevant functions are:

function file.needs_updating(oldname,newname,threshold) -- size modification access change
    local oldtime = lfs.attributes(oldname, modification)
    local newtime = lfs.attributes(newname, modification)
    if newtime >= oldtime then
        return false
    elseif oldtime - newtime < (threshold or 1) then
        return false
    else
        return true
    end
end

function file.checksum(name)
    if md5 then
        local data = io.loaddata(name)
        if data then
            return md5.HEX(data)
        end
    end
    return nil
end

function file.loadchecksum(name)
    if md5 then
        local data = io.loaddata(name .. ".md5")
        return data and (gsub(data,"%s",""))
    end
    return nil
end

Rest is just a matter of wrapping them around user macros.

4
  • +1 for informing this capability in ConTeXt. But I am not using it now. Maybe someday. Commented Jun 15, 2011 at 22:10
  • ConTeXt can make use of LuaTeX? Commented Jun 15, 2011 at 22:11
  • @xport: you don't need to use ConTeXt to use this feature. As the example shows, you can run pdflatex using mtxrun. (There is a bug in the implementation of --iftouched, so only --ifchanged will work.
    – Aditya
    Commented Jun 15, 2011 at 22:12
  • @xport: ConTeXt is using LuaTeX (rather texlua symlink to luatex binary). I added the relevant lua code.
    – Aditya
    Commented Jun 15, 2011 at 22:13
1

This answer will have nothing to do with TeX, but I would like to point out that using the right tools greatly simplifies the solution. In this case, you should use make. There is a good manual on this tool here.

A very simple Makefile follows (it should be expanded further to fit good practices):

TARGETS = <list of targets to build> (GNU Make's wildcard and patsubst might help)

.PHONY: all clean

all: $(TARGETS)

%.pdf: %.tex
    <call your batch file or directly integrate commands here, $< stands for source name>

clean:
    $(RM) $(TARGETS)

Now just type make at any time and it will ensure the targets are up to date.

3
  • 1
    Yes. It is clearly preferable to use the right tool for the job. However, make isn't particularly good for using with latex, due to the need to rerun latex multiple times (with makeindex, bibtex, etc) interspersed. It takes quite a lot of effort to convince make to run latex enough times (but not too many). For simple jobs like converting figures, this isn't a problem (in fact I too use make for this myself), but for more sophisticated uses of latex, I would use something like rubber.
    – Lev Bishop
    Commented Jun 16, 2011 at 15:49
  • @Lev: It is not so hard. In my Makefiles I re-run LaTeX if any of the auxiliary files like .aux or .toc has changed. To do so, I compare the checksums of these files, which I keep in a separate file, before and after a LaTeX run. The list of auxiliary files can be obtained from the .log file (look for \openout lines). The workflow is then as follows: 1. Run LaTeX; 2. While (the checksum file is missing) OR (not all checksums match) Do { Obtain the list of auxiliary files; Compute and store new checksums; Run additional commands like MakeIndex; Run LaTeX }. Commented Jul 23, 2011 at 14:08
  • Sure, you can do it that way. But then you are not getting much benefit from using make and you may as well have written the logic you described using some proper scripting language (perl, python, etc) or rather than reinvent the wheel just stick with one of the preexisting solutions such as rubber or latexmk.
    – Lev Bishop
    Commented Jul 23, 2011 at 19:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .