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)
47 int i, j, in_middle, terminate = 0;
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 /* Abs Unix path to abs Mac path. */
59 if (strncmp (unixname, "/tmp/", 5) == 0)
61 /* A temporary name, make a more Mac-flavored tmpname. */
62 /* A better choice would be {Boot}Trash:foo, but that would
63 require being able to identify the boot disk's and trashcan's
64 name. Another option would be to have an env var, so user
65 can point it at a ramdisk. */
66 strncpy (macname, unixname, 255);
74 /* Assume that the leading component is a valid disk name. */
75 strncpy (macname, unixname + 1, 255);
80 /* If this is a "Unix-only" pathname, assume relative. */
81 if (strchr (unixname, '/') && ! strchr (unixname, ':'))
84 strncpy (macname + 1, unixname, 255);
88 /* Otherwise copy it verbatim. */
89 /* ... but if of the form ":/foo", lose the extra colon;
90 the slash will be made into a colon shortly. */
91 if (unixname[0] == ':' && unixname[1] == '/')
93 strncpy (macname, unixname, 255);
98 for (i = 0; macname[i] != '\0'; ++i)
100 if (macname[i] == '/')
105 for (i = 0; macname[i] != '\0'; ++i)
107 /* We're in the middle of the name when a char is not a colon. */
108 if (macname[i] != ':')
110 /* Copy chars verbatim, *unless* the char is the first of a pair
111 of colons in the middle of a pathname. */
112 if (!(in_middle && macname[i] == ':' && macname[i+1] == ':'))
113 macname[j++] = macname[i];
116 /* If we have a trailing ":.", make it into a ":". */
117 if (j >= 2 && macname[j-2] == ':' && macname[j-1] == '.')
121 fprintf (stderr, "# Made \"%s\"\n", unixname);
122 fprintf (stderr, "# into \"%s\"\n", macname);
126 /* MPW-flavored basename finder. */
144 /* Mixed MPW/Unix basename finder. This can be led astray by
145 filenames with slashes in them and come up with a basename that
146 either corresponds to no file or (worse) to some other file, so
147 should only be tried if other methods of finding a file via a
148 basename have failed. */
151 mpw_mixed_basename (name)
158 if (*name == '/' || *name == ':')
167 /* This function is fopen() modified to create files that are type TEXT
168 or 'BIN ', and always of type 'MPS '. */
171 mpw_fopen (char *name, char *mode)
178 mpwify_filename (name, tmpname);
180 fp = fopen (tmpname, mode);
183 /* If writing, need to set type and creator usefully. */
184 if (strchr (mode, 'w'))
186 char *pname = (char *) malloc (strlen (tmpname) + 2);
190 pname[0] = strlen (tmpname);
191 strcpy (pname+1, tmpname);
193 e = GetFInfo ((ConstStr255Param) pname, 0, &fi);
194 /* should do spiffier error handling */
196 fprintf(stderr, "GetFInfo returns %d\n", e);
197 if (strchr (mode, 'b'))
199 fi.fdType = (OSType) 'BIN ';
203 fi.fdType = (OSType) 'TEXT';
205 fi.fdCreator = (OSType) 'MPS ';
206 e = SetFInfo ((ConstStr255Param) pname, 0, &fi);
208 fprintf(stderr, "SetFInfo returns %d\n", e);
216 /* This is a version of fseek() modified to fill the file with zeros
217 if seeking past the end of it. */
219 #define ZEROBLKSIZE 4096
221 char zeros[ZEROBLKSIZE];
224 mpw_fseek (FILE *fp, int offset, int whence)
227 int cursize, numleft;
230 if (whence == SEEK_SET)
232 fseek (fp, 0, SEEK_END);
233 cursize = ftell (fp);
234 if (offset > cursize)
236 numleft = offset - cursize;
237 while (numleft > ZEROBLKSIZE)
239 /* This might fail, should check for that. */
241 fwrite (zeros, 1, ZEROBLKSIZE, fp);
242 numleft -= ZEROBLKSIZE;
245 fwrite (zeros, 1, numleft, fp);
249 return fseek (fp, offset, whence);
253 mpw_fread (char *ptr, int size, int nitems, FILE *stream)
259 rslt = fread (ptr, size, nitems, stream);
265 mpw_fwrite (char *ptr, int size, int nitems, FILE *stream)
271 rslt = fwrite (ptr, size, nitems, stream);
279 fprintf (stderr, "link not available!\n");
286 fprintf (stderr, "fork not available!\n");
293 fprintf (stderr, "vfork not available!\n");
301 fprintf (stderr, "pipe not available!\n");
306 #ifndef USE_MW_HEADERS
308 execvp (char *file, char **argv)
310 fprintf (stderr, "execvp not available!\n");
316 execv (char *path, char **argv)
318 fprintf (stderr, "execv not available!\n");
325 kill (int pid, int sig)
327 fprintf (stderr, "kill not available!\n");
339 #ifndef USE_MW_HEADERS
343 unsigned long start_time, now;
351 if (now > start_time + seconds)
360 /* The GCC driver calls this to do things for collect2, but we
361 don't care about collect2. */
365 chmod (char *path, int mode)
367 /* Pretend it was all OK. */
371 #ifndef USE_MW_HEADERS
375 /* One value is as good as another... */
382 /* One value is as good as another... */
387 /* Instead of coredumping, which is not a normal Mac facility, we
388 drop into Macsbug. If we then "g" from Macsbug, the program will
394 /* Make sure no output still buffered up, then zap into MacsBug. */
397 printf("## Abort! ##\n");
403 /* "g" in MacsBug will then cause a regular error exit. */
407 /* Imitation getrusage based on the ANSI clock() function. */
410 getrusage (int who, struct rusage *rusage)
415 rusage->ru_utime.tv_sec = clk / CLOCKS_PER_SEC;
416 rusage->ru_utime.tv_usec = ((clk * 1000) / CLOCKS_PER_SEC) * 1000;
417 rusage->ru_stime.tv_sec = 0;
418 rusage->ru_stime.tv_usec = 0;
428 #ifndef USE_MW_HEADERS
435 /* This is inherited from Timothy Murray's Posix library. */
440 utime (char *filename, struct utimbuf *times)
443 HFileInfo *fpb = (HFileInfo *) &cipbr;
444 DirInfo *dpb = (DirInfo *) &cipbr;
445 unsigned char pname[256];
448 strcpy ((char *) pname, filename);
452 fpb->ioNamePtr = pname;
454 fpb->ioFDirIndex = 0;
456 err = PBGetCatInfo (&cipbr, 0);
462 fpb->ioFlMdDat = times->modtime;
463 fpb->ioFlCrDat = times->actime;
464 err = PBSetCatInfo (&cipbr, 0);
473 mkdir (char *path, int mode)
493 char *myenviron[] = {NULL};
495 char **environ = myenviron;
497 #ifndef USE_MW_HEADERS
499 /* Minimal 'stat' emulation: tells directories from files and
500 gives length and mtime.
502 Derived from code written by Guido van Rossum, CWI, Amsterdam
503 and placed by him in the public domain. */
505 extern int __uid, __gid;
510 /* Bits in ioFlAttrib: */
511 #define LOCKBIT (1<<0) /* File locked */
512 #define DIRBIT (1<<4) /* It's a directory */
514 /* Macified "stat" in which filename is given relative to a directory,
515 specified by long DirID. */
518 _stat (char *name, long dirid, struct stat *buf)
521 HFileInfo *fpb = (HFileInfo*) &cipbr;
522 DirInfo *dpb = (DirInfo*) &cipbr;
526 /* Make a temp copy of the name and pascalize. */
527 strcpy ((char *) pname, name);
530 cipbr.dirInfo.ioDrDirID = dirid;
531 cipbr.hFileInfo.ioNamePtr = pname;
532 cipbr.hFileInfo.ioVRefNum = 0;
533 cipbr.hFileInfo.ioFDirIndex = 0;
534 cipbr.hFileInfo.ioFVersNum = 0;
535 err = PBGetCatInfo (&cipbr, 0);
541 /* Mac files are readable if they can be accessed at all. */
543 /* Mark unlocked files as writeable. */
544 if (!(fpb->ioFlAttrib & LOCKBIT))
545 buf->st_mode |= 0222;
546 if (fpb->ioFlAttrib & DIRBIT)
548 /* Mark directories as "executable". */
549 buf->st_mode |= 0111 | S_IFDIR;
550 buf->st_size = dpb->ioDrNmFls;
555 buf->st_mode |= S_IFREG;
556 /* Mark apps as "executable". */
557 if (fpb->ioFlFndrInfo.fdType == 'APPL')
558 buf->st_mode |= 0111;
559 /* Fill in the sizes of data and resource forks. */
560 buf->st_size = fpb->ioFlLgLen;
561 buf->st_rsize = fpb->ioFlRLgLen;
563 /* Fill in various times. */
564 buf->st_atime = fpb->ioFlCrDat;
565 buf->st_mtime = fpb->ioFlMdDat;
566 buf->st_ctime = fpb->ioFlCrDat;
567 /* Set up an imitation inode number. */
568 buf->st_ino = (unsigned short) fpb->ioDirID;
569 /* Set up an imitation device. */
570 GetVRefNum (buf->st_ino, &buf->st_dev);
573 /* buf->st_FlFndrInfo = fpb->ioFlFndrInfo; */
577 /* stat() sets up an empty dirid. */
580 stat (char *path, struct stat *buf)
585 mpwify_filename (path, tmpname);
587 fprintf (stderr, "# stat (%s, %x)", tmpname, buf);
589 rslt = _stat (tmpname, 0L, buf);
593 fprintf (stderr, " -> %d", rslt);
595 fprintf (stderr, " (errno is %d)", errnum);
596 fprintf (stderr, "\n");
605 fstat (int fd, struct stat *buf)
610 long dirid = 0L, temp;
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 ((const char *) "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);