I have had problems installing the VMS daemon 2.07 on a VMS platform.
I think I have solved this problem - I have attach to this E-mail the HTFile.c
source with modifications I have made to the source.  I have linked it with the
original WWWLIB2.06 found in CERN (With no other modifications).
The corrections are marked with "DR SEP 93"
Thanks
Dudu
/*			File Access				HTFile.c
**			===========
**
**	This is unix-specific code in general, with some VMS bits.
**	These are routines for file access used by browsers.
**
** History:
**	   Feb 91	Written Tim Berners-Lee CERN/CN
**	   Apr 91	vms-vms access included using DECnet syntax
**	26 Jun 92 (JFG) When running over DECnet, suppressed FTP.
**			Fixed access bug for relative names on VMS.
**	09 Sep 93 (DR) Bugfix for VMS Daemon file retreival.
**
** Bugs:
**	FTP: Cannot access VMS files from a unix machine.
**      How can we know that the
**	target machine runs VMS?
*/
#include "HTFile.h"		/* Implemented here */
#define INFINITY 512		/* file name length @@ FIXME */
#define MULTI_SUFFIX ".multi"   /* Extension for scanning formats */
#include "HTUtils.h"
#include "HTParse.h"
#include "tcp.h"
#include "HTTCP.h"
#ifndef DECNET
#include "HTFTP.h"
#endif
#include "HTAnchor.h"
#include "HTAtom.h"
#include "HTWriter.h"
#include "HTFWriter.h"
#include "HTInit.h"
#include "HTBTree.h"
typedef struct _HTSuffix {
	char *		suffix;
	HTAtom *	rep;
	HTAtom *	encoding;
	float		quality;
} HTSuffix;
#ifdef USE_DIRENT		/* Set this for Sys V systems */
#define STRUCT_DIRENT struct dirent
#else
#define STRUCT_DIRENT struct direct
#endif
#include "HTML.h"		/* For directory object building */
#define PUTC(c) (*target->isa->put_character)(target, c)
#define PUTS(s) (*target->isa->put_string)(target, s)
#define START(e) (*target->isa->start_element)(target, e, 0, 0)
#define END(e) (*target->isa->end_element)(target, e)
#define END_TARGET (*target->isa->end_document)(target)
#define FREE_TARGET (*target->isa->free)(target)
struct _HTStructured {
	CONST HTStructuredClass *	isa;
	/* ... */
};
/*                   Controlling globals
**
*/
PUBLIC int HTDirAccess = HT_DIR_OK;
PUBLIC int HTDirReadme = HT_DIR_README_TOP;
PRIVATE char *HTMountRoot = "/Net/";		/* Where to find mounts */
#ifdef vms
PRIVATE char *HTCacheRoot = "/WWW$SCRATCH/";   /* Where to cache things */
#else
PRIVATE char *HTCacheRoot = "/tmp/W3_Cache_";   /* Where to cache things */
#endif
/* PRIVATE char *HTSaveRoot  = "$(HOME)/WWW/";*/    /* Where to save things */
/*	Suffix registration
*/
PRIVATE HTList * HTSuffixes = 0;
PRIVATE HTSuffix no_suffix = { "*", NULL, NULL, 1.0 };
PRIVATE HTSuffix unknown_suffix = { "*.*", NULL, NULL, 1.0};
/*	Define the representation associated with a file suffix 
    HTSuffix * suff; 
    if (strcmp(suffix, "*")==0) suff = &no_suffix; 
    suff->rep = HTAtom_for(representation); 
    { 
    suff->quality = value; 
 
 
 
#ifdef vms 
/*	We try converting the filename into Files-11 syntax. That is, we assume 
    char * hostname = HTHostName(); 
    if (!filename :: !nodename) outofmem(__FILE__, "vms_name"); 
    second = strchr(filename+1, '/');		/* 2nd slash */ 
    if (!second) {				/* Only one slash */ 
 
#endif /* vms */ 
 
 
/*	Send README file 
#ifdef GOT_READ_DIR 
    fp = fopen(readme_file_name,  "r"); 
    if (fp) { 
 
/*	Make the cache file name for a W3 document 
    char * result; 
 
/*	Open a file for write, creating the path 
/*	Convert filenames between local and WWW formats 
    HTUnEscape(path);	/* Interpret % signs */ 
    if (0==strcmp(access, "file")) { 
 
/*	Make a WWW name from a full local path name 
PUBLIC char * WWW_nameOfFile ARGS1 (CONST char *,name) 
 
/*	Determine a suitable suffix, given the representation 
#ifndef NO_INIT 
 
/*	Determine file format from file name 
PUBLIC HTFormat HTFileFormat ARGS2 ( 
{ 
#ifndef NO_INIT 
    /* defaults tree */ 
    suff = strchr(filename, '.') ? 	/* Unknown suffix */ 
 
/*	Determine value from file name 
PUBLIC float HTFileValue ARGS1 (CONST char *,filename) 
{ 
#ifndef NO_INIT 
 
/*	Determine write access to a file 
#ifdef vms 
PUBLIC BOOL HTEditable ARGS1 (CONST char *,filename) 
    if (stat(filename, &fileStatus))		/* Get details of filename */ 
    ngroups = getgroups(NGROUPS, groups);	/* Groups to which
    myUid = geteuid();				/* Get my user identifier */ 
    if (TRACE) { 
    if (fileStatus.st_mode & 0002)		/* I can write anyway? */ 
    if (fileStatus.st_mode & 0020)		/* Group I am in can write? */ 
 
/*	Make a save stream 
    CONST char * addr = HTAnchor_address((HTAnchor*)anchor); 
    FILE* fp = fopen(localname, "w"); 
    return HTFWriter_new(fp); 
} 
/*      Output one directory entry 
    /* If empty tail, gives absolute ref below */ 
/*      Output parent directory entry 
{ 
    current = strrchr(path, '/');	/* last part or "" */ 
    { 
      START(HTML_H1); 
    /*  Make link back to parent directory 
    if (current && current[1]) {   /* was a slash AND something else too */ 
	relative = (char*) malloc(strlen(current) + 4); 
	PUTS("Up to "); 
	END(HTML_A); 
    } 
 
/*	Load a document 
/* DR SEP 93 */ 
    char * nodename = 0; 
/*	Reduce the filename to a basic form (hopefully unique!) 
    format = HTFileFormat(filename, &encoding); 
 
#ifdef vms 
	if (!fd) { 
	if (fd) { 
    } 
    free(filename); 
/*	For unix, we try to translate the name into the name of a transparently 
/*			  Multiformat handling 
	    STRUCT_DIRENT * dirbuf; 
	    char * base = strrchr(localname, '/'); 
	    if (!base :: base == localname) goto forget_multi; 
	    dp = opendir(localname); 
	}  else {		/* Stat was OK */ 
	    if (((dir_info.st_mode) & S_IFMT) == S_IFDIR) { 
		HTStructured* target;		/* HTML object */ 
		DIR *dp; 
 
		if (HTDirAccess == HT_DIR_SELECTIVE) { 
 
		dp = opendir(localname); 
 
 /*	Directory access is allowed and possible 
                if (HTDirReadme == HT_DIR_README_TOP) 
		    while (dirbuf = readdir(dp)) 
			    /* while there are directory entries to be read */ 
				/* if the current entry is parent directory */ 
			dirname = (HTBTElement *)malloc( 
					/* if filename is not root directory */ 
 
			StrAllocCat(tmpfilename,dirbuf->d_name); 
		    /*    Run through tree printing out in order 
			while (next_element != NULL) 
					/* if filename is not root directory */ 
			    StrAllocCat(tmpfilename, 
			    next_element = HTBTree_next(bt,next_element); 
		        /* end while directory entries left to read */ 
		    if (HTDirReadme == HT_DIR_README_BOTTOM) 
	    } /* end if localname is directory */ 
#ifndef DECNET 
/*	All attempts have failed. 
 
} 
/*		Protocol descriptors 
**	-------------------------------------------------------
**
**	Calling this with suffix set to "*" will set the default
**	representation.
**	Calling this with suffix set to "*.*" will set the default
**	representation for unknown suffix files which
PUBLIC void HTSetSuffix ARGS4(
	CONST char *,	suffix,
	CONST char *,	representation,
	CONST char *,	encoding,
	float,		value)
{
    else if (strcmp(suffix, "*.*")==0) suff = &unknown_suffix;
    else {
	suff = (HTSuffix*) calloc(1, sizeof(HTSuffix));
	if (suff == NULL) outofmem(__FILE__, "HTSetSuffix");
	
	if (!HTSuffixes) HTSuffixes = HTList_new();
	HTList_addObject(HTSuffixes, suff);
	
	StrAllocCopy(suff->suffix, suffix);
    }
    	char * enc = NULL;
	char * p;
	StrAllocCopy(enc, encoding);
	for (p=enc; *p; p++) *p = TOLOWER(*p);
	suff->encoding = HTAtom_for(encoding);
    }
}
/*	Convert unix-style name into VMS name
**	-------------------------------------
**
** Bug:	Returns pointer to static -- non-reentrant
*/
PRIVATE char * vms_name(CONST char * nn, CONST char * fn)
{
**	first that the file is, like us, on a VMS node. We try remote
**	(or local) DECnet access. Files-11, VMS, VAX and DECnet
**	are trademarks of Digital Equipment Corporation.
**	The node is assumed to be local if the hostname WITHOUT DOMAIN
**	matches the local one. @@@
*/
    static char vmsname[INFINITY];	/* returned */
    char * filename = (char*)malloc(strlen(fn)+1);
    char * nodename = (char*)malloc(strlen(nn)+2+1);	/* Copies to hack */
    char *second;		/* 2nd slash */
    char *last;			/* last slash */
    strcpy(filename, fn);
    strcpy(nodename, "");	/* On same node? Yes if node names match */
    {
        char *p, *q;
        for (p=hostname, q=nn; *p && *p!='.' && *q && *q!='.'; p++, q++){
	    if (TOUPPER(*p)!=TOUPPER(*q)) {
	        strcpy(nodename, nn);
		q = strchr(nodename, '.');	/* Mismatch */
		if (q) *q=0;			/* Chop domain */
		strcat(nodename, "::");		/* Try decnet anyway */
		break;
	    }
	}
    }
    last = strrchr(filename, '/');	/* last slash */
/* DR SEP 93 */
	sprintf(vmsname, "%s%s", nodename, filename );
    } else if(second==last) {		/* Exactly two slashes */
	*second = 0;		/* Split filename from disk */
/* DR SEP 93 */
	sprintf(vmsname, "%s%s:%s", nodename, filename, second+1);
	*second = '/';	/* restore */
    } else { 				/* More than two slashes */
	char * p;
	*second = 0;		/* Split disk from directories */
	*last = 0;		/* Split dir from filename */
/* DR SEP 93 */
	sprintf(vmsname, "%s%s:[%s]%s",
		nodename, filename, second+1, last+1);
	*second = *last = '/';	/* restore filename */
	for (p=strchr(vmsname, '['); *p!=']'; p++)
	    if (*p=='/') *p='.';	/* Convert dir sep.  to dots */
    }
    free(nodename);
    free(filename);
    return vmsname;
}
**
**  If a README file exists, then it is inserted into the document here.
*/
PRIVATE void do_readme ARGS2(HTStructured *, target, CONST char *, localname)
{
    FILE * fp;
    char * readme_file_name =
	malloc(strlen(localname)+ 1 + strlen(HT_DIR_README_FILE) + 1);
    strcpy(readme_file_name, localname);
    strcat(readme_file_name, "/");
    strcat(readme_file_name, HT_DIR_README_FILE);
	HTStructuredClass targetClass;
	
	targetClass =  *target->isa;	/* (Can't init agregate in K&R) */
	START(HTML_PRE);
	for(;;){
	    char c = fgetc(fp);
	    if (c == (char)EOF) break;
	    switch (c) {
	    	case '&':
		case '<':
		case '>':
			PUTC('&');
			PUTC('#');
			PUTC((char)(c / 10));
			PUTC((char) (c % 10));
			PUTC(';');
			break;
/*	    	case '\n':
			PUTC('\r');
Bug removed thanks to joe@athena.mit.edu */			
		default:
			PUTC(c);
	    }
	}
	END(HTML_PRE);
	fclose(fp);
    }
}
#endif
**	------------------------------------------
**	Make up a suitable name for saving the node in
**
**	E.g.	/tmp/WWW_Cache_news/1234@cernvax.cern.ch
**		/tmp/WWW_Cache_http/crnvmc/FIND/xx.xxx.xx
**
** On exit,
**	returns	a malloc'ed string which
PUBLIC char * HTCacheFileName ARGS1(CONST char *,name)
{
    char * access = HTParse(name, "", PARSE_ACCESS);
    char * host = HTParse(name, "", PARSE_HOST);
    char * path = HTParse(name, "", PARSE_PATH+PARSE_PUNCTUATION);
    result = (char *)malloc(
	    strlen(HTCacheRoot)+strlen(access)
	    +strlen(host)+strlen(path)+6+1);
    if (result == NULL) outofmem(__FILE__, "HTCacheFileName");
    sprintf(result, "%s/WWW/%s/%s%s", HTCacheRoot, access, host, path);
    free(path);
    free(access);
    free(host);
    return result;
}
**	----------------------------------------
*/
#ifdef NOT_IMPLEMENTED
PRIVATE int HTCreatePath ARGS1(CONST char *,path)
{
    return -1;
}
#endif
**	-----------------------------------------------
**	Make up a suitable name for saving the node in
**
**	E.g.	$(HOME)/WWW/news/1234@cernvax.cern.ch
**		$(HOME)/WWW/http/crnvmc/FIND/xx.xxx.xx
**
** On exit,
**	returns	a malloc'ed string which
PUBLIC char * HTLocalName ARGS1(CONST char *,name)
{
    char * access = HTParse(name, "", PARSE_ACCESS);
    char * host = HTParse(name, "", PARSE_HOST);
    char * path = HTParse(name, "", PARSE_PATH+PARSE_PUNCTUATION);
        free(access);	
	if ((0==strcasecomp(host, HTHostName())) ::
	    (0==strcasecomp(host, "localhost")) :: !*host) {
	    free(host);
	    if (TRACE) fprintf(stderr, "Node `%s' means path `%s'\n", name, path);
	    return(path);
	} else {
	    char * result = (char *)malloc(
	    			strlen("/Net/")+strlen(host)+strlen(path)+1);
              if (result == NULL) outofmem(__FILE__, "HTLocalName");
	    sprintf(result, "%s%s%s", "/Net/", host, path);
	    free(host);
	    free(path);
	    if (TRACE) fprintf(stderr, "Node `%s' means file `%s'\n", name, result);
	    return result;
	}
    } else {  /* other access */
	char * result;
        CONST char * home =  (CONST char*)getenv("HOME");
	if (!home) home = "/tmp";
	result = (char *)malloc(
		strlen(home)+strlen(access)+strlen(host)+strlen(path)+6+1);
      if (result == NULL) outofmem(__FILE__, "HTLocalName");
	sprintf(result, "%s/WWW/%s/%s%s", home, access, host, path);
	free(path);
	free(access);
	free(host);
	return result;
    }
}
**
** Bugs:
**	At present, only the names of two network root nodes are hand-coded
**	in and valid for the NeXT only. This should be configurable in
**	the general case.
*/
{
    char * result;
#ifdef NeXT
    if (0==strncmp("/private/Net/", name, 13)) {
	result = (char *)malloc(7+strlen(name+13)+1);
	if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
	sprintf(result, "file://%s", name+13);
    } else
#endif
    if (0==strncmp(HTMountRoot, name, 5)) {
	result = (char *)malloc(7+strlen(name+5)+1);
	if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
	sprintf(result, "file://%s", name+5);
    } else {
        result = (char *)malloc(7+strlen(HTHostName())+strlen(name)+1);
	if (result == NULL) outofmem(__FILE__, "WWW_nameOfFile");
	sprintf(result, "file://%s%s", HTHostName(), name);
    }
    if (TRACE) fprintf(stderr, "File `%s'\n\tmeans node `%s'\n", name, result);
    return result;
}
**	-----------------------------------------------------
**
** On entry,
**	rep	is the atomized MIME style representation
**
** On exit,
**	returns	a pointer to a suitable suffix string if one has been
**		found, else "".
*/
PUBLIC CONST char * HTFileSuffix ARGS1(HTAtom*, rep)
{
    HTSuffix * suff;
    int n;
    int i;
    if (!HTSuffixes) HTFileInit();
#endif
    n = HTList_count(HTSuffixes);
    for(i=0; i<n; i++) {
	suff = HTList_objectAt(HTSuffixes, i);
	if (suff->rep == rep) {
	    return suff->suffix;		/* OK -- found */
	}
    }
    return "";		/* Dunno */
}
**	------------------------------------
**
**	This version will return the representation and also set
**	a variable for the encoding.
**
**	It will handle for example  x.txt, x.txt,Z, x.Z
*/
			CONST char *,	filename,
			HTAtom **,	pencoding)
    HTSuffix * suff;
    int n;
    int i;
    int lf = strlen(filename);
    if (!HTSuffixes) HTFileInit();
#endif
    *pencoding = NULL;
    n = HTList_count(HTSuffixes);
    for(i=0; i<n; i++) {
        int ls;
	suff = HTList_objectAt(HTSuffixes, i);
	ls = strlen(suff->suffix);
	if ((ls <= lf) && 0==strcmp(suff->suffix, filename + lf - ls)) {
	    int j;
	    *pencoding = suff->encoding;
	    if (suff->rep) return suff->rep;		/* OK -- found */
	
	    for(j=0; j<n; j++) {  /* Got encoding, need representation */
		int ls2;
		suff = HTList_objectAt(HTSuffixes, j);
		ls2 = strlen(suff->suffix);
		if ((ls <= lf) && 0==strncmp(
			suff->suffix, filename + lf - ls -ls2, ls2)) {
		    if (suff->rep) return suff->rep;
		}
	    }
	
	}
    }
    	 ( unknown_suffix.rep ? &unknown_suffix : &no_suffix)
	 : &no_suffix;
	
    /* set default encoding unless found with suffix already */
    if (!*pencoding) *pencoding = suff->encoding ? suff->encoding
				    : HTAtom_for("binary");
    return suff->rep ? suff->rep : WWW_BINARY;
}
**	------------------------------
**
*/
    HTSuffix * suff;
    int n;
    int i;
    int lf = strlen(filename);
    if (!HTSuffixes) HTFileInit();
#endif
    n = HTList_count(HTSuffixes);
    for(i=0; i<n; i++) {
        int ls;
	suff = HTList_objectAt(HTSuffixes, i);
	ls = strlen(suff->suffix);
	if ((ls <= lf) && 0==strcmp(suff->suffix, filename + lf - ls)) {
	    if (TRACE) fprintf(stderr, "File: Value of %s is %.3f\n",
			       filename, suff->quality);
	    return suff->quality;		/* OK -- found */
	}
    }
    return 0.3;		/* Dunno! */
}
**	--------------------------------
**
** On exit,
**	return value	YES if file can be accessed and can be written to.
**
** Bugs:
**	1.	No code for non-unix systems.
**	2.	Isn't there a quicker way?
*/
#define NO_GROUPS
#endif
#ifdef NO_UNIX_IO
#define NO_GROUPS
#endif
#ifdef PCNFS
#define NO_GROUPS
#endif
{
#ifdef NO_GROUPS
    return NO;		/* Safe answer till we find the correct algorithm */
#else
    int 	groups[NGROUPS];	
    uid_t	myUid;
    int		ngroups;			/* The number of groups  */
    struct stat	fileStatus;
    int		i;
    	return NO;				/* Can't even access file! */
        int i;
	fprintf(stderr,
	    "File mode is 0%o, uid=%d, gid=%d. My uid=%d, %d groups (",
    	    (unsigned int) fileStatus.st_mode, fileStatus.st_uid,
	    fileStatus.st_gid,
	    myUid, ngroups);
	for (i=0; i<ngroups; i++) fprintf(stderr, " %d", groups[i]);
	fprintf(stderr, ")\n");
    }
    	return YES;
	
    if ((fileStatus.st_mode & 0200)		/* I can write my own file? */
     && (fileStatus.st_uid == myUid))
    	return YES;
    {
   	for (i=0; i<ngroups; i++) {
            if (groups[i] == fileStatus.st_gid)
	        return YES;
	}
    }
    if (TRACE) fprintf(stderr, "\tFile is not editable.\n");
    return NO;					/* If no excuse, can't do */
