delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2000/12/11/23:14:59

Message-Id: <5.0.2.1.0.20001211221616.00a71e51@pop5.banet.net>
X-Sender: usbanet DOT farley3 AT pop5 DOT banet DOT net (Unverified)
X-Mailer: QUALCOMM Windows Eudora Version 5.0.2
Date: Mon, 11 Dec 2000 23:09:39 -0500
To: djgpp-workers AT delorie DOT com
From: "Peter J. Farley III" <pjfarley AT banet DOT net>
Subject: Locking fcntl changes #2
Mime-Version: 1.0
Reply-To: djgpp-workers AT delorie DOT com

--=====================_4043618==_
Content-Type: text/plain; charset="us-ascii"; format=flowed

OK, Real Soon Now has arrived.  I think I have incorporated all of the 
suggestions and corrections that were made.  Here are the major changes 
since the first version:

1.	fcntl changes:

All F_RDLCK requests are treated just like F_WRLCK requests.

FAT32 support has been added, with three new fcntl command values 
called F_GETLK64, F_SETLK64 and F_SETLKW64.  There is also a new struct 
flock64 to match.

F_SETLKW[64] functions now work as advertised, and lock up the program 
as advertised when the lock is already held.  FIXME comments have been 
added in the test programs where it would be good to have a SIGINT 
handler to better test and recover from F_SETLKW endless loops.  I've 
never done signal programming, so I don't know how to add such code.

Additional checking has been added to the internal functions for SFT 
processing, in case they are ever externalized.

2.	Internal functions _dos_lk64, _dos_unlk64, lock64 and unlock64 have 
been added.  The "_dos" functions where the interrupt is actually 
called were modeled on the coding used in llseek to put 32-bit values 
into the registers.

3.	Function llockf has been added for FAT32 support.  Function lockf is 
also provided as an interface to the 31-bit locking functions.

4.	All .txh files were updated as suggested, to the best of my 
knowledge.  New .txh files were written for all functions added.

5.	The dostrerr function replaces the four functions implemented in the 
first pass.  It now takes two structure arguments, the second one 
containing four (char *) pointer members.  All "magic numbers" have 
been removed.  Ditto for strerror, which had an identical "magic 
number".

6.	Tests were expanded for all major functions added (fcntl, flock, 
[l]lockf).

As before, all comments and suggestions welcome.  In addition, after 
these patches are accepted and applied, someone needs to test the FAT32 
functions with real 32-bit offsets on a file whose size is > 2GB.  I 
have not done that.  All coded tests just use zero offsets.  Similarly, 
multi-region locking tests need to be added, though I may try to add 
them myself if there are a lot of other changes needed to this pass.

--=====================_4043618==_
Content-Type: text/plain; charset="us-ascii"

diff -ruN djgpp-cvs/include/dos.h djgpp/include/dos.h
--- djgpp-cvs/include/dos.h	Thu Jun 22 14:20:36 2000
+++ djgpp/include/dos.h	Fri Dec  8 23:26:46 2000
@@ -1,3 +1,4 @@
+/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
@@ -235,6 +236,18 @@
 };
 #define DOSERROR _DOSERROR
 
+struct _DOSERROR_STR {
+  char *exterror_str;
+  #ifdef __cplusplus
+  char *errclass_str;
+  #else
+  char *class_str;
+  #endif
+  char *action_str;
+  char *locus_str;
+};
+#define DOSERROR_STR _DOSERROR_STR
+
 unsigned int   _dos_creat(const char *_filename, unsigned int _attr, int *_handle);
 unsigned int   _dos_creatnew(const char *_filename, unsigned int _attr, int *_handle);
 unsigned int   _dos_open(const char *_filename, unsigned int _mode, int *_handle);
@@ -262,6 +275,8 @@
 
 int            _dosexterr(struct _DOSERROR *_p_error);
 #define dosexterr(_ep) _dosexterr(_ep)
+int            _dostrerr(struct _DOSERROR *_p_error, struct _DOSERROR_STR *_p_str);
+#define dostrerr(_ep,_sp) _dostrerr(_ep,_sp)
 
 #define int386(_i, _ir, _or)         int86(_i, _ir, _or)
 #define int386x(_i, _ir, _or, _sr)   int86x(_i, _ir, _or, _sr)
diff -ruN djgpp-cvs/include/fcntl.h djgpp/include/fcntl.h
--- djgpp-cvs/include/fcntl.h	Thu Aug 17 04:46:00 2000
+++ djgpp/include/fcntl.h	Sat Dec  9 12:35:24 2000
@@ -21,6 +21,9 @@
 #define F_SETFL		6
 #define F_SETLK		7
 #define F_SETLKW	8
+#define F_GETLK64   9
+#define F_SETLK64	10
+#define F_SETLKW64	11
 
 #define F_UNLCK		0
 #define F_RDLCK		1
@@ -51,6 +54,14 @@
   short	l_type;
   short	l_whence;
 };
+
+struct flock64 {
+  offset_t	l_len;
+  pid_t	l_pid;
+  offset_t	l_start;
+  short	l_type;
+  short	l_whence;
+};
 
 extern int _fmode; /* O_TEXT or O_BINARY */
 
diff -ruN djgpp-cvs/include/io.h djgpp/include/io.h
--- djgpp-cvs/include/io.h	Sun Jun 28 18:42:16 1998
+++ djgpp/include/io.h	Sat Dec  9 14:13:02 2000
@@ -21,15 +21,19 @@
 int		_creatnew(const char *_path, int _attrib, int _mode);
 ssize_t		crlf2nl(char *_buffer, ssize_t _length);
 int		_dos_lock(int _fd, long _offset, long _length);
+int		_dos_lk64(int _fd, long long _offset, long long _length);
 long		filelength(int _handle);
 short		_get_dev_info(int _arg);
 int		lock(int _fd, long _offset, long _length);
+int		lock64(int _fd, long long _offset, long long _length);
 int		_open(const char *_path, int _oflag);
 ssize_t		_read(int _fd, void *_buf, size_t _nbyte);
 int		setmode(int _fd, int _newmode);
 off_t		tell(int _fd);
 int		_dos_unlock(int _fd, long _offset, long _length);
+int		_dos_unlk64(int _fd, long long _offset, long long _length);
 int		unlock(int _fd, long _offset, long _length);
+int		unlock64(int _fd, long long _offset, long long _length);
 ssize_t		_write(int _fd, const void *_buf, size_t _nbyte);
 int	        _chmod(const char *_path, int _func, ...);
 void		_flush_disk_cache(void);
diff -ruN djgpp-cvs/include/libc/getdinfo.h djgpp/include/libc/getdinfo.h
--- djgpp-cvs/include/libc/getdinfo.h	Thu Jan  1 00:00:00 1970
+++ djgpp/include/libc/getdinfo.h	Wed Dec  6 01:15:22 2000
@@ -0,0 +1,25 @@
+/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
+#ifndef __dj_include_libc_getdinfo_h__
+#define __dj_include_libc_getdinfo_h__
+
+#ifndef __dj_ENFORCE_ANSI_FREESTANDING
+
+#ifndef __STRICT_ANSI__
+
+#ifndef _POSIX_SOURCE
+
+/* For parsing the bits returned by _get_dev_info.  */
+#define _DEV_STDIN	0x0001
+#define _DEV_STDOUT	0x0002
+#define _DEV_NUL	0x0004
+#define _DEV_CLOCK	0x0008
+#define _DEV_RAW	0x0020
+#define _DEV_CDEV	0x0080
+#define _DEV_NO_INHERIT	0x1000 /* Undocumented. */
+#define _DEV_IOCTRL	0x4000
+
+#endif /* !_POSIX_SOURCE */
+#endif /* !__STRICT_ANSI__ */
+#endif /* !__dj_ENFORCE_ANSI_FREESTANDING */
+
+#endif
diff -ruN djgpp-cvs/include/sys/file.h djgpp/include/sys/file.h
--- djgpp-cvs/include/sys/file.h	Thu Apr 20 01:35:34 1995
+++ djgpp/include/sys/file.h	Fri Dec  8 23:33:58 2000
@@ -22,6 +22,18 @@
 #define L_CURR 1
 #define L_INCR 1
 #define L_XTND 2
+
+/* Operations for the `flock' call.  */
+#define	LOCK_SH	1	/* Shared lock.  */
+#define	LOCK_EX	2 	/* Exclusive lock.  */
+#define	LOCK_UN	8	/* Unlock.  */
+
+/* Can be OR'd in to one of the above.  */
+#define	LOCK_NB	4	/* Don't block when locking.  */
+
+/* Apply or remove an advisory lock, according to OPERATION,
+   on the file FD refers to.  */
+int	flock (int _fildes, int _op);
   
 #ifndef __dj_ENFORCE_FUNCTION_CALLS
 #endif /* !__dj_ENFORCE_FUNCTION_CALLS */
diff -ruN djgpp-cvs/include/unistd.h djgpp/include/unistd.h
--- djgpp-cvs/include/unistd.h	Fri Aug 11 07:16:16 2000
+++ djgpp/include/unistd.h	Mon Dec 11 00:39:44 2000
@@ -18,6 +18,15 @@
 #define SEEK_SET	0
 #define SEEK_CUR	1
 #define SEEK_END	2
+
+/* `lockf' is a simpler interface to the locking facilities of `fcntl'.
+   LEN is always relative to the current file position.
+   The CMD argument is one of the following.  */
+
+# define F_ULOCK 0	/* Unlock a previously locked region.  */
+# define F_LOCK  1	/* Lock a region for exclusive use.  */
+# define F_TLOCK 2	/* Test and lock a region for exclusive use.  */
+# define F_TEST  3	/* Test a region for other processes locks.  */
   
 /* Some programs think they know better... */
 #undef NULL
@@ -136,6 +145,8 @@
 int		getpagesize(void);
 char *		getwd(char *__buffer);
 int             lchown(const char * file, int owner, int group);
+int		lockf(int _fildes, int _cmd, off_t _len);
+int		llockf(int _fildes, int _cmd, offset_t _len);
 offset_t	llseek(int _fildes, offset_t _offset, int _whence);
 int		nice(int _increment);
 int             readlink(const char * __file, char * __buffer, size_t __size);

--=====================_4043618==_
Content-Type: text/plain; charset="us-ascii"

diff -ruN djgpp-cvs/tests/libc/compat/unistd/makefile djgpp/tests/libc/compat/unistd/makefile
--- djgpp-cvs/tests/libc/compat/unistd/makefile	Fri Aug 25 07:37:10 2000
+++ djgpp/tests/libc/compat/unistd/makefile	Mon Dec 11 00:51:08 2000
@@ -3,6 +3,8 @@
 SRC += readlink.c
 SRC += sdirlink.c
 SRC += symlink.c
+SRC += tlockf.c
+SRC += tllockf.c
 SRC += xsymlink.c
 
 include $(TOP)/../makefile.inc
