[comp.sys.atari.st] patch for MiNT library

7103_2622@uwovax.uwo.ca (Eric Smith) (10/03/90)

The MiNT library mintlib.zoo on atari.archive (at patchlevel 1) has some
bugs in it -- in particular, stat.c and unx2dos.c won't compile, as the
result of a last minute cleanup that didn't quite clean everything up.
(A header file, device.h, was removed; neither of the .c files actually used
anything from that header, but they did include it, and stat() had a useless
device declaration in it as well).

Here are patches to bring the library up to patchlevel 2. As well as fixing
the compilation bug some new features are provided:

-- some new dummy routines added to avoid link-time errors
-- popen() re-written to use pipes instead of temporary files; this is
   a win under MiNT, but doesn't work under TOS. Ideally we should
   support both, but the library is big enough already :-(.
-- stat() and fstat() now give pipes and fifos a file type of S_IFIFO
-- fstat() was broken in several ways; it should be OK now
-- the assert() macro had the wrong parameter names (oops!)
-- osbind.h was being overly optimistic about the future development of
   MiNT; it seems unlikely that >14 character file names will be supported
   in the near future, so we might as well maintain 100% TOS compatibility
   here
-- re-arranged compiler.h a bit, and added support for the C68 compiler

I haven't uploaded the new library to atari.archive, because I'm still
working on the C68 support (the GNU code should be quite stable now).

Please report bugs to the address at the bottom of this posting.
=========================== cut here =====================================
*** lib/orig/link.c	Fri Apr 27 18:10:08 1990
--- lib/link.c	Mon Oct  1 20:27:24 1990
***************
*** 1,8 ****
  #include <errno.h>
  
  int
  link()
  {
! 	errno=EXDEV;
  	return -1;
  }
--- 1,27 ----
  #include <errno.h>
  
+ /*
+  * try to choose failure modes that applications will best be able to
+  * handle
+  */
+ 
  int
  link()
  {
! 	errno = EXDEV;
! 	return -1;
! }
! 
! int
! symlink()
! {
! 	errno = EUNCMD;
! 	return -1;
! }
! 
! int
! readlink()
! {
! 	errno = 0;	/* should never happen */
  	return -1;
  }
*** lib/orig/patchlev.h	Sat Sep 29 01:46:36 1990
--- lib/patchlev.h	Mon Oct  1 20:48:16 1990
***************
*** 1,5 ****
  /*
!  *	PatchLevel: 1
   *
   *	This identifies the version of the MiNT library in this
   *	directory.
--- 1,5 ----
  /*
!  *	PatchLevel: 2
   *
   *	This identifies the version of the MiNT library in this
   *	directory.
*** lib/orig/popen.c	Thu Sep  6 13:55:58 1990
--- lib/popen.c	Tue Oct  2 20:45:02 1990
***************
*** 1,109 ****
! /* popen.c
!  *
!  * Implementation of popen() / pclose for Atari ST (will eventually work for
!  * MSDOS too). The pipe is simulated by a temporary file. If caller wants to
!  * read the pipe, then execute the command in popen and return a descriptor
!  * to the output delivered by the command. If caller wants to write to the
!  * pipe, then preserve the callers output in a temp file and execute the
!  * command on pclose.
!  * Since it is necessary to keep some information from popen() up to the
!  * pclose(), we keep all opened pipes in a list and fill up the entries as
!  * needed. Pipes are identified by their FILE descriptor returned from the
!  * fopen() call.
!  *
!  * Revision 1.2, jrb 08-15-89	applied kai's diffs
!  *	gcc-lib's system() now does re-direction. Changes to
!  *	for re-direction stuff because of this.
!  *
!  * Revision 1.1, kub 05-23-89
!  * written 89/05/23 by Kai-Uwe Bloem (I5110401@DBSTU1.BITNET for now)
   */
  
  #include	<stdio.h>
! #include	<memory.h>
  #include	<fcntl.h>
  #include	<string.h>
  
  struct _pipe {
! 	char	pmode;		/* "r" or "w" to/from the pipe ?	*/
! 	char	*pcommand;	/* cmd to execute (only for "w")	*/
! 	int	pstat;		/* exit code of cmd (only for "r")	*/
! 	char	pname[20];	/* temp filename. 20 should be enough...*/
! 	FILE	*pfile;		/* pipe identifier			*/
  	struct _pipe	*pnext;	/* next pipe in the list.		*/
! 	};
  
  static struct _pipe	*__pipes = NULL;	/* head of pipe list	*/
  
- static char		ptmp[] = "pipeXXXX";	/* skeleton for temp filename */
- 
- /* open a pipe to the command argument in the mode given by the type string.
-  * If caller wants to read the pipe, redirect output and execute command,
-  * then open the temp file and return that. If caller wants to write to
-  * the pipe, create the temp file and return that.
-  */
  FILE *popen(command, type)
  const char	*command, *type;
  {
  	struct _pipe *p;	/* the new pipe's list entry	*/
  
  	/* get space for the new pipe. If we can't get it then that's that */
  	p = (struct _pipe *) malloc(sizeof(struct _pipe));
! 	if (p == NULL) return (FILE *) NULL;
  
  	/* initialize the new pipe entry */
! 	p->pmode = *type;
! 	p->pfile = (FILE *) NULL;
! 	strcpy(p->pname,ptmp);
! 	mktemp(p->pname);
! 	/* make command line with appropriate re-direction */
! 	if((p->pcommand = (char *)malloc(strlen(command)+strlen(ptmp)+4L))
! 		== (char *)NULL)
! 	{	/* no  mem */
  		free(p);
! 		return (FILE *)NULL;
  	}
! 	strcpy(p->pcommand, command);
! 	strcat(p->pcommand, (p->pmode == 'r')? " >" : " <");
! 	strcat(p->pcommand, p->pname);
  
! 	/* Everything has now been set up to really execute the pipe request */
! 	switch(p->pmode)
! 	{
! 	case 'r':	/* reading */
! 		/* execute the command, output redir. to tmp pipe file */
! 		p->pstat = system(p->pcommand);
! 		if (p->pstat < 0) {
! 			unlink(p->pname);
! 			return (FILE *)NULL;
! 		}
! 		p->pfile = fopen(p->pname,"r");	/* now open the pipe	*/
! 		break;
! 	case 'w':	/* writing */
! 		/* open tmp pipe file */
! 		p->pfile = fopen(p->pname,"w"); /* open the pipe file	*/
! 		break;
  	}
  
! 	if (p->pfile)
! 	{	/* pipe successfully established. Link it to the list	*/
  		p->pnext = __pipes;
  		__pipes = p;
- 		return p->pfile;
  	}
! 	else
! 	{	/* if there is no pipe identifier then throw it away	*/
! 		unlink(p->pname);
! 		free(p->pcommand);
  		free(p);
- 		return (FILE *) NULL;
  	}
  }
  
! /* close a pipe created by popen(). If caller wanted to read the pipe, then
!  * just do the cleanup and return the command's status code. If caller wanted
!  * to write to the pipe, the work has just started. Close the tempfile, call
!  * the command with input redirected to the temp file and cleanup after that.
   */
  int pclose(fp)
  FILE	*fp;
--- 1,81 ----
! /* popen(): open a file handle to a process. Works only under MiNT.
!  * Written by Eric R. Smith, based on the TOS version by Kai-Uwe Bloem.
   */
  
  #include	<stdio.h>
! #include	<stdlib.h>
! #include	<process.h>
  #include	<fcntl.h>
  #include	<string.h>
+ #include	<errno.h>
  
  struct _pipe {
! 	int	pid;		/* process id of child			*/
! 	FILE	*pfile;		/* created file descriptor		*/
  	struct _pipe	*pnext;	/* next pipe in the list.		*/
! };
  
  static struct _pipe	*__pipes = NULL;	/* head of pipe list	*/
  
  FILE *popen(command, type)
  const char	*command, *type;
  {
  	struct _pipe *p;	/* the new pipe's list entry	*/
+ 	int pipfd[2];		/* pipe file handles */
+ 	int savefd;		/* saved file descriptor for parent */
+ 	int kidfd;		/* file descriptor changed in child */
+ 				/* 1 for "r", 0 for "w" */	
+ 
+ 	char *shell;
+ 	FILE *pipefile = 0;
+ 	extern int __mint;
+ 
+ 	if (__mint == 0) {
+ 		errno = EINVAL;
+ 		return (FILE *)0;
+ 	}
+ 
+ 	shell = getenv("SHELL");
+ 	if (!shell)
+ 		shell = "sh";
  
  	/* get space for the new pipe. If we can't get it then that's that */
  	p = (struct _pipe *) malloc(sizeof(struct _pipe));
! 	if (p == NULL) return (FILE *)0;
  
  	/* initialize the new pipe entry */
! 	kidfd = (*type == 'r') ? 1 : 0;
! 
! 	savefd = dup(kidfd);
! 
! 	if (savefd < 0 || pipe(pipfd) != 0) {	/* can't create pipe?? */
  		free(p);
! 		return (FILE *)0;
  	}
! 
! 	dup2(pipfd[kidfd], kidfd);
! 	close(pipfd[kidfd]);
! 	p->pid = spawnlp(P_NOWAIT, shell, shell, "-c", command, (char *)0);
! 	dup2(savefd, kidfd);
! 	close(savefd);
  
! 	if (p->pid > 0) {	/* command ran all right */
! 	/* note: 1-kidfd tells us which handle to use in the parent */
! 		pipefile = fdopen(pipfd[1 - kidfd], type);
  	}
  
! 	if (pipefile) {
! 		p->pfile = pipefile;
  		p->pnext = __pipes;
  		__pipes = p;
  	}
! 	else {
  		free(p);
  	}
+ 	return pipefile;
  }
  
! /* close a pipe created by popen().
   */
  int pclose(fp)
  FILE	*fp;
***************
*** 111,116 ****
--- 83,89 ----
  	struct _pipe	*p,		/* the pipe's list element	*/
  			*q;		/* predecessor of p in the list	*/
  	int	status = -1;		/* return status of the command	*/
+ 	int	pid;
  
  	/* search the pipe list for a pipe matching the FILE descriptor	*/
  	for (p = __pipes, q = NULL;  p && p->pfile != fp;  q = p, p = p->pnext);
***************
*** 117,133 ****
  	if (p == NULL)		/* Never had a popen() for this file...	*/
  		return status;	/* this pclose call makes no sense !	*/
  
! 	fclose(p->pfile);		/* close temp file		*/
! 	switch(p->pmode)
! 	{
! 	case 'w':	/* writing */
! 		status = system(p->pcommand);	/* execute the command	*/
! 		break;
! 	case 'r':	/* reading */
! 		status = p->pstat;	/* just get status code		*/
! 		break;
! 	}
! 	unlink(p->pname);		/* temp file no longer needed	*/
  
  	/* remove the pipe from the list */
  	if (q)	/* not the first in the list, unlink it from previous pipe */
--- 90,102 ----
  	if (p == NULL)		/* Never had a popen() for this file...	*/
  		return status;	/* this pclose call makes no sense !	*/
  
! 	fclose(p->pfile);	/* close the connection		*/
! 
! /* now wait for the command to finish */
! 
! 	do {
! 		pid = wait(&status);
! 	} while (pid >= 0 && pid != p->pid);
  
  	/* remove the pipe from the list */
  	if (q)	/* not the first in the list, unlink it from previous pipe */
***************
*** 136,142 ****
  		__pipes = __pipes->pnext;
  
  	/* Now free the pipe entry */
- 	free(p->pcommand);
  	free(p);
  
  	return status;
--- 105,110 ----
*** lib/orig/stat.c	Wed Sep 26 14:24:28 1990
--- lib/stat.c	Mon Oct  1 20:22:12 1990
***************
*** 15,22 ****
  #include	<osbind.h>
  #include	<string.h>
  #include	<dirent.h>
- #include	<device.h>
  
  ino_t	__inode = 32;		/* used in readdir also */
  int	_x_Bit_set_in_stat = 0;	/* default 0, need change in emacs:sysdep.c */
  
--- 15,23 ----
  #include	<osbind.h>
  #include	<string.h>
  #include	<dirent.h>
  
+ extern int __mint;
+ 
  ino_t	__inode = 32;		/* used in readdir also */
  int	_x_Bit_set_in_stat = 0;	/* default 0, need change in emacs:sysdep.c */
  
***************
*** 33,40 ****
   * need stat() in the near future; plus, opendir did Fsfirst()/Fsnext()
   * already). Programs like "ls" should win big time.
   *