#endif
}
**	------------------
**
**	The stream
*/
PUBLIC HTStream<* HTFileSaveStream
    char *  localname = HTLocalName(addr);
    if (!fp) return NULL;
**
*/
PUBLIC void HTDirEntry
		 CONST char *,  entry)
{
    char * relative;
    char * escaped = HTEscape(entry, URL_XPALPHAS);
    relative = (char*) malloc(
			      strlen(tail) + strlen(escaped)+2);
    if (relative == NULL) outofmem(__FILE__, "DirRead");
    sprintf(relative, "%s/%s", tail, escaped);
    HTStartAnchor(target, "", relative);
    free(escaped);
    free(relative);
    PUTS(entry);
    END(HTML_A);
}
**
**    This gives the TITLE and H1 header, and also a link
**    to the parent directory if appropriate.
*/
PUBLIC void HTDirTitles ARGS2(HTStructured *, target,
		 HTAnchor * , anchor)
    char * logical = HTAnchor_address(anchor);
    char * path = HTParse(logical, "", PARSE_PATH + PARSE_PUNCTUATION);
    char * current;
    free(logical);
      char * printable = NULL;
      StrAllocCopy(printable, (current + 1));
      HTUnEscape(printable);
      START(HTML_TITLE);
      PUTS(*printable ? printable : "Welcome ");
      PUTS(" directory");
      END(HTML_TITLE);
      PUTS(*printable ? printable : "Welcome");
      END(HTML_H1);
      free(printable);
    }
     */
        char * parent;
	char * relative;
	*current++ = 0;
      parent = strrchr(path, '/');  /* penultimate slash */
	if (relative == NULL) outofmem(__FILE__, "DirRead");
	sprintf(relative, "%s/..", current);
	HTStartAnchor(target, "", relative);
	free(relative);
	if (parent) {
	  char * printable = NULL;
	  StrAllocCopy(printable, parent + 1);
	  HTUnEscape(printable);
	  PUTS(printable);
	  free(printable);
	} else {
	  PUTS("/");
	}
    free(path);
}
		
