home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 March / PCWK3A99.iso / Linux / DDD331 / DDD-3_1_.000 / DDD-3_1_ / ddd-3.1.1 / libiberty / mpw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-12-15  |  19.4 KB  |  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 = -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.      a 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
  1011.