home *** CD-ROM | disk | FTP | other *** search
/ ftp.whtech.com / ftp.whtech.com.7z / ftp.whtech.com / emulators / v9t9 / linux / sources / V9t9 / source / OSLib / MacOS.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-10-19  |  29.0 KB  |  1,590 lines

  1.  
  2. /*
  3.  *    Operating system library for Macintosh.
  4.  *
  5.  *    This module handles interaction with the operating-system specific
  6.  *    intricacies with file manipulation, memory management, process
  7.  *    spawning, etc.
  8.  *
  9.  */
  10.  
  11. #if (defined(POSIX_FS) || defined(WIN32_FS)) && !defined(MAC_FS)
  12. #error Wrong module!
  13. #endif
  14.  
  15. #include "OSLib.h"
  16. #include "StringUtils.h"
  17.  
  18. #include <string.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #if __MWERKS__
  22. #include <alloca.h>
  23. #else
  24. #include <malloc.h>
  25. #endif
  26. #include <stdlib.h>
  27. #include <ctype.h>
  28.  
  29. #include <assert.h>
  30.  
  31. /* Universal headers */
  32. #include <MacTypes.h>
  33. #include <Files.h>
  34. #include <Aliases.h>
  35. #include <Errors.h>
  36. #include <Script.h>
  37. #include <TextUtils.h>
  38. #include <Gestalt.h>
  39. #include <LowMem.h>
  40.  
  41. #if defined(UNDER_MPW)
  42.  
  43. /*  MPW includes */
  44. #include <ErrMgr.h>
  45. #include <CursorCtl.h>
  46. #include <IntEnv.h>
  47. #endif
  48.  
  49. //#define DEBUG 1
  50.  
  51. #if DEBUG
  52. #define ASSERT(x)     assert(x)
  53. #else
  54. #define ASSERT(x)
  55. #endif
  56.  
  57. /*    System state variables  */
  58. static Boolean systemHandles;
  59. static Boolean aliasAvail;
  60.  
  61.  
  62. /*  I wrote these to learn the OS  */
  63.  
  64. static      OSErr
  65. CanonicalizeIfDirectory(FSSpec * fss)
  66. {
  67.     CInfoPBRec  pb;
  68.     OSErr       err;
  69.  
  70.     pb.hFileInfo.ioNamePtr = fss->name;
  71.     pb.hFileInfo.ioVRefNum = fss->vRefNum;
  72.     pb.hFileInfo.ioFDirIndex = 0;    /* get file info */
  73.     pb.hFileInfo.ioDirID = fss->parID;
  74.     err = PBGetCatInfoSync(&pb);
  75.     if (err == noErr && (pb.hFileInfo.ioFlAttrib & 0x10)) {
  76.         fss->parID = pb.dirInfo.ioDrDirID;
  77.         *fss->name = 0;
  78.     } else if (err == paramErr)
  79.         err = noErr;
  80.  
  81.     return err;
  82. }
  83.  
  84. #if !defined(UNDER_MPW)
  85.  
  86. static      OSErr
  87. ResolveFSSpec(short vRefNum, long dirID, Str255 name,
  88.               Boolean resolveLeafAlias, FSSpec * fss,
  89.               Boolean * isFolder, Boolean * hadAlias, Boolean * leafIsAlias)
  90. {
  91.     int         idx;
  92.     OSErr       err;
  93.  
  94.     *isFolder = 0;
  95.     *hadAlias = 0;
  96.  
  97.     if (!aliasAvail) {
  98.         *leafIsAlias = 0;
  99.         *hadAlias = 0;
  100.         *isFolder = 0;
  101.         err = FSMakeFSSpec(vRefNum, dirID, name, fss);
  102.         if (*fss->name) {
  103.             err = CanonicalizeIfDirectory(fss);
  104.             if (err == noErr && *fss->name == 0)
  105.                 *isFolder = 1;
  106.         } else if (err == noErr)
  107.             *isFolder = 1;
  108.         return err;
  109.     } else {
  110.         idx = 0;
  111.         while (idx < name[0]) {
  112.             Str255      outname;
  113.  
  114.             *leafIsAlias = 0;
  115.             outname[0] = 0;
  116.  
  117.             /*  Get next path component, either a name or a series of ':'s */
  118.             if (name[idx + 1] == ':') {
  119.                 /*  Skip the first colon */
  120.                 idx++;
  121.                 while (idx < name[0] && name[idx + 1] == ':')
  122.                     outname[++outname[0]] = name[++idx];
  123.             } else
  124.                 while (idx < name[0] && name[idx + 1] != ':')
  125.                     outname[++outname[0]] = name[++idx];
  126.  
  127. #ifdef DEBUG
  128.             p2cstr(outname);
  129.             printf("Component is '%s'\n", (char *) outname);
  130.             c2pstr((char *) outname);
  131. #endif
  132.  
  133.             err = FSMakeFSSpec(vRefNum, dirID, outname, fss);
  134.             if (err != noErr) {
  135.                 /*  ugly: it we were passed a full path, this may have
  136.                    failed on the volume.  Need to append ':'.  
  137.                    Unfortunately, this couldn't be done above, because
  138.                    aliased files would trigger an error if the colon
  139.                    were present.
  140.                  */
  141.  
  142.                 if (idx < name[0]) {
  143.                     outname[++outname[0]] = ':';
  144.                     err = FSMakeFSSpec(vRefNum, dirID, outname, fss);
  145.                     if (err != noErr)
  146.                         return err;
  147.                 } else
  148.                     return err;
  149.             }
  150.  
  151.             /*  See if component is an alias */
  152.             err = ResolveAliasFile(fss, 1, isFolder, leafIsAlias);
  153.             if (err != noErr)
  154.                 return err;
  155.  
  156.  
  157.             if (*leafIsAlias)
  158.                 *hadAlias = 1;
  159.  
  160. #ifdef DEBUG
  161.             if (*leafIsAlias) {
  162.                 p2cstr(fss->name);
  163.                 printf("Component was an alias (--> '%s')\n",
  164.                        (char *) fss->name);
  165.                 c2pstr((char *) fss->name);
  166.             } else
  167.                 printf("Component was not an alias.\n");
  168. #endif
  169.  
  170.             /*  If it's a directory, go to it */
  171.             if (outname[0]) {
  172.                 if (*isFolder && outname[1] != ':')
  173.                     err = CanonicalizeIfDirectory(fss);
  174.  
  175.                 vRefNum = fss->vRefNum;
  176.                 dirID = fss->parID;
  177.             }
  178.  
  179.             /*  we should be done if *isFolder was not set */
  180.             if (!*isFolder && idx < name[0])
  181.                 return dirNFErr;
  182.         }
  183.     }
  184.     return err;
  185. }
  186.  
  187.  
  188. static      OSErr
  189. MakeResolvedFSSpec(short vRefNum, long dirID, Str255 name, FSSpec * fss,
  190.                    Boolean * isFolder, Boolean * hadAlias,
  191.                    Boolean * leafIsAlias)
  192. {
  193.     OSErr       err;
  194.     CInfoPBRec  pb;
  195.  
  196.     *hadAlias = 0;
  197.     *leafIsAlias = 0;
  198.  
  199.     /*  hope for easy case  */
  200.     err = FSMakeFSSpec(vRefNum, dirID, name, fss);
  201.  
  202.     if (err == noErr) {
  203.         if (aliasAvail) {
  204. #ifdef DEBUG
  205.             printf("FSMakeFSSpec succeeded, trying ResolveAliasFile\n");
  206. #endif
  207.  
  208.             err = ResolveAliasFile(fss, 1, isFolder, leafIsAlias);
  209.             if (err == noErr) {
  210.  
  211. #ifdef DEBUG
  212.                 if (*leafIsAlias)
  213.                     printf("Had a leaf alias\n");
  214. #endif
  215.  
  216.                 *hadAlias = *leafIsAlias;
  217.             } else {
  218. #ifdef DEBUG
  219.                 printf("Leaf had an invalid alias\n");
  220. #endif
  221.             }
  222.         } else {
  223.             *hadAlias = 0;
  224.         }
  225.  
  226.         /*  See if it's a directory. */
  227.  
  228.         pstrcpy(name, fss->name);
  229.         pb.hFileInfo.ioNamePtr = name;
  230.         pb.hFileInfo.ioVRefNum = fss->vRefNum;
  231.         pb.hFileInfo.ioFDirIndex = 0;    /* get file info */
  232.         pb.hFileInfo.ioDirID = fss->parID;
  233.         err = PBGetCatInfoSync(&pb);
  234.         if (err == noErr) {
  235.             if (pb.hFileInfo.ioFlAttrib & 0x10)
  236.                 *isFolder = 1;
  237.         }
  238.  
  239.         return err;
  240.     } else
  241.         /*  try going up the chain... */
  242.     {
  243.         //char  fn[256];
  244.  
  245. #ifdef DEBUG
  246.         printf("FSMakeFSSpec failed, resolving alias.\n");
  247. #endif
  248.  
  249.         err =
  250.             ResolveFSSpec(vRefNum, dirID, name, 1, fss, isFolder, hadAlias,
  251.                           leafIsAlias);
  252.         if (err == noErr) {
  253. #ifdef DEBUG
  254. //          printf("MakeResolvedPath returned '%s'\n", fn);
  255. #endif
  256.  
  257.             //c2pstr(fn);
  258.             //err = FSMakeFSSpec(0, 0, (unsigned char *)fn, fss);
  259.         }
  260.         return err;
  261.     }
  262. }
  263.  
  264. #endif // !defined(UNDER_MPW)
  265.  
  266. #if 0
  267. #pragma mark -
  268. #endif
  269.  
  270.  
  271. /*    get error text for an OSError */
  272.  
  273. char
  274.            *
  275. OS_GetErrText(OSError err)
  276. {
  277.     static char errmsg[256];
  278.     char       *ret;
  279.  
  280. #if defined(BUILDHOST_MPW)
  281.     char       *rep;
  282.  
  283.     ret = GetSysErrText(err, errmsg);
  284.     rep = strstr(ret, " (OS error");
  285.     // get rid of this; we already append this 
  286.     // to our error message
  287.     if (rep != NULL) {
  288.         *rep = 0;
  289.     }
  290. #else
  291. #warning "Need error message..."
  292.     sprintf(errmsg, "Error #%d", err);
  293.     ret = errmsg;
  294. #endif
  295.     return ret;
  296. }
  297.  
  298. /*********************/
  299. #if 0
  300. #pragma mark -
  301. #endif
  302.  
  303.  
  304. /*    Initialize C program context  */
  305.  
  306. OSError
  307. OS_InitProgram(int *argc, char ***argv)
  308. {
  309.     long        gestaltReply;
  310.  
  311. #if !defined(UNDER_MPW)
  312.  
  313.     /*  Get some command-line arguments  */
  314.  
  315.     if (argc != NULL && argv != NULL) {
  316.         ccommand(argv);
  317.         *argc = 0;
  318.         while ((*argv)[*argc])
  319.             (*argc)++;
  320.     }
  321.  
  322.     /*  Don't save the window...  */
  323.     SIOUXSettings.asktosaveonclose = 0;
  324.  
  325. #else
  326.  
  327.     InitGraf(&qd.thePort);
  328.     GetDateTime((unsigned long *) &qd.randSeed);
  329.  
  330.     InitCursorCtl(NULL);
  331.     InitErrMgr("", "", true);
  332.  
  333. #endif
  334.  
  335.     systemHandles = false;
  336.     aliasAvail = false;
  337.     InitGraf(&qd.thePort);
  338.     GetDateTime((unsigned long *) &qd.randSeed);
  339.  
  340.     if (Gestalt(gestaltOSAttr, &gestaltReply) == noErr &&
  341.         (gestaltReply & (1L << gestaltRealTempMemory)))
  342.         systemHandles = true;
  343.  
  344.     if (Gestalt(gestaltAliasMgrAttr, &gestaltReply) == noErr &&
  345.         (gestaltReply & (1L << gestaltAliasMgrPresent)))
  346.         aliasAvail = true;
  347.  
  348.     return OS_NOERR;
  349. }
  350.  
  351. /*    Terminate C program context  */
  352.  
  353. OSError
  354. OS_TermProgram(void)
  355. {
  356.     return OS_NOERR;
  357. }
  358.  
  359. /*********************/
  360. #if 0
  361. #pragma mark -
  362. #endif
  363.  
  364.  
  365. OSFileType  OS_TEXTTYPE = 'TEXT';
  366.  
  367. #define FSS(sp) sp->path.vRefNum, sp->path.dirID, sp->name.name
  368.  
  369. /*    create a new file, overwrite an old one if existing */
  370.  
  371. OSError
  372. OS_Create(const OSSpec * spec, OSFileType * type)
  373. {
  374.     OSErr       err = HDelete(FSS(spec));
  375.  
  376.     if (err == noErr || err == fnfErr)
  377.         err = HCreate(FSS(spec), 'CWIE', *type);
  378.     return err;
  379. }
  380.  
  381. /*    tell if a file exists */
  382.  
  383. OSError
  384. OS_Status(const OSSpec * spec)
  385. {
  386.     OSErr       err;
  387.     FInfo       fi;
  388.  
  389.     err = HGetFInfo(FSS(spec), &fi);
  390.     return err;
  391. }
  392.  
  393.  
  394. /*  get type of a file */
  395.  
  396. OSError
  397. OS_GetFileType(const OSSpec * spec, OSFileType * type)
  398. {
  399.     OSErr       err;
  400.     FInfo       fi;
  401.  
  402.     err = HGetFInfo(FSS(spec), &fi);
  403.     if (err == noErr)
  404.         *type = fi.fdType;
  405.     else
  406.         *type = '????';
  407.     return err;
  408. }
  409.  
  410. /*  set type for a file */
  411.  
  412. OSError
  413. OS_SetFileType(const OSSpec * spec, OSFileType * type)
  414. {
  415.     OSErr       err;
  416.     FInfo       fi;
  417.  
  418.     err = HGetFInfo(FSS(spec), &fi);
  419.     if (err == noErr) {
  420.         fi.fdType = *type;
  421.         err = HSetFInfo(FSS(spec), &fi);
  422.     }
  423.     return err;
  424. }
  425.  
  426. /*  get timestamps of a file */
  427.  
  428. OSError
  429. OS_GetFileTime(const OSSpec * spec, OSTime * crtm, OSTime * chtm)
  430. {
  431.     OSErr       err;
  432.     CInfoPBRec  pb;
  433.     Str63       name;
  434.  
  435.     /* Think reference sez name is overwritten */
  436.     pstrcpy(name, spec->name.name);
  437.     pb.hFileInfo.ioNamePtr = name;
  438.     pb.hFileInfo.ioVRefNum = spec->path.vRefNum;
  439.     pb.hFileInfo.ioDirID = spec->path.dirID;
  440.     pb.hFileInfo.ioFDirIndex = 0;
  441.  
  442.     if ((err = PBGetCatInfoSync(&pb)) != noErr)
  443.         return err;
  444.  
  445.     if (crtm)
  446.         *crtm = pb.hFileInfo.ioFlCrDat;
  447.     if (chtm)
  448.         *chtm = pb.hFileInfo.ioFlMdDat;
  449.  
  450.     return OS_NOERR;
  451. }
  452.  
  453. /*  set timestamps of a file */
  454.  
  455. OSError
  456. OS_SetFileTime(const OSSpec * spec, OSTime * crtm, OSTime * chtm)
  457. {
  458.     OSErr       err;
  459.     CInfoPBRec  pb;
  460.     Str63       name;
  461.  
  462.     /* Think reference sez name is overwritten */
  463.     pstrcpy(name, spec->name.name);
  464.     pb.hFileInfo.ioNamePtr = name;
  465.     pb.hFileInfo.ioVRefNum = spec->path.vRefNum;
  466.     pb.hFileInfo.ioDirID = spec->path.dirID;
  467.     pb.hFileInfo.ioFDirIndex = 0;
  468.  
  469.     if ((err = PBGetCatInfoSync(&pb)) != noErr)
  470.         return err;
  471.  
  472.     if (crtm)
  473.         pb.hFileInfo.ioFlCrDat = *crtm;
  474.     if (chtm)
  475.         pb.hFileInfo.ioFlMdDat = *chtm;
  476.  
  477.     if ((err = PBSetCatInfoSync(&pb)) != noErr)
  478.         return err;
  479.  
  480.     return OS_NOERR;
  481. }
  482.  
  483. /*    modify protection on a file */
  484. OSError
  485. OS_ModifyProtection(const OSSpec * spec, bool protected)
  486. {
  487. #error not implemented yet
  488.     return OS_NOERR;
  489. }
  490.  
  491. /*    get disk space info (total, free are measured in units of blocksize bytes) */
  492. OSError
  493. OS_GetDiskStats(const OSPathSpec * spec,
  494.                 OSSize * blocksize, OSSize * total, OSSize * free)
  495. {
  496. #error not implemented yet
  497.     *blocksize = 256;
  498.     *total = 90;
  499.     *free = 0;
  500.     return OS_NOERR;
  501. }
  502.  
  503. /*************************************/
  504. #if 0
  505. #pragma mark -
  506. #endif
  507.  
  508.  
  509. /*    open an existing file */
  510.  
  511. OSError
  512. OS_Open(const OSSpec * spec, OSOpenMode mode, OSRef * ref)
  513. {
  514.     static int  modetrans[] = { fsRdPerm, fsWrPerm,
  515.         fsRdWrPerm, fsWrPerm
  516.     };
  517.     OSErr       err;
  518.  
  519.     err = HOpenDF(FSS(spec), modetrans[mode], ref);
  520.  
  521.     if (err != noErr) {
  522.         *ref = -1;
  523.         return err;
  524.     } else {
  525.         if (mode == OSAppend)
  526.             err = SetFPos(*ref, fsFromLEOF, 0L);
  527.         return err;
  528.     }
  529. }
  530.  
  531. /*    write binary data, up to length bytes;
  532.     length==0 can extend file;
  533.     update length;
  534.     error indicates serious failure */
  535.  
  536. /*    On Mac, can't even seek past EOF.  
  537.     OS_Seek handles extending the file. */
  538.  
  539. OSError
  540. OS_Write(OSRef ref, void *buffer, OSSize * length)
  541. {
  542.     return FSWrite(ref, (long *) length, buffer);
  543. }
  544.  
  545. /*    read binary data, up to length bytes;
  546.     update length;
  547.     error indicates serious failure.  */
  548.  
  549. OSError
  550. OS_Read(OSRef ref, void *buffer, OSSize * length)
  551. {
  552.     OSErr       err;
  553.  
  554.     err = FSRead(ref, (long *) length, buffer);
  555.     // ignore EOF; in Posix-land we just return length < requested
  556.     return (err != eofErr) ? err : noErr;
  557. }
  558.  
  559. /*    seek a file;
  560.     illegal seek is revealed by next write or read;
  561.     error indicates serious failure.  */
  562.  
  563. /*  Whoops, on the Mac this is different.  You can't seek past EOF,
  564.     so we ask Posix-ly and extend the file as implied, returning
  565.     an error only when something else happens. */
  566.  
  567. OSError
  568. OS_Seek(OSRef ref, OSSeekMode how, OSPos offset)
  569. {
  570.     static int  howtrans[] = { fsFromMark, fsFromStart, fsFromLEOF };
  571.     long        length, final, curpos;
  572.     OSErr       err;
  573.  
  574.     if ((err = GetEOF(ref, &length)) != noErr ||
  575.         (err = GetFPos(ref, &curpos)) != noErr)
  576.         return err;
  577.  
  578.     switch (how) {
  579.     case OSSeekRel:
  580.         final = curpos + offset;
  581.         break;
  582.     case OSSeekAbs:
  583.         final = 0 + offset;
  584.         break;
  585.     case OSSeekEnd:
  586.         final = length + offset;
  587.         break;
  588.     default:
  589.         return paramErr;
  590.     }
  591.  
  592.     /*  Don't use SetEOF() since it doesn't provide zeroed blocks */
  593.     while (final > length) {
  594.         static char zeroes[32] = { 0 };
  595.         long        fill;
  596.  
  597.         fill = final - length;
  598.         if (fill > sizeof(zeroes))
  599.             fill = sizeof(zeroes);
  600.  
  601.         if ((err = FSWrite(ref, &fill, zeroes)) != noErr || fill == 0)
  602.             return err;
  603.  
  604.         length += fill;
  605.     }
  606.  
  607.     return SetFPos(ref, fsFromStart, final);
  608. }
  609.  
  610. /*    return file pointer */
  611.  
  612. OSError
  613. OS_Tell(OSRef ref, OSPos * offset)
  614. {
  615.     return GetFPos(ref, offset);
  616. }
  617.  
  618.  
  619. /*    close a file */
  620.  
  621. OSError
  622. OS_Close(OSRef ref)
  623. {
  624.     return FSClose(ref);
  625. }
  626.  
  627. /*  get length of a file;
  628.     return error if directory or not found */
  629.  
  630. OSError
  631. OS_GetSize(OSRef ref, OSSize * length)
  632. {
  633.     return GetEOF(ref, (long *) length);
  634. }
  635.  
  636. /*  set length of a file;
  637.     return error if directory or not found */
  638.  
  639. OSError
  640. OS_SetSize(OSRef ref, OSSize length)
  641. {
  642.     return SetEOF(ref, length);
  643. }
  644.  
  645. /**************************************/
  646. #if 0
  647. #pragma mark -
  648. #endif
  649.  
  650.  
  651. /*    delete a file */
  652.  
  653. OSError
  654. OS_Delete(const OSSpec * spec)
  655. {
  656.     return HDelete(FSS(spec));
  657. }
  658.  
  659. /*    rename a file */
  660.  
  661. /*    for Mac, we need to allow moving through directories, 
  662.     but not moving through volumes. */
  663.  
  664. OSError
  665. OS_Rename(const OSSpec * oldspec, const OSSpec * newspec)
  666. {
  667.     /*  Move through directory first if necessary. */
  668.  
  669.     if (!OS_EqualPathSpec(&oldspec->path, &newspec->path)) {
  670.         CMovePBRec  pb;
  671.         OSErr       err;
  672.  
  673.         if (oldspec->path.vRefNum != newspec->path.vRefNum)
  674.             return paramErr;
  675.  
  676.         pb.ioVRefNum = oldspec->path.vRefNum;
  677.  
  678.         pb.ioDirID = oldspec->path.dirID;
  679.         pb.ioNamePtr = (unsigned char *) oldspec->name.name;
  680.         pb.ioNewDirID = newspec->path.dirID;
  681.         pb.ioNewName = NULL;    /* must specify directory */
  682.  
  683.         err = PBCatMoveSync(&pb);
  684.  
  685.         if (err != noErr)
  686.             return err;
  687.     }
  688.  
  689.     return HRename(newspec->path.vRefNum, newspec->path.dirID,
  690.                    oldspec->name.name, newspec->name.name);
  691. }
  692.  
  693. /*    make directory */
  694.  
  695. /*  The user passes the new directory name in the FSSpec. 
  696.     FSMakeFSSpec will do this for us, unless the file already
  697.     exists. */
  698.  
  699. OSError
  700. OS_Mkdir(const OSSpec * spec)
  701. {
  702.     long        newdirID;
  703.     FSSpec      fss;
  704.  
  705.     fss.vRefNum = spec->path.vRefNum;
  706.     fss.parID = spec->path.dirID;
  707.     pstrcpy(fss.name, spec->name.name);
  708.  
  709.     return FSpDirCreate(&fss, smSystemScript, &newdirID);
  710. }
  711.  
  712. /*    remove directory */
  713.  
  714. /*    The directory should exist, else spec->name specifies a
  715.     non-directory. */
  716.  
  717. OSError
  718. OS_Rmdir(const OSPathSpec * spec)
  719. {
  720.     return HDelete(spec->vRefNum, spec->dirID, (unsigned char *) "");
  721. }
  722.  
  723. /*    change directory */
  724.  
  725. OSError
  726. OS_Chdir(const OSPathSpec * spec)
  727. {
  728.     WDPBRec     wd;
  729.  
  730.     wd.ioNamePtr = NULL;
  731.     wd.ioVRefNum = spec->vRefNum;
  732.     wd.ioWDDirID = spec->dirID;
  733.     return PBHSetVolSync(&wd);
  734. }
  735.  
  736. /*    get current working directory */
  737.  
  738. OSError
  739. OS_GetCWD(OSPathSpec * spec)
  740. {
  741.     FSSpec      fss;
  742.     OSError     err;
  743.  
  744.     err = FSMakeFSSpec(0, 0, (unsigned char *) "", &fss);
  745.     if (err != noErr)
  746.         return err;
  747.  
  748.     err = CanonicalizeIfDirectory(&fss);
  749.  
  750.     spec->vRefNum = fss.vRefNum;
  751.     spec->dirID = fss.parID;
  752.     return err;
  753. }
  754.  
  755. /*    spawn a subprocess */
  756.  
  757. OSError
  758. OS_Execute(const OSSpec * spec, char **argv, char **envp, const char *outname,
  759.            const char *errname, int *exitcode)
  760. {
  761.     int         idx;
  762.  
  763.     for (idx = 0; argv[idx]; idx++) {
  764.         bool        esc = strpbrk(argv[idx], "\t\n\r|()\"\',= ") != NULL;
  765.  
  766.         if (esc)
  767.             printf("\"%s\" ", argv[idx]);
  768.         else
  769.             printf("%s ", argv[idx]);
  770.     }
  771.  
  772.     if (outname)
  773.         printf("> \"%s\" ", outname);
  774.     if (errname)
  775.         printf("2> \"%s\" ", errname);
  776.     printf("\n");
  777.  
  778.     *exitcode = 0;
  779.     return noErr;
  780. }
  781.  
  782. /*************************************/
  783. #if 0
  784. #pragma mark -
  785. #endif
  786.  
  787.  
  788. /*    canonicalize a filepath for host; if dst is NULL, overwrite src in place */
  789. static      OSError
  790. OS_CanonPath(char *src, char *dst)
  791. {
  792.     char       *ptr, *dptr;
  793.     char       *vptr;
  794.     int         nds;
  795.     int         looksunix, fnlen;
  796.  
  797.     if (strlen(src) >= OS_MAXPATHLEN)
  798.         return OS_FNTLERR;
  799.  
  800.     /*  We can do this since dst is at most the length of src */
  801.     if (dst == NULL)
  802.         dst = src;
  803.  
  804.     ptr = src;
  805.     dptr = dst;
  806.     vptr = NULL;                /* volume ptr */
  807.     nds = 0;
  808.  
  809.     /*  First, check for Unix usage as in
  810.        /dir/dir/name.c  -->  dir:dir:name.c and
  811.        //node/dir/dir/name.c --> node:dir:dir:name.c */
  812.  
  813.     looksunix = (strchr(ptr, '/') != NULL && strchr(ptr, ':') == NULL) ||
  814.         strcmp(ptr, ".") == 0;
  815.  
  816.     if (looksunix) {
  817.         if (*ptr == '/') {
  818.             OSErr       err;
  819.             short       volref;
  820.  
  821.             do
  822.                 ptr++;
  823.             while (*ptr == '/');
  824.  
  825.             err = GetVol((unsigned char *) dptr, &volref);
  826.             if (err != noErr)
  827.                 strcpy(dptr, "Desktop");
  828.             else
  829.                 p2cstr((unsigned char *) dptr);
  830.  
  831.             dptr += strlen(dptr);
  832.             vptr = dptr;
  833.             nds = 0;
  834.         }
  835.  
  836.         if (strcmp(ptr, ".") != 0)
  837.             *dptr++ = ':';
  838.     }
  839.  
  840.     /*  Convert slashes to colons and '..' to ':' */
  841.  
  842.     fnlen = 0;
  843.     while (*ptr) {
  844.         if (looksunix) {
  845.             if (*ptr == '/') {
  846.                 if (fnlen > 0)
  847.                     *dptr++ = ':';
  848.                 fnlen = 0;
  849.                 nds++;
  850.             }
  851.                 else
  852.                 if (fnlen == 0 &&
  853.                     *ptr == '.' && *(ptr + 1) == '.' &&
  854.                     (*(ptr + 2) == 0 || *(ptr + 2) == '/')) {
  855.                 /* some yahoos do "/.."; we can't have Ontology:: */
  856.                 if (vptr == NULL || nds > 0) {
  857.                     *dptr++ = ':';
  858.                     nds--;
  859.                 }
  860.                 fnlen = 0;
  861.                 if (*(ptr + 2))
  862.                     ptr += 2;
  863.             }
  864.                 else
  865.                 if (fnlen == 0 &&
  866.                     *ptr == '.' && (*(ptr + 1) == 0 || *(ptr + 1) == '/')) {
  867.                 if (*(ptr + 1))
  868.                     ptr++;
  869.                 fnlen = 0;
  870.             } else {
  871.                 *dptr++ = *ptr;
  872.                 fnlen++;
  873.             }
  874.         } else
  875.             *dptr++ = *ptr;
  876.  
  877.         ptr++;
  878.     }
  879.  
  880.     *dptr = 0;
  881.  
  882.     return OS_NOERR;
  883. }
  884.  
  885.  
  886. /*    tell if a filepath is legal for filesystem;
  887.     call after OS_CanonPath if necessary */
  888.  
  889. OSError
  890. OS_IsLegalPath(const char *path)
  891. {
  892.     const char *scan = path;
  893.     int         pthlen = 0, fnlen = 0;
  894.  
  895.     while (*scan) {
  896.         if (fnlen == 0 && *scan == '.')
  897.             return bdNamErr;    /* don't allow device name */
  898.  
  899.         if (*scan == ':')
  900.             fnlen = 0;
  901.         else
  902.             fnlen++;
  903.  
  904.         pthlen++;
  905.  
  906.         if (fnlen > OS_MAXNAMELEN || pthlen > OS_MAXPATHLEN)
  907.             return OS_FNTLERR;
  908.  
  909.         scan++;
  910.     }
  911.     return OS_NOERR;
  912. }
  913.  
  914. /*    tell if a filepath represents a full path */
  915.  
  916. int
  917. OS_IsFullPath(const char *path)
  918. {
  919.     /*  a relative path begins with ':' but a bare filename is also relative */
  920.     return (path[0] != ':') && (strchr(path, ':') != NULL);
  921. }
  922.  
  923.  
  924. /*    compact a canonical full path; if dst is NULL, overwrite src in place */
  925. static int
  926. OS_CompactPath(char *src, char *dst)
  927. {
  928.     char       *from, *to, *bptr;
  929.  
  930.     ASSERT(OS_IsFullPath(src));
  931.  
  932.     from = strchr(src, ':');
  933.     bptr = to = (dst == NULL ? src : dst);
  934.  
  935.     if (from != NULL) {
  936.         /* from always points to ':' */
  937.         while (*from) {
  938.             char       *brk;
  939.  
  940.             brk = from + 1;
  941.             while (*brk && *brk != ':')
  942.                 brk++;
  943.  
  944.             if (brk == from + 1) {    /* eliminate "::" */
  945.                 if (to > bptr) {
  946.                     do
  947.                         to--;
  948.                     while (to >= bptr && *to != ':');
  949.                 }
  950.                 from = brk + 1;
  951.             } else                /* copy */
  952.                 while (from < brk)
  953.                     *to++ = *from++;
  954.         }
  955.     }
  956.  
  957.     if (to == bptr || from == NULL || *(from - 1) == ':')
  958.         *to++ = ':';            /* ended at volume */
  959.  
  960.     *to = 0;                    /* end string */
  961.  
  962.     return OS_NOERR;
  963. }
  964.  
  965. /*************************************/
  966. #if 0
  967. #pragma mark -
  968. #endif
  969.  
  970.  
  971. /*    make OSSpec from a path; tell what kind it is */
  972.  
  973. OSError
  974. OS_MakeSpec(const char *path, OSSpec * spec, bool * isfile)
  975. {
  976.     OSErr       err;
  977.     char        tmp[OS_PATHSIZE];
  978.     FSSpec      fss;
  979.     Boolean     isFolder, hadAlias, leafIsAlias;
  980.  
  981.     spec->path.vRefNum = spec->path.dirID = 0;
  982.     *spec->name.name = 0;
  983.  
  984.     /*  Get rid of bad chars */
  985.     if ((err = OS_CanonPath((char *) path, tmp)) != OS_NOERR ||
  986.         (err = OS_IsLegalPath(tmp)) != OS_NOERR)
  987.         return err;
  988.     else {
  989.         c2pstr(tmp);
  990.         err = MakeResolvedFSSpec(0, 0, (unsigned char *) tmp, &fss,
  991.                                  &isFolder, &hadAlias, &leafIsAlias);
  992.         if (err == noErr) {
  993.             if (fss.vRefNum == 0 && fss.parID == 0)
  994.                 return nsvErr;
  995.             else if (isFolder) {
  996.                 /*  canonicalize this: directories always
  997.                    have spec->name==""
  998.                  */
  999.  
  1000.                 if (isfile)
  1001.                     *isfile = false;
  1002.                 if ((err = CanonicalizeIfDirectory(&fss)) != noErr)
  1003.                     return err;
  1004.             } else if (isfile)
  1005.                 *isfile = true;
  1006.         } else if (err == fnfErr) {
  1007.             if (isfile)
  1008.                 *isfile = true;
  1009.             err = OS_NOERR;
  1010.         }
  1011.  
  1012.         spec->path.vRefNum = fss.vRefNum;
  1013.         spec->path.dirID = fss.parID;
  1014.         pstrcpy(spec->name.name, fss.name);
  1015.     }
  1016.     return err;
  1017. }
  1018.  
  1019. /*    make OSSpec from a path;
  1020.     must resolve to a file */
  1021. _DLL _PAS   OSError
  1022. OS_MakeFileSpec(const char *path, OSSpec * spec)
  1023. {
  1024.     bool        isfile;
  1025.     OSError     err;
  1026.  
  1027.     err = OS_MakeSpec(path, spec, &isfile);
  1028.     if (err != OS_NOERR)
  1029.         return err;
  1030.  
  1031.     if (!isfile)
  1032.         return OS_FIDERR;
  1033.  
  1034.     return OS_NOERR;
  1035. }
  1036.  
  1037. /*    make OSPathSpec from a volume and dir; 
  1038.     guaranteed to be a directory */
  1039.  
  1040. OSError
  1041. OS_MakePathSpec(const char *vol, const char *dir, OSPathSpec * pspec)
  1042. {
  1043.     OSSpec      spec;
  1044.     OSErr       err;
  1045.     bool        isfile;
  1046.     char        path[OS_PATHSIZE + OS_VOLSIZE];
  1047.  
  1048.     if ((vol ? strlen(vol) : 0) + (dir ? strlen(dir) : 0) + 2 > sizeof(path))
  1049.         return OS_FNTLERR;
  1050.  
  1051.     sprintf(path, "%s%s", vol ? vol : "", dir ? dir : "");
  1052.  
  1053.     err = OS_MakeSpec(path, &spec, &isfile);
  1054.     *pspec = spec.path;
  1055.  
  1056.     if (err != OS_NOERR)
  1057.         return err;
  1058.  
  1059.     if (isfile)
  1060.         return OS_FNIDERR;
  1061.  
  1062.     return OS_NOERR;
  1063. }
  1064.  
  1065. /*    make OSNameSpec from a filename */
  1066.  
  1067. OSError
  1068. OS_MakeNameSpec(const char *name, OSNameSpec * nspec)
  1069. {
  1070.     if (strchr(name, ':') != NULL)
  1071.         return OS_FIDERR;
  1072.  
  1073.     if (strlen(name) > OS_MAXNAMELEN)
  1074.         return OS_FNTLERR;
  1075.  
  1076.     c2pstrcpy(nspec->name, name);
  1077.  
  1078.     return OS_NOERR;
  1079. }
  1080.  
  1081. /*    return FS root spec */
  1082.  
  1083. OSError
  1084. OS_GetRootSpec(OSPathSpec * spec)
  1085. {
  1086.     spec->vRefNum = -1;
  1087.     spec->dirID = 2;
  1088.     return OS_NOERR;
  1089. }
  1090.  
  1091. /*    make a full pathname from OSSpec */
  1092.  
  1093.  
  1094. char       *
  1095. OS_SpecToString(const OSSpec * spec, char *path, int size)
  1096. {
  1097.     char        thepath[OS_PATHSIZE], thename[OS_NAMESIZE];
  1098.     int         plen, nlen;
  1099.  
  1100.     if (size == 0)
  1101.         size = OS_PATHSIZE;
  1102.     if (path == NULL && (path = (char *) malloc(size)) == NULL)
  1103.         return NULL;
  1104.  
  1105.     if (OS_PathSpecToString(&spec->path, thepath, OS_PATHSIZE) == NULL)
  1106.         return NULL;
  1107.     if (OS_NameSpecToString(&spec->name, thename, OS_NAMESIZE) == NULL)
  1108.         return NULL;
  1109.  
  1110.     plen = strlen(thepath);
  1111.     nlen = strlen(thename);
  1112.     if (plen + nlen >= size) {
  1113.         if (plen >= size) {
  1114.             nlen = 0;
  1115.             plen = size - 1;
  1116.         } else {
  1117.             nlen = size - plen - 1;
  1118.         }
  1119.     }
  1120.     memcpy(path, thepath, plen);
  1121.     memcpy(path + plen, thename, nlen);
  1122.     path[plen + nlen] = 0;
  1123.     return path;
  1124. }
  1125.  
  1126. static      OSErr
  1127. VolDirToPath(short vRefNum, long dirID, char *path)
  1128. {
  1129.     CInfoPBRec  pb;
  1130.     Str255      name;
  1131.  
  1132.     if (dirID > 1) {            /* top of volume */
  1133.         OSErr       err;
  1134.  
  1135.         pb.dirInfo.ioNamePtr = name;    /* buffer */
  1136.         pb.dirInfo.ioVRefNum = vRefNum;
  1137.         pb.dirInfo.ioFDirIndex = -1;    /* get dir info */
  1138.         pb.dirInfo.ioDrDirID = dirID;
  1139.  
  1140.         err = PBGetCatInfoSync(&pb);
  1141.         if (err != noErr) {
  1142.             strcat(path, "\003???");    /* dead */
  1143.             return err;
  1144.         } else {
  1145.             pstrcharcat(name, ':');
  1146.  
  1147.             err = VolDirToPath(vRefNum, pb.dirInfo.ioDrParID, path);
  1148.             p2cstr(name);
  1149.             strcat(path, (char *) name);
  1150.             return err;
  1151.         }
  1152.     } else {
  1153.         *path = 0;
  1154.         return noErr;
  1155.     }
  1156. }
  1157.  
  1158. /*    make a path from OSPathSpec */
  1159.  
  1160. char       *
  1161. OS_PathSpecToString(const OSPathSpec * pspec, char *path, int size)
  1162. {
  1163.     char        thepath[OS_PATHSIZE];
  1164.     int         plen;
  1165.  
  1166.     if (size == 0)
  1167.         size = OS_PATHSIZE;
  1168.     if (path == NULL && (path = (char *) malloc(size)) == NULL)
  1169.         return NULL;
  1170.  
  1171.     VolDirToPath(pspec->vRefNum, pspec->dirID, thepath);
  1172.     plen = strlen(thepath);
  1173.     if (plen >= size)
  1174.         plen = size - 1;
  1175.  
  1176.     memcpy(path, thepath, plen);
  1177.     path[plen] = 0;
  1178.     return path;
  1179. }
  1180.  
  1181.  
  1182. char       *
  1183. OS_NameSpecToString(const OSNameSpec * spec, char *name, int size)
  1184. {
  1185.     int         nlen;
  1186.  
  1187.     if (size == 0)
  1188.         size = OS_NAMESIZE;
  1189.     if (name == NULL && (name = (char *) malloc(size)) == NULL)
  1190.         return NULL;
  1191.  
  1192.     nlen = spec->name[0];
  1193.     if (nlen >= size)
  1194.         nlen = size - 1;
  1195.  
  1196.     memcpy(name, spec->name + 1, nlen);
  1197.     name[nlen] = 0;
  1198.     return name;
  1199. }
  1200.  
  1201. /*    return the size of an OSPathSpec, for duplication purposes */
  1202.  
  1203. int
  1204. OS_SizeOfPathSpec(const OSPathSpec * spec)
  1205. {
  1206.     return sizeof(OSPathSpec);
  1207. }
  1208.  
  1209. /*    return the size of an OSNameSpec, for duplication purposes */
  1210.  
  1211. int
  1212. OS_SizeOfNameSpec(const OSNameSpec * spec)
  1213. {
  1214.     return *spec->name + 1;
  1215. }
  1216.  
  1217. /*    compare OSSpecs */
  1218.  
  1219. int
  1220. OS_EqualSpec(const OSSpec * a, const OSSpec * b)
  1221. {
  1222.     return OS_EqualPathSpec(&a->path, &b->path) &&
  1223.         OS_EqualNameSpec(&a->name, &b->name);
  1224. }
  1225.  
  1226. /*    compare OSPathSpecs */
  1227.  
  1228. int
  1229. OS_EqualPathSpec(const OSPathSpec * a, const OSPathSpec * b)
  1230. {
  1231.     return a->vRefNum == b->vRefNum && a->dirID == b->dirID;
  1232. }
  1233.  
  1234. /*    compare OSNameSpecs */
  1235.  
  1236. int
  1237. OS_EqualNameSpec(const OSNameSpec * a, const OSNameSpec * b)
  1238. {
  1239.     unsigned char len;
  1240.  
  1241.     if (a->name[0] != b->name[0])
  1242.         return 0;
  1243.  
  1244.     len = a->name[0];
  1245.     while (len) {
  1246.         if (tolower(a->name[len]) != tolower(b->name[len]))
  1247.             return 0;
  1248.         len--;
  1249.     }
  1250.  
  1251.     return 1;
  1252. }
  1253.  
  1254. #if 0
  1255. #pragma mark -
  1256. #endif
  1257.  
  1258. /*    tell if OSSpec is a directory */
  1259.  
  1260. int
  1261. OS_IsDir(const OSSpec * spec)
  1262. {
  1263.     CInfoPBRec  pb;
  1264.     Str255      name;
  1265.     OSErr       err;
  1266.  
  1267.     pstrcpy(name, spec->name.name);
  1268.     if (!*name) {
  1269.         name[0] = 1;
  1270.         name[1] = ':';
  1271.     }
  1272.     pb.hFileInfo.ioNamePtr = name;
  1273.     pb.hFileInfo.ioVRefNum = spec->path.vRefNum;
  1274.     pb.hFileInfo.ioFDirIndex = 0;
  1275.     pb.hFileInfo.ioDirID = spec->path.dirID;
  1276.     if ((err = PBGetCatInfoSync(&pb)) != 0)
  1277.         return 0;
  1278.     else {
  1279.         return (pb.hFileInfo.ioFlAttrib & 0x10) == 0x10;
  1280.     }
  1281. }
  1282.  
  1283. /*    tell if OSSpec is a file */
  1284.  
  1285. int
  1286. OS_IsFile(const OSSpec * spec)
  1287. {
  1288.     CInfoPBRec  pb;
  1289.     Str255      name;
  1290.     OSErr       err;
  1291.  
  1292.     pstrcpy(name, spec->name.name);
  1293.     if (!*name) {
  1294.         name[0] = 1;
  1295.         name[1] = ':';
  1296.     }
  1297.     pb.hFileInfo.ioNamePtr = name;
  1298.     pb.hFileInfo.ioVRefNum = spec->path.vRefNum;
  1299.     pb.hFileInfo.ioFDirIndex = 0;
  1300.     pb.hFileInfo.ioDirID = spec->path.dirID;
  1301.     if ((err = PBGetCatInfoSync(&pb)) != 0)
  1302.         return 0;
  1303.     else {
  1304.         return (pb.hFileInfo.ioFlAttrib & 0x10) != 0x10;
  1305.     }
  1306. }
  1307.  
  1308. /*    tell if OSSpec is a [soft] link / alias */
  1309.  
  1310. /*    this only checks leaves */
  1311.  
  1312. int
  1313. OS_IsLink(const OSSpec * spec)
  1314. {
  1315.     FSSpec      alias;
  1316.     OSErr       err;
  1317.     Boolean     isFolder, leafIsAlias;
  1318.  
  1319.     err = FSMakeFSSpec(FSS(spec), &alias);
  1320.     if (err != noErr)
  1321.         return 0;
  1322.  
  1323.     err = ResolveAliasFile(&alias, 1, &isFolder, &leafIsAlias);
  1324.     if (err != noErr)
  1325.         return 0;
  1326.     else
  1327.         return leafIsAlias;
  1328. }
  1329.  
  1330. /*    resolve a [soft] link / alias */
  1331.  
  1332. /*    this only resolves leaves */
  1333.  
  1334. OSError
  1335. OS_ResolveLink(const OSSpec * link, OSSpec * target)
  1336. {
  1337.     FSSpec      alias;
  1338.     OSErr       err;
  1339.     Boolean     isFolder, leafIsAlias;
  1340.  
  1341.     err = FSMakeFSSpec(FSS(link), &alias);
  1342.     if (err != noErr)
  1343.         return err;
  1344.  
  1345.     err = ResolveAliasFile(&alias, 1, &isFolder, &leafIsAlias);
  1346.  
  1347.     target->path.vRefNum = alias.vRefNum;
  1348.     target->path.dirID = alias.parID;
  1349.     pstrcpy(target->name.name, alias.name);
  1350.     return err;
  1351. }
  1352.  
  1353.  
  1354. /*************************************/
  1355. #if 0
  1356. #pragma mark -
  1357. #endif
  1358.  
  1359.  
  1360. /*    open a directory for reading */
  1361.  
  1362. OSError
  1363. OS_OpenDir(const OSPathSpec * spec, OSDirRef * ref)
  1364. {
  1365.     CInfoPBRec  pb;
  1366.     OSErr       err;
  1367.  
  1368.     pb.dirInfo.ioNamePtr = NULL;
  1369.     pb.dirInfo.ioVRefNum = spec->vRefNum;
  1370.     pb.dirInfo.ioFDirIndex = -1;
  1371.     pb.dirInfo.ioDrDirID = spec->dirID;
  1372.  
  1373.     err = PBGetCatInfoSync(&pb);
  1374.     if (err != noErr) {            /* directory not found? */
  1375.         ref->vRefNum = ref->dirID = 0;
  1376.         return err;
  1377.     } else {
  1378.         ref->vRefNum = spec->vRefNum;
  1379.         ref->dirID = pb.dirInfo.ioDrDirID;
  1380.         ref->index = 1;
  1381.         return OS_NOERR;
  1382.     }
  1383. }
  1384.  
  1385. /*    read an entry from a directory;
  1386.     don't return "." or "..";
  1387.     return error when end-of-directory reached */
  1388.  
  1389. OSError
  1390. OS_ReadDir(OSDirRef * ref, OSSpec * entry, char *filename, bool * isfile)
  1391. {
  1392.     CInfoPBRec  pb;
  1393.     Str255      name;
  1394.     OSErr       err;
  1395.  
  1396.     *name = 0;
  1397.     pb.dirInfo.ioNamePtr = name;
  1398.     pb.dirInfo.ioVRefNum = ref->vRefNum;
  1399.     pb.dirInfo.ioDrDirID = ref->dirID;
  1400.     pb.dirInfo.ioFDirIndex = ref->index;
  1401.  
  1402.     err = PBGetCatInfoSync(&pb);
  1403.     if (err == noErr) {
  1404.         FSSpec      fss;
  1405.  
  1406.         pstrcpy(fss.name, name);
  1407.         p2cstrcpy(filename, name);
  1408.         fss.vRefNum = ref->vRefNum;
  1409.         fss.parID = ref->dirID;
  1410.  
  1411.         CanonicalizeIfDirectory(&fss);
  1412.  
  1413.         entry->path.vRefNum = fss.vRefNum;
  1414.         entry->path.dirID = fss.parID;
  1415.         pstrcpy(entry->name.name, fss.name);
  1416.         if (isfile)
  1417.             *isfile = (*fss.name != 0);
  1418.  
  1419.         ref->index++;
  1420.     }
  1421.     return err;
  1422. }
  1423.  
  1424. /*    close directory */
  1425.  
  1426. OSError
  1427. OS_CloseDir(OSDirRef * ref)
  1428. {
  1429.     ref->index = 0;
  1430.     ref->vRefNum = ref->dirID = 0;
  1431.     return OS_NOERR;
  1432. }
  1433.  
  1434. /***************************************/
  1435. #if 0
  1436. #pragma mark -
  1437. #endif
  1438.  
  1439. /*    return time in milliseconds */
  1440.  
  1441. unsigned long
  1442. OS_GetMilliseconds(void)
  1443. {
  1444.     return LMGetTicks() * 1000 / 60;
  1445. }
  1446.  
  1447.  
  1448. /*    return current time */
  1449.  
  1450. void
  1451. OS_GetTime(OSTime * tm)
  1452. {
  1453.     GetDateTime(tm);
  1454. }
  1455.  
  1456. #if 0
  1457. #pragma mark -
  1458. #endif
  1459.  
  1460.  
  1461. /*    allocate a memory handle  */
  1462.  
  1463. OSError
  1464. OS_NewHandle(OSSize size, OSHandle * hand)
  1465. {
  1466.     if (systemHandles) {
  1467.         OSErr       res;
  1468.  
  1469.         hand->h = TempNewHandle(size, &res);
  1470.         if (res == OS_NOERR)
  1471.             return OS_NOERR;
  1472.     }
  1473.  
  1474.     hand->h = NewHandle(size);
  1475.     if (hand->h != NULL)
  1476.         return OS_NOERR;
  1477.  
  1478.     return OS_MEMERR;
  1479. }
  1480.  
  1481. /*    resize handle  */
  1482.  
  1483. OSError
  1484. OS_ResizeHandle(OSHandle * hand, OSSize size)
  1485. {
  1486.     SetHandleSize(hand->h, size);
  1487.     if (GetHandleSize(hand->h) == size)
  1488.         return OS_NOERR;
  1489.     else
  1490.         return OS_MEMERR;
  1491. }
  1492.  
  1493. /*    lock handle  */
  1494.  
  1495. void       *
  1496. OS_LockHandle(OSHandle * hand)
  1497. {
  1498.     if (GetHandleSize(hand->h) >= 65536)
  1499.         HLockHi(hand->h);
  1500.     else
  1501.         HLock(hand->h);
  1502.     return (void *) *hand->h;
  1503. }
  1504.  
  1505. /*    unlock handle  */
  1506.  
  1507. void
  1508. OS_UnlockHandle(OSHandle * hand)
  1509. {
  1510.     HUnlock(hand->h);
  1511. }
  1512.  
  1513. /*    free handle  */
  1514.  
  1515. OSError
  1516. OS_FreeHandle(OSHandle * hand)
  1517. {
  1518.     DisposeHandle(hand->h);
  1519.     hand->h = NULL;
  1520.     return OS_NOERR;
  1521. }
  1522.  
  1523. /*    get handle size */
  1524.  
  1525. /*  a return of 0 may indicate error, 
  1526.     but we have no way to report this.
  1527. */
  1528.  
  1529. OSError
  1530. OS_GetHandleSize(OSHandle * hand, OSSize * size)
  1531. {
  1532.     *size = GetHandleSize(hand->h);
  1533.     if (*size == 0)
  1534.         return MemError();
  1535.     else
  1536.         return OS_NOERR;
  1537. }
  1538.  
  1539. /*    invalidate handle */
  1540.  
  1541. void
  1542. OS_InvalidateHandle(OSHandle * hand)
  1543. {
  1544.     hand->h = NULL;
  1545. }
  1546.  
  1547. /*    tell whether a handle is valid */
  1548.  
  1549. bool
  1550. OS_ValidHandle(OSHandle * hand)
  1551. {
  1552.     return hand != NULL && hand->h != NULL;
  1553. }
  1554.  
  1555. /*************************************/
  1556. #if 0
  1557. #pragma mark -
  1558. #endif
  1559.  
  1560.  
  1561. /*    Code resource routines  */
  1562.  
  1563. /*    No support yet */
  1564.  
  1565. /*    open a shared library  */
  1566.  
  1567. OSError
  1568. OS_OpenLibrary(const OSSpec * spec, OSLibrary * lib)
  1569. {
  1570.     *lib = NULL;
  1571.     return fnfErr;
  1572. }
  1573.  
  1574. /*    find a symbol in the library */
  1575.  
  1576. OSError
  1577. OS_GetLibrarySymbol(OSLibrary lib, char *name, void **sym)
  1578. {
  1579.     *sym = NULL;
  1580.     return rfNumErr;            /* assume it wasn't open */
  1581. }
  1582.  
  1583. /*    close a shared library */
  1584.  
  1585. OSError
  1586. OS_CloseLibrary(OSLibrary lib)
  1587. {
  1588.     return rfNumErr;            /* assume it wasn't open */
  1589. }
  1590.