awp8101@ritcv.UUCP (Andrew W. Potter) (02/09/88)
$Part3: $ File_is="MAKE.RNO" $ Check_Sum_is=625635744 $ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY X.! X.! MAKE version 1.1, April 1987 X.! Copyright (C) 1987 by Jesse Perry. X.! MAKE is in the public domain and may be freely distributed, X.! used, and modified, provided this notice is not removed. X.! X.! make.rno X.! This file is a tutorial introduction to MAKE. The HELP entry for X.! MAKE (MAKE.RNH) refers to this file. It says that the user can X.! print a file called MAKE$DOCUMENT for more information. This file X.! should therefore be RUNOFF'd and the logical name MAKE$DOCUMENT set X.! to be full pathname of the .MEM file. X.! X.nnm X.ps 58 X.lm 5 X.rm 75 X.sp 1 X.spr 4 X.fl bo X.be X.nfl space X.b 3 X.c X^*MAKE TUTORIAL\* X.b 1 X.ap X.c X^*Introduction\* X Large programs typically have more than one source file. Each source file Xis compiled separately. The resulting object files are then linked together Xto produce an executable image. A major advantage of this organization is that Xwhen changes are made, only the modified source files need to be re-compiled. XWhen making changes, however, it is easy to forget which source files have Xbeen modified. The MAKE program checks the modification date of each file Xto determine which files must be re-compiled. (The modification date is Xby default the file creation date. The file revision date is used if the X/REVISED qualifier is given.) X MAKE divides files into two classes; ^*targets\* and ^*prerequisites\*. XA target file is a file which is produced by some DCL command. A Xprerequisite file for a given target file is a file used as input by the Xcommand which produces the target file. For example, if you have a fortran Xfile called test.for, you can compile it with the FORTRAN command to get an Xobject file, test.obj. Then test.obj is the target file, and test.for is its Xprerequisite file, or equivalently, test.obj ^*depends on\* test.for. X Notice that a file can be both a target ^*and\* a prerequisite. Test.obj Xis a target file with prerequisite file test.for, but it is itself a Xprerequisite file for target test.exe. Also, a target may have more than Xone prerequisite file. For example, if test.for includes test.inc, then Xboth test.for and test.inc are prerequisites of test.obj. (Notice, test.inc Xis ^*not\* a prerequisite of test.for.) X.b 1 X.c X^*Dependency Statements\* X MAKE reads a ^*makefile\*, whose name you specify in the logical name XMAKE$DEFNAME, or on the command line using the /MAKEFILE qualifier. XThe makefile tells MAKE what target files you want kept up to date, and Xwhat prerequisite files each target file depends on. XThe makefile contains ^*dependency statements\* which describe Xwhat files depend on what other files, and give the commands needed Xto update each file when it is out of date with respect to any of its Xprerequisite files. A target file is ^*out of date\* with respect Xto a prerequisite file if the target file does not exist, or if its Xmodification date is ^*earlier\* than the modification date of the Xprerequisite file. X The following is a sample makefile which shows how to specify the Xexample given above, using MAKE. (Throughout this document, the sample Xmakefiles will be set off from ordinary text by "#-----"). X.b 1 X.nf X#----- Xtest.obj : test.for X fortran test.for X#----- X.f X This makefile contains a single ^*dependency statement\*. XThe statement says that file test.obj depends on file test.for, and that if Vtest.obj is out of date with respect to test.for, the command "fortran test.for X" Xshould be executed. The file test.obj is the ^*target\* of the dependency Xstatement. Test.for is the only prerequisite of test.obj. A dependency Xstatement must have at least one name in the target list (that is, before Xthe ':'). It may have any number of names in the prerequisite list (after Xthe ':'), and any number of command lines following the initial Xtarget/prerequisite line. The target name in a dependency statement must Xnot be indented. The command line(s) which follow the target line must each Xstart with at least one space or tab. This leading white space tells XMAKE that the line contains a command. X Suppose that in the above example, test.for contains an include statement to Ximport a file named stuff.inc. Then test.obj must depend on both test.for Xand stuff.inc, since if either file is modified, test.obj must be re-compiled Xto reflect the changes. A makefile expressing these dependencies is, X.b 1 X.nf X#----- Xtest.obj : test.for stuff.inc X fortran test.for X#----- X.f X.bl 1 XNotice that test.obj depends on stuff.inc; test.for ^*does not\*. X If test.for and subs.for are the source files for a program called Xtest.exe, then the makefile to keep test.exe up to date is, X.b 1 X.nf X#----- Xtest.exe: test.obj subs.obj X link test.obj, subs.obj Xtest.obj: test.for stuff.inc X fortran test.for Xsubs.obj: subs.for X fortran subs.for X#----- X.f X Comments in a makefile can help explain what is being done. XA MAKE comment starts with a '#' and stops at the end of the line. XThe above makefile, with some comments, is, X.b 1 X.nf X#----- X# Test.exe is produced from modules test.obj and subs.obj. Xtest.exe: test.obj subs.obj X link test.obj, subs.obj # link names .exe after first file X X# Test.obj depends on stuff.inc because test.for includes it. Xtest.obj: test.for stuff.inc X fortran test.for X X# Subs.obj depends only on subs.for. Xsubs.obj: subs.for X fortran subs.for X#----- X.f X MAKE does not, by default, update every target in the makefile. XIt updates only the targets which are specified on the command line. If no Xtargets are named on the command line, it updates the ^*first\* target that Xit finds in the makefile. If MAKE is run with no arguments, using the Xexample makefile just given, it will update test.exe. Since test.exe Xdepends on test.obj and subs.obj, MAKE must update these targets before Xit can update test.exe. So in this case, MAKE does update all the targets Xin the makefile, but only because the first target in the makefile depends Xon all the others. X Assume there is also a file called test.rno containing documentation for Xthe program test.exe. The runoff program converts a .rno file into Xa .mem file. Thus, test.mem depends on test.rno. This dependency can be Xadded to the makefile, so that MAKE will keep both the program and its Xdocumentation file up to date. The makefile to do this is, X.b 1 X.nf X#----- Xtest.exe: test.obj subs.obj X link test.obj, subs.obj Xtest.obj: test.for stuff.inc X fortran test.for Xsubs.obj: subs.for X fortran subs.for X Xtest.mem: test.rno X runoff test.rno X#----- X.f X.b 1 XUsing this makefile, the command "$ MAKE" will update test.exe, Xwhile the command "$ MAKE TEST.MEM" will update test.mem. XAny number of targets can be named on the command line, separated Xby commas. For example, the command to update both test.exe and test.mem Xis, "$ MAKE TEST.EXE, TEST.MEM". X.b 1 X.c X^*MAKE Macros\* X Let's consider a different example. Three files named first.for, Xsecond.for, and third.for are the source files for a program called Xlab5.exe. No include files are used. The makefile to maintain Xlab5.exe is, X.b 1 X.nf X#----- Xlab5.exe: first.obj second.obj third.obj X link /exe=lab5.exe first.obj, second.obj, third.obj Xfirst.obj: first.for X fortran first.for Xsecond.obj: second.for X fortran second.for Xthird.obj: third.for X fortran third.for X#----- X.f X.b 1 XThis makefile contains quite a bit of repetitive information. Make Xmacros can be used to reduce this repetition. MAKE translates two kinds of Xmacros. ^*Named macros\* allow arbitrary strings of text to be placed Xwherever they are needed. ^*Dependency macros\* provide a notation to Xrefer to the parts of a dependency statement. X Three dependency macros are automatically defined within each Xdependency statement. Each is identified by a single punctuation Xcharacter. The name of the Xcurrent target is given by the dependency macro '@'. The name of the Xcurrent target with its file type (e.g., .for, .obj, etc.) deleted Xis given by the dependency macro '_*'. The list of prerequisites Xof the current target is given by '?'. Each dependency macro is invoked Xby a '$' followed by the single character name of the macro. X The first dependency statement in the above makefile is, X.nf X.b 1 X#----- Xlab5.exe: first.obj second.obj third.obj X link /exe=lab5.exe first.obj, second.obj, third.obj X#----- X.b 1 X.f XThe target of this statement is lab5.exe. Throughout the rest of the Xstatement, the dependency macro '@' is defined as 'lab5.exe', and the Xdependency macro '_*' is defined as just 'lab5' (because the .exe is Xdeleted for the '_*' macro). The dependency macro '@' can be Xused to rewrite the command line of this statement: X.b 1 X.nf X#----- Xlab5.exe: first.obj second.obj third.obj X link /exe=$@ first.obj, second.obj, third.obj X#----- X.f X.b 1 XWhen MAKE processes the command line, it will replace the '$@' with X'lab5.exe'. Similarly, the other dependency statements in the makefile Xcan be re-written using the '_*' macro to produce, X.b 1 X.nf X#----- X # This makefile is exactly equivalent to the X # first makefile given for this example. X X# Within this statement, '$@' is defined to be 'lab5.exe'. Xlab5.exe: first.obj second.obj third.obj X link /exe=$@ first.obj, second.obj, third.obj X X# Within this statement, '$_*' is defined to be 'first'. X# So MAKE translates '$_*.for' into 'first.for'. Xfirst.obj: $_*.for X fortran $_*.for X X# Within this statement, '$_*' is defined to be 'second'. X# So MAKE translates '$_*.for' into 'second.for'. Xsecond.obj: $_*.for X fortran $_*.for X X# Within this statement, '$_*' is defined to be 'third'. X# So MAKE translates '$_*.for' into 'third.for'. Xthird.obj: $_*.for X fortran $_*.for X#----- X.f X Of course, $_* and $@ ^*cannot be used in the target part of a Xdependency statement\*, since the target part of the statement Xis what ^*defines\* these macros. For example, both dependency Xstatements in the following makefile are invalid: X.b 1 X.nf X#----- X$_*.obj: foo1.for X fortran foo1.for X$@: foo2.for X fortran foo2.for X#----- X.f X The example makefile can be further simplified using the '?' macro. XAs stated above, this macro is defined as the list of prerequisites Xof the dependency statement it is used in. The example makefile, with X$? used in all dependencies except the first, is, X.bl 1 X.nf X#----- Xlab5.exe: first.obj second.obj third.obj X link /exe=$@ first.obj, second.obj, third.obj Xfirst.obj: $_*.for X fortran $? Xsecond.obj: $_*.for X fortran $? Xthird.obj: $_*.for X fortran $? X#----- X.f X The '?' macro is a bit harder to use in the first dependency statement, Xbecause the arguments to link must be separated by commas. If we just Xreplace the link arguments with '$?', we get, X.bl 1 X.nf X#----- Xlab5.exe: first.obj second.obj third.obj X link /exe=$@ $? X#----- X.f X.bl 1 XMAKE will translate this dependency statement into, X.bl 1 X.nf X#----- Xlab5.exe: first.obj second.obj third.obj X link /exe=$@ first.obj second.obj third.obj X#----- X.f X.bl 1 XThis link command line will fail, because the arguments are not Xseparated by commas. The next idea is to append a comma to the Xuse of the '?' macro, just as '.for' was appended to the use of Xthe '_*' macro. That is, change the dependency statement to, X.bl 1 X.nf X#----- Xlab5.exe: first.obj second.obj third.obj X link /exe=$@ $?, X#----- X.f X.bl 1 XMAKE will expand this as, X.bl 1 X.nf X#----- Xlab5.exe: first.obj second.obj third.obj X link /exe=$@ first.obj, second.obj, third.obj, X#----- X.f X.bl 1 XThis is almost right -- notice that the comma was appended to ^*each\* Xname in the prerequisite list. Unfortunately, the comma appended to Xthe last filename will cause another link error. To get around this, Xif any single character is placed ^*between\* the '$' and the macro symbol X(in this case '?'), that character will be used as a ^*separator\* when XMAKE expands the macro. The most common separators are ',' and '+'. XUsing this feature, we can re-write the makefile as, X.bl 1 X.nf X#----- Xlab5.exe: first.obj second.obj third.obj X link /exe=$@ $,? Xfirst.obj: $_*.for X fortran $? Xsecond.obj: $_*.for X fortran $? Xthird.obj: $_*.for X fortran $? X#----- X.f X.bl 1 XMAKE will expand this makefile into precisely the original makefile. X This makefile uses all three dependency macros; '_*', '@', and '?'. XNonetheless, it still has a noticeable amount of repetition. The Xlast three dependency statements are identical, except for the names of Xtheir targets. As mentioned briefly above, MAKE allows a dependency Xstatement to have more than one name in its target list. When MAKE finds Xsuch a statement in a makefile, it creates a copy of the statement Xfor each name in the target list. Each copy has only one Xname in its target list, but is otherwise identical to the original Xstatement -- each has the same dependency list and command lines. We can Xtake advantage of this to compress the example makefile still further: X.bl 1 X.nf X#----- Xlab5.exe: first.obj second.obj third.obj X link /exe=$@ $,? Xfirst.obj second.obj third.obj: $_*.for X fortran $? X#----- X.f X.bl 1 XMAKE will expand the second dependency statement into three separate Xstatements, each with one target. It will then expand the macros in Xeach target to produce the original example makefile. X MAKE also allows user-defined macros called ^*named macros\*. A Xnamed macro is defined by a line containing the macro name, followed Xby an equal sign ('='), followed by the text for the definition. Once Xa named macro has been defined, it can be used like a dependency macro. XInstead of a single punctuation character, a named macro is referred Xto by its name, in parentheses, after the '$'. We can reduce the Xexample makefile further by defining a named macro for the various Xmodules of the lab5.exe program: X.bl 1 X.nf X#----- XLABMODULES = first.obj second.obj third.obj X Xlab5.exe: $(LABMODULES) X link /exe=$@ $,? X$(LABMODULES): $_*.for X fortran $? X#----- X.f X.bl 1 XThis makefile can be easily updated if a new module (say, fourth.obj) Xis added to lab5.exe. Only the definition of LABMODULES must change. XEverything else will be taken care of automatically by the macro and Xtarget expansion which MAKE performs. X MAKE expands each use of a named macro in the same way it expands Xeach use of a dependency macro. Text attached to the use of the macro X(e.g., the '.for' in '$_*.for') is attached to each name in the macro Xdefinition after the expansion. Also, a separator character can be inserted Xafter the '$' and before the '('. For example, the following makefile Xis exactly equivalent to the one just given: X.bl 1 X.nf X#----- XLABMODULES = first second third X Xlab5.exe: $(LABMODULES).obj X link /exe=$@ $,(LABMODULES).obj X$(LABMODULES).obj: $_*.for X fortran $? X#----- X.f X.bl 1 XThe trickiest part of this makefile is the use of LABMODULES in the Xlink command line, '$,(LABMODULES).obj'. MAKE expands this macro Xin two steps. First, it creates the list of names in the expansion by Xcopying the attached text ('.obj') after each name in the definition Xof LABMODULES. Then it appends the separator character ',' to every Xname except the last in the expansion list. X.bl 1 X.c X^*Default Rules\* X In the example makefile above, the second dependency statement tells XMAKE how to create each object file from its fortran source file. XThis is such a simple thing that it is inconvenient to have to specify Xit at all -- if we need to create an object file from ^*any\* fortran Xfile, we must use the fortran compiler to do it. MAKE can be told Xthis by a ^*default rule\*. A default rule tells MAKE how to Xcreate one particular kind of file from another kind. In this case, Xwe need a rule which specifies how to create a .obj file from a .for Xfile. The default rule for this is, X.bl 1 X.nf X#----- X_.for.obj: X fortran $_*.for X#----- X.f X The default rule statement has a syntax similar to a dependency statement. XIts "target" is just the source file type followed by the target Xfile type. Unlike a dependency statement, every default rule Xstatement must include at least one command line -- otherwise, the Xdefault rule is useless. XOrdinarily, no prerequisites are named in the default rule. XMAKE knows that the actual target (in this case, the .obj file) Xdepends on the source (.for) file, so it automatically makes the Xsource file a prerequisite of the target file. Since MAKE can infer Xwhat the target and prerequisite files are, all of the dependency macros Xare defined within each default rule statement. X In the example above, for instance, '$_*.for' is ^*not\* expanded into X'.for.for', as one might expect (since the target is '.for.obj', and Xtherefore the target without its .obj file type is '.for'). Instead, Xwhen MAKE needs to update an object file which is not a target of any Xdependency statement, and a fortran file with the same name exists, XMAKE will automatically create a dependency statement whose target is Xthe object file, and whose only prerequisite is the fortran file. The Xcommand line of the default rule, 'fortran $_*.for' will become the only Xcommand line of this new dependency. MAKE will then use the dependency Xstatement just like any other to update the object file. X Other prerequisites of a default rule Xcan be specified after the ':'. For example, if every fortran source Xfile includes a file called stuff.inc, the following default rule Xcan be used. X.bl 1 X.nf X#----- X_.for.obj: stuff.inc X fortran $_*.for X#----- X.f X A number of commonly used default rules are provided in the Xdefault rules file. MAKE reads this file before reading the Xmakefile. The default rules file name is given in the logical Xname MAKE$DEFRULE. If a rule is defined in the default rules Xfile, and re-defined in the makefile, the makefile definition Xwill be used. If a rule is defined several times, only the last Xdefinition which MAKE reads will be used. X.bl 1 X.c X^*Command Lines\* X Every MAKE statement can contain one or more DCL ^*command lines\* Xwhich are executed, in the order they are given, Xwhen the target of the statement is out of date with respect to any of Xits prerequisites. Command lines from the makefile are executed in Xa single sub-process which MAKE creates with Xthe same "context" as the user's process. This means that any symbols Xor logical names which are defined in the user's process are also defined Xin the MAKE sub-process, and thus can be used in command lines inside the Xmakefile. X When a command line is executed, MAKE checks to see if the command exits Xwith a status value indicating error. If a command signals an error, MAKE Xaborts, since the likeliest interpretation is that the current target cannot Xbe updated. If the command line is preceded by '-', MAKE will ignore the exit Xstatus, and continue executing even if an error occurs. (The MAKE command Xoption /IGNORE causes MAKE to ignore all command execution errors.) The Xfollowing makefile demonstrates the use of '-'. X.bl 1 X.nf X#----- Xtest.exe: test.obj X - del $@;_* X link $? X#----- X.f X.bl 1 XThe '-' is necessary because if the target file TEST.EXE does not exist, Xthe delete command will return an error status. MAKE should ignore Xthis error, if it occurs, because it is unimportant. X By default, MAKE prints each command line as it is executed. XIf the command line is preceded by '@', it will not be Xprinted when executed. The MAKE command option /SILENT suppresses Xprinting of all command lines. The following makefile uses '@' Xto print a message without displaying the command line responsible. X.bl 1 X.nf X#----- Xtest.exe: test.obj io.obj X link $,? X @ write sys\$output "TEST.EXE created, deleting objects." X - del $,?;_* X#----- X.f X.bl 1 X.c X^*Literal Characters\* X Notice the use of backslash in the makefile just given. This is the X"accept" character for make, as '__' is the accept character for RUNOFF. XIt tells MAKE that the character which follows it is not to have its usual Xsyntactic meaning, but should instead be treated like any ordinary character. XIn this case, it tells MAKE that the '$' in 'sys$output' does not indicate Xuse of a macro, but is just another character in the command line. X Another use of backslash is suggested by the same command line. The initial X'@' tells MAKE not to print the command line when it is executed. This Xis also the character which tells DCL to run a command file. To get Xthis second meaning, the '@' must be preceded by a backslash, which tells XMAKE that the '@' is part of the command line. X One further use of backslash is to continue long lines in makefiles. If a Xbackslash is found at the end of a line, MAKE deletes it and interprets the Xend of line as a blank. This is demonstrated in the following makefile. X.bl 1 X.nf X#----- Xtest.exe: file1.obj file2.obj file3.obj file4.obj file5.obj \ X file6.obj file7.obj file8.obj file9.obj file10.obj X link /exe=$@ $,? X#----- X.f $ GoSub Convert_File $ File_is="MAKEFILE.MAK" $ Check_Sum_is=1997041993 $ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY XCC_QUAL = XLINK_QUAL = X X# A macro to print messages for user. X XSAY = @write sys\$output X X# What to make by default. X Xstuff: make.hlb make.mem make.exe X`009$(SAY) "********** Everything is up to date **********" X`009purge X X# Modules needed to create make.exe X XMK_MOD = mkdate mkexit mkext mkfile mkmacro mkmain \ X`009mkscan mkshow mksub mkutil X X# How to create the make program. X Xmake.exe: $(MK_MOD).obj mkerrs.obj X`009$(SAY) "********** CREATING NEW VERSION **********" X`009-del $@;* X`009link $(LINK_QUAL) /exe=$* $?, c_opts/o X$(MK_MOD).obj: make.h X X# How to create the stand alone test programs. X Xext: exitast.exe Xsub: subproc.exe Xexitast.exe subproc.exe: $*.obj X`009link $*, c_opts/o X`009del $?;* Xexitast.obj: mkexit.c X`009cc /def=AST_STAND_ALONE /obj=$* $? Xsubproc.obj: mksub.c X`009cc /def=SUB_STAND_ALONE /obj=$* $? X X# How to make the help library. X Xmake.hlb: $*.hlp X`009lib/cre/help $* $* X X# Rule to create the help file. X X.rnh.hlp: X`009runo $? $ GoSub Convert_File $ File_is="MAKE_STARTUP.COM" $ Check_Sum_is=187269125 $ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY X$! X$! This is the startup file needed to for MAKE. X$! X$! This line must be modified to point to where you decide to place X$! MAKE and associated files. X$! X$ define/system/exec make_homedir DISK:[DIR] X$! X$ define/system make$defrule make_homedir:defrule.mak X$ define/system make$document make_homedir:make.mem X$! X$! Define the default file name for a Makefile. (Users can override X$! this by defining make$defname themselves. If undefined then X$! make will look for MAKE$DEFNAME.MAK in the current working dir.) X$! X$ define/system make$defname makefile.mak X$! $ GoSub Convert_File $ File_is="MKDATE.C" $ Check_Sum_is=1359303793 $ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY X/* XMAKE version 1.1, April 1987 XCopyright (C) 1987 by Jesse Perry. XMAKE is in the public domain and may be freely distributed, Xused, and modified, provided this notice is not removed. X Xmkdate.c XThis file contains the routines which deal with file modification Xdates, including the date caching routines. X*/ X X#include <fab.h> X#include <xab.h> X#include "make.h" X Xtypedef struct cache_entry { X`009struct cache_entry *ce_next; X`009DATE ce_filedate; X`009char ce_filename[1];`009/* will actually be longer than one */ X} CACHE_ENTRY; X Xstatic CACHE_ENTRY *Cacheptr; Xstatic int Cache_n_cmd; X X/* Determine the modify date of the named file and put the date in the Xbuffer pointed to by fdateptr. Return 0 for success, -1 if the date Xcannot be obtained. */ X Xget_file_date(fname, fdateptr) Xchar *fname; XDATE *fdateptr; X{ X`009int dstat; X`009int fnmdsc[2]; X X`009/* See if file is in file-date cache. */ X X`009if (Cache_n_cmd != Num_cmd_sent) { X`009`009clear_cache(); X`009`009Cache_n_cmd = Num_cmd_sent; X`009} else if (get_cache_date(fname, fdateptr) == 0) { X`009`009return (0); X`009} X X`009/* Since file not cached, we have to find it out. */ X X`009fnmdsc[0] = strlen(fnmdsc[1] = (int)fname); X`009if (Created) { X`009`009dstat = getfdate(fnmdsc, fdateptr, NULL, NULL, NULL); X`009} else { X`009`009dstat = getfdate(fnmdsc, NULL, fdateptr, NULL, NULL); X`009} X X`009/* If the date was found, add the file-date to the cache. */ X X`009if (ERRSTAT(dstat)) { X`009`009return (-1); X`009} else { X`009`009add_cache_date(fname, fdateptr); X`009} X`009return (0); X} X X/* See if a file-date is in the cache. */ X Xstatic Xget_cache_date(fname, fdateptr) Xchar *fname; XDATE *fdateptr; X{ X`009register CACHE_ENTRY *cptr; X X`009for (cptr = Cacheptr; cptr != NULL; cptr = cptr->ce_next) { X`009`009if (COMPARE(fname, cptr->ce_filename) == 0) { X`009`009`009if (fdateptr != NULL) { X`009`009`009`009fdateptr->date_lo = cptr->ce_filedate.date_lo; X`009`009`009`009fdateptr->date_hi = cptr->ce_filedate.date_hi; X`009`009`009} X#ifdef CACHE_DEBUG Xprintf("**** %s date found in cache.\n", fname); X#endif X`009`009`009return (0); X`009`009} X`009} X`009return (-1); X} X X/* Add a new file-date to the cache. */ X Xstatic Xadd_cache_date(fname, fdateptr) Xchar *fname; XDATE *fdateptr; X{ X`009register CACHE_ENTRY *cptr; X X`009cptr = (CACHE_ENTRY *)err_alloc(sizeof(CACHE_ENTRY) + strlen(fname)); X`009strecpy(fname, cptr->ce_filename); X`009cptr->ce_filedate.date_lo = fdateptr->date_lo; X`009cptr->ce_filedate.date_hi = fdateptr->date_hi; X X`009cptr->ce_next = Cacheptr; X`009Cacheptr = cptr; X X#ifdef CACHE_DEBUG Xprintf("**** %s date added to cache.\n", fname); X#endif X`009return (0); X} X X/* Empty the cache -- a command has been executed, so any Xor all of the cached file-dates may be wrong. */ X Xstatic Xclear_cache() X{ X`009register CACHE_ENTRY *cptr, *nextptr; X X`009for (cptr = Cacheptr; cptr != NULL; cptr = nextptr) { X`009`009nextptr = cptr->ce_next; X`009`009free(cptr); X`009} X`009Cacheptr = NULL; X#ifdef CACHE_DEBUG Xprintf("**** Cache cleared.\n"); X#endif X} X X/* Set the modification date of a file to the current time. */ X Xtouch_file(filename) Xchar *filename; X{ X`009int fnmdsc[2], currtime[2]; X X`009if (Verbose) { X`009`009printf("\r\nTouching %s\r\n", filename); X`009} X`009fnmdsc[0] = strlen(fnmdsc[1] = (int)filename); X`009currtime[0] = currtime[1] = 0;`009/* setfdate will fill in current time */ X`009if (Created) { X`009`009setfdate(fnmdsc, currtime, NULL, NULL, NULL); X`009} else { X`009`009setfdate(fnmdsc, NULL, currtime, NULL, NULL); X`009} X} X X/* Return TRUE if the date pointed to by depdptr is later than the date Xpointed to by targdptr. */ X Xout_of_date(depdptr, targdptr) XDATE *depdptr, *targdptr; X{ X`009return (depdptr->date_hi > targdptr->date_hi || X`009 (depdptr->date_hi == targdptr->date_hi && X`009 depdptr->date_lo > targdptr->date_lo)); X} X X/* Print the ascii version of a file date. */ X Xprintdate(bindate) Xregister DATE *bindate; X{ X`009STR_DESC date_desc; X`009char datebuf[ASCII_DATE_LEN]; X X`009if (bindate->date_lo == -1 && bindate->date_hi == -1) { X`009`009printf("<DATE UNAVAILABLE>"); X`009`009return (-1); X`009} X X`009date_desc.sd_len = ASCII_DATE_LEN; X`009date_desc.sd_str = datebuf; X`009datebuf[ASCII_DATE_LEN] = '\0'; X`009sys$asctim(NULL, &date_desc, bindate); X X`009printf(datebuf); X`009return (0); X} $ GoSub Convert_File $ Goto Part4