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

  1. /* $Header: /nfs/unmvax/faculty/crowley/x/pt/RCS/copymove.c,v 1.8 1992/03/04 17:07:18 crowley Exp crowley $ */
  2.  
  3. #include <stdio.h>
  4. #include "pt.h"
  5.  
  6. extern int addHandle;
  7. extern Offset addPosition;
  8.  
  9. /* the scrap buffer */
  10. struct changeItem scrapBuffer;
  11. int scrapMode = SELCHAR;
  12.  
  13. void
  14. updateFile( fileId, offset, len, oneLineOnly )
  15.     int fileId;
  16.     Offset offset;
  17.     Offset len;
  18.     int oneLineOnly;
  19. {
  20.     extern char msgBuffer[];
  21.     extern struct window *windowList;
  22.     extern struct window *selWindow;
  23.     extern int debug;
  24.  
  25.     register struct window *w;
  26.     Offset topOffset;
  27.     int n, col, firstRow, lastRow;
  28.     int fid;
  29.  
  30.     /* redraw the affected windows */
  31.     w = windowList;
  32.     while( w != NULL ) {
  33.         fid = w->fileId;
  34.         if( fid == fileId ) {
  35.             /* repaint the window as necessary */
  36.             if( offset <= w->posBotline )
  37.                 w->posBotline += len;
  38.             else
  39.                 goto nextWindow;
  40.             topOffset = w->posTopline;
  41.             if( offset < topOffset ) {
  42.                 /* remember: len < 0 for a delete */
  43.                 /* a delete overlapping this window? */
  44.                 if( offset > (topOffset+len) ) {
  45.                     n = -1;
  46.                     w->posTopline = prevLine( fid,
  47.                             topOffset, &n );
  48.                 }
  49.                 if( !oneLineOnly ) {
  50.                     /* recalculate the line number by */
  51.                     /* letting prevLine count as far back */
  52.                     /* as it can */
  53.                     n = 3000000;
  54.                     (void)prevLine(fid, w->posTopline, &n);
  55.                     w->numTopline = n + 1;
  56.                 }
  57.             }
  58.             OffsetToXY( w, offset, &firstRow, &col );
  59.             if( oneLineOnly ) {
  60.                 if( len > 1 )
  61.                     /* len > 0 ==> an insert */
  62.                     OffsetToXY( w, offset+len-1, &lastRow,
  63.                                     &col );
  64.                 else
  65.                     lastRow = firstRow;
  66.             } else {
  67.                 lastRow = w->nRows - 1;
  68.             }
  69.             if( firstRow != -1 )
  70.                 drawWindowFast(w, firstRow, lastRow,
  71.                                 0, w->nCols-1);
  72.         }
  73.     nextWindow:
  74.         w = w->nextWindow;
  75.     }
  76. }
  77.  
  78. void
  79. updateTops(fileId, offset, len, oneLineOnly )
  80.     int fileId;
  81.     Offset offset;
  82.     Offset len;
  83.     int oneLineOnly;
  84. {
  85.     extern char msgBuffer[];
  86.     extern struct window *windowList;
  87.     extern int debug;
  88.  
  89.     register struct window *w;
  90.     int n;
  91.     Offset topOffset;
  92.     int fid;
  93.  
  94.     /* adjust the data of the affected windows */
  95.     w = windowList;
  96.     while( w != NULL ) {
  97.         fid = w->fileId;
  98.         if( fid == fileId ) {
  99.             if( offset < w->posBotline )
  100.                 w->posBotline += len;
  101.             else
  102.                 goto nextWindow;
  103.             topOffset = w->posTopline;
  104.             if( offset < topOffset ) {
  105.                 /* a delete overlapping this window? */
  106.                 if( offset > (topOffset+len) ) {
  107.                     n = -1;
  108.                     w->posTopline = prevLine( fid,
  109.                             topOffset, &n);
  110.                 }
  111.                 if( !oneLineOnly ) {
  112.                     /* recalculate the line number by */
  113.                     /* letting prevLine count as far back */
  114.                     /* as it can */
  115.                     n = 3000000;
  116.                     (void)prevLine(fid, w->posTopline, &n);
  117.                     w->numTopline = n + 1;
  118.                 }
  119.             }
  120.         }
  121.     nextWindow:
  122.         w = w->nextWindow;
  123.     }
  124. }
  125.  
  126. void
  127. exchWithScrap()
  128. {
  129.     extern char msgBuffer[];
  130.     extern struct changeItem scrapBuffer;
  131.     extern Offset selBegin, selEnd;
  132.     extern struct window *selWindow;
  133.     extern struct openFile *files;
  134.  
  135.     Offset length;
  136.     struct changeItem *thisChange;
  137.     Piece firstPiece;
  138.     struct openFile * ff = &files[selWindow->fileId];
  139.  
  140.     /* check if this is a readOnly file */
  141.     if( ff->flags & READ_ONLY ) {
  142.         sprintf(msgBuffer, "File %s is read only", ff->origName);
  143.         msg(msgBuffer, (int)1);
  144.         return;
  145.     }
  146.  
  147.     /* remember what was in the scrap */
  148.     firstPiece = scrapBuffer.firstPiece;
  149.     length = scrapBuffer.length;
  150.     /* prevent this from getting freed when the scrap buffer is reused */
  151.     scrapBuffer.firstPiece = NULL;
  152.     
  153.     /* move the selection into the scrap */
  154.     (void)deleteChars( selWindow->fileId, NOUPDATE, 1 );
  155.  
  156.     /* record in the change history */
  157.     thisChange = GetNewChange( ff );
  158.     thisChange->type = CINSERT;
  159.     thisChange->w = selWindow;
  160.     thisChange->flags = 0;
  161.     thisChange->position = selBegin;
  162.     thisChange->length = length;
  163.     thisChange->lineNumber = selWindow->numTopline;
  164.     thisChange->fileId = selWindow->fileId;
  165.     thisChange->firstPiece = firstPiece;
  166.     RecordChange( ff, thisChange );
  167.  
  168.     /* copy the old scrap into the file */
  169.     copyPieces( firstPiece, selWindow, selBegin, length, 1, 0 );
  170.     
  171.     /* free the scrap pieces */
  172.     freePieces(firstPiece);
  173. }
  174.  
  175. void
  176. copyToScrap(fromWindow, fromBegin, fromEnd)
  177.     struct window *fromWindow;
  178.     Offset fromBegin, fromEnd;
  179. {
  180.     extern char msgBuffer[];
  181.     extern struct changeItem scrapBuffer;
  182.     extern struct window *selWindow;
  183.     extern int selMode;
  184.     extern int scrapMode;
  185.  
  186.     int fromId;
  187.     Offset fb, copyLength;
  188.     Piece tempPP;
  189.  
  190.     fromId = fromWindow->fileId;
  191.     
  192.     /* eliminate the EOF marker from the selection */
  193.     fb = fileSize(fromId);
  194.     if( fromEnd >= fb ) {
  195.         if( fromBegin < fb )
  196.             fromEnd = fb-1;
  197.         else    /* only the EOF symbol is selected */
  198.             return;
  199.     }
  200.     copyLength = fromEnd - fromBegin + 1;
  201.  
  202.     /* free the old scrap buffer pieces */
  203.     freePieces(scrapBuffer.firstPiece);
  204.  
  205.     /* record in the scrap buffer */
  206.     scrapBuffer.type = 1;
  207.     scrapBuffer.length = copyLength;
  208.     scrapBuffer.w = selWindow;
  209.     scrapBuffer.flags = 0;
  210.     tempPP = getFreePiece();
  211.     scrapBuffer.firstPiece = tempPP;
  212.     scrapMode = selMode;
  213.  
  214.     tempPP->file = addHandle;
  215.     tempPP->position = addPosition;
  216.     fb = fromBegin;
  217.     while( fb <= fromEnd ) {
  218.         writeChar( (char)getFileByte(fromId, fb++), addPosition++);
  219.     }
  220.     tempPP->length = copyLength;
  221. }
  222.  
  223. void
  224. insScrap( doInsert, update )
  225.     int doInsert;
  226.     int update;
  227. {
  228.     extern char msgBuffer[];
  229.     extern struct window *selWindow;
  230.     extern Offset selBegin, selEnd;
  231.     extern struct changeItem scrapBuffer;
  232.     extern struct openFile *files;
  233.      extern int selMode;
  234.     extern int scrapMode;
  235.     extern int maxFiles;
  236.  
  237.     Offset limit, logByte;
  238.     Piece tempPP, oldScrap;
  239.     struct openFile *ff;
  240.     struct changeItem *thisChange;
  241.  
  242.     /* check if this is a readOnly file */
  243.     if( files[selWindow->fileId].flags & READ_ONLY ) {
  244.         sprintf(msgBuffer, "File %s is read only",
  245.             files[selWindow->fileId].origName);
  246.         msg(msgBuffer, (int)1);
  247.         return;
  248.     }
  249.  
  250.     /* See if the text in the scrap buffer is in an edit file rather */
  251.     /* then in the add file.  If it is we need to copy it to the add */
  252.     /* file. */
  253.     if( !scrapBuffer.type ) {
  254.         /* keep a pointer to the old piece list */
  255.         oldScrap = scrapBuffer.firstPiece;
  256.         /* scrapBuffer.length will not change */
  257.         
  258.         /* get a new piece and initialize the fields */
  259.         tempPP = getFreePiece();
  260.         tempPP->file = addHandle;
  261.         tempPP->position = addPosition;
  262.         tempPP->length = scrapBuffer.length;
  263.         
  264.         /* this will be the new scrapBuffer piece list */
  265.         scrapBuffer.type = 1;  /* now it is addFile only type */
  266.         scrapBuffer.firstPiece = tempPP;
  267.         
  268.         /* Now copy the characters into the add file */
  269.         logByte = 0;
  270.         limit = scrapBuffer.length;
  271.  
  272.         /* simulate a file this was deleted from */
  273.         ff = &files[maxFiles];
  274.         ff->hiLogBuffer = -1;
  275.         ff->loLogBuffer = -1;
  276.         ff->origHandle = scrapBuffer.fileId;
  277.         ff->fileSize = limit;
  278.         ff->logPiece = oldScrap;
  279.         ff->loLogPiece = 0;
  280.         ff->hiLogPiece = oldScrap->length - 1;
  281.         while( logByte < limit ) {
  282.             /* copy the characters in pp to the add file */
  283.             writeChar( (char)getFileByte(maxFiles, logByte++),
  284.                 addPosition++);
  285.         }
  286.         
  287.         freePieces(oldScrap);  /* free the old piece chain */
  288.     }
  289.     if( doInsert ) {
  290.         /* record in the change history */
  291.         ff = &files[selWindow->fileId];
  292.         thisChange = GetNewChange( ff );
  293.         thisChange->type = CCOPY;
  294.         selMode = scrapMode;
  295.         selBegin = adjustSelMode( selBegin );
  296.         thisChange->position = selBegin;
  297.         thisChange->length = scrapBuffer.length;
  298.         thisChange->lineNumber = selWindow->numTopline;
  299.         thisChange->fileId = selWindow->fileId;
  300.         thisChange->w = selWindow;
  301.         thisChange->flags = 0;
  302.         thisChange->firstPiece = dupPieces(scrapBuffer.firstPiece);
  303.         RecordChange( ff, thisChange );
  304.  
  305.         copyPieces( scrapBuffer.firstPiece, selWindow, selBegin,
  306.             scrapBuffer.length, update, 0 );
  307.     }
  308. }
  309.  
  310. void
  311. copyMove(fromWindow, fromBegin, fromEnd, toWindow, toPosition, mode)
  312.     struct window *fromWindow, *toWindow;
  313.     Offset fromBegin, fromEnd, toPosition;
  314.     int mode;
  315. {
  316.     extern char msgBuffer[];
  317.     extern struct openFile *files;
  318.     extern Offset selBegin, selEnd;
  319.     extern struct window *selWindow;
  320.  
  321.     int n, fromId, toId;
  322.     Offset  fb, copyLength;
  323.     Piece tempPP;
  324.     struct changeItem *thisChange;
  325.     struct changeItem *currentChange;
  326.     int wasCR;
  327.     char ch;
  328.     struct openFile * ff = &files[toWindow->fileId];
  329.  
  330.     /* check if this is a readOnly file */
  331.     if( ff->flags & READ_ONLY ) {
  332.         sprintf(msgBuffer, "File %s is read only",ff->origName);
  333.         msg(msgBuffer, (int)1);
  334.         return;
  335.     }
  336.  
  337.     /* Is this a move with source and destination ovelapping? */
  338.     if( mode==MOVE && fromBegin<=toPosition && toPosition<=fromEnd
  339.                         && fromWindow==toWindow ) {
  340.         msg("Cannot move text into itself", 2);
  341.         return;
  342.     }
  343.  
  344.     fromId = fromWindow->fileId;
  345.     toId = toWindow->fileId;
  346.  
  347.     /* eliminate the EOF marker from the selection */
  348.     fb = fileSize(fromId);
  349.     if( fromEnd >= fb ) {
  350.         if( fromBegin < fb )
  351.             fromEnd = fb-1;
  352.         else    /* only the EOF symbol is selected */
  353.             return;
  354.     }
  355.     copyLength = fromEnd - fromBegin + 1;
  356.  
  357.     /* record in the change history */
  358.     thisChange = GetNewChange( ff );
  359.     if( mode == COPY )
  360.         thisChange->type = CCOPY;
  361.     else
  362.         thisChange->type = CMOVE;
  363.     thisChange->position = toPosition;
  364.     thisChange->length = copyLength;
  365.     thisChange->lineNumber = selWindow->numTopline;
  366.     thisChange->fileId = toId;
  367.     thisChange->w = selWindow;
  368.     thisChange->flags = 0;
  369.     tempPP = getFreePiece();
  370.     thisChange->firstPiece = tempPP;
  371.     RecordChange( ff, thisChange );
  372.  
  373.     tempPP->file = addHandle;
  374.     tempPP->position = addPosition;
  375.     fb = fromBegin;
  376.     wasCR = 0;
  377.     while( fb <= fromEnd ) {
  378.         ch = (char)getFileByte(fromId, fb++);
  379.         if( ch == '\n' )
  380.             wasCR = 1;
  381.         writeChar( ch, addPosition++);
  382.     }
  383.     tempPP->length = copyLength;
  384.  
  385.     /* if it is a move, then delete the from text */
  386.     if( mode == MOVE ) {
  387.         selWindow = fromWindow;
  388.         selBegin = fromBegin;
  389.         selEnd = fromEnd;
  390. #ifdef XXXXXXXX
  391.         if( fromWindow == toWindow )
  392.             n = NOUPDATE;
  393.         else
  394. #endif
  395.             n = UPDATEWINDOWS;
  396.         (void)deleteChars( fromWindow->fileId, n, 1 );
  397.         /* we're going to change the selection in copyPieces */
  398.         /* to the character after the moved text. */
  399.         drawSelection( 1 );
  400.         /* if we deleted text before the toPosition we have */
  401.         /* to adjust it since the logical text positions change */
  402.         /* after a delete.  We also fix up the position on the */
  403.         /* delete following so it will look like it really did */
  404.         /* take place AFTER the copying in of the moved text */
  405.         if( fromWindow->fileId == toWindow->fileId ) {
  406.             if( toPosition > fromBegin )
  407.                 toPosition -= copyLength;
  408.             else {
  409.                 currentChange = GetCurrentChange( ff );
  410.                 currentChange->position += copyLength;
  411.             }
  412.         }
  413.     }
  414.  
  415.     copyPieces(thisChange->firstPiece, toWindow, toPosition, copyLength,
  416.                         1, !wasCR );
  417. }
  418.  
  419. void
  420. copyPieces(fromPP, toWindow, toPosition, copyLength, update, oneLineOnly)
  421.     Piece fromPP;
  422.     struct window *toWindow;
  423.     Offset toPosition, copyLength;
  424.     int update;
  425.     int oneLineOnly;
  426. {
  427.     extern char msgBuffer[];
  428.     extern struct openFile *files;
  429.     extern Offset selBegin, selEnd;
  430.     extern int selMode;
  431.     extern struct window *selWindow;
  432.     extern int trace_file;
  433.  
  434.     int toId;
  435.     Offset offset, toNN;
  436.     Piece nextPP, toPP, lastPP;
  437.     struct openFile *toFF;
  438.     Piece pp2;
  439.     struct window *w;
  440.  
  441.     if( trace_file > 0 ) {
  442.         sprintf( msgBuffer, "C %2d %5d %5d\n",
  443.             toWindow->fileId, toPosition, copyLength);
  444.         write( trace_file, msgBuffer, strlen(msgBuffer) );
  445.     }
  446.     if( update ) {
  447.         /* just using these variables to save the selection */
  448.         offset = selBegin;
  449.         toNN = selEnd;
  450.         w = selWindow;
  451.         selBegin = selEnd = toPosition;
  452.         selWindow = toWindow;
  453.         selBegin = offset;
  454.         selEnd = toNN;
  455.         selWindow = w;
  456.     }
  457.     
  458.     /* This is a special case to handle a backspace problem.  To wit, */
  459.     /* if we delete text and type in new text, then select other text */
  460.     /* and AGAIN, then the piece from the first change is copied in. */
  461.     /* If we then backspace and type a new character, the piece itself */
  462.     /* is changed and so the orignal edit is changed also.  We have to */
  463.     /* prevent this so we bump addPosition in this case so the */
  464.     /* backspace does not change the piece */
  465.     /* A BETTER SOLUTION would be to make an actual copy of the text */
  466.     /* in the piece.  This would allow further editing that would then */
  467.     /* be able to be repeated again. */
  468.     toPP = fromPP;        /* just using toPP as a convenient variable */
  469.     while( toPP->nextPiece != NULL )
  470.         toPP = toPP->nextPiece;
  471.     if( (toPP->file == addHandle)
  472.      && (toPP->position+toPP->length == addPosition) )
  473.          ++addPosition;
  474.         
  475.     /* compute some values for later efficiency */
  476.     toId = toWindow->fileId;
  477.     toFF = &files[toId];
  478.  
  479.     /* find out what piece 'toBegin' is in */
  480.     toPP = findPiece(toPosition, toFF, &toNN);
  481.     /* special case for the end of the file */
  482.     if( toPosition > toFF->fileSize ) {
  483.         /* leave toPP as the last piece in the file */
  484.         nextPP = NULL;
  485.     } else if( toPosition > toNN ) {
  486.         /* copied text starts inside piece "toPP" */
  487.         /* We split toPP into two pieces (toPP and nextPP) */
  488.         /* at toPosition */
  489.         /* get a new piece */
  490.         nextPP = getFreePiece();
  491.         /* link the new piece in before the piece after toPP */
  492.         pp2 = toPP->nextPiece;
  493.         nextPP->nextPiece = pp2;
  494.         if( pp2 != NULL )
  495.             pp2->prevPiece = nextPP;
  496.         /* adjust the fields of the two pieces */
  497.         offset = toPosition - toNN;
  498.         nextPP->file = toPP->file;
  499.         nextPP->position = toPP->position + offset;
  500.         nextPP->length = toPP->length - offset;
  501.         toPP->length = offset;
  502.     } else {
  503.         nextPP = toPP;
  504.         toPP = toPP->prevPiece;
  505.     }
  506.     
  507.     /* now copy the pieces into the piece list between toPP and nextPP */
  508.     lastPP = toPP;
  509.     while( fromPP != NULL ) {
  510.         pp2 = getFreePiece();
  511.         /* copy the information into the new piece */
  512.         pp2->file = fromPP->file;
  513.         pp2->position = fromPP->position;
  514.         pp2->length = fromPP->length;
  515.         /* link in the new piece */
  516.         pp2->prevPiece = lastPP;
  517.         /* link it into the list */
  518.         if( lastPP != NULL )
  519.             lastPP->nextPiece = pp2;
  520.         else /* new first item on the list */
  521.             toFF->pieceList = pp2;
  522.         /* move to the next piece to copy */
  523.         lastPP = pp2;
  524.         fromPP = fromPP->nextPiece;
  525.     }
  526.     lastPP->nextPiece = nextPP;
  527.     if( nextPP != NULL )
  528.         nextPP->prevPiece = lastPP;
  529.  
  530.     /* make the cached piece the one after the copied pieces */
  531.     /* unless it is NULL */
  532.     if( nextPP != NULL ) {
  533.         toFF->logPiece = nextPP;
  534.         toFF->loLogPiece = toPosition + copyLength;
  535.         toFF->hiLogPiece = toFF->loLogPiece + nextPP->length - 1;
  536.     } else {    /* make it the first piece in the file */
  537.         toFF->logPiece = toFF->pieceList;
  538.         toFF->loLogPiece = 0;
  539.         toFF->hiLogPiece = toFF->loLogPiece
  540.                     + (toFF->logPiece)->length - 1;
  541.     }
  542.  
  543.     /* update the length of the "to" file */
  544.     toFF->fileSize += copyLength;
  545.  
  546.     /* invalidate the buffer cache of the "to" file */
  547.     toFF->hiLogBuffer = -1;
  548.     toFF->loLogBuffer = -1;
  549.  
  550.     /* record the fact that the file has changed */
  551.     if( !(toFF->flags & IS_CHANGED) ) {
  552.         toFF->flags |= IS_CHANGED;
  553.         NewOpenList();
  554.         banner( toWindow, 0 );
  555.     }
  556.  
  557.     /* invalidate the last-row-found cache */
  558.     if( toWindow->posCurLast > toPosition )
  559.         toWindow->lastPosTop = -1;
  560.     
  561.     /* make the selection the character past the copied text */
  562.     if( selWindow != toWindow ) {
  563.         drawSelection( 1 );
  564.         selWindow = toWindow;
  565.     }
  566.     selEnd = selBegin = toPosition + copyLength;
  567.  
  568.     /* change selection mode to character mode */
  569.     selMode = SELCHAR;
  570.     if( update )
  571.         updateFile(toId, toPosition, copyLength, oneLineOnly);
  572. }
  573.