[mercury-users] Problem with mmake

Richard A. O'Keefe ok at atlas.otago.ac.nz
Thu May 31 13:29:01 AEST 2001


Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
	If you don't use --use-subdirs, then Mmake does assume that anything named
	*.d in the current directory is a dependency file.  I don't think it is
	worth changing that assumption, since it would complicate the software,
	and it is easy to avoid, either by using --use-subdirs, or by naming your
	directories something different.
	
It's a bug.  It should be easy enough to fix.
I *don't* want to use --use-subdirs, and I don't see why I should have to
change a naming convention that has worked perfectly well for the last 20
years just because one program is a bit lazy about checking.

At Quintus we had a customer complain about [foo] trying to load a directory,
and I personally fixed the responsible code.  C'mon, it *can't* be hard
to fix this bug.  [Wait an hour.... I've fixed it.]

	Mmake should certainly issue a proper error message rather than just
	dumping the directory in binary.  However, Mmake just uses the system
	utility `cat'.  If `cat' is dumping the binary contents of directories,
	rather than reporting an error message to stderr, I'd consider that a bug
	in `cat'.

It is documented behaviour in UNIX ever since Version 6.

	I suggest you contact your OS vendor, and in the mean time
	install GNU cat (it's part of the GNU textutils package).
	
I can confidently predict that the OS vendor will refuse to "correct" a
program that works precisely as documented.

	On Solaris 2.7 (SunOS 5.7), /bin/cat seems to do the right thing for
	directories (i.e. it reports an error "cat: input error on foo.d:
	Invalid argument").  Which version of Solaris are you using?
	
Ever since NFS came out, SunOS and then Solaris have been consistently
inconsistent here.  *Local* directories are readable, *NFS* directories
are not.  I discovered this the hard way 15 years ago, when a certain
directory was readable on the server but not a client.  It has nothing
to do with 'cat'; _any_ program trying to open a directory on a local hard
disc for input will succeed, _any_ program trying to open an NFS-mounted
directory for input will fail.

Here is the simple fix.  

Change code like
                dvs="`echo *.dv`"
                if [ "$dvs" = "*.dv" ]; then
                        dvs=""
                fi

in mmake to
		dvs="`mmfind .dv`"	
with similar changes for deps and ds, and also change code like
                dvs="`echo Mercury/deps/*.dv`"
                if [ "$dvs" = "Mercury/deps/*.dv" ]; then
                        dvs=""
                fi
in mmake to
		dvs="`mmfind Mercury/deps .dv`"
with similar changes for deps and ds,
where mmfind is obtained by compiling the following file with -DMAIN:

/*  File   : mmfind.c
    Author : Richard A. O'Keefe
    Updated: 2001.05.31
    Purpose: Find readable plain-text files with a given suffix.
    Usage  : mmfind(suffix, handler); passes name and stat record to handler.
    Command: mmfind [dir] {suffix} writes file names one per line.
    Errors : function returns 0 for success, -1 for failure.
    Note   : file names beginning with '.' are not reported.
    Compile: with -DMAIN to get the command, otherwise you just get the fn.

    mmfind suffix
	reports all the file names in the current directory that
	- don't begin with "."
	- are strictly longer than suffix
	- end with suffix
	- can be opened for input
	- and are not directories.
    mmfind directory suffix
	does the same thing in directory; each output line has the form
	directory/filename
*/

#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

int mmfind(
    char const *suffix,
    void (*handler)(char const *, struct stat const *)
) {
    size_t suflen, namlen;
    DIR *d;
    struct dirent *f;
    struct stat b;    
    int fd;

    if (suffix == (char const *)0
     || handler == (void (*)(char const *, struct stat const *))0
    ) return errno = EINVAL, -1;

    d = opendir(".");
    if (d == 0) return -1;	/* errno set by opendir() */

    suflen = strlen(suffix);
    while ((f = readdir(d)) != (struct dirent *)0) {
	if (f->d_name[0] != '.'
	 && (namlen = strlen(f->d_name)) > suflen
	 && 0 == strcmp(f->d_name + (namlen - suflen), suffix)
	 && (fd = open(f->d_name, O_RDONLY, 0)) >= 0
	 && fstat(fd, &b) >= 0
	 && S_ISREG(b.st_mode)
	) {
	    handler(f->d_name, &b);
	}
    }
    (void)closedir(d);
    return 0;
}

#ifdef MAIN

#include <stdio.h>
#include <stdlib.h>

static char *directory = (char *)0;

static void handler(char const *name, struct stat const *buf) {
    if ((directory == (char *)0 ? puts(name)
	: printf("%s/%s\n", directory, name)
	) < 0
    ) {
	perror("/dev/stdout");
	exit(EXIT_FAILURE);
    }
}

int main(int argc, char **argv) {
    if (argc == 3) {
	directory = argv[1];
	if (chdir(directory) < 0) {
	    perror(directory);
	    return EXIT_FAILURE;
	}
	argv++, argc--;
    } else {
	if (argc != 2) {
	    fprintf(stderr, "Usage: %s SUFFIX\n", argv[0]);
	    return EXIT_FAILURE;
	}
    }
    if (mmfind(argv[1], handler) < 0) {
	perror(argv[0]);
	return EXIT_FAILURE;
    }
    if (fflush(stdout) != 0) {
	perror("/dev/stdout");
	return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

#endif
--------------------------------------------------------------------------
mercury-users mailing list
post:  mercury-users at cs.mu.oz.au
administrative address: owner-mercury-users at cs.mu.oz.au
unsubscribe: Address: mercury-users-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-users-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the users mailing list