]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/gdb/libiberty/mpw.c
This commit was generated by cvs2svn to compensate for changes in r38776,
[FreeBSD/FreeBSD.git] / contrib / gdb / libiberty / mpw.c
1 /* MPW-Unix compatibility library.
2    Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
3
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.
9
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.
14
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.  */
19
20 /* This should only be compiled and linked under MPW. */
21
22 #include "mpw.h"
23
24 #include <stdlib.h>
25
26 #ifndef USE_MW_HEADERS
27 #include <sys/time.h>
28 #include <sys/resource.h>
29 #endif
30
31 #include <Types.h>
32 #include <Files.h>
33
34 #include <Timer.h>
35
36 /* Initialize to 0 at first, then set to errno_max() later.  */
37
38 int sys_nerr = 0;
39
40 /* Debug flag for pathname hacking.  Set this to one and rebuild. */
41
42 int DebugPI = 0;
43
44 void
45 mpwify_filename(char *unixname, char *macname)
46 {
47   int i, j, in_middle, terminate = 0;
48
49   /* (should truncate 255 chars from end of name, not beginning) */
50   if (strlen (unixname) > 255)
51     {
52       fprintf (stderr, "Pathname \"%s\" is too long for Macs, truncating\n",
53                unixname);
54       terminate = 1;
55     }
56   /* Abs Unix path to abs Mac path. */
57   if (*unixname == '/')
58     {
59       if (strncmp (unixname, "/tmp/", 5) == 0)
60         {
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);
67           if (terminate)
68             macname[255] = '\0';
69           macname[0] = ':';
70           macname[4] = '_';
71         }
72       else
73         {
74           /* Assume that the leading component is a valid disk name. */
75           strncpy (macname, unixname + 1, 255);
76         }
77     }
78   else
79     {
80       /* If this is a "Unix-only" pathname, assume relative. */
81       if (strchr (unixname, '/') && ! strchr (unixname, ':'))
82         {
83           macname[0] = ':';
84           strncpy (macname + 1, unixname, 255);
85         }
86       else
87         {
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] == '/')
92             ++unixname;
93           strncpy (macname, unixname, 255);
94         }
95     }
96   if (terminate)
97     macname[255] = '\0';
98   for (i = 0; macname[i] != '\0'; ++i)
99     {
100       if (macname[i] == '/')
101         macname[i] = ':';
102     }
103   in_middle = 0;
104   j = 0;
105   for (i = 0; macname[i] != '\0'; ++i)
106     {
107       /* We're in the middle of the name when a char is not a colon. */
108       if (macname[i] != ':')
109         in_middle = 1;
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];
114     }
115   macname[j] = '\0';
116   /* If we have a trailing ":.", make it into a ":". */
117   if (j >= 2 && macname[j-2] == ':' && macname[j-1] == '.')
118     macname[j-1] = '\0';
119   if (DebugPI)
120     {
121       fprintf (stderr, "# Made \"%s\"\n", unixname);
122       fprintf (stderr, "# into \"%s\"\n", macname);
123     }
124 }
125
126 /* MPW-flavored basename finder. */
127
128 char *
129 mpw_basename (name)
130   char *name;
131 {
132   char *base = name;
133
134   while (*name)
135     {
136       if (*name++ == ':')
137         {
138           base = name;
139         }
140     }
141   return base;
142 }
143
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.  */
149
150 char *
151 mpw_mixed_basename (name)
152   char *name;
153 {
154   char *base = name;
155
156   while (*name)
157     {
158       if (*name == '/' || *name == ':')
159         {
160           base = name + 1;
161         }
162       ++name;
163     }
164   return base;
165 }
166
167 /* This function is fopen() modified to create files that are type TEXT
168    or 'BIN ', and always of type 'MPS '.  */
169
170 FILE *
171 mpw_fopen (char *name, char *mode)
172 {
173 #undef fopen
174   int errnum;
175   FILE *fp;
176   char tmpname[256];
177
178   mpwify_filename (name, tmpname);
179   PROGRESS (1);
180   fp = fopen (tmpname, mode);
181   errnum = errno;
182
183   /* If writing, need to set type and creator usefully. */
184   if (strchr (mode, 'w'))
185     {
186       char *pname = (char *) malloc (strlen (tmpname) + 2);
187       OSErr e;
188       struct FInfo fi;
189
190       pname[0] = strlen (tmpname);
191       strcpy (pname+1, tmpname);
192         
193       e = GetFInfo ((ConstStr255Param) pname, 0, &fi);
194       /* should do spiffier error handling */
195       if (e != 0)
196         fprintf(stderr, "GetFInfo returns %d\n", e);
197       if (strchr (mode, 'b'))
198         {
199           fi.fdType = (OSType) 'BIN ';
200         }
201       else
202         {
203           fi.fdType = (OSType) 'TEXT';
204         }
205       fi.fdCreator = (OSType) 'MPS ';
206       e = SetFInfo ((ConstStr255Param) pname, 0, &fi);
207       if (e != 0)
208         fprintf(stderr, "SetFInfo returns %d\n", e);
209       free (pname);
210     }
211   if (fp == NULL)
212     errno = errnum;
213   return fp;
214 }
215
216 /* This is a version of fseek() modified to fill the file with zeros
217    if seeking past the end of it.  */
218
219 #define ZEROBLKSIZE 4096
220
221 char zeros[ZEROBLKSIZE];
222
223 int
224 mpw_fseek (FILE *fp, int offset, int whence)
225 {
226 #undef fseek
227   int cursize, numleft;
228
229   PROGRESS (1);
230   if (whence == SEEK_SET)
231     {
232       fseek (fp, 0, SEEK_END);
233       cursize = ftell (fp);
234       if (offset > cursize)
235         {
236           numleft = offset - cursize;
237           while (numleft > ZEROBLKSIZE)
238             {
239               /* This might fail, should check for that. */
240               PROGRESS (1);
241               fwrite (zeros, 1, ZEROBLKSIZE, fp);
242               numleft -= ZEROBLKSIZE;
243             }
244           PROGRESS (1);
245           fwrite (zeros, 1, numleft, fp);
246           fflush (fp);
247         }
248     }
249   return fseek (fp, offset, whence);
250 }
251
252 int
253 mpw_fread (char *ptr, int size, int nitems, FILE *stream)
254 {
255 #undef fread
256   int rslt;
257
258   PROGRESS (1);
259   rslt = fread (ptr, size, nitems, stream);
260   PROGRESS (1);
261   return rslt;
262 }
263
264 int
265 mpw_fwrite (char *ptr, int size, int nitems, FILE *stream)
266 {
267 #undef fwrite
268   int rslt;
269
270   PROGRESS (1);
271   rslt = fwrite (ptr, size, nitems, stream);
272   PROGRESS (1);
273   return rslt;
274 }
275
276 int
277 link ()
278 {
279   fprintf (stderr, "link not available!\n");
280   mpw_abort ();
281 }
282
283 int
284 fork ()
285 {
286   fprintf (stderr, "fork not available!\n");
287   mpw_abort ();
288 }
289
290 int
291 vfork ()
292 {
293   fprintf (stderr, "vfork not available!\n");
294   mpw_abort ();
295   return (-1);
296 }
297
298 int
299 pipe (int *fd)
300 {
301   fprintf (stderr, "pipe not available!\n");
302   mpw_abort ();
303   return (-1);
304 }
305
306 #ifndef USE_MW_HEADERS
307 int
308 execvp (char *file, char **argv)
309 {
310   fprintf (stderr, "execvp not available!\n");
311   mpw_abort ();
312   return (-1);
313 }
314
315 int
316 execv (char *path, char **argv)
317 {
318   fprintf (stderr, "execv not available!\n");
319   mpw_abort ();
320   return (-1);
321 }
322 #endif
323
324 int
325 kill (int pid, int sig)
326 {
327   fprintf (stderr, "kill not available!\n");
328   mpw_abort ();
329   return (-1);
330 }
331
332 int
333 wait (int *status)
334 {
335   *status = 0;
336   return 0;
337 }
338
339 #ifndef USE_MW_HEADERS
340 int
341 sleep (int seconds)
342 {
343   unsigned long start_time, now;
344
345   time (&start_time);
346
347   while (1)
348     {
349       PROGRESS (1);
350       time (&now);
351       if (now > start_time + seconds)
352         return 0;
353     }
354 }
355 #endif
356
357 void
358 putenv (char *str)
359 {
360   /* The GCC driver calls this to do things for collect2, but we
361      don't care about collect2. */
362 }
363
364 int
365 chmod (char *path, int mode)
366 {
367   /* Pretend it was all OK. */
368   return 0;
369 }
370
371 #ifndef USE_MW_HEADERS
372 int
373 getuid ()
374 {
375   /* One value is as good as another... */
376   return 0;
377 }
378
379 int
380 getgid ()
381 {
382   /* One value is as good as another... */
383   return 0;
384 }
385 #endif
386
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
389    exit cleanly. */
390
391 void
392 mpw_abort ()
393 {
394   /* Make sure no output still buffered up, then zap into MacsBug. */
395   fflush(stdout);
396   fflush(stderr);
397   printf("## Abort! ##\n");
398 #ifdef MPW_SADE
399   SysError(8005);
400 #else 
401   Debugger();
402 #endif
403   /* "g" in MacsBug will then cause a regular error exit. */
404   exit (1);
405 }
406
407 /* Imitation getrusage based on the ANSI clock() function. */
408
409 int
410 getrusage (int who, struct rusage *rusage)
411 {
412   int clk = clock ();
413
414 #if 0
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;
419 #endif
420 }
421
422 int
423 sbrk ()
424 {
425   return 0;
426 }
427
428 #ifndef USE_MW_HEADERS
429 int
430 isatty (int fd)
431 {
432   return 0;
433 }
434
435 /* This is inherited from Timothy Murray's Posix library. */
436
437 #include "utime.h"
438
439 int
440 utime (char *filename, struct utimbuf *times)
441 {
442   CInfoPBRec cipbr;
443   HFileInfo *fpb = (HFileInfo *) &cipbr;
444   DirInfo *dpb = (DirInfo *) &cipbr;
445   unsigned char pname[256];
446   short err;
447   
448   strcpy ((char *) pname, filename);
449   c2pstr (pname);
450
451   dpb->ioDrDirID = 0L;
452   fpb->ioNamePtr = pname;
453   fpb->ioVRefNum = 0;
454   fpb->ioFDirIndex = 0;
455   fpb->ioFVersNum = 0;
456   err = PBGetCatInfo (&cipbr, 0);
457   if (err != noErr) {
458     errno = ENOENT;
459     return -1;
460   }
461   dpb->ioDrDirID = 0L;
462   fpb->ioFlMdDat = times->modtime;
463   fpb->ioFlCrDat = times->actime;
464   err = PBSetCatInfo (&cipbr, 0);
465   if (err != noErr) {
466     errno = EACCES;
467     return -1;
468   }
469   return 0;
470 }
471
472 int
473 mkdir (char *path, int mode)
474 {
475   errno = ENOSYS;
476   return -1;
477 }
478
479 int
480 rmdir ()
481 {
482   errno = ENOSYS;
483   return -1;
484 }
485 #endif
486
487 chown ()
488 {
489   errno = ENOSYS;
490   return -1;
491 }
492
493 char *myenviron[] = {NULL};
494
495 char **environ = myenviron;
496
497 #ifndef USE_MW_HEADERS
498
499 /* Minimal 'stat' emulation: tells directories from files and
500    gives length and mtime.
501
502    Derived from code written by Guido van Rossum, CWI, Amsterdam
503    and placed by him in the public domain.  */
504
505 extern int __uid, __gid;
506
507 int __uid = 0;
508 int __gid = 0;
509
510 /* Bits in ioFlAttrib: */
511 #define LOCKBIT (1<<0)          /* File locked */
512 #define DIRBIT  (1<<4)          /* It's a directory */
513
514 /* Macified "stat" in which filename is given relative to a directory,
515    specified by long DirID.  */
516
517 static int
518 _stat (char *name, long dirid, struct stat *buf)
519 {
520   CInfoPBRec cipbr;
521   HFileInfo *fpb = (HFileInfo*) &cipbr;
522   DirInfo *dpb = (DirInfo*) &cipbr;
523   Str255 pname;
524   short err;
525
526   /* Make a temp copy of the name and pascalize. */
527   strcpy ((char *) pname, name);
528   c2pstr (pname);
529   
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);
536   if (err != noErr)
537     {
538       errno = ENOENT;
539       return -1;
540     }
541   /* Mac files are readable if they can be accessed at all. */
542   buf->st_mode = 0444;
543   /* Mark unlocked files as writeable. */
544   if (!(fpb->ioFlAttrib & LOCKBIT))
545     buf->st_mode |= 0222;
546   if (fpb->ioFlAttrib & DIRBIT)
547     {
548       /* Mark directories as "executable". */
549       buf->st_mode |= 0111 | S_IFDIR;
550       buf->st_size = dpb->ioDrNmFls;
551       buf->st_rsize = 0;
552     }
553   else
554     {
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;
562     }
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);
571   buf->st_uid = __uid;
572   buf->st_gid = __gid;
573 /*  buf->st_FlFndrInfo = fpb->ioFlFndrInfo;  */
574   return 0;
575 }
576
577 /* stat() sets up an empty dirid. */
578
579 int
580 stat (char *path, struct stat *buf)
581 {
582   long rslt, errnum;
583   char tmpname[256];
584
585   mpwify_filename (path, tmpname);
586   if (DebugPI)
587     fprintf (stderr, "# stat (%s, %x)", tmpname, buf);
588   PROGRESS (1);
589   rslt = _stat (tmpname, 0L, buf);
590   errnum = errno;
591   if (DebugPI)
592     {
593       fprintf (stderr, " -> %d", rslt);
594       if (rslt != 0)
595         fprintf (stderr, " (errno is %d)", errnum);
596       fprintf (stderr, "\n");
597       fflush (stderr);
598     }
599   if (rslt != 0)
600     errno = errnum;
601   return rslt;
602 }
603
604 int
605 fstat (int fd, struct stat *buf)
606 {
607   FCBPBRec fcb;
608   FILE *fp;
609   Str255 pathname;
610   long dirid = 0L, temp;
611   long rslt, errnum;
612   short err;
613
614   if (DebugPI)
615     fprintf (stderr, "# fstat (%d, %x)", fd, buf);
616   PROGRESS (1);
617   pathname[0] = 0;
618 #ifdef FIOFNAME
619   /* Use an MPW-specific ioctl to get the pathname associated with
620      the file descriptor.  */
621   ioctl (fd, FIOFNAME, (long *) pathname); 
622 #else
623   you lose
624 #endif
625   if (DebugPI)
626     fprintf (stderr, " (name is %s)", pathname);
627   dirid = 0L /* fcb.ioFCBParID */ ;
628   rslt = _stat ((char *) pathname, dirid, buf);
629   errnum = errno;
630   if (DebugPI)
631     {
632       fprintf (stderr, " -> %d", rslt);
633       if (rslt != 0)
634         fprintf (stderr, " (errno is %d)", errnum);
635       fprintf (stderr, "\n");
636       fflush (stderr);
637     }
638   if (rslt != 0)
639     errno = errnum;
640   return rslt;
641 }
642
643 #endif /* n USE_MW_HEADERS */
644
645 chdir ()
646 {
647   errno = ENOSYS;
648   return (-1);
649 }
650
651 char *
652 getcwd (char *buf, int size)
653 {
654   if (buf == NULL)
655     buf = (char *) malloc (size);
656   strcpy(buf, ":");
657   return buf;
658 }
659
660 /* This should probably be more elaborate for MPW. */
661
662 char *
663 getpwd ()
664 {
665   return ":";
666 }
667
668 int
669 mpw_open (char *filename, int arg2, int arg3)
670 {
671 #undef open
672   int fd, errnum = 0;
673   char tmpname[256];
674
675   mpwify_filename (filename, tmpname);
676   fd = open (tmpname, arg2);
677   errnum = errno;
678
679   if (DebugPI)
680     {
681       fprintf (stderr, "# open (%s, %d, %d)", tmpname, arg2, arg3);
682       fprintf (stderr, " -> %d", fd);
683       if (fd == -1)
684         fprintf (stderr, " (errno is %d)", errnum);
685       fprintf (stderr, "\n");
686     }
687   if (fd == -1)
688     errno = errnum;
689   return fd;
690 }
691
692 int
693 mpw_access (char *filename, unsigned int cmd)
694 {
695 #undef access
696
697   int rslt, errnum = 0;
698   struct stat st;
699   char tmpname[256];
700
701   mpwify_filename (filename, tmpname);
702   if (cmd & R_OK || cmd & X_OK)
703     {
704       rslt = stat (tmpname, &st);
705       errnum = errno;
706       if (rslt >= 0)
707         {
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)))
711             {
712               rslt = -1;
713               errnum = EACCES;
714             }
715         }
716     }
717   if (DebugPI)
718     {
719       fprintf (stderr, "# mpw_access (%s, %d)", tmpname, cmd);
720       fprintf (stderr, " -> %d", rslt);
721       if (rslt != 0)
722         fprintf (stderr, " (errno is %d)", errnum);
723       fprintf (stderr, "\n");
724     }
725   if (rslt != 0)
726     errno = errnum;
727   return rslt;
728 }
729
730 /* The MPW library creat() has no mode argument. */
731
732 int
733 mpw_creat (char *path, /* mode_t */ int mode)
734 {
735 #undef creat
736
737 #ifdef USE_MW_HEADERS
738   return creat (path, mode);
739 #else
740   return creat (path);
741 #endif
742 }
743
744 /* This is a hack to get control in an MPW tool before it crashes the
745    machine.  */
746
747 mpw_special_init (name)
748      char *name;
749 {
750   if (strstr (name, "DEBUG"))
751     DebugStr("\pat beginning of program");
752 }
753
754 static int current_umask;
755
756 int
757 umask(int mask)
758 {
759   int oldmask = current_umask;
760
761   current_umask = mask;
762   return oldmask;
763 }
764
765 /* Cursor-spinning stuff that includes metering of spin rate and delays.  */
766
767 /* Nonzero when cursor spinning has been set up properly.  */
768
769 int cursor_inited;
770
771 /* Nonzero if spin should be measured and excessive delays reported.  */
772
773 int measure_spin;
774
775 /* Nonzero if spin histogram and rate data should be written out.  */
776
777 int dump_spin_data;
778
779 long warning_threshold = 400000;
780
781 long bucket_size = 1024;
782
783 long bucket_power = 10;
784
785 long numbuckets = 300;
786
787 int *delay_counts;
788
789 int overflow_count;
790
791 char *current_progress;
792
793 static UnsignedWide last_microseconds;
794
795 static char *last_spin_file = "";
796
797 static int last_spin_line;
798
799 void
800 warn_if_spin_delay (char *file, int line)
801 {
802   long diff, ix;
803   UnsignedWide now;
804
805   Microseconds(&now);
806
807   diff = now.lo - last_microseconds.lo;
808
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);
814   if (dump_spin_data)
815     {
816       if (diff >= 0)
817         {
818           ix = diff >> bucket_power;
819           if (ix >= 0 && ix < numbuckets && delay_counts != NULL)
820             ++delay_counts[ix];
821           else
822             ++overflow_count;
823         }
824       else
825         fprintf (stderr, "raw diff is %ld (?)\n", diff);
826     }
827 }
828
829 void
830 record_for_spin_delay (char *file, int line)
831 {
832   Microseconds (&last_microseconds);
833   last_spin_file = file;
834   last_spin_line = line;
835 }
836
837 void
838 mpw_start_progress (char *str, int n, char *file, int line)
839 {
840   int i;
841   char *measure, *threshold;
842
843   if (!cursor_inited)
844     {
845       InitCursorCtl (nil);
846       cursor_inited = 1;
847       record_for_spin_delay (file, line);
848       measure = getenv ("MEASURE_SPIN");
849       if (measure != NULL && measure[0] != '\0')
850         {
851           measure_spin = 1;
852           if (strcmp (measure, "all") == 0)
853             dump_spin_data = 1;
854         }
855       threshold = getenv ((const char *) "SPIN_WARN_THRESHOLD");
856       if (threshold != NULL && threshold[0] != '\0')
857         warning_threshold = atol (threshold);
858       if (dump_spin_data)
859         {
860           if (delay_counts == NULL)
861             delay_counts = (int *) malloc (numbuckets * sizeof (int));
862           for (i = 0; i < numbuckets; ++i)
863             delay_counts[i] = 0;
864           overflow_count = 0;
865         }
866     }
867   current_progress = str;
868
869   sys_nerr = errno_max ();
870
871   mpw_special_init (str);
872 }
873
874 void
875 mpw_progress (int n)
876 {
877   SpinCursor (32);
878 }
879
880 void
881 mpw_progress_measured (int n, char *file, int line)
882 {
883   if (measure_spin)
884     warn_if_spin_delay (file, line);
885   SpinCursor (32);
886   if (measure_spin)
887     record_for_spin_delay (file, line);
888 }
889
890 void
891 mpw_end_progress (char *str, char *file, int line)
892 {
893   long i, delay, count = 0, sum = 0, avgdelay, spinrate;
894   long curpower = 0, curgroup = 0;
895
896   /* Warn if it's been a while since the last spin.  */
897   if (measure_spin)
898     warn_if_spin_delay (file, line);
899
900   /* Dump all the nonzero delay counts and an approximation of the delay.  */
901   if (dump_spin_data && delay_counts != NULL)
902     {
903       for (i = 0; i < numbuckets; ++i)
904         {
905           delay = (i + 1) * bucket_size;
906           sum += delay_counts[i] * (i + 1);
907           count += delay_counts[i];
908           if (delay <= (1 << curpower))
909             {
910               curgroup += delay_counts[i];
911             }
912           else
913             {
914               if (curgroup > 0)
915                 fprintf (stderr,
916                          "# %s: %d delays between %ld.%06ld and %ld.%06ld sec\n",
917                          (str ? str : ""),
918                          curgroup,
919                          (1 << curpower) / 1000000,
920                          (1 << curpower) % 1000000,
921                          (1 << (curpower + 1)) / 1000000,
922                          (1 << (curpower + 1)) % 1000000);
923               ++curpower;
924               curgroup = 0;
925             }
926         }
927       if (count > 0)
928         {
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);
933         }
934     }
935 }
936
937 #ifdef PROGRESS_TEST
938
939 /* Test program.  */
940
941 main ()
942 {
943   int i, j;
944   double x = 1.0, y = 2.4;
945   long start = Microseconds (), tm;  FIXME
946
947   START_PROGRESS ("hi", 0);
948
949   for (i = 0; i < 1000; ++i)
950     {
951       PROGRESS (1);
952
953       for (j = 0; j < (i * 100); ++j)
954         {
955           x += (x * y) / j;
956         }
957     }
958   
959   END_PROGRESS ("hi");
960   
961   tm = Microseconds () - start;
962
963   printf ("Total time is %d.%d secs\n", tm / 1000000, tm % 1000000);
964 }
965
966 #endif
967
968 #ifdef USE_MW_HEADERS
969 /* Empty definitions for Metrowerks' SIOUX console library. */
970
971 #ifndef __CONSOLE__
972 #include <console.h>
973 #endif
974
975 short
976 InstallConsole(short fd)
977 {
978 #pragma unused (fd)
979         return 0;
980 }
981
982 void
983 RemoveConsole(void)
984 {
985 }
986
987 long
988 WriteCharsToConsole(char *buf, long n)
989 {
990 #pragma unused (buf, n)
991         return 0;
992 }
993
994 long ReadCharsFromConsole(char *buf, long n)
995 {
996 #pragma unused (buf, n)
997         return 0;
998 }
999
1000 extern char *
1001 __ttyname(long fd)
1002 {
1003         static char *__devicename = "null device";
1004
1005         if (fd >= 0 && fd <= 2)
1006           return (__devicename);
1007         return NULL;
1008 }
1009
1010 #endif