**	---------------
**
** On entry,
**	addr		must point to the fully qualified hypertext reference.
**			This is the physsical address of the file
**
** On exit,
**	returns		<0		Error has occured.
**			HTLOADED	OK
**
*/
PUBLIC int HTLoadFile ARGS4 (
	CONST char *,		addr,
	HTParentAnchor *,	anchor,
	HTFormat,		format_out,
	HTStream<*,		sink
)
{
    char * filename;
    HTFormat format;
    FILE * fd;
    char * newname=0;	/* Simplified name of file */
    HTAtom * encoding;	/* @@ not used yet */
*/
    StrAllocCopy(newname, addr);
    filename=HTParse(newname, "", PARSE_PATH:PARSE_PUNCTUATION);
    nodename=HTParse(newname, "", PARSE_HOST);
    free(newname);
/* Assume that the file is in Unix-style syntax if it
    {
	char * vmsname = strchr(filename + 1, '/') ?
	  vms_name(nodename, filename) : filename + 1;
/* DR SEP 93 */
        fd = fopen(vmsname,  "r");
	
/*	If the file wasn't VMS syntax, then perhaps it is ultrix
*/
/* DR SEP 93 */
	    char ultrixname[INFINITY];
	    if (TRACE) fprintf(stderr, "HTFile: Can't open as %s\n", vmsname);
	    sprintf(ultrixname, "%s::\"%s\"", nodename, filename);
	    fd = fopen(ultrixname,  "r");
	    if (!fd) {
		if (TRACE) fprintf(stderr,
				   "HTFile: Can't open as %s\n", ultrixname);
	} }
		if (HTEditable(vmsname)) {
		    HTAtom * put = HTAtom_for("PUT");
		    HTList * methods = HTAnchor_methods(anchor);
		    if (HTList_indexOf(methods, put) == (-1)) {
			HTList_addObject(methods, put);
		    }
		}
		HTParseFile(format, format_out, anchor, fd, sink);
		fclose(fd);
		return HT_LOADED;
	    }  /* If succesfull open */
