| /* 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 |