mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1011 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1011 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
| /* MPW-Unix compatibility library.
 | |
|    Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of the libiberty library.
 | |
| Libiberty is free software; you can redistribute it and/or
 | |
| modify it under the terms of the GNU Library General Public
 | |
| License as published by the Free Software Foundation; either
 | |
| version 2 of the License, or (at your option) any later version.
 | |
| 
 | |
| Libiberty is distributed in the hope that it will be useful,
 | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| Library General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU Library General Public
 | |
| License along with libiberty; see the file COPYING.LIB.  If
 | |
| not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 | |
| Boston, MA 02111-1307, USA.  */
 | |
| 
 | |
| /* This should only be compiled and linked under MPW. */
 | |
| 
 | |
| #include "mpw.h"
 | |
| 
 | |
| #include <stdlib.h>
 | |
| 
 | |
| #ifndef USE_MW_HEADERS
 | |
| #include <sys/time.h>
 | |
| #include <sys/resource.h>
 | |
| #endif
 | |
| 
 | |
| #include <Types.h>
 | |
| #include <Files.h>
 | |
| 
 | |
| #include <Timer.h>
 | |
| 
 | |
| /* Initialize to 0 at first, then set to errno_max() later.  */
 | |
| 
 | |
| int sys_nerr = 0;
 | |
| 
 | |
| /* Debug flag for pathname hacking.  Set this to one and rebuild. */
 | |
| 
 | |
| int DebugPI = -1;
 | |
| 
 | |
| void
 | |
| mpwify_filename(char *unixname, char *macname)
 | |
