home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gdb-4.16-base.tgz / gdb-4.16-base.tar / fsf / gdb / libiberty / mpw.c < prev    next >
C/C++ Source or Header  |  1996-03-07  |  20KB  |  1,011 lines

  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
  1011.