1 /* MPW-Unix compatibility library.
2 Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
4 This file is part of the libiberty library.
5 Libiberty is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 Libiberty is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with libiberty; see the file COPYING.LIB. If
17 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
20 /* This should only be compiled and linked under MPW. */
26 #ifndef USE_MW_HEADERS
28 #include <sys/resource.h>
36 /* Initialize to 0 at first, then set to errno_max() later. */
40 /* Debug flag for pathname hacking. Set this to one and rebuild. */
45 mpwify_filename(char *unixname, char *macname)
49 /* (should truncate 255 chars from end of name, not beginning) */
50 if (strlen (unixname) > 255)
52 fprintf (stderr, "Pathname \"%s\" is too long for Macs, truncating\n",
56 /* If you're going to end up with one or more colons in the middle of a
57 path after an all-Unix relative path is translated, you must add a
58 colon on the front, so that the first component is not thought to be
60 if (unixname[0] != '/' && ! strchr (unixname, ':') && strchr (unixname, '/'))
64 for (i = 0; unixname[i] != '\0' && i < 255; ++i)
66 if (i == 0 && unixname[i] == '/')
68 if (strncmp (unixname, "/tmp/", 5) == 0)
70 /* A temporary name, make a more Mac-flavored tmpname. */
71 /* A better choice would be {Boot}Trash:foo, but
72 that would require being able to identify the
73 boot disk's and trashcan's name. Another option
74 would be to have an env var, so user can point it
85 /* Don't copy the leading slash. */
88 else if (unixname[i] == ':' && unixname[i+1] == '/')
93 else if (unixname[i] == '.' && unixname[i+1] == '/')
98 else if (unixname[i] == '.' && unixname[i+1] == '.' && unixname[i+2] == '/')
104 else if (unixname[i] == '/')
110 macname[j++] = unixname[i];
114 /* Allow for getting the debug flag from an env var; quite useful. */
116 DebugPI = (*(getenv ("DEBUG_PATHNAMES")) == '1' ? 1 : 0);
119 fprintf (stderr, "# Made \"%s\"\n", unixname);
120 fprintf (stderr, "# into \"%s\"\n", macname);
124 /* MPW-flavored basename finder. */
142 /* Mixed MPW/Unix basename finder. This can be led astray by
143 filenames with slashes in them and come up with a basename that
144 either corresponds to no file or (worse) to some other file, so
145 should only be tried if other methods of finding a file via a
146 basename have failed. */
149 mpw_mixed_basename (name)
156 if (*name == '/' || *name == ':')
165 /* This function is fopen() modified to create files that are type TEXT
166 or 'BIN ', and always of type 'MPS '. */
169 mpw_fopen (char *name, char *mode)
176 mpwify_filename (name, tmpname);
178 fp = fopen (tmpname, mode);
181 /* If writing, need to set type and creator usefully. */
182 if (strchr (mode, 'w'))
184 char *pname = (char *) malloc (strlen (tmpname) + 2);
188 pname[0] = strlen (tmpname);
189 strcpy (pname+1, tmpname);
191 e = GetFInfo ((ConstStr255Param) pname, 0, &fi);
192 /* should do spiffier error handling */
194 fprintf(stderr, "GetFInfo returns %d\n", e);
195 if (strchr (mode, 'b'))
197 fi.fdType = (OSType) 'BIN ';
201 fi.fdType = (OSType) 'TEXT';
203 fi.fdCreator = (OSType) 'MPS ';
204 e = SetFInfo ((ConstStr255Param) pname, 0, &fi);
206 fprintf(stderr, "SetFInfo returns %d\n", e);
214 /* This is a version of fseek() modified to fill the file with zeros
215 if seeking past the end of it. */
217 #define ZEROBLKSIZE 4096
219 char zeros[ZEROBLKSIZE];
222 mpw_fseek (FILE *fp, int offset, int whence)
225 int cursize, numleft;
228 if (whence == SEEK_SET)
230 fseek (fp, 0, SEEK_END);
231 cursize = ftell (fp);
232 if (offset > cursize)
234 numleft = offset - cursize;
235 while (numleft > ZEROBLKSIZE)
237 /* This might fail, should check for that. */
239 fwrite (zeros, 1, ZEROBLKSIZE, fp);
240 numleft -= ZEROBLKSIZE;
243 fwrite (zeros, 1, numleft, fp);
247 return fseek (fp, offset, whence);
251 mpw_fread (char *ptr, int size, int nitems, FILE *stream)
257 rslt = fread (ptr, size, nitems, stream);
263 mpw_fwrite (char *ptr, int size, int nitems, FILE *stream)
269 rslt = fwrite (ptr, size, nitems, stream);
277 fprintf (stderr, "link not available!\n");
284 fprintf (stderr, "fork not available!\n");
291 fprintf (stderr, "vfork not available!\n");
299 fprintf (stderr, "pipe not available!\n");
304 #ifndef USE_MW_HEADERS
306 execvp (char *file, char **argv)
308 fprintf (stderr, "execvp not available!\n");
314 execv (char *path, char **argv)
316 fprintf (stderr, "execv not available!\n");
323 kill (int pid, int sig)
325 fprintf (stderr, "kill not available!\n");
337 #ifndef USE_MW_HEADERS
341 unsigned long start_time, now;
349 if (now > start_time + seconds)
358 /* The GCC driver calls this to do things for collect2, but we
359 don't care about collect2. */
363 chmod (char *path, int mode)
365 /* Pretend it was all OK. */
369 #ifndef USE_MW_HEADERS
373 /* One value is as good as another... */
380 /* One value is as good as another... */
385 /* Instead of coredumping, which is not a normal Mac facility, we
386 drop into Macsbug. If we then "g" from Macsbug, the program will
392 /* Make sure no output still buffered up, then zap into MacsBug. */
395 printf("## Abort! ##\n");
401 /* "g" in MacsBug will then cause a regular error exit. */
405 /* Imitation getrusage based on the ANSI clock() function. */
408 getrusage (int who, struct rusage *rusage)
413 rusage->ru_utime.tv_sec = clk / CLOCKS_PER_SEC;
414 rusage->ru_utime.tv_usec = ((clk * 1000) / CLOCKS_PER_SEC) * 1000;
415 rusage->ru_stime.tv_sec = 0;
416 rusage->ru_stime.tv_usec = 0;
426 #ifndef USE_MW_HEADERS
433 /* This is inherited from Timothy Murray's Posix library. */
438 utime (char *filename, struct utimbuf *times)
441 HFileInfo *fpb = (HFileInfo *) &cipbr;
442 DirInfo *dpb = (DirInfo *) &cipbr;
443 unsigned char pname[256];
446 strcpy ((char *) pname, filename);
450 fpb->ioNamePtr = pname;
452 fpb->ioFDirIndex = 0;
454 err = PBGetCatInfo (&cipbr, 0);
460 fpb->ioFlMdDat = times->modtime;
461 fpb->ioFlCrDat = times->actime;
462 err = PBSetCatInfo (&cipbr, 0);
471 mkdir (char *path, int mode)
491 char *myenviron[] = {NULL};
493 char **environ = myenviron;
495 #ifndef USE_MW_HEADERS
497 /* Minimal 'stat' emulation: tells directories from files and
498 gives length and mtime.
500 Derived from code written by Guido van Rossum, CWI, Amsterdam
501 and placed by him in the public domain. */
503 extern int __uid, __gid;
508 /* Bits in ioFlAttrib: */
509 #define LOCKBIT (1<<0) /* File locked */
510 #define DIRBIT (1<<4) /* It's a directory */
512 /* Macified "stat" in which filename is given relative to a directory,
513 specified by long DirID. */
516 _stat (char *name, long dirid, struct stat *buf)
519 HFileInfo *fpb = (HFileInfo*) &cipbr;
520 DirInfo *dpb = (DirInfo*) &cipbr;
524 /* Make a temp copy of the name and pascalize. */
525 strcpy ((char *) pname, name);
528 cipbr.dirInfo.ioDrDirID = dirid;
529 cipbr.hFileInfo.ioNamePtr = pname;
530 cipbr.hFileInfo.ioVRefNum = 0;
531 cipbr.hFileInfo.ioFDirIndex = 0;
532 cipbr.hFileInfo.ioFVersNum = 0;
533 err = PBGetCatInfo (&cipbr, 0);
539 /* Mac files are readable if they can be accessed at all. */
541 /* Mark unlocked files as writeable. */
542 if (!(fpb->ioFlAttrib & LOCKBIT))
543 buf->st_mode |= 0222;
544 if (fpb->ioFlAttrib & DIRBIT)
546 /* Mark directories as "executable". */
547 buf->st_mode |= 0111 | S_IFDIR;
548 buf->st_size = dpb->ioDrNmFls;
553 buf->st_mode |= S_IFREG;
554 /* Mark apps as "executable". */
555 if (fpb->ioFlFndrInfo.fdType == 'APPL')
556 buf->st_mode |= 0111;
557 /* Fill in the sizes of data and resource forks. */
558 buf->st_size = fpb->ioFlLgLen;
559 buf->st_rsize = fpb->ioFlRLgLen;
561 /* Fill in various times. */
562 buf->st_atime = fpb->ioFlCrDat;
563 buf->st_mtime = fpb->ioFlMdDat;
564 buf->st_ctime = fpb->ioFlCrDat;
565 /* Set up an imitation inode number. */
566 buf->st_ino = (unsigned short) fpb->ioDirID;
567 /* Set up an imitation device. */
568 GetVRefNum (buf->st_ino, &buf->st_dev);
571 /* buf->st_FlFndrInfo = fpb->ioFlFndrInfo; */
575 /* stat() sets up an empty dirid. */
578 stat (char *path, struct stat *buf)
583 mpwify_filename (path, tmpname);
585 fprintf (stderr, "# stat (%s, %x)", tmpname, buf);
587 rslt = _stat (tmpname, 0L, buf);
591 fprintf (stderr, " -> %d", rslt);
593 fprintf (stderr, " (errno is %d)", errnum);
594 fprintf (stderr, "\n");
603 fstat (int fd, struct stat *buf)
608 long dirid = 0L, temp;
613 DebugPI = (*(getenv ("DEBUG_PATHNAMES")) == '1' ? 1 : 0);
615 fprintf (stderr, "# fstat (%d, %x)", fd, buf);
619 /* Use an MPW-specific ioctl to get the pathname associated with
620 the file descriptor. */
621 ioctl (fd, FIOFNAME, (long *) pathname);
626 fprintf (stderr, " (name is %s)", pathname);
627 dirid = 0L /* fcb.ioFCBParID */ ;
628 rslt = _stat ((char *) pathname, dirid, buf);
632 fprintf (stderr, " -> %d", rslt);
634 fprintf (stderr, " (errno is %d)", errnum);
635 fprintf (stderr, "\n");
643 #endif /* n USE_MW_HEADERS */
652 getcwd (char *buf, int size)
655 buf = (char *) malloc (size);
660 /* This should probably be more elaborate for MPW. */
669 mpw_open (char *filename, int arg2, int arg3)
675 mpwify_filename (filename, tmpname);
676 fd = open (tmpname, arg2);
681 fprintf (stderr, "# open (%s, %d, %d)", tmpname, arg2, arg3);
682 fprintf (stderr, " -> %d", fd);
684 fprintf (stderr, " (errno is %d)", errnum);
685 fprintf (stderr, "\n");
693 mpw_access (char *filename, unsigned int cmd)
697 int rslt, errnum = 0;
701 mpwify_filename (filename, tmpname);
702 if (cmd & R_OK || cmd & X_OK)
704 rslt = stat (tmpname, &st);
708 if ((((st.st_mode & 004) == 0) && (cmd & R_OK))
709 || (((st.st_mode & 002) == 0) && (cmd & W_OK))
710 || (((st.st_mode & 001) == 0) && (cmd & X_OK)))
719 fprintf (stderr, "# mpw_access (%s, %d)", tmpname, cmd);
720 fprintf (stderr, " -> %d", rslt);
722 fprintf (stderr, " (errno is %d)", errnum);
723 fprintf (stderr, "\n");
730 /* The MPW library creat() has no mode argument. */
733 mpw_creat (char *path, /* mode_t */ int mode)
737 #ifdef USE_MW_HEADERS
738 return creat (path, mode);
744 /* This is a hack to get control in an MPW tool before it crashes the
747 mpw_special_init (name)
750 if (strstr (name, "DEBUG"))
751 DebugStr("\pat beginning of program");
754 static int current_umask;
759 int oldmask = current_umask;
761 current_umask = mask;
765 /* Cursor-spinning stuff that includes metering of spin rate and delays. */
767 /* Nonzero when cursor spinning has been set up properly. */
771 /* Nonzero if spin should be measured and excessive delays reported. */
775 /* Nonzero if spin histogram and rate data should be written out. */
779 long warning_threshold = 400000;
781 long bucket_size = 1024;
783 long bucket_power = 10;
785 long numbuckets = 300;
791 char *current_progress;
793 static UnsignedWide last_microseconds;
795 static char *last_spin_file = "";
797 static int last_spin_line;
800 warn_if_spin_delay (char *file, int line)
807 diff = now.lo - last_microseconds.lo;
809 if (diff > warning_threshold)
810 fprintf (stderr, "# %s: %ld.%06ld sec delay getting from %s:%d to %s:%d\n",
811 (current_progress ? current_progress : ""),
812 diff / 1000000, diff % 1000000,
813 last_spin_file, last_spin_line, file, line);
818 ix = diff >> bucket_power;
819 if (ix >= 0 && ix < numbuckets && delay_counts != NULL)
825 fprintf (stderr, "raw diff is %ld (?)\n", diff);
830 record_for_spin_delay (char *file, int line)
832 Microseconds (&last_microseconds);
833 last_spin_file = file;
834 last_spin_line = line;
838 mpw_start_progress (char *str, int n, char *file, int line)
841 char *measure, *threshold;
847 record_for_spin_delay (file, line);
848 measure = getenv ("MEASURE_SPIN");
849 if (measure != NULL && measure[0] != '\0')
852 if (strcmp (measure, "all") == 0)
855 threshold = getenv ("SPIN_WARN_THRESHOLD");
856 if (threshold != NULL && threshold[0] != '\0')
857 warning_threshold = atol (threshold);
860 if (delay_counts == NULL)
861 delay_counts = (int *) malloc (numbuckets * sizeof (int));
862 for (i = 0; i < numbuckets; ++i)
867 current_progress = str;
869 sys_nerr = errno_max ();
871 mpw_special_init (str);
881 mpw_progress_measured (int n, char *file, int line)
884 warn_if_spin_delay (file, line);
887 record_for_spin_delay (file, line);
891 mpw_end_progress (char *str, char *file, int line)
893 long i, delay, count = 0, sum = 0, avgdelay, spinrate;
894 long curpower = 0, curgroup = 0;
896 /* Warn if it's been a while since the last spin. */
898 warn_if_spin_delay (file, line);
900 /* Dump all the nonzero delay counts and an approximation of the delay. */
901 if (dump_spin_data && delay_counts != NULL)
903 for (i = 0; i < numbuckets; ++i)
905 delay = (i + 1) * bucket_size;
906 sum += delay_counts[i] * (i + 1);
907 count += delay_counts[i];
908 if (delay <= (1 << curpower))
910 curgroup += delay_counts[i];
916 "# %s: %d delays between %ld.%06ld and %ld.%06ld sec\n",
919 (1 << curpower) / 1000000,
920 (1 << curpower) % 1000000,
921 (1 << (curpower + 1)) / 1000000,
922 (1 << (curpower + 1)) % 1000000);
929 avgdelay = (sum * bucket_size) / count;
930 spinrate = 1000000 / avgdelay;
931 fprintf (stderr, "# %s: Average spin rate is %d times/sec\n",
932 (str ? str : ""), spinrate);
944 double x = 1.0, y = 2.4;
945 long start = Microseconds (), tm; FIXME
947 START_PROGRESS ("hi", 0);
949 for (i = 0; i < 1000; ++i)
953 for (j = 0; j < (i * 100); ++j)
961 tm = Microseconds () - start;
963 printf ("Total time is %d.%d secs\n", tm / 1000000, tm % 1000000);
968 #ifdef USE_MW_HEADERS
969 /* Empty definitions for Metrowerks' SIOUX console library. */
976 InstallConsole(short fd)
988 WriteCharsToConsole(char *buf, long n)
990 #pragma unused (buf, n)
994 long ReadCharsFromConsole(char *buf, long n)
996 #pragma unused (buf, n)
1003 static char *__devicename = "null device";
1005 if (fd >= 0 && fd <= 2)
1006 return (__devicename);