#else
**	mounted file.
**
**	Not allowed in secure (HTClienntHost) situations TBL 921019
*/
#ifndef NO_UNIX_IO
    /*  Need protection here for telnet server but not httpd server */
	
    if (!HTSecure) {		/* try local file system */
	char * localname = HTLocalName(addr);
	struct stat dir_info;
	
#ifdef GOT_READ_DIR
**
**	If needed, scan directory to find a good file.
**  Bug:  we don't stat the file to find the length
*/
	if ( (strlen(localname) > strlen(MULTI_SUFFIX))
	   && (0==strcmp(localname + strlen(localname) - strlen(MULTI_SUFFIX),
	                  MULTI_SUFFIX))) {
	    DIR *dp;
	    float best = NO_VALUE_FOUND;	/* So far best is bad */
	    HTFormat best_rep = NULL;	/* Set when rep found */
	    STRUCT_DIRENT best_dirbuf;	/* Best dir entry so far */
	    int baselen;
	    *base++ = 0;		/* Just got directory name */
	    baselen = strlen(base)- strlen(MULTI_SUFFIX);
	    base[baselen] = 0;	/* Chop off suffix */
	    if (!dp) {
forget_multi:
		free(localname);
		return HTLoadError(sink, 500,
			"Multiformat: directory scan failed.");
	    }
	
	    while (dirbuf = readdir(dp)) {
			/* while there are directory entries to be read */
		if (dirbuf->d_ino == 0)
		
		if (dirbuf->d_namlen > baselen &&      /* Match? */
		    !strncmp(dirbuf->d_name, base, baselen)) {	
		    HTFormat rep = HTFileFormat(dirbuf->d_name, &encoding);
		    float value = HTStackValue(rep, format_out,
		    				HTFileValue(dirbuf->d_name),
						0.0  /* @@@@@@ */);
		    if (value != NO_VALUE_FOUND) {
		        if (TRACE) fprintf(stderr,
				"HTFile: value of presenting %s is %f\n",
				HTAtom_name(rep), value);
			if  (value > best) {
			    best_rep = rep;
			    best = value;
			    best_dirbuf = *dirbuf;
		       }
		    }	/* if best so far */ 		
		 } /* if match */
		
	    } /* end while directory entries left to read */
	    closedir(dp);
	
	    if (best_rep) {
		format = best_rep;
		base[-1] = '/';		/* Restore directory name */
		base[0] = 0;
		StrAllocCat(localname, best_dirbuf.d_name);
		goto open_file;
		
	    } else { 			/* If not found suitable file */
		free(localname);
		return HTLoadError(sink, 403,	/* List formats? */
		   "Could not find suitable representation for transmission.");
	    }
	    /*NOTREACHED*/
	} /* if multi suffix */
/*
**	Check to see if the 'localname' is in fact a directory.  If it is
**	create a new hypertext object containing a list of files and
**	subdirectories contained in the directory.  All of these are links
**      to the directories or files listed.
**      NB This assumes the existance of a type 'STRUCT_DIRENT', which
*/
	
	
	if (stat(localname,&dir_info) == -1) {     /* get file information */
	                               /* if can't read file information */
	    if (TRACE) fprintf(stderr, "HTFile: can't stat %s\n", localname);
		
		/* if localname is a directory */	
		HTStructuredClass targetClass;
		STRUCT_DIRENT * dirbuf;
		
		char * logical;
		char * tail;
		
		BOOL present[HTML_A_ATTRIBUTES];
		
		char * tmpfilename = NULL;
		struct stat file_info;
		
		if (TRACE)
		    fprintf(stderr,"%s is a directory\n",localname);
			
/*	Check directory access.
**	Selective access means only those directories containing a
**	marker file can be browsed
*/
		if (HTDirAccess == HT_DIR_FORBID) {
		    free(localname);
		    return HTLoadError(sink, 403,
		    "Directory browsing is not allowed.");
		}
		    char * enable_file_name =
			malloc(strlen(localname)+ 1 +
			 strlen(HT_DIR_ENABLE_FILE) + 1);
		    strcpy(enable_file_name, localname);
		    strcat(enable_file_name, "/");
		    strcat(enable_file_name, HT_DIR_ENABLE_FILE);
		    if (stat(enable_file_name, &file_info) != 0)<{
			free(localname);
			return HTLoadError(sink, 403,
			"Selective access is not enabled for this directory");
		    }
		}
		if (!dp) {
		    free(localname);
		    return HTLoadError(sink, 403, "This directory is not readable.");
		}
 */
		logical = HTAnchor_address((HTAnchor*)anchor);
		tail = strrchr(logical, '/') +1;	/* last part or "" */
		
		target = HTML_new(anchor, format_out, sink);
		targetClass = *target->isa;	/* Copy routine entry points */
		
  		{ int i;
			for(i=0; i<HTML_A_ATTRIBUTES; i++)
				present[i] = (i==HTML_A_HREF);
		}
		
                HTDirTitles(target, (HTAnchor *)anchor);
		    do_readme(target, localname);
		{
		    HTBTree * bt = HTBTree_new((HTComparer)strcasecomp);
		    {
		        HTBTElement * dirname = NULL;
		        if (dirbuf->d_ino == 0)
				  /* if the entry is not being used, skip it */
			    continue;
		
			if ((*(dirbuf->d_name)=='.') ::
				(*(dirbuf->d_name)==','))
			    continue;    /* skip those files whose name begins
					    with '.' or ',' */
					strlen(dirbuf->d_name) + 2);
			if (dirname == NULL) outofmem(__FILE__,"DirRead");
			StrAllocCopy(tmpfilename,localname);
			if (strcmp(localname,"/"))
			    StrAllocCat(tmpfilename,"/");
			stat(tmpfilename, &file_info);
			if (((file_info.st_mode) & S_IFMT) == S_IFDIR)
		                sprintf((char *)dirname,"D%s",dirbuf->d_name);
			else sprintf((char *)dirname,"F%s",dirbuf->d_name);
			    /* D & F to have first directories, then files */
			HTBTree_add(bt,dirname); /* Sort dirname in the tree bt */
		    }
		     */
		    {
		        HTBTElement * next_element = HTBTree_next(bt,NULL);
			    /* pick up the first element of the list */
			char state;
			    /* I for initial (.. file),
			       D for directory file,
			       F for file */
			
			state = 'I';
		        {
			    StrAllocCopy(tmpfilename,localname);
			    if (strcmp(localname,"/"))
			        StrAllocCat(tmpfilename,"/");
					(char *)HTBTree_object(next_element)+1);
			    /* append the current entry's filename to the path */
			    HTSimplify(tmpfilename);
			    /* Output the directory entry */
			    if (strcmp((char *)
					     (HTBTree_object(next_element)),"D.."))
			    {			
				if (state != *(char *)(HTBTree_object(next_element)))
				{
				    if (state == 'D')
				        END(HTML_DIR);
				    state = *(char *)
				        (HTBTree_object(next_element))=='D'?'D':'F';
				    START(HTML_H2);
				    PUTS(state == 'D'?"Subdirectories:":"Files");
				    END(HTML_H2);
				    START(HTML_DIR);
				}
			        START(HTML_LI);
			    }
			    HTDirEntry(target, tail,
				       (char*)HTBTree_object(next_element) +1);
			        /* pick up the next element of the list;
				 if none, return NULL*/
			}
			if (state == 'I')
			{
			    START(HTML_P);
			    PUTS("Empty Directory");
			}
			else
			    END(HTML_DIR);
		    }
		    closedir(dp);
		    free(logical);
		    free(tmpfilename);
		    HTBTreeAndObject_free(bt);
			  do_readme(target, localname);
		    END_TARGET;
		    FREE_TARGET;
		    free(localname);
		    return HT_LOADED;	/* document loaded */
		}
	
	} /* end if file stat worked */
	
