home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Developer Essentials / DTS Sample Code / System 7.0 Samples / Kibitz / File.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-21  |  17.6 KB  |  706 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:         Kibitz
  5. ** File:            file.c
  6. ** Some code from:  Traffic Light 2.0 version, by Keith Rollin & John Harvey
  7. ** Modified by:     Eric Soldan
  8. **
  9. ** Copyright © 1990-1991 Apple Computer, Inc.
  10. ** All rights reserved.
  11. */
  12.  
  13.  
  14.  
  15. /*****************************************************************************/
  16.  
  17.  
  18.  
  19. #include "Kibitz.h"                /* Get the Kibitz includes/typedefs, etc.    */
  20. #include "KibitzCommon.h"        /* Get the stuff in common with rez.        */
  21. #include "Kibitz.protos"        /* Get the prototypes for Kibitz.            */
  22.  
  23. #ifndef __ERRORS__
  24. #include <Errors.h>
  25. #endif
  26.  
  27. #ifndef __MEMORY__
  28. #include <Memory.h>
  29. #endif
  30.  
  31. #ifndef __PACKAGES__
  32. #include <Packages.h>
  33. #endif
  34.  
  35. #ifndef __TOOLUTILS__
  36. #include <ToolUtils.h>
  37. #endif
  38.  
  39. #ifndef __UTILITIES__
  40. #include <Utilities.h>
  41. #endif
  42.  
  43.  
  44.  
  45. /*****************************************************************************/
  46.  
  47.  
  48.  
  49. static Boolean    gIncNewFileNumFlag = true;
  50.  
  51.  
  52.  
  53. /*****************************************************************************/
  54. /*****************************************************************************/
  55.  
  56.  
  57.  
  58. /* This function disposes of the document.  It checks to see if a file is
  59. ** currently open for the document.  If it is, then the document is closed.
  60. ** Once there is no open file for the document, the memory occupied by the
  61. ** document is released.
  62. */
  63.  
  64. #pragma segment File
  65. OSErr    AppDisposeDocument(FileRecHndl frHndl)
  66. {
  67.     OSErr        err;
  68.     Handle        snd;
  69.  
  70.     err = noErr;
  71.  
  72.     if (frHndl) {
  73.         SetOpponentType(frHndl, kOnePlayer);
  74.             /* Disconnect from opponent. */
  75.  
  76.         if ((*frHndl)->fileState.fss.vRefNum != kInvalVRefNum)
  77.             err = FSClose((*frHndl)->fileState.refNum);
  78.                 /* Close the file, if opened. */
  79.  
  80.         DisposHandle((Handle)(*frHndl)->doc.legalMoves);
  81.         DisposHandle((Handle)(*frHndl)->doc.gameMoves);
  82.         if (snd = (*frHndl)->doc.sound)
  83.             DisposHandle(snd);
  84.                 /* Release all handles hanging off the document. */
  85.  
  86.         DisposHandle((Handle)frHndl);
  87.             /* Release memory for the document handle. */
  88.     }
  89.  
  90.     return(err);
  91. }
  92.  
  93.  
  94.  
  95. /*****************************************************************************/
  96.  
  97.  
  98.  
  99. /* This function returns whether or not the document is dirty.
  100. */
  101.  
  102. #pragma segment File
  103. Boolean    AppDocumentDirty(FileRecHndl frHndl)
  104. {
  105.     return((*frHndl)->fileState.docDirty);
  106. }
  107.  
  108.  
  109.  
  110. /*****************************************************************************/
  111.  
  112.  
  113.  
  114. /* This function creates a new document.  A handle is created as the
  115. ** reference to the document.  Header information is placed in this handle.
  116. ** The application-specific data follows this header information.  The
  117. ** handle is returned (or nil upon failure), and typically the handle is
  118. ** then stored in the refCon field of the window.  Note that this is a
  119. ** convention, and is not mandatory.  This allows a document to exist that
  120. ** has no window.  A document with no window is useful when the application
  121. ** is called from the finder in response to a print request.  The document
  122. ** can be loaded and printed without involving a window on the screen.
  123. */
  124.  
  125.  
  126. #pragma segment File
  127. OSErr    AppNewDocument(FileRecHndl *returnHndl)
  128. {
  129.     static short    untitledCount;
  130.     FileRecHndl        frHndl;
  131.     FileRecPtr        frPtr;
  132.     Str255            untitled;
  133.     char            *pstr;
  134.     MoveListHndl    legalMovesHndl;
  135.     GameListHndl    gameMovesHndl;
  136.  
  137.     *returnHndl = nil;
  138.  
  139.     if (frHndl = (FileRecHndl)NewHandle(sizeof(FileRec))) {
  140.  
  141.         GetIndString(untitled, rMiscStrings, sOrigName);
  142.         frPtr = *frHndl;
  143.         frPtr->fileState.docDirty    = false;
  144.         frPtr->fileState.readOnly    = false;
  145.         frPtr->fileState.fss.vRefNum = kInvalVRefNum;
  146.         frPtr->fileState.window      = nil;
  147.         pstr = &(frPtr->fileState.fss.name);
  148.         pstrcpy(pstr, untitled);
  149.         if (gIncNewFileNumFlag) ++untitledCount;
  150.         appendi2pstr(pstr, untitledCount);
  151.  
  152.         legalMovesHndl = (MoveListHndl)NewHandle(0);
  153.         if (!legalMovesHndl) {
  154.             DisposHandle((Handle)frHndl);
  155.             return(memFullErr);
  156.         }
  157.  
  158.         gameMovesHndl = (GameListHndl)NewHandle(0);
  159.         if (!gameMovesHndl) {
  160.             DisposHandle((Handle)frHndl);
  161.             DisposHandle((Handle)legalMovesHndl);
  162.             return(memFullErr);
  163.         }
  164.  
  165.         NewGame(frHndl);        /* Initialize the game. */
  166.  
  167.         frPtr = *frHndl;
  168.         frPtr->doc.legalMoves = legalMovesHndl;
  169.         frPtr->doc.gameMoves  = gameMovesHndl;
  170.  
  171.         *returnHndl = frHndl;
  172.         return(noErr);            /* All is well. */
  173.     }
  174.  
  175.     return(memFullErr);
  176. }
  177.  
  178.  
  179.  
  180. /*****************************************************************************/
  181.  
  182.  
  183.  
  184. #pragma segment File
  185. OSErr    AppOpenDocument(FileRecHndl *result, FSSpecPtr fileToOpen,
  186.                         char permission)
  187. {
  188.     StandardFileReply    reply;
  189.     short                fileRefNum;
  190.     FileRecHndl            frHndl;
  191.     OSErr                err;
  192.     FSSpec                myFileSpec;
  193.     DialogPtr            openDialog;
  194.     short                item;
  195.  
  196.     *result = nil;        /* Assume we will fail. */
  197.  
  198.     if (!fileToOpen) {
  199.         if (DisplayGetFile(&reply))        /* Let the user decide which file. */
  200.             myFileSpec = reply.sfFile;    /* User's choice.                   */
  201.         else
  202.             return(userCanceledErr);    /* User canceled. */
  203.     }
  204.     else
  205.         myFileSpec = *fileToOpen;        /* Pre-designated file to open. */
  206.  
  207.     if (err = AppNewDocument(&frHndl))
  208.         return(err);
  209.             /* We couldn't create an empty document, so give it up. */
  210.  
  211.     err = HOpen(myFileSpec.vRefNum, myFileSpec.parID,
  212.                 myFileSpec.name, permission, &fileRefNum);
  213.  
  214.     if (err == opWrErr) {
  215.  
  216.         ParamText(myFileSpec.name, nil, nil, nil);
  217.         openDialog = GetCenteredDialog(rOpenReadOnly, nil, nil, (WindowPtr)-1L);
  218.         if (!openDialog) {
  219.             AppDisposeDocument(frHndl);
  220.             return(err);
  221.         }
  222.  
  223.         OutlineDialogItem(openDialog, kOpenYes);
  224.         DoSetCursor(&qd.arrow);
  225.         ModalDialog((ModalFilterProcPtr)keyEquivFilter, &item);
  226.         DisposDialog(openDialog);
  227.         if (item != kOpenYes) return(userCanceledErr);
  228.  
  229.         (*frHndl)->fileState.readOnly = true;
  230.         err = HOpen(myFileSpec.vRefNum, myFileSpec.parID,
  231.                     myFileSpec.name, fsRdPerm, &fileRefNum);
  232.     }
  233.  
  234.     if (err) {
  235.         AppDisposeDocument(frHndl);
  236.         return(err);
  237.     }
  238.  
  239.     (*frHndl)->fileState.fss    = myFileSpec;
  240.     (*frHndl)->fileState.refNum = fileRefNum;
  241.  
  242.     if (err = AppReadDocument(frHndl)) {
  243.         AppDisposeDocument(frHndl);
  244.         return(err);
  245.     }
  246.  
  247.     if ((*frHndl)->fileState.readOnly) {
  248.         FSClose((*frHndl)->fileState.refNum);
  249.         (*frHndl)->fileState.fss.vRefNum = kInvalVRefNum;
  250.     }        /* If it's read-only, we don't need the file left open. */
  251.  
  252.     *result = frHndl;
  253.     return(noErr);
  254. }
  255.  
  256.  
  257.  
  258. /*****************************************************************************/
  259.  
  260.  
  261.  
  262. #pragma segment File
  263. OSErr    AppSaveDocument(FileRecHndl    frHndl, WindowPtr window, short saveMode)
  264. {
  265.     Str255                closeOrQuit;
  266.     short                item, gameStatus;
  267.     StandardFileReply    reply;
  268.     OSErr                err;
  269.     short                fileRefNum;
  270.     DialogPtr            saveDialog;
  271.     Boolean                doPrompt;
  272.     Boolean                youLose;
  273.  
  274. /*    When entering, saveMode is set to the menu command number of the
  275. **    the item that prompted this. Current settings are iSave, iSaveAs,
  276. **    iClose, and iQuit.
  277. */
  278.  
  279.     if (saveMode != iSaveAs) {                        /* If regular save... */
  280.         if (!AppDocumentDirty(frHndl))                /* If file clean...   */
  281.             return(noErr);                            /* Consider it saved. */
  282.     }
  283.  
  284.     pstrcpy(reply.sfFile.name, (*frHndl)->fileState.fss.name);
  285.  
  286.     if ((saveMode == iClose) || (saveMode == iQuit)) {
  287.         /* If implicit save... */
  288.  
  289.         GetIndString(closeOrQuit, rMiscStrings,
  290.                      (saveMode == iClose) ? sClosing : sQuitting);
  291.         ParamText(reply.sfFile.name, closeOrQuit, nil, nil);
  292.  
  293.         gameStatus = GameStatus(frHndl);
  294.         youLose = ((gameStatus == kYouLose) || (gameStatus == kYouLoseOnTime));
  295.         if (youLose)
  296.             saveDialog = GetCenteredDialog(rNoYesCancel, nil, window, (WindowPtr)-1L);
  297.         else
  298.             saveDialog = GetCenteredDialog(rYesNoCancel, nil, window, (WindowPtr)-1L);
  299.  
  300.         if (saveDialog) {
  301.             OutlineDialogItem(saveDialog, kSaveYes);
  302.             DoSetCursor(&qd.arrow);
  303.             ModalDialog((ModalFilterProcPtr)keyEquivFilter, &item);
  304.             DisposDialog(saveDialog);
  305.             if (youLose)
  306.                 if (item != kSaveCanceled)
  307.                     item = (item == kSaveYes) ? kSaveNo : kSaveYes;
  308.         }
  309.         else
  310.             item = kSaveYes;
  311.  
  312.         if (item != kSaveYes) {
  313.             err = noErr;
  314.             if (item == kSaveCanceled) err = userCanceledErr;
  315.             return(err);
  316.         }
  317.     }
  318.  
  319.     doPrompt = (
  320.         (saveMode == iSaveAs) ||
  321.         ((*frHndl)->fileState.fss.vRefNum == kInvalVRefNum)
  322.     );
  323.  
  324.     if (doPrompt) {
  325.         /* Prompt with SFGetFile if doing a Save As or have never saved before. */
  326.  
  327.         if (!DisplayPutFile(&reply))
  328.             return(userCanceledErr);
  329.                 /* User canceled the save. */
  330.  
  331.         if ((*frHndl)->fileState.fss.vRefNum != kInvalVRefNum)
  332.             FSClose((*frHndl)->fileState.refNum);
  333.                 /* Close the old file.  Don't respond to any error here because
  334.                 ** the user may be trying to do a save-as because their old file
  335.                 ** is bad.  If we fail to close the old file, and then respond
  336.                 ** to the error, the user won't get the opportunity to save
  337.                 ** their document to a new file.
  338.                 */
  339.  
  340.         if (err = Create_OpenFile(&reply.sfFile, &fileRefNum)) {
  341.             (*frHndl)->fileState.fss.vRefNum = kInvalVRefNum;
  342.             return(err);
  343.         }
  344.  
  345.         (*frHndl)->fileState.fss    = reply.sfFile;
  346.         (*frHndl)->fileState.refNum = fileRefNum;
  347.             /* This is the new file. */
  348.  
  349.         if (window) AppNewWindowTitle(window);
  350.     }
  351.  
  352.     if (err = AppWriteDocument(frHndl))
  353.         return(err);
  354.  
  355.     (*frHndl)->fileState.docDirty = false;
  356.     (*frHndl)->fileState.readOnly = false;
  357.     return(noErr);
  358. }
  359.  
  360.  
  361.  
  362. /*****************************************************************************/
  363.  
  364.  
  365.  
  366. /* ConvertOldToNewSFReply
  367. **
  368. ** struct StandardFileReply {            struct SFReply {
  369. **     Boolean     sfGood;                <-    Boolean good;
  370. **     Boolean     sfReplacing;        <-    Boolean copy;
  371. **     OSType         sfType;                <-    OSType fType;
  372. **     FSSpec        sfFile;
  373. **                     vRefNum;        <-    real vRefnum from (short vRefNum)
  374. **                     parID;            <-    real dirID from (short vRefNum)
  375. **                     name;            <-    Str63 fName;
  376. **     ScriptCode    sfScript;            <-    iuSystemScript
  377. **     short         sfFlags;            <-    0
  378. **     Boolean     sfIsFolder;            <-    false
  379. **     Boolean     sfIsVolume;            <-    false
  380. **     long        sfReserved1;        <-    0
  381. **     short        sfReserved2;        <-    0
  382. ** };                                    };
  383. */
  384.  
  385. #pragma segment File
  386. void    ConvertOldToNewSFReply(SFReply *oldReply, StandardFileReply *newReply)
  387. {
  388.     OSErr        err;
  389.     long        ignoredProcID;
  390.     
  391.     newReply->sfGood        = oldReply->good;
  392.     newReply->sfReplacing    = oldReply->copy;        /* Correct assignment? */
  393.     newReply->sfType        = oldReply->fType;
  394.  
  395.     err = GetWDInfo(oldReply->vRefNum,
  396.                     &newReply->sfFile.vRefNum,
  397.                     &newReply->sfFile.parID,
  398.                     &ignoredProcID);
  399.     BlockMove((Ptr)&oldReply->fName,
  400.               (Ptr)&newReply->sfFile.name,
  401.               oldReply->fName[0]+1);
  402.  
  403.     /* Punt on the rest. */
  404.     newReply->sfScript        = iuSystemScript;
  405.     newReply->sfFlags        = 0;
  406.     newReply->sfIsFolder    = false;
  407.     newReply->sfIsVolume    = false;
  408.     newReply->sfReserved1    = 0;
  409.     newReply->sfReserved2    = 0;
  410. }
  411.  
  412.  
  413.  
  414. /*****************************************************************************/
  415.  
  416.  
  417.  
  418. /* Create_OpenFile
  419. **
  420. ** Opens the file specified by the passed FSSpec, creating it if it doesn't
  421. ** already exist. Refturns the refnum of the open file to the application.
  422. ** File Manager errors are reported and returned.
  423. */
  424.  
  425. #pragma segment File
  426. OSErr    Create_OpenFile(FSSpec *file, short *refNum)
  427. {
  428.     OSErr    err;
  429.  
  430.     err = HCreate(file->vRefNum, file->parID, file->name, docCreator, docFileType);
  431.     if (err == dupFNErr) {
  432.  
  433.         /* The user already told Standard File to replace the old file
  434.            so let's get rid of it. */
  435.  
  436.         HDelete(file->vRefNum, file->parID, file->name);
  437.  
  438.         /* Try creating it again. */
  439.         err = HCreate(file->vRefNum, file->parID, file->name, docCreator, docFileType);
  440.     }
  441.  
  442.     if (!err) {
  443.         err = HOpen(file->vRefNum, file->parID, file->name, fsRdWrPerm, refNum);
  444.         if (err)
  445.             HDelete(file->vRefNum, file->parID, file->name);
  446.     }
  447.  
  448.     return(err);
  449. }
  450.  
  451.  
  452.  
  453. /*****************************************************************************/
  454.  
  455.  
  456.  
  457. /* DisplayGetFile
  458. **
  459. ** Simple routine to display a list of files with our file type.
  460. */
  461.  
  462. #pragma segment File
  463. Boolean DisplayGetFile(StandardFileReply *reply)
  464. {
  465.     SFTypeList    typeList = {docFileType};
  466.     Point        where = {100, 100};
  467.     SFReply        oldReply;
  468.  
  469.     if (gSystemVersion >= 0x0700)    /* If new standard file available... */
  470.         StandardGetFile(nil, 1, typeList, reply);
  471.  
  472.     else {
  473.         SFGetFile(where, "\pSelect a document to open.",
  474.                          nil, 1, typeList, nil, &oldReply);
  475.  
  476.         ConvertOldToNewSFReply(&oldReply, reply);
  477.     }
  478.  
  479.     return(reply->sfGood);
  480. }
  481.  
  482.  
  483.  
  484. /*****************************************************************************/
  485.  
  486.  
  487.  
  488. /* DisplayPutFile
  489. **
  490. ** Displays the StandardFile PutFile dialog box. Fills out the passed reply
  491. ** record, and returns the sfGood field as a result.
  492. */
  493.  
  494. #pragma segment File
  495. Boolean DisplayPutFile(StandardFileReply *reply)
  496. {
  497.     Str255        prompt;
  498.     Point        where = {100, 100};
  499.     SFReply        oldReply;
  500.  
  501.     GetIndString(prompt, rMiscStrings, sSFprompt);
  502.  
  503.     if (gSystemVersion >= 0x0700)    /* If new standard file available... */
  504.         StandardPutFile(prompt, reply->sfFile.name, reply);
  505.     else {
  506.         SFPutFile(where, prompt, reply->sfFile.name, nil, &oldReply);
  507.         ConvertOldToNewSFReply(&oldReply, reply);
  508.     }
  509.  
  510.     return(reply->sfGood);
  511. }
  512.  
  513.  
  514.  
  515. /*****************************************************************************/
  516.  
  517.  
  518.  
  519. #pragma segment File
  520. void    IncNewFileNum(Boolean flag)
  521. {
  522.     gIncNewFileNumFlag = flag;
  523. }
  524.  
  525.  
  526.  
  527. /*****************************************************************************/
  528. /*****************************************************************************/
  529. /*****************************************************************************/
  530.  
  531.  
  532.  
  533. /* AppReadDocument
  534. **
  535. ** Reads in specified file into the data portion of a document handle.
  536. */
  537.  
  538. #pragma segment File
  539. OSErr    AppReadDocument(FileRecHndl frHndl)
  540. {
  541.     short            fileRefNum;
  542.     OSErr            err;
  543.     char            hstate;
  544.     Ptr                ptr1, ptr2;
  545.     long            count;
  546.     GameListHndl    gameMovesHndl;
  547.     Handle            textHndl;
  548.  
  549.     fileRefNum = (*frHndl)->fileState.refNum;
  550.  
  551.     err = SetFPos(fileRefNum, fsFromStart, 0);
  552.         /* Set the file position to the beginning of the file. */
  553.  
  554.     if (!err) {        /* Read board info from file. */
  555.         hstate = LockHandleHigh((Handle)frHndl);
  556.         ptr1   = (Ptr)&((*frHndl)->doc);
  557.         ptr2   = (Ptr)&((*frHndl)->doc.endFileInfo);
  558.         count  = (long)ptr2 - (long)ptr1;
  559.         err    = FSRead(fileRefNum, &count, ptr1);
  560.         HSetState((Handle)frHndl, hstate);
  561.         if ((*frHndl)->doc.version != kVersion)
  562.             err = kWrongVersion;
  563.     }
  564.  
  565.     if (!err) {        /* Read move info from file. */
  566.         gameMovesHndl = (*frHndl)->doc.gameMoves;
  567.         count         = (*frHndl)->doc.numGameMoves * sizeof(GameElement);
  568.         SetHandleSize((Handle)gameMovesHndl, count);
  569.         err = MemError();
  570.         if (!err) {
  571.             hstate = LockHandleHigh((Handle)gameMovesHndl);
  572.             err = FSRead(fileRefNum, &count, (Ptr)(*gameMovesHndl));
  573.             HSetState((Handle)gameMovesHndl, hstate);
  574.             (*frHndl)->doc.timerRefTick = TickCount();
  575.             if (!err)
  576.                 if ((*frHndl)->doc.version != kVersion)
  577.                     err = kWrongVersion;
  578.         }
  579.     }
  580.  
  581.     if (!err) {        /* Read TextEdit text from file. */
  582.         textHndl = (Handle)(*frHndl)->doc.legalMoves;
  583.             /* There may be text saved to the file.  If there is any, this text
  584.             ** belongs in the out-box TextEdit control.  AppNewWindow creates
  585.             ** this control.  The problem is that a document is read before the
  586.             ** window for it is created.  Therefore the text will be placed
  587.             ** temporarily in the legalMoves handle.  Once GenerateLegalMoves
  588.             ** is called, the content of this handle will be overwritten.
  589.             ** GenereteLegalMoves isn't called until the window is created, so
  590.             ** this is an easy way to pass the text to AppNewWindow. */
  591.         count = 32000;
  592.             /* The size of the text isn't saved to disk.  This is the maximum
  593.             ** that we will accept. */
  594.         SetHandleSize(textHndl, count);
  595.         if (!(err = MemError())) {
  596.             hstate = LockHandleHigh(textHndl);
  597.             err    = FSRead(fileRefNum, &count, *textHndl);
  598.             HSetState((Handle)frHndl, hstate);
  599.             if (err == eofErr) err = noErr;
  600.             if (err) count = 0;
  601.             SetHandleSize(textHndl, count);
  602.                 /* Set the handle to the actual size of the text on disk. */
  603.         }
  604.     }
  605.  
  606.     return(err);
  607. }
  608.  
  609.  
  610.  
  611. /*****************************************************************************/
  612.  
  613.  
  614.  
  615. /* AppWriteDocument
  616. **
  617. ** Writes the data portion of a document handle to the specified file.
  618. */
  619.  
  620. #pragma segment File
  621. OSErr    AppWriteDocument(FileRecHndl frHndl)
  622. {
  623.     short            fileRefNum;
  624.     OSErr            err;
  625.     char            hstate;
  626.     Ptr                ptr1, ptr2;
  627.     long            count, fpos;
  628.     GameListHndl    gameMovesHndl;
  629.     TEHandle        te;
  630.     Handle            textHndl;
  631.  
  632.     fileRefNum = (*frHndl)->fileState.refNum;
  633.  
  634.     err = SetFPos(fileRefNum, fsFromStart, 0);
  635.         /* Set the file position to the beginning of the file. */
  636.  
  637.     if (!err) {        /* Write board info to file. */
  638.         hstate = LockHandleHigh((Handle)frHndl);
  639.         ptr1   = (Ptr)&((*frHndl)->doc);
  640.         ptr2   = (Ptr)&((*frHndl)->doc.endFileInfo);
  641.         count  = (long)ptr2 - (long)ptr1;
  642.         err    = FSWrite(fileRefNum, &count, ptr1);
  643.         HSetState((Handle)frHndl, hstate);
  644.     }
  645.  
  646.     if (!err) {        /* Write move info to file. */
  647.         gameMovesHndl = (*frHndl)->doc.gameMoves;
  648.         count         = (*frHndl)->doc.numGameMoves * sizeof(GameElement);
  649.         hstate = LockHandleHigh((Handle)gameMovesHndl);
  650.         err = FSWrite(fileRefNum, &count, (Ptr)(*gameMovesHndl));
  651.         HSetState((Handle)gameMovesHndl, hstate);
  652.     }
  653.  
  654.     if (!err) {        /* Write out-box TextEdit control text to file. */
  655.         te       = (*frHndl)->doc.message[1];
  656.         textHndl = (*te)->hText;
  657.         count    = (*te)->teLength;
  658.         hstate   = LockHandleHigh(textHndl);
  659.         err      = FSWrite(fileRefNum, &count, *textHndl);
  660.         HSetState(textHndl, hstate);
  661.     }
  662.  
  663.     if (!err) {
  664.         err = GetFPos(fileRefNum, &fpos);
  665.         if (!err) err = SetEOF(fileRefNum, fpos);
  666.     }
  667.  
  668.     return(err);
  669. }
  670.  
  671.  
  672.  
  673. /*****************************************************************************/
  674.  
  675.  
  676.  
  677. #pragma segment File
  678. OSErr    AppDuplicateDocument(FileRecHndl oldFrHndl, FileRecHndl *newFrHndl)
  679. {
  680.     OSErr            err;
  681.     GameListHndl    oldMoves, newMoves;
  682.     Ptr                ptr1, ptr2;
  683.     long            oldMovesSize, dataSize;
  684.  
  685.     err = AppNewDocument(newFrHndl);
  686.     if (!err) {
  687.         oldMoves = (*oldFrHndl)->doc.gameMoves;
  688.         newMoves = (**newFrHndl)->doc.gameMoves;
  689.         oldMovesSize = GetHandleSize((Handle)oldMoves);
  690.         SetHandleSize((Handle)newMoves, oldMovesSize);
  691.         err = MemError();
  692.         if (!err) {
  693.             ptr1     = (Ptr)&((*oldFrHndl)->doc);
  694.             ptr2     = (Ptr)&((*oldFrHndl)->doc.endFileInfo);
  695.             dataSize = (long)ptr2 - (long)ptr1;
  696.             ptr2     = (Ptr)&((**newFrHndl)->doc);
  697.             BlockMove(ptr1, ptr2, dataSize);
  698.             BlockMove((Ptr)*oldMoves, (Ptr)*newMoves, oldMovesSize);
  699.         }
  700.     }
  701.     return(err);
  702. }
  703.  
  704.  
  705.  
  706.