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);