/* End of directory reading section
*/
#endif
open_file:
	{
	    FILE * fp = fopen(localname,"r");
	    if(TRACE) fprintf (stderr, "HTFile: Opening `%s' gives %p\n",
				localname, (void*)fp);
	    if (fp) {		/* Good! */
		if (HTEditable(localname)) {
		    HTAtom * put = HTAtom_for("PUT");
		    HTList * methods = HTAnchor_methods(anchor);
		    if (HTList_indexOf(methods, put) == (-1)) {
			HTList_addObject(methods, put);
		    }
		}
		free(localname);
		HTParseFile(format, format_out, anchor, fp, sink);
		fclose(fp);
		return HT_LOADED;
	    }  /* If succesfull open */
	}    /* scope of fp */
    }  /* local unix file system */
#endif
#endif
/*	Now, as transparently mounted access has failed, we try FTP.
*/
    {
	if (strcmp(nodename, HTHostName())!=0)
	    return HTFTPLoad(addr, anchor, format_out, sink);
    }
#endif
*/
    {
    	if (fd<0) if (TRACE)
    	printf("Can't open `%s', errno=%d\n", addr, errno);
	return HTLoadError(sink, 403, "Can't access requested file.");
    }
*/
PUBLIC HTProtocol HTFTP  = { "ftp", HTLoadFile, 0 };
PUBLIC HTProtocol HTFile = { "file", HTLoadFile, HTFileSaveStream<};