home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / MacPerl 5.1.3 / Mac_Perl_513_src / MacPerl5 / MPFile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-18  |  20.1 KB  |  903 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    MacPerl            -    Real Perl Application
  3. File        :    MPFile.c            -
  4. Author    :    Matthias Neeracher
  5.  
  6. A lot of this code is borrowed from 7Edit written by
  7. Apple Developer Support UK
  8.  
  9. Language    :    MPW C
  10.  
  11. $Log: MPFile.c,v $
  12. Revision 1.1  1994/02/27  23:00:47  neeri
  13. Initial revision
  14.  
  15. Revision 0.6  1993/09/17  00:00:00  neeri
  16. Runtime version
  17.  
  18. Revision 0.5  1993/08/28  00:00:00  neeri
  19. Handle multiple preference files
  20.  
  21. Revision 0.4  1993/08/17  00:00:00  neeri
  22. Enable Save
  23.  
  24. Revision 0.3  1993/08/13  00:00:00  neeri
  25. Write bounds rectangles
  26.  
  27. Revision 0.2  1993/05/30  00:00:00  neeri
  28. Support Console Windows
  29.  
  30. Revision 0.1  1993/05/29  00:00:00  neeri
  31. Compiles correctly
  32.  
  33. *********************************************************************/
  34.  
  35. #include <Errors.h>
  36. #include <Resources.h>
  37. #include <Desk.h>
  38. #include <PLStringFuncs.h>
  39. #include <AppleEvents.h>
  40. #include <AERegistry.h>
  41. #include <StandardFile.h>
  42. #include <TFileSpec.h>
  43. #include <Balloons.h>
  44.  
  45. #include "MPFile.h"
  46. #include "MPScript.h"
  47. #include "MPSave.h"
  48. #include "MPEditor.h"
  49. #include "MPPreferences.h"
  50.  
  51. /**-----------------------------------------------------------------------
  52.         Name:             FileError
  53.         Purpose:        Puts up an error alert.
  54.     -----------------------------------------------------------------------**/
  55.  
  56.  
  57. #if !defined(powerc) && !defined(__powerc)
  58. #pragma segment File
  59. #endif
  60.  
  61. pascal void FileError(Str255 s, Str255 f)
  62. {
  63.     SetCursor(&qd.arrow);
  64.     ParamText(s, f, (StringPtr) "\p", (StringPtr) "\p");
  65.      Alert(ErrorAlert, nil);
  66. }
  67.  
  68. /**-----------------------------------------------------------------------
  69.         Name:             DoClose
  70.         Purpose:        Closes a window.
  71.     -----------------------------------------------------------------------**/
  72.  
  73. #if !defined(powerc) && !defined(__powerc)
  74. #pragma segment File
  75. #endif
  76.  
  77. pascal OSErr DoClose(WindowPtr aWindow, Boolean canInteract, DescType dialogAnswer)
  78. {
  79.      DPtr    aDocument;
  80.      short   alertResult;
  81.      Str255  theName;
  82.     OSErr   myErr;
  83.  
  84.     myErr = noErr;
  85.  
  86.      if (gWCount > 0) {
  87.         aDocument = DPtrFromWindowPtr(aWindow);
  88.  
  89.         if (aDocument->kind == kDocumentWindow) {
  90.             if (aDocument->dirty)
  91.                 if (canInteract && (dialogAnswer==kAEAsk)) {
  92.                     if (aDocument->u.reg.everSaved == false)
  93.                         GetWTitle(aWindow, theName); /* Pick it up as a script may have changed it */
  94.                     else
  95.                         PLstrcpy(theName, aDocument->theFileName);
  96.     
  97.                     ParamText(theName, (StringPtr) "\p", (StringPtr) "\p", (StringPtr) "\p");
  98.                     SetCursor(&qd.arrow);
  99.                     alertResult = Alert(SaveAlert, nil);
  100.                     switch (alertResult) {
  101.                     case aaSave:
  102.                         myErr = SaveAskingName(aDocument, canInteract);
  103.                         break;
  104.     
  105.                     case aaCancel:
  106.                         return userCanceledErr;
  107.     
  108.                     case aaDiscard:
  109.                         aDocument->dirty = false;
  110.                         break;
  111.                     }
  112.                 } else {
  113.                     if (dialogAnswer==kAEYes)
  114.                         myErr = SaveAskingName(aDocument, canInteract);
  115.                     else
  116.                         myErr = noErr; /* Don't save */
  117.                 }
  118.                 
  119.             if (!myErr) {
  120. #ifdef EVIL_USELESS_EDITIONS
  121.                 if (aDocument->kind == kDocumentWindow && aDocument->u.reg.numSections)
  122.                     DeRegisterAllSections(aDocument);
  123. #endif
  124.  
  125.                 CloseMyWindow(aWindow);
  126.             }
  127.         } else if (aDocument->u.cons.selected) {
  128.             if (!gQuitting) {
  129.                 SysBeep(0);
  130.     
  131.                 return userCanceledErr;
  132.             }
  133.         } else 
  134.             SaveConsole(aDocument);
  135.     } else
  136.         myErr = errAEIllegalIndex;
  137.  
  138.     return myErr;
  139. }
  140.  
  141. #if !defined(powerc) && !defined(__powerc)
  142. #pragma segment File
  143. #endif
  144.  
  145. //  DoQuit
  146. //  saveOpt - one of kAEAsk,kAEYes,kAENo
  147. //  if kAEYes or kAEAsk then AEInteactWithUser should have been called
  148. //  before DoQuit. Assumes that it can interact if it needs to.
  149.  
  150. pascal void DoQuit(DescType saveOpt)
  151. {
  152.     WindowPtr    aWindow;
  153.     WindowPtr    nextWindow;
  154.     short            theKind;
  155.  
  156.     if (gRunningPerl && (Alert(AbortAlert, nil) == 2))
  157.         return;
  158.         
  159.     gQuitting = true;
  160.  
  161.     for (aWindow = FrontWindow(); aWindow; aWindow = nextWindow) {
  162.         nextWindow = GetNextWindow(aWindow);
  163.         if (Ours((WindowPtr) aWindow)) {
  164.             if (DoClose((WindowPtr) aWindow, true, saveOpt)) {
  165.                 gQuitting = false;
  166.                 
  167.                 return;
  168.             }
  169.         } else {
  170.             theKind = GetWindowKind(aWindow);
  171.             if (theKind < 0)
  172.                 CloseDeskAcc(theKind);
  173.         }
  174.     }
  175. }
  176.  
  177. pascal Boolean GetFileFilter(CInfoPBPtr pb)
  178. {
  179.     switch (GetDocTypeFromInfo(pb)) {
  180.     case kPreferenceDoc:
  181.         /* We don't want preference files here. Maybe we should */
  182.     case kUnknownDoc:
  183.         return true;
  184.     default:
  185.         return false;
  186.     }
  187. }
  188.  
  189. #if USESROUTINEDESCRIPTORS
  190. RoutineDescriptor    uGetFileFilter = 
  191.         BUILD_ROUTINE_DESCRIPTOR(uppFileFilterProcInfo, GetFileFilter);
  192. #else
  193. #define uGetFileFilter *(FileFilterUPP)&GetFileFilter
  194. #endif
  195.  
  196. pascal OSErr GetFile(FSSpec *theFSSpec)
  197. {
  198.     StandardFileReply  reply;
  199.  
  200.     BuildSEList();
  201.     
  202.     StandardGetFile(&uGetFileFilter, MacPerlFileTypeCount, MacPerlFileTypes, &reply);
  203.  
  204.     if (reply.sfGood) {
  205.         *theFSSpec = reply.sfFile;
  206.         return noErr;
  207.     } else
  208.         return userCanceledErr;
  209. }
  210.  
  211. #if !defined(powerc) && !defined(__powerc)
  212. #pragma segment File
  213. #endif
  214.  
  215. pascal OSErr DoCreate(FSSpec theSpec)
  216. {
  217.     OSErr err;
  218.  
  219.     err = FSpCreate(&theSpec, MPAppSig, 'TEXT', smSystemScript);
  220.  
  221.     if (!err)
  222.         HCreateResFile(theSpec.vRefNum, theSpec.parID, theSpec.name);
  223.     else
  224.         ShowError((StringPtr) "\pCreating", err);
  225.  
  226.     return err;
  227. }
  228.  
  229. pascal OSErr SaveConsole(DPtr doc)
  230. {
  231.     OSErr            err;
  232.     short       resFile;
  233.     HHandle     theHHandle;
  234.     Str255        title;
  235.     Boolean        existing;
  236.     
  237.     resFile    =    CurResFile();
  238.     
  239.     OpenPreferences();
  240.     if (gPrefsFile) {
  241.         UseResFile(gPrefsFile);
  242.         GetWTitle(doc->theWindow, title);
  243.         
  244.         if (theHHandle = (HHandle) Get1NamedResource('TFSS', title)) {
  245.             existing = true;
  246.         } else {
  247.             existing = false;
  248.             theHHandle = (HHandle)NewHandle(sizeof(HeaderRec));
  249.         }
  250.         
  251.         HLock((Handle)theHHandle);
  252.     
  253.         (*theHHandle)->theRect     = doc->theWindow->portRect;
  254.         OffsetRect(
  255.             &(*theHHandle)->theRect,
  256.             -doc->theWindow->portBits.bounds.left,
  257.             -doc->theWindow->portBits.bounds.top);
  258.             
  259.         GetFontName((*(doc->theText))->txFont, (StringPtr) &(*theHHandle)->theFont);
  260.         
  261.         (*theHHandle)->theSize     = (*(doc->theText))->txSize;
  262.         (*theHHandle)->lastID      = 0;
  263.         (*theHHandle)->numSections = 0;
  264.     
  265.         HUnlock((Handle)theHHandle);
  266.     
  267.         if (existing) {
  268.             ChangedResource((Handle) theHHandle);
  269.             WriteResource((Handle) theHHandle);
  270.             UpdateResFile(gPrefsFile);
  271.         } else {
  272.             AddResource((Handle)theHHandle, 'TFSS', Unique1ID('TFSS'), title);
  273.         }
  274.         
  275.         err = ResError();
  276.         
  277.         CloseResFile(gPrefsFile);
  278.         UseResFile(resFile);
  279.     }
  280.     
  281.     if (doc->u.cons.cookie) {
  282.         /* We might need this window again. */
  283.         DoHideWindow(doc->theWindow);
  284.         TESetSelect(0, 32767, doc->theText);
  285.         TEDelete(doc->theText);
  286.     
  287.         if (doc->u.cons.fence < 32767)
  288.             doc->u.cons.fence    = 0;
  289.     } else /* Done with this window */
  290.         CloseMyWindow(doc->theWindow);
  291.     
  292.     return err;
  293.  
  294. pascal void ApplySettings(DPtr doc, HPtr settings)
  295. {
  296.     short        fNum;
  297.     FontInfo    info;
  298.     Rect        bounds;
  299.     
  300.     GetFNum(settings->theFont, &fNum);
  301.     SetPort(doc->theWindow);
  302.     TextFont(fNum);
  303.     TextSize(settings->theSize);
  304.     GetFontInfo(&info);
  305.     
  306.     (*doc->theText)->txFont         = fNum;
  307.     (*doc->theText)->txSize         = settings->theSize;
  308.     (*doc->theText)->lineHeight    = info.ascent+info.descent+info.leading;
  309.     (*doc->theText)->fontAscent    = info.ascent;
  310.     
  311.     bounds.top                            = settings->theRect.top - 13;
  312.     bounds.left                            = settings->theRect.left + 5;
  313.     bounds.bottom                        = settings->theRect.top  - 5;
  314.     bounds.right                        = settings->theRect.right - 5;
  315.     
  316.     if (settings->theRect.right > settings->theRect.left + 50 &&
  317.         settings->theRect.bottom > settings->theRect.top  + 50 &&
  318.         RectInRgn(&bounds, GetGrayRgn())
  319.     ) {
  320.         MoveWindow(doc->theWindow, settings->theRect.left, settings->theRect.top, false);
  321.         SizeWindow(
  322.             doc->theWindow,
  323.             settings->theRect.right - settings->theRect.left,
  324.             settings->theRect.bottom - settings->theRect.top,
  325.             false);
  326.     }
  327.         
  328.     ResizeWindow(doc);
  329. }
  330.  
  331. pascal void RestoreConsole(DPtr doc)
  332. {
  333.     short       resFile;
  334.     HHandle     theHHandle;
  335.     Str255        title;
  336.     
  337.     resFile    =    CurResFile();
  338.     OpenPreferences();
  339.     if (!gPrefsFile)
  340.         return;
  341.         
  342.     UseResFile(gPrefsFile);
  343.     GetWTitle(doc->theWindow, title);
  344.     
  345.     if (theHHandle = (HHandle) Get1NamedResource('TFSS', title)) {
  346.          HLock((Handle)theHHandle);
  347.         
  348.         ApplySettings(doc, *theHHandle);
  349.         
  350.         HUnlock((Handle)theHHandle);
  351.     }
  352.     
  353.     CloseResFile(gPrefsFile);
  354.     UseResFile(resFile);
  355. }
  356.  
  357.  
  358. /** -----------------------------------------------------------------------
  359.         Name:         GetFileContents
  360.         Purpose:        Opens the document specified by theFSSpec and puts
  361.                         the contents into theDocument.
  362.      -----------------------------------------------------------------------**/
  363.  
  364. #if !defined(powerc) && !defined(__powerc)
  365. #pragma segment File
  366. #endif
  367.  
  368. pascal OSErr GetFileContents(FSSpec spec, DPtr theDocument)
  369. {
  370.     long            theSize;
  371.     short            oldRes;
  372.     short            resFile;
  373.     short            refNum;
  374.     OSErr            err;
  375.     HHandle        aHandle;
  376.     Handle        gHandle;
  377.  
  378.     oldRes    =    CurResFile();
  379.     resFile     =    HOpenResFile(spec.vRefNum, spec.parID, spec.name, fsRdPerm);
  380.     
  381.     theDocument->u.reg.everLoaded = true;
  382.     theDocument->u.reg.origFSSpec = spec;
  383.     
  384.     if (theDocument->inDataFork) {
  385.         if (err = HOpenDF(spec.vRefNum, spec.parID, spec.name, fsRdPerm, &refNum)) {
  386.             ShowError((StringPtr) "\pread file - HOpenDF", err);
  387.             refNum = 0;
  388.             
  389.             goto giveUp;
  390.         }
  391.     
  392.         if (err = GetEOF(refNum, &theSize))
  393.             goto giveUp;
  394.  
  395.           gHandle = NewHandle(theSize);
  396.  
  397.         HLock(gHandle);
  398.         if (err = FSRead(refNum, &theSize, *gHandle))
  399.             return err;
  400.         HUnlock(gHandle);
  401.         FSClose(refNum);
  402.     } else {
  403.         gHandle    =    Get1NamedResource('TEXT', (StringPtr) "\p!");
  404.         
  405.         if (gHandle) 
  406.             DetachResource(gHandle);
  407.         else {
  408.             err = ResError();
  409.             
  410.             goto giveUp;
  411.         }
  412.     }
  413.  
  414. #ifdef EVIL_USELESS_EDITIONS
  415.     theDocument->u.reg.numSections = 0;
  416. #endif
  417.  
  418.     if (resFile != -1) {
  419.         aHandle = nil;
  420.  
  421.         if (Count1Resources('TFSS'))
  422.             aHandle = (HHandle)Get1Resource('TFSS', 255);
  423.  
  424.         if (aHandle) {
  425. #ifdef EVIL_USELESS_EDITIONS
  426.             theDocument->u.reg.numSections = (*aHandle)->numSections;
  427. #endif
  428.  
  429.             HLock((Handle) aHandle);
  430.             ApplySettings(theDocument, *aHandle);
  431.         }
  432.  
  433.         /*
  434.             If there is a print record saved, ditch the old one
  435.             created by new document and fill this one in
  436.         */
  437.         if (Count1Resources('TFSP')) {
  438.             if (theDocument->thePrintSetup)
  439.                 DisposHandle((Handle)theDocument->thePrintSetup);
  440.  
  441.             theDocument->thePrintSetup = (THPrint)Get1Resource('TFSP', 255);
  442.               HandToHand((Handle *)&theDocument->thePrintSetup);
  443.  
  444.             PrOpen();
  445.             PrValidate(theDocument->thePrintSetup);
  446.             PrClose();
  447.         }
  448.  
  449. #ifdef EVIL_USELESS_EDITIONS
  450.         if (theDocument->u.reg.numSections) {
  451.             ReadSectionRecords(theDocument);
  452.             ReadAllSectionResources(theDocument);
  453.         }
  454. #endif
  455.  
  456.         CloseResFile(resFile);
  457.  
  458.         if (err = ResError()) {
  459.             ShowError((StringPtr) "\pread file- CloseResFile", err);
  460.             return err;
  461.         }
  462.     }
  463.  
  464.     HLock(gHandle);
  465.     if (GetHandleSize(gHandle) > 32000) {
  466.         PtrToXHand(
  467.             *gHandle, 
  468.             (*theDocument->theText)->hText, 
  469.             GetHandleSize(gHandle));
  470.         
  471.         err = elvisErr;
  472.     } else
  473.         TESetText(*gHandle, GetHandleSize(gHandle), theDocument->theText);
  474.     DisposHandle(gHandle);
  475.  
  476.     if (err == fnfErr)
  477.         return noErr;
  478.     else
  479.           return err;
  480.  
  481. giveUp:    
  482.     if (refNum)
  483.         FSClose(refNum);
  484.         
  485.     if (resFile > -1)
  486.         CloseResFile(resFile);
  487.     
  488.     UseResFile(oldRes);
  489.     
  490.     return err;
  491. } /* GetFileContents */
  492.  
  493.  
  494. #if !defined(powerc) && !defined(__powerc)
  495. #pragma segment File
  496. #endif
  497.  
  498. pascal OSErr SaveAskingName(DPtr aDocument, Boolean canInteract)
  499. {
  500.     OSErr    myErr;
  501.  
  502.     if (aDocument->kind != kDocumentWindow || !aDocument->u.reg.everSaved) {
  503.  
  504.         if (canInteract) {
  505.             if (myErr = GetFileNameToSaveAs(aDocument))
  506.                 return myErr;
  507.  
  508.             if (myErr = SaveWithoutTemp(aDocument, aDocument->theFSSpec))
  509.                 return myErr;            
  510. #ifdef EVIL_USELESS_EDITIONS
  511.             AssocAllSections(aDocument);
  512. #endif
  513.             return noErr;
  514.         } else
  515.             return errAENoUserInteraction;
  516.  
  517.     } else
  518.         return SaveUsingTemp(aDocument);
  519. }
  520.  
  521. #if !defined(powerc) && !defined(__powerc)
  522. #pragma segment File
  523. #endif
  524.  
  525. void NukeFileProcess(FSSpec * spec)
  526. {
  527.     /* Search for process running with this file and quit it if necessary */
  528.     ProcessInfoRec         info;
  529.     FSSpec                    procSpec;
  530.     CInfoPBRec                specInfo;
  531.     AppleEvent                quitEvent;
  532.     AppleEvent                ignoreReply;
  533.     ProcessSerialNumber    psn;
  534.     
  535.     if (FSpCatInfo(spec, &specInfo))
  536.         return;
  537.         
  538.     psn.highLongOfPSN = 0;
  539.     psn.lowLongOfPSN  = kNoProcess;
  540.     while (!GetNextProcess(&psn))    {
  541.         info.processInfoLength     = sizeof(info);
  542.         info.processName             = nil;
  543.         info.processAppSpec         = &procSpec;
  544.         
  545.         if (GetProcessInformation(&psn, &info))
  546.             continue;
  547.         if (info.processSignature != specInfo.hFileInfo.ioFlFndrInfo.fdCreator)
  548.             continue;
  549.         if (!SameFSSpec(&procSpec, spec))
  550.             continue;
  551.         if(AEBuildAppleEvent(kCoreEventClass, kAEQuitApplication,
  552.                         typeProcessSerialNumber, &psn, sizeof(ProcessSerialNumber),
  553.                         0, 0, &quitEvent,
  554.                         ""))
  555.             return;
  556.         AESend(&quitEvent, &ignoreReply, 
  557.                  kAEWaitReply+kAENeverInteract, kAENormalPriority, kAEDefaultTimeout,
  558.                  nil, nil);
  559.         AEDisposeDesc(&quitEvent);
  560.         AEDisposeDesc(&ignoreReply);
  561.     }
  562. }
  563.  
  564. pascal OSErr SaveUsingTemp(DPtr theDocument)
  565. {
  566.     OSErr        err;
  567.     FSSpec    tempFSSpec;
  568.  
  569.     /*save the file to disk using a temporary file*/
  570.     /*this is the recommended way of doing things*/
  571.     /*first write out the file to disk using a temporary filename*/
  572.     /*if it is sucessfully written, exchange the temporary file with the last one saved*/
  573.     /*then delete the temporary file- so if anything goes wrong, the original version is still there*/
  574.     /*first generate the temporary filename*/
  575.  
  576.     GetTempFSSpec(theDocument, &tempFSSpec);
  577.  
  578.     if (err = DoCreate(tempFSSpec))
  579.         return err;
  580.  
  581.     if (err = DoSave(theDocument, tempFSSpec, theDocument->theFSSpec.name))
  582.         return err;
  583.     
  584.     NukeFileProcess(&theDocument->theFSSpec);
  585.     
  586.     if (err = FSpExchangeFiles(&tempFSSpec, &theDocument->theFSSpec))
  587.         return err;
  588.     
  589.     /*we've exchanged the files, now delete the temporary one*/
  590.  
  591.     FSpDelete(&tempFSSpec);
  592.     
  593.     if (!err && theDocument->kind == kDocumentWindow) {
  594.         theDocument->dirty                 = false;
  595.         theDocument->u.reg.everSaved     = true;
  596.         theDocument->u.reg.origFSSpec = theDocument->theFSSpec;
  597.     }
  598.  
  599.     return err;
  600. }
  601.  
  602. pascal OSErr SaveWithoutTemp(DPtr theDocument, FSSpec spec)
  603. {
  604.     OSErr        err;
  605.     
  606.     if (err = DoSave(theDocument, spec, spec.name))
  607.         return err;
  608.  
  609.     if (theDocument->kind == kDocumentWindow) {
  610.         theDocument->dirty                 = false;
  611.         theDocument->u.reg.everSaved     = true;
  612.         theDocument->u.reg.origFSSpec = theDocument->theFSSpec = spec;
  613.                 
  614.         SetWTitle(theDocument->theWindow, theDocument->theFSSpec.name);
  615.     }
  616.     /* Rebuild list of standard scripts */
  617.     AddStandardScripts();
  618.     
  619.     return noErr;
  620. }
  621.  
  622. #if !defined(powerc) && !defined(__powerc)
  623. #pragma segment File
  624. #endif
  625.  
  626. pascal short SaveScriptHook(short item, DialogPtr dlg, void * params)
  627. {
  628.     short                kind;
  629.     ControlHandle    type;
  630.     MenuHandle        typeMenu;
  631.     Rect                r;
  632.     DPtr                doc = (DPtr) params;
  633.     
  634.     if (GetWRefCon(dlg) != 'stdf')
  635.         return item;
  636.         
  637.     switch (item) {
  638.     case sfHookFirstCall:
  639.         GetDItem(dlg, ssd_Type, &kind, (Handle *) &type, &r);
  640.         typeMenu = (*(PopupPrivateDataHandle)(*type)->contrlData)->mHandle;
  641.         
  642.         AddExtensionsToMenu(typeMenu);
  643.         SetControlMaximum(type, CountMItems(typeMenu));
  644.         SetCtlValue(type, Type2Menu(doc->type));
  645.         
  646.         return sfHookFirstCall;
  647.     case ssd_Type:
  648.         GetDItem(dlg, item, &kind, (Handle *) &type, &r);
  649.         
  650.         doc->type = (DocType) Menu2Type(GetCtlValue(type));
  651.         
  652.         return sfHookNullEvent;
  653.     default:
  654.         return item;
  655.     }
  656. }
  657.  
  658. #if USESROUTINEDESCRIPTORS
  659. RoutineDescriptor    uSaveScriptHook = 
  660.         BUILD_ROUTINE_DESCRIPTOR(uppDlgHookYDProcInfo, SaveScriptHook);
  661. #else
  662. #define uSaveScriptHook *(DlgHookYDUPP)&SaveScriptHook
  663. #endif
  664.  
  665. /*
  666.     Fills in the document record with the user chosen destination
  667. */
  668.  
  669. pascal OSErr GetFileNameToSaveAs(DPtr theDocument)
  670. {
  671.     OSErr                    err;
  672.     StandardFileReply    reply;
  673.     Str255            suggestName;
  674.     Point                    where;
  675.     
  676.     where.h = where.v = -1;
  677.  
  678.     GetWTitle(theDocument->theWindow, suggestName);
  679.  
  680.     HMSetDialogResID(SaveScriptDialog);
  681.     CustomPutFile(
  682.         (StringPtr) "\pSave Document As:", suggestName, &reply,
  683.         SaveScriptDialog,
  684.         where,
  685.         &uSaveScriptHook,
  686.         (ModalFilterYDUPP) nil,
  687.         nil,
  688.         (ActivateYDUPP) nil,
  689.         theDocument);
  690.     HMSetDialogResID(-1);
  691.  
  692.     if (reply.sfGood)
  693.         switch (err = FSpDelete(&reply.sfFile)) {
  694.         case noErr:
  695.         case fnfErr:
  696.             theDocument->theFSSpec = reply.sfFile;
  697.             PLstrcpy(theDocument->theFileName, reply.sfFile.name);
  698.  
  699.             return noErr;
  700.         default:
  701.             return err;
  702.         }
  703.     else
  704.         return userCanceledErr;
  705. } /* GetFileNameToSaveAs */
  706.  
  707. #if !defined(powerc) && !defined(__powerc)
  708. #pragma segment File
  709. #endif
  710.  
  711. pascal DPtr MakeOldDoc(FSSpec aFSSpec, DocType type)
  712. {
  713.     DPtr          theDocument;
  714.     
  715.     theDocument = NewDocument(true, kDocumentWindow);
  716.  
  717.     SetWTitle(theDocument->theWindow, aFSSpec.name);
  718.  
  719.     SetPort(theDocument->theWindow);
  720.  
  721.     theDocument->theFSSpec   = aFSSpec;
  722.  
  723.     PLstrcpy(theDocument->theFileName, aFSSpec.name);
  724.  
  725.     theDocument->dirty               = false;
  726.     theDocument->inDataFork            = type == kPlainTextDoc;
  727.     
  728.     /* We *can* open documents created by unknown save extensions, but we can't
  729.        save them again 
  730.     */
  731.     if (CanSaveAs(type)) {
  732.         CInfoPBRec    info;
  733.  
  734.         theDocument->type                 = type;
  735.         if (!FSpCatInfo(&aFSSpec, &info) && info.hFileInfo.ioFlAttrib & 1)
  736.             theDocument->u.reg.everSaved    = false;        /* Locked file, don't overwrite */
  737.         else
  738.             theDocument->u.reg.everSaved    = true;
  739.     } else {
  740.         theDocument->type                    = kPlainTextDoc;
  741.         theDocument->u.reg.everSaved    = false;
  742.     }
  743.  
  744.     return theDocument;
  745. }
  746.  
  747. pascal OSErr OpenOld(FSSpec aFSSpec, DocType type)
  748. {
  749.     DPtr          theDocument;
  750.     OSErr         fileErr;
  751.     WindowPtr    win;
  752.  
  753.     if (win = AlreadyOpen(&aFSSpec, nil)) {
  754.         SelectWindow(win);
  755.         
  756.         return noErr;
  757.     }
  758.     
  759.     theDocument    =    MakeOldDoc(aFSSpec, type);
  760.     
  761.     fileErr = GetFileContents(aFSSpec, theDocument);
  762.  
  763.     if (!fileErr) {
  764.         ResizeWindow(theDocument);
  765.         DoShowWindow(theDocument->theWindow);
  766.     } else {
  767.         if (fileErr == elvisErr) {
  768.             theDocument->u.reg.everSaved    = false;
  769. #ifdef RUNTIME
  770.             if (AEInteractWithUser(kAEDefaultTimeout, nil, nil))
  771. #endif
  772.                 switch (Alert(gExternalEditor ? ElvisEditAlert : ElvisAlert, nil)) {
  773.                 case 1:
  774.                     SaveAskingName(theDocument, true);
  775.                     break;
  776.                 case 2:
  777.                     /* Abandon */
  778.                     break;
  779.                 case 3:
  780.                     /* Edit */
  781.                     EditExternal(&aFSSpec);
  782.                     break;
  783.                 }
  784.         } else
  785.             FileError((StringPtr) "\pError Opening ", aFSSpec.name);
  786.         
  787.         CloseMyWindow(theDocument->theWindow);
  788.     }
  789.  
  790.     return fileErr;
  791. } /* OpenOld */
  792.  
  793. pascal OSErr File2File(FSSpec aFSSpec, DocType type, FSSpec toFSSpec, DocType newtype)
  794. {
  795.     DPtr          theDocument;
  796.     OSErr         fileErr;
  797.  
  798.     theDocument    =    MakeOldDoc(aFSSpec, type);
  799.     
  800.     switch (fileErr = GetFileContents(aFSSpec, theDocument)) {
  801.     case elvisErr:
  802.         fileErr = noErr;
  803.         /* Fall through */
  804.     case noErr:
  805.         theDocument->type = newtype;
  806.         theDocument->u.reg.everSaved    = false;
  807.         if (SameFSSpec(&aFSSpec, &toFSSpec))
  808.             fileErr = SaveUsingTemp(theDocument);
  809.         else
  810.             fileErr = SaveWithoutTemp(theDocument, toFSSpec);
  811.         
  812.         /* Fall through */
  813.     default:
  814.         CloseMyWindow(theDocument->theWindow);
  815.     }
  816.  
  817.     return fileErr;
  818. } /* File2File */
  819.  
  820. pascal OSErr Handle2File(Handle text, FSSpec toFSSpec, DocType newtype)
  821. {
  822.     DPtr          theDocument;
  823.     OSErr         fileErr;
  824.  
  825.     theDocument = NewDocument(true, kDocumentWindow);
  826.     
  827.     HLock(text);
  828.     PtrToXHand(*text, (*theDocument->theText)->hText, GetHandleSize(text));
  829.     HUnlock(text);
  830.     
  831.     theDocument->u.reg.everSaved    = false;
  832.     theDocument->type                 = newtype;
  833.  
  834.     fileErr = SaveWithoutTemp(theDocument, toFSSpec);
  835.     
  836.     CloseMyWindow(theDocument->theWindow);
  837.  
  838.     return fileErr;
  839. } /* Handle2File */
  840.  
  841. pascal DocType GetDocTypeFromFile(short vRefNum, long dirID, StringPtr name)
  842. {
  843.     short            resFile;
  844.     short            nuFile;
  845.     OSType    **    rtType;
  846.     DocType        type    =    kUnknownDoc;
  847.     
  848.     resFile    = CurResFile();
  849.     nuFile    = HOpenResFile(vRefNum, dirID, name, fsRdPerm);
  850.     
  851.     if (nuFile != -1) {
  852.         if (rtType = (OSType **) Get1Resource('MrPL', 128))
  853.             type = **(DocType **) rtType;
  854.             
  855.         CloseResFile(nuFile);
  856.     }
  857.     UseResFile(resFile);
  858.     
  859.     return type;
  860. }
  861.  
  862. pascal DocType GetDocTypeFromInfo(CInfoPBPtr info)
  863. {
  864.     DocType        type    =    kUnknownDoc;
  865.     
  866.     switch (info->hFileInfo.ioFlFndrInfo.fdType) {
  867.     case 'APPL':
  868.         if (info->hFileInfo.ioFlFndrInfo.fdCreator == MPAppSig) 
  869.             /* A heuristic to separate old runtimes from PowerPC executables */
  870.             if (info->hFileInfo.ioFlLgLen && info->hFileInfo.ioFlLgLen < 100000)
  871.                 return kOldRuntime6Doc; 
  872.         
  873.         break;
  874.     case 'TEXT':
  875.         return kPlainTextDoc;
  876.     case 'pref':
  877.         switch (info->hFileInfo.ioFlFndrInfo.fdCreator) {
  878.         case MPAppSig:
  879.         case MPRtSig:
  880.             return kPreferenceDoc;
  881.         }
  882.         break;
  883.     default:
  884.         break;
  885.     }
  886.     
  887.     /* Ultimately, with save extensions, every file could be ours */
  888.     return GetDocTypeFromFile(
  889.         info->hFileInfo.ioVRefNum, 
  890.         info->hFileInfo.ioFlParID, 
  891.         info->hFileInfo.ioNamePtr);
  892. }
  893.  
  894. pascal DocType GetDocType(FSSpec * spec)
  895. {
  896.     CInfoPBRec    info;
  897.  
  898.     if (FSpCatInfo(spec, &info))
  899.         return kUnknownDoc;
  900.     else
  901.         return GetDocTypeFromInfo(&info);
  902. }