This is the mail archive of the cygwin-developers@sourceware.cygnus.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

cygwin, ftell, cr/lf - better handling



A longstanding bug in cygwin is that ftell returns bogus values,
because it doesn't know what kind of line ending conversions cygwin
did before handing the buffer to newlib.  This patch moves the CR/LF
conversions to newlib, so that its buffers always reflect the actual
file (and thus ftell can be accurate).  As a bonus, fgetc and fgets
are much faster, with only a slight slowdown for fread.

Note that this bug only exists for DOS text files; Mac CR files won't
have this problem because text conversions preserve the number of
characters.

2000-05-01  DJ Delorie  <dj@cygnus.com>

	* libc/include/stdio.h (FILE): define __SCLE for "convert line
 	endings" for Cygwin.
	(__sgetc): convert line endings if needed
	(__sputc): ditto
	* libc/stdio/fdopen.c (_fdopen_r): Remember if we opened in text mode
	* libc/stdio/fopen.c (_fopen_r): ditto
	* libc/stdio/freopen.c (freopen): ditto
	* libc/stdio/fread.c (fread): perform CRLF conversions if __SCLE
	* libc/stdio/fvwrite.c (__sfvwrite): ditto

Index: newlib/libc/include/stdio.h
===================================================================
RCS file: /cvs/src/src/newlib/libc/include/stdio.h,v
retrieving revision 1.1.1.1
diff -p -3 -r1.1.1.1 stdio.h
*** stdio.h	2000/02/17 19:39:46	1.1.1.1
--- stdio.h	2000/05/01 16:54:25
*************** typedef struct __sFILE FILE;
*** 66,71 ****
--- 66,74 ----
  #define	__SNPT	0x0800		/* do not do fseek() optimisation */
  #define	__SOFF	0x1000		/* set iff _offset is in fact correct */
  #define	__SMOD	0x2000		/* true => fgetline modified _p text */
+ #if defined(__CYGWIN__) || defined(__CYGWIN32__)
+ #define __SCLE	0x4000		/* convert line endings CR/LF <-> NL */
+ #endif
  
  /*
   * The following three definitions are for ANSI C, which took them
*************** FILE	*_EXFUN(funopen,(const _PTR _cookie
*** 251,257 ****
   * The __sfoo macros are here so that we can 
   * define function versions in the C library.
   */
! #define	__sgetc(p) (--(p)->_r < 0 ? __srget(p) : (int)(*(p)->_p++))
  #ifdef _never /* __GNUC__ */
  /* If this inline is actually used, then systems using coff debugging
     info get hopelessly confused.  21sept93 rich@cygnus.com.  */
--- 254,279 ----
   * The __sfoo macros are here so that we can 
   * define function versions in the C library.
   */
! #define	__sgetc_raw(p) (--(p)->_r < 0 ? __srget(p) : (int)(*(p)->_p++))
! 
! #ifdef __SCLE
! static __inline__ int __sgetc(FILE *__p)
!   {
!     int __c = __sgetc_raw(__p);
!     if ((__p->_flags & __SCLE) && (__c == '\r'))
!       {
! 	int __c2 = __sgetc_raw(__p);
! 	if (__c2 == '\n')
! 	  __c = __c2;
! 	else
! 	  ungetc(__c2, __p);
!       }
!     return __c;
!   }
! #else
! #define __sgetc(p) __sgetc_raw(p)
! #endif
! 
  #ifdef _never /* __GNUC__ */
  /* If this inline is actually used, then systems using coff debugging
     info get hopelessly confused.  21sept93 rich@cygnus.com.  */
