diff options
Diffstat (limited to 'libiberty/mpw.c')
-rw-r--r-- | libiberty/mpw.c | 1010 |
1 files changed, 1010 insertions, 0 deletions
diff --git a/libiberty/mpw.c b/libiberty/mpw.c new file mode 100644 index 00000000000..ca3ae412d25 --- /dev/null +++ b/libiberty/mpw.c @@ -0,0 +1,1010 @@ +/* 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 |