| {
 | |
|   int i, j;
 | |
| 
 | |
|   /* (should truncate 255 chars from end of name, not beginning) */
 | |
|   if (strlen (unixname) > 255)
 | |
|     {
 | |
|       fprintf (stderr, "Pathname \"%s\" is too long for Macs, truncating\n",
 | |
| 	       unixname);
 | |
|     }
 | |
|   j = 0;
 | |
|   /* If you're going to end up with one or more colons in the middle of a
 | |
|      path after an all-Unix relative path is translated, you must add a
 | |
|      colon on the front, so that the first component is not thought to be
 | |
|      a disk name.  */
 | |
|   if (unixname[0] != '/' && ! strchr (unixname, ':') && strchr (unixname, '/'))
 | |
|     {
 | |
|       macname[j++] = ':';
 | |
|     }
 | |
|   for (i = 0; unixname[i] != '\0' && i < 255; ++i)
 | |
|     {
 | |
|       if (i == 0 && unixname[i] == '/')
 | |
| 	{
 | |
| 	  if (strncmp (unixname, "/tmp/", 5) == 0)
 | |
| 	    {
 | |
| 	      /* A temporary name, make a more Mac-flavored tmpname. */
 | |
| 	      /* A better choice would be {Boot}Trash:foo, but
 | |
| 		 that would require being able to identify the
 | |
| 		 boot disk's and trashcan's name.  Another option
 | |
| 		 would be to have an env var, so user can point it
 | |
| 		 at a ramdisk. */
 | |
| 	      macname[j++] = ':';
 | |
| 	      macname[j++] = 't';
 | |
| 	      macname[j++] = 'm';
 | |
| 	      macname[j++] = 'p';
 | |
| 	      macname[j++] = '_';
 | |
| 	      i += 4;
 | |
| 	    }
 | |
| 	  else
 | |
| 	    {
 | |
| 	      /* Don't copy the leading slash. */
 | |
| 	    }
 | |
| 	}
 | |
|       else if (unixname[i] == ':' && unixname[i+1] == '/')
 | |
| 	{
 | |
| 	  macname[j++] = ':';
 | |
| 	  i += 1;
 | |
| 	}
 | |
|       else if (unixname[i] == '.' && unixname[i+1] == '/')
 | |
| 	{
 | |
| 	  macname[j++] = ':';
 | |
| 	  i += 1;
 | |
| 	}
 | |
|       else if (unixname[i] == '.' && unixname[i+1] == '.' && unixname[i+2] == '/')
 | |
| 	{
 | |
| 	  macname[j++] = ':';
 | |
| 	  macname[j++] = ':';
 | |
| 	  i += 2;
 | |
| 	}
 | |
|       else if (unixname[i] == '/')
 | |
| 	{
 | |
| 	  macname[j++] = ':';
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  macname[j++] = unixname[i];
 | |
| 	}
 | |
|     }
 | |
|   macname[j] = '\0';
 | |
|   /* Allow for getting the debug flag from an env var; quite useful. */
 | |
|   if (DebugPI < 0)
 | |
|     DebugPI = (*(getenv ("DEBUG_PATHNAMES")) == '1' ? 1 : 0);
 | |
|   if (DebugPI)
 | |
|     {
 | |
|       fprintf (stderr, "# Made \"%s\"\n", unixname);
 | |
|       fprintf (stderr, "# into \"%s\"\n", macname);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* MPW-flavored basename finder. */
 | |
| 
 | |
| char *
 | |
| mpw_basename (name)
 | |
|   char *name;
 | |
| {
 | |
|   char *base = name;
 | |
| 
 | |
|   while (*name)
 | |
|     {
 | |
|       if (*name++ == ':')
 | |
| 	{
 | |
| 	  base = name;
 | |
| 	}
 | |
|     }
 | |
|   return base;
 | |
| }
 | |
| 
 | |
| /* Mixed MPW/Unix basename finder.  This can be led astray by
 | |
|    filenames with slashes in them and come up with a basename that
 | |
|    either corresponds to no file or (worse) to some other file, so
 | |
|    should only be tried if other methods of finding a file via a
 | |
|    basename have failed.  */
 | |
| 
 | |
| char *
 | |
| mpw_mixed_basename (name)
 | |
|   char *name;
 | |
| {
 | |
|   char *base = name;
 | |
| 
 | |
|   while (*name)
 | |
|     {
 | |
|       if (*name == '/' || *name == ':')
 | |
| 	{
 | |
| 	  base = name + 1;
 | |
| 	}
 | |
|       ++name;
 | |
|     }
 | |
|   return base;
 | |
| }
 | |
| 
 | |
| /* This function is fopen() modified to create files that are type TEXT
 | |
|    or 'BIN ', and always of type 'MPS '.  */
 | |
| 
 | |
| FILE *
 | |
| mpw_fopen (char *name, char *mode)
 | |
| {
 | |
| #undef fopen
 | |
|   int errnum;
 | |
|   FILE *fp;
 | |
|   char tmpname[256];
 | |
| 
 | |
|   mpwify_filename (name, tmpname);
 | |
|   PROGRESS (1);
 | |
|   fp = fopen (tmpname, mode);
 | |
|   errnum = errno;
 | |
| 
 | |
|   /* If writing, need to set type and creator usefully. */
 | |
|   if (strchr (mode, 'w'))
 | |
|     {
 | |
|       char *pname = (char *) malloc (strlen (tmpname) + 2);
 | |
|       OSErr e;
 | |
|       struct FInfo fi;
 | |
| 
 | |
|       pname[0] = strlen (tmpname);
 | |
|       strcpy (pname+1, tmpname);
 | |
| 	
 | |
|       e = GetFInfo ((ConstStr255Param) pname, 0, &fi);
 | |
|       /* should do spiffier error handling */
 | |
|       if (e != 0)
 | |
| 	fprintf(stderr, "GetFInfo returns %d\n", e);
 | |
|       if (strchr (mode, 'b'))
 | |
| 	{
 | |
| 	  fi.fdType = (OSType) 'BIN ';
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  fi.fdType = (OSType) 'TEXT';
 | |
| 	}
 | |
|       fi.fdCreator = (OSType) 'MPS ';
 | |
|       e = SetFInfo ((ConstStr255Param) pname, 0, &fi);
 | |
|       if (e != 0)
 | |
| 	fprintf(stderr, "SetFInfo returns %d\n", e);
 | |
|       free (pname);
 | |
|     }
 | |
|   if (fp == NULL)
 | |
|     errno = errnum;
 | |
|   return fp;
 | |
| }
 | |
| 
 | |
| /* This is a version of fseek() modified to fill the file with zeros
 | |
|    if seeking past the end of it.  */
 | |
| 
 | |
| #define ZEROBLKSIZE 4096
 | |
| 
 | |
| char zeros[ZEROBLKSIZE];
 | |
| 
 | |
| int
 | |
| mpw_fseek (FILE *fp, int offset, int whence)
 | |
| {
 | |
| #undef fseek
 | |
|   int cursize, numleft;
 | |
| 
 | |
|   PROGRESS (1);
 | |
|   if (whence == SEEK_SET)
 | |
|     {
 | |
|       fseek (fp, 0, SEEK_END);
 | |
|       cursize = ftell (fp);
 | |
|       if (offset > cursize)
 | |
| 	{
 | |
| 	  numleft = offset - cursize;
 | |
| 	  while (numleft > ZEROBLKSIZE)
 | |
| 	    {
 | |
| 	      /* This might fail, should check for that. */
 | |
| 	      PROGRESS (1);
 | |
| 	      fwrite (zeros, 1, ZEROBLKSIZE, fp);
 | |
| 	      numleft -= ZEROBLKSIZE;
 | |
| 	    }
 | |
| 	  PROGRESS (1);
 | |
| 	  fwrite (zeros, 1, numleft, fp);
 | |
| 	  fflush (fp);
 | |
| 	}
 | |
|     }
 | |
|   return fseek (fp, offset, whence);
 | |
| }
 | |
| 
 | |
| int
 | |
| mpw_fread (char *ptr, int size, int nitems, FILE *stream)
 | |
| {
 | |
| #undef fread
 | |
|   int rslt;
 | |
| 
 | |
|   PROGRESS (1);
 | |
|   rslt = fread (ptr, size, nitems, stream);
 | |
|   PROGRESS (1);
 | |
|   return rslt;
 | |
| }
 | |
| 
 | |
| int
 | |
| mpw_fwrite (char *ptr, int size, int nitems, FILE *stream)
 | |
| {
 | |
| #undef fwrite
 | |
|   int rslt;
 | |
| 
 | |
|   PROGRESS (1);
 | |
|   rslt = fwrite (ptr, size, nitems, stream);
 | |
|   PROGRESS (1);
 | |
|   return rslt;
 | |
| }
 | |
| 
 | |
| int
 | |
| link ()
 | |
| {
 | |
|   fprintf (stderr, "link not available!\n");
 | |
|   mpw_abort ();
 | |
| }
 | |
| 
 | |
| int
 | |
| fork ()
 | |
| {
 | |
|   fprintf (stderr, "fork not available!\n");
 | |
|   mpw_abort ();
 | |
| }
 | |
| 
 | |
| int
 | |
| vfork ()
 | |
| {
 | |
|   fprintf (stderr, "vfork not available!\n");
 | |
|   mpw_abort ();
 | |
|   return (-1);
 | |
| }
 | |
| 
 | |
| int
 | |
| pipe (int *fd)
 | |
| {
 | |
|   fprintf (stderr, "pipe not available!\n");
 | |
|   mpw_abort ();
 | |
|   return (-1);
 | |
| }
 | |
| 
 | |
| #ifndef USE_MW_HEADERS
 | |
| int
 | |
| execvp (char *file, char **argv)
 | |
| {
 | |
|   fprintf (stderr, "execvp not available!\n");
 | |
|   mpw_abort ();
 | |
|   return (-1);
 | |
| }
 | |
| 
 | |
| int
 | |
| execv (char *path, char **argv)
 | |
| {
 | |
|   fprintf (stderr, "execv not available!\n");
 | |
|   mpw_abort ();
 | |
|   return (-1);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| int
 | |
| kill (int pid, int sig)
 | |
| {
 | |
|   fprintf (stderr, "kill not available!\n");
 | |
|   mpw_abort ();
 | |
|   return (-1);
 | |
| }
 | |
| 
 | |
| int
 | |
| wait (int *status)
 | |
| {
 | |
|   *status = 0;
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| #ifndef USE_MW_HEADERS
 | |
| int
 | |
| sleep (int seconds)
 | |
| {
 | |
|   unsigned long start_time, now;
 | |
| 
 | |
|   time (&start_time);
 | |
| 
 | |
|   while (1)
 | |
|     {
 | |
|       PROGRESS (1);
 | |
|       time (&now);
 | |
|       if (now > start_time + seconds)
 | |
| 	return 0;
 | |
|     }
 | |
| }
 | |
| #endif
 | |
| 
 | |
| void
 | |
| putenv (char *str)
 | |
| {
 | |
|   /* The GCC driver calls this to do things for collect2, but we
 | |
|      don't care about collect2. */
 | |
| }
 | |
| 
 | |
| int
 | |
| chmod (char *path, int mode)
 | |
| {
 | |
|   /* Pretend it was all OK. */
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| #ifndef USE_MW_HEADERS
 | |
| int
 | |
| getuid ()
 | |
| {
 | |
|   /* One value is as good as another... */
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| getgid ()
 | |
| {
 | |
|   /* One value is as good as another... */
 | |
|   return 0;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /* Instead of coredumping, which is not a normal Mac facility, we
 | |
|    drop into Macsbug.  If we then "g" from Macsbug, the program will
 | |
|    exit cleanly. */
 | |
| 
 | |
| void
 | |
| mpw_abort ()
 | |
| {
 | |
|   /* Make sure no output still buffered up, then zap into MacsBug. */
 | |
|   fflush(stdout);
 | |
|   fflush(stderr);
 | |
|   printf("## Abort! ##\n");
 | |
| #ifdef MPW_SADE
 | |
|   SysError(8005);
 | |
| #else 
 | |
|   Debugger();
 | |
| #endif
 | |
|   /* "g" in MacsBug will then cause a regular error exit. */
 | |
|   exit (1);
 | |
| }
 | |
| 
 | |
| /* Imitation getrusage based on the ANSI clock() function. */
 | |
| 
 | |
| int
 | |
| getrusage (int who, struct rusage *rusage)
 | |
| {
 | |
|   int clk = clock ();
 | |
| 
 | |
| #if 0
 | |
|   rusage->ru_utime.tv_sec = clk / CLOCKS_PER_SEC;
 | |
|   rusage->ru_utime.tv_usec = ((clk * 1000) / CLOCKS_PER_SEC) * 1000;
 | |
|   rusage->ru_stime.tv_sec = 0;
 | |
|   rusage->ru_stime.tv_usec = 0;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| int
 | |
| sbrk ()
 | |
| {
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| #ifndef USE_MW_HEADERS
 | |
| int
 | |
| isatty (int fd)
 | |
| {
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* This is inherited from Timothy Murray's Posix library. */
 | |
| 
 | |
| #include "utime.h"
 | |
| 
 | |
| int
 | |
| utime (char *filename, struct utimbuf *times)
 | |
| {
 | |
|   CInfoPBRec cipbr;
 | |
|   HFileInfo *fpb = (HFileInfo *) &cipbr;
 | |
|   DirInfo *dpb = (DirInfo *) &cipbr;
 | |
|   unsigned char pname[256];
 | |
|   short err;
 | |
|   
 | |
|   strcpy ((char *) pname, filename);
 | |
|   c2pstr (pname);
 | |
| 
 | |
|   dpb->ioDrDirID = 0L;
 | |
|   fpb->ioNamePtr = pname;
 | |
|   fpb->ioVRefNum = 0;
 | |
|   fpb->ioFDirIndex = 0;
 | |
|   fpb->ioFVersNum = 0;
 | |
|   err = PBGetCatInfo (&cipbr, 0);
 | |
|   if (err != noErr) {
 | |
|     errno = ENOENT;
 | |
|     return -1;
 | |
|   }
 | |
|   dpb->ioDrDirID = 0L;
 | |
|   fpb->ioFlMdDat = times->modtime;
 | |
|   fpb->ioFlCrDat = times->actime;
 | |
|   err = PBSetCatInfo (&cipbr, 0);
 | |
|   if (err != noErr) {
 | |
|     errno = EACCES;
 | |
|     return -1;
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| mkdir (char *path, int mode)
 | |
| {
 | |
|   errno = ENOSYS;
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| int
 | |
| rmdir ()
 | |
| {
 | |
|   errno = ENOSYS;
 | |
|   return -1;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| chown ()
 | |
| {
 | |
|   errno = ENOSYS;
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| char *myenviron[] = {NULL};
 | |
| 
 | |
| char **environ = myenviron;
 | |
| 
 | |
| #ifndef USE_MW_HEADERS
 | |
| 
 | |
| /* Minimal 'stat' emulation: tells directories from files and
 | |
|    gives length and mtime.
 | |
| 
 | |
|    Derived from code written by Guido van Rossum, CWI, Amsterdam
 | |
|    and placed by him in the public domain.  */
 | |
| 
 | |
| extern int __uid, __gid;
 | |
| 
 | |
| int __uid = 0;
 | |
| int __gid = 0;
 | |
| 
 | |
| /* Bits in ioFlAttrib: */
 | |
| #define LOCKBIT	(1<<0)		/* File locked */
 | |
| #define DIRBIT	(1<<4)		/* It's a directory */
 | |
| 
 | |
| /* Macified "stat" in which filename is given relative to a directory,
 | |
|    specified by long DirID.  */
 | |
| 
 | |
| static int
 | |
| _stat (char *name, long dirid, struct stat *buf)
 | |
| {
 | |
|   CInfoPBRec cipbr;
 | |
|   HFileInfo *fpb = (HFileInfo*) &cipbr;
 | |
|   DirInfo *dpb = (DirInfo*) &cipbr;
 | |
|   Str255 pname;
 | |
|   short err;
 | |
| 
 | |
|   /* Make a temp copy of the name and pascalize. */
 | |
|   strcpy ((char *) pname, name);
 | |
|   c2pstr (pname);
 | |
|   
 | |
|   cipbr.dirInfo.ioDrDirID = dirid;
 | |
|   cipbr.hFileInfo.ioNamePtr = pname;
 | |
|   cipbr.hFileInfo.ioVRefNum = 0;
 | |
|   cipbr.hFileInfo.ioFDirIndex = 0;
 | |
|   cipbr.hFileInfo.ioFVersNum = 0;
 | |
|   err = PBGetCatInfo (&cipbr, 0);
 | |
|   if (err != noErr)
 | |
|     {
 | |
|       errno = ENOENT;
 | |
|       return -1;
 | |
|     }
 | |
|   /* Mac files are readable if they can be accessed at all. */
 | |
|   buf->st_mode = 0444;
 | |
|   /* Mark unlocked files as writeable. */
 | |
|   if (!(fpb->ioFlAttrib & LOCKBIT))
 | |
|     buf->st_mode |= 0222;
 | |
|   if (fpb->ioFlAttrib & DIRBIT)
 | |
|     {
 | |
|       /* Mark directories as "executable". */
 | |
|       buf->st_mode |= 0111 | S_IFDIR;
 | |
|       buf->st_size = dpb->ioDrNmFls;
 | |
|       buf->st_rsize = 0;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       buf->st_mode |= S_IFREG;
 | |
|       /* Mark apps as "executable". */
 | |
|       if (fpb->ioFlFndrInfo.fdType == 'APPL')
 | |
| 	buf->st_mode |= 0111;
 | |
|       /* Fill in the sizes of data and resource forks. */
 | |
|       buf->st_size = fpb->ioFlLgLen;
 | |
|       buf->st_rsize = fpb->ioFlRLgLen;
 | |
|     }
 | |
|   /* Fill in various times. */
 | |
|   buf->st_atime = fpb->ioFlCrDat;
 | |
|   buf->st_mtime = fpb->ioFlMdDat;
 | |
|   buf->st_ctime = fpb->ioFlCrDat;
 | |
|   /* Set up an imitation inode number. */
 | |
|   buf->st_ino = (unsigned short) fpb->ioDirID;
 | |
|   /* Set up an imitation device. */
 | |
|   GetVRefNum (buf->st_ino, &buf->st_dev);
 | |
|   buf->st_uid = __uid;
 | |
|   buf->st_gid = __gid;
 | |
| /*  buf->st_FlFndrInfo = fpb->ioFlFndrInfo;  */
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* stat() sets up an empty dirid. */
 | |
| 
 | |
| int
 | |
| stat (char *path, struct stat *buf)
 | |
| {
 | |
|   long rslt, errnum;
 | |
|   char tmpname[256];
 | |
| 
 | |
|   mpwify_filename (path, tmpname);
 | |
|   if (DebugPI)
 | |
|     fprintf (stderr, "# stat (%s, %x)", tmpname, buf);
 | |
|   PROGRESS (1);
 | |
|   rslt = _stat (tmpname, 0L, buf);
 | |
|   errnum = errno;
 | |
|   if (DebugPI)
 | |
|     {
 | |
|       fprintf (stderr, " -> %d", rslt);
 | |
|       if (rslt != 0)
 | |
| 	fprintf (stderr, " (errno is %d)", errnum);
 | |
|       fprintf (stderr, "\n");
 | |
|       fflush (stderr);
 | |
|     }
 | |
|   if (rslt != 0)
 | |
|     errno = errnum;
 | |
|   return rslt;
 | |
| }
 | |
| 
 | |
| int
 | |
| fstat (int fd, struct stat *buf)
 | |
| {
 | |
|   FCBPBRec fcb;
 | |
|   FILE *fp;
 | |
|   Str255 pathname;
 | |
|   long dirid = 0L, temp;
 | |
|   long rslt, errnum;
 | |
|   short err;
 | |
| 
 | |
|   if (DebugPI < 0)
 | |
|     DebugPI = (*(getenv ("DEBUG_PATHNAMES")) == '1' ? 1 : 0);
 | |
|   if (DebugPI)
 | |
|     fprintf (stderr, "# fstat (%d, %x)", fd, buf);
 | |
|   PROGRESS (1);
 | |
|   pathname[0] = 0;
 | |
| #ifdef FIOFNAME
 | |
|   /* Use an MPW-specific ioctl to get the pathname associated with
 | |
|      the file descriptor.  */
 | |
|   ioctl (fd, FIOFNAME, (long *) pathname); 
 | |
| #else
 | |
|   you lose
 | |
| #endif
 | |
|   if (DebugPI)
 | |
|     fprintf (stderr, " (name is %s)", pathname);
 | |
|   dirid = 0L /* fcb.ioFCBParID */ ;
 | |
|   rslt = _stat ((char *) pathname, dirid, buf);
 | |
|   errnum = errno;
 | |
|   if (DebugPI)
 | |
|     {
 | |
|       fprintf (stderr, " -> %d", rslt);
 | |
|       if (rslt != 0)
 | |
| 	fprintf (stderr, " (errno is %d)", errnum);
 | |
|       fprintf (stderr, "\n");
 | |
|       fflush (stderr);
 | |
|     }
 | |
|   if (rslt != 0)
 | |
|     errno = errnum;
 | |
|   return rslt;
 | |
| }
 | |
| 
 | |
| #endif /* n USE_MW_HEADERS */
 | |
| 
 | |
| chdir ()
 | |
| {
 | |
|   errno = ENOSYS;
 | |
|   return (-1);
 | |
| }
 | |
| 
 | |
| char *
 | |
| getcwd (char *buf, int size)
 | |
| {
 | |
|   if (buf == NULL)
 | |
|     buf = (char *) malloc (size);
 | |
|   strcpy(buf, ":");
 | |
|   return buf;
 | |
| }
 | |
| 
 | |
| /* This should probably be more elaborate for MPW. */
 | |
| 
 | |
| char *
 | |
| getpwd ()
 | |
| {
 | |
|   return ":";
 | |
| }
 | |
| 
 | |
| int
 | |
| mpw_open (char *filename, int arg2, int arg3)
 | |
| {
 | |
| #undef open
 | |
|   int fd, errnum = 0;
 | |
|   char tmpname[256];
 | |
| 
 | |
|   mpwify_filename (filename, tmpname);
 | |
|   fd = open (tmpname, arg2);
 | |
|   errnum = errno;
 | |
| 
 | |
|   if (DebugPI)
 | |
|     {
 | |
|       fprintf (stderr, "# open (%s, %d, %d)", tmpname, arg2, arg3);
 | |
|       fprintf (stderr, " -> %d", fd);
 | |
|       if (fd == -1)
 | |
| 	fprintf (stderr, " (errno is %d)", errnum);
 | |
|       fprintf (stderr, "\n");
 | |
|     }
 | |
|   if (fd == -1)
 | |
|     errno = errnum;
 | |
|   return fd;
 | |
| }
 | |
| 
 | |
| int
 | |
| mpw_access (char *filename, unsigned int cmd)
 | |
| {
 | |
| #undef access
 | |
| 
 | |
|   int rslt, errnum = 0;
 | |
|   struct stat st;
 | |
|   char tmpname[256];
 | |
| 
 | |
|   mpwify_filename (filename, tmpname);
 | |
|   if (cmd & R_OK || cmd & X_OK)
 | |
|     {
 | |
|       rslt = stat (tmpname, &st);
 | |
|       errnum = errno;
 | |
|       if (rslt >= 0)
 | |
| 	{
 | |
| 	  if ((((st.st_mode & 004) == 0) && (cmd & R_OK))
 | |
| 	      || (((st.st_mode & 002) == 0) && (cmd & W_OK))
 | |
| 	      || (((st.st_mode & 001) == 0) && (cmd & X_OK)))
 | |
| 	    {
 | |
| 	      rslt = -1;
 | |
| 	      errnum = EACCES;
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|   if (DebugPI)
 | |
|     {
 | |
|       fprintf (stderr, "# mpw_access (%s, %d)", tmpname, cmd);
 | |
|       fprintf (stderr, " -> %d", rslt);
 | |
|       if (rslt != 0)
 | |
| 	fprintf (stderr, " (errno is %d)", errnum);
 | |
|       fprintf (stderr, "\n");
 | |
|     }
 | |
|   if (rslt != 0)
 | |
|     errno = errnum;
 | |
|   return rslt;
 | |
| }
 | |
| 
 | |
| /* The MPW library creat() has no mode argument. */
 | |
| 
 | |
| int
 | |
| mpw_creat (char *path, /* mode_t */ int mode)
 | |
| {
 | |
| #undef creat
 | |
| 
 | |
| #ifdef USE_MW_HEADERS
 | |
|   return creat (path, mode);
 | |
| #else
 | |
|   return creat (path);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /* This is a hack to get control in an MPW tool before it crashes the
 | |
|    machine.  */
 | |
| 
 | |
| mpw_special_init (name)
 | |
|      char *name;
 | |
| {
 | |
|   if (strstr (name, "DEBUG"))
 | |
|     DebugStr("\pat beginning of program");
 | |
| }
 | |
| 
 | |
| static int current_umask;
 | |
| 
 | |
| int
 | |
| umask(int mask)
 | |
| {
 | |
|   int oldmask = current_umask;
 | |
| 
 | |
|   current_umask = mask;
 | |
|   return oldmask;
 | |
| }
 | |
| 
 | |
| /* Cursor-spinning stuff that includes metering of spin rate and delays.  */
 | |
| 
 | |
| /* Nonzero when cursor spinning has been set up properly.  */
 | |
| 
 | |
| int cursor_inited;
 | |
| 
 | |
| /* Nonzero if spin should be measured and excessive delays reported.  */
 | |
| 
 | |
| int measure_spin;
 | |
| 
 | |
| /* Nonzero if spin histogram and rate data should be written out.  */
 | |
| 
 | |
| int dump_spin_data;
 | |
| 
 | |
| long warning_threshold = 400000;
 | |
| 
 | |
| long bucket_size = 1024;
 | |
| 
 | |
| long bucket_power = 10;
 | |
| 
 | |
| long numbuckets = 300;
 | |
| 
 | |
| int *delay_counts;
 | |
| 
 | |
| int overflow_count;
 | |
| 
 | |
| char *current_progress;
 | |
| 
 | |
| static UnsignedWide last_microseconds;
 | |
| 
 | |
| static char *last_spin_file = "";
 | |
| 
 | |
| static int last_spin_line;
 | |
| 
 | |
| void
 | |
| warn_if_spin_delay (char *file, int line)
 | |
| {
 | |
|   long diff, ix;
 | |
|   UnsignedWide now;
 | |
| 
 | |
|   Microseconds(&now);
 | |
| 
 | |
|   diff = now.lo - last_microseconds.lo;
 | |
| 
 | |
|   if (diff > warning_threshold)
 | |
|     fprintf (stderr, "# %s: %ld.%06ld sec delay getting from %s:%d to %s:%d\n",
 | |
| 	     (current_progress ? current_progress : ""),
 | |
| 	     diff / 1000000, diff % 1000000,
 | |
| 	     last_spin_file, last_spin_line, file, line);
 | |
|   if (dump_spin_data)
 | |
|     {
 | |
|       if (diff >= 0)
 | |
| 	{
 | |
| 	  ix = diff >> bucket_power;
 | |
| 	  if (ix >= 0 && ix < numbuckets && delay_counts != NULL)
 | |
| 	    ++delay_counts[ix];
 | |
| 	  else
 | |
| 	    ++overflow_count;
 | |
| 	}
 | |
|       else
 | |
| 	fprintf (stderr, "raw diff is %ld (?)\n", diff);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| record_for_spin_delay (char *file, int line)
 | |
| {
 | |
|   Microseconds (&last_microseconds);
 | |
|   last_spin_file = file;
 | |
|   last_spin_line = line;
 | |
| }
 | |
| 
 | |
| void
 | |
| mpw_start_progress (char *str, int n, char *file, int line)
 | |
| {
 | |
|   int i;
 | |
|   char *measure, *threshold;
 | |
| 
 | |
|   if (!cursor_inited)
 | |
|     {
 | |
|       InitCursorCtl (nil);
 | |
|       cursor_inited = 1;
 | |
|       record_for_spin_delay (file, line);
 | |
|       measure = getenv ("MEASURE_SPIN");
 | |
|       if (measure != NULL && measure[0] != '\0')
 | |
| 	{
 | |
| 	  measure_spin = 1;
 | |
| 	  if (strcmp (measure, "all") == 0)
 | |
| 	    dump_spin_data = 1;
 | |
| 	}
 | |
|       threshold = getenv ("SPIN_WARN_THRESHOLD");
 | |
|       if (threshold != NULL && threshold[0] != '\0')
 | |
| 	warning_threshold = atol (threshold);
 | |
|       if (dump_spin_data)
 | |
| 	{
 | |
| 	  if (delay_counts == NULL)
 | |
| 	    delay_counts = (int *) malloc (numbuckets * sizeof (int));
 | |
| 	  for (i = 0; i < numbuckets; ++i)
 | |
| 	    delay_counts[i] = 0;
 | |
| 	  overflow_count = 0;
 | |
| 	}
 | |
|     }
 | |
|   current_progress = str;
 | |
| 
 | |
|   sys_nerr = errno_max ();
 | |
| 
 | |
|   mpw_special_init (str);
 | |
| }
 | |
| 
 | |
| void
 | |
| mpw_progress (int n)
 | |
| {
 | |
|   SpinCursor (32);
 | |
| }
 | |
| 
 | |
| void
 | |
| mpw_progress_measured (int n, char *file, int line)
 | |
| {
 | |
|   if (measure_spin)
 | |
|     warn_if_spin_delay (file, line);
 | |
|   SpinCursor (32);
 | |
|   if (measure_spin)
 | |
|     record_for_spin_delay (file, line);
 | |
| }
 | |
| 
 | |
| void
 | |
| mpw_end_progress (char *str, char *file, int line)
 | |
| {
 | |
|   long i, delay, count = 0, sum = 0, avgdelay, spinrate;
 | |
|   long curpower = 0, curgroup = 0;
 | |
| 
 | |
|   /* Warn if it's been a while since the last spin.  */
 | |
|   if (measure_spin)
 | |
|     warn_if_spin_delay (file, line);
 | |
| 
 | |
|   /* Dump all the nonzero delay counts and an approximation of the delay.  */
 | |
|   if (dump_spin_data && delay_counts != NULL)
 | |
|     {
 | |
|       for (i = 0; i < numbuckets; ++i)
 | |
| 	{
 | |
| 	  delay = (i + 1) * bucket_size;
 | |
| 	  sum += delay_counts[i] * (i + 1);
 | |
| 	  count += delay_counts[i];
 | |
| 	  if (delay <= (1 << curpower))
 | |
| 	    {
 | |
| 	      curgroup += delay_counts[i];
 | |
| 	    }
 | |
| 	  else
 | |
| 	    {
 | |
| 	      if (curgroup > 0)
 | |
| 		fprintf (stderr,
 | |
| 			 "# %s: %d delays between %ld.%06ld and %ld.%06ld sec\n",
 | |
| 			 (str ? str : ""),
 | |
| 			 curgroup,
 | |
| 			 (1 << curpower) / 1000000,
 | |
| 			 (1 << curpower) % 1000000,
 | |
| 			 (1 << (curpower + 1)) / 1000000,
 | |
| 			 (1 << (curpower + 1)) % 1000000);
 | |
| 	      ++curpower;
 | |
| 	      curgroup = 0;
 | |
| 	    }
 | |
| 	}
 | |
|       if (count > 0)
 | |
| 	{
 | |
| 	  avgdelay = (sum * bucket_size) / count;
 | |
| 	  spinrate = 1000000 / avgdelay;
 | |
| 	  fprintf (stderr, "# %s: Average spin rate is %d times/sec\n",
 | |
| 		   (str ? str : ""), spinrate);
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| #ifdef PROGRESS_TEST
 | |
| 
 | |
| /* Test program.  */
 | |
| 
 | |
| main ()
 | |
| {
 | |
|   int i, j;
 | |
|   double x = 1.0, y = 2.4;
 | |
|   long start = Microseconds (), tm;  FIXME
 | |
| 
 | |
|   START_PROGRESS ("hi", 0);
 | |
| 
 | |
|   for (i = 0; i < 1000; ++i)
 | |
|     {
 | |
|       PROGRESS (1);
 | |
| 
 | |
|       for (j = 0; j < (i * 100); ++j)
 | |
| 	{
 | |
| 	  x += (x * y) / j;
 | |
| 	}
 | |
|     }
 | |
|   
 | |
|   END_PROGRESS ("hi");
 | |
|   
 | |
|   tm = Microseconds () - start;
 | |
| 
 | |
|   printf ("Total time is %d.%d secs\n", tm / 1000000, tm % 1000000);
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #ifdef USE_MW_HEADERS
 | |
| /* Empty definitions for Metrowerks' SIOUX console library. */
 | |
| 
 | |
| #ifndef __CONSOLE__
 | |
| #include <console.h>
 | |
| #endif
 | |
| 
 | |
| short
 | |
| InstallConsole(short fd)
 | |
| {
 | |
| #pragma unused (fd)
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void
 | |
| RemoveConsole(void)
 | |
| {
 | |
| }
 | |
| 
 | |
| long
 | |
| WriteCharsToConsole(char *buf, long n)
 | |
| {
 | |
| #pragma unused (buf, n)
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| long ReadCharsFromConsole(char *buf, long n)
 | |
| {
 | |
| #pragma unused (buf, n)
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| extern char *
 | |
| __ttyname(long fd)
 | |
| {
 | |
| 	static char *__devicename = "null device";
 | |
| 
 | |
| 	if (fd >= 0 && fd <= 2)
 | |
| 	  return (__devicename);
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| #endif
 |