*************** static __inline int __sputc(int _c, FILE
*** 265,271 ****
  /*
   * This has been tuned to generate reasonable code on the vax using pcc
   */
! #define	__sputc(c, p) \
  	(--(p)->_w < 0 ? \
  		(p)->_w >= (p)->_lbfsize ? \
  			(*(p)->_p = (c)), *(p)->_p != '\n' ? \
--- 287,293 ----
  /*
   * This has been tuned to generate reasonable code on the vax using pcc
   */
! #define	__sputc_raw(c, p) \
  	(--(p)->_w < 0 ? \
  		(p)->_w >= (p)->_lbfsize ? \
  			(*(p)->_p = (c)), *(p)->_p != '\n' ? \
*************** static __inline int __sputc(int _c, FILE
*** 273,278 ****
--- 295,308 ----
  				__swbuf('\n', p) : \
  			__swbuf((int)(c), p) : \
  		(*(p)->_p = (c), (int)*(p)->_p++))
+ #ifdef __SCLE
+ #define __sputc(c, p) \
+ 	  ((((p)->_flags & __SCLE) && ((c) == '\n')) \
+ 	    ? __sputc_raw('\r', (p)) : 0 , \
+ 	  __sputc_raw((c), (p)))
+ #else
+ #define __sputc(c, p) __sputc_raw(c, p)
+ #endif
  #endif
  
  #define	__sfeof(p)	(((p)->_flags & __SEOF) != 0)
Index: newlib/libc/stdio/fdopen.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/fdopen.c,v
retrieving revision 1.1.1.1
diff -p -3 -r1.1.1.1 fdopen.c
*** fdopen.c	2000/02/17 19:39:47	1.1.1.1
--- fdopen.c	2000/05/01 16:54:25
*************** _DEFUN (_fdopen_r, (ptr, fd, mode),
*** 100,105 ****
--- 100,111 ----
    fp->_write = __swrite;
    fp->_seek = __sseek;
    fp->_close = __sclose;
+ 
+ #ifdef __SCLE
+   if (setmode(fp->_file, O_BINARY) == O_TEXT)
+     fp->_flags |= __SCLE;
+ #endif
+ 
    return fp;
  }
  
Index: newlib/libc/stdio/fopen.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/fopen.c,v
retrieving revision 1.1.1.1
diff -p -3 -r1.1.1.1 fopen.c
*** fopen.c	2000/02/17 19:39:47	1.1.1.1
--- fopen.c	2000/05/01 16:54:25
*************** static char sccsid[] = "%W% (Berkeley) %
*** 116,121 ****
--- 116,124 ----
  #include <stdio.h>
  #include <errno.h>
  #include "local.h"
+ #ifdef __CYGWIN__
+ #include <fcntl.h>
+ #endif
  
  FILE *
  _DEFUN (_fopen_r, (ptr, file, mode),
*************** _DEFUN (_fopen_r, (ptr, file, mode),
*** 148,153 ****
--- 151,161 ----
  
    if (fp->_flags & __SAPP)
      fseek (fp, 0, SEEK_END);
+ 
+ #ifdef __SCLE
+   if (setmode(fp->_file, O_BINARY) == O_TEXT)
+     fp->_flags |= __SCLE;
+ #endif
  
    return fp;
  }
Index: newlib/libc/stdio/fread.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/fread.c,v
retrieving revision 1.1.1.1
diff -p -3 -r1.1.1.1 fread.c
*** fread.c	2000/02/17 19:39:47	1.1.1.1
--- fread.c	2000/05/01 16:54:25
*************** Supporting OS subroutines required: <<cl
*** 59,64 ****
--- 59,113 ----
  #include <string.h>
  #include "local.h"
  
+ #ifdef __SCLE
+ static size_t
+ _DEFUN (crlf, (fp, buf, count, eof),
+ 	FILE * fp _AND
+ 	char * buf _AND
+ 	size_t count _AND
+ 	int eof)
+ {
+   int newcount = 0, r;
+   char *s, *d, *e;
+ 
+   if (count == 0)
+     return 0;
+ 
+   e = buf + count;
+   for (s=d=buf; s<e-1; s++)
+     {
+       if (*s == '\r' && s[1] == '\n')
+ 	s++;
+       *d++ = *s;
+     }
+   if (s < e)
+     {
+       if (*s == '\r')
+ 	{
+ 	  int c = __sgetc_raw(fp);
+ 	  if (c == '\n')
+ 	    *s = '\n';
+ 	  else
+ 	    ungetc(c, fp);
+ 	}
+       *d++ = *s++;
+     }
+ 
+ 
+   while (d < e)
+     {
+       r = getc(fp);
+       if (r == EOF)
+ 	return count - (e-d);
+       *d++ = r;
+     }
+ 
+   return count;
+   
+ }
+ 
+ #endif
+ 
  size_t
  _DEFUN (fread, (buf, size, count, fp),
  	_PTR buf _AND
*************** _DEFUN (fread, (buf, size, count, fp),
*** 77,82 ****
--- 126,132 ----
      fp->_r = 0;
    total = resid;
    p = buf;
+ 
    while (resid > (r = fp->_r))
      {
        (void) memcpy ((void *) p, (void *) fp->_p, (size_t) r);
*************** _DEFUN (fread, (buf, size, count, fp),
*** 87,97 ****
--- 137,155 ----
        if (__srefill (fp))
  	{
  	  /* no more input: return partial result */
+ #ifdef __SCLE
+ 	  if (fp->_flags & __SCLE)
+ 	      return crlf(fp, buf, total-resid, 1) / size;
+ #endif
  	  return (total - resid) / size;
  	}
      }
    (void) memcpy ((void *) p, (void *) fp->_p, resid);
    fp->_r -= resid;
    fp->_p += resid;
+ #ifdef __SCLE
+   if (fp->_flags & __SCLE)
+     return crlf(fp, buf, total, 0) / size;
+ #endif
    return count;
  }
Index: newlib/libc/stdio/freopen.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/freopen.c,v
retrieving revision 1.1.1.1
diff -p -3 -r1.1.1.1 freopen.c
*** freopen.c	2000/02/17 19:39:47	1.1.1.1
--- freopen.c	2000/05/01 16:54:25
*************** _DEFUN (freopen, (file, mode, fp),
*** 147,151 ****
--- 147,157 ----
    fp->_write = __swrite;
    fp->_seek = __sseek;
    fp->_close = __sclose;
+ 
+ #ifdef __SCLE
+   if (setmode(fp->_file, O_BINARY) == O_TEXT)
+     fp->_flags |= __SCLE;
+ #endif
+ 
    return fp;
  }
Index: newlib/libc/stdio/fvwrite.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/fvwrite.c,v
retrieving revision 1.1.1.1
diff -p -3 -r1.1.1.1 fvwrite.c
*** fvwrite.c	2000/02/17 19:39:47	1.1.1.1
--- fvwrite.c	2000/05/01 16:54:25
*************** __sfvwrite (fp, uio)
*** 62,67 ****
--- 62,88 ----
  
    iov = uio->uio_iov;
    len = 0;
+ 
+ #ifdef __SCLE
+   if (fp->_flags & __SCLE) /* text mode */
+     {
+       do
+ 	{
+ 	  GETIOV (;);
+ 	  while (len > 0)
+ 	    {
+ 	      if (putc(*p, fp) == EOF)
+ 		return EOF;
+ 	      p++;
+ 	      len--;
+ 	      uio->uio_resid--;
+ 	    }
+ 	}
+       while (uio->uio_resid > 0);
+       return 0;
+     }
+ #endif
+ 
    if (fp->_flags & __SNBF)
      {
        /*


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]