# Commits

committed 7ecc491

Take Tim's work on file.truncate out of 2.2.1 again.

• Participants
• Parent commits a34f919
• Branches 2.2

# File Doc/lib/libstdtypes.tex


 \subsection{Numeric Types \label{typesnumeric}}

-There are four numeric types: \dfn{plain integers}, \dfn{long integers},
+There are four numeric types: \dfn{plain integers}, \dfn{long integers},
 \dfn{floating point numbers}, and \dfn{complex numbers}.
 Plain integers (also just called \dfn{integers})
 are implemented using \ctype{long} in C, which gives them at least 32

 Complex numbers have a real and imaginary part, which are both
 implemented using \ctype{double} in C.  To extract these parts from
-a complex number \var{z}, use \code{\var{z}.real} and \code{\var{z}.imag}.
+a complex number \var{z}, use \code{\var{z}.real} and \code{\var{z}.imag}.

 Numbers are created by numeric literals or as the result of built-in
 functions and operators.  Unadorned integer literals (including hex

 \item[(1)]
 For (plain or long) integer division, the result is an integer.
-The result is always rounded towards minus infinity: 1/2 is 0,
+The result is always rounded towards minus infinity: 1/2 is 0,
 (-1)/2 is -1, 1/(-2) is -1, and (-1)/(-2) is 0.  Note that the result
 is a long integer if either operand is a long integer, regardless of
 the numeric value.
   the end of the string: \code{len(\var{s}) + \var{i}} or
   \code{len(\var{s}) + \var{j}} is substituted.  But note that \code{-0} is
   still \code{0}.
-
+
 \item[(3)] The slice of \var{s} from \var{i} to \var{j} is defined as
   the sequence of items with index \var{k} such that \code{\var{i} <=
   \var{k} < \var{j}}.  If \var{i} or \var{j} is greater than

 Additional string operations are defined in standard modules
 \refmodule{string}\refstmodindex{string} and
-\refmodule{re}.\refstmodindex{re}
+\refmodule{re}.\refstmodindex{re}


 \subsubsection{XRange Type \label{typesseq-xrange}}
   no longer works in Python 2.0.  Use of this misfeature has been
   deprecated since Python 1.4.

-\item[(2)] Raises an exception when \var{x} is not a list object.  The
+\item[(2)] Raises an exception when \var{x} is not a list object.  The
   \method{extend()} method is experimental and not supported by
   mutable sequence types other than lists.


 File objects\obindex{file} are implemented using C's \code{stdio}
 package and can be created with the built-in constructor
-\function{file()}\bifuncindex{file} described in section
+\function{file()}\bifuncindex{file} described in section
 \ref{built-in-funcs}, Built-in Functions.''\footnote{\function{file()}
 is new in Python 2.2.  The older built-in \function{open()} is an
 alias for \function{file()}.}
 \begin{methoddesc}[file]{readline}{\optional{size}}
   Read one entire line from the file.  A trailing newline character is
   kept in the string\footnote{
-	The advantage of leaving the newline on is that an empty string
-	can be returned to mean \EOF{} without being ambiguous.  Another
-	advantage is that (in cases where it might matter, for example. if you
-	want to make an exact copy of a file while scanning its lines)
+	The advantage of leaving the newline on is that an empty string
+	can be returned to mean \EOF{} without being ambiguous.  Another
+	advantage is that (in cases where it might matter, for example. if you
+	want to make an exact copy of a file while scanning its lines)
 	you can tell whether the last line of a file ended in a newline
 	or not (yes this happens!).
   } (but may be absent when a file ends with an
 \end{methoddesc}

 \begin{methoddesc}[file]{truncate}{\optional{size}}
-  Truncate the file's size.  If the optional \var{size} argument is
+  Truncate the file's size.  If the optional \var{size} argument
   present, the file is truncated to (at most) that size.  The size
-  defaults to the current position.  The current file position is
-  not changed.  Note that if a specified size exceeds the file's
-  current size, the result is platform-dependent:  possibilities
-  include that file may remain unchanged, increase to the specified
-  size as if zero-filled, or increase to the specified size with
-  undefined new content.
-  Availability:  Windows, many \UNIX variants.
+  defaults to the current position.  Availability of this function
+  depends on the operating system version (for example, not all
+  \UNIX{} versions support this operation).
 \end{methoddesc}

 \begin{methoddesc}[file]{write}{str}

# File Lib/test/test_largefile.py

 expect(f.read(1), 'a') # the 'a' that was written at the end of the file above
 f.close()

-if hasattr(f, 'truncate'):
-    if test_support.verbose:
-        print 'try truncate'
-    f = open(name, 'r+b')
-    f.seek(0, 2)
-    expect(f.tell(), size+1)    # else we've lost track of the true size
-    # Cut it back via seek + truncate with no argument.
-    newsize = size - 10
-    f.seek(newsize)
-    f.truncate()
-    expect(f.tell(), newsize)   # else pointer moved
-    f.seek(0, 2)
-    expect(f.tell(), newsize)   # else wasn't truncated
-    # Ensure that truncate(smaller than true size) shrinks the file.
-    newsize -= 1
-    f.seek(42)
-    f.truncate(newsize)
-    expect(f.tell(), 42)        # else pointer moved
-    f.seek(0, 2)
-    expect(f.tell(), newsize)   # else wasn't truncated

-    # XXX truncate(larger than true size) is ill-defined across platforms
-
-    # cut it waaaaay back
-    f.seek(0)
-    f.truncate(1)
-    expect(f.tell(), 0)         # else pointer moved
-    expect(len(f.read()), 1)    # else wasn't truncated
-
-    f.close()
+# XXX add tests for truncate if it exists
+# XXX has truncate ever worked on Windows? specifically on WinNT I get:
+#     "IOError: [Errno 13] Permission denied"
+##try:
+##      newsize = size - 10
+##      f.seek(newsize)
+##      f.truncate()
+##      expect(f.tell(), newsize)
+##      newsize = newsize - 1
+##      f.seek(0)
+##      f.truncate(newsize)
+##      expect(f.tell(), newsize)
+##except AttributeError:
+##      pass

 os.unlink(name)

# File Misc/NEWS

   arbitrary shell code can't be executed because a bogus URL was
   passed in.

-Windows
-
-- file.truncate([newsize]) now works on Windows for all newsize values.
-  It used to fail if newsize didn't fit in 32 bits, reflecting a
-  limitation of MS _chsize (which is no longer used).

 What's New in Python 2.2 final?
 Release date: 21-Dec-2001

# File Objects/fileobject.c


 #ifdef MS_WIN32
 #define fileno _fileno
-/* can simulate truncate with Win32 API functions; see file_truncate */
+/* can (almost fully) duplicate with _chsize, see file_truncate */
 #define HAVE_FTRUNCATE
-#define WINDOWS_LEAN_AND_MEAN
-#include <windows.h>
 #endif

 #ifdef macintosh
 	newsizeobj = NULL;
 	if (!PyArg_ParseTuple(args, "|O:truncate", &newsizeobj))
 		return NULL;
-
-	/* Set newsize to current postion if newsizeobj NULL, else to the
-	   specified value. */
 	if (newsizeobj != NULL) {
 #if !defined(HAVE_LARGEFILE_SUPPORT)
 		newsize = PyInt_AsLong(newsizeobj);
 #endif
 		if (PyErr_Occurred())
 			return NULL;
-	}
-	else {
-		/* Default to current position. */
+	} else {
+		/* Default to current position*/
 		Py_BEGIN_ALLOW_THREADS
 		errno = 0;
 		newsize = _portable_ftell(f->f_fp);
 		Py_END_ALLOW_THREADS
-		if (newsize == -1)
-			goto onioerror;
+		if (newsize == -1) {
+		        PyErr_SetFromErrno(PyExc_IOError);
+			clearerr(f->f_fp);
+			return NULL;
+		}
 	}
-
-	/* Flush the file. */
 	Py_BEGIN_ALLOW_THREADS
 	errno = 0;
 	ret = fflush(f->f_fp);
 	Py_END_ALLOW_THREADS
-	if (ret != 0)
-		goto onioerror;
+	if (ret != 0) goto onioerror;

 #ifdef MS_WIN32
-	/* MS _chsize doesn't work if newsize doesn't fit in 32 bits,
-	   so don't even try using it. */
-	{
-		Py_off_t current;	/* current file position */
-		HANDLE hFile;
-		int error;
-
-		/* current <- current file postion. */
-		if (newsizeobj == NULL)
-			current = newsize;
-		else {
-			Py_BEGIN_ALLOW_THREADS
-			errno = 0;
-			current = _portable_ftell(f->f_fp);
-			Py_END_ALLOW_THREADS
-			if (current == -1)
-				goto onioerror;
-		}
-
-		/* Move to newsize. */
-		if (current != newsize) {
-			Py_BEGIN_ALLOW_THREADS
-			errno = 0;
-			error = _portable_fseek(f->f_fp, newsize, SEEK_SET)
-				!= 0;
-			Py_END_ALLOW_THREADS
-			if (error)
-				goto onioerror;
-		}
-
-		/* Truncate.  Note that this may grow the file! */
+	/* can use _chsize; if, however, the newsize overflows 32-bits then
+	   _chsize is *not* adequate; in this case, an OverflowError is raised */
+	if (newsize > LONG_MAX) {
+		PyErr_SetString(PyExc_OverflowError,
+			"the new size is too long for _chsize (it is limited to 32-bit values)");
+		return NULL;
+	} else {
 		Py_BEGIN_ALLOW_THREADS
 		errno = 0;
-		hFile = (HANDLE)_get_osfhandle(fileno(f->f_fp));
-		error = hFile == (HANDLE)-1;
-		if (!error) {
-			error = SetEndOfFile(hFile) == 0;
-			if (error)
-				errno = EACCES;
-		}
+		ret = _chsize(fileno(f->f_fp), (long)newsize);
 		Py_END_ALLOW_THREADS
-		if (error)
-			goto onioerror;
-
-		/* Restore original file position. */
-		if (current != newsize) {
-			Py_BEGIN_ALLOW_THREADS
-			errno = 0;
-			error = _portable_fseek(f->f_fp, current, SEEK_SET)
-				!= 0;
-			Py_END_ALLOW_THREADS
-			if (error)
-				goto onioerror;
-		}
+		if (ret != 0) goto onioerror;
 	}
 #else
 	Py_BEGIN_ALLOW_THREADS