diff -ruN djgpp-cvs/tests/libc/compat/unistd/tllockf.c djgpp/tests/libc/compat/unistd/tllockf.c
--- djgpp-cvs/tests/libc/compat/unistd/tllockf.c	Thu Jan  1 00:00:00 1970
+++ djgpp/tests/libc/compat/unistd/tllockf.c	Mon Dec 11 00:50:56 2000
@@ -0,0 +1,114 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <dos.h>
+#include <libc/dosio.h>
+
+void prdoserr(int fd) {
+  struct DOSERROR de;
+  struct DOSERROR_STR se;
+  int errsave;
+
+  printf("fd: %i\n", fd);
+  printf("errno: %i : %s\n", errno, strerror(errno));
+  dosexterr(&de);
+  errsave = de.exterror;
+  de.exterror = _doserrno;
+  dostrerr(&de, &se);
+  printf("DOS errno: %i : %s\n", _doserrno, se.exterror_str);
+  de.exterror = errsave;
+  dostrerr(&de, &se);
+  printf("DOS extended error to errno: %i : %s\n",
+    __doserr_to_errno(de.exterror),strerror(__doserr_to_errno(de.exterror)));
+  printf("Extended DOS error information:\n");
+  printf("Extended error: %i : %s\n",de.exterror,se.exterror_str);
+  printf("Class:          %02X : %s\n",de.class,se.class_str);
+  printf("Action:         %02X : %s\n",de.action,se.action_str);
+  printf("Error Locus:    %02X : %s\n",de.locus,se.locus_str);
+}
+
+
+int main(void) {
+  int retval, fd;
+
+  fd = open("tllockf.c", O_RDONLY);
+
+  errno = 0;
+  retval = llockf(fd, F_TEST, 0);
+  printf("F_TEST:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = llockf(fd, F_TLOCK, 0);
+  printf("F_TLOCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = llockf(fd, F_TLOCK, 0);
+  printf("F_TLOCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = llockf(fd, F_TEST, 0);
+  printf("F_TEST:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = llockf(fd, F_ULOCK, 0);
+  printf("F_ULOCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = llockf(fd, F_ULOCK, 0);
+  printf("F_ULOCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = llockf(fd, F_TEST, 0);
+  printf("F_TEST:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = llockf(fd, F_LOCK, 0);
+  printf("F_LOCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  /* This call will lock the program in an endless loop,
+     since it already has the lock.
+
+     FIXME -- Need to add SIGINT interrupt handler and
+              console output (syserr?) telling user to
+              press CNTL-Break to continue the test.
+
+     Commented out for now, replaced with message about bypass.
+
+  errno = 0;
+  retval = llockf(fd, F_LOCK, 0);
+  printf("F_LOCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  */
+
+  printf("F_LOCK:Bypassed to avoid lockup in endless loop.\n");
+
+  errno = 0;
+  retval = llockf(fd, F_TEST, 0);
+  printf("F_TEST:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = llockf(fd, F_ULOCK, 0);
+  printf("F_ULOCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = llockf(fd, F_TEST, 0);
+  printf("F_TEST:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  close(fd);
+  exit(0);
+}
diff -ruN djgpp-cvs/tests/libc/compat/unistd/tlockf.c djgpp/tests/libc/compat/unistd/tlockf.c
--- djgpp-cvs/tests/libc/compat/unistd/tlockf.c	Thu Jan  1 00:00:00 1970
+++ djgpp/tests/libc/compat/unistd/tlockf.c	Sun Dec 10 23:52:42 2000
@@ -0,0 +1,114 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <dos.h>
+#include <libc/dosio.h>
+
+void prdoserr(int fd) {
+  struct DOSERROR de;
+  struct DOSERROR_STR se;
+  int errsave;
+
+  printf("fd: %i\n", fd);
+  printf("errno: %i : %s\n", errno, strerror(errno));
+  dosexterr(&de);
+  errsave = de.exterror;
+  de.exterror = _doserrno;
+  dostrerr(&de, &se);
+  printf("DOS errno: %i : %s\n", _doserrno, se.exterror_str);
+  de.exterror = errsave;
+  dostrerr(&de, &se);
+  printf("DOS extended error to errno: %i : %s\n",
+    __doserr_to_errno(de.exterror),strerror(__doserr_to_errno(de.exterror)));
+  printf("Extended DOS error information:\n");
+  printf("Extended error: %i : %s\n",de.exterror,se.exterror_str);
+  printf("Class:          %02X : %s\n",de.class,se.class_str);
+  printf("Action:         %02X : %s\n",de.action,se.action_str);
+  printf("Error Locus:    %02X : %s\n",de.locus,se.locus_str);
+}
+
+
+int main(void) {
+  int retval, fd;
+
+  fd = open("tlockf.c", O_RDONLY);
+
+  errno = 0;
+  retval = lockf(fd, F_TEST, 0);
+  printf("F_TEST:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = lockf(fd, F_TLOCK, 0);
+  printf("F_TLOCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = lockf(fd, F_TLOCK, 0);
+  printf("F_TLOCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = lockf(fd, F_TEST, 0);
+  printf("F_TEST:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = lockf(fd, F_ULOCK, 0);
+  printf("F_ULOCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = lockf(fd, F_ULOCK, 0);
+  printf("F_ULOCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = lockf(fd, F_TEST, 0);
+  printf("F_TEST:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = lockf(fd, F_LOCK, 0);
+  printf("F_LOCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  /* This call will lock the program in an endless loop,
+     since it already has the lock.
+
+     FIXME -- Need to add SIGINT interrupt handler and
+              console output (syserr?) telling user to
+              press CNTL-Break to continue the test.
+
+     Commented out for now, replaced with message about bypass.
+
+  errno = 0;
+  retval = lockf(fd, F_LOCK, 0);
+  printf("F_LOCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  */
+
+  printf("F_LOCK:Bypassed to avoid lockup in endless loop.\n");
+
+  errno = 0;
+  retval = lockf(fd, F_TEST, 0);
+  printf("F_TEST:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = lockf(fd, F_ULOCK, 0);
+  printf("F_ULOCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = lockf(fd, F_TEST, 0);
+  printf("F_TEST:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  close(fd);
+  exit(0);
+}
diff -ruN djgpp-cvs/tests/libc/posix/fcntl/makefile djgpp/tests/libc/posix/fcntl/makefile
--- djgpp-cvs/tests/libc/posix/fcntl/makefile	Thu Aug 17 04:46:22 2000
+++ djgpp/tests/libc/posix/fcntl/makefile	Fri Dec  8 23:51:24 2000
@@ -4,5 +4,6 @@
 SRC += bt.c
 SRC += open.c
 SRC += trunc.c
+SRC += tfcntl.c
 
 include $(TOP)/../makefile.inc
diff -ruN djgpp-cvs/tests/libc/posix/fcntl/tfcntl.c djgpp/tests/libc/posix/fcntl/tfcntl.c
--- djgpp-cvs/tests/libc/posix/fcntl/tfcntl.c	Thu Jan  1 00:00:00 1970
+++ djgpp/tests/libc/posix/fcntl/tfcntl.c	Sun Dec 10 00:16:30 2000
@@ -0,0 +1,220 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <dos.h>
+#include <libc/dosio.h>
+
+void prdoserr(int fd) {
+  struct _DOSERROR de;
+  struct DOSERROR_STR se;
+  int errsave;
+
+  printf("fd: %i\n", fd);
+  printf("errno: %i : %s\n", errno, strerror(errno));
+  dosexterr(&de);
+  errsave = de.exterror;
+  de.exterror = _doserrno;
+  dostrerr(&de, &se);
+  printf("DOS errno: %i : %s\n", _doserrno, se.exterror_str);
+  de.exterror = errsave;
+  dostrerr(&de, &se);
+  printf("DOS extended error to errno: %i : %s\n",
+    __doserr_to_errno(de.exterror),strerror(__doserr_to_errno(de.exterror)));
+  printf("Extended DOS error information:\n");
+  printf("Extended error: %i : %s\n",de.exterror,se.exterror_str);
+  printf("Class:          %02X : %s\n",de.class,se.class_str);
+  printf("Action:         %02X : %s\n",de.action,se.action_str);
+  printf("Error Locus:    %02X : %s\n",de.locus,se.locus_str);
+}
+
+
+int main(void) {
+#if defined(F_SETLK) && defined(F_SETLKW)
+  struct flock fl;
+  struct flock64 fl64;
+  int retval, fd;
+
+  fd = open("tfcntl.c", O_RDONLY);
+  fl.l_type = F_RDLCK;
+  fl.l_whence = SEEK_SET;
+  fl.l_start = fl.l_len = 0;
+
+  fl64.l_type = F_RDLCK;
+  fl64.l_whence = SEEK_SET;
+  fl64.l_start = fl64.l_len = 0L;
+
+  errno = 0;
+  retval = fcntl(fd, F_SETLK, &fl);
+  printf("F_SETLK/F_RDLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = fcntl(fd, F_SETLK, &fl);
+  printf("F_SETLK/F_RDLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = fcntl(fd, F_GETLK, &fl);
+  printf("F_GETLK/F_RDLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  fl.l_type = F_UNLCK;
+  retval = fcntl(fd, F_SETLK, &fl);
+  printf("F_SETLK/F_UNLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  fl.l_type = F_UNLCK;
+  retval = fcntl(fd, F_SETLK, &fl);
+  printf("F_SETLK/F_UNLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  fl.l_type = F_RDLCK;
+  retval = fcntl(fd, F_GETLK, &fl);
+  printf("F_GETLK/F_RDLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  /* F_SETLKW tests */
+
+  errno = 0;
+  fl.l_type = F_RDLCK;
+  retval = fcntl(fd, F_SETLKW, &fl);
+  printf("F_SETLKW/F_RDLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  /* This call will lock the program in an endless loop,
+     since it already has the lock.
+
+     FIXME -- Need to add SIGINT interrupt handler and
+              console output (syserr?) telling user to
+              press CNTL-Break to continue the test.
+
+     Commented out for now, replaced with message about bypass.
+
+  errno = 0;
+  retval = fcntl(fd, F_SETLKW, &fl);
+  printf("F_SETLKW/F_RDLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  */
+
+  printf("F_SETLKW/F_RDLCK:Bypassed to avoid lockup in endless loop.\n");
+
+  errno = 0;
+  retval = fcntl(fd, F_GETLK, &fl);
+  printf("F_GETLK/F_RDLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  fl.l_type = F_UNLCK;
+  retval = fcntl(fd, F_SETLK, &fl);
+  printf("F_SETLK/F_UNLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  fl.l_type = F_RDLCK;
+  retval = fcntl(fd, F_GETLK, &fl);
+  printf("F_GETLK/F_RDLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  /* FAT32 tests */
+
+  errno = 0;
+  fl64.l_type = F_RDLCK;
+  retval = fcntl(fd, F_SETLK64, &fl64);
+  printf("F_SETLK64/F_RDLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = fcntl(fd, F_SETLK64, &fl64);
+  printf("F_SETLK64/F_RDLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = fcntl(fd, F_GETLK64, &fl64);
+  printf("F_GETLK64/F_RDLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  fl64.l_type = F_UNLCK;
+  retval = fcntl(fd, F_SETLK64, &fl64);
+  printf("F_SETLK64/F_UNLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  fl64.l_type = F_RDLCK;
+  retval = fcntl(fd, F_GETLK64, &fl64);
+  printf("F_GETLK64/F_RDLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  /* F_SETLKW64 tests */
+
+  errno = 0;
+  fl64.l_type = F_RDLCK;
+  retval = fcntl(fd, F_SETLKW64, &fl64);
+  printf("F_SETLKW64/F_RDLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  /* This call will lock the program in an endless loop,
+     since it already has the lock.
+
+     FIXME -- Need to add SIGINT interrupt handler and
+              console output (syserr?) telling user to
+              press CNTL-Break to continue the test.
+
+     Commented out for now, replaced with message about bypass.
+
+  errno = 0;
+  retval = fcntl(fd, F_SETLKW64, &fl64);
+  printf("F_SETLKW64/F_RDLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  */
+
+  printf("F_SETLKW64/F_RDLCK:Bypassed to avoid lockup in endless loop.\n");
+
+  errno = 0;
+  retval = fcntl(fd, F_GETLK64, &fl64);
+  printf("F_GETLK64/F_RDLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  fl64.l_type = F_UNLCK;
+  retval = fcntl(fd, F_SETLK64, &fl64);
+  printf("F_SETLK64/F_UNLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  fl64.l_type = F_RDLCK;
+  retval = fcntl(fd, F_GETLK64, &fl64);
+  printf("F_GETLK64/F_RDLCK:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  /* Other function tests (non-lock-related) */
+
+  errno = 0;
+  retval = fcntl(fd, F_GETFD);
+  printf("F_GETFD:retval=%04x\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = fcntl(fd, F_SETFL, O_BINARY);
+  printf("F_SETFL:retval=%04x\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = fcntl(fd, F_GETFL);
+  printf("F_GETFL:retval=%04x\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  close(fd);
+  exit(0);
+#else
+  exit(99);
+#endif
+}
diff -ruN djgpp-cvs/tests/libc/posix/sys/file/makefile djgpp/tests/libc/posix/sys/file/makefile
--- djgpp-cvs/tests/libc/posix/sys/file/makefile	Thu Jan  1 00:00:00 1970
+++ djgpp/tests/libc/posix/sys/file/makefile	Sun Nov 26 01:00:14 2000
@@ -0,0 +1,5 @@
+TOP=../../..
+
+SRC += tflock.c
+
+include $(TOP)/../makefile.inc
diff -ruN djgpp-cvs/tests/libc/posix/sys/file/tflock.c djgpp/tests/libc/posix/sys/file/tflock.c
--- djgpp-cvs/tests/libc/posix/sys/file/tflock.c	Thu Jan  1 00:00:00 1970
+++ djgpp/tests/libc/posix/sys/file/tflock.c	Sun Dec 10 00:28:14 2000
@@ -0,0 +1,179 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <dos.h>
+#include <sys/file.h>
+#include <libc/dosio.h>
+
+void prdoserr(int fd) {
+  struct DOSERROR de;
+  struct DOSERROR_STR se;
+  int errsave;
+
+  printf("fd: %i\n", fd);
+  printf("errno: %i : %s\n", errno, strerror(errno));
+  dosexterr(&de);
+  errsave = de.exterror;
+  de.exterror = _doserrno;
+  dostrerr(&de, &se);
+  printf("DOS errno: %i : %s\n", _doserrno, se.exterror_str);
+  de.exterror = errsave;
+  dostrerr(&de, &se);
+  printf("DOS extended error to errno: %i : %s\n",
+    __doserr_to_errno(de.exterror),strerror(__doserr_to_errno(de.exterror)));
+  printf("Extended DOS error information:\n");
+  printf("Extended error: %i : %s\n",de.exterror,se.exterror_str);
+  printf("Class:          %02X : %s\n",de.class,se.class_str);
+  printf("Action:         %02X : %s\n",de.action,se.action_str);
+  printf("Error Locus:    %02X : %s\n",de.locus,se.locus_str);
+}
+
+
+int main(void) {
+  int retval, fd;
+
+  fd = open("tflock.c", O_RDONLY);
+
+  errno = 0;
+  retval = flock(fd, LOCK_SH);
+  printf("LOCK_SH:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  /* This call will lock the program in an endless loop,
+     since it already has the lock.
+
+     FIXME -- Need to add SIGINT interrupt handler and
+              console output (syserr?) telling user to
+              press CNTL-Break to continue the test.
+
+     Commented out for now, replaced with message about bypass.
+
+  errno = 0;
+  retval = flock(fd, LOCK_SH);
+  printf("LOCK_SH:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  */
+
+  printf("LOCK_SH:Bypassed to avoid lockup in endless loop.\n");
+
+  errno = 0;
+  retval = flock(fd, LOCK_UN);
+  printf("LOCK_UN:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = flock(fd, LOCK_UN);
+  printf("LOCK_UN:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = flock(fd, LOCK_EX);
+  printf("LOCK_EX:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  /* This call will lock the program in an endless loop,
+     since it already has the lock.
+
+     FIXME -- Need to add SIGINT interrupt handler and
+              console output (syserr?) telling user to
+              press CNTL-Break to continue the test.
+
+     Commented out for now, replaced with message about bypass.
+
+  errno = 0;
+  retval = flock(fd, LOCK_EX);
+  printf("LOCK_EX:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  */
+
+  printf("LOCK_EX:Bypassed to avoid lockup in endless loop.\n");
+
+  errno = 0;
+  retval = flock(fd, LOCK_UN);
+  printf("LOCK_UN:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = flock(fd, 77);
+  printf("Bad function code:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = flock(fd, LOCK_SH | LOCK_NB);
+  printf("LOCK_SH | LOCK_NB:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = flock(fd, LOCK_SH | LOCK_NB);
+  printf("LOCK_SH | LOCK_NB:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = flock(fd, LOCK_UN | LOCK_NB);
+  printf("LOCK_UN | LOCK_NB:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = flock(fd, LOCK_UN | LOCK_NB);
+  printf("LOCK_UN | LOCK_NB:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = flock(fd, LOCK_EX | LOCK_NB);
+  printf("LOCK_EX | LOCK_NB:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = flock(fd, LOCK_EX | LOCK_NB);
+  printf("LOCK_EX | LOCK_NB:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = flock(fd, LOCK_UN | LOCK_NB);
+  printf("LOCK_UN | LOCK_NB:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  close(fd);
+
+  errno = 0;
+  retval = flock(fd, LOCK_SH);
+  printf("Closed fd LOCK_UN:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = flock(fd, LOCK_EX);
+  printf("Closed fd LOCK_EX:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = flock(fd, LOCK_UN);
+  printf("Closed fd LOCK_UN:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = flock(fd, LOCK_SH | LOCK_NB);
+  printf("Closed fd LOCK_UN | LOCK_NB:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = flock(fd, LOCK_EX | LOCK_NB);
+  printf("Closed fd LOCK_EX | LOCK_NB:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = flock(fd, LOCK_UN | LOCK_NB);
+  printf("Closed fd LOCK_UN | LOCK_NB:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  errno = 0;
+  retval = flock(fd, 77);
+  printf("Closed fd Bad function code:retval=%d\n", retval);
+  if ((retval < 0) && (errno != 0)) prdoserr(fd);
+
+  exit(0);
+}
diff -ruN djgpp-cvs/tests/makefile.def djgpp/tests/makefile.def
--- djgpp-cvs/tests/makefile.def	Thu Jan  1 00:00:00 1970
+++ djgpp/tests/makefile.def	Tue Dec 14 06:35:56 1999
@@ -0,0 +1,65 @@
+# Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details
+# -*- makefile -*-
+
+#  These define the cross-to-djgpp and native programs.
+
+ifneq ($(COMSPEC),)
+CROSS_BUILD = 0
+else
+CROSS_BUILD = 1
+endif
+
+# OK, pay attention: The CROSS_* programs are used to build objects
+# and executables that become part of djgpp itself (like libc.a and
+# stubedit.exe) and the not-CROSS_* programs are used to build
+# programs that are used as part of the build.  When you're building
+# *with* djgpp, they should be the same program, but when you're
+# building under unix (IRIX, Linux, etc), it makes a difference
+# because we often have to build programs twice - once for our use
+# (runs under unix) and once for the distribution (runs under dos).
+
+ifeq ($(CROSS_BUILD),0)
+
+# These programs shouldn't need to be changed; they're used
+# when building djgpp *with* djgpp.
+
+# For building distributed (djgpp) libraries and programs
+CROSS_GCC = gcc
+CROSS_AR = ar
+CROSS_LD = ld
+CROSS_STRIP = strip
+CROSS_BISON = bison
+
+# For building native programs (hostbin/*); assumes GNU versions
+GCC = gcc -g
+AR = ar
+LD = ld
+STRIP = strip
+BISON = bison
+
+else
+
+# These may need to be changed based on where/how you installed
+# your native gcc and your cross compiler.
+
+# For building distributed (djgpp) libraries and programs
+
+CROSS_GCC = i586-pc-msdosdjgpp-gcc -pipe
+CROSS_AR = i586-pc-msdosdjgpp-ar
+CROSS_LD = i586-pc-msdosdjgpp-ld
+CROSS_STRIP = i586-pc-msdosdjgpp-strip
+CROSS_BISON = bison
+
+# For building programs that *run* during the build (hostbin/*);
+# assumes GNU versions
+
+GCC = gcc -g -O2 -pipe
+AR = ar
+LD = ld
+STRIP = strip
+BISON = bison
+
+# You may need to replace coff-go32 with coff-i386 in lib/djgpp.djl or
+# edit your cross_ld to replace coff-i386 with coff-go32 (as I did)
+
+endif
diff -ruN djgpp-cvs/tests/makefile.inc djgpp/tests/makefile.inc
--- djgpp-cvs/tests/makefile.inc	Sun Sep  1 15:39:18 1996
+++ djgpp/tests/makefile.inc	Sat Dec  2 11:29:48 2000
@@ -1,3 +1,6 @@
+# Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details
+
+include $(TOP)/../makefile.def
 
 .SUFFIXES: .o .i .c .cc .s
 
@@ -31,7 +34,19 @@
 EXES := $(addsuffix .exe, $(basename $(SRC)))
 ERRS := $(addsuffix .err, $(basename $(SRC)))
 
-LINK = ld $(LDFLAGS) $^ -o $@ ${LIB}/libgcc.a -T ${TOP}/../../lib/djgpp.djl
+ifeq ($(LIBGCCA),)
+LIBGCCA := $(shell $(CROSS_GCC) $(GCC_OPT) -print-file-name=libgcc.a)
+LIBGCCA := $(subst \,/,$(LIBGCCA))
+export LIBGCCA
+endif
+
+ifeq ($(DJGPP_DJL),)
+DJGPP_DJL := $(shell $(CROSS_GCC) $(GCC_OPT) -print-file-name=djgpp.djl)
+DJGPP_DJL := $(subst \,/,$(DJGPP_DJL))
+export DJGPP_DJL
+endif
+
+LINK = ld $(LDFLAGS) $^ -o $@ $(LIBGCCA) -T $(DJGPP_DJL)
 EXE = @${TOP}/../../bin/stubify.exe $@
 
 .PRECIOUS: %.exe %.out %.err

--=====================_4043618==_
Content-Type: text/plain; charset="us-ascii"

diff -ruN djgpp-cvs/src/debug/common/dbgcom.c djgpp/src/debug/common/dbgcom.c
--- djgpp-cvs/src/debug/common/dbgcom.c	Mon Oct 11 07:34:18 1999
+++ djgpp/src/debug/common/dbgcom.c	Sat Nov 18 19:39:20 2000
@@ -458,9 +458,16 @@
 _get_exception_handler:                                                 \n\
         pushl   %eax                                                    \n\
 	pushf								\n\
-	.byte	0x2e							\n\
-	lcall	_old_i31						\n\
-        popl   %eax                                                     \n\
+	.byte	0x2e							\n"
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
+"	lcall	_old_i31						\n\
+"
+#else
+"	lcall	*_old_i31						\n\
+"
+#endif
+"	popl   %eax                                                     \n\
 	jc	Lc31_set_flags_and_iret					\n\
         pushl   %eax                                                    \n\
         push    %es                                                     \n\
@@ -487,9 +494,16 @@
         pop   %ds                                                       \n\
         pop   %es                                                       \n\
         popl  %eax                                                      \n\
-        .byte 0x2e                                                      \n\
-        ljmp _old_i31                                                   \n\
-        ret                                                             \n"
+        .byte 0x2e                                                      \n"
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
+"	ljmp	_old_i31						\n\
+"
+#else
+"	ljmp	*_old_i31						\n\
+"
+#endif
+"	ret                                                             \n"
 ); 
 
 /* Change a handle in the list: EAX is the old handle, EDX is the new */
@@ -562,9 +576,16 @@
 	pushl	%eax							\n\
 	movw	$0x0003,%ax						\n\
 	pushf								\n\
-	.byte	0x2e							\n\
-	lcall	_old_i31						\n\
-	movw	%ax,%bx							\n\
+	.byte	0x2e							\n"
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
+"	lcall	_old_i31						\n\
+"
+#else
+"	lcall	*_old_i31						\n\
+"
+#endif
+"	movw	%ax,%bx							\n\
 	popl	%eax							\n\
 	pushl	%eax							\n\
 	movw	%ax,%dx							\n\
@@ -691,9 +712,16 @@
 	cmpw	$0x0503,%ax						\n\
 	je	Lc31_resize_mem						\n\
 L_jmp_to_old_i31:                                                       \n\
-        .byte	0x2e							\n\
-	ljmp	_old_i31						\n\
-Lc31_set_flags_and_iret:                                                \n\
+        .byte	0x2e							\n"
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
+"	ljmp	_old_i31						\n\
+"
+#else
+"	ljmp	*_old_i31						\n\
+"
+#endif
+"Lc31_set_flags_and_iret:                                                \n\
         pushl	%eax				                        \n\
 	pushf								\n\
 	popl	%eax		/* store the right flags for iret */	\n\
@@ -732,9 +760,16 @@
 	cmpw	_app_ds,%bx					        \n\
 	jne	L_jmp_to_old_i31					\n\
 	pushf								\n\
-	.byte	0x2e							\n\
-	lcall	_old_i31						\n\
-	call	___djgpp_save_interrupt_regs				\n\
+	.byte	0x2e							\n"
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
+"	lcall	_old_i31						\n\
+"
+#else
+"	lcall	*_old_i31						\n\
+"
+#endif
+"	call	___djgpp_save_interrupt_regs				\n\
 	call	__clear_break_DPMI					\n\
 	call	__set_break_DPMI					\n\
 	movl	___djgpp_exception_state_ptr,%eax			\n\
@@ -753,9 +788,16 @@
 	jmp	L_jmp_to_old_i31					\n\
 Lc31_alloc_mem:								\n\
 	pushf								\n\
-	.byte	0x2e							\n\
-	lcall	_old_i31						\n\
-	jc	Lc31_set_flags_and_iret					\n\
+	.byte	0x2e							\n"
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
+"	lcall	_old_i31						\n\
+"
+#else
+"	lcall	*_old_i31						\n\
+"
+#endif
+"	jc	Lc31_set_flags_and_iret					\n\
 	pushf								\n\
 	pushl	%edx							\n\
 	pushw	%si							\n\
@@ -771,9 +813,16 @@
 	pushw	%si							\n\
 	pushw	%di							\n\
 	pushf								\n\
-	.byte	0x2e							\n\
-	lcall	_old_i31						\n\
-	jc	Lc31_resize_mem_error					\n\
+	.byte	0x2e							\n"
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
+"	lcall	_old_i31						\n\
+"
+#else
+"	lcall	*_old_i31						\n\
+"
+#endif
+"	jc	Lc31_resize_mem_error					\n\
 	popl	%eax							\n\
 	push	%edx							\n\
 	xorl	%edx,%edx						\n\
@@ -785,9 +834,16 @@
 	pushw	%si							\n\
 	pushw	%di							\n\
 	pushf								\n\
-	.byte	0x2e							\n\
-	lcall	_old_i31						\n\
-	jnc	Lc31_resize_mem_ok					\n\
+	.byte	0x2e							\n"
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
+"	lcall	_old_i31						\n\
+"
+#else
+"	lcall	*_old_i31						\n\
+"
+#endif
+"	jnc	Lc31_resize_mem_ok					\n\
 Lc31_resize_mem_error:							\n\
 	addl	$4,%esp							\n\
 	stc								\n\
@@ -803,9 +859,16 @@
 Lc31_alloc_descriptors:							\n\
 	pushl	%ecx							\n\
 	pushf								\n\
-	.byte	0x2e							\n\
-	lcall	_old_i31						\n\
-	popl	%ecx							\n\
+	.byte	0x2e							\n"
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
+"	lcall	_old_i31						\n\
+"
+#else
+"	lcall	*_old_i31						\n\
+"
+#endif
+"	popl	%ecx							\n\
 	jc	Lc31_set_flags_and_iret					\n\
 	call	_add_descriptors					\n\
 	clc								\n\
@@ -813,9 +876,16 @@
 Lc31_free_descriptor:							\n\
 	pushl	%ebx							\n\
 	pushf								\n\
-	.byte	0x2e							\n\
-	lcall	_old_i31						\n\
-	popl	%eax							\n\
+	.byte	0x2e							\n"
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
+"	lcall	_old_i31						\n\
+"
+#else
+"	lcall	*_old_i31						\n\
+"
+#endif
+"	popl	%eax							\n\
 	jc	Lc31_set_flags_and_iret					\n\
 	push	%edx							\n\
 	xorw	%dx,%dx							\n\
@@ -825,9 +895,16 @@
 	jmp	Lc31_set_flags_and_iret					\n\
 Lc31_create_alias_descriptor:						\n\
 	pushf								\n\
-	.byte	0x2e							\n\
-	lcall	_old_i31						\n\
-	jc	Lc31_set_flags_and_iret					\n\
+	.byte	0x2e							\n"
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
+"	lcall	_old_i31						\n\
+"
+#else
+"	lcall	*_old_i31						\n\
+"
+#endif
+"	jc	Lc31_set_flags_and_iret					\n\
 	pushl	%eax							\n\
 	push	%edx							\n\
 	movw	%ax,%dx							\n\
@@ -839,9 +916,16 @@
 	jmp	Lc31_set_flags_and_iret					\n\
 Lc31_allocate_dos_memory:						\n\
 	pushf								\n\
-	.byte	0x2e							\n\
-	lcall	_old_i31						\n\
-	jc	Lc31_set_flags_and_iret					\n\
+	.byte	0x2e							\n"
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
+"	lcall	_old_i31						\n\
+"
+#else
+"	lcall	*_old_i31						\n\
+"
+#endif
+"	jc	Lc31_set_flags_and_iret					\n\
 	pushl	%eax							\n\
 	xorl	%eax,%eax						\n\
 	call	_change_dos_descriptor					\n\
@@ -851,9 +935,16 @@
 Lc31_free_dos_memory:							\n\
 	pushl	%edx							\n\
 	pushf								\n\
-	.byte	0x2e							\n\
-	lcall	_old_i31						\n\
-	popl	%eax							\n\
+	.byte	0x2e							\n"
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
+"	lcall	_old_i31						\n\
+"
+#else
+"	lcall	*_old_i31						\n\
+"
+#endif
+"	popl	%eax							\n\
 	jc	Lc31_set_flags_and_iret					\n\
 	xorw	%dx,%dx							\n\
 	call	_change_dos_descriptor					\n\
@@ -865,18 +956,32 @@
         pushl  %ecx                                                     \n\
         pushl  %edx                                                     \n\
         pushf                                                           \n\
-        .byte  0x2e                                                     \n\
-        lcall   _old_i31                                                \n\
-        popl   %edx                                                     \n\
+        .byte  0x2e                                                     \n"
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
+"	lcall	_old_i31						\n\
+"
+#else
+"	lcall	*_old_i31						\n\
+"
+#endif
+"	popl   %edx                                                     \n\
         popl   %ecx                                                     \n\
         popl   %ebx                                                     \n\
         popl   %eax                                                     \n\
         jc   Lc31_set_flags_and_iret                                    \n\
         call   _change_exception_handler                                \n\
         pushf                                                           \n\
-        .byte  0x2e                                                     \n\
-        lcall   _old_i31                                                \n\
-        jmp Lc31_set_flags_and_iret                                     \n\
+        .byte  0x2e                                                     \n"
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
+"	lcall	_old_i31						\n\
+"
+#else
+"	lcall	*_old_i31						\n\
+"
+#endif
+"	jmp Lc31_set_flags_and_iret                                     \n\
 	.balign  16,,7							\n\
         .globl  _dbgcom_hook_i21                                        \n\
 _dbgcom_hook_i21:                                                       \n\
@@ -884,9 +989,16 @@
 	cmpb	$0x4c,%ah						\n\
 	je	Lc21							\n\
 Lc21_jmp_to_old:                                                        \n\
-        .byte	0x2e							\n\
-	ljmp	_old_i21						\n\
-Lc21:	push	%eax							\n\
+        .byte	0x2e							\n"
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
+"	ljmp	_old_i21						\n\
+"
+#else
+"	ljmp	*_old_i21						\n\
+"
+#endif
+"Lc21:	push	%eax							\n\
 	movl	8(%esp),%eax						\n\
 	cs								\n\
 	cmpw	_app_exit_cs,%ax					\n\
@@ -1002,9 +1114,14 @@
 /* do not set limit of ds selector two times */
 asm (".text
         .global ___dbgcom_kbd_hdlr
-___dbgcom_kbd_hdlr:
-        ljmp    %cs:___djgpp_old_kbd");
-        
+___dbgcom_kbd_hdlr:"
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
+"	ljmp    %cs:___djgpp_old_kbd");
+#else
+"	ljmp    *%cs:___djgpp_old_kbd");
+#endif
+
     
     
 static void unhook_dpmi(void)
diff -ruN djgpp-cvs/src/docs/kb/wcfcntl.txi djgpp/src/docs/kb/wcfcntl.txi
--- djgpp-cvs/src/docs/kb/wcfcntl.txi	Thu Jan  1 00:00:00 1970
+++ djgpp/src/docs/kb/wcfcntl.txi	Mon Dec 11 23:00:46 2000
@@ -0,0 +1,56 @@
+
+@findex fcntl
+The @code{fcntl} function has been significantly enhanced.  In
+particular:
+
+@itemize @minus{}
+@item
+@cindex file locking functions
+File locking functions (which were missing in every version up to
+v2.03) now work, with some exceptions relating to the absence of any
+read locking in DOS/Win9x environments.
+
+@item
+@findex fcntl AT r{ commands }F_GETFD AT r{ and }F_SETFD
+These functions now interrogate and use the value of the DOS flag
+@code{_DEV_NO_INHERIT} to implement the @code{FD_CLOEXEC} flag;
+
+@item
+@findex fcntl AT r{ commands }F_GETFL AT r{ and }F_SETFL
+These functions are still effective no-ops, since DOS/Windows does not
+allow flags to be modified on an open file.  A small exception is made
+for @code{F_SETFL}:  You may use @code{F_SETFL} to remove the
+@code{O_NONBLOCK} flag, because it is not supported by DJGPP anyway, and
+it does no harm to allow this functionality.
+
+@item
+Documentation has been updated to reflect the new functionality and
+test programs have been provided for most new or changed functions.
+
+@findex flock
+@findex lockf
+@findex llockf
+@code{flock} has been implemented using the new @code{fcntl} locking
+functions to implement file-level locking and unlocking.  @code{lockf}
+(31-bit support) and @code{llockf} (FAT32 support, 32-bit only) have
+been added as compatible interfaces to the new @code{fcntl} locking
+functions.
+
+@findex dosexterr
+@findex dostrerr
+New function @code{dostrerr} has been coded to provide string
+values for the error codes returned from function @code{dosexterr}.
+Documentation and a test program has been provided.  This function is an
+analogue of the @code{strerror} function for errno values, and is
+intended to be used when coding functions or programs that call DOS and
+want to print messages when errors occur.
+
+@findex _dos_lk64
+@findex _dos_unlk64
+@findex lock64
+@findex unlock64
+New functions @code{_dos_lk64} and @code{_dos_unlk64} have been added to
+provide a FAT32-compatible interface to the DOS locking code.
+Compatible functions @code{lock64} and @code{unlock64} are direct
+interfaces to these two new "_dos" functions.
+@end itemize
diff -ruN djgpp-cvs/src/libc/ansi/string/strerror.c djgpp/src/libc/ansi/string/strerror.c
--- djgpp-cvs/src/libc/ansi/string/strerror.c	Fri Jun 16 04:16:48 1995
+++ djgpp/src/libc/ansi/string/strerror.c	Sat Dec  2 17:32:16 2000
@@ -1,3 +1,4 @@
+/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
 #include <stdio.h>
 #include <string.h>
@@ -15,7 +16,7 @@
     return(unconst(__sys_errlist[errnum], char *));
 
   strcpy(ebuf, "Unknown error: ");
-  cp = ebuf + 15;
+  cp = ebuf + strlen(ebuf);
   if (errnum < 0)
   {
     *cp++ = '-';
diff -ruN djgpp-cvs/src/libc/compat/unistd/llockf.c djgpp/src/libc/compat/unistd/llockf.c
--- djgpp-cvs/src/libc/compat/unistd/llockf.c	Thu Jan  1 00:00:00 1970
+++ djgpp/src/libc/compat/unistd/llockf.c	Mon Dec 11 00:06:10 2000
@@ -0,0 +1,55 @@
+/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
+
+/* lockf is a simplified interface to fcntl's locking facilities.  */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+int
+llockf (int _fildes, int _cmd, offset_t _len)
+{
+  struct flock64 lock_req;
+
+  memset ((char *) &lock_req, '\0', sizeof (lock_req));
+
+  /* lockf is always relative to the current file position.  */
+  lock_req.l_whence = SEEK_CUR;
+  lock_req.l_start = 0L;
+  lock_req.l_len = _len;
+
+  switch (_cmd)
+    {
+    case F_TEST:
+      lock_req.l_type = F_WRLCK;
+      /* Test the lock: return 0 if FD is unlocked;
+	return -1, set errno to EACCES, if the lock cannot be obtained.  */
+      if (fcntl (_fildes, F_GETLK64, &lock_req) < 0)
+	return -1;
+      if (lock_req.l_type == F_UNLCK)
+	return 0;
+      errno = EACCES;
+      return -1;
+
+    case F_ULOCK:
+      lock_req.l_type = F_UNLCK;
+      _cmd = F_SETLK64;
+      break;
+    case F_LOCK:
+      lock_req.l_type = F_WRLCK;
+      _cmd = F_SETLKW64;
+      break;
+    case F_TLOCK:
+      lock_req.l_type = F_WRLCK;
+      _cmd = F_SETLK64;
+      break;
+
+    default:
+      errno = EINVAL;
+      return -1;
+    }
+
+  return fcntl (_fildes, _cmd, &lock_req);
+}
diff -ruN djgpp-cvs/src/libc/compat/unistd/llockf.txh djgpp/src/libc/compat/unistd/llockf.txh
--- djgpp-cvs/src/libc/compat/unistd/llockf.txh	Thu Jan  1 00:00:00 1970
+++ djgpp/src/libc/compat/unistd/llockf.txh	Mon Dec 11 20:54:16 2000
@@ -0,0 +1,127 @@
+@node llockf, unistd
+@subheading Syntax
+
+@example
+#include <unistd.h>
+
+int llockf (int fildes, int function, offset_t size);
+@end example
+
+@subheading Description
+
+The @code{llockf} command is a simplified interface to the locking
+facilities of @code{fcntl} (see @ref{fcntl} for more detailed
+information).
+
+The @code{llockf} command performs exactly the same functions as
+@code{lockf}, with exactly the same input commands and results, but the
+input @var{size} parameter is of type @code{offset_t} instead of
+@code{off_t}, and the @code{fcntl} calls are made using functions
+@code{F_GETLK64}, @code{F_SETLK64} and @code{F_SETLKW64}, where
+@code{lockf} uses functions @code{F_GETLK}, @code{F_SETLK} and
+@code{F_SETLKW}.
+
+The @code{llockf} command is intended to permit using @code{fcntl}
+functions with @var{size} values greater than 2^31 - 1.
+
+@var{fildes} is an open file descriptor.
+
+@var{function} is a control value which specifies the action to be
+taken.  The permissible values for function are defined in <unistd.h> as
+follows:
+
+@example
+#define   F_ULOCK   0   /* Unlock a previously locked section */
+#define   F_LOCK    1   /* Lock a section for exclusive use */
+#define   F_TLOCK   2   /* Test and lock a section for exclusive use */
+#define   F_TEST    3   /* Test section for other locks */
+@end example
+
+All other values of @var{function} are reserved for future extensions
+and will result in an error return if not implemented, with @code{errno}
+set to @code{EINVAL}.
+
+@var{size} is the number of contiguous bytes to be locked or unlocked.
+The resource to be locked starts at the current offset in the file and
+extends forward for a positive size and backward for a negative size
+(the preceding bytes up to but not including the current offset).  If
+size is zero, the section from the current offset through the largest
+file offset is locked (i.e., from the current offset through the
+end-of-file).
+
+The functions defined for @code{llockf} are as follows:
+
+@table @code
+@item F_TEST
+This function is used to detect if the specified section is already
+locked. @code{F_LOCK} and @code{F_TLOCK} both lock a section of a file
+if the section is available.  @code{F_ULOCK} removes locks from a
+section of the file.
+
+@item F_LOCK
+@item F_TLOCK
+These two function requests differ only by the action taken if the
+resource is not available.  @code{F_LOCK} will cause the calling program
+to wait until the resource is available.  @code{F_TLOCK} will cause the
+function to return a -1 and set @code{errno} to @code{EACCES} error if
+the section is already locked.
+
+@item F_ULOCK
+This function will release locked sections controlled by the program.
+@end table
+
+The @code{llockf} utility will fail if one or more of the following are
+true:
+
+@table @code
+@item EBADF
+Parameter @var{fildes} is not a valid open file.
+
+@item EACCES
+Cmd is @code{F_TLOCK} or @code{F_TEST} and the section is already
+locked.
+
+@item EINVAL
+Parameter @var{function} is not one of the implemented functions.
+@end table
+
+All lock requests in this implementation are coded as exclusive locks
+(i.e., all locks use the @code{fcntl} request @code{F_WRLCK}).
+
+It is therefore wise to code @code{llockf} by using function
+@code{F_TLOCK} with all lock requests, and to test the return value to
+determine if the lock was obtained or not.  Using @code{F_TLOCK} will
+cause the implementation to use @code{F_SETLK} instead of
+@code{F_SETLKW}, which will return an error if the lock cannot be
+obtained.
+
+
+@subheading Return Value
+
+On success, zero is returned.  On error, -1 is returned, and
+@code{errno} is set appropriately, as described above.
+
+@subheading Portability
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+ /* Request a lock on file handle fd from the current position to
+    the end of the file */
+  errno = 0;
+  retval = llockf(fd, F_LOCK, 0);
+
+ /* Request a non-blocking lock on file handle fd */
+  errno = 0;
+  retval = llockf(fd, F_TLOCK, 0);
+
+ /* Test a lock on file handle fd */
+  errno = 0;
+  retval = llockf(fd, F_TEST, 0);
+
+ /* Release a lock on file handle fd */
+  errno = 0;
+  retval = llockf(fd, F_ULOCK, 0);
+@end example
diff -ruN djgpp-cvs/src/libc/compat/unistd/lockf.c djgpp/src/libc/compat/unistd/lockf.c
--- djgpp-cvs/src/libc/compat/unistd/lockf.c	Thu Jan  1 00:00:00 1970
+++ djgpp/src/libc/compat/unistd/lockf.c	Sun Nov 26 22:12:36 2000
@@ -0,0 +1,55 @@
+/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
+
+/* lockf is a simplified interface to fcntl's locking facilities.  */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+int
+lockf (int _fildes, int _cmd, off_t _len)
+{
+  struct flock lock_req;
+
+  memset ((char *) &lock_req, '\0', sizeof (lock_req));
+
+  /* lockf is always relative to the current file position.  */
+  lock_req.l_whence = SEEK_CUR;
+  lock_req.l_start = 0;
+  lock_req.l_len = _len;
+
+  switch (_cmd)
+    {
+    case F_TEST:
+      lock_req.l_type = F_WRLCK;
+      /* Test the lock: return 0 if FD is unlocked;
+	return -1, set errno to EACCES, if the lock cannot be obtained.  */
+      if (fcntl (_fildes, F_GETLK, &lock_req) < 0)
+	return -1;
+      if (lock_req.l_type == F_UNLCK)
+	return 0;
+      errno = EACCES;
+      return -1;
+
+    case F_ULOCK:
+      lock_req.l_type = F_UNLCK;
+      _cmd = F_SETLK;
+      break;
+    case F_LOCK:
+      lock_req.l_type = F_WRLCK;
+      _cmd = F_SETLKW;
+      break;
+    case F_TLOCK:
+      lock_req.l_type = F_WRLCK;
+      _cmd = F_SETLK;
+      break;
+
+    default:
+      errno = EINVAL;
+      return -1;
+    }
+
+  return fcntl (_fildes, _cmd, &lock_req);
+}
diff -ruN djgpp-cvs/src/libc/compat/unistd/lockf.txh djgpp/src/libc/compat/unistd/lockf.txh
--- djgpp-cvs/src/libc/compat/unistd/lockf.txh	Thu Jan  1 00:00:00 1970
+++ djgpp/src/libc/compat/unistd/lockf.txh	Mon Dec 11 00:56:36 2000
@@ -0,0 +1,115 @@
+@node lockf, unistd
+@subheading Syntax
+
+@example
+#include <unistd.h>
+
+int lockf (int fildes, int function, off_t size);
+@end example
+
+@subheading Description
+
+The @code{lockf} command is a simplified interface to the locking
+facilities of @code{fcntl} (see @ref{fcntl} for more detailed
+information).
+
+@var{fildes} is an open file descriptor.
+
+@var{function} is a control value which specifies the action to be
+taken.  The permissible values for function are defined in <unistd.h> as
+follows:
+
+@example
+#define   F_ULOCK   0   /* Unlock a previously locked section */
+#define   F_LOCK    1   /* Lock a section for exclusive use */
+#define   F_TLOCK   2   /* Test and lock a section for exclusive use */
+#define   F_TEST    3   /* Test section for other locks */
+@end example
+
+All other values of @var{function} are reserved for future extensions
+and will result in an error return if not implemented, with @code{errno}
+set to @code{EINVAL}.
+
+@var{size} is the number of contiguous bytes to be locked or unlocked.
+The resource to be locked starts at the current offset in the file and
+extends forward for a positive size and backward for a negative size
+(the preceding bytes up to but not including the current offset).  If
+size is zero, the section from the current offset through the largest
+file offset is locked (i.e., from the current offset through the
+end-of-file).
+
+The functions defined for @code{lockf} are as follows:
+
+@table @code
+@item F_TEST
+This function is used to detect if the specified section is already
+locked. @code{F_LOCK} and @code{F_TLOCK} both lock a section of a file
+if the section is available.  @code{F_ULOCK} removes locks from a
+section of the file.
+
+@item F_LOCK
+@item F_TLOCK
+These two function requests differ only by the action taken if the
+resource is not available.  @code{F_LOCK} will cause the calling program
+to wait until the resource is available.  @code{F_TLOCK} will cause the
+function to return a -1 and set @code{errno} to @code{EACCES} error if
+the section is already locked.
+
+@item F_ULOCK
+This function will release locked sections controlled by the program.
+@end table
+
+The lockf utility will fail if one or more of the following are true:
+
+@table @code
+@item EBADF
+Parameter @var{fildes} is not a valid open file.
+
+@item EACCES
+Cmd is @code{F_TLOCK} or @code{F_TEST} and the section is already
+locked.
+
+@item EINVAL
+Parameter @var{function} is not one of the implemented functions.
+@end table
+
+All lock requests in this implementation are coded as exclusive locks
+(i.e., all locks use the @code{fcntl} request @code{F_WRLCK}).
+
+It is therefore wise to code @code{lockf} by using function
+@code{F_TLOCK} with all lock requests, and to test the return value to
+determine if the lock was obtained or not.  Using @code{F_TLOCK} will
+cause the implementation to use @code{F_SETLK} instead of
+@code{F_SETLKW}, which will return an error if the lock cannot be
+obtained.
+
+
+@subheading Return Value
+
+On success, zero is returned.  On error, -1 is returned, and
+@code{errno} is set appropriately, as described above.
+
+@subheading Portability
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+ /* Request a lock on file handle fd from the current position to
+    the end of the file */
+  errno = 0;
+  retval = lockf(fd, F_LOCK, 0);
+
+ /* Request a non-blocking lock on file handle fd */
+  errno = 0;
+  retval = lockf(fd, F_TLOCK, 0);
+
+ /* Test a lock on file handle fd */
+  errno = 0;
+  retval = lockf(fd, F_TEST, 0);
+
+ /* Release a lock on file handle fd */
+  errno = 0;
+  retval = lockf(fd, F_ULOCK, 0);
+@end example
diff -ruN djgpp-cvs/src/libc/compat/unistd/makefile djgpp/src/libc/compat/unistd/makefile
--- djgpp-cvs/src/libc/compat/unistd/makefile	Fri Aug 25 07:35:36 2000
+++ djgpp/src/libc/compat/unistd/makefile	Mon Dec 11 00:06:34 2000
@@ -13,6 +13,8 @@
 SRC += getwd.c
 SRC += lchown.c
 SRC += llseek.c
+SRC += lockf.c
+SRC += llockf.c
 SRC += nice.c
 SRC += readlink.c
 SRC += sdirlink.c
diff -ruN djgpp-cvs/src/libc/crt0/crt0.S djgpp/src/libc/crt0/crt0.S
--- djgpp-cvs/src/libc/crt0/crt0.S	Tue May 30 14:09:12 2000
+++ djgpp/src/libc/crt0/crt0.S	Sat Dec  9 01:55:54 2000
@@ -366,7 +366,12 @@
 	movw	%cs, %bx
 /* Call exit procedure with BX=32-bit CS; SI+DI=32-bit handle; DL=exit status */
 	.byte 0x2e
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
 	ljmp	sbrk16_api_ofs
+#else
+	ljmp	*sbrk16_api_ofs
+#endif
 
 /*-----------------------------------------------------------------------------*/
 
@@ -455,7 +460,12 @@
 	int	$0x31
 	pushl	%eax
 
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
 	lcall	sbrk16_api_ofs
+#else
+	lcall	*sbrk16_api_ofs
+#endif
 	setc	%dl						/* Save carry */
 
 	popl	%eax					/* restore interrupts */
diff -ruN djgpp-cvs/src/libc/dos/compat/d_exterr.txh djgpp/src/libc/dos/compat/d_exterr.txh
--- djgpp-cvs/src/libc/dos/compat/d_exterr.txh	Sun Sep 27 11:21:20 1998
+++ djgpp/src/libc/dos/compat/d_exterr.txh	Sat Dec  9 01:32:04 2000
@@ -13,7 +13,7 @@
 @var{p_error} structure.
 
 @example
-struct _DOSERROR @{
+struct DOSERROR @{
   int  exterror;
   char class;
   char action;
@@ -21,134 +21,271 @@
 @};
 @end example
 
-Values for extended error code (@var{exterror} field):
+Values for DOS extended error code (@var{exterr} field):
 @example
-00h (0)   no error
-01h (1)   function number invalid
-02h (2)   file not found
-03h (3)   path not found
-04h (4)   too many open files (no handles available)
-05h (5)   access denied
-06h (6)   invalid handle
-07h (7)   memory control block destroyed
-08h (8)   insufficient memory
-09h (9)   memory block address invalid
-0Ah (10)  environment invalid (usually >32K in length)
-0Bh (11)  format invalid
-0Ch (12)  access code invalid
-0Dh (13)  data invalid
-0Eh (14)  reserved
-0Fh (15)  invalid drive
-10h (16)  attempted to remove current directory
-11h (17)  not same device
-12h (18)  no more files
-13h (19)  disk write-protected
-14h (20)  unknown unit
-15h (21)  drive not ready
-16h (22)  unknown command
-17h (23)  data error (CRC)
-18h (24)  bad request structure length
-19h (25)  seek error
-1Ah (26)  unknown media type (non-DOS disk)
-1Bh (27)  sector not found
-1Ch (28)  printer out of paper
-1Dh (29)  write fault
-1Eh (30)  read fault
-1Fh (31)  general failure
-20h (32)  sharing violation
-21h (33)  lock violation
-22h (34)  disk change invalid (ES:DI -> media ID structure)(see below)
-23h (35)  FCB unavailable
-24h (36)  sharing buffer overflow
-25h (37)  (DOS 4+) code page mismatch
-26h (38)  (DOS 4+) cannot complete file operation (out of input)
-27h (39)  (DOS 4+) insufficient disk space
-28h-31h   reserved
-32h (50)  network request not supported
-33h (51)  remote computer not listening
-34h (52)  duplicate name on network
-35h (53)  network name not found
-36h (54)  network busy
-37h (55)  network device no longer exists
-38h (56)  network BIOS command limit exceeded
-39h (57)  network adapter hardware error
-3Ah (58)  incorrect response from network
-3Bh (59)  unexpected network error
-3Ch (60)  incompatible remote adapter
-3Dh (61)  print queue full
-3Eh (62)  queue not full
-3Fh (63)  not enough space to print file
-40h (64)  network name was deleted
-41h (65)  network: Access denied
-42h (66)  network device type incorrect
-43h (67)  network name not found
-44h (68)  network name limit exceeded
-45h (69)  network BIOS session limit exceeded
-46h (70)  temporarily paused
-47h (71)  network request not accepted
-48h (72)  network print/disk redirection paused
-49h (73)  network software not installed
-          (LANtastic) invalid network version
-4Ah (74)  unexpected adapter close
-          (LANtastic) account expired
-4Bh (75)  (LANtastic) password expired
-4Ch (76)  (LANtastic) login attempt invalid at this time
-4Dh (77)  (LANtastic v3+) disk limit exceeded on network node
-4Eh (78)  (LANtastic v3+) not logged in to network node
-4Fh (79)  reserved
-50h (80)  file exists
-51h (81)  reserved
-52h (82)  cannot make directory
-53h (83)  fail on INT 24h
-54h (84)  (DOS 3.3+) too many redirections
-55h (85)  (DOS 3.3+) duplicate redirection
-56h (86)  (DOS 3.3+) invalid password
-57h (87)  (DOS 3.3+) invalid parameter
-58h (88)  (DOS 3.3+) network write fault
-59h (89)  (DOS 4+) function not supported on network
-5Ah (90)  (DOS 4+) required system component not installed
-64h (100) (MSCDEX) unknown error
-65h (101) (MSCDEX) not ready
-66h (102) (MSCDEX) EMS memory no longer valid
-67h (103) (MSCDEX) not High Sierra or ISO-9660 format
-68h (104) (MSCDEX) door open
+---DOS 2.0+ ---
+ 00h (0)   no error
+ 01h (1)   function number invalid
+ 02h (2)   file not found
+ 03h (3)   path not found
+ 04h (4)   too many open files (no handles available)
+ 05h (5)   access denied
+ 06h (6)   invalid handle
+ 07h (7)   memory control block destroyed
+ 08h (8)   insufficient memory
+ 09h (9)   memory block address invalid
+ 0Ah (10)  environment invalid (usually >32K in length)
+ 0Bh (11)  format invalid
+ 0Ch (12)  access code invalid
+ 0Dh (13)  data invalid
+ 0Eh (14)  reserved
+ 0Eh (14)  (PTS-DOS 6.51+, S/DOS 1.0+) fixup overflow
+ 0Fh (15)  invalid drive
+ 10h (16)  attempted to remove current directory
+ 11h (17)  not same device
+ 12h (18)  no more files
+---DOS 3.0+ (INT 24 errors)---
+ 13h (19)  disk write-protected
+ 14h (20)  unknown unit
+ 15h (21)  drive not ready
+ 16h (22)  unknown command
+ 17h (23)  data error (CRC)
+ 18h (24)  bad request structure length
+ 19h (25)  seek error
+ 1Ah (26)  unknown media type (non-DOS disk)
+ 1Bh (27)  sector not found
+ 1Ch (28)  printer out of paper
+ 1Dh (29)  write fault
+ 1Eh (30)  read fault
+ 1Fh (31)  general failure
+ 20h (32)  sharing violation
+ 21h (33)  lock violation
+ 22h (34)  disk change invalid (ES:DI -> media ID structure)(see #01681)
+ 23h (35)  FCB unavailable
+ 23h (35)  (PTS-DOS 6.51+, S/DOS 1.0+) bad FAT
+ 24h (36)  sharing buffer overflow
+ 25h (37)  (DOS 4.0+) code page mismatch
+ 26h (38)  (DOS 4.0+) cannot complete file operation (EOF / out of input)
+ 27h (39)  (DOS 4.0+) insufficient disk space
+ 28h-31h   reserved
+---OEM network errors (INT 24)---
+ 32h (50)  network request not supported
+ 33h (51)  remote computer not listening
+ 34h (52)  duplicate name on network
+ 35h (53)  network name not found
+ 36h (54)  network busy
+ 37h (55)  network device no longer exists
+ 38h (56)  network BIOS command limit exceeded
+ 39h (57)  network adapter hardware error
+ 3Ah (58)  incorrect response from network
+ 3Bh (59)  unexpected network error
+ 3Ch (60)  incompatible remote adapter
+ 3Dh (61)  print queue full
+ 3Eh (62)  queue not full
+ 3Fh (63)  not enough space to print file
+ 40h (64)  network name was deleted
+ 41h (65)  network: Access denied
+	  (DOS 3.0+ [maybe 3.3+???]) codepage switching not possible
+	    (see also INT 21/AX=6602h,INT 2F/AX=AD42h)
+ 42h (66)  network device type incorrect
+ 43h (67)  network name not found
+ 44h (68)  network name limit exceeded
+ 45h (69)  network BIOS session limit exceeded
+ 46h (70)  temporarily paused
+ 47h (71)  network request not accepted
+ 48h (72)  network print/disk redirection paused
+ 49h (73)  network software not installed
+	    (LANtastic) invalid network version
+ 4Ah (74)  unexpected adapter close
+	    (LANtastic) account expired
+ 4Bh (75)  (LANtastic) password expired
+ 4Ch (76)  (LANtastic) login attempt invalid at this time
+ 4Dh (77)  (LANtastic v3+) disk limit exceeded on network node
+ 4Eh (78)  (LANtastic v3+) not logged in to network node
+ 4Fh (79)  reserved
+---end of errors reportable via INT 24---
+ 50h (80)  file exists
+ 51h (81)  (undoc) duplicated FCB
+ 52h (82)  cannot make directory
+ 53h (83)  fail on INT 24h
+---network-related errors (non-INT 24)---
+ 54h (84)  (DOS 3.3+) too many redirections / out of structures
+ 55h (85)  (DOS 3.3+) duplicate redirection / already assigned
+ 56h (86)  (DOS 3.3+) invalid password
+ 57h (87)  (DOS 3.3+) invalid parameter
+ 58h (88)  (DOS 3.3+) network write fault
+ 59h (89)  (DOS 4.0+) function not supported on network / no process slots
+	      available
+ 5Ah (90)  (DOS 4.0+) required system component not installed / not frozen
+ 5Bh (91)  (DOS 4.0+,NetWare4) timer server table overflowed
+ 5Ch (92)  (DOS 4.0+,NetWare4) duplicate in timer service table
+ 5Dh (93)  (DOS 4.0+,NetWare4) no items to work on
+ 5Fh (95)  (DOS 4.0+,NetWare4) interrupted / invalid system call
+ 64h (100) (MSCDEX) unknown error
+ 64h (100) (DOS 4.0+,NetWare4) open semaphore limit exceeded
+ 65h (101) (MSCDEX) not ready
+ 65h (101) (DOS 4.0+,NetWare4) exclusive semaphore is already owned
+ 66h (102) (MSCDEX) EMS memory no longer valid
+ 66h (102) (DOS 4.0+,NetWare4) semaphore was set when close attempted
+ 67h (103) (MSCDEX) not High Sierra or ISO-9660 format
+ 67h (103) (DOS 4.0+,NetWare4) too many exclusive semaphore requests
+ 68h (104) (MSCDEX) door open
+ 68h (104) (DOS 4.0+,NetWare4) operation invalid from interrupt handler
+ 69h (105) (DOS 4.0+,NetWare4) semaphore owner died
+ 6Ah (106) (DOS 4.0+,NetWare4) semaphore limit exceeded
+ 6Bh (107) (DOS 4.0+,NetWare4) insert drive B: disk into A: / disk changed
+ 6Ch (108) (DOS 4.0+,NetWare4) drive locked by another process
+ 6Dh (109) (DOS 4.0+,NetWare4) broken pipe
+ 6Eh (110) (DOS 5.0+,NetWare4) pipe open/create failed
+ 6Fh (111) (DOS 5.0+,NetWare4) pipe buffer overflowed
+ 70h (112) (DOS 5.0+,NetWare4) disk full
+ 71h (113) (DOS 5.0+,NetWare4) no more search handles
+ 72h (114) (DOS 5.0+,NetWare4) invalid target handle for dup2
+ 73h (115) (DOS 5.0+,NetWare4) bad user virtual address / protection violation
+ 74h (116) (DOS 5.0+) VIOKBD request
+ 74h (116) (NetWare4) error on console I/O
+ 75h (117) (DOS 5.0+,NetWare4) unknown category code for IOCTL
+ 76h (118) (DOS 5.0+,NetWare4) invalid value for verify flag
+ 77h (119) (DOS 5.0+,NetWare4) level four driver not found by DOS IOCTL
+ 78h (120) (DOS 5.0+,NetWare4) invalid / unimplemented function number
+ 79h (121) (DOS 5.0+,NetWare4) semaphore timeout
+ 7Ah (122) (DOS 5.0+,NetWare4) buffer too small to hold return data
+ 7Bh (123) (DOS 5.0+,NetWare4) invalid character or bad file-system name
+ 7Ch (124) (DOS 5.0+,NetWare4) unimplemented information level
+ 7Dh (125) (DOS 5.0+,NetWare4) no volume label found
+ 7Eh (126) (DOS 5.0+,NetWare4) module handle not found
+ 7Fh (127) (DOS 5.0+,NetWare4) procedure address not found
+ 80h (128) (DOS 5.0+,NetWare4) CWait found no children
+ 81h (129) (DOS 5.0+,NetWare4) CWait children still running
+ 82h (130) (DOS 5.0+,NetWare4) invalid operation for direct disk-access handle
+ 83h (131) (DOS 5.0+,NetWare4) attempted seek to negative offset
+ 84h (132) (DOS 5.0+,NetWare4) attempted to seek on device or pipe
+---JOIN/SUBST errors---
+ 85h (133) (DOS 5.0+,NetWare4) drive already has JOINed drives
+ 86h (134) (DOS 5.0+,NetWare4) drive is already JOINed
+ 87h (135) (DOS 5.0+,NetWare4) drive is already SUBSTed
+ 88h (136) (DOS 5.0+,NetWare4) can not delete drive which is not JOINed
+ 89h (137) (DOS 5.0+,NetWare4) can not delete drive which is not SUBSTed
+ 8Ah (138) (DOS 5.0+,NetWare4) can not JOIN to a JOINed drive
+ 8Bh (139) (DOS 5.0+,NetWare4) can not SUBST to a SUBSTed drive
+ 8Ch (140) (DOS 5.0+,NetWare4) can not JOIN to a SUBSTed drive
+ 8Dh (141) (DOS 5.0+,NetWare4) can not SUBST to a JOINed drive
+ 8Eh (142) (DOS 5.0+,NetWare4) drive is busy
+ 8Fh (143) (DOS 5.0+,NetWare4) can not JOIN/SUBST to same drive
+ 90h (144) (DOS 5.0+,NetWare4) directory must not be root directory
+ 91h (145) (DOS 5.0+,NetWare4) can only JOIN to empty directory
+ 92h (146) (DOS 5.0+,NetWare4) path is already in use for SUBST
+ 93h (147) (DOS 5.0+,NetWare4) path is already in use for JOIN
+ 94h (148) (DOS 5.0+,NetWare4) path is in use by another process
+ 95h (149) (DOS 5.0+,NetWare4) directory previously SUBSTituted
+ 96h (150) (DOS 5.0+,NetWare4) system trace error
+ 97h (151) (DOS 5.0+,NetWare4) invalid event count for DosMuxSemWait
+ 98h (152) (DOS 5.0+,NetWare4) too many waiting on mutex
+ 99h (153) (DOS 5.0+,NetWare4) invalid list format
+ 9Ah (154) (DOS 5.0+,NetWare4) volume label too large
+ 9Bh (155) (DOS 5.0+,NetWare4) unable to create another TCB
+ 9Ch (156) (DOS 5.0+,NetWare4) signal refused
+ 9Dh (157) (DOS 5.0+,NetWare4) segment discarded
+ 9Eh (158) (DOS 5.0+,NetWare4) segment not locked
+ 9Fh (159) (DOS 5.0+,NetWare4) invalid thread-ID address
+-----
+ A0h (160) (DOS 5.0+) bad arguments
+ A0h (160) (NetWare4) bad environment pointer
+ A1h (161) (DOS 5.0+,NetWare4) invalid pathname passed to EXEC
+ A2h (162) (DOS 5.0+,NetWare4) signal already pending
+ A3h (163) (DOS 5.0+) uncertain media
+ A3h (163) (NetWare4) ERROR_124 mapping
+ A4h (164) (DOS 5.0+) maximum number of threads reached
+ A4h (164) (NetWare4) no more process slots
+ A5h (165) (NetWare4) ERROR_124 mapping
+ B0h (176) (MS-DOS 7.0) volume is not locked
+ B1h (177) (MS-DOS 7.0) volume is locked in drive
+ B2h (178) (MS-DOS 7.0) volume is not removable
+ B4h (180) (MS-DOS 7.0) lock count has been exceeded
+ B4h (180) (NetWare4) invalid segment number
+ B5h (181) (MS-DOS 7.0) a valid eject request failed
+ B5h (181) (DOS 5.0-6.0,NetWare4) invalid call gate
+ B6h (182) (DOS 5.0+,NetWare4) invalid ordinal
+ B7h (183) (DOS 5.0+,NetWare4) shared segment already exists
+ B8h (184) (DOS 5.0+,NetWare4) no child process to wait for
+ B9h (185) (DOS 5.0+,NetWare4) NoWait specified and child still running
+ BAh (186) (DOS 5.0+,NetWare4) invalid flag number
+ BBh (187) (DOS 5.0+,NetWare4) semaphore does not exist
+ BCh (188) (DOS 5.0+,NetWare4) invalid starting code segment
+ BDh (189) (DOS 5.0+,NetWare4) invalid stack segment
+ BEh (190) (DOS 5.0+,NetWare4) invalid module type (DLL can not be used as
+	      application)
+ BFh (191) (DOS 5.0+,NetWare4) invalid EXE signature
+ C0h (192) (DOS 5.0+,NetWare4) EXE marked invalid
+ C1h (193) (DOS 5.0+,NetWare4) bad EXE format (e.g. DOS-mode program)
+ C2h (194) (DOS 5.0+,NetWare4) iterated data exceeds 64K
+ C3h (195) (DOS 5.0+,NetWare4) invalid minimum allocation size
+ C4h (196) (DOS 5.0+,NetWare4) dynamic link from invalid Ring
+ C5h (197) (DOS 5.0+,NetWare4) IOPL not enabled
+ C6h (198) (DOS 5.0+,NetWare4) invalid segment descriptor privilege level
+ C7h (199) (DOS 5.0+,NetWare4) automatic data segment exceeds 64K
+ C8h (200) (DOS 5.0+,NetWare4) Ring2 segment must be moveable
+ C9h (201) (DOS 5.0+,NetWare4) relocation chain exceeds segment limit
+ CAh (202) (DOS 5.0+,NetWare4) infinite loop in relocation chain
+ CBh (203) (NetWare4) environment variable not found
+ CCh (204) (NetWare4) not current country
+ CDh (205) (NetWare4) no signal sent
+ CEh (206) (NetWare4) file name not 8.3
+ CFh (207) (NetWare4) Ring2 stack in use
+ D0h (208) (NetWare4) meta expansion is too long
+ D1h (209) (NetWare4) invalid signal number
+ D2h (210) (NetWare4) inactive thread
+ D3h (211) (NetWare4) file system information not available
+ D4h (212) (NetWare4) locked error
+ D5h (213) (NetWare4) attempted to execute non-family API call in DOS mode
+ D6h (214) (NetWare4) too many modules
+ D7h (215) (NetWare4) nesting not allowed
+ E6h (230) (NetWare4) non-existent pipe, or bad operation
+ E7h (231) (NetWare4) pipe is busy
+ E8h (232) (NetWare4) no data available for nonblocking read
+ E9h (233) (NetWare4) pipe disconnected by server
+ EAh (234) (NetWare4) more data available
+ FFh (255) (NetWare4) invalid drive
 @end example
 
 Values for error class (@var{class} field):
 @example
-01h  out of resource (storage space or I/O channels)
-02h  temporary situation (file or record lock)
-03h  authorization (denied access)
-04h  internal (system software bug)
-05h  hardware failure
-06h  system failure (configuration file missing or incorrect)
-07h  application program error
-08h  not found
-09h  bad format
-0Ah  locked
-0Bh  media error
-0Ch  already exists
-0Dh  unknown
+ 01h (1)  out of resource (storage space or I/O channels)
+ 02h (2)  temporary situation (file or record lock)
+ 03h (3)  authorization / permission problem (denied access)
+ 04h (4)  internal system error (system software bug)
+ 05h (5)  hardware failure
+ 06h (6)  system failure (configuration file missing or incorrect)
+ 07h (7)  application program error
+ 08h (8)  not found
+ 09h (9)  bad format
+ 0Ah (10) locked
+ 0Bh (11) media error
+ 0Ch (12) already exists / collision with existing item
+ 0Dh (13) unknown / other
+ 0Eh (14) (undoc) cannot
+ 0Fh (15) (undoc) time
 @end example
 
 Values for suggested action (@var{action} field):
 @example
-01h  retry
-02h  delayed retry
-03h  prompt user to reenter input
-04h  abort after cleanup
-05h  immediate abort
-06h  ignore
-07h  retry after user intervention
+ 01h	retry
+ 02h	delayed retry (after pause)
+ 03h	prompt user to reenter input
+ 04h	abort after cleanup
+ 05h	immediate abort ("panic")
+ 06h	ignore
+ 07h	retry after user intervention
 @end example
 
 Values for error locus (@var{locus} field):
 @example
-01h  unknown or not appropriate
-02h  block device (disk error)
-03h  network related
-04h  serial device (timeout)
-05h  memory related
+ 01h	unknown or not appropriate
+ 02h	block device (disk error)
+ 03h	network related
+ 04h	serial device (timeout)
+ 04h	(PTS-DOS 6.51+ & S/DOS 1.0+) character device
+ 05h	memory related
 @end example
 
 @subheading Return Value
@@ -165,21 +302,111 @@
 #include <stdio.h>
 #include <dos.h>
 
-void main(void)
+int main(void)
 @{
   FILE *fp;
-  struct _DOSERROR de;
+  struct DOSERROR de;
 
   fp = fopen("EXAMPLE.DAT","r");
   if ( fp == NULL )
   @{
     puts("Unable to open file for reading.");
-    _dosexterr(&de);
+    dosexterr(&de);
     printf("Extended DOS error information:\n");
     printf("Extended error: %i\n",de.exterror);
     printf("Class:          %x\n",de.class);
     printf("Action:         %x\n",de.action);
     printf("Error Locus:    %x\n",de.locus);
   @}
+  return 0;
+@}
+@end example
+
+@node dostrerr, dos
+@subheading Syntax
+
+@example
+#include <dos.h>
+
+int dostrerr(struct DOSERROR *p_error, struct DOSERROR_str *p_str);
+@end example
+
+@subheading Description
+
+This function accepts the extended error structure from DOS (e.g., from
+the returned parameter from function @code{dosexterr}, see
+@ref{dosexterr}) and returns the strings which describes that error
+structure in the structure pointed to by the second parameter.  This
+function is a DOS analogue of the ANSI function @ref{strerror}, and can
+be used to print descriptive messages corresponding to the errors
+described in the @code{DOSERROR} structure.
+
+For a list of the strings returned for each error number and type, see
+@ref{dosexterr}.
+
+@var{p_error} must point to the following structure:
+
+@example
+struct DOSERROR @{
+  int  exterror;
+  char class;
+  char action;
+  char locus;
+@};
+@end example
+
+@var{p_str} must point to the following structure:
+
+@example
+struct DOSERROR_STR @{
+  char *exterror_str;
+  char *class_str;
+  char *action_str;
+  char *locus_str;
+@};
+@end example
+
+
+@subheading Return Value
+
+If either pointer parameter is @code{NULL}, returns -1 and sets
+@code{errno} to EINVAL.  If both parameters are not @code{NULL}, checks
+the value of each member of the @code{DOSERROR} parameter @var{p_error}.
+If each value is within the limits of valid error codes for that member,
+sets parameter @var{p_str} member fields with the corresponding string
+describing the error code.  If any error code is outside of the valid
+values for that code, sets the corresponding @var{p_str} member to the
+string "Unknown error: " followed by the decimal numeric value of the
+error code.
+
+@subheading Portability
+
+@portability !ansi, !posix
+
+@subheading Example
+
+@example
+#include <stdio.h>
+#include <dos.h>
+
+int main(void)
+@{
+  FILE *fp;
+  struct DOSERROR de;
+  struct DOSERROR_STR se;
+
+  fp = fopen("EXAMPLE.DAT","r");
+  if ( fp == NULL )
+  @{
+    puts("Unable to open file for reading.");
+    dosexterr(&de);
+    dostrerr(&de, &se);
+    printf("Extended DOS error information:\n");
+    printf("Extended error: %i : %s\n",de.exterror,se.exterror_str);
+    printf("Class:          %x : %s\n",de.class,se.class_str);
+    printf("Action:         %x : %s\n",de.action,se.action_str);
+    printf("Error Locus:    %x : %s\n",de.locus,se.locus_str);
+  @}
+  return 0;
 @}
 @end example
diff -ruN djgpp-cvs/src/libc/dos/compat/d_strerr.c djgpp/src/libc/dos/compat/d_strerr.c
--- djgpp-cvs/src/libc/dos/compat/d_strerr.c	Thu Jan  1 00:00:00 1970
+++ djgpp/src/libc/dos/compat/d_strerr.c	Fri Dec  8 00:16:30 2000
@@ -0,0 +1,400 @@
+/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
+/*
+ * D_STRERR.C.
+ *
+ * Written by Peter J. Farley III 2000 <pjfarley AT banet DOT net>.
+ *
+ * This file is distributed WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <dos.h>
+#include <libc/unconst.h>
+
+/* Values for extended error code (EXTERROR field): */
+const char *__dos_errlist [] = {
+/* ---DOS 2.0+ --- */
+/* 00h (0)   */ "No error",
+/* 01h (1)   */ "Function number invalid",
+/* 02h (2)   */ "File not found",
+/* 03h (3)   */ "Path not found",
+/* 04h (4)   */ "Too many open files (no handles available)",
+/* 05h (5)   */ "Access denied",
+/* 06h (6)   */ "Invalid handle",
+/* 07h (7)   */ "Memory control block destroyed",
+/* 08h (8)   */ "Insufficient memory",
+/* 09h (9)   */ "Memory block address invalid",
+/* 0Ah (10)  */ "Environment invalid (usually >32K in length)",
+/* 0Bh (11)  */ "Format invalid",
+/* 0Ch (12)  */ "Access code invalid",
+/* 0Dh (13)  */ "Data invalid",
+/* 0Eh (14)  */ "Reserved/(PTS-DOS 6.51+, S/DOS 1.0+) fixup overflow",
+/* 0Fh (15)  */ "Invalid drive",
+/* 10h (16)  */ "Attempted to remove current directory",
+/* 11h (17)  */ "Not same device",
+/* 12h (18)  */ "No more files",
+/* ---DOS 3.0+ (INT 24 errors)--- */
+/* 13h (19)  */ "Disk write-protected",
+/* 14h (20)  */ "Unknown unit",
+/* 15h (21)  */ "Drive not ready",
+/* 16h (22)  */ "Unknown command",
+/* 17h (23)  */ "Data error (CRC)",
+/* 18h (24)  */ "Bad request structure length",
+/* 19h (25)  */ "Seek error",
+/* 1Ah (26)  */ "Unknown media type (non-DOS disk)",
+/* 1Bh (27)  */ "Sector not found",
+/* 1Ch (28)  */ "Printer out of paper",
+/* 1Dh (29)  */ "Write fault",
+/* 1Eh (30)  */ "Read fault",
+/* 1Fh (31)  */ "General failure",
+/* 20h (32)  */ "Sharing violation",
+/* 21h (33)  */ "Lock violation",
+/* 22h (34)  */ "Disk change invalid (ES:DI -> media ID structure)(see #01681)",
+/* 23h (35)  */ "FCB unavailable",
+/* 23h (35)  */ "(PTS-DOS 6.51+, S/DOS 1.0+) Bad FAT",
+/* 24h (36)  */ "Sharing buffer overflow",
+/* 25h (37)  */ "(DOS 4.0+) Code page mismatch",
+/* 26h (38)  */ "(DOS 4.0+) Cannot complete file operation (EOF / out of input)",
+/* 27h (39)  */ "(DOS 4.0+) Insufficient disk space",
+/* 28h (40)  */ "Reserved",
+/* 29h (41)  */ "Reserved",
+/* 2Ah (42)  */ "Reserved",
+/* 2Bh (43)  */ "Reserved",
+/* 2Ch (44)  */ "Reserved",
+/* 2Dh (45)  */ "Reserved",
+/* 2Eh (46)  */ "Reserved",
+/* 2Fh (47)  */ "Reserved",
+/* 30h (48)  */ "Reserved",
+/* 31h (49)  */ "Reserved",
+/* ---OEM network errors (INT 24)--- */
+/* 32h (50)  */ "Network request not supported",
+/* 33h (51)  */ "Remote computer not listening",
+/* 34h (52)  */ "Duplicate name on network",
+/* 35h (53)  */ "Network name not found",
+/* 36h (54)  */ "Network busy",
+/* 37h (55)  */ "Network device no longer exists",
+/* 38h (56)  */ "Network BIOS command limit exceeded",
+/* 39h (57)  */ "Network adapter hardware error",
+/* 3Ah (58)  */ "Incorrect response from network",
+/* 3Bh (59)  */ "Unexpected network error",
+/* 3Ch (60)  */ "Incompatible remote adapter",
+/* 3Dh (61)  */ "Print queue full",
+/* 3Eh (62)  */ "Queue not full",
+/* 3Fh (63)  */ "Not enough space to print file",
+/* 40h (64)  */ "Network name was deleted",
+/* 41h (65)  */ "Network: Access denied",
+/*	  (DOS 3.0+ [maybe 3.3+???]) codepage switching not possible
+	    (see also INT 21/AX=6602h,INT 2F/AX=AD42h) */
+/* 42h (66)  */ "Network device type incorrect",
+/* 43h (67)  */ "Network name not found",
+/* 44h (68)  */ "Network name limit exceeded",
+/* 45h (69)  */ "Network BIOS session limit exceeded",
+/* 46h (70)  */ "Temporarily paused",
+/* 47h (71)  */ "Network request not accepted",
+/* 48h (72)  */ "Network print/disk redirection paused",
+/* 49h (73)  */ "Network software not installed/(LANtastic) Invalid network version",
+/* 4Ah (74)  */ "Unexpected adapter close/(LANtastic) Account expired",
+/* 4Bh (75)  */ "(LANtastic) Password expired",
+/* 4Ch (76)  */ "(LANtastic) Login attempt invalid at this time",
+/* 4Dh (77)  */ "(LANtastic v3+) Disk limit exceeded on network node",
+/* 4Eh (78)  */ "(LANtastic v3+) Not logged in to network node",
+/* 4Fh (79)  */ "Reserved",
+/* ---end of errors reportable via INT 24--- */
+/* 50h (80)  */ "File exists",
+/* 51h (81)  */ "(undoc) Duplicated FCB",
+/* 52h (82)  */ "Cannot make directory",
+/* 53h (83)  */ "Fail on INT 24h",
+/* ---network-related errors (non-INT 24)--- */
+/* 54h (84)  */ "(DOS 3.3+) Too many redirections / out of structures",
+/* 55h (85)  */ "(DOS 3.3+) Duplicate redirection / already assigned",
+/* 56h (86)  */ "(DOS 3.3+) Invalid password",
+/* 57h (87)  */ "(DOS 3.3+) Invalid parameter",
+/* 58h (88)  */ "(DOS 3.3+) Network write fault",
+/* 59h (89)  */ "(DOS 4.0+) Function not supported on network / no process slots available",
+/* 5Ah (90)  */ "(DOS 4.0+) Required system component not installed / not frozen",
+/* 5Bh (91)  */ "(DOS 4.0+,NetWare4) Timer server table overflowed",
+/* 5Ch (92)  */ "(DOS 4.0+,NetWare4) Duplicate in timer service table",
+/* 5Dh (93)  */ "(DOS 4.0+,NetWare4) No items to work on",
+/* 5Eh (94)  */ "Reserved",
+/* 5Fh (95)  */ "(DOS 4.0+,NetWare4) Interrupted / invalid system call",
+/* 60h (96)  */ "Reserved",
+/* 61h (97)  */ "Reserved",
+/* 62h (98)  */ "Reserved",
+/* 63h (99)  */ "Reserved",
+/* 64h (100) */ "(MSCDEX) Unknown error/(DOS 4.0+,NetWare4) Open semaphore limit exceeded",
+/* 65h (101) */ "(MSCDEX) Not ready/(DOS 4.0+,NetWare4) Exclusive semaphore is already owned",
+/* 66h (102) */ "(MSCDEX) EMS memory no longer valid/(DOS 4.0+,NetWare4) Semaphore was set when close attempted",
+/* 67h (103) */ "(MSCDEX) Not High Sierra or ISO-9660 format/(DOS 4.0+,NetWare4) Too many exclusive semaphore requests",
+/* 68h (104) */ "(MSCDEX) Door open/(DOS 4.0+,NetWare4) Operation invalid from interrupt handler",
+/* 69h (105) */ "(DOS 4.0+,NetWare4) Semaphore owner died",
+/* 6Ah (106) */ "(DOS 4.0+,NetWare4) Semaphore limit exceeded",
+/* 6Bh (107) */ "(DOS 4.0+,NetWare4) Insert drive B: disk into A: / disk changed",
+/* 6Ch (108) */ "(DOS 4.0+,NetWare4) Drive locked by another process",
+/* 6Dh (109) */ "(DOS 4.0+,NetWare4) Broken pipe",
+/* 6Eh (110) */ "(DOS 5.0+,NetWare4) Pipe open/create failed",
+/* 6Fh (111) */ "(DOS 5.0+,NetWare4) Pipe buffer overflowed",
+/* 70h (112) */ "(DOS 5.0+,NetWare4) Disk full",
+/* 71h (113) */ "(DOS 5.0+,NetWare4) No more search handles",
+/* 72h (114) */ "(DOS 5.0+,NetWare4) Invalid target handle for dup2",
+/* 73h (115) */ "(DOS 5.0+,NetWare4) Bad user virtual address / protection violation",
+/* 74h (116) */ "(DOS 5.0+) VIOKBD request/(NetWare4) error on console I/O",
+/* 75h (117) */ "(DOS 5.0+,NetWare4) Unknown category code for IOCTL",
+/* 76h (118) */ "(DOS 5.0+,NetWare4) Invalid value for verify flag",
+/* 77h (119) */ "(DOS 5.0+,NetWare4) Level four driver not found by DOS IOCTL",
+/* 78h (120) */ "(DOS 5.0+,NetWare4) Invalid / unimplemented function number",
+/* 79h (121) */ "(DOS 5.0+,NetWare4) Semaphore timeout",
+/* 7Ah (122) */ "(DOS 5.0+,NetWare4) Buffer too small to hold return data",
+/* 7Bh (123) */ "(DOS 5.0+,NetWare4) Invalid character or bad file-system name",
+/* 7Ch (124) */ "(DOS 5.0+,NetWare4) Unimplemented information level",
+/* 7Dh (125) */ "(DOS 5.0+,NetWare4) No volume label found",
+/* 7Eh (126) */ "(DOS 5.0+,NetWare4) Module handle not found",
+/* 7Fh (127) */ "(DOS 5.0+,NetWare4) Procedure address not found",
+/* 80h (128) */ "(DOS 5.0+,NetWare4) CWait found no children",
+/* 81h (129) */ "(DOS 5.0+,NetWare4) CWait children still running",
+/* 82h (130) */ "(DOS 5.0+,NetWare4) Invalid operation for direct disk-access handle",
+/* 83h (131) */ "(DOS 5.0+,NetWare4) Attempted seek to negative offset",
+/* 84h (132) */ "(DOS 5.0+,NetWare4) Attempted to seek on device or pipe",
+/* ---JOIN/SUBST Errors--- */
+/* 85h (133) */ "(DOS 5.0+,NetWare4) Drive already has JOINed drives",
+/* 86h (134) */ "(DOS 5.0+,NetWare4) Drive is already JOINed",
+/* 87h (135) */ "(DOS 5.0+,NetWare4) Drive is already SUBSTed",
+/* 88h (136) */ "(DOS 5.0+,NetWare4) Can not delete drive which is not JOINed",
+/* 89h (137) */ "(DOS 5.0+,NetWare4) Can not delete drive which is not SUBSTed",
+/* 8Ah (138) */ "(DOS 5.0+,NetWare4) Can not JOIN to a JOINed drive",
+/* 8Bh (139) */ "(DOS 5.0+,NetWare4) Can not SUBST to a SUBSTed drive",
+/* 8Ch (140) */ "(DOS 5.0+,NetWare4) Can not JOIN to a SUBSTed drive",
+/* 8Dh (141) */ "(DOS 5.0+,NetWare4) Can not SUBST to a JOINed drive",
+/* 8Eh (142) */ "(DOS 5.0+,NetWare4) Drive is busy",
+/* 8Fh (143) */ "(DOS 5.0+,NetWare4) Can not JOIN/SUBST to same drive",
+/* 90h (144) */ "(DOS 5.0+,NetWare4) Directory must not be root directory",
+/* 91h (145) */ "(DOS 5.0+,NetWare4) Can only JOIN to empty directory",
+/* 92h (146) */ "(DOS 5.0+,NetWare4) Path is already in use for SUBST",
+/* 93h (147) */ "(DOS 5.0+,NetWare4) Path is already in use for JOIN",
+/* 94h (148) */ "(DOS 5.0+,NetWare4) Path is in use by another process",
+/* 95h (149) */ "(DOS 5.0+,NetWare4) Directory previously SUBSTituted",
+/* 96h (150) */ "(DOS 5.0+,NetWare4) System trace error",
+/* 97h (151) */ "(DOS 5.0+,NetWare4) Invalid event count for DosMuxSemWait",
+/* 98h (152) */ "(DOS 5.0+,NetWare4) Too many waiting on mutex",
+/* 99h (153) */ "(DOS 5.0+,NetWare4) Invalid list format",
+/* 9Ah (154) */ "(DOS 5.0+,NetWare4) Volume label too large",
+/* 9Bh (155) */ "(DOS 5.0+,NetWare4) Unable to create another TCB",
+/* 9Ch (156) */ "(DOS 5.0+,NetWare4) Signal refused",
+/* 9Dh (157) */ "(DOS 5.0+,NetWare4) Segment discarded",
+/* 9Eh (158) */ "(DOS 5.0+,NetWare4) Segment not locked",
+/* 9Fh (159) */ "(DOS 5.0+,NetWare4) Invalid thread-ID address",
+/* ----- */
+/* A0h (160) */ "(DOS 5.0+) Bad arguments/(NetWare4) bad environment pointer",
+/* A1h (161) */ "(DOS 5.0+,NetWare4) Invalid pathname passed to EXEC",
+/* A2h (162) */ "(DOS 5.0+,NetWare4) Signal already pending",
+/* A3h (163) */ "(DOS 5.0+) Uncertain media",
+/* A3h (163) */ "(NetWare4) ERROR_124 mapping",
+/* A4h (164) */ "(DOS 5.0+) Maximum number of threads reached/(NetWare4) No more process slots",
+/* A5h (165) */ "(NetWare4) ERROR_124 mapping",
+/* A6h (166) */ "Reserved",
+/* A7h (167) */ "Reserved",
+/* A8h (168) */ "Reserved",
+/* A9h (169) */ "Reserved",
+/* AAh (170) */ "Reserved",
+/* ABh (171) */ "Reserved",
+/* ACh (172) */ "Reserved",
+/* ADh (173) */ "Reserved",
+/* AEh (174) */ "Reserved",
+/* AFh (175) */ "Reserved",
+/* B0h (176) */ "(MS-DOS 7.0) Volume is not locked",
+/* B1h (177) */ "(MS-DOS 7.0) Volume is locked in drive",
+/* B2h (178) */ "(MS-DOS 7.0) Volume is not removable",
+/* B4h (180) */ "(MS-DOS 7.0) Lock count has been exceeded",
+/* B4h (180) */ "(NetWare4) Invalid segment number",
+/* B5h (181) */ "(MS-DOS 7.0) A valid eject request failed",
+/* B5h (181) */ "(DOS 5.0-6.0,NetWare4) Invalid call gate",
+/* B6h (182) */ "(DOS 5.0+,NetWare4) Invalid ordinal",
+/* B7h (183) */ "(DOS 5.0+,NetWare4) Shared segment already exists",
+/* B8h (184) */ "(DOS 5.0+,NetWare4) No child process to wait for",
+/* B9h (185) */ "(DOS 5.0+,NetWare4) NoWait specified and child still running",
+/* BAh (186) */ "(DOS 5.0+,NetWare4) Invalid flag number",
+/* BBh (187) */ "(DOS 5.0+,NetWare4) Semaphore does not exist",
+/* BCh (188) */ "(DOS 5.0+,NetWare4) Invalid starting code segment",
+/* BDh (189) */ "(DOS 5.0+,NetWare4) Invalid stack segment",
+/* BEh (190) */ "(DOS 5.0+,NetWare4) Invalid module type (DLL can not be used as application)",
+/* BFh (191) */ "(DOS 5.0+,NetWare4) Invalid EXE signature",
+/* C0h (192) */ "(DOS 5.0+,NetWare4) EXE marked invalid",
+/* C1h (193) */ "(DOS 5.0+,NetWare4) Bad EXE format (e.g. DOS-mode program)",
+/* C2h (194) */ "(DOS 5.0+,NetWare4) Iterated data exceeds 64K",
+/* C3h (195) */ "(DOS 5.0+,NetWare4) Invalid minimum allocation size",
+/* C4h (196) */ "(DOS 5.0+,NetWare4) Dynamic link from invalid Ring",
+/* C5h (197) */ "(DOS 5.0+,NetWare4) IOPL not enabled",
+/* C6h (198) */ "(DOS 5.0+,NetWare4) Invalid segment descriptor privilege level",
+/* C7h (199) */ "(DOS 5.0+,NetWare4) Automatic data segment exceeds 64K",
+/* C8h (200) */ "(DOS 5.0+,NetWare4) Ring2 segment must be moveable",
+/* C9h (201) */ "(DOS 5.0+,NetWare4) Relocation chain exceeds segment limit",
+/* CAh (202) */ "(DOS 5.0+,NetWare4) Infinite loop in relocation chain",
+/* CBh (203) */ "(NetWare4) Environment variable not found",
+/* CCh (204) */ "(NetWare4) Not current country",
+/* CDh (205) */ "(NetWare4) No signal sent",
+/* CEh (206) */ "(NetWare4) File name not 8.3",
+/* CFh (207) */ "(NetWare4) Ring2 stack in use",
+/* D0h (208) */ "(NetWare4) Meta expansion is too long",
+/* D1h (209) */ "(NetWare4) Invalid signal number",
+/* D2h (210) */ "(NetWare4) Inactive thread",
+/* D3h (211) */ "(NetWare4) File system information not available",
+/* D4h (212) */ "(NetWare4) Locked error",
+/* D5h (213) */ "(NetWare4) Attempted to execute non-family API call in DOS mode",
+/* D6h (214) */ "(NetWare4) Too many modules",
+/* D7h (215) */ "(NetWare4) Nesting not allowed",
+/* D8h (216) */ "Reserved",
+/* D9h (217) */ "Reserved",
+/* DAh (218) */ "Reserved",
+/* DBh (219) */ "Reserved",
+/* DCh (220) */ "Reserved",
+/* DDh (221) */ "Reserved",
+/* DEh (222) */ "Reserved",
+/* DFh (223) */ "Reserved",
+/* E0h (224) */ "Reserved",
+/* E1h (225) */ "Reserved",
+/* E2h (226) */ "Reserved",
+/* E3h (227) */ "Reserved",
+/* E4h (228) */ "Reserved",
+/* E5h (229) */ "Reserved",
+/* E6h (230) */ "(NetWare4) Non-existent pipe, or bad operation",
+/* E7h (231) */ "(NetWare4) Pipe is busy",
+/* E8h (232) */ "(NetWare4) No data available for nonblocking read",
+/* E9h (233) */ "(NetWare4) Pipe disconnected by server",
+/* EAh (234) */ "(NetWare4) More data available",
+/* EBh (235) */ "Reserved",
+/* ECh (236) */ "Reserved",
+/* EDh (237) */ "Reserved",
+/* EEh (238) */ "Reserved",
+/* EFh (239) */ "Reserved",
+/* F0h (240) */ "Reserved",
+/* F1h (241) */ "Reserved",
+/* F2h (242) */ "Reserved",
+/* F3h (243) */ "Reserved",
+/* F4h (244) */ "Reserved",
+/* F5h (245) */ "Reserved",
+/* F6h (246) */ "Reserved",
+/* F7h (247) */ "Reserved",
+/* F8h (248) */ "Reserved",
+/* F9h (249) */ "Reserved",
+/* FAh (250) */ "Reserved",
+/* FBh (251) */ "Reserved",
+/* FCh (252) */ "Reserved",
+/* FDh (253) */ "Reserved",
+/* FEh (254) */ "Reserved",
+/* FFh (255) */ "(NetWare4) Invalid drive"
+/* (End of list) */ };
+
+int __dos_nerr = sizeof(__dos_errlist) / sizeof(__dos_errlist[0]);
+
+/* Values for error class (CLASS field): */
+const char *__dos_errclass [] = {
+/* 01h (1)  */ "Out of resource (storage space or I/O channels)",
+/* 02h (2)  */ "Temporary situation (file or record lock)",
+/* 03h (3)  */ "Authorization / permission problem (denied access)",
+/* 04h (4)  */ "Internal system error (system software bug)",
+/* 05h (5)  */ "Hardware failure",
+/* 06h (6)  */ "System failure (configuration file missing or incorrect)",
+/* 07h (7)  */ "Application program error",
+/* 08h (8)  */ "Not found",
+/* 09h (9)  */ "Bad format",
+/* 0Ah (10) */ "Locked",
+/* 0Bh (11) */ "Media error",
+/* 0Ch (12) */ "Already exists / collision with existing item",
+/* 0Dh (13) */ "Unknown / other",
+/* 0Eh (14) */ "(Undoc) Cannot",
+/* 0Fh (15) */ "(Undoc) Time"
+/* (End of list) */ };
+
+int __dos_ncls = sizeof(__dos_errclass) / sizeof(__dos_errclass[0]);
+
+/* Values for suggested action (ACTION field): */
+const char *__dos_erraction [] = {
+/* 01h (01) */ "Retry",
+/* 02h (02) */ "Delayed retry",
+/* 03h (03) */ "Prompt user to reenter input",
+/* 04h (04) */ "Abort after cleanup",
+/* 05h (05) */ "Immediate abort",
+/* 06h (06) */ "Ignore",
+/* 07h (07) */ "Retry after user intervention"
+/* (End of list) */ };
+
+int __dos_nact = sizeof(__dos_erraction) / sizeof(__dos_erraction[0]);
+
+/* Values for error locus (LOCUS field): */
+const char *__dos_errlocus [] = {
+/*   01h (01) */  "Unknown or not appropriate",
+/*   02h (02) */  "Block device (disk error)",
+/*   03h (03) */  "Network related",
+/*   04h (04) */  "Serial device (timeout)/(PTS-DOS 6.51+ & S/DOS 1.0+) Character device",
+/*   05h (05) */  "Memory related"
+/* (End of list) */ };
+
+int __dos_nloc = sizeof(__dos_errlocus) / sizeof(__dos_errlocus[0]);
+
+static char *
+_err_unknown(int errnum)
+{
+  static char ebuf[40];         /* 64-bit number + slop */
+  char *cp;
+  int v=1000000, lz=0;
+
+  strcpy(ebuf, "Unknown error: ");
+  cp = ebuf + strlen(ebuf);
+  if (errnum < 0)
+  {
+    *cp++ = '-';
+    errnum = -errnum;
+  }
+  while (v)
+  {
+    int d = errnum / v;
+    if (d || lz || (v == 1))
+    {
+      *cp++ = d+'0';
+      lz = 1;
+    }
+    errnum %= v;
+    v /= 10;
+  }
+
+  return ebuf;
+}
+
+int
+_dostrerr(struct _DOSERROR *p_error, struct _DOSERROR_STR *p_str)
+{
+  if (!p_error || !p_str)
+  {
+    errno = EINVAL;
+    return -1;
+  }
+
+  if (p_error->exterror >= 0 && p_error->exterror < __dos_nerr)
+    p_str->exterror_str = unconst(__dos_errlist[p_error->exterror], char *);
+  else
+    p_str->exterror_str = _err_unknown(p_error->exterror);
+
+  if (p_error->class >= 0 && p_error->class < __dos_ncls)
+  #ifdef __cplusplus
+    p_str->errclass_str = unconst(__dos_errclass[(unsigned char)p_error->errclass], char *);
+  #else
+    p_str->class_str = unconst(__dos_errclass[(unsigned char)p_error->class], char *);
+  #endif
+  else
+    p_str->class_str = _err_unknown(p_error->class);
+
+  if (p_error->action >= 0 && p_error->action < __dos_nact)
+    p_str->action_str = unconst(__dos_erraction[(unsigned char)p_error->action], char *);
+  else
+    p_str->action_str = _err_unknown(p_error->action);
+
+  if (p_error->locus >= 0 && p_error->locus < __dos_nloc)
+    p_str->locus_str = unconst(__dos_errlocus[(unsigned char)p_error->locus], char *);
+  else
+    p_str->locus_str = _err_unknown(p_error->locus);
+
+  return 0;
+}
diff -ruN djgpp-cvs/src/libc/dos/compat/makefile djgpp/src/libc/dos/compat/makefile
--- djgpp-cvs/src/libc/dos/compat/makefile	Sun Aug 27 02:38:32 1995
+++ djgpp/src/libc/dos/compat/makefile	Sat Nov 25 13:02:16 2000
@@ -21,6 +21,7 @@
 SRC += d_setfa.c
 SRC += d_setftm.c
 SRC += d_settim.c
+SRC += d_strerr.c
 SRC += d_write.c
 
 include $(TOP)/../makefile.inc
diff -ruN djgpp-cvs/src/libc/dos/errno/doserr2e.c djgpp/src/libc/dos/errno/doserr2e.c
--- djgpp-cvs/src/libc/dos/errno/doserr2e.c	Tue Sep  8 07:49:26 1998
+++ djgpp/src/libc/dos/errno/doserr2e.c	Sat Dec  9 00:47:46 2000
@@ -1,5 +1,10 @@
+/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
+
+/* 21h (33) EPERM -> EACCES                                  */
+/*          lock violation needs EACCES errno in fcntl       */
+
 #include <errno.h>
 #include <libc/dosio.h>
 
@@ -8,7 +13,7 @@
   /* 08-0f */ ENOMEM, EFAULT, EFAULT, EINVAL, EINVAL, EINVAL, EINVAL, ENODEV,
   /* 10-17 */ EBUSY, EXDEV, ENMFILE, EROFS, ENXIO, ENXIO, EINVAL, EIO,
   /* 18-1f */ EINVAL, EIO, EIO, EIO, EIO, EIO, EIO, EIO,
-  /* 20-27 */ EPERM, EPERM, ENXIO, EBADF, ENOLCK, EINVAL, EIO, ENOSPC,
+  /* 20-27 */ EPERM, EACCES, ENXIO, EBADF, ENOLCK, EINVAL, EIO, ENOSPC,
   /* 28-2f */ EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, EINVAL, EINVAL,
   /* 30-37 */ EINVAL, EINVAL, ENOSYS, EIO, EINVAL, EINVAL, EBUSY, ENXIO,
   /* 38-3f */ EINVAL, EIO, EIO, EIO, EIO, EAGAIN, EINVAL, ENOSPC,
diff -ruN djgpp-cvs/src/libc/dos/io/doslk64.c djgpp/src/libc/dos/io/doslk64.c
--- djgpp-cvs/src/libc/dos/io/doslk64.c	Thu Jan  1 00:00:00 1970
+++ djgpp/src/libc/dos/io/doslk64.c	Sun Dec 10 00:15:28 2000
@@ -0,0 +1,19 @@
+/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
+#include <dpmi.h>
+#include <io.h>
+
+int
+_dos_lk64(int _fd, long long _offset, long long _length)
+{
+  __dpmi_regs r;
+  r.x.ax = 0x5c00;
+  r.x.bx = _fd;
+  r.x.cx = _offset >> 16;
+  r.x.dx = _offset & 0xffff;
+  r.x.si = _length >> 16;
+  r.x.di = _length & 0xffff;
+  __dpmi_int(0x21, &r);
+  if (r.x.flags & 1)
+    return r.x.ax;
+  return 0;
+}
diff -ruN djgpp-cvs/src/libc/dos/io/dosunl64.c djgpp/src/libc/dos/io/dosunl64.c
--- djgpp-cvs/src/libc/dos/io/dosunl64.c	Thu Jan  1 00:00:00 1970
+++ djgpp/src/libc/dos/io/dosunl64.c	Sun Dec 10 00:15:48 2000
@@ -0,0 +1,19 @@
+/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
+#include <dpmi.h>
+#include <io.h>
+
+int
+_dos_unlk64(int _fd, long long _offset, long long _length)
+{
+  __dpmi_regs r;
+  r.x.ax = 0x5c01;
+  r.x.bx = _fd;
+  r.x.cx = _offset >> 16;
+  r.x.dx = _offset & 0xffff;
+  r.x.si = _length >> 16;
+  r.x.di = _length & 0xffff;
+  __dpmi_int(0x21, &r);
+  if (r.x.flags & 1)
+    return r.x.ax;
+  return 0;
+}
diff -ruN djgpp-cvs/src/libc/dos/io/lock64.c djgpp/src/libc/dos/io/lock64.c
--- djgpp-cvs/src/libc/dos/io/lock64.c	Thu Jan  1 00:00:00 1970
+++ djgpp/src/libc/dos/io/lock64.c	Sat Dec  9 14:05:12 2000
@@ -0,0 +1,24 @@
+/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
+/* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */
+/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
+#include <io.h>
+#include <errno.h>
+#include <libc/dosio.h>
+
+int
+lock64(int fd, long long offset, long long length)
+{
+  int ret = _dos_lk64(fd, offset, length);
+#if 0 /* __doserr_to_errno does the same */
+  /* change return code because Borland does it this way */
+  if (ret == 0x21)
+    ret = EACCES;
+#endif
+  if (ret != 0)
+  {
+    errno = __doserr_to_errno(ret);
+    return -1;
+  }
+  else
+    return 0;
+}
diff -ruN djgpp-cvs/src/libc/dos/io/makefile djgpp/src/libc/dos/io/makefile
--- djgpp-cvs/src/libc/dos/io/makefile	Sun Jun 28 18:42:16 1998
+++ djgpp/src/libc/dos/io/makefile	Sat Dec  9 14:06:32 2000
@@ -12,14 +12,18 @@
 SRC += _write.c
 SRC += crlf2nl.c
 SRC += dosio.c
+SRC += doslk64.c
 SRC += doslock.c
+SRC += dosunl64.c
 SRC += dosunloc.c
 SRC += fmode.c
 SRC += lock.c
+SRC += lock64.c
 SRC += putpath.c
 SRC += setmode.c
 SRC += tell.c
 SRC += unlock.c
+SRC += unlock64.c
 SRC += flushdc.c
 
 include $(TOP)/../makefile.inc
diff -ruN djgpp-cvs/src/libc/dos/io/unlock64.c djgpp/src/libc/dos/io/unlock64.c
--- djgpp-cvs/src/libc/dos/io/unlock64.c	Thu Jan  1 00:00:00 1970
+++ djgpp/src/libc/dos/io/unlock64.c	Sat Dec  9 14:05:08 2000
@@ -0,0 +1,25 @@
+/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
+/* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */
+/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
+#include <io.h>
+#include <errno.h>
+#include <libc/dosio.h>
+
+int
+unlock64(int fd, long long offset, long long length)
+{
+  int ret = _dos_unlk64(fd, offset, length);
+#if 0 /* __doserr_to_errno does the same */
+  /* change return code because Borland does it this way */
+  if (ret == 0x21)
+    ret = EACCES;
+#endif
+  if (ret != 0)
+  {
+    errno = __doserr_to_errno(ret);
+    return -1;
+  }
+  else
+    return 0;
+}
+
diff -ruN djgpp-cvs/src/libc/go32/exceptn.S djgpp/src/libc/go32/exceptn.S
--- djgpp-cvs/src/libc/go32/exceptn.S	Tue May 30 14:14:08 2000
+++ djgpp/src/libc/go32/exceptn.S	Sat Nov 18 19:01:16 2000
@@ -348,7 +348,12 @@
 	popl	%ds
 	popl	%ebx
 	popl	%eax
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
 	ljmp	%cs:___djgpp_old_kbd
+#else
+	ljmp	*%cs:___djgpp_old_kbd
+#endif
 
 	.balign 16,,7
 	.global	___djgpp_kbd_hdlr_pc98
@@ -400,7 +405,12 @@
    	.byte	0x2e				/* CS: */
 	testb	$4, ___djgpp_hwint_flags	/* IRET or chain? */
 	jne	2f
+#if    (GAS_MAJOR == 2) \
+    && ((GAS_MINOR < 9) || ((GAS_MINOR == 9) && (GAS_MINORMINOR < 5)))
 	ljmp	%cs:___djgpp_old_timer
+#else
+	ljmp	*%cs:___djgpp_old_timer
+#endif
 2:
 	pushl	%eax
 	movb	$0x20,%al			/* EOI the interrupt */
diff -ruN djgpp-cvs/src/libc/posix/fcntl/fcntl.c djgpp/src/libc/posix/fcntl/fcntl.c
--- djgpp-cvs/src/libc/posix/fcntl/fcntl.c	Thu Jun  3 13:27:38 1999
+++ djgpp/src/libc/posix/fcntl/fcntl.c	Mon Dec 11 20:41:46 2000
@@ -1,3 +1,4 @@
+/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
@@ -7,28 +8,119 @@
 #include <stdarg.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <io.h>
 #include <sys/fsext.h>
+#include <sys/movedata.h>
+#include <sys/farptr.h>
+#include <libc/dosio.h>
+#include <libc/getdinfo.h>
+
+
+#include <go32.h>
+
+
+static unsigned long _get_sft_entry_ptr(int fd)
+{
+  __dpmi_regs regs;
+  unsigned char index;
+  unsigned long es, di;
+
+
+  /* Get the JFT entry address for this handle.  */
+  regs.x.ax = 0x1220;
+  regs.x.bx = fd;
+  __dpmi_int(0x2f, &regs);
+
+
+  if (regs.x.flags & 1) /* int2F/1220 returns CF set if bad input */
+  {
+    errno = __doserr_to_errno(regs.h.al);  /* And AL has the error number */
+    return 0;
+  }
+
+
+  /* Get the SFT entry number for this handle.  */
+  es = regs.x.es;
+  di = regs.x.di;
+  index = _farpeekb(_dos_ds, es * 16 + di);
+
+
+  if (index < 0xff)
+  {
+    /* Now get the address of the entry.  */
+    regs.x.ax = 0x1216;
+    regs.x.bx = index;
+    __dpmi_int (0x2f, &regs);
+  }
+  else
+    regs.x.flags |= 1;  /* Set carry flag to simulate error       */
+
+  if (regs.x.flags & 1) /* int2F/1216 returns CF set if bad input */
+  {
+    errno = EBADF;      /* But no other information is returned   */
+    return 0;
+  }
+
+
+  es = regs.x.es;
+  di = regs.x.di;
+
+
+  return es * 16 + di;
+}
+
 
 static int
-is_used_fd(int fd)
+inherit_bit_test (int fd, short dev_info)
 {
   __dpmi_regs regs;
+  short new_dev_info;
+
 
-  regs.x.ax = 0x4400;
+  dev_info |= _DEV_NO_INHERIT;
+  regs.x.ax = 0x4401;
   regs.x.bx = fd;
+  regs.x.dx = dev_info;
   __dpmi_int(0x21, &regs);
-  if (regs.x.flags & 1)
-    return 0;
 
-  return 1;
+  new_dev_info = _get_dev_info(fd);
+
+  /* If the dev info words are equal, then the documented
+     interface can be used to set the inheritance bit.  */
+  return (new_dev_info == dev_info) ? 1 : 0;
 }
 
+static int
+_get_SHARE_status (void)
+{
+  __dpmi_regs regs;
+
+  regs.x.ax = 0x1000;
+  __dpmi_int(0x2f, &regs);
+
+  /* If al == 0xff then SHARE is installed, otherwise not */
+  return (regs.h.al == 0xff) ? 1 : 0;
+}
+
+
 int
 fcntl(int fd, int cmd, ...)
 {
   int tofd, open_max;
   va_list ap;
-  __FSEXT_Function *func = __FSEXT_get_function(fd);
+  __FSEXT_Function *func;
+  short dev_info = _get_dev_info(fd);
+  static int inherit_bit_visible = -1;
+  int errno_save;
+
+  /* Verify the descriptor is valid by retrieving
+     the handle's device info word.  */
+  if (dev_info == -1)
+    return dev_info;
+
+
+  /* Allow a fd to override with a FSEXT.  */
+  func = __FSEXT_get_function(fd);
   if (func)
   {
     int rv;
@@ -36,62 +128,426 @@
       return rv;
   }
 
+
+  errno_save = errno;
+
   switch (cmd)
   {
-  case F_DUPFD:
-    va_start(ap, cmd);
-    tofd = va_arg(ap, int);
-    va_end(ap);
-
-    open_max = getdtablesize();
-    if (tofd < 0 || tofd >= open_max)
+    case F_DUPFD:
     {
-      errno = EINVAL;
-      return -1;
+      va_start(ap, cmd);
+      tofd = va_arg(ap, int);
+      va_end(ap);
+
+
+      open_max = getdtablesize();
+      while (tofd < open_max)
+      {
+        /* If unable to get the device info for the handle,
+           then the handle is not active and it can be used.  */
+        if (_get_dev_info(tofd) == -1)
+          break;
+        tofd++;
+      }
+
+
+      if (tofd >= open_max)
+      {
+        errno = EMFILE;
+        return -1;
+      }
+
+
+      errno = errno_save;
+      return dup2(fd, tofd);
     }
-    while (tofd < open_max)
+
+
+    case F_GETFD:
     {
-      if (! is_used_fd(tofd))
-	break;
-      tofd++;
+       unsigned long entry_ptr;
+
+
+      /* DOS only passes the first 20 handles to child programs.  In
+         addition, handles 19 and 18 will be closed by the stub of the
+         child program (if it is a DJGPP program).  */
+
+
+      if (fd >= 18)
+        return FD_CLOEXEC;
+
+
+      /* Determine if the documented interface will allow twiddling with
+         the inherit bit. If not, fallback to the undocumented one.  */
+      if (inherit_bit_visible == -1)
+        inherit_bit_visible = inherit_bit_test (fd, dev_info);
+
+      if (!inherit_bit_visible)
+      {
+        entry_ptr = _get_sft_entry_ptr(fd);
+        if (entry_ptr == 0)
+        {
+          /* The fd has already been validated, so reaching here means
+             something is wrong with _get_sft_entry_ptr. */
+          return -1;
+        }
+        /* Offset 5 in the SFT contains the device info word.  */
+        dev_info = _farpeekw(_dos_ds, entry_ptr + 5);
+      }
+      return (dev_info & _DEV_NO_INHERIT) ? FD_CLOEXEC : 0;
     }
 
-    if (tofd >= open_max)
+
+    case F_SETFD:
     {
-      errno = EMFILE;
-      return -1;
+      unsigned int flag;
+      unsigned long entry_ptr = 0; /* shut up -Wall */
+      __dpmi_regs regs;
+
+
+      va_start (ap, cmd);
+      flag = va_arg(ap, int);
+      va_end(ap);
+
+
+      /* DOS only passes the first 20 handles to child programs.  In
+         addition, handles 19 and 18 will be closed by the stub of the
+         child program (if it is a DJGPP program).  */
+      if (fd >= 18)
+      {
+        if (flag & FD_CLOEXEC)
+          return 0;
+        else
+        {
+          errno = ENOSYS;
+          return -1;
+        }
+      }
+
+
+      /* Determine if the documented interface will allow twiddling with
+         the inherit bit. If not, fallback to the undocumented one.  */
+      if (inherit_bit_visible == -1)
+        inherit_bit_visible = inherit_bit_test(fd, dev_info);
+
+      if (!inherit_bit_visible)
+      {
+        entry_ptr = _get_sft_entry_ptr(fd);
+        if (entry_ptr == 0)
+        {
+          /* The fd has already been validated, so reaching here means
+             something is wrong with _get_sft_entry_ptr. */
+          return -1;
+        }
+
+
+        dev_info = _farpeekw(_dos_ds, entry_ptr + 5);
+      }
+
+
+      if (flag & FD_CLOEXEC)
+        dev_info |= _DEV_NO_INHERIT;
+      else
+        dev_info &= ~(_DEV_NO_INHERIT);
+
+
+      if (inherit_bit_visible)
+      {
+        regs.x.ax = 0x4401;
+        regs.x.bx = fd;
+        regs.x.dx = dev_info;
+        __dpmi_int(0x21, &regs);
+      }
+      else
+        _farpokew(_dos_ds, entry_ptr + 5, dev_info);
+
+
+      return 0;
     }
 
-    return dup2(fd, tofd);
-    
-  case F_GETFD:
-    /* DOS only passes the first 20 handles to child programs.  In
-       addition, handles 19 and 18 will be closed by the stub of the
-       child program (if it is a DJGPP program).
 
-       FIXME: we should look at the no-inherit bit stashed in the SFT
-       entry pointed to by the handle, since some of the first 18
-       handles could have been opened with a no-inherit bit.  */
-    return fd >= 18 ? FD_CLOEXEC : 0;
-  case F_SETFD:
-    if ((fd < 18) ^ ((cmd & FD_CLOEXEC) != 0))
+    case F_GETFL:
+    {
       return 0;
-    else
+    }
+
+
+    case F_SETFL:
+    {
+      unsigned char new_mode_bits;
+
+
+      va_start (ap, cmd);
+      new_mode_bits = va_arg(ap,int);
+      va_end(ap);
+
+
+      /* Allow removal of O_NONBLOCK, since DJGPP doesn't support it
+         anyway.  */
+      return (new_mode_bits == 0) ? 0 : -1;
+    }
+
+
+    case F_GETLK:
+    case F_SETLK:
+    case F_SETLKW:
+    {
+      struct flock *lock_req = NULL; /* shut up -Wall */
+      int ret = -1;
+      off_t pos, cur_pos, lock_pos;
+      off_t len;
+
+      /* First check if SHARE is loaded */
+      ret = _get_SHARE_status();
+
+      if (!ret) /* Then SHARE is NOT loaded, just return success */
+      {
+        if (cmd == F_GETLK) /* Then make believe the lock is available */
+          lock_req->l_type = F_UNLCK;
+
+        return ret;
+      }
+      else ret = -1; /* Restore default value */
+
+      cur_pos = lseek(fd, 0, SEEK_CUR);
+      if (cur_pos < 0)
+        return -1;      /* Assumes lseek has set errno */
+
+      va_start (ap, cmd);
+      lock_req = va_arg(ap, struct flock *);
+      va_end (ap);
+
+      lock_pos = lseek (fd, lock_req->l_start, lock_req->l_whence);
+      if (lock_pos < 0)
+        return -1;      /* Assumes lseek has set errno */
+
+      len = lock_req->l_len;
+
+
+      /* If l_len is zero, then the lock is to be set from l_start
+         until the end-of-file. */
+      if (len == 0)
+      {
+        len = filelength(fd) - cur_pos;
+        /* This should probably be an error.  */
+        if (len <= 0)
+          len = 1;
+      }
+
+
+      ret = lseek (fd, cur_pos, SEEK_SET);
+      if (ret < 0)
+        return -1;      /* Assumes lseek has set errno */
+      else ret = -1;    /* Restore default value */
+
+
+      /* If l_len is positive, the area to lock is from l_start
+         to l_start + l_len - 1. If l_len is negative, the area to lock is
+         from l_start + len to l_start - 1.  */
+      if (len > 0)
+      {
+        pos = lock_pos;
+      }
+      else
+      {
+        pos = lock_pos + len;
+        len = -lock_req->l_len;
+      }
+
+
+      /* DOS/Win9x only support write locks via int 21/5C, so
+         all read lock requests are treated like write locks
+      */
+
+      if (lock_req->l_type == F_UNLCK)
+      {
+        ret = _dos_unlock(fd, pos, len);
+        if (ret != 0)
+        {
+          _doserrno = ret;
+          errno = __doserr_to_errno(ret);
+          return -1;
+        }
+      }
+      else if ((lock_req->l_type == F_WRLCK) || (lock_req->l_type == F_RDLCK))
+      {
+        ret = _dos_lock(fd, pos, len);
+        if (cmd == F_GETLK)
+        {
+          if (ret == 0)
+          {
+            _dos_unlock(fd, pos, len);
+            /* If no lock is found that would prevent a lock from
+               being created, the lock type is set to F_UNLCK.  */
+            lock_req->l_type = F_UNLCK;
+          }
+          else
+          {
+            /* If a lock is found then l_whence, l_start, and l_len
+               should point to the area covered by the lock. But the
+               file locking interface doesn't report where the
+               existing lock is, so nothing more can be done.  */
+            _doserrno = ret;
+            errno = __doserr_to_errno(ret);
+            return -1;
+          }
+        }
+        else
+        {
+          /* If F_SETLKW is set, wait for the lock to be released.  */
+          if (cmd == F_SETLKW && ret != 0)
+          {
+            while ((ret = _dos_lock(fd, pos, len)) != 0)
+              __dpmi_yield();
+          }
+          else if (ret != 0)
+          {
+            _doserrno = ret;
+            errno = __doserr_to_errno(ret);
+            return -1;
+          }
+        }
+      }
+      if (ret != 0)
+        errno = ENOSYS;
+
+
+      return ret;
+    }
+
+
+    case F_GETLK64:
+    case F_SETLK64:
+    case F_SETLKW64:
+    {
+      struct flock64 *lock_req = NULL; /* shut up -Wall */
+      int ret = -1;
+      long long int ret64 = -1L;
+      offset_t pos, cur_pos, lock_pos;
+      offset_t len;
+
+      /* First check if SHARE is loaded */
+      ret = _get_SHARE_status();
+
+      if (!ret) /* Then SHARE is NOT loaded, just return success */
+      {
+        if (cmd == F_GETLK64) /* Then make believe the lock is available */
+          lock_req->l_type = F_UNLCK;
+
+        return ret;
+      }
+      else ret = -1; /* Restore default value */
+
+      cur_pos = llseek(fd, 0L, SEEK_CUR);
+      if (cur_pos < 0)
+        return -1;      /* Assumes lseek has set errno */
+
+      va_start (ap, cmd);
+      lock_req = va_arg(ap, struct flock64 *);
+      va_end (ap);
+
+      lock_pos = llseek (fd, lock_req->l_start, lock_req->l_whence);
+      if (lock_pos < 0)
+        return -1;      /* Assumes lseek has set errno */
+
+      len = lock_req->l_len;
+
+
+      /* If l_len is zero, then the lock is to be set from l_start
+         until the end-of-file. */
+      if (len == 0L)
       {
-	errno = ENOSYS;
-	return -1;
+        len = filelength(fd) - cur_pos;
+        /* This should probably be an error.  */
+        if (len <= 0L)
+          len = 1L;
       }
-  case F_GETFL:
-    return 0;	/* FIXME: should use the data in the SFT */
-  case F_SETFL:
-    errno = ENOSYS;
-    return -1;
-  case F_GETLK:
-  case F_SETLK:
-  case F_SETLKW:
-    errno = ENOSYS;
-    return -1;
+
+
+      ret64 = llseek (fd, cur_pos, SEEK_SET);
+      if (ret64 < 0L)
+        return -1;      /* Assumes lseek has set errno */
+      else
+        ret64 = -1;     /* Restore default value */
+
+
+      /* If l_len is positive, the area to lock is from l_start
+         to l_start + l_len - 1. If l_len is negative, the area to lock is
+         from l_start + len to l_start - 1.  */
+      if (len > 0L)
+      {
+        pos = lock_pos;
+      }
+      else
+      {
+        pos = lock_pos + len;
+        len = -lock_req->l_len;
+      }
+
+
+      /* DOS/Win9x only support write locks via int 21/5C, so
+         all read lock requests are treated like write locks
+      */
+
+      if (lock_req->l_type == F_UNLCK)
+      {
+        ret = _dos_unlk64(fd, pos, len);
+        if (ret != 0)
+        {
+          _doserrno = ret;
+          errno = __doserr_to_errno(ret);
+          return -1;
+        }
+      }
+      else if ((lock_req->l_type == F_WRLCK) || (lock_req->l_type == F_RDLCK))
+      {
+        ret = _dos_lk64(fd, pos, len);
+        if (cmd == F_GETLK64)
+        {
+          if (ret == 0)
+          {
+            _dos_unlk64(fd, pos, len);
+            /* If no lock is found that would prevent a lock from
+               being created, the lock type is set to F_UNLCK.  */
+            lock_req->l_type = F_UNLCK;
+          }
+          else
+          {
+            /* If a lock is found then l_whence, l_start, and l_len
+               should point to the area covered by the lock. But the
+               file locking interface doesn't report where the
+               existing lock is, so nothing more can be done.  */
+            _doserrno = ret;
+            errno = __doserr_to_errno(ret);
+            return -1;
+          }
+        }
+        else
+        {
+          /* If F_SETLKW64 is set, wait for the lock to be released.  */
+          if (cmd == F_SETLKW64 && ret != 0)
+          {
+            while ((ret = _dos_lk64(fd, pos, len)) != 0)
+              __dpmi_yield();
+          }
+          else if (ret != 0)
+          {
+            _doserrno = ret;
+            errno = __doserr_to_errno(ret);
+            return -1;
+          }
+        }
+      }
+      if (ret != 0)
+        errno = ENOSYS;
+
+
+      return ret;
+    }
   }
+
+
+  /* In case fcntl is called with an unrecognized command.  */
   errno = ENOSYS;
   return -1;
 }
diff -ruN djgpp-cvs/src/libc/posix/fcntl/fcntl.txh djgpp/src/libc/posix/fcntl/fcntl.txh
--- djgpp-cvs/src/libc/posix/fcntl/fcntl.txh	Thu Jun  3 02:35:56 1999
+++ djgpp/src/libc/posix/fcntl/fcntl.txh	Mon Dec 11 20:10:04 2000
@@ -31,19 +31,33 @@
 stub loader of the child DJGPP program will forcibly close handles 19
 and 18 (since otherwise it will be unable to read the COFF executable
 information and enter protected mode).  Therefore, the current
-implementation always returns 0 for handles below 18, meaning that all
-those handles are inherited, and @code{FD_CLOEXEC} for handles 18 and
+implementation always returns @code{FD_CLOEXEC} for handles 18 and
 above.
 
-The no-inherit bit can be set when the file is open, by using the
+For handles less than 18, the call will try to determine the status of
+the @code{O_NOINHERIT} flag for that file and will return either
+@code{FD_CLOEXEC} if the flag is set, or 0 if the flag is not set.  If
+the status of the @code{O_NOINHERIT} flag cannot be determined, the call
+will return -1, setting @code{errno} to @code{ENOSYS}.
+
+The no-inherit bit can be set when the file is opened by using the
 @code{O_NOINHERIT} in the open flags; see @ref{open}.
 
 @item F_SETFD
-Set the close-on-exec flag for the handle @var{fd} using the LSB of the
-integer value supplied as the third argument.  Currently, @code{fcntl}
-always fails this call and sets @code{errno} to @code{ENOSYS}, since
-DOS/Windows don't support changing the no-inherit status of an open
-file.
+Set or unset the close-on-exec flag for the handle @var{fd} using the
+LSB of the integer value supplied as the third argument.  Since only the
+first 20 handles are passed to child programs, and since the stub loader
+of the child DJGPP program will forcibly close handles 19 and 18 (since
+otherwise it will be unable to read the COFF executable information and
+enter protected mode), the flag can only be set or unset on the first 18
+handles.  Attempts to set the flag for handles 18 or above will always
+return 0, and attempts to unset the flag for handles 18 or above will
+always return -1, setting @code{errno} to @code{ENOSYS}.
+
+For handles less than 18, the call will try to set or unset the
+@code{O_NOINHERIT} flag for that file and will return 0 if the flag is
+changed.  If the @code{O_NOINHERIT} flag cannot be changed, the call
+will return -1, setting @code{errno} to @code{ENOSYS}.
 
 @item F_GETFL
 Get the open mode and status flags associated with the handle @var{fd}.
@@ -53,23 +67,55 @@
 
 @item F_SETFL
 Set the open mode and status flags associated with the handle @var{fd}.
-This always fails and sets @code{errno} to @code{ENOSYS}, since DOS and
-Windows don't allow to change the descriptor flags after the file is
-open.
+This fails in all but one case, and sets @code{errno} to @code{ENOSYS},
+since DOS and Windows don't allow changing the descriptor flags after
+the file is open.
+
+The one allowed case is for @code{O_NONBLOCK}, since DJGPP doesn't
+support it anyway.  That is, calls using @code{F_SETFL} will fail for
+all flag values @strong{except} @code{O_NONBLOCK}.
+
+@example
+#include <fcntl.h>
+
+ret = fcntl (fd, F_SETFL, O_BINARY); /* This will fail, returning -1 */
+                                     /* and setting errno to ENOSYS  */
+
+ret = fcntl (fd, F_SETFL, O_NONBLOCK); /* This will succeed          */
+                                       /* returning 0                */
+@end example
 
 @item F_GETLK
-Get a description of a file segment lock as specified in the structure
-pointed to by the third argument.  This is unsupported and will always
-fail.
+Return the lock structure that prevents obtaining the lock pointed to by
+the third argument, or set the @code{l_type} field of the lock structure
+to @code{F_UNLCK} if there is no obstruction.  Currently, only the
+setting of the @code{l_type} field is provided.  This call will not
+return values in the @code{struct flock} parameter identifying what lock
+parameters prevent getting the requested lock, since there is no way to
+obtain this information from DOS/Windows.  If the lock cannot be
+obtained, -1 is returned and @code{errno} is set to the reason (which
+will be one of @code{EINVAL}, @code{EBADF}, @code{EACCES} or
+@code{ENOLCK}).
 
 @item F_SETLK
 Set or clear a file segment lock according to the structure pointed to
-by the third argument.  This is unsupported and will always fail.
+by the third argument.  The lock is set when @code{l_type} is
+@code{F_RDLCK} (shared lock request) or @code{F_WRLCK} (exclusive lock
+request), and the lock is cleared when @code{l_type} is @code{F_UNLCK}.
+If the lock is already held, then this call returns -1 and sets
+@code{errno} to @code{EACCES}.
+
+The @code{F_RDLCK} value for requesting a read lock is always treated as
+if it were @code{F_WRLCK} for a write lock.
+
+This is because DOS/Win9x only supports one kind of lock, and it is the
+exclusive kind.
 
 @item F_SETLKW
 Same as @code{F_SETLK}, but if the lock is blocked, the call will wait
-until it is unblocked and the lock can be applied.  This is unsupported
-and will always fail.
+(using @code{__dpmi_yield}, see @pxref{__dpmi_yield}) until it is
+unblocked and the lock can be applied.  This call will never exit if the
+program making the call is program which already owns the lock.
 @end table
 
 This function can be hooked by the @dfn{Filesystem extensions}, see
@@ -99,4 +145,46 @@
  /* Save the handle in a way that it won't be passed
     to child processes.  */
   int saved_fd = fcntl (fd, F_DUPFD, 20);
+
+ /* Set an advisory lock for the whole file */
+  struct flock flock;
+  int retval, fd;
+
+  flock.l_type = F_RDLCK;
+  flock.l_whence = SEEK_SET;
+  flock.l_start = flock.l_len = 0;
+  errno = 0;
+  retval = fcntl(fd, F_SETLK, &flock);
+
+ /* Get the status of the lock we just obtained
+    (should return -1 with errno == EACCES) */
+  errno = 0;
+  retval = fcntl(fd, F_GETLK, &flock);
+
+ /* Release the lock */
+  errno = 0;
+  flock.l_type = F_UNLCK;
+  retval = fcntl(fd, F_SETLK, &flock);
+
+ /* Get the status of the lock we just released
+    (should return 0) */
+  errno = 0;
+  flock.l_type = F_RDLCK;
+  retval = fcntl(fd, F_GETLK, &flock);
+
+ /* Try to set the O_BINARY flag on the open file
+    (should return -1 with errno == ENOSYS) */
+  errno = 0;
+  retval = fcntl(fd, F_SETFL, O_BINARY);
+
+ /* Set the O_NONBLOCK flag on the open file
+    (should return 0) */
+  errno = 0;
+  retval = fcntl(fd, F_SETFL, O_NONBLOCK);
+
+ /* Get the flags on the open file
+    (always returns 0) */
+  errno = 0;
+  retval = fcntl(fd, F_GETFL);
+
 @end example
diff -ruN djgpp-cvs/src/libc/posix/sys/file/flock.c djgpp/src/libc/posix/sys/file/flock.c
--- djgpp-cvs/src/libc/posix/sys/file/flock.c	Thu Jan  1 00:00:00 1970
+++ djgpp/src/libc/posix/sys/file/flock.c	Sat Nov 25 23:57:40 2000
@@ -0,0 +1,38 @@
+/* Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details */
+
+/* This file implements the `flock' function in terms of the POSIX.1 `fcntl'
+   locking mechanism.  */
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/file.h>
+
+/* Apply or remove an advisory lock, according to OPERATION,
+   on the file FD refers to.  */
+int
+flock (int _fildes, int _op)
+{
+  struct flock lock_req;
+
+  switch (_op & ~LOCK_NB)
+    {
+    case LOCK_SH:
+      lock_req.l_type = F_RDLCK;
+      break;
+    case LOCK_EX:
+      lock_req.l_type = F_WRLCK;
+      break;
+    case LOCK_UN:
+      lock_req.l_type = F_UNLCK;
+      break;
+    default:
+      errno = EINVAL;
+      return -1;
+    }
+
+  lock_req.l_whence = SEEK_SET;
+  lock_req.l_start = lock_req.l_len = 0L; /* Lock the whole file.  */
+
+  return fcntl (_fildes, (_op & LOCK_NB) ? F_SETLK : F_SETLKW, &lock_req);
+}
diff -ruN djgpp-cvs/src/libc/posix/sys/file/flock.txh djgpp/src/libc/posix/sys/file/flock.txh
--- djgpp-cvs/src/libc/posix/sys/file/flock.txh	Thu Jan  1 00:00:00 1970
+++ djgpp/src/libc/posix/sys/file/flock.txh	Mon Dec 11 20:55:46 2000
@@ -0,0 +1,89 @@
+@node flock, sys
+@subheading Syntax
+
+@example
+#include <sys/file.h>
+
+int flock (int _fildes, int _op);
+@end example
+
+@subheading Description
+
+Apply or remove an advisory lock on an open file. The file is specified
+by file handle @var{_fildes}. Valid operations are given below:
+
+@table @code
+@item LOCK_SH
+Shared lock.  More than one process may hold a shared lock for a given
+file at a given time.
+
+However, all locks on DOS/Win9x are exclusive locks, so @code{LOCK_SH}
+requests are treated as if they were @code{LOCK_EX} requests.
+
+@item LOCK_EX
+Exclusive lock.  Only one process may hold an exclusive lock for a given
+file at a given time.
+
+@item LOCK_UN
+Unlock the file.
+
+@item LOCK_NB
+Don't block when locking. May be specified (by or'ing) along with one of
+the other operations.
+@end table
+
+On other systems, a single file may not simultaneously have both shared
+and exclusive locks.  However, on DOS/Win9x, all locks are exclusive
+locks, so this rule is not true for DOS/Win9x.
+
+A file is locked, not the file descriptor.  So, dup (2) does not create
+multiple instances of a lock.
+
+Dos/Win9x does not support shared locks, but the underlying
+implementation (which uses the @code{F_SETLK} (non-blocking) or
+@code{F_SETLKW} (blocking) commands to @code{fcntl}, see @ref{fcntl})
+translates all shared lock request into exclusive lock requests.  Thus,
+requests for shared locks will be treated as if exclusive locks were
+requested, and only one lock will ever be permitted at any one time on
+any specified region of the file.
+
+It is therefore wise to code @code{flock} by or'ing @code{LOCK_NB} with
+all lock requests, whether shared or exclusive, and to test the return
+value to determine if the lock was obtained or not.  Using
+@code{LOCK_NB} will cause the implementation to use @code{F_SETLK}
+instead of @code{F_SETLKW}, which will return an error if the lock
+cannot be obtained.
+
+@subheading Return Value
+
+On success, zero is returned.  On error, -1 is returned, and
+@code{errno} is set appropriately.
+
+@subheading Portability
+
+@port-note posix 4.4BSD (the flock (2) call first appeared in 4.2BSD).
+@portability !ansi, posix
+
+@subheading Example
+
+@example
+ /* Request a shared lock on file handle fd */
+  errno = 0;
+  retval = flock(fd, LOCK_SH);
+
+ /* Request a non-blocking shared lock on file handle fd */
+  errno = 0;
+  retval = flock(fd, LOCK_SH | LOCK_NB);
+
+ /* Request an exclusive lock on file handle fd */
+  errno = 0;
+  retval = flock(fd, LOCK_EX);
+
+ /* Request a non-blocking exclusive lock on file handle fd */
+  errno = 0;
+  retval = flock(fd, LOCK_EX | LOCK_NB);
+
+ /* Release a lock on file handle fd */
+  errno = 0;
+  retval = flock(fd, LOCK_UN);
+@end example
diff -ruN djgpp-cvs/src/libc/posix/sys/file/makefile djgpp/src/libc/posix/sys/file/makefile
--- djgpp-cvs/src/libc/posix/sys/file/makefile	Thu Jan  1 00:00:00 1970
+++ djgpp/src/libc/posix/sys/file/makefile	Sun Nov 26 00:28:40 2000
@@ -0,0 +1,6 @@
+# Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details
+TOP=../../..
+
+SRC += flock.c
+
+include $(TOP)/../makefile.inc
diff -ruN djgpp-cvs/src/makefile.inc djgpp/src/makefile.inc
--- djgpp-cvs/src/makefile.inc	Mon Sep  7 14:12:10 1998
+++ djgpp/src/makefile.inc	Sat Nov 25 18:09:08 2000
@@ -1,3 +1,4 @@
+# Copyright (C) 2000 DJ Delorie, see COPYING.DJ for details
 # Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details
 # -*- makefile -*-
 
@@ -7,12 +8,58 @@
 
 .SUFFIXES: .o .i .c .cc .s
 
+# Set $(GCC{L}_OPT) here so they are defined before first use
+#
+ifeq ($(CROSS_BUILD),1)
+GCC_OPT := $(shell cat $(TOP)/../gcc.opt)
+GCCL_OPT := $(shell cat $(TOP)/../gcc-l.opt)
+endif
+
+# Set $(AS) before first use
+#
+AS := $(shell $(CROSS_GCC) $(GCC_OPT) -print-prog-name=as)
+AS := $(subst \,/,$(AS))
+
+# These were suggested by Tim Van Holder <tim DOT van DOT holder AT pandora DOT be>
+# but since $(CROSS_LD) is set in makefile.def and $(LD) is not used
+# anywhere, they seem not very useful at this time.
+#
+#LD := $(shell $(CROSS_GCC) $(GCC_OPT) -print-prog-name=ld)
+#LD := $(subst \,/,$(LD))
+
+# Figure out GAS version for use in *.S and inline asm compile flags
+#
+GAS_VERSION    := $(subst ., ,$(shell $(AS) --version))
+GAS_MAJOR      := $(word 3,$(GAS_VERSION))
+GAS_MINOR      := $(word 4,$(GAS_VERSION))
+GAS_MINORMINOR := $(word 5,$(GAS_VERSION))
+
+# Defaults for GAS version numbers
+ifeq ($(GAS_MAJOR),)
+GAS_MAJOR := 0
+endif
+ifeq ($(GAS_MINOR),)
+GAS_MINOR := 0
+endif
+ifeq ($(GAS_MINORMINOR),)
+GAS_MINORMINOR := 0
+endif
+
+# Pass defines as compiler/assembler switches
+CFLAGS += -DGAS_MAJOR=$(GAS_MAJOR)
+CFLAGS += -DGAS_MINOR=$(GAS_MINOR)
+CFLAGS += -DGAS_MINORMINOR=$(GAS_MINORMINOR)
+
+ASFLAGS += -DGAS_MAJOR=$(GAS_MAJOR)
+ASFLAGS += -DGAS_MINOR=$(GAS_MINOR)
+ASFLAGS += -DGAS_MINORMINOR=$(GAS_MINORMINOR)
+
+# Moved setting of $(GCC{L}_OPT) to top of file
+#
 ifneq ($(CROSS_BUILD),1)
 XGCC = $(CROSS_GCC) @$(TOP)/../gcc.opt -I. -I- -I$(TOP)/../../include $(CFLAGS)
 XLGCC = $(CROSS_GCC) -s @$(TOP)/../gcc-l.opt -I. -I- -I$(TOP)/../../include $(CFLAGS)
 else
-GCC_OPT := $(shell cat $(TOP)/../gcc.opt)
-GCCL_OPT := $(shell cat $(TOP)/../gcc-l.opt)
 XGCC = $(CROSS_GCC) $(GCC_OPT) -I. -I- -I$(TOP)/../../include $(CFLAGS)
 XLGCC = $(CROSS_GCC) $(GCCL_OPT) -I. -I- -I$(TOP)/../../include $(CFLAGS)
 endif
@@ -59,13 +106,13 @@
 L = $(LIB)/libc.a
 
 ifeq ($(LIBGCCA),)
-LIBGCCA := $(shell $(CROSS_GCC) -print-file-name=libgcc.a)
+LIBGCCA := $(shell $(CROSS_GCC) $(GCC_OPT) -print-file-name=libgcc.a)
 LIBGCCA := $(subst \,/,$(LIBGCCA))
 export LIBGCCA
 endif
 
 ifeq ($(DJGPP_DJL),)
-DJGPP_DJL := $(shell $(CROSS_GCC) -print-file-name=djgpp.djl)
+DJGPP_DJL := $(shell $(CROSS_GCC) $(GCC_OPT) -print-file-name=djgpp.djl)
 DJGPP_DJL := $(subst \,/,$(DJGPP_DJL))
 export DJGPP_DJL
 endif

--=====================_4043618==_
Content-Type: text/plain; charset="us-ascii"; format=flowed

---------------------------------------------------------
Peter J. Farley III (pjfarley AT dorsai DOT org OR
                      pjfarley AT banet DOT net)
--=====================_4043618==_--

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019