* doc/internals.texi (Relaxing with a table) <after relaxation>:
[external/binutils.git] / 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 = -1;
43
44 void
45 mpwify_filename(char *unixname, char *macname)
46 {
47   int i, j;
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     }
55   j = 0;
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
59      a disk name.  */
60   if (unixname[0] != '/' && ! strchr (unixname, ':') && strchr (unixname, '/'))
61     {
62       macname[j++] = ':';
63     }
64   for (i = 0; unixname[i] != '\0' && i < 255; ++i)
65     {
66       if (i == 0 && unixname[i] == '/')
67         {
68           if (strncmp (unixname, "/tmp/", 5) == 0)
69             {
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
75                  at a ramdisk. */
76               macname[j++] = ':';
77               macname[j++] = 't';
78               macname[j++] = 'm';
79               macname[j++] = 'p';
80               macname[j++] = '_';
81               i += 4;
82             }
83           else
84             {
85               /* Don't copy the leading slash. */
86             }
87         }
88       else if (unixname[i] == ':' && unixname[i+1] == '/')
89         {
90           macname[j++] = ':';
91           i += 1;
92         }
93       else if (unixname[i] == '.' && unixname[i+1] == '/')
94         {
95           macname[j++] = ':';
96           i += 1;
97         }
98       else if (unixname[i] == '.' && unixname[i+1] == '.' && unixname[i+2] == '/')
99         {
100           macname[j++] = ':';
101           macname[j++] = ':';
102           i += 2;
103         }
104       else if (unixname[i] == '/')
105         {
106           macname[j++] = ':';
107         }
108       else
109         {
110           macname[j++] = unixname[i];
111         }
112     }
113   macname[j] = '\0';
114   /* Allow for getting the debug flag from an env var; quite useful. */
115   if (DebugPI < 0)
116     DebugPI = (*(getenv ("DEBUG_PATHNAMES")) == '1' ? 1 : 0);
117   if (DebugPI)
118     {
119       fprintf (stderr, "# Made \"%s\"\n", unixname);
120       fprintf (stderr, "# into \"%s\"\n", macname);
121     }
122 }
123
124 /* MPW-flavored basename finder. */
125
126 char *
127 mpw_basename (name)
128   char *name;
129 {
130   char *base = name;
131
132   while (*name)
133     {
134       if (*name++ == ':')
135         {
136           base = name;
137         }
138     }
139   return base;
140 }
141
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.  */
147
148 char *
149 mpw_mixed_basename (name)
150   char *name;
151 {
152   char *base = name;
153
154   while (*name)
155     {
156       if (*name == '/' || *name == ':')
157         {
158           base = name + 1;
159         }
160       ++name;
161     }
162   return base;
163 }
164
165 /* This function is fopen() modified to create files that are type TEXT
166    or 'BIN ', and always of type 'MPS '.  */
167
168 FILE *
169 mpw_fopen (char *name, char *mode)
170 {
171 #undef fopen
172   int errnum;
173   FILE *fp;
174   char tmpname[256];
175
176   mpwify_filename (name, tmpname);
177   PROGRESS (1);
178   fp = fopen (tmpname, mode);
179   errnum = errno;
180
181   /* If writing, need to set type and creator usefully. */
182   if (strchr (mode, 'w'))
183     {
184       char *pname = (char *) malloc (strlen (tmpname) + 2);
185       OSErr e;
186       struct FInfo fi;
187
188       pname[0] = strlen (tmpname);
189       strcpy (pname+1, tmpname);
190         
191       e = GetFInfo ((ConstStr255Param) pname, 0, &fi);
192       /* should do spiffier error handling */
193       if (e != 0)
194         fprintf(stderr, "GetFInfo returns %d\n", e);
195       if (strchr (mode, 'b'))
196         {
197           fi.fdType = (OSType) 'BIN ';
198         }
199       else
200         {
201           fi.fdType = (OSType) 'TEXT';
202         }
203       fi.fdCreator = (OSType) 'MPS ';
204       e = SetFInfo ((ConstStr255Param) pname, 0, &fi);
205       if (e != 0)
206         fprintf(stderr, "SetFInfo returns %d\n", e);
207       free (pname);
208     }
209   if (fp == NULL)
210     errno = errnum;
211   return fp;
212 }
213
214 /* This is a version of fseek() modified to fill the file with zeros
215    if seeking past the end of it.  */
216
217 #define ZEROBLKSIZE 4096
218
219 char zeros[ZEROBLKSIZE];
220
221 int
222 mpw_fseek (FILE *fp, int offset, int whence)
223 {
224 #undef fseek
225   int cursize, numleft;
226
227   PROGRESS (1);
228   if (whence == SEEK_SET)
229     {
230       fseek (fp, 0, SEEK_END);
231       cursize = ftell (fp);
232       if (offset > cursize)
233         {
234           numleft = offset - cursize;
235           while (numleft > ZEROBLKSIZE)
236             {
237               /* This might fail, should check for that. */
238               PROGRESS (1);
239               fwrite (zeros, 1, ZEROBLKSIZE, fp);
240               numleft -= ZEROBLKSIZE;
241             }
242           PROGRESS (1);
243           fwrite (zeros, 1, numleft, fp);
244           fflush (fp);
245         }
246     }
247   return fseek (fp, offset, whence);
248 }
249
250 int
251 mpw_fread (char *ptr, int size, int nitems, FILE *stream)
252 {
253 #undef fread
254   int rslt;
255
256   PROGRESS (1);
257   rslt = fread (ptr, size, nitems, stream);
258   PROGRESS (1);
259   return rslt;
260 }
261
262 int
263 mpw_fwrite (char *ptr, int size, int nitems, FILE *stream)
264 {
265 #undef fwrite
266   int rslt;
267
268   PROGRESS (1);
269   rslt = fwrite (ptr, size, nitems, stream);
270   PROGRESS (1);
271   return rslt;
272 }
273
274 int
275 link ()
276 {
277   fprintf (stderr, "link not available!\n");
278   mpw_abort ();
279 }
280
281 int
282 fork ()
283 {
284   fprintf (stderr, "fork not available!\n");
285   mpw_abort ();
286 }
287
288 int
289 vfork ()
290 {
291   fprintf (stderr, "vfork not available!\n");
292   mpw_abort ();
293   return (-1);
294 }
295
296 int
297 pipe (int *fd)
298 {
299   fprintf (stderr, "pipe not available!\n");
300   mpw_abort ();
301   return (-1);
302 }
303
304 #ifndef USE_MW_HEADERS
305 int
306 execvp (char *file, char **argv)
307 {
308   fprintf (stderr, "execvp not available!\n");
309   mpw_abort ();
310   return (-1);
311 }
312
313 int
314 execv (char *path, char **argv)
315 {
316   fprintf (stderr, "execv not available!\n");
317   mpw_abort ();
318   return (-1);
319 }
320 #endif
321
322 int
323 kill (int pid, int sig)
324 {
325   fprintf (stderr, "kill not available!\n");
326   mpw_abort ();
327   return (-1);
328 }
329
330 int
331 wait (int *status)
332 {
333   *status = 0;
334   return 0;
335 }
336
337 #ifndef USE_MW_HEADERS
338 int
339 sleep (int seconds)
340 {
341   unsigned long start_time, now;
342
343   time (&start_time);
344
345   while (1)
346     {
347       PROGRESS (1);
348       time (&now);
349       if (now > start_time + seconds)
350         return 0;
351     }
352 }
353 #endif
354
355 void
356 putenv (char *str)
357 {
358   /* The GCC driver calls this to do things for collect2, but we
359      don't care about collect2. */
360 }
361
362 int
363 chmod (char *path, int mode)
364 {
365   /* Pretend it was all OK. */
366   return 0;
367 }
368
369 #ifndef USE_MW_HEADERS
370 int
371 getuid ()
372 {
373   /* One value is as good as another... */
374   return 0;
375 }
376
377 int
378 getgid ()
379 {
380   /* One value is as good as another... */
381   return 0;
382 }
383 #endif
384
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
387    exit cleanly. */
388
389 void
390 mpw_abort ()
391 {
392   /* Make sure no output still buffered up, then zap into MacsBug. */
393   fflush(stdout);
394   fflush(stderr);
395   printf("## Abort! ##\n");
396 #ifdef MPW_SADE
397   SysError(8005);
398 #else 
399   Debugger();
400 #endif
401   /* "g" in MacsBug will then cause a regular error exit. */
402   exit (1);
403 }
404
405 /* Imitation getrusage based on the ANSI clock() function. */
406
407 int
408 getrusage (int who, struct rusage *rusage)
409 {
410   int clk = clock ();
411
412 #if 0
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;
417 #endif
418 }
419
420 int
421 sbrk ()
422 {
423   return 0;
424 }
425
426 #ifndef USE_MW_HEADERS
427 int
428 isatty (int fd)
429 {
430   return 0;
431 }
432
433 /* This is inherited from Timothy Murray's Posix library. */
434
435 #include "utime.h"
436
437 int
438 utime (char *filename, struct utimbuf *times)
439 {
440   CInfoPBRec cipbr;
441   HFileInfo *fpb = (HFileInfo *) &cipbr;
442   DirInfo *dpb = (DirInfo *) &cipbr;
443   unsigned char pname[256];
444   short err;
445   
446   strcpy ((char *) pname, filename);
447   c2pstr (pname);
448
449   dpb->ioDrDirID = 0L;
450   fpb->ioNamePtr = pname;
451   fpb->ioVRefNum = 0;
452   fpb->ioFDirIndex = 0;
453   fpb->ioFVersNum = 0;
454   err = PBGetCatInfo (&cipbr, 0);
455   if (err != noErr) {
456     errno = ENOENT;
457     return -1;
458   }
459   dpb->ioDrDirID = 0L;
460   fpb->ioFlMdDat = times->modtime;
461   fpb->ioFlCrDat = times->actime;
462   err = PBSetCatInfo (&cipbr, 0);
463   if (err != noErr) {
464     errno = EACCES;
465     return -1;
466   }
467   return 0;
468 }
469
470 int
471 mkdir (char *path, int mode)
472 {
473   errno = ENOSYS;
474   return -1;
475 }
476
477 int
478 rmdir ()
479 {
480   errno = ENOSYS;
481   return -1;
482 }
483 #endif
484
485 chown ()
486 {
487   errno = ENOSYS;
488   return -1;
489 }
490
491 char *myenviron[] = {NULL};
492
493 char **environ = myenviron;
494
495 #ifndef USE_MW_HEADERS
496
497 /* Minimal 'stat' emulation: tells directories from files and
498    gives length and mtime.
499
500    Derived from code written by Guido van Rossum, CWI, Amsterdam
501    and placed by him in the public domain.  */
502
503 extern int __uid, __gid;
504
505 int __uid = 0;
506 int __gid = 0;
507
508 /* Bits in ioFlAttrib: */
509 #define LOCKBIT (1<<0)          /* File locked */
510 #define DIRBIT  (1<<4)          /* It's a directory */
511
512 /* Macified "stat" in which filename is given relative to a directory,
513    specified by long DirID.  */
514
515 static int
516 _stat (char *name, long dirid, struct stat *buf)
517 {
518   CInfoPBRec cipbr;
519   HFileInfo *fpb = (HFileInfo*) &cipbr;
520   DirInfo *dpb = (DirInfo*) &cipbr;
521   Str255 pname;
522   short err;
523
524   /* Make a temp copy of the name and pascalize. */
525   strcpy ((char *) pname, name);
526   c2pstr (pname);
527   
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);
534   if (err != noErr)
535     {
536       errno = ENOENT;
537       return -1;
538     }
539   /* Mac files are readable if they can be accessed at all. */
540   buf->st_mode = 0444;
541   /* Mark unlocked files as writeable. */
542   if (!(fpb->ioFlAttrib & LOCKBIT))
543     buf->st_mode |= 0222;
544   if (fpb->ioFlAttrib & DIRBIT)
545     {
546       /* Mark directories as "executable". */
547       buf->st_mode |= 0111 | S_IFDIR;
548       buf->st_size = dpb->ioDrNmFls;
549       buf->st_rsize = 0;
550     }
551   else
552     {
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;
560     }
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);
569   buf->st_uid = __uid;
570   buf->st_gid = __gid;
571 /*  buf->st_FlFndrInfo = fpb->ioFlFndrInfo;  */
572   return 0;
573 }
574
575 /* stat() sets up an empty dirid. */
576
577 int
578 stat (char *path, struct stat *buf)
579 {
580   long rslt, errnum;
581   char tmpname[256];
582
583   mpwify_filename (path, tmpname);
584   if (DebugPI)
585     fprintf (stderr, "# stat (%s, %x)", tmpname, buf);
586   PROGRESS (1);
587   rslt = _stat (tmpname, 0L, buf);
588   errnum = errno;
589   if (DebugPI)
590     {
591       fprintf (stderr, " -> %d", rslt);
592       if (rslt != 0)
593         fprintf (stderr, " (errno is %d)", errnum);
594       fprintf (stderr, "\n");
595       fflush (stderr);
596     }
597   if (rslt != 0)
598     errno = errnum;
599   return rslt;
600 }
601
602 int
603 fstat (int fd, struct stat *buf)
604 {
605   FCBPBRec fcb;
606   FILE *fp;
607   Str255 pathname;
608   long dirid = 0L, temp;
609   long rslt, errnum;
610   short err;
611
612   if (DebugPI < 0)
613     DebugPI = (*(getenv ("DEBUG_PATHNAMES")) == '1' ? 1 : 0);
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 ("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