-  * BUG/FEATURE: if the _lHIDE flag is set, opendir() never records the
-  * existence of .dir, and so stat() in an open directory won't find it.
   */
  
  struct dirent *
--- 34,39 ----
***************
*** 103,109 ****
  	int	fd;
  	short	magic;
  	struct dirent *d;
- 	struct _device *device;
  
  	if (!_path) {
  		errno = EFAULT;
--- 102,107 ----
***************
*** 117,123 ****
  	if (nval == 1) {
  		st->st_mode = S_IFCHR | 0600;
  		st->st_attr = 0xfe;
! 		st->st_ino = st->st_rdev = -1;
  		st->st_mtime = st->st_ctime = st->st_atime = 
  			time((time_t *)0) - 2;
  		st->st_dev = 0;
--- 115,122 ----
  	if (nval == 1) {
  		st->st_mode = S_IFCHR | 0600;
  		st->st_attr = 0xfe;
! 		st->st_ino = ++__inode;
! 		st->st_rdev = 0;
  		st->st_mtime = st->st_ctime = st->st_atime = 
  			time((time_t *)0) - 2;
  		st->st_dev = 0;
***************
*** 124,129 ****
--- 123,129 ----
  		st->st_nlink = 1;
  		st->st_uid = geteuid();
  		st->st_gid = getegid();
+ 		st->st_size = st->st_blocks = 0;
  		st->st_blksize = 1024;
  		return 0;
  	}
***************
*** 148,157 ****
  	}
  	st->st_mtime = st->st_ctime = st->st_atime =
  		unixtime(d->d_time, d->d_date);
  	st->st_ino = d->d_ino;
  	st->st_attr = d->d_attribute;
! 	st->st_mode = 0644 | (d->d_attribute & FA_DIR ?
  			      S_IFDIR | 0111 : S_IFREG);
  	if (d->d_attribute & FA_RDONLY)
  		st->st_mode &= ~0222;	/* no write permission */
  	if (d->d_attribute & FA_HIDDEN)
--- 148,167 ----
  	}
  	st->st_mtime = st->st_ctime = st->st_atime =
  		unixtime(d->d_time, d->d_date);
