[comp.sys.ibm.pc] MicroEmacs, MicroSoft C and PC-NFS

sch@oce-rd1.oce.nl (Jakob Schripsema) (09/16/87)

When using MicroEmacs (3.8i) with PC-NFS I ran into a performance problem :
Writing a file to the local hard-disk took 8 secs, writting the same file
to the virtual disk took 80 secs.

The problem seems to be in the MicroSoft library (I'm using MSC 3.0).
The stdio code does \n to \r\n conversion. When encountering a \n the
filebuffer seems to get flushed (1 write syscall) and a \r\n is added
(another write syscall). After that buffering continues. This creates
a lot of write calls with relatively short byte counts. This seems
to upset PC-NFS.

The cure is simple: open the file in binary mode and do the \n to \r\n
yourself. Changes are in the routines 'ffwopen' and 'ffputline' in the
file 'fileio.c'. The changed version is attached to this message.


JaKob Schripsema (sch@oce.nl)
Oce-Nederland B.V.
The Netherlands
	
======================================================
 This note does not necessarily represent the position
 of Oce-Nederland B.V. Therefore no liability or
 responsibility for whatever will be accepted.
======================================================


----------- cut here -----
/*
 * The routines in this file read and write ASCII files from the disk. All of
 * the knowledge about files are here. A better message writing scheme should
 * be used.
 */
#include        <stdio.h>
#include	"estruct.h"
#include        "edef.h"

FILE    *ffp;                           /* File pointer, all functions. */

/*
 * Open a file for reading.
 */
ffropen(fn)
char    *fn;
{
        if ((ffp=fopen(fn, "r")) == NULL)
                return (FIOFNF);
        return (FIOSUC);
}

/*
 * Open a file for writing. Return TRUE if all is well, and FALSE on error
 * (cannot create).
 */
ffwopen(fn)
char    *fn;
{
#if     VMS
        register int    fd;

        if ((fd=creat(fn, 0666, "rfm=var", "rat=cr")) < 0
        || (ffp=fdopen(fd, "w")) == NULL) {
#else
#if	MSDOS
        if ((ffp=fopen(fn, "wb")) == NULL) {
#else
        if ((ffp=fopen(fn, "w")) == NULL) {
#endif
#endif
                mlwrite("Cannot open file for writing");
                return (FIOERR);
        }
        return (FIOSUC);
}

/*
 * Close a file. Should look at the status in all systems.
 */
ffclose()
{
#if	MSDOS & CTRLZ
	fputc(26, ffp);		/* add a ^Z at the end of the file */
#endif
	
#if     V7 | USG | BSD | (MSDOS & (LATTICE | MSC))
        if (fclose(ffp) != FALSE) {
                mlwrite("Error closing file");
                return(FIOERR);
        }
        return(FIOSUC);
#else
        fclose(ffp);
        return (FIOSUC);
#endif
}

/*
 * Write a line to the already opened file. The "buf" points to the buffer,
 * and the "nbuf" is its length, less the free newline. Return the status.
 * Check only at the newline.
 */
ffputline(buf, nbuf)
char    buf[];
{
        register int    i;
#if	CRYPT
	char c;		/* character to translate */

	if (cryptflag) {
	        for (i = 0; i < nbuf; ++i) {
			c = buf[i] & 0xff;
			crypt(&c, 1);
			fputc(c, ffp);
		}
	} else
	        for (i = 0; i < nbuf; ++i)
        	        fputc(buf[i]&0xFF, ffp);
#else
        for (i = 0; i < nbuf; ++i)
                fputc(buf[i]&0xFF, ffp);
#endif

#if	ST520 | MSDOS
        fputc('\r', ffp);
#endif        
        fputc('\n', ffp);

        if (ferror(ffp)) {
                mlwrite("Write I/O error");
                return (FIOERR);
        }

        return (FIOSUC);
}

/*
 * Read a line from a file, and store the bytes in the supplied buffer. The
 * "nbuf" is the length of the buffer. Complain about long lines and lines
 * at the end of the file that don't have a newline present. Check for I/O
 * errors too. Return status.
 */
ffgetline(buf, nbuf)
register char   buf[];
{
        register int    c;
        register int    i;

        i = 0;

        while ((c = fgetc(ffp)) != EOF && c != '\n') {
                if (i >= nbuf-2) {
			buf[nbuf - 2] = c;	/* store last char read */
			buf[nbuf - 1] = 0;	/* and terminate it */
                        mlwrite("File has long line");
#if	CRYPT
			if (cryptflag)
				crypt(buf, strlen(buf));
#endif
                        return (FIOLNG);
                }
                buf[i++] = c;
        }

#if	ST520
	if(buf[i-1] == '\r')
		i--;
#endif
        if (c == EOF) {
                if (ferror(ffp)) {
                        mlwrite("File read error");
                        return (FIOERR);
                }

                if (i != 0) {
                	buf[i] = 0;
                        return(FIOFUN);
                }

                return (FIOEOF);
        }

        buf[i] = 0;
#if	CRYPT
	if (cryptflag)
		crypt(buf, strlen(buf));
#endif
        return (FIOSUC);
}

#if	AZTEC & MSDOS
#undef	fgetc
/*	a1getc:		Get an ascii char from the file input stream
			but DO NOT strip the high bit
*/

int a1getc(fp)

FILE *fp;

{
	int c;		/* translated character */

	c = getc(fp);	/* get the character */

	/* if its a <LF> char, throw it out  */
	while (c == 10)
		c = getc(fp);

	/* if its a <RETURN> char, change it to a LF */
	if (c == '\r')
		c = '\n';

	/* if its a ^Z, its an EOF */
	if (c == 26)
		c = EOF;

	return(c);
}
#endif