home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / NOTEPAD2.ZIP / MTEXT.C < prev    next >
C/C++ Source or Header  |  1989-02-08  |  27KB  |  901 lines

  1. /*
  2.  * mtext.c -- Text manager
  3.  *
  4.  * Created by Microsoft Corporation, 1989
  5.  */
  6.  
  7. #include <memory.h>
  8. #define INCL_WIN
  9. #include <os2.h>
  10. #include <opendlg.h>
  11. #include "mtypes.h"
  12. #include "mfuncs.h"
  13.  
  14. /***********************************************************************
  15. * Forward declarations
  16. ***********************************************************************/
  17.  
  18. // update the cursor and anchor position after text change
  19. private VOID UpdateMarks(PED ped, IPT iptFrom, IPT iptTo, IPT cch);
  20.  
  21. // signal that the text has changed
  22. private VOID TxtSignalChange(PED ped, BOOL fChanged);
  23.  
  24. /***********************************************************************
  25. * Searching text
  26. ***********************************************************************/
  27.  
  28. /*
  29.  * PPR TxtPPROfIpt(PED ped, PIPT ipt)
  30.  *
  31.  * Given an insertion point, returns a ppr which corresponds to that
  32.  * ipt.  Note that this could be one of several pieces -- a marker,
  33.  * or either of the pieces if an ipt falls in a split between two pieces.
  34.  * This function does not guarantee which of those pieces is returned.
  35.  *
  36.  * As a side-effect, this routine sets sets *pipt to the number of
  37.  * characters into the piece at which the ipt will be found.
  38.  *
  39.  * Note:  this function is a preliminary version.  It should be rewritten
  40.  * for speed.
  41.  */
  42. public PPR TxtPPROfIpt(PED ped, PIPT pipt)
  43. {
  44.     if (*pipt >= ped->iptFVL) {
  45.         *pipt -= ped->iptFVL;
  46.         return(PprOfOffset((PPR)(ped->pmrFVL), pipt));
  47.     } else {
  48.         return(PprOfOffset(ped->pprHead, pipt));
  49.     }
  50. }
  51.  
  52. /***********************************************************************
  53. * Text Deletion
  54. ***********************************************************************/
  55.  
  56. /*
  57.  * PPR DelText(PED ped, IPT offBegin, IPT cch)
  58.  *
  59.  * Deletes cch characters, starting at offBegin characters into the
  60.  * text.  Marks marker records as dirty as appropriate.
  61.  * Returns the piece containing text immediately before the deleted
  62.  * region.  Any text that is to be inserted, replacing this deletion,
  63.  * can be directly inserted at the end of this returned piece.
  64.  * (note that this *will* cause a split at the appropriate
  65.  * point even if no text is being deleted.)
  66.  */
  67. private PPR DelText(PED ped, IPT offBegin, IPT cch)
  68. {
  69.     PPR ppr;
  70.     OFFSET cchDel;
  71.     PMR pmr;
  72.  
  73.     ped->iptMac -= cch;
  74.     TxtSignalChange(ped, cch>0);
  75.  
  76.     ppr = TxtPPROfIpt(ped, &offBegin);
  77.     ppr = SkipMarkers(ppr,MARKER_ANY);
  78.     pmr = (PMR)SkipBackText(ppr->pprTextPrev,MARKER_LINE);
  79.     pmr->cchValid = min(pmr->cchValid,
  80.                         TxtLengthToBOLPPR(ped,ppr,(OFFSET)offBegin));
  81.  
  82.  
  83.     if ((cch + offBegin) < ppr->cchText) {
  84.         if (offBegin > 0) {
  85.             ppr = SplitPiece(ped, ppr, (SHORT)offBegin);
  86.         }
  87.         ppr = DelStartChars(ped, ppr, (SHORT)cch);
  88.     } else {
  89.         if (cch > 0) {
  90.             cchDel = (OFFSET)min((IPT)PieceLength(ppr)-offBegin,cch);
  91.             ppr = DelEndChars(ped, ppr, cchDel);
  92.             cch -= cchDel;
  93.             while (cch > 0)  {
  94.                 cchDel = (OFFSET)min((IPT)PieceLength(ppr),cch);
  95.                 ppr = DelStartChars(ped, ppr, cchDel);
  96.                 cch -= cchDel;
  97.             }
  98.         }
  99.     }
  100.     return(ppr->pprTextPrev);
  101. }
  102.  
  103. /***********************************************************************
  104. * Text Insertion
  105. ***********************************************************************/
  106.  
  107. /*
  108.  * BOOL InsText(PED ped, PPR ppr, PCHAR pchFrom, OFFSET cch)
  109.  *
  110.  * Inserts cch characters from *pchFrom at the end of the piece ppr.
  111.  * Returns TRUE iff the insertion finished successfully.
  112.  
  113.  */
  114. private BOOL InsText(PED ped, PPR ppr, PCHAR pchFrom, OFFSET cch)
  115. {
  116.     OFFSET cchRes, cchToGo;
  117.     PCHAR pchTo;
  118.     BOOL fOkay;
  119.  
  120.     if (cch == 0)
  121.         return(TRUE);
  122.  
  123.     TxtSignalChange(ped, TRUE);
  124.  
  125.     fOkay = TRUE;
  126.     cchToGo = cch;
  127.     while (cchToGo > 0) {
  128.         cchRes = cchToGo;
  129.         pchTo = InsEndChars(ped, &ppr, &cchRes);
  130.         if (pchTo == NULL) {    // memory failure
  131.             NotifyOwner(ped, EN_MEMERROR, NULL);
  132.             fOkay = FALSE;
  133.             break;
  134.         }
  135.         LCopyStruct(pchFrom, pchTo, cchRes);
  136.         cchToGo -= cchRes;
  137.         pchFrom += cchRes;
  138.     }
  139.     ped->iptMac += cch;
  140.     return(fOkay);
  141. }
  142.  
  143. /***********************************************************************
  144. * Text reformatting
  145. ***********************************************************************/
  146.  
  147. /*
  148.  * VOID SetValidPt(PMR pmr)
  149.  *
  150.  * Sets the valid point to be at most the current pixel/character length.
  151.  */
  152. private VOID SetValidPt(PMR pmr)
  153. {
  154.         if (pmr->cchValid >= pmr->cchLine) {
  155.                 pmr->cchValid = pmr->cchLine;
  156.                 pmr->pixValid = pmr->pixLine;
  157.         }
  158. }
  159.  
  160.  
  161. /*
  162.  * VOID TxtReformatNoWW(PED ped, PPR ppr, BOOL fAllText)
  163.  *
  164.  * A change has been made which affects the text; the text needs
  165.  * to be reformatted as a result.  This change could either be that text
  166.  * has been inserted or deleted, or that the formatting size has changed.
  167.  * All characters up to the piece PPR are assumed to be
  168.  * correctly formatted for the current formatting status.
  169.  * All bets are off after that ipt -- the text can be wrongly
  170.  * formatted; the text can contain any text, including end-of-line
  171.  * markers (which will require inserting new line markers.)
  172.  *
  173.  * if fAllText == TRUE, then we are trying to reformat the entire text
  174.  * from beginning to end.
  175.  *
  176.  * This function is used only when reformatting with word-wrap off.
  177.  */
  178. public VOID TxtReformatNoWW(PED ped, PPR ppr, BOOL fAllText)
  179. {
  180.     OFFSET off;
  181.     register CHAR ch;
  182.     PMR pmrLine;
  183.     BOOL fExit;
  184.     PPR pprSave;
  185.  
  186.     // set ppr to be the beginning of line's text (if not already) and
  187.     // set beginning-of-line piece pointer
  188.     pmrLine = (PMR)SkipBackText(ppr,MARKER_LINE);
  189.     ppr = SkipMarkers(pmrLine->pr.pprTextNext,~MARKER_LINE);
  190.  
  191.     // miscellaneous initialisation
  192.     pmrLine->pixLine = 0;
  193.     pmrLine->cchLine = 0;
  194.     off = 0;
  195.     ch = CharOfPointer(ppr,off);
  196.     fExit = FALSE;
  197.  
  198.     while (!fExit) {
  199.         if (pmrLine->cchValid == pmrLine->cchLine)
  200.             SetValidPt(pmrLine);
  201.         if (fIsMarker(ppr)) {
  202.             if (((PMR)ppr)->fFlags & MARKER_EOT) {
  203.                 fExit = TRUE;
  204.                 if (pmrLine->pixLine > ped->pixCurMax)
  205.                     ped->pixCurMax = pmrLine->pixLine;
  206.                 SetValidPt(pmrLine);
  207.             } else {
  208.                 pprSave = ppr;
  209.                 ch = AdvancePointer(&ppr, &off);
  210.                 DelMarker(ped, (PMR)pprSave);
  211.                 SetValidPt(pmrLine);
  212.             }
  213.         } else {
  214.             if (ch == '\n') {
  215.                 pmrLine->cchLine++;
  216.                 if (pmrLine->pixLine > ped->pixCurMax)
  217.                     ped->pixCurMax = pmrLine->pixLine;
  218.                 SetValidPt(pmrLine);
  219.                 ch = AdvancePointer(&ppr, &off);
  220.                 ppr = ConditionalSplitPiece(ped,ppr,off);
  221.                 off = 0;
  222.                 if (fIsMarkerType(ppr,(MARKER_LB))) {
  223.                     fExit = !fAllText;
  224.                     if (fExit) {
  225.                         break;
  226.                     }
  227.                     pmrLine = (PMR)ppr;
  228.                     ch = AdvancePointer(&ppr, &off);
  229.                 } else {
  230.                     pmrLine = InsBeforeMarker(ped,ppr,MARKER_LB);
  231.                 }
  232.                 pmrLine->pixLine = 0;
  233.                 pmrLine->cchLine = 0;
  234.             } else {
  235.                 if (fAllText && (ch == '\t')) {
  236.                     SetValidPt(pmrLine);
  237.                 }
  238.                 pmrLine->cchLine++;
  239.                 pmrLine->pixLine += PixOfChar(ped,
  240.                                               pmrLine->pixLine,
  241.                                               ch);
  242.                 ch = AdvancePointer(&ppr, &off);
  243.             }
  244.         }
  245.     }
  246. }
  247.  
  248.  
  249.  
  250. /*
  251.  * VOID TxtReformatWW(PED ped, PPR ppr, BOOL fAllText)
  252.  *
  253.  * A change has been made which affects the text; the text needs
  254.  * to be reformatted as a result.  This change could either be that text
  255.  * has been inserted or deleted, or that the formatting size has changed.
  256.  * All characters up to the piece PPR are assumed to be
  257.  * correctly formatted for the current formatting status (i.e. are word
  258.  * wrapped according to current window dimensions and no textual change
  259.  * has been made.)  All bets are off after that ipt -- the text can be wrongly
  260.  * formatted; the text can contain any text, including end-of-line
  261.  * markers (which will require inserting new line markers.)  Note that
  262.  * deleting spaces may cause characters to be moved to the previous line.
  263.  *
  264.  * if fAllText == TRUE, then we are trying to reformat the entire text
  265.  * from beginning to end.
  266.  *
  267.  * This function is used only when reformatting with word-wrap on.
  268.  */
  269. public VOID TxtReformatWW(PED ped, PPR ppr, BOOL fAllText)
  270. {
  271.     PIX pix, pixLine, pixLineSave;
  272.     IPT cchLineSave;
  273.     OFFSET off, offSave;
  274.     BOOL fExit;
  275.     PPR pprSave;
  276.     BOOL fFirstOnLine;
  277.     register CHAR ch;
  278.     IPT cMarkers;
  279.     PMR pmrLine;
  280.  
  281.     // set ppr to be the beginning of the previous line's text (if any)
  282.     ppr = SkipBackText(ppr,MARKER_LINE);
  283.     cMarkers = 1;
  284.     if (ppr->pprTextPrev != NULL) {
  285.         cMarkers = 0;
  286.         ppr = ppr->pprTextPrev;
  287.         ppr = SkipBackText(ppr,MARKER_LINE);
  288.     }
  289.     pmrLine = (PMR)ppr;
  290.     ppr = SkipMarkers(ppr,MARKER_ANY);
  291.  
  292.     // miscellaneous initialisation
  293.     pixLine = 0;
  294.     pmrLine->pixLine = 0;
  295.     pmrLine->cchLine = 0;
  296.     off = 0;
  297.     fFirstOnLine = TRUE;
  298.  
  299.     for (fExit = FALSE; !fExit; ) {
  300.         if (fIsMarker(ppr)) {
  301.             if (((PMR)ppr)->fFlags & MARKER_EOT) {
  302.                 fExit = TRUE;
  303.             } else {
  304.                 pprSave = ppr;
  305.                 ppr = ppr->pprTextNext;
  306.                 off = 0;
  307.                 DelMarker(ped, (PMR)pprSave);
  308.                 cMarkers++;
  309.                 pmrLine->cchValid = min(pmrLine->cchValid,pmrLine->cchLine);
  310.  
  311.             }
  312.         } else {
  313.             ch = *(ppr->pchText + off);
  314.             while (fFirstOnLine && !(fIsWhiteSpace(ch)) && (ch != '\n') && !(fIsMarker(ppr))) {
  315.                 pix = PixOfChar(ped,pixLine,ch);
  316.                 pixLine += pix;
  317.                 pmrLine->pixLine += pix;
  318.                 pmrLine->cchLine++;
  319.                 pprSave = ppr;
  320.                 offSave = off;
  321.                 pixLineSave = pixLine;
  322.                 cchLineSave = pmrLine->cchLine;
  323.                 ch = AdvancePointer(&ppr, &off);
  324.                 if (fIsWhiteSpace(ch) || (ch == '\n')) {
  325.                     fFirstOnLine = FALSE;
  326.                     break;
  327.                 } else if ((pixLine>DispWidth(ped)) && (ped->fWordWrap)) {
  328.                     ppr = ConditionalSplitPiece(ped, pprSave, offSave);
  329.                     pmrLine->cchLine = cchLineSave;
  330.                     pmrLine->pixLine = pixLineSave;
  331.                     pmrLine = InsBeforeMarker(ped,ppr,MARKER_SPILL);
  332.                     ppr = pprSave;
  333.                     off = offSave;
  334.                     fFirstOnLine = TRUE;
  335.                     pixLine = 0;
  336.                     pmrLine->pixLine = 0;
  337.                     pmrLine->cchLine = 0;
  338.                 }
  339.             }
  340.             while (!fIsMarker(ppr)) {
  341.                 while ((ch == ' ') || (ch == '\t')) {
  342.                     fFirstOnLine = FALSE;
  343.                     pix = PixOfChar(ped,pixLine,ch);
  344.                     pixLine += pix;
  345.                     pmrLine->pixLine += pix;
  346.                     pmrLine->cchLine++;
  347.                     ch = AdvancePointer(&ppr, &off);
  348.                 }
  349.                 if (ch == '\n') {
  350.                     pmrLine->cchLine++;
  351.                     ch = AdvancePointer(&ppr, &off);
  352.                     ppr = ConditionalSplitPiece(ped, ppr, off);
  353.                     off = 0;
  354.                     if (fIsMarkerType(ppr,MARKER_LB) && !fAllText) {
  355.                         if ((cMarkers > 0) && (!fAllText)) {
  356.                                 fExit = TRUE;
  357.                         } else {
  358.                                 pmrLine = (PMR)ppr;
  359.                                 cMarkers++;
  360.                                 AdvancePointer(&ppr, &off);
  361.                         }
  362.                     } else {
  363.                         pmrLine = InsBeforeMarker(ped,ppr,MARKER_LB);
  364.                     }
  365.                     if (pixLine > ped->pixCurMax)
  366.                             ped->pixCurMax = pixLine;
  367.                     fFirstOnLine = TRUE;
  368.                     pixLine = 0;
  369.                     if (!fExit) {
  370.                             pmrLine->pixLine = 0;
  371.                             pmrLine->cchLine = 0;
  372.                     }
  373.                     break;
  374.                 }
  375.                 if (!fIsWhiteSpace(ch) && !fIsMarker(ppr)) {
  376.                     pprSave = ppr;
  377.                     offSave = off;
  378.                     pixLineSave = pixLine;
  379.                     cchLineSave = pmrLine->cchLine;
  380.                     do {
  381.                         pix = PixOfChar(ped,pixLine,ch);
  382.                         pixLine += pix;
  383.                         pmrLine->pixLine +=  pix;
  384.                         pmrLine->cchLine++;
  385.                         ch = AdvancePointer(&ppr, &off);
  386.                     } while (!fIsWhiteSpace(ch) &&
  387.                         (ch != '\n') &&
  388.                         ((!ped->fWordWrap)||(pixLine <= DispWidth(ped))) &&
  389.                         !fIsMarker(ppr));
  390.                     if ((!ped->fWordWrap) && (pixLine > DispWidth(ped))) {
  391.                         ppr = pprSave;
  392.                         off = offSave;
  393.                         pmrLine->pixLine = pixLineSave;
  394.                         pmrLine->cchLine = cchLineSave;
  395.                         ch = '\0';
  396.                         ppr = ConditionalSplitPiece(ped, ppr, off);
  397.                         off = 0;
  398.                         pmrLine = InsBeforeMarker(ped,ppr,MARKER_SLB);
  399.                         fFirstOnLine = TRUE;
  400.                         if (pixLine > ped->pixCurMax)
  401.                             ped->pixCurMax = pixLine;
  402.                         pixLine = 0;
  403.                         pmrLine->pixLine = 0;
  404.                         pmrLine->cchLine = 0;
  405.                         break;
  406.                     }
  407.                 }
  408.             }
  409.         }
  410.     }
  411. }
  412.  
  413. /*
  414.  * VOID TxtReformat(PED ped, PPR ppr, BOOL fAllText)
  415.  *
  416.  * A change has been made which affects the text; the text needs
  417.  * to be reformatted as a result.  This change could either be that text
  418.  * has been inserted or deleted, or that the formatting size has changed.
  419.  * All characters up to the piece PPR are assumed to be
  420.  * correctly formatted for the current formatting status (i.e. are word
  421.  * wrapped according to current window dimensions and no textual change
  422.  * has been made.)  All bets are off after that ipt -- the text can be wrongly
  423.  * formatted; the text can contain any text, including end-of-line
  424.  * markers (which will require inserting new line markers.)  Note that
  425.  * deleting spaces may cause characters to be moved to the previous line.
  426.  *
  427.  * if fAllText == TRUE, then we are trying to reformat the entire text
  428.  * from beginning to end.
  429.  */
  430. public VOID TxtReformat(PED ped, PPR ppr, BOOL fAllText)
  431. {
  432.         if  (TxtQueryWordWrap(ped)) {
  433.                 TxtReformatWW(ped,  ppr, fAllText);
  434.         } else {
  435.                 TxtReformatNoWW(ped, ppr, fAllText);
  436.         }
  437. }
  438.  
  439.  
  440. /***********************************************************************
  441. * Really truly global functions
  442. * These functions define the interface to the outside world
  443. ***********************************************************************/
  444.  
  445. /*
  446.  * BOOL TxtInit(PED ped)
  447.  *
  448.  * Initialises the text manager by creating a single empty paragraph.
  449.  * Assumes memory manager has already been initialised.  Causes
  450.  * initialisation of piece manager.
  451.  *
  452.  * Returns TRUE iff initialisation went through without a problem.
  453.  */
  454.  
  455. public BOOL TxtInit(PED ped)
  456. {
  457.     PPR ppr;
  458.  
  459.     ped->iptCursor = ped->iptAnchor = 0L;
  460.     ppr = PieceInit(ped,CCHDEFAULTMAX);
  461.     ped->pprHead = (PPR)InsBeforeMarker(ped, ppr, MARKER_BOT);
  462.     LockMarker((PMR)ped->pprHead,TRUE);
  463.     ped->pprTail = (PPR)InsEndMarker(ped, ppr, MARKER_EOT);
  464.     LockMarker((PMR)ped->pprTail,TRUE);
  465.     ped->fWordWrap = FALSE;
  466.     ped->fChanged = FALSE;
  467.     ped->iptMac = 0;
  468.     ped->iptMax = CCHDEFAULTMAX;
  469.     return(ped->pprHead != NULL);
  470. }
  471.  
  472.  
  473. /*
  474.  * BOOL TxtChange(PED ped, IPT iptFrom, IPT iptTo, PCHAR pch, IPT cch)
  475.  *
  476.  * Causes the text in the range [from, to) to be deleted, and replaced
  477.  * with the contents of the buffer pointed to by pch.  The buffer is
  478.  * assumed to be cch characters long.  Note that buffers are limited
  479.  * to 64K-1 bytes in length.
  480.  *
  481.  * If a maximum text length has been defined, and the change will cause
  482.  * the text length to exceed that limit, the change fails and no changes
  483.  * are made.
  484.  *
  485.  * Initiates a reformat on the text.
  486.  * Returns true iff the operation completed successfully.
  487.  */
  488. public BOOL TxtChange(PED ped, IPT iptFrom, IPT iptTo, PCHAR pch, OFFSET cch)
  489. {
  490.     PPR ppr;
  491.     IPT iptRem;
  492.  
  493.     if (iptTo < iptFrom) {
  494.         iptRem = iptTo;
  495.         iptTo = iptFrom;
  496.         iptFrom = iptRem;
  497.     }
  498.  
  499.     if ((ped->iptMax>0) && (ped->iptMac+cch-iptTo+iptFrom>ped->iptMax)) {
  500.         NotifyOwner(ped, EN_MEMERROR, NULL);
  501.         return(FALSE);
  502.     }
  503.  
  504.     ppr = DelText(ped, iptFrom, iptTo-iptFrom);
  505.     if (!InsText(ped, ppr, pch, cch)) {
  506.         return(FALSE);
  507.     }
  508.     TxtReformat(ped, ppr, FALSE);
  509.     UpdateMarks(ped, iptFrom, iptTo, (IPT)cch);
  510.     return(TRUE);
  511. }
  512.  
  513.  
  514. /*
  515.  * IPT TxtLength(PED ped)
  516.  *
  517.  * returns the total number of characters in the text.
  518.  */
  519. public IPT TxtLength(PED ped)
  520. {
  521.     return(ped->iptMac);
  522. }
  523.  
  524. /***********************************************************************
  525. *  Word wrap status
  526. ***********************************************************************/
  527.  
  528. /*
  529.  * BOOL TxtQueryWordWrap(PED ped)
  530.  *
  531.  * Returns the word wrap status of a document.
  532.  */
  533. public BOOL TxtQueryWordWrap(PED ped)
  534. {
  535.     return(ped->fWordWrap);
  536. }
  537.  
  538.  
  539. /*
  540.  * BOOL TxtSetWordWrap(PED ped, BOOL fWW)
  541.  *
  542.  * Sets a document's wordwrap status to fWW.
  543.  * Causes reformatting to occur if wordwrap is being turned on.
  544.  */
  545. public BOOL TxtSetWordWrap(PED ped, BOOL fWW)
  546. {
  547.     if (fWW != ped->fWordWrap) {
  548.         ped->fWordWrap = fWW;
  549.         TxtReformat(ped, ped->pprHead, TRUE);
  550.     }
  551.     return(fWW);
  552. }
  553.  
  554. /***********************************************************************
  555. *  Cursor/Anchor external manipulation
  556. ***********************************************************************/
  557.  
  558. /*
  559.  * IPT UpdateAMark(IPT ipt, IPT iptFrom, IPT iptTo, IPT cch, BOOL fEnd)
  560.  *
  561.  * Given a TxtChange which deleted the range iptFrom..iptTo and replaced
  562.  * it with cch characters at iptFrom, updates the mark ipt to reflect
  563.  * the deletion/insertion.  fEnd => mark will be set to end of changed
  564.  * region if mark was in [iptFrom, iptTo],  else will be set to beginning
  565.  * of changed region.
  566.  */
  567. private IPT UpdateAMark(IPT ipt, IPT iptFrom, IPT iptTo, IPT cch, BOOL fEnd)
  568. {
  569.     if (ipt >= iptFrom) {
  570.         if (ipt <= iptTo) {
  571.             ipt = iptFrom + (fEnd ? cch : 0);
  572.         } else {
  573.             ipt += cch - iptTo + iptFrom;
  574.         }
  575.     }
  576.     return(ipt);
  577. }
  578.  
  579.  
  580. /*
  581.  * VOID UpdateMarks(PED ped, IPT iptFrom, IPT iptTo, IPT cch)
  582.  *
  583.  * Given a TxtChange which deleted the range iptFrom..iptTo and replaced
  584.  * it with cch characters at iptFrom, updates the marks to reflect
  585.  * the deletion/insertion.
  586.  */
  587. private VOID UpdateMarks(PED ped, IPT iptFrom, IPT iptTo, IPT cch)
  588. {
  589.     TxtSetAnchorCursor(ped,
  590.             UpdateAMark(ped->iptAnchor, iptFrom, iptTo, cch, TRUE),
  591.             UpdateAMark(ped->iptCursor, iptFrom, iptTo, cch, TRUE));
  592.     ped->iptFVL = UpdateAMark(ped->iptFVL, iptFrom, iptTo, cch, FALSE);
  593. }
  594.  
  595.  
  596. /*
  597.  * IPT TxtQueryAnchor(PED ped)
  598.  *
  599.  * Returns the current anchor.
  600.  */
  601. public IPT TxtQueryAnchor(PED ped)
  602. {
  603.     return(ped->iptAnchor);
  604. }
  605.  
  606.  
  607. /*
  608.  * IPT TxtQueryCursor(PED ped)
  609.  *
  610.  * Returns the current cursor.
  611.  */
  612. public IPT TxtQueryCursor(PED ped)
  613. {
  614.     return(ped->iptCursor);
  615. }
  616.  
  617.  
  618. /*
  619.  * IPT TxtQueryMinSel(PED ped)
  620.  *
  621.  * Returns the current minimum selection point.
  622.  */
  623. public IPT TxtQueryMinSel(PED ped)
  624. {
  625.     return((ped->iptAnchor<ped->iptCursor)?ped->iptAnchor:ped->iptCursor);
  626. }
  627.  
  628.  
  629. /*
  630.  * IPT TxtQueryMaxSel(PED ped)
  631.  *
  632.  * Returns the current maximum selection point.
  633.  */
  634. public IPT TxtQueryMaxSel(PED ped)
  635. {
  636.     return((ped->iptAnchor>ped->iptCursor)?ped->iptAnchor:ped->iptCursor);
  637. }
  638.  
  639.  
  640. /*
  641.  * BOOL TxtSetAnchorCursor(PED ped, IPT iptAnchor, IPT iptCursor)
  642.  *
  643.  * Sets the cursor and anchor position.  Does not cause redraw.
  644.  * If an ipt is negative, leaves that mark alone.
  645.  */
  646. public IPT TxtSetAnchorCursor(PED ped, IPT iptAnchor, IPT iptCursor)
  647. {
  648.     IPT cchText;
  649.  
  650.     cchText = TxtLength(ped);
  651.     ped->fSelDelta = TRUE;
  652.  
  653.     if (iptAnchor >= 0)
  654.         ped->iptAnchor = min(cchText,iptAnchor);
  655.     if (iptCursor >= 0)
  656.         ped->iptCursor = min(cchText,iptCursor);
  657.  
  658.     return(TRUE);
  659. }
  660.  
  661. /***********************************************************************
  662. *  Changed flag status
  663. ***********************************************************************/
  664.  
  665. /*
  666.  * BOOL TxtQueryChanged(PED ped)
  667.  *
  668.  * Returns the changed status of a document.
  669.  */
  670. public BOOL TxtQueryChanged(PED ped)
  671. {
  672.     return(ped->fChanged);
  673. }
  674.  
  675.  
  676. /*
  677.  * BOOL TxtSetChanged(PED ped, BOOL fChanged)
  678.  *
  679.  * Sets a document's wordwrap status to fChanged.  Returns old changed status.
  680.  */
  681. public BOOL TxtSetChanged(PED ped, BOOL fChanged)
  682. {
  683.     if (fChanged != ped->fChanged) {
  684.         ped->fChanged = fChanged;
  685.         if (fChanged) {
  686.             NotifyOwner(ped, EN_CHANGE, NULL);
  687.             return(FALSE);
  688.         } else {
  689.             return(TRUE);
  690.         }
  691.     } else {
  692.         return(fChanged);
  693.     }
  694. }
  695.  
  696. /*
  697.  * VOID TxtSignalChange(PED ped, BOOL fChanged)
  698.  *
  699.  * Signals that a change has happened if fChanged is TRUE.
  700.  */
  701. private VOID TxtSignalChange(PED ped, BOOL fChanged)
  702. {
  703.     if (fChanged)
  704.         TxtSetChanged(ped,TRUE);
  705. }
  706.  
  707. /***********************************************************************
  708. *  Text Limit Set/Query
  709. ***********************************************************************/
  710.  
  711. /*
  712.  * IPT TxtQueryLimit(PED ped)
  713.  *
  714.  * Returns the maximum text length of a document.
  715.  */
  716. public IPT TxtQueryLimit(PED ped)
  717. {
  718.     return(ped->iptMax);
  719. }
  720.  
  721.  
  722. /*
  723.  * BOOL TxtSetLimit(PED ped, IPT iptMax)
  724.  *
  725.  * Sets the text limit to a given value.  If more text than the new
  726.  * limit currently exists, truncates the document.  Returns TRUE if
  727.  * the limit was set without truncation; FALSE otherwise.
  728.  */
  729. public BOOL TxtSetLimit(PED ped, IPT iptMax)
  730. {
  731.     ped->iptMax = iptMax;
  732.     if ((ped->iptMac > iptMax) && (iptMax > 0)) {
  733.             TxtChange(ped, iptMax, ped->iptMac, NULL, 0);
  734.             return(FALSE);
  735.     } else {
  736.             return(TRUE);
  737.     }
  738. }
  739.  
  740. /***********************************************************************
  741. *  Miscellaneous text structure queries
  742. ***********************************************************************/
  743.  
  744. /*
  745.  * IPT TxtLengthToEOLPPR(PED ped, PPR ppr, OFFSET off, BOOL fIncludeLBCh)
  746.  *
  747.  * Returns the number of characters between this ppr/off and the end of
  748.  * the line.  Only valid in formatted text.
  749.  */
  750. public IPT TxtLengthToEOLPPR(PED ped, PPR ppr, OFFSET off, BOOL fIncludeLBCh)
  751. {
  752.         IPT cipt;
  753.  
  754.         cipt = -off;
  755.     if (!ped) return cipt;
  756.         do {
  757.                 cipt += ppr->cchText;
  758.                 ppr = ppr->pprTextNext;
  759.         } while ((ppr != NULL) &&
  760.                  (!fIsMarker(ppr) || !(((PMR)ppr)->fFlags & MARKER_LINE)));
  761.         if (!fIncludeLBCh &&
  762.             (ppr != NULL) &&
  763.             (((PMR)ppr)->fFlags & MARKER_LB))
  764.                 cipt--;
  765.         return(cipt);
  766. }
  767.  
  768.  
  769. /*
  770.  * IPT TxtLengthToEOL(PED ped, IPT ipt, BOOL fIncludeLBCh)
  771.  *
  772.  * Returns the number of characters between this ipt and the end of
  773.  * the line.  Only valid in formatted text.
  774.  */
  775. public IPT TxtLengthToEOL(PED ped, IPT ipt, BOOL fIncludeLBCh)
  776. {
  777.         PPR ppr;
  778.  
  779.         ppr = TxtPPROfIpt(ped, &ipt);
  780.         return(TxtLengthToEOLPPR(ped, ppr, (OFFSET)ipt, fIncludeLBCh));
  781. }
  782.  
  783.  
  784. /*
  785.  * IPT TxtLengthToBOLPPR(PED ped, PPR ppr, OFFSET off)
  786.  *
  787.  * Returns the number of characters between this ppr/off and the beginning of
  788.  * the line.  Only valid in formatted text.
  789.  */
  790. public IPT TxtLengthToBOLPPR(PED ped, PPR ppr, OFFSET off)
  791. {
  792.         IPT cipt;
  793.  
  794.         cipt = off;
  795.     if (!ped) return cipt;
  796.  
  797.         ppr = ppr->pprTextPrev;
  798.         while ((ppr != NULL) &&
  799.                (!fIsMarker(ppr) || !(((PMR)ppr)->fFlags & MARKER_LINE))) {
  800.                 cipt += ppr->cchText;
  801.                 ppr = ppr->pprTextPrev;
  802.         }
  803.         return(cipt);
  804. }
  805.  
  806.  
  807. /*
  808.  * IPT TxtLengthToBOL(PED ped, IPT ipt)
  809.  *
  810.  * Returns the number of characters between this ipt and the beginning of
  811.  * the line.  Only valid in formatted text.
  812.  */
  813. public IPT TxtLengthToBOL(PED ped, IPT ipt)
  814. {
  815.         PPR ppr;
  816.  
  817.         ppr = TxtPPROfIpt(ped, &ipt);
  818.         return(TxtLengthToBOLPPR(ped, ppr, (OFFSET)ipt));
  819. }
  820.  
  821.  
  822. /*
  823.  * IPT TxtLineLength(PED ped, PPR ppr)
  824.  *
  825.  * Returns the length of a line containing a piece.
  826.  */
  827. public IPT TxtLineLength(PED ped, PPR ppr)
  828. {
  829.         IPT cipt;
  830.  
  831.         cipt = 0;
  832.         ppr = SkipBackText(ppr, MARKER_LINE);
  833.         return(TxtLengthToEOLPPR(ped, ppr, 0, TRUE));
  834. }
  835.  
  836.  
  837.  
  838. /*
  839.  * IPT TxtCchToBegOfToken(PPR ppr, OFFSET off)
  840.  *
  841.  * Returns the number of characters between this ppr/off and the beginning of
  842.  * the surrounding token.
  843.  */
  844. public IPT TxtCchToBegOfToken(PPR ppr, OFFSET off)
  845. {
  846.     BOOL fSpace;
  847.     CHAR ch;
  848.     IPT cch = 0;
  849.  
  850.     if (fIsMarker(ppr)) {
  851.         ppr = SkipMarkers(ppr, MARKER_ANY);
  852.         off = 0;
  853.     }
  854.     ch = CharOfPointer(ppr, off);
  855.     fSpace = fIsWhiteSpace(ch);
  856.     while ((fIsWhiteSpace(ch) == fSpace) && (ch != '\n')) {
  857.         cch++;
  858.         do {
  859.             ch = RetreatPointer(&ppr, &off);
  860.         } while (fIsMarkerType(ppr,MARKER_NOTLINE));
  861.         if (fIsMarker(ppr)) {
  862.             return(cch-1);
  863.         }
  864.     }
  865.     return(cch-1);
  866. }
  867.  
  868.  
  869.  
  870. /*
  871.  * IPT TxtCchToEndOfToken(PPR ppr, OFFSET off)
  872.  *
  873.  * Returns the number of characters between this ppr/off and the end of
  874.  * the surrounding token.  If ppr is a marker, uses next piece.
  875.  */
  876. public IPT TxtCchToEndOfToken(PPR ppr, OFFSET off)
  877. {
  878.     BOOL fSpace;
  879.     CHAR ch;
  880.     IPT cch = 0;
  881.  
  882.     if (fIsMarker(ppr)) {
  883.         ppr = SkipMarkers(ppr, MARKER_ANY);
  884.         off = 0;
  885.     }
  886.     ch = CharOfPointer(ppr, off);
  887.     fSpace = fIsWhiteSpace(ch);
  888.  
  889.     while ((fIsWhiteSpace(ch) == fSpace) && (ch != '\n')) {
  890.         cch++;
  891.         do {
  892.             ch = AdvancePointer(&ppr, &off);
  893.         } while (fIsMarker(ppr) && (((PMR)ppr)->fFlags & (~MARKER_LINE)));
  894.         if (fIsMarker(ppr)) {
  895.             break;
  896.         }
  897.     }
  898.  
  899.     return(cch);
  900. }
  901.