+ 	if ((drv = *path) && path[1] == ':')
+ 		st->st_dev = toupper(drv) - 'A';
+ 	else
+ 		st->st_dev = Dgetdrv();
+ 
  	st->st_ino = d->d_ino;
  	st->st_attr = d->d_attribute;
! 	if (__mint && st->st_dev == ('Q' - 'A'))
! 			st->st_mode = 0644 | S_IFIFO;
! 	else {
! 		st->st_mode = 0644 | (d->d_attribute & FA_DIR ?
  			      S_IFDIR | 0111 : S_IFREG);
+ 	}
+ 
  	if (d->d_attribute & FA_RDONLY)
  		st->st_mode &= ~0222;	/* no write permission */
  	if (d->d_attribute & FA_HIDDEN)
***************
*** 189,198 ****
  	}
  
  fill_rest:
- 	if ((drv = *path) && path[1] == ':')
- 		st->st_dev = islower(drv) ? drv - 'a' : drv - 'A';
- 	else
- 		st->st_dev = Dgetdrv();
  	st->st_rdev = 0;
  	st->st_uid = geteuid();	/* the current user owns every file */
  	st->st_gid = getegid();
--- 199,204 ----
***************
*** 209,232 ****
   * a tty.
   */
  
! int fstat(fd, st)
  int fd;
  struct stat *st;
  {
      long oldplace, r;
      short timeptr[2];
  
!     oldplace = Fseek(0L, fd, SEEK_CUR); /* get current file location */
!     r = Fseek(0L, fd, SEEK_END);	/* go to end of file */
!     st->st_size = r - oldplace;
!     Fseek(oldplace, fd, SEEK_SET);	/* go back to old location */
!     
!     r = Fdatime(fd, timeptr, 0);
      if (r < 0) {			/* assume TTY */
  	st->st_mode = S_IFCHR | 0600;
  	st->st_attr = 0xfe;
  	st->st_mtime = st->st_ctime = st->st_atime =
  		time((time_t *)0) - 2;
      }
      else {
  	st->st_mtime = st->st_atime = st->st_ctime =
--- 215,236 ----
   * a tty.
   */
  
! int
! fstat(fd, st)
  int fd;
  struct stat *st;
  {
      long oldplace, r;
      short timeptr[2];
+     short magic;
  
!     r = Fdatime(timeptr, fd, 0);
      if (r < 0) {			/* assume TTY */
  	st->st_mode = S_IFCHR | 0600;
  	st->st_attr = 0xfe;
  	st->st_mtime = st->st_ctime = st->st_atime =
  		time((time_t *)0) - 2;
+ 	st->st_size = 0;
      }
      else {
  	st->st_mtime = st->st_atime = st->st_ctime =
***************
*** 233,238 ****
--- 237,259 ----
  		unixtime(timeptr[0], timeptr[1]);
  	st->st_mode = S_IFREG | 0644;	/* this may be false */
  	st->st_attr = 0;			/* because this is */
+ 
+ 	oldplace = Fseek(0L, fd, SEEK_CUR); /* get current file location */
+ 	if (oldplace < 0) {		/* can't seek -- must be pipe */
+ 		st->st_mode = S_IFIFO | 0644;
+ 		st->st_size = 1024;
+ 	}
+ 	else {
+ 		r = Fseek(0L, fd, SEEK_END);	/* go to end of file */
+ 		st->st_size = r;
+ 		Fseek(0L, fd, SEEK_SET);	/* go to start of file */
+ 			/* check for executable file */
+ 		if (Fread(fd, 2, (char *)&magic) == 2) {
+ 			if (magic == 0x601a || magic == 0x2321)
+ 				st->st_mode |= 0111;
+ 		}
+ 		Fseek(oldplace, fd, SEEK_SET);	/* go back to old location */
+ 	}
      }
      st->st_dev = Dgetdrv();		/* this might be false, too */
      st->st_rdev = 0;
***************
*** 239,246 ****
      st->st_uid = geteuid();
      st->st_gid = getegid();
      st->st_blksize = 1024;
      st->st_ino = ++__inode;
!     st->st_blocks = st->st_nlink = 1;
      return 0;
  }
  
--- 260,268 ----
      st->st_uid = geteuid();
      st->st_gid = getegid();
      st->st_blksize = 1024;
+     st->st_blocks = (st->st_size + 1023) / 1024;
      st->st_ino = ++__inode;
!     st->st_nlink = 1;
      return 0;
  }
  
*** lib/orig/unx2dos.c	Thu Sep 27 01:03:06 1990
--- lib/unx2dos.c	Mon Oct  1 20:01:10 1990
***************
*** 2,8 ****
  #include <string.h>
  #include <ctype.h>
  #include <osbind.h>
- #include <device.h>
  #include <types.h>
  
  extern int __mint;
--- 2,7 ----
***************
*** 9,14 ****
--- 8,17 ----
  
  int _unixmode;		/* not used right now */
  
+ /*
+  * returns 0 for ordinary files, 1 for special files (like /dev/tty)
+  */
+ 
  int
  _unx2dos(unx, dos)
  	const char *unx;
***************
*** 16,21 ****
--- 19,25 ----
  {
  	const char *u;
  	char *d, c;
+ 	int rval = 0;
  
  	dos[0] = 0;
  	u = unx; d = dos;
***************
*** 32,37 ****
--- 36,42 ----
  		else if (__mint) {
  			strcpy(d, "V:\\");
  			d += 3;
+ 			rval = 1;
  		}
  		else {
  			strcpy(d, u);
***************
*** 56,62 ****
  		*d++ = c;
  	}
  	*d++ = 0;
! 	return 0;
  }
  
  int
--- 61,68 ----
  		*d++ = c;
  	}
  	*d++ = 0;
! 	if (rval) return rval;
! 	return (toupper(dos[0]) == 'V' && dos[1] == ':') ? 1 : 0;
  }
  
  int
*** include/orig/assert.h	Thu Sep  6 12:34:50 1990
--- include/assert.h	Mon Oct  1 19:39:50 1990
***************
*** 10,21 ****
  
  #ifdef __STDC__
  #define assert(cond) \
! if(!(cond)) { __eprintf(__FAILED, #expression, __LINE__, __FILE__); abort(); }
  
  #else
  
  #define assert(cond) \
! if(!(cond)) { __eprintf(__FAILED, "expression", __LINE__, __FILE__); abort(); }
  
  
  #endif /* __STDC__ */
--- 10,21 ----
  
  #ifdef __STDC__
  #define assert(cond) \
! if(!(cond)) { __eprintf(__FAILED, #cond, __LINE__, __FILE__); abort(); }
  
  #else
  
  #define assert(cond) \
! if(!(cond)) { __eprintf(__FAILED, "cond", __LINE__, __FILE__); abort(); }
  
  
  #endif /* __STDC__ */
*** include/orig/compiler.h	Sun Sep  2 16:43:14 1990
--- include/compiler.h	Tue Oct  2 20:03:02 1990
***************
*** 12,17 ****
--- 12,20 ----
  #ifdef __SOZOBON__
  typedef unsigned int size_t;
  #endif
+ #ifdef __C68__
+ typedef unsigned long size_t;
+ #endif
  
  #endif /* _SIZE_T */
  
***************
*** 18,32 ****
  /*
   * fudge non-ANSI compilers to be like ANSI
   */
! #ifdef __SOZOBON__
  
  #define const
  #define volatile
  
! #ifndef _VOID_T
  typedef char void;
  #endif
  
! #endif /* __SOZOBON__ */
  
  #endif /* _COMPILER_H */
--- 21,35 ----
  /*
   * fudge non-ANSI compilers to be like ANSI
   */
! #ifndef __STDC__
  
  #define const
  #define volatile
  
! #ifdef __NO_VOID__
  typedef char void;
  #endif
  
! #endif /* __STDC__ */
  
  #endif /* _COMPILER_H */
*** include/orig/osbind.h	Wed Sep  5 20:26:04 1990
--- include/osbind.h	Tue Oct  2 20:01:24 1990
***************
*** 1124,1133 ****
  	unsigned short	dta_time;
  	unsigned short	dta_date;
  	long		dta_size;
! 	char		dta_name[32];
! /* for TOS, only 14 are needed, but MiNT can send back up to 32 if
!  * we're running in the MiNT domain
!  */
  };
  
  #endif /* _OSBIND_H */
--- 1124,1130 ----
  	unsigned short	dta_time;
  	unsigned short	dta_date;
  	long		dta_size;
! 	char		dta_name[14];
  };
  
  #endif /* _OSBIND_H */
*** include/orig/patchlev.h	Sat Sep 29 01:46:36 1990
--- include/patchlev.h	Mon Oct  1 20:48:30 1990
***************
*** 1,5 ****
  /*
!  *	PatchLevel: 1
   *
   *	This identifies the version of the MiNT library in this
   *	directory.
--- 1,5 ----
  /*
!  *	PatchLevel: 2
   *
   *	This identifies the version of the MiNT library in this
   *	directory.
*** include/orig/stat.h	Thu Sep  6 12:52:22 1990
--- include/stat.h	Mon Oct  1 20:22:26 1990
***************
*** 27,32 ****
--- 27,33 ----
  #define	S_IFCHR			0020000
  #define	S_IFDIR			0040000
  #define	S_IFREG			0100000
+ #define S_IFIFO			0120000
  #define	S_IFLNK			0160000
  
  #define	S_ISUID			0004000


--
Eric R. Smith                     email:
Dept. of Mathematics            ersmith@uwovax.uwo.ca
University of Western Ontario   ersmith@uwovax.bitnet
London, Ont. Canada N6A 5B7
ph: (519) 661-3638