home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume17 / tcl-editor / part07 / insdel.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-18  |  15.5 KB  |  575 lines

  1. /* $Header: /nfs/unmvax/faculty/crowley/x/pt/RCS/insdel.c,v 1.7 1992/03/04 17:07:18 crowley Exp crowley $ */
  2.  
  3. #include "pt.h"
  4. #include <stdio.h>
  5.  
  6. /* the globals additions file */
  7. int addHandle;
  8. Offset addPosition;
  9.  
  10. void
  11. insertChar(c)
  12.     int c;
  13. {
  14.     extern struct window *selWindow;
  15.     extern Offset selBegin, selEnd;
  16.     extern char msgBuffer[];
  17.     extern struct openFile *files;
  18.     extern Offset addPosition;
  19.     extern int addHandle;
  20.     extern int debug;
  21.     extern int hypertextOn;
  22.     extern int trace_file;
  23.  
  24.     struct changeItem *thisChange;
  25.     struct openFile *ff = &files[selWindow->fileId];
  26.     Piece pp, pp2, thispp, nextpp, thirdpp;
  27.     Offset nn, offset;
  28.     unsigned char ch = (unsigned char)c;
  29.     int oldSelBegin;
  30.  
  31. #ifdef HYPERTEXT
  32.     if( hypertextOn && selWindow->document != NULL ) {
  33.         int ret;
  34.  
  35.         /* convert selBegin to the underlying (real) file */
  36.         oldSelBegin = selBegin;
  37.         ret = GetRealSelection( ff, 1 /* get selBegin only */ );
  38.  
  39.         /* check for insertion in decoration */
  40.         if( ret & 1 ) {
  41.             printf(
  42. "insertChar ERROR: cannot insert into synthetic text\n");
  43.             return;
  44.         }
  45.  
  46.         /* free the piece list of the old view */
  47.         FreeOldViewPieces( ff );
  48.  
  49.         /* fix up the fileId and ff */
  50.         selWindow->fileId = selWindow->realFileId;
  51.         ff = &files[selWindow->fileId];
  52.     }
  53. #endif
  54.  
  55.     /* check if this is a readOnly file */
  56.     if( ff->flags & READ_ONLY ) {
  57.         sprintf(msgBuffer, "File %s is read only", ff->origName);
  58.         msg(msgBuffer, 1);
  59.         return;
  60.     }
  61.  
  62.     /* find out what piece 'selBegin' is in */
  63.     pp = findPiece( selBegin, ff, &nn );
  64.  
  65.     offset = selBegin - nn;
  66.     if( offset > 0 ) {    /* we must split the piece */
  67.         /* we insert two new pieces */
  68.         /* nextpp is for the character we are inserting */
  69.         /* thirdpp is the split of portion of pp */
  70.         
  71.         /* update the fields of the new piece */
  72.         nextpp = getFreePiece();
  73.         nextpp->file = addHandle;
  74.         nextpp->position = addPosition;
  75.         nextpp->length = 1;
  76.  
  77.         /* update the fields of the split off piece */
  78.         thirdpp = getFreePiece();
  79.         thirdpp->file = pp->file;
  80.         thirdpp->position = pp->position + offset;
  81.         thirdpp->length = pp->length - offset;
  82.  
  83.         /* update the fields of the original piece */
  84.         /* pp->file remains the same */
  85.         /* pp->position remains the same */
  86.         pp->length = offset;
  87.         
  88.         /* link everything together again */
  89.         nextpp->nextPiece = thirdpp;
  90.         thirdpp->prevPiece = nextpp;
  91.         pp2 = pp->nextPiece;
  92.         thirdpp->nextPiece = pp2;
  93.         if( pp2 != NULL )
  94.             pp2->prevPiece = thirdpp;
  95.         nextpp->prevPiece = pp;
  96.         pp->nextPiece = nextpp;
  97.  
  98.         /* make the third piece the cached one */
  99.         ff->logPiece = thirdpp;
  100.         ff->loLogPiece = selBegin + 1;
  101.         ff->hiLogPiece = selBegin + thirdpp->length;
  102.     } else {    /* put in front of this piece */
  103.         /* can we put it at the end of the previous piece? */
  104.         thispp = pp->prevPiece;
  105.         /* if (1) there IS a previous piece and */
  106.         /*    (2) it is a piece in the add file and */
  107.         /*    (3) it is just before the piece we are adding */
  108.         /* then we coalsce the two pieces */
  109.         if( (thispp != NULL)    /* pp is not the first piece */
  110.          && (thispp->file == addHandle)    /* in the add file */
  111.          && (thispp->position+thispp->length == addPosition)
  112.         ) {
  113.             ++(thispp->length);    /* simply adjust the length */
  114.             ff->logPiece = pp;
  115.             ff->loLogPiece = nn + 1;
  116.             ff->hiLogPiece = nn + pp->length;
  117.         } else {
  118.             /* create a new piece for this character */
  119.             thispp = getFreePiece();
  120.             thispp->file = addHandle;
  121.             thispp->position = addPosition;
  122.             thispp->length = 1;
  123.             thispp->nextPiece = pp;
  124.             pp2 = pp->prevPiece;
  125.             pp->prevPiece = thispp;
  126.             thispp->prevPiece = pp2;
  127.             if( pp2 != NULL )
  128.                 pp2->nextPiece = thispp;
  129.             else
  130.                 ff->pieceList = thispp;
  131.             ff->logPiece = thispp;
  132.             ff->loLogPiece = selBegin;
  133.             ff->hiLogPiece = selBegin;
  134.         }
  135.     }
  136.  
  137.     /* record in the change history */
  138.     /* see if we can add this to the last insert */
  139.     thisChange = GetCurrentChange( ff );
  140.     if( thisChange->type == CINSERT
  141.      && thisChange->fileId == selWindow->fileId
  142.      && selBegin == thisChange->position+thisChange->length ) {
  143.         ++(thisChange->length);
  144.         ++(thisChange->firstPiece->length);
  145.     } else {
  146.         /* record in the change history */
  147.         thisChange = GetNewChange( ff );
  148.         thisChange->type = CINSERT;
  149.         thisChange->position = selBegin;
  150.         thisChange->length = 1;
  151.         thisChange->flags = 0;
  152.         thisChange->lineNumber = selWindow->numTopline;
  153.         thisChange->fileId = selWindow->fileId;
  154.         thisChange->w = selWindow;
  155.         pp = getFreePiece();
  156.         thisChange->firstPiece = pp;
  157.         pp->file = addHandle;
  158.         pp->position = addPosition;
  159.         pp->length = 1;
  160.         RecordChange( ff, thisChange );
  161.     }
  162.  
  163.     if( trace_file > 0 ) {
  164.         sprintf( msgBuffer, "I %2d %5d %5d\n",
  165.             selWindow->fileId, selBegin, 1 );
  166.         write( trace_file, msgBuffer, strlen(msgBuffer) );
  167.     }
  168.  
  169.     /* add one character to the file */
  170.     ff->fileSize += 1;
  171.     writeChar(ch, addPosition++);
  172.  
  173.     /* invalidate the buffer cache */
  174.     ff->hiLogBuffer = -1;
  175.     ff->loLogBuffer = -1;
  176.  
  177.     /* record the fact that the file has changed */
  178.     if( !(ff->flags & IS_CHANGED) ) {
  179.         ff->flags |= IS_CHANGED;
  180.         NewOpenList();
  181.         banner( selWindow, 0 );
  182.     }
  183.  
  184.     /* adjust window data even though we do not redraw */
  185.     updateTops( selWindow->fileId, selBegin, 1, (c!='\n') );
  186.  
  187.     /* invalidate the last-row-found cache */
  188.     if( selWindow->posCurLast > selBegin )
  189.         selWindow->lastPosTop = -1;
  190.     
  191.     /* move the selection to char past new char */
  192.     selEnd = ++selBegin;
  193.  
  194. #ifdef HYPERTEXT
  195.     if( hypertextOn && selWindow->document != NULL ) {
  196.         /* create a new piece table for the view */
  197.         selBegin = selEnd = ++oldSelBegin;
  198.         selWindow->realFileId = selWindow->fileId;
  199.         selWindow->fileId = CreateViewFile( selWindow );
  200.         drawWindow( selWindow );
  201.     }
  202. #endif
  203.     /* NOTE -- THE SELECTION WILL BE WRONG. FIX THIS LATER */
  204. }
  205.  
  206. int
  207. delChar()
  208. {
  209.     extern struct window *selWindow;
  210.     extern Offset selBegin, selEnd;
  211.     extern char msgBuffer[];
  212.     extern struct openFile *files;
  213.     extern Offset addPosition;
  214.     extern int addHandle;
  215.     extern int debug;
  216.  
  217.     Offset nn, offset;
  218.     struct openFile *ff;
  219.     Piece pp, thispp;
  220.     struct changeItem *currentChange;
  221.     char ch;
  222.  
  223.     /* find out what piece 'selBegin' is in */
  224.     ff = &files[selWindow->fileId];
  225.     pp = findPiece(selBegin, ff, &nn);
  226.  
  227.     /* check if this is a readOnly file */
  228.     if( ff->flags & READ_ONLY ) {
  229.         sprintf(msgBuffer, "File %s is read only", ff->origName);
  230.         msg(msgBuffer, 1);
  231.         return 0;
  232.     }
  233.  
  234.     offset = selBegin - nn;
  235.     if( offset > 0 )
  236.         return 0;
  237.  
  238.     /* get the char deleted (for updateTops) */
  239.     ch = getFileByte( selWindow->fileId, selBegin );
  240.  
  241.     /* is the char to delete at the end of the previous piece? */
  242.     thispp = pp->prevPiece;
  243.     /* if (1) there IS a previous piece and */
  244.     /*    (2) it is a piece in the add file and */
  245.     /*    (3) it is just before the piece we are adding and */
  246.     /*    (4) we are not deleting the last char in the piece */
  247.     /*    (5) the preceding change was an insert */
  248.     /* then we coalsce the two pieces */
  249.     currentChange = GetCurrentChange( ff );
  250.     if( (thispp != NULL)    /* pp is not the first piece */
  251.      && (thispp->file == addHandle)    /* in the add file */
  252.      && (thispp->position+thispp->length == addPosition)
  253.      && (thispp->length >= 1)
  254.      && (currentChange->type == CINSERT)
  255.     ) {
  256.         --(thispp->length);    /* simply adjust the length */
  257.         ff->logPiece = pp;
  258.         ff->loLogPiece = nn - 1;
  259.         ff->hiLogPiece = nn + pp->length - 1;
  260.     } else
  261.         return 0;
  262.  
  263.     /* record in the change history */
  264.     /* see if we can add this to the last insert */
  265.     if( currentChange->type == CINSERT
  266.      && currentChange->fileId == selWindow->fileId
  267.      && selBegin == currentChange->position+currentChange->length ) {
  268.         --(currentChange->length);
  269.         --(currentChange->firstPiece->length);
  270.     } else {
  271.         ++(thispp->length);    /* re-adjust the length */
  272.         return 0;
  273.     }
  274.  
  275.     /* subtract one character to the file */
  276.     ff->fileSize -= 1;
  277.     --addPosition;
  278.  
  279.     /* invalidate the buffer cache */
  280.     ff->hiLogBuffer = -1;
  281.     ff->loLogBuffer = -1;
  282.  
  283.     /* record the fact that the file has changed */
  284.     if( !(ff->flags & IS_CHANGED) ) {
  285.         ff->flags |= IS_CHANGED;
  286.         NewOpenList();
  287.         banner( selWindow, 0 );
  288.     }
  289.  
  290.     /* adjust window data even though we do not redraw */
  291.     updateTops( selWindow->fileId, selBegin, 1, (ch!='\n') );
  292.  
  293.     /* invalidate the last-row-found cache */
  294.     if( selWindow->posCurLast > selBegin )
  295.         selWindow->lastPosTop = -1;
  296.  
  297.     selEnd = --selBegin;
  298.     return 1;
  299. }
  300.  
  301. int
  302. deleteChars(fileId, update, toScrap)
  303.     /* toScrap=0 --> do not put in the scrap */
  304.     /* toScrap=1 --> do put in the scrap */
  305.     /* toScrap=2 --> do not put in the scrap or the history */
  306.     int fileId, toScrap;
  307.     DoUpdate update;
  308. {
  309.     extern char msgBuffer[];
  310.     extern int debug;
  311.     extern Offset selBegin, selEnd;
  312.     extern struct window *selWindow;
  313.     extern struct changeItem scrapBuffer;
  314.     extern int selMode;
  315.     extern int scrapMode;
  316.     extern Offset addPosition;
  317.     extern struct openFile *files;
  318.     extern int addHandle;
  319.     extern int trace_file;
  320.  
  321.     struct openFile *ff = &files[fileId];
  322.     Offset sb, nn, curPos, nextPos, offset, delLength;
  323.     int wasLF;
  324.     Piece pp;
  325.     Piece pp2, firstPP, nextPP, lastPP;
  326.     struct changeItem *thisChange;
  327.     int oldSelBegin;
  328.  
  329. #ifdef HYPERTEXT
  330.     if( hypertextOn && selWindow->document != NULL ) {
  331.         int ret;
  332.  
  333.         /* convert selBegin and selEnd to the underlying (real) file */
  334.         oldSelBegin = selBegin;
  335.         ret = GetRealSelection( ff, 0 /* get selBegin and selEnd */ );
  336.  
  337.         /* check for insertion in decoration */
  338.         if( ret & 1 ) {
  339.             printf(
  340. "deleteChars ERROR: cannot delete from synthetic text\n");
  341. /* LATER: just adjust to the first real text */
  342.             return 0;
  343.         }
  344.  
  345.         /* LATER: go through and only delete real text */
  346.         /* NOT any block markers */
  347.  
  348.         /* free the piece list of the old view */
  349.         FreeOldViewPieces( ff );
  350.  
  351.         /* fix up the fileId and ff */
  352.         selWindow->fileId = selWindow->realFileId;
  353.         ff = &files[selWindow->fileId];
  354.     }
  355. #endif
  356.     nn = ff->fileSize;
  357.  
  358.     /* check if this is a readOnly file */
  359.     if( ff->flags & READ_ONLY ) {
  360.         sprintf(msgBuffer, "File %s is read only", ff->origName);
  361.         msg(msgBuffer, 1);
  362.         return 0;
  363.     }
  364.  
  365.     /* eliminate the EOF marker from the selection */
  366.     if( selEnd >= nn ) {
  367.         if( selBegin < nn )
  368.             selEnd = nn-1;
  369.         else    /* only the EOF symbol is selected */
  370.             return 0;
  371.     }
  372.  
  373.     delLength = selEnd - selBegin + 1;
  374.  
  375.     /* see if we are deleting a newline */
  376.     if( delLength < 100 ) {    /* lines are usally < 100 chars */
  377.         wasLF = 0;
  378.         sb = selBegin;
  379.         while( sb <= selEnd )
  380.             if( (char)getFileByte( fileId, sb++ ) == '\n' ) {
  381.                 wasLF = 1;
  382.                 break;
  383.             }
  384.     } else    /* assume there is one -- too many to search */
  385.         wasLF = 1;
  386.  
  387.     /* find out what piece 'selBegin' is in */
  388.     firstPP = findPiece( selBegin, ff, &curPos);
  389.  
  390. /* first see if we have to split pp */
  391. offset = selBegin - curPos;
  392. if( offset > 0 ) {    /* delete starts inside this piece */
  393.     /* split firstPP at selBegin */
  394.     /* that is, get a new piece and adjust all the fields */
  395.     nextPP = getFreePiece();
  396.     nextPP->file = firstPP->file;
  397.     nextPP->position = firstPP->position + offset;
  398.     nextPP->length = firstPP->length - offset;
  399.     firstPP->length = offset;
  400.     nextPP->nextPiece = firstPP->nextPiece;
  401.     nextPP->prevPiece = firstPP;
  402.     if( (pp = firstPP->nextPiece) != NULL )
  403.         pp->prevPiece = nextPP;
  404.     firstPP->nextPiece = nextPP;
  405.     firstPP = nextPP;
  406.     curPos += offset;
  407. }
  408.  
  409. /* Now the delete begins at the first byte of firstPP */
  410. /* See where the last piece is */
  411. lastPP = firstPP;
  412. while( 1 ) {
  413.     /* does the selection end in this piece? */
  414.     nextPos = curPos + lastPP->length;
  415.     if( nextPos > selEnd )
  416.         break;
  417.     curPos = nextPos;
  418.     lastPP = lastPP->nextPiece;
  419. }
  420.  
  421. /* now we see if we have to split this piece */
  422. if( selEnd < nextPos-1 ) {    /* delete ends inside this piece */
  423.     /* split lastPP at selEnd */
  424.     /* that is, get a new piece and adjust all the fields */
  425.     nextPP = getFreePiece();
  426.     nextPP->file = lastPP->file;
  427.     offset = selEnd - curPos + 1;
  428.     nextPP->position = lastPP->position + offset;
  429.     nextPP->length = lastPP->length - offset;
  430.     lastPP->length = offset;
  431.     pp = lastPP->nextPiece;
  432.     nextPP->nextPiece = pp;
  433.     nextPP->prevPiece = lastPP;
  434.     if( pp != NULL )
  435.         pp->prevPiece = nextPP;
  436.     lastPP->nextPiece = nextPP;
  437. }
  438.  
  439. /* Now the selection has been isolated in pieces firstPP (which begins */
  440. /* with selBegin) and lastPP (which ends with selEnd) */
  441. /* Now just link them out of this piece table */
  442. if( (pp = firstPP->prevPiece) != NULL ) {
  443.     nextPP = lastPP->nextPiece;
  444.     pp->nextPiece = nextPP;
  445.     ff->logPiece = pp;
  446.     ff->loLogPiece = selBegin - pp->length;
  447.     if( nextPP != NULL )
  448.         nextPP->prevPiece = firstPP->prevPiece;
  449.     /* see if we can combine the two pieces now together */
  450.     if( (nextPP != NULL) && (pp->file == nextPP->file)
  451.      && ((pp->position+pp->length) == nextPP->position) ) {
  452.         pp->length += nextPP->length;    /* add to first piece */
  453.         /* link the second piece out of the list */
  454.         pp2 = nextPP->nextPiece;
  455.         pp->nextPiece = pp2;
  456.         if( pp2 != NULL )
  457.             pp2->prevPiece = pp;
  458.         /* isolate the one piece and free is (as a chain) */
  459.         nextPP->nextPiece = nextPP->prevPiece = NULL;
  460.         freePieces(nextPP);
  461.     }
  462. } else {    /* this delete is at the beginning of the file and there */
  463.         /* are no pieces in front of firstPiece */
  464.     pp = lastPP->nextPiece;
  465.     ff->pieceList = pp;
  466.     if( pp != NULL ) {
  467.         pp->prevPiece = NULL;
  468.         ff->logPiece = pp;
  469.     } else {
  470.         /* the piece table is empty so put a 0 length piece in it */
  471.         /* it is convenient to be able to assume (in other parts */
  472.         /* of the editor) that a piece table always contains at */
  473.         /* least one piece */
  474.         pp = getFreePiece();
  475.         pp->file = addHandle;
  476.         pp->position = addPosition;
  477.         pp->length = 0;
  478.         ff->pieceList = pp;
  479.         ff->logPiece = pp;
  480.     }
  481.     ff->loLogPiece = 0;
  482. }
  483.  
  484.     /* make this an independent chain */
  485.     firstPP->prevPiece = NULL;
  486.     lastPP->nextPiece = NULL;
  487.  
  488.     /* put it into the history */
  489.     if( toScrap != 2 ) {
  490.         /* record in the change history */
  491.         thisChange = GetNewChange( ff );
  492.         thisChange->type = CDELETE;
  493.         thisChange->position = selBegin;
  494.         thisChange->length = delLength;
  495.         thisChange->flags = 0;
  496.         thisChange->lineNumber = selWindow->numTopline;
  497.         thisChange->fileId = fileId;
  498.         thisChange->w = selWindow;
  499.         thisChange->firstPiece = firstPP;
  500.         RecordChange( ff, thisChange );
  501.     }
  502.  
  503.     if( trace_file > 0 ) {
  504.         sprintf( msgBuffer, "D %2d %5d %5d\n",
  505.             fileId, selBegin, delLength );
  506.         write( trace_file, msgBuffer, strlen(msgBuffer) );
  507.     }
  508.  
  509.     if( toScrap == 1 ) {
  510.         freePieces(scrapBuffer.firstPiece);
  511.         scrapBuffer.length = delLength;
  512.         scrapBuffer.type = 0;
  513.         scrapBuffer.fileId = ff->origHandle;
  514.         scrapBuffer.firstPiece = dupPieces(firstPP);
  515.         scrapMode = selMode;
  516.     } else if( toScrap == 2 )
  517.         freePieces(firstPP);
  518.  
  519.     /* update the cached piece */
  520.     ff->hiLogPiece = ff->loLogPiece + (ff->logPiece)->length - 1;
  521.     if( ff->hiLogPiece > ff->fileSize )
  522.         /* this could happen if we just deleted the last piece */
  523.         /* in the piece table */
  524.         ff->hiLogPiece = ff->fileSize;
  525.  
  526.     /* invalidate the buffer cache */
  527.     ff->hiLogBuffer = -1;
  528.     ff->loLogBuffer = -1;
  529.  
  530.     /* record the fact that the file has changed */
  531.     if( !(ff->flags & IS_CHANGED) ) {
  532.         ff->flags |= IS_CHANGED;
  533.         NewOpenList();
  534.         banner( selWindow, 0 );
  535.     }
  536.  
  537.     /* invalidate the last-row-found cache */
  538.     if( selWindow->posCurLast > selBegin )
  539.         selWindow->lastPosTop = -1;
  540.         
  541.     /* update the file length */
  542.     ff->fileSize -= delLength;
  543.  
  544.     /* the character after the deleted characters is the new selection */
  545.     selEnd = selBegin;
  546.  
  547.     /* entend the selection according to the selection mode */
  548.     { int row, col, n = -1;
  549.     Offset beginRowCp;
  550.     OffsetToXY( selWindow, selBegin, &row, &col );
  551.     beginRowCp = prevLine( selWindow->fileId, selBegin, &n );
  552.     modeExtend( selWindow, selBegin, row, col, beginRowCp );
  553.     }
  554.  
  555. #ifdef HYPERTEXT
  556.     if( hypertextOn && selWindow->document != NULL ) {
  557.         /* create a new piece table for the view */
  558.         selBegin = selEnd = oldSelBegin;
  559.         selWindow->realFileId = selWindow->fileId;
  560.         selWindow->fileId = CreateViewFile( selWindow );
  561.         drawWindow( selWindow );
  562.     }
  563. #endif
  564.  
  565.     if( update == UPDATEWINDOWS ) {
  566.         /* redraw all the affected windows */
  567.         updateFile( fileId, selBegin, -delLength, !wasLF );
  568.     } else {
  569.         /* adjust window data even though we do not redraw */
  570.         updateTops( fileId, selBegin, -delLength, !wasLF );
  571.     }
  572.  
  573.     return wasLF;
  574. }
  575.