[mercury-users] Problem with mmake

Richard A. O'Keefe ok at atlas.otago.ac.nz
Fri Jun 1 09:18:50 AEST 2001


	I didn't actually try it, but there's similar code using fstat() in the
	Mercury standard library which we tried and had to modify because it
	didn't work under MSVC.
	
	Also, they only provide _(f)stat() in their Win32 compiler.
	The version of the MSVC command-line compiler that is included
	in the .NET SDK doesn't support _(f)stat(), even though it does
	support the ISO C standard library routines.
	
Using the Microsoft web site is a curiously frustrating experience.
Amongst other things, the only hint I could find about what header(s)
to include came from the WinCE pages for Find*().  So the Windows code
below is believed to be *close* to correct but desperately needs to be
corrected by someone who has a Windows SDK to try it out.  You will not
that this code contains *no* POSIX functions, not even ones that MS say
they have.

	> Note that even if directories were not readable in UNIX, that would not
	> be a sufficient answer.  There are so *many* ways that the call to 'cat'
	> in mmake can break, and the mmfind program I posted deals with all of them
	> that I could think of.  For example, "echo *.d" is perfectly happy to
	> report dead links and files that are not readable, but "cat" is not happy
	> to copy them!
	
	But in that case "cat" will issue an error message, which is the right
	thing to do, given the design constraint that filename pattern "*.d" is
	reserved (in directories in which `mmake' is used without `--use-subdirs')
	for make dependency files.
	
There may be such a design constraint, but it is not stated in the
documentation.  If I compile a foobar.c or foobar.p or foobar.pl or
foobar.erl or foobar.scm or foobar.e or .... program, I do *not* expect
the compiler to go around stuffing unrelated zarkon.dat files into a
Makefile.  If I have a bunch of test cases, I certainly expect to be
able to have a tests.d directory with impunity so long as none of my
source files is tests.(anything).

	You didn't answer my earlier question about `--use-subdirs'.  Perhaps I
	can rephrase it: would making `--use-subdirs' the default provide an
	adequate solution to this problem for you?  Or is there some reason why
	you would continue to use `--no-use-subdirs'?
	
It's very simple:  the interface to the Mercury compilation system is
fiendishly complicated.  I assume that the default settings are well-
considered and adequately tested until proven otherwise, and change them
away from the defaults with *extreme* trepidation.  I'm not about to
mess with an option that I don't fully understand, and can't even *find*
again in the User's Guide.  (Is there something about TeXInfo that prevents
the User's Guide having an index?)  I'm reasonably happy with the way
Clean stuffs its working files in a 'Clean System Files' directory, although
I could wish they hadn't put spaces in the name.  Is that what it's about?

Here is mmfind.c again, with Windows-specific code enabled by /DMSVC.
Could someone please correct this?

/*  File   : mmfind.c
    Author : Richard A. O'Keefe
    Updated: 2001.06.01
    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.
    Caveat : The Windows version was written based on the documentation at
             http://msdn.microsoft.com/library/, and HAS NOT BEEN TESTED.
             The Unix version has been tested, but I do not have a Windows
             box to do any Windows testing on.

    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
*/

#ifdef MSVC

#include <Winbase.h>
#include <string.h>
typedef WIN32_FIND_DATA info_block;
#define dir_sep "\\"

int mmfind(
    char const *suffix,
    void (*handler)(char const *, info_block const *)
) {
    size_t suflen, namlen;
    HANDLE d;
    WIN32_FIND_DATA b;

    d = FindFirstFile("*.*", &b);
    if (d != INVALID_HANDLE_VALUE) {
	do {
	    DWORD a = b.dwFileAttributes &~ FILE_ATTRIBUTE_ARCHIVE;

	    if ((a == FILE_ATTRIBUTE_NORMAL || a == FILE_ATTRIBUTE_READONLY)
	     && (n = strlen(b.cFileName) > suflen
	     && 0 == strcmp(b.cFileName + (n-suflen), suffix)
	    ) {
		handler(b.cFileName, &b);
	    }
	} while (FindNextFile(d, &b) != 0);	    
	(void)FindClose(d);
    }
    return 0;
}

#else

#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
typedef struct stat info_block;
#define dir_sep "/"

int mmfind(
    char const *suffix,
    void (*handler)(char const *, info_block 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;
}

#endif

#ifdef MAIN

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

static char *directory = (char *)0;

static void handler(char const *name, info_block const *buf) {
    if ((directory == (char *)0 ? puts(name)
	: printf("%s" dir_sep "%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