home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / x / volume17 / tcleditr / part07 < prev    next >
Encoding:
Text File  |  1992-03-17  |  49.5 KB  |  1,828 lines

  1. Newsgroups: comp.sources.x
  2. Path: uunet!cis.ohio-state.edu!zaphod.mps.ohio-state.edu!mips!msi!dcmartin
  3. From: crowley@chaco.cs.unm.edu (Charlie Crowley)
  4. Subject: v17i008: point text editor (TCL and TK), Part07/16
  5. Message-ID: <1992Mar18.141448.26827@msi.com>
  6. Originator: dcmartin@fascet
  7. Sender: dcmartin@msi.com (David C. Martin - Moderator)
  8. Organization: Molecular Simulations, Inc.
  9. References: <csx-17i002-tcl-editor@uunet.UU.NET>
  10. Date: Wed, 18 Mar 1992 14:14:48 GMT
  11. Approved: dcmartin@msi.com
  12.  
  13. Submitted-by: crowley@chaco.cs.unm.edu (Charlie Crowley)
  14. Posting-number: Volume 17, Issue 8
  15. Archive-name: tcl-editor/part07
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then unpack
  19. # it by saving it into a file and typing "sh file".  To overwrite existing
  20. # files, type "sh file -c".  You can also feed this as standard input via
  21. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  22. # will see the following message at the end:
  23. #        "End of archive 6 (of 15)."
  24. # Contents:  copymove.c insdel.c undoredo.c
  25. # Wrapped by crowley@chaco.cs.unm.edu on Tue Mar 10 15:05:41 1992
  26. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  27. if test -f 'copymove.c' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'copymove.c'\"
  29. else
  30. echo shar: Extracting \"'copymove.c'\" \(15083 characters\)
  31. sed "s/^X//" >'copymove.c' <<'END_OF_FILE'
  32. X/* $Header: /nfs/unmvax/faculty/crowley/x/pt/RCS/copymove.c,v 1.8 1992/03/04 17:07:18 crowley Exp crowley $ */
  33. X
  34. X#include <stdio.h>
  35. X#include "pt.h"
  36. X
  37. extern int addHandle;
  38. extern Offset addPosition;
  39. X
  40. X/* the scrap buffer */
  41. struct changeItem scrapBuffer;
  42. int scrapMode = SELCHAR;
  43. X
  44. void
  45. updateFile( fileId, offset, len, oneLineOnly )
  46. X    int fileId;
  47. X    Offset offset;
  48. X    Offset len;
  49. X    int oneLineOnly;
  50. X{
  51. X    extern char msgBuffer[];
  52. X    extern struct window *windowList;
  53. X    extern struct window *selWindow;
  54. X    extern int debug;
  55. X
  56. X    register struct window *w;
  57. X    Offset topOffset;
  58. X    int n, col, firstRow, lastRow;
  59. X    int fid;
  60. X
  61. X    /* redraw the affected windows */
  62. X    w = windowList;
  63. X    while( w != NULL ) {
  64. X        fid = w->fileId;
  65. X        if( fid == fileId ) {
  66. X            /* repaint the window as necessary */
  67. X            if( offset <= w->posBotline )
  68. X                w->posBotline += len;
  69. X            else
  70. X                goto nextWindow;
  71. X            topOffset = w->posTopline;
  72. X            if( offset < topOffset ) {
  73. X                /* remember: len < 0 for a delete */
  74. X                /* a delete overlapping this window? */
  75. X                if( offset > (topOffset+len) ) {
  76. X                    n = -1;
  77. X                    w->posTopline = prevLine( fid,
  78. X                            topOffset, &n );
  79. X                }
  80. X                if( !oneLineOnly ) {
  81. X                    /* recalculate the line number by */
  82. X                    /* letting prevLine count as far back */
  83. X                    /* as it can */
  84. X                    n = 3000000;
  85. X                    (void)prevLine(fid, w->posTopline, &n);
  86. X                    w->numTopline = n + 1;
  87. X                }
  88. X            }
  89. X            OffsetToXY( w, offset, &firstRow, &col );
  90. X            if( oneLineOnly ) {
  91. X                if( len > 1 )
  92. X                    /* len > 0 ==> an insert */
  93. X                    OffsetToXY( w, offset+len-1, &lastRow,
  94. X                                    &col );
  95. X                else
  96. X                    lastRow = firstRow;
  97. X            } else {
  98. X                lastRow = w->nRows - 1;
  99. X            }
  100. X            if( firstRow != -1 )
  101. X                drawWindowFast(w, firstRow, lastRow,
  102. X                                0, w->nCols-1);
  103. X        }
  104. X    nextWindow:
  105. X        w = w->nextWindow;
  106. X    }
  107. X}
  108. X
  109. void
  110. updateTops(fileId, offset, len, oneLineOnly )
  111. X    int fileId;
  112. X    Offset offset;
  113. X    Offset len;
  114. X    int oneLineOnly;
  115. X{
  116. X    extern char msgBuffer[];
  117. X    extern struct window *windowList;
  118. X    extern int debug;
  119. X
  120. X    register struct window *w;
  121. X    int n;
  122. X    Offset topOffset;
  123. X    int fid;
  124. X
  125. X    /* adjust the data of the affected windows */
  126. X    w = windowList;
  127. X    while( w != NULL ) {
  128. X        fid = w->fileId;
  129. X        if( fid == fileId ) {
  130. X            if( offset < w->posBotline )
  131. X                w->posBotline += len;
  132. X            else
  133. X                goto nextWindow;
  134. X            topOffset = w->posTopline;
  135. X            if( offset < topOffset ) {
  136. X                /* a delete overlapping this window? */
  137. X                if( offset > (topOffset+len) ) {
  138. X                    n = -1;
  139. X                    w->posTopline = prevLine( fid,
  140. X                            topOffset, &n);
  141. X                }
  142. X                if( !oneLineOnly ) {
  143. X                    /* recalculate the line number by */
  144. X                    /* letting prevLine count as far back */
  145. X                    /* as it can */
  146. X                    n = 3000000;
  147. X                    (void)prevLine(fid, w->posTopline, &n);
  148. X                    w->numTopline = n + 1;
  149. X                }
  150. X            }
  151. X        }
  152. X    nextWindow:
  153. X        w = w->nextWindow;
  154. X    }
  155. X}
  156. X
  157. void
  158. exchWithScrap()
  159. X{
  160. X    extern char msgBuffer[];
  161. X    extern struct changeItem scrapBuffer;
  162. X    extern Offset selBegin, selEnd;
  163. X    extern struct window *selWindow;
  164. X    extern struct openFile *files;
  165. X
  166. X    Offset length;
  167. X    struct changeItem *thisChange;
  168. X    Piece firstPiece;
  169. X    struct openFile * ff = &files[selWindow->fileId];
  170. X
  171. X    /* check if this is a readOnly file */
  172. X    if( ff->flags & READ_ONLY ) {
  173. X        sprintf(msgBuffer, "File %s is read only", ff->origName);
  174. X        msg(msgBuffer, (int)1);
  175. X        return;
  176. X    }
  177. X
  178. X    /* remember what was in the scrap */
  179. X    firstPiece = scrapBuffer.firstPiece;
  180. X    length = scrapBuffer.length;
  181. X    /* prevent this from getting freed when the scrap buffer is reused */
  182. X    scrapBuffer.firstPiece = NULL;
  183. X    
  184. X    /* move the selection into the scrap */
  185. X    (void)deleteChars( selWindow->fileId, NOUPDATE, 1 );
  186. X
  187. X    /* record in the change history */
  188. X    thisChange = GetNewChange( ff );
  189. X    thisChange->type = CINSERT;
  190. X    thisChange->w = selWindow;
  191. X    thisChange->flags = 0;
  192. X    thisChange->position = selBegin;
  193. X    thisChange->length = length;
  194. X    thisChange->lineNumber = selWindow->numTopline;
  195. X    thisChange->fileId = selWindow->fileId;
  196. X    thisChange->firstPiece = firstPiece;
  197. X    RecordChange( ff, thisChange );
  198. X
  199. X    /* copy the old scrap into the file */
  200. X    copyPieces( firstPiece, selWindow, selBegin, length, 1, 0 );
  201. X    
  202. X    /* free the scrap pieces */
  203. X    freePieces(firstPiece);
  204. X}
  205. X
  206. void
  207. copyToScrap(fromWindow, fromBegin, fromEnd)
  208. X    struct window *fromWindow;
  209. X    Offset fromBegin, fromEnd;
  210. X{
  211. X    extern char msgBuffer[];
  212. X    extern struct changeItem scrapBuffer;
  213. X    extern struct window *selWindow;
  214. X    extern int selMode;
  215. X    extern int scrapMode;
  216. X
  217. X    int fromId;
  218. X    Offset fb, copyLength;
  219. X    Piece tempPP;
  220. X
  221. X    fromId = fromWindow->fileId;
  222. X    
  223. X    /* eliminate the EOF marker from the selection */
  224. X    fb = fileSize(fromId);
  225. X    if( fromEnd >= fb ) {
  226. X        if( fromBegin < fb )
  227. X            fromEnd = fb-1;
  228. X        else    /* only the EOF symbol is selected */
  229. X            return;
  230. X    }
  231. X    copyLength = fromEnd - fromBegin + 1;
  232. X
  233. X    /* free the old scrap buffer pieces */
  234. X    freePieces(scrapBuffer.firstPiece);
  235. X
  236. X    /* record in the scrap buffer */
  237. X    scrapBuffer.type = 1;
  238. X    scrapBuffer.length = copyLength;
  239. X    scrapBuffer.w = selWindow;
  240. X    scrapBuffer.flags = 0;
  241. X    tempPP = getFreePiece();
  242. X    scrapBuffer.firstPiece = tempPP;
  243. X    scrapMode = selMode;
  244. X
  245. X    tempPP->file = addHandle;
  246. X    tempPP->position = addPosition;
  247. X    fb = fromBegin;
  248. X    while( fb <= fromEnd ) {
  249. X        writeChar( (char)getFileByte(fromId, fb++), addPosition++);
  250. X    }
  251. X    tempPP->length = copyLength;
  252. X}
  253. X
  254. void
  255. insScrap( doInsert, update )
  256. X    int doInsert;
  257. X    int update;
  258. X{
  259. X    extern char msgBuffer[];
  260. X    extern struct window *selWindow;
  261. X    extern Offset selBegin, selEnd;
  262. X    extern struct changeItem scrapBuffer;
  263. X    extern struct openFile *files;
  264. X     extern int selMode;
  265. X    extern int scrapMode;
  266. X    extern int maxFiles;
  267. X
  268. X    Offset limit, logByte;
  269. X    Piece tempPP, oldScrap;
  270. X    struct openFile *ff;
  271. X    struct changeItem *thisChange;
  272. X
  273. X    /* check if this is a readOnly file */
  274. X    if( files[selWindow->fileId].flags & READ_ONLY ) {
  275. X        sprintf(msgBuffer, "File %s is read only",
  276. X            files[selWindow->fileId].origName);
  277. X        msg(msgBuffer, (int)1);
  278. X        return;
  279. X    }
  280. X
  281. X    /* See if the text in the scrap buffer is in an edit file rather */
  282. X    /* then in the add file.  If it is we need to copy it to the add */
  283. X    /* file. */
  284. X    if( !scrapBuffer.type ) {
  285. X        /* keep a pointer to the old piece list */
  286. X        oldScrap = scrapBuffer.firstPiece;
  287. X        /* scrapBuffer.length will not change */
  288. X        
  289. X        /* get a new piece and initialize the fields */
  290. X        tempPP = getFreePiece();
  291. X        tempPP->file = addHandle;
  292. X        tempPP->position = addPosition;
  293. X        tempPP->length = scrapBuffer.length;
  294. X        
  295. X        /* this will be the new scrapBuffer piece list */
  296. X        scrapBuffer.type = 1;  /* now it is addFile only type */
  297. X        scrapBuffer.firstPiece = tempPP;
  298. X        
  299. X        /* Now copy the characters into the add file */
  300. X        logByte = 0;
  301. X        limit = scrapBuffer.length;
  302. X
  303. X        /* simulate a file this was deleted from */
  304. X        ff = &files[maxFiles];
  305. X        ff->hiLogBuffer = -1;
  306. X        ff->loLogBuffer = -1;
  307. X        ff->origHandle = scrapBuffer.fileId;
  308. X        ff->fileSize = limit;
  309. X        ff->logPiece = oldScrap;
  310. X        ff->loLogPiece = 0;
  311. X        ff->hiLogPiece = oldScrap->length - 1;
  312. X        while( logByte < limit ) {
  313. X            /* copy the characters in pp to the add file */
  314. X            writeChar( (char)getFileByte(maxFiles, logByte++),
  315. X                addPosition++);
  316. X        }
  317. X        
  318. X        freePieces(oldScrap);  /* free the old piece chain */
  319. X    }
  320. X    if( doInsert ) {
  321. X        /* record in the change history */
  322. X        ff = &files[selWindow->fileId];
  323. X        thisChange = GetNewChange( ff );
  324. X        thisChange->type = CCOPY;
  325. X        selMode = scrapMode;
  326. X        selBegin = adjustSelMode( selBegin );
  327. X        thisChange->position = selBegin;
  328. X        thisChange->length = scrapBuffer.length;
  329. X        thisChange->lineNumber = selWindow->numTopline;
  330. X        thisChange->fileId = selWindow->fileId;
  331. X        thisChange->w = selWindow;
  332. X        thisChange->flags = 0;
  333. X        thisChange->firstPiece = dupPieces(scrapBuffer.firstPiece);
  334. X        RecordChange( ff, thisChange );
  335. X
  336. X        copyPieces( scrapBuffer.firstPiece, selWindow, selBegin,
  337. X            scrapBuffer.length, update, 0 );
  338. X    }
  339. X}
  340. X
  341. void
  342. copyMove(fromWindow, fromBegin, fromEnd, toWindow, toPosition, mode)
  343. X    struct window *fromWindow, *toWindow;
  344. X    Offset fromBegin, fromEnd, toPosition;
  345. X    int mode;
  346. X{
  347. X    extern char msgBuffer[];
  348. X    extern struct openFile *files;
  349. X    extern Offset selBegin, selEnd;
  350. X    extern struct window *selWindow;
  351. X
  352. X    int n, fromId, toId;
  353. X    Offset  fb, copyLength;
  354. X    Piece tempPP;
  355. X    struct changeItem *thisChange;
  356. X    struct changeItem *currentChange;
  357. X    int wasCR;
  358. X    char ch;
  359. X    struct openFile * ff = &files[toWindow->fileId];
  360. X
  361. X    /* check if this is a readOnly file */
  362. X    if( ff->flags & READ_ONLY ) {
  363. X        sprintf(msgBuffer, "File %s is read only",ff->origName);
  364. X        msg(msgBuffer, (int)1);
  365. X        return;
  366. X    }
  367. X
  368. X    /* Is this a move with source and destination ovelapping? */
  369. X    if( mode==MOVE && fromBegin<=toPosition && toPosition<=fromEnd
  370. X                        && fromWindow==toWindow ) {
  371. X        msg("Cannot move text into itself", 2);
  372. X        return;
  373. X    }
  374. X
  375. X    fromId = fromWindow->fileId;
  376. X    toId = toWindow->fileId;
  377. X
  378. X    /* eliminate the EOF marker from the selection */
  379. X    fb = fileSize(fromId);
  380. X    if( fromEnd >= fb ) {
  381. X        if( fromBegin < fb )
  382. X            fromEnd = fb-1;
  383. X        else    /* only the EOF symbol is selected */
  384. X            return;
  385. X    }
  386. X    copyLength = fromEnd - fromBegin + 1;
  387. X
  388. X    /* record in the change history */
  389. X    thisChange = GetNewChange( ff );
  390. X    if( mode == COPY )
  391. X        thisChange->type = CCOPY;
  392. X    else
  393. X        thisChange->type = CMOVE;
  394. X    thisChange->position = toPosition;
  395. X    thisChange->length = copyLength;
  396. X    thisChange->lineNumber = selWindow->numTopline;
  397. X    thisChange->fileId = toId;
  398. X    thisChange->w = selWindow;
  399. X    thisChange->flags = 0;
  400. X    tempPP = getFreePiece();
  401. X    thisChange->firstPiece = tempPP;
  402. X    RecordChange( ff, thisChange );
  403. X
  404. X    tempPP->file = addHandle;
  405. X    tempPP->position = addPosition;
  406. X    fb = fromBegin;
  407. X    wasCR = 0;
  408. X    while( fb <= fromEnd ) {
  409. X        ch = (char)getFileByte(fromId, fb++);
  410. X        if( ch == '\n' )
  411. X            wasCR = 1;
  412. X        writeChar( ch, addPosition++);
  413. X    }
  414. X    tempPP->length = copyLength;
  415. X
  416. X    /* if it is a move, then delete the from text */
  417. X    if( mode == MOVE ) {
  418. X        selWindow = fromWindow;
  419. X        selBegin = fromBegin;
  420. X        selEnd = fromEnd;
  421. X#ifdef XXXXXXXX
  422. X        if( fromWindow == toWindow )
  423. X            n = NOUPDATE;
  424. X        else
  425. X#endif
  426. X            n = UPDATEWINDOWS;
  427. X        (void)deleteChars( fromWindow->fileId, n, 1 );
  428. X        /* we're going to change the selection in copyPieces */
  429. X        /* to the character after the moved text. */
  430. X        drawSelection( 1 );
  431. X        /* if we deleted text before the toPosition we have */
  432. X        /* to adjust it since the logical text positions change */
  433. X        /* after a delete.  We also fix up the position on the */
  434. X        /* delete following so it will look like it really did */
  435. X        /* take place AFTER the copying in of the moved text */
  436. X        if( fromWindow->fileId == toWindow->fileId ) {
  437. X            if( toPosition > fromBegin )
  438. X                toPosition -= copyLength;
  439. X            else {
  440. X                currentChange = GetCurrentChange( ff );
  441. X                currentChange->position += copyLength;
  442. X            }
  443. X        }
  444. X    }
  445. X
  446. X    copyPieces(thisChange->firstPiece, toWindow, toPosition, copyLength,
  447. X                        1, !wasCR );
  448. X}
  449. X
  450. void
  451. copyPieces(fromPP, toWindow, toPosition, copyLength, update, oneLineOnly)
  452. X    Piece fromPP;
  453. X    struct window *toWindow;
  454. X    Offset toPosition, copyLength;
  455. X    int update;
  456. X    int oneLineOnly;
  457. X{
  458. X    extern char msgBuffer[];
  459. X    extern struct openFile *files;
  460. X    extern Offset selBegin, selEnd;
  461. X    extern int selMode;
  462. X    extern struct window *selWindow;
  463. X    extern int trace_file;
  464. X
  465. X    int toId;
  466. X    Offset offset, toNN;
  467. X    Piece nextPP, toPP, lastPP;
  468. X    struct openFile *toFF;
  469. X    Piece pp2;
  470. X    struct window *w;
  471. X
  472. X    if( trace_file > 0 ) {
  473. X        sprintf( msgBuffer, "C %2d %5d %5d\n",
  474. X            toWindow->fileId, toPosition, copyLength);
  475. X        write( trace_file, msgBuffer, strlen(msgBuffer) );
  476. X    }
  477. X    if( update ) {
  478. X        /* just using these variables to save the selection */
  479. X        offset = selBegin;
  480. X        toNN = selEnd;
  481. X        w = selWindow;
  482. X        selBegin = selEnd = toPosition;
  483. X        selWindow = toWindow;
  484. X        selBegin = offset;
  485. X        selEnd = toNN;
  486. X        selWindow = w;
  487. X    }
  488. X    
  489. X    /* This is a special case to handle a backspace problem.  To wit, */
  490. X    /* if we delete text and type in new text, then select other text */
  491. X    /* and AGAIN, then the piece from the first change is copied in. */
  492. X    /* If we then backspace and type a new character, the piece itself */
  493. X    /* is changed and so the orignal edit is changed also.  We have to */
  494. X    /* prevent this so we bump addPosition in this case so the */
  495. X    /* backspace does not change the piece */
  496. X    /* A BETTER SOLUTION would be to make an actual copy of the text */
  497. X    /* in the piece.  This would allow further editing that would then */
  498. X    /* be able to be repeated again. */
  499. X    toPP = fromPP;        /* just using toPP as a convenient variable */
  500. X    while( toPP->nextPiece != NULL )
  501. X        toPP = toPP->nextPiece;
  502. X    if( (toPP->file == addHandle)
  503. X     && (toPP->position+toPP->length == addPosition) )
  504. X         ++addPosition;
  505. X        
  506. X    /* compute some values for later efficiency */
  507. X    toId = toWindow->fileId;
  508. X    toFF = &files[toId];
  509. X
  510. X    /* find out what piece 'toBegin' is in */
  511. X    toPP = findPiece(toPosition, toFF, &toNN);
  512. X    /* special case for the end of the file */
  513. X    if( toPosition > toFF->fileSize ) {
  514. X        /* leave toPP as the last piece in the file */
  515. X        nextPP = NULL;
  516. X    } else if( toPosition > toNN ) {
  517. X        /* copied text starts inside piece "toPP" */
  518. X        /* We split toPP into two pieces (toPP and nextPP) */
  519. X        /* at toPosition */
  520. X        /* get a new piece */
  521. X        nextPP = getFreePiece();
  522. X        /* link the new piece in before the piece after toPP */
  523. X        pp2 = toPP->nextPiece;
  524. X        nextPP->nextPiece = pp2;
  525. X        if( pp2 != NULL )
  526. X            pp2->prevPiece = nextPP;
  527. X        /* adjust the fields of the two pieces */
  528. X        offset = toPosition - toNN;
  529. X        nextPP->file = toPP->file;
  530. X        nextPP->position = toPP->position + offset;
  531. X        nextPP->length = toPP->length - offset;
  532. X        toPP->length = offset;
  533. X    } else {
  534. X        nextPP = toPP;
  535. X        toPP = toPP->prevPiece;
  536. X    }
  537. X    
  538. X    /* now copy the pieces into the piece list between toPP and nextPP */
  539. X    lastPP = toPP;
  540. X    while( fromPP != NULL ) {
  541. X        pp2 = getFreePiece();
  542. X        /* copy the information into the new piece */
  543. X        pp2->file = fromPP->file;
  544. X        pp2->position = fromPP->position;
  545. X        pp2->length = fromPP->length;
  546. X        /* link in the new piece */
  547. X        pp2->prevPiece = lastPP;
  548. X        /* link it into the list */
  549. X        if( lastPP != NULL )
  550. X            lastPP->nextPiece = pp2;
  551. X        else /* new first item on the list */
  552. X            toFF->pieceList = pp2;
  553. X        /* move to the next piece to copy */
  554. X        lastPP = pp2;
  555. X        fromPP = fromPP->nextPiece;
  556. X    }
  557. X    lastPP->nextPiece = nextPP;
  558. X    if( nextPP != NULL )
  559. X        nextPP->prevPiece = lastPP;
  560. X
  561. X    /* make the cached piece the one after the copied pieces */
  562. X    /* unless it is NULL */
  563. X    if( nextPP != NULL ) {
  564. X        toFF->logPiece = nextPP;
  565. X        toFF->loLogPiece = toPosition + copyLength;
  566. X        toFF->hiLogPiece = toFF->loLogPiece + nextPP->length - 1;
  567. X    } else {    /* make it the first piece in the file */
  568. X        toFF->logPiece = toFF->pieceList;
  569. X        toFF->loLogPiece = 0;
  570. X        toFF->hiLogPiece = toFF->loLogPiece
  571. X                    + (toFF->logPiece)->length - 1;
  572. X    }
  573. X
  574. X    /* update the length of the "to" file */
  575. X    toFF->fileSize += copyLength;
  576. X
  577. X    /* invalidate the buffer cache of the "to" file */
  578. X    toFF->hiLogBuffer = -1;
  579. X    toFF->loLogBuffer = -1;
  580. X
  581. X    /* record the fact that the file has changed */
  582. X    if( !(toFF->flags & IS_CHANGED) ) {
  583. X        toFF->flags |= IS_CHANGED;
  584. X        NewOpenList();
  585. X        banner( toWindow, 0 );
  586. X    }
  587. X
  588. X    /* invalidate the last-row-found cache */
  589. X    if( toWindow->posCurLast > toPosition )
  590. X        toWindow->lastPosTop = -1;
  591. X    
  592. X    /* make the selection the character past the copied text */
  593. X    if( selWindow != toWindow ) {
  594. X        drawSelection( 1 );
  595. X        selWindow = toWindow;
  596. X    }
  597. X    selEnd = selBegin = toPosition + copyLength;
  598. X
  599. X    /* change selection mode to character mode */
  600. X    selMode = SELCHAR;
  601. X    if( update )
  602. X        updateFile(toId, toPosition, copyLength, oneLineOnly);
  603. X}
  604. END_OF_FILE
  605. if test 15083 -ne `wc -c <'copymove.c'`; then
  606.     echo shar: \"'copymove.c'\" unpacked with wrong size!
  607. fi
  608. # end of 'copymove.c'
  609. fi
  610. if test -f 'insdel.c' -a "${1}" != "-c" ; then 
  611.   echo shar: Will not clobber existing file \"'insdel.c'\"
  612. else
  613. echo shar: Extracting \"'insdel.c'\" \(15918 characters\)
  614. sed "s/^X//" >'insdel.c' <<'END_OF_FILE'
  615. X/* $Header: /nfs/unmvax/faculty/crowley/x/pt/RCS/insdel.c,v 1.7 1992/03/04 17:07:18 crowley Exp crowley $ */
  616. X
  617. X#include "pt.h"
  618. X#include <stdio.h>
  619. X
  620. X/* the globals additions file */
  621. int addHandle;
  622. Offset addPosition;
  623. X
  624. void
  625. insertChar(c)
  626. X    int c;
  627. X{
  628. X    extern struct window *selWindow;
  629. X    extern Offset selBegin, selEnd;
  630. X    extern char msgBuffer[];
  631. X    extern struct openFile *files;
  632. X    extern Offset addPosition;
  633. X    extern int addHandle;
  634. X    extern int debug;
  635. X    extern int hypertextOn;
  636. X    extern int trace_file;
  637. X
  638. X    struct changeItem *thisChange;
  639. X    struct openFile *ff = &files[selWindow->fileId];
  640. X    Piece pp, pp2, thispp, nextpp, thirdpp;
  641. X    Offset nn, offset;
  642. X    unsigned char ch = (unsigned char)c;
  643. X    int oldSelBegin;
  644. X
  645. X#ifdef HYPERTEXT
  646. X    if( hypertextOn && selWindow->document != NULL ) {
  647. X        int ret;
  648. X
  649. X        /* convert selBegin to the underlying (real) file */
  650. X        oldSelBegin = selBegin;
  651. X        ret = GetRealSelection( ff, 1 /* get selBegin only */ );
  652. X
  653. X        /* check for insertion in decoration */
  654. X        if( ret & 1 ) {
  655. X            printf(
  656. X"insertChar ERROR: cannot insert into synthetic text\n");
  657. X            return;
  658. X        }
  659. X
  660. X        /* free the piece list of the old view */
  661. X        FreeOldViewPieces( ff );
  662. X
  663. X        /* fix up the fileId and ff */
  664. X        selWindow->fileId = selWindow->realFileId;
  665. X        ff = &files[selWindow->fileId];
  666. X    }
  667. X#endif
  668. X
  669. X    /* check if this is a readOnly file */
  670. X    if( ff->flags & READ_ONLY ) {
  671. X        sprintf(msgBuffer, "File %s is read only", ff->origName);
  672. X        msg(msgBuffer, 1);
  673. X        return;
  674. X    }
  675. X
  676. X    /* find out what piece 'selBegin' is in */
  677. X    pp = findPiece( selBegin, ff, &nn );
  678. X
  679. X    offset = selBegin - nn;
  680. X    if( offset > 0 ) {    /* we must split the piece */
  681. X        /* we insert two new pieces */
  682. X        /* nextpp is for the character we are inserting */
  683. X        /* thirdpp is the split of portion of pp */
  684. X        
  685. X        /* update the fields of the new piece */
  686. X        nextpp = getFreePiece();
  687. X        nextpp->file = addHandle;
  688. X        nextpp->position = addPosition;
  689. X        nextpp->length = 1;
  690. X
  691. X        /* update the fields of the split off piece */
  692. X        thirdpp = getFreePiece();
  693. X        thirdpp->file = pp->file;
  694. X        thirdpp->position = pp->position + offset;
  695. X        thirdpp->length = pp->length - offset;
  696. X
  697. X        /* update the fields of the original piece */
  698. X        /* pp->file remains the same */
  699. X        /* pp->position remains the same */
  700. X        pp->length = offset;
  701. X        
  702. X        /* link everything together again */
  703. X        nextpp->nextPiece = thirdpp;
  704. X        thirdpp->prevPiece = nextpp;
  705. X        pp2 = pp->nextPiece;
  706. X        thirdpp->nextPiece = pp2;
  707. X        if( pp2 != NULL )
  708. X            pp2->prevPiece = thirdpp;
  709. X        nextpp->prevPiece = pp;
  710. X        pp->nextPiece = nextpp;
  711. X
  712. X        /* make the third piece the cached one */
  713. X        ff->logPiece = thirdpp;
  714. X        ff->loLogPiece = selBegin + 1;
  715. X        ff->hiLogPiece = selBegin + thirdpp->length;
  716. X    } else {    /* put in front of this piece */
  717. X        /* can we put it at the end of the previous piece? */
  718. X        thispp = pp->prevPiece;
  719. X        /* if (1) there IS a previous piece and */
  720. X        /*    (2) it is a piece in the add file and */
  721. X        /*    (3) it is just before the piece we are adding */
  722. X        /* then we coalsce the two pieces */
  723. X        if( (thispp != NULL)    /* pp is not the first piece */
  724. X         && (thispp->file == addHandle)    /* in the add file */
  725. X         && (thispp->position+thispp->length == addPosition)
  726. X        ) {
  727. X            ++(thispp->length);    /* simply adjust the length */
  728. X            ff->logPiece = pp;
  729. X            ff->loLogPiece = nn + 1;
  730. X            ff->hiLogPiece = nn + pp->length;
  731. X        } else {
  732. X            /* create a new piece for this character */
  733. X            thispp = getFreePiece();
  734. X            thispp->file = addHandle;
  735. X            thispp->position = addPosition;
  736. X            thispp->length = 1;
  737. X            thispp->nextPiece = pp;
  738. X            pp2 = pp->prevPiece;
  739. X            pp->prevPiece = thispp;
  740. X            thispp->prevPiece = pp2;
  741. X            if( pp2 != NULL )
  742. X                pp2->nextPiece = thispp;
  743. X            else
  744. X                ff->pieceList = thispp;
  745. X            ff->logPiece = thispp;
  746. X            ff->loLogPiece = selBegin;
  747. X            ff->hiLogPiece = selBegin;
  748. X        }
  749. X    }
  750. X
  751. X    /* record in the change history */
  752. X    /* see if we can add this to the last insert */
  753. X    thisChange = GetCurrentChange( ff );
  754. X    if( thisChange->type == CINSERT
  755. X     && thisChange->fileId == selWindow->fileId
  756. X     && selBegin == thisChange->position+thisChange->length ) {
  757. X        ++(thisChange->length);
  758. X        ++(thisChange->firstPiece->length);
  759. X    } else {
  760. X        /* record in the change history */
  761. X        thisChange = GetNewChange( ff );
  762. X        thisChange->type = CINSERT;
  763. X        thisChange->position = selBegin;
  764. X        thisChange->length = 1;
  765. X        thisChange->flags = 0;
  766. X        thisChange->lineNumber = selWindow->numTopline;
  767. X        thisChange->fileId = selWindow->fileId;
  768. X        thisChange->w = selWindow;
  769. X        pp = getFreePiece();
  770. X        thisChange->firstPiece = pp;
  771. X        pp->file = addHandle;
  772. X        pp->position = addPosition;
  773. X        pp->length = 1;
  774. X        RecordChange( ff, thisChange );
  775. X    }
  776. X
  777. X    if( trace_file > 0 ) {
  778. X        sprintf( msgBuffer, "I %2d %5d %5d\n",
  779. X            selWindow->fileId, selBegin, 1 );
  780. X        write( trace_file, msgBuffer, strlen(msgBuffer) );
  781. X    }
  782. X
  783. X    /* add one character to the file */
  784. X    ff->fileSize += 1;
  785. X    writeChar(ch, addPosition++);
  786. X
  787. X    /* invalidate the buffer cache */
  788. X    ff->hiLogBuffer = -1;
  789. X    ff->loLogBuffer = -1;
  790. X
  791. X    /* record the fact that the file has changed */
  792. X    if( !(ff->flags & IS_CHANGED) ) {
  793. X        ff->flags |= IS_CHANGED;
  794. X        NewOpenList();
  795. X        banner( selWindow, 0 );
  796. X    }
  797. X
  798. X    /* adjust window data even though we do not redraw */
  799. X    updateTops( selWindow->fileId, selBegin, 1, (c!='\n') );
  800. X
  801. X    /* invalidate the last-row-found cache */
  802. X    if( selWindow->posCurLast > selBegin )
  803. X        selWindow->lastPosTop = -1;
  804. X    
  805. X    /* move the selection to char past new char */
  806. X    selEnd = ++selBegin;
  807. X
  808. X#ifdef HYPERTEXT
  809. X    if( hypertextOn && selWindow->document != NULL ) {
  810. X        /* create a new piece table for the view */
  811. X        selBegin = selEnd = ++oldSelBegin;
  812. X        selWindow->realFileId = selWindow->fileId;
  813. X        selWindow->fileId = CreateViewFile( selWindow );
  814. X        drawWindow( selWindow );
  815. X    }
  816. X#endif
  817. X    /* NOTE -- THE SELECTION WILL BE WRONG. FIX THIS LATER */
  818. X}
  819. X
  820. int
  821. delChar()
  822. X{
  823. X    extern struct window *selWindow;
  824. X    extern Offset selBegin, selEnd;
  825. X    extern char msgBuffer[];
  826. X    extern struct openFile *files;
  827. X    extern Offset addPosition;
  828. X    extern int addHandle;
  829. X    extern int debug;
  830. X
  831. X    Offset nn, offset;
  832. X    struct openFile *ff;
  833. X    Piece pp, thispp;
  834. X    struct changeItem *currentChange;
  835. X    char ch;
  836. X
  837. X    /* find out what piece 'selBegin' is in */
  838. X    ff = &files[selWindow->fileId];
  839. X    pp = findPiece(selBegin, ff, &nn);
  840. X
  841. X    /* check if this is a readOnly file */
  842. X    if( ff->flags & READ_ONLY ) {
  843. X        sprintf(msgBuffer, "File %s is read only", ff->origName);
  844. X        msg(msgBuffer, 1);
  845. X        return 0;
  846. X    }
  847. X
  848. X    offset = selBegin - nn;
  849. X    if( offset > 0 )
  850. X        return 0;
  851. X
  852. X    /* get the char deleted (for updateTops) */
  853. X    ch = getFileByte( selWindow->fileId, selBegin );
  854. X
  855. X    /* is the char to delete at the end of the previous piece? */
  856. X    thispp = pp->prevPiece;
  857. X    /* if (1) there IS a previous piece and */
  858. X    /*    (2) it is a piece in the add file and */
  859. X    /*    (3) it is just before the piece we are adding and */
  860. X    /*    (4) we are not deleting the last char in the piece */
  861. X    /*    (5) the preceding change was an insert */
  862. X    /* then we coalsce the two pieces */
  863. X    currentChange = GetCurrentChange( ff );
  864. X    if( (thispp != NULL)    /* pp is not the first piece */
  865. X     && (thispp->file == addHandle)    /* in the add file */
  866. X     && (thispp->position+thispp->length == addPosition)
  867. X     && (thispp->length >= 1)
  868. X     && (currentChange->type == CINSERT)
  869. X    ) {
  870. X        --(thispp->length);    /* simply adjust the length */
  871. X        ff->logPiece = pp;
  872. X        ff->loLogPiece = nn - 1;
  873. X        ff->hiLogPiece = nn + pp->length - 1;
  874. X    } else
  875. X        return 0;
  876. X
  877. X    /* record in the change history */
  878. X    /* see if we can add this to the last insert */
  879. X    if( currentChange->type == CINSERT
  880. X     && currentChange->fileId == selWindow->fileId
  881. X     && selBegin == currentChange->position+currentChange->length ) {
  882. X        --(currentChange->length);
  883. X        --(currentChange->firstPiece->length);
  884. X    } else {
  885. X        ++(thispp->length);    /* re-adjust the length */
  886. X        return 0;
  887. X    }
  888. X
  889. X    /* subtract one character to the file */
  890. X    ff->fileSize -= 1;
  891. X    --addPosition;
  892. X
  893. X    /* invalidate the buffer cache */
  894. X    ff->hiLogBuffer = -1;
  895. X    ff->loLogBuffer = -1;
  896. X
  897. X    /* record the fact that the file has changed */
  898. X    if( !(ff->flags & IS_CHANGED) ) {
  899. X        ff->flags |= IS_CHANGED;
  900. X        NewOpenList();
  901. X        banner( selWindow, 0 );
  902. X    }
  903. X
  904. X    /* adjust window data even though we do not redraw */
  905. X    updateTops( selWindow->fileId, selBegin, 1, (ch!='\n') );
  906. X
  907. X    /* invalidate the last-row-found cache */
  908. X    if( selWindow->posCurLast > selBegin )
  909. X        selWindow->lastPosTop = -1;
  910. X
  911. X    selEnd = --selBegin;
  912. X    return 1;
  913. X}
  914. X
  915. int
  916. deleteChars(fileId, update, toScrap)
  917. X    /* toScrap=0 --> do not put in the scrap */
  918. X    /* toScrap=1 --> do put in the scrap */
  919. X    /* toScrap=2 --> do not put in the scrap or the history */
  920. X    int fileId, toScrap;
  921. X    DoUpdate update;
  922. X{
  923. X    extern char msgBuffer[];
  924. X    extern int debug;
  925. X    extern Offset selBegin, selEnd;
  926. X    extern struct window *selWindow;
  927. X    extern struct changeItem scrapBuffer;
  928. X    extern int selMode;
  929. X    extern int scrapMode;
  930. X    extern Offset addPosition;
  931. X    extern struct openFile *files;
  932. X    extern int addHandle;
  933. X    extern int trace_file;
  934. X
  935. X    struct openFile *ff = &files[fileId];
  936. X    Offset sb, nn, curPos, nextPos, offset, delLength;
  937. X    int wasLF;
  938. X    Piece pp;
  939. X    Piece pp2, firstPP, nextPP, lastPP;
  940. X    struct changeItem *thisChange;
  941. X    int oldSelBegin;
  942. X
  943. X#ifdef HYPERTEXT
  944. X    if( hypertextOn && selWindow->document != NULL ) {
  945. X        int ret;
  946. X
  947. X        /* convert selBegin and selEnd to the underlying (real) file */
  948. X        oldSelBegin = selBegin;
  949. X        ret = GetRealSelection( ff, 0 /* get selBegin and selEnd */ );
  950. X
  951. X        /* check for insertion in decoration */
  952. X        if( ret & 1 ) {
  953. X            printf(
  954. X"deleteChars ERROR: cannot delete from synthetic text\n");
  955. X/* LATER: just adjust to the first real text */
  956. X            return 0;
  957. X        }
  958. X
  959. X        /* LATER: go through and only delete real text */
  960. X        /* NOT any block markers */
  961. X
  962. X        /* free the piece list of the old view */
  963. X        FreeOldViewPieces( ff );
  964. X
  965. X        /* fix up the fileId and ff */
  966. X        selWindow->fileId = selWindow->realFileId;
  967. X        ff = &files[selWindow->fileId];
  968. X    }
  969. X#endif
  970. X    nn = ff->fileSize;
  971. X
  972. X    /* check if this is a readOnly file */
  973. X    if( ff->flags & READ_ONLY ) {
  974. X        sprintf(msgBuffer, "File %s is read only", ff->origName);
  975. X        msg(msgBuffer, 1);
  976. X        return 0;
  977. X    }
  978. X
  979. X    /* eliminate the EOF marker from the selection */
  980. X    if( selEnd >= nn ) {
  981. X        if( selBegin < nn )
  982. X            selEnd = nn-1;
  983. X        else    /* only the EOF symbol is selected */
  984. X            return 0;
  985. X    }
  986. X
  987. X    delLength = selEnd - selBegin + 1;
  988. X
  989. X    /* see if we are deleting a newline */
  990. X    if( delLength < 100 ) {    /* lines are usally < 100 chars */
  991. X        wasLF = 0;
  992. X        sb = selBegin;
  993. X        while( sb <= selEnd )
  994. X            if( (char)getFileByte( fileId, sb++ ) == '\n' ) {
  995. X                wasLF = 1;
  996. X                break;
  997. X            }
  998. X    } else    /* assume there is one -- too many to search */
  999. X        wasLF = 1;
  1000. X
  1001. X    /* find out what piece 'selBegin' is in */
  1002. X    firstPP = findPiece( selBegin, ff, &curPos);
  1003. X
  1004. X/* first see if we have to split pp */
  1005. offset = selBegin - curPos;
  1006. if( offset > 0 ) {    /* delete starts inside this piece */
  1007. X    /* split firstPP at selBegin */
  1008. X    /* that is, get a new piece and adjust all the fields */
  1009. X    nextPP = getFreePiece();
  1010. X    nextPP->file = firstPP->file;
  1011. X    nextPP->position = firstPP->position + offset;
  1012. X    nextPP->length = firstPP->length - offset;
  1013. X    firstPP->length = offset;
  1014. X    nextPP->nextPiece = firstPP->nextPiece;
  1015. X    nextPP->prevPiece = firstPP;
  1016. X    if( (pp = firstPP->nextPiece) != NULL )
  1017. X        pp->prevPiece = nextPP;
  1018. X    firstPP->nextPiece = nextPP;
  1019. X    firstPP = nextPP;
  1020. X    curPos += offset;
  1021. X}
  1022. X
  1023. X/* Now the delete begins at the first byte of firstPP */
  1024. X/* See where the last piece is */
  1025. lastPP = firstPP;
  1026. while( 1 ) {
  1027. X    /* does the selection end in this piece? */
  1028. X    nextPos = curPos + lastPP->length;
  1029. X    if( nextPos > selEnd )
  1030. X        break;
  1031. X    curPos = nextPos;
  1032. X    lastPP = lastPP->nextPiece;
  1033. X}
  1034. X
  1035. X/* now we see if we have to split this piece */
  1036. if( selEnd < nextPos-1 ) {    /* delete ends inside this piece */
  1037. X    /* split lastPP at selEnd */
  1038. X    /* that is, get a new piece and adjust all the fields */
  1039. X    nextPP = getFreePiece();
  1040. X    nextPP->file = lastPP->file;
  1041. X    offset = selEnd - curPos + 1;
  1042. X    nextPP->position = lastPP->position + offset;
  1043. X    nextPP->length = lastPP->length - offset;
  1044. X    lastPP->length = offset;
  1045. X    pp = lastPP->nextPiece;
  1046. X    nextPP->nextPiece = pp;
  1047. X    nextPP->prevPiece = lastPP;
  1048. X    if( pp != NULL )
  1049. X        pp->prevPiece = nextPP;
  1050. X    lastPP->nextPiece = nextPP;
  1051. X}
  1052. X
  1053. X/* Now the selection has been isolated in pieces firstPP (which begins */
  1054. X/* with selBegin) and lastPP (which ends with selEnd) */
  1055. X/* Now just link them out of this piece table */
  1056. if( (pp = firstPP->prevPiece) != NULL ) {
  1057. X    nextPP = lastPP->nextPiece;
  1058. X    pp->nextPiece = nextPP;
  1059. X    ff->logPiece = pp;
  1060. X    ff->loLogPiece = selBegin - pp->length;
  1061. X    if( nextPP != NULL )
  1062. X        nextPP->prevPiece = firstPP->prevPiece;
  1063. X    /* see if we can combine the two pieces now together */
  1064. X    if( (nextPP != NULL) && (pp->file == nextPP->file)
  1065. X     && ((pp->position+pp->length) == nextPP->position) ) {
  1066. X        pp->length += nextPP->length;    /* add to first piece */
  1067. X        /* link the second piece out of the list */
  1068. X        pp2 = nextPP->nextPiece;
  1069. X        pp->nextPiece = pp2;
  1070. X        if( pp2 != NULL )
  1071. X            pp2->prevPiece = pp;
  1072. X        /* isolate the one piece and free is (as a chain) */
  1073. X        nextPP->nextPiece = nextPP->prevPiece = NULL;
  1074. X        freePieces(nextPP);
  1075. X    }
  1076. X} else {    /* this delete is at the beginning of the file and there */
  1077. X        /* are no pieces in front of firstPiece */
  1078. X    pp = lastPP->nextPiece;
  1079. X    ff->pieceList = pp;
  1080. X    if( pp != NULL ) {
  1081. X        pp->prevPiece = NULL;
  1082. X        ff->logPiece = pp;
  1083. X    } else {
  1084. X        /* the piece table is empty so put a 0 length piece in it */
  1085. X        /* it is convenient to be able to assume (in other parts */
  1086. X        /* of the editor) that a piece table always contains at */
  1087. X        /* least one piece */
  1088. X        pp = getFreePiece();
  1089. X        pp->file = addHandle;
  1090. X        pp->position = addPosition;
  1091. X        pp->length = 0;
  1092. X        ff->pieceList = pp;
  1093. X        ff->logPiece = pp;
  1094. X    }
  1095. X    ff->loLogPiece = 0;
  1096. X}
  1097. X
  1098. X    /* make this an independent chain */
  1099. X    firstPP->prevPiece = NULL;
  1100. X    lastPP->nextPiece = NULL;
  1101. X
  1102. X    /* put it into the history */
  1103. X    if( toScrap != 2 ) {
  1104. X        /* record in the change history */
  1105. X        thisChange = GetNewChange( ff );
  1106. X        thisChange->type = CDELETE;
  1107. X        thisChange->position = selBegin;
  1108. X        thisChange->length = delLength;
  1109. X        thisChange->flags = 0;
  1110. X        thisChange->lineNumber = selWindow->numTopline;
  1111. X        thisChange->fileId = fileId;
  1112. X        thisChange->w = selWindow;
  1113. X        thisChange->firstPiece = firstPP;
  1114. X        RecordChange( ff, thisChange );
  1115. X    }
  1116. X
  1117. X    if( trace_file > 0 ) {
  1118. X        sprintf( msgBuffer, "D %2d %5d %5d\n",
  1119. X            fileId, selBegin, delLength );
  1120. X        write( trace_file, msgBuffer, strlen(msgBuffer) );
  1121. X    }
  1122. X
  1123. X    if( toScrap == 1 ) {
  1124. X        freePieces(scrapBuffer.firstPiece);
  1125. X        scrapBuffer.length = delLength;
  1126. X        scrapBuffer.type = 0;
  1127. X        scrapBuffer.fileId = ff->origHandle;
  1128. X        scrapBuffer.firstPiece = dupPieces(firstPP);
  1129. X        scrapMode = selMode;
  1130. X    } else if( toScrap == 2 )
  1131. X        freePieces(firstPP);
  1132. X
  1133. X    /* update the cached piece */
  1134. X    ff->hiLogPiece = ff->loLogPiece + (ff->logPiece)->length - 1;
  1135. X    if( ff->hiLogPiece > ff->fileSize )
  1136. X        /* this could happen if we just deleted the last piece */
  1137. X        /* in the piece table */
  1138. X        ff->hiLogPiece = ff->fileSize;
  1139. X
  1140. X    /* invalidate the buffer cache */
  1141. X    ff->hiLogBuffer = -1;
  1142. X    ff->loLogBuffer = -1;
  1143. X
  1144. X    /* record the fact that the file has changed */
  1145. X    if( !(ff->flags & IS_CHANGED) ) {
  1146. X        ff->flags |= IS_CHANGED;
  1147. X        NewOpenList();
  1148. X        banner( selWindow, 0 );
  1149. X    }
  1150. X
  1151. X    /* invalidate the last-row-found cache */
  1152. X    if( selWindow->posCurLast > selBegin )
  1153. X        selWindow->lastPosTop = -1;
  1154. X        
  1155. X    /* update the file length */
  1156. X    ff->fileSize -= delLength;
  1157. X
  1158. X    /* the character after the deleted characters is the new selection */
  1159. X    selEnd = selBegin;
  1160. X
  1161. X    /* entend the selection according to the selection mode */
  1162. X    { int row, col, n = -1;
  1163. X    Offset beginRowCp;
  1164. X    OffsetToXY( selWindow, selBegin, &row, &col );
  1165. X    beginRowCp = prevLine( selWindow->fileId, selBegin, &n );
  1166. X    modeExtend( selWindow, selBegin, row, col, beginRowCp );
  1167. X    }
  1168. X
  1169. X#ifdef HYPERTEXT
  1170. X    if( hypertextOn && selWindow->document != NULL ) {
  1171. X        /* create a new piece table for the view */
  1172. X        selBegin = selEnd = oldSelBegin;
  1173. X        selWindow->realFileId = selWindow->fileId;
  1174. X        selWindow->fileId = CreateViewFile( selWindow );
  1175. X        drawWindow( selWindow );
  1176. X    }
  1177. X#endif
  1178. X
  1179. X    if( update == UPDATEWINDOWS ) {
  1180. X        /* redraw all the affected windows */
  1181. X        updateFile( fileId, selBegin, -delLength, !wasLF );
  1182. X    } else {
  1183. X        /* adjust window data even though we do not redraw */
  1184. X        updateTops( fileId, selBegin, -delLength, !wasLF );
  1185. X    }
  1186. X
  1187. X    return wasLF;
  1188. X}
  1189. END_OF_FILE
  1190. if test 15918 -ne `wc -c <'insdel.c'`; then
  1191.     echo shar: \"'insdel.c'\" unpacked with wrong size!
  1192. fi
  1193. # end of 'insdel.c'
  1194. fi
  1195. if test -f 'undoredo.c' -a "${1}" != "-c" ; then 
  1196.   echo shar: Will not clobber existing file \"'undoredo.c'\"
  1197. else
  1198. echo shar: Extracting \"'undoredo.c'\" \(15116 characters\)
  1199. sed "s/^X//" >'undoredo.c' <<'END_OF_FILE'
  1200. X/* $Header: /nfs/unmvax/faculty/crowley/x/pt/RCS/undoredo.c,v 1.7 1992/03/04 17:07:18 crowley Exp crowley $ */
  1201. X
  1202. X#include <string.h>
  1203. X#include <stdio.h>
  1204. X#include "pt.h"
  1205. X
  1206. X#define CHANGES_TO_SHOW        30
  1207. X
  1208. static struct openFile * mostRecentChange = NULL;
  1209. X
  1210. void
  1211. initChanges()
  1212. X{
  1213. X    extern struct changeItem scrapBuffer;
  1214. X    extern int addHandle;
  1215. X
  1216. X    scrapBuffer.firstPiece = getFreePiece();
  1217. X    scrapBuffer.firstPiece->file = addHandle;
  1218. X    scrapBuffer.firstPiece->position = 0L;
  1219. X    scrapBuffer.firstPiece->length = 0L;
  1220. X}
  1221. X
  1222. struct changeItem *
  1223. GetCurrentChange( ff )
  1224. X    struct openFile * ff;
  1225. X{
  1226. X    return ff->cmdHistory;
  1227. X}
  1228. X
  1229. static void
  1230. SetCurrentChange( ff, new_change )
  1231. X    struct openFile * ff;
  1232. X    struct changeItem * new_change;
  1233. X{
  1234. X    ff->cmdHistory = new_change;
  1235. X}
  1236. X
  1237. X/*ARGSUSED*/
  1238. struct changeItem *
  1239. GetNewChange( ff )
  1240. X    struct openFile * ff;
  1241. X{
  1242. X    struct changeItem * new_change;
  1243. X
  1244. X    new_change = (struct changeItem *)
  1245. X            PtMalloc( sizeof(struct changeItem), "change item" );
  1246. X    return new_change;
  1247. X}
  1248. X
  1249. void
  1250. RecordChange( ff, new_change )
  1251. X    struct openFile * ff;
  1252. X    struct changeItem * new_change;
  1253. X{
  1254. X    struct changeItem * last_change;
  1255. X    struct changeItem * next_change;
  1256. X    struct changeItem * change_to_free;
  1257. X    
  1258. X    /* link it into the chain */
  1259. X    last_change = GetCurrentChange( ff );
  1260. X    next_change = last_change->next;
  1261. X
  1262. X    /* free all undone edits */
  1263. X    while( next_change != NULL ) {
  1264. X        change_to_free = next_change;
  1265. X        next_change = next_change->next;
  1266. X        PtFree( (char *)change_to_free );
  1267. X    }
  1268. X
  1269. X    new_change->next = NULL;
  1270. X    new_change->prev = last_change;
  1271. X    last_change->next = new_change;
  1272. X    SetCurrentChange( ff, new_change );
  1273. X    mostRecentChange = ff;
  1274. X}
  1275. X
  1276. static char *
  1277. GetUndoText( thisChange )
  1278. X    struct changeItem * thisChange;
  1279. X{
  1280. X    extern char textBuffer[];
  1281. X    extern struct openFile *files;
  1282. X    extern int maxFiles;
  1283. X
  1284. X    struct openFile *ff;
  1285. X    int len = thisChange->length;
  1286. X    Offset limit, logByte;
  1287. X    int i, ch;
  1288. X
  1289. X    /* cannot do it if the file is closed */
  1290. X    if( thisChange->flags & FILE_WAS_CLOSED ) {
  1291. X        return "File is closed";
  1292. X    }
  1293. X    /* simulate a file this was deleted from */
  1294. X    ff = &files[maxFiles];
  1295. X    ff->hiLogBuffer = -1;
  1296. X    ff->loLogBuffer = -1;
  1297. X    ff->origHandle = thisChange->fileId;
  1298. X    ff->fileSize = len;
  1299. X    ff->logPiece = thisChange->firstPiece;
  1300. X    ff->loLogPiece = 0;
  1301. X    ff->hiLogPiece = thisChange->firstPiece->length - 1;
  1302. X    i = 0;
  1303. X    logByte = 0;
  1304. X    if( (limit = 15) > len )
  1305. X        limit = len;
  1306. X    while( i < limit ) {
  1307. X        ch = getFileByte(maxFiles, logByte++);
  1308. X        /* temporay fix because of Tcl parsing of {...} */
  1309. X        if( ch == '{' )
  1310. X            ch = '[';
  1311. X        else if( ch == '}' )
  1312. X            ch = ']';
  1313. X        textBuffer[i++] = ch;
  1314. X    }
  1315. X    if( len > 33 ) {
  1316. X        textBuffer[i++] = '.';
  1317. X        textBuffer[i++] = '.';
  1318. X        textBuffer[i++] = '.';
  1319. X        logByte = len - 15;
  1320. X    }
  1321. X    while( 1 ) {
  1322. X        ch = getFileByte(maxFiles, logByte++);
  1323. X        if( ch == BLOCK_EOF )
  1324. X            break;
  1325. X        /* temporay fix because of Tcl parsing of {...} */
  1326. X        if( ch == '{' )
  1327. X            ch = '[';
  1328. X        else if( ch == '}' )
  1329. X            ch = ']';
  1330. X        textBuffer[i++] = ch;
  1331. X    }
  1332. X    textBuffer[i] = '\0';
  1333. X    return textBuffer;
  1334. X}
  1335. X
  1336. static char *
  1337. flag_msg( flags )
  1338. X    int flags;
  1339. X{
  1340. X    static char buffer[10];
  1341. X
  1342. X    if( flags & FILE_WAS_CLOSED )
  1343. X        return "closed ";
  1344. X    if( flags & CHANGE_WAS_UNDONE )
  1345. X        strcpy( buffer, "no     " );
  1346. X    else
  1347. X        strcpy( buffer, "yes    " );
  1348. X    if( flags & BLOCK_UNDO_BEGIN )
  1349. X        buffer[5] = '>';
  1350. X    else if( flags & BLOCK_UNDO_END )
  1351. X        buffer[5] = '<';
  1352. X    return buffer;
  1353. X}
  1354. X
  1355. void
  1356. UpdateUndoList( ff )
  1357. X    struct openFile * ff;
  1358. X{
  1359. X    extern char msgBuffer[];
  1360. X    extern char textBuffer[];
  1361. X    extern struct window *selWindow;
  1362. X    extern Offset selBegin, selEnd;
  1363. X    extern struct window *windowList;
  1364. X    extern struct openFile *files;
  1365. X    extern int display_width;
  1366. X    extern int debug;
  1367. X
  1368. X    int i;
  1369. X    char *s, *str;
  1370. X    struct changeItem *thisChange;
  1371. X    struct changeItem *prevChange;
  1372. X
  1373. X    /* empty the current list */
  1374. X    (void)ExecTclCommand( "catch {.ub.list.list delete 0 end}" );
  1375. X
  1376. X    /* fill undo box */
  1377. X    sprintf( msgBuffer,
  1378. X        "catch {.ub.list.list insert end {%-7s%-8s%-16s%5s%7s%6s %-20s}}",
  1379. X        "Done", "Type", "File", "Line", "Pos", "Len", "Chars" );
  1380. X    (void)ExecTclCommand( msgBuffer );
  1381. X    /* get the current change */
  1382. X    thisChange = GetCurrentChange( ff );
  1383. X    /* show up to 10 already undone changes */
  1384. X    for( i = 0; i < 10; ++i ) {
  1385. X        if( thisChange->next == NULL )
  1386. X            break;
  1387. X        thisChange = thisChange->next;
  1388. X    }
  1389. X    i = 0;
  1390. X    while( thisChange != NULL && i < CHANGES_TO_SHOW ) {
  1391. X        s = textBuffer;
  1392. X        prevChange = thisChange->prev;
  1393. X        switch( thisChange->type ) {
  1394. X        case CNULL:    /* skip null changes */
  1395. X            /* WAS: continue; */
  1396. X            sprintf( s, "%s", "*** End of list ***" );
  1397. X            break;
  1398. X        case CINSERT:
  1399. X            sprintf( s, "%7s%-8s%-16s%5d%7d%6d \"%s\"",
  1400. X                flag_msg(thisChange->flags),
  1401. X                "Insert",
  1402. X                &((files[thisChange->fileId].origName)
  1403. X                    [thisChange->w->nameOffset]),
  1404. X                thisChange->lineNumber, thisChange->position,
  1405. X                thisChange->length,
  1406. X                GetUndoText(thisChange) );
  1407. X            break;
  1408. X        case CDELETE:
  1409. X            if( prevChange->type == CMOVE )
  1410. X                str = "MvFrom";
  1411. X            else
  1412. X                str = "Delete";
  1413. X            sprintf( s, "%7s%-8s%-16s%5d%7d%6d \"%s\"",
  1414. X                flag_msg(thisChange->flags),
  1415. X                str,
  1416. X                &((files[thisChange->fileId].origName)
  1417. X                    [thisChange->w->nameOffset]),
  1418. X                thisChange->lineNumber, thisChange->position,
  1419. X                thisChange->length,
  1420. X                GetUndoText(thisChange) );
  1421. X            break;
  1422. X        case CMOVE:
  1423. X            /* not used -- a combination of CCOPY and CDELETE */
  1424. X            sprintf( s, "%7s%-8s%-16s%5d%7d%6d \"%s\"",
  1425. X                flag_msg(thisChange->flags),
  1426. X                "MoveTo",
  1427. X                &((files[thisChange->fileId].origName)
  1428. X                    [thisChange->w->nameOffset]),
  1429. X                thisChange->lineNumber, thisChange->position,
  1430. X                thisChange->length,
  1431. X                GetUndoText(thisChange) );
  1432. X            break;
  1433. X        case CCOPY:
  1434. X            sprintf( s, "%7s%-8s%-16s%5d%7d%6d \"%s\"",
  1435. X                flag_msg(thisChange->flags),
  1436. X                "Copy",
  1437. X                &((files[thisChange->fileId].origName)
  1438. X                    [thisChange->w->nameOffset]),
  1439. X                thisChange->lineNumber, thisChange->position,
  1440. X                thisChange->length,
  1441. X                GetUndoText(thisChange) );
  1442. X            break;
  1443. X        case CREPLACE:
  1444. X            /* not used -- a combination of CDELETE and CINSERT */
  1445. X            sprintf( s, "%7s%-8s%-16s%5d%7d%6d \"%s\"",
  1446. X                flag_msg(thisChange->flags),
  1447. X                "Replace",
  1448. X                &((files[thisChange->fileId].origName)
  1449. X                    [thisChange->w->nameOffset]),
  1450. X                thisChange->lineNumber, thisChange->position,
  1451. X                thisChange->length,
  1452. X                GetUndoText(thisChange) );
  1453. X            break;
  1454. X        case CMOTION:
  1455. X            sprintf( s, "%7s%-8s%-16s%5d%7d%6d",
  1456. X                flag_msg(thisChange->flags),
  1457. X                "Motion",
  1458. X                &((files[thisChange->fileId].origName)
  1459. X                    [thisChange->w->nameOffset]),
  1460. X                thisChange->lineNumber, thisChange->position,
  1461. X                thisChange->length );
  1462. X            break;
  1463. X        }
  1464. X        sprintf(msgBuffer, "catch {.ub.list.list insert end {%s}}",s);
  1465. X        (void)ExecTclCommand( msgBuffer );
  1466. X        ++i;
  1467. X        thisChange = prevChange;
  1468. X    }
  1469. X}
  1470. X
  1471. void
  1472. ShowUndos( ff )
  1473. X    struct openFile * ff;
  1474. X{
  1475. X    extern struct window *activeWindow;
  1476. X    extern int display_width;
  1477. X
  1478. X    (void)ExecTclCommand( "MakeUndoBox" );
  1479. X
  1480. X    UpdateUndoList( ff );
  1481. X}
  1482. X
  1483. void
  1484. again( ff, mostRecent )
  1485. X    struct openFile * ff;
  1486. X    int mostRecent;
  1487. X{
  1488. X    extern char msgBuffer[];
  1489. X    extern struct window *selWindow;
  1490. X    extern Offset selBegin, selEnd;
  1491. X    extern struct openFile *files;
  1492. X
  1493. X    struct changeItem *newChange;
  1494. X    struct changeItem *thisChange, *prevChange;
  1495. X    int type;
  1496. X
  1497. X    /* check if this is a readOnly file */
  1498. X    if( files[selWindow->fileId].flags & READ_ONLY ) {
  1499. X        sprintf(msgBuffer, "File %s is read only",
  1500. X            files[selWindow->fileId].origName);
  1501. X        msg(msgBuffer, 1);
  1502. X        return;
  1503. X    }
  1504. X
  1505. X    /* most recent in this file or voer all files? */
  1506. X    if( mostRecent )
  1507. X        ff = mostRecentChange;
  1508. X
  1509. X    thisChange = GetCurrentChange( ff );
  1510. X    if( thisChange == NULL || thisChange->type == CNULL ) {
  1511. noChanges:
  1512. X        msg("No previous change to repeat", 1);
  1513. X        return;
  1514. X    }
  1515. X
  1516. X    /* find the change to repeat (not a delete ) */
  1517. X    while( 1 ) {
  1518. X        if( thisChange == NULL )
  1519. X            goto noChanges;
  1520. X        if( (thisChange->type)!=CDELETE && (thisChange->type)!=CNULL )
  1521. X            break;
  1522. X        thisChange = thisChange->prev;
  1523. X    }
  1524. X
  1525. X    switch( thisChange->type ) {
  1526. X
  1527. X    case CINSERT:
  1528. X        type = CINSERT;
  1529. X        goto doCopy;
  1530. X
  1531. X    case CCOPY:
  1532. X    case CMOVE:
  1533. X        type = CCOPY;
  1534. X    doCopy:
  1535. X        /* see if the previous change was a delete */
  1536. X        prevChange = thisChange->prev;
  1537. X        if( thisChange->position == prevChange->position 
  1538. X         && prevChange->type == CDELETE )
  1539. X            /* the delete must go into the history first */
  1540. X            (void)deleteChars(selWindow->fileId, NOUPDATE, 0);
  1541. X        /* record the change before copyPieces changes things */
  1542. X        newChange = GetNewChange( ff );
  1543. X        newChange->type = type;
  1544. X        newChange->position = selBegin;
  1545. X        newChange->length = thisChange->length;
  1546. X        newChange->lineNumber = selWindow->numTopline;
  1547. X        newChange->w = thisChange->w;
  1548. X        newChange->flags = 0;
  1549. X        newChange->fileId = selWindow->fileId;
  1550. X        newChange->firstPiece = dupPieces(thisChange->firstPiece);
  1551. X        copyPieces( thisChange->firstPiece, selWindow, selBegin,
  1552. X            thisChange->length, 1, 0 );
  1553. X        RecordChange( ff, newChange );
  1554. X        break;
  1555. X    
  1556. X    case CDELETE:
  1557. X        (void)deleteChars(selWindow->fileId, UPDATEWINDOWS, 0);
  1558. X        break;
  1559. X    }
  1560. X}
  1561. X
  1562. void
  1563. redo( ff, count )
  1564. X    struct openFile * ff;
  1565. X    int count;
  1566. X{
  1567. X    extern char msgBuffer[];
  1568. X    extern struct window *selWindow;
  1569. X    extern Offset selBegin, selEnd;
  1570. X    extern struct window *windowList;
  1571. X    extern int debug;
  1572. X
  1573. X    struct changeItem *prevChange;
  1574. X    struct changeItem *thisChange, *nextChange;
  1575. X    struct window *w1;
  1576. X    int blockRedo = 0;
  1577. X
  1578. while( count > 0 || blockRedo ) {
  1579. X    prevChange = GetCurrentChange( ff );
  1580. X    thisChange = prevChange->next;
  1581. X    if( thisChange == NULL ) {
  1582. X        msg("No undone change to redo", 1);
  1583. X        return;
  1584. X    }
  1585. X
  1586. X    if( (prevChange->flags & BLOCK_UNDO_BEGIN)
  1587. X     && (prevChange->type != CNULL) ) {
  1588. X        blockRedo = 1;
  1589. X    } else if( (prevChange->flags & BLOCK_UNDO_END) && blockRedo ) {
  1590. X        blockRedo = 0;
  1591. X        if( --count <= 0 )
  1592. X            break;
  1593. X    } else
  1594. X        --count;
  1595. X
  1596. X    /* move up the pointer to the last done change */
  1597. X    SetCurrentChange( ff, thisChange );
  1598. X
  1599. X    thisChange->flags &= ~CHANGE_WAS_UNDONE;
  1600. X    nextChange = thisChange->next;
  1601. X
  1602. X    /* find a window displaying the file the change was made in */
  1603. X    if( thisChange->fileId != selWindow->fileId ) {
  1604. X        w1 = windowList;
  1605. X        while( w1 != NULL && w1->fileId != thisChange->fileId )
  1606. X            w1 = w1->nextWindow;
  1607. X        if( w1 == NULL ) {
  1608. X            msg("Cannot redo. No windows have that file open.", 1);
  1609. X            return;
  1610. X        } else
  1611. X            selWindow = w1;
  1612. X    }
  1613. X
  1614. X    switch( thisChange->type ) {
  1615. X
  1616. X    case CMOTION:
  1617. X        doGoto( (struct window *)(thisChange->firstPiece),
  1618. X                thisChange->length, 0 );
  1619. X        break;
  1620. X
  1621. X    case CCOPY:
  1622. X    case CMOVE:
  1623. X        showChange();
  1624. X        copyPieces( thisChange->firstPiece, selWindow,
  1625. X            thisChange->position, thisChange->length, 1, 0 );
  1626. X        /* if this is not a move, stop, we are done */
  1627. X        if( thisChange->type != CMOVE )
  1628. X            break;
  1629. X        /* if it is a move then the delete follows */
  1630. X        /* else finish redoing the move by dropping through */
  1631. X        /* to the CDELETE case to delete the MOVEd text */
  1632. X        nextChange->flags &= ~CHANGE_WAS_UNDONE;
  1633. X        thisChange = nextChange;
  1634. X        SetCurrentChange( ff, thisChange );
  1635. X
  1636. X    case CDELETE:
  1637. X        selBegin = thisChange->position;
  1638. X        selEnd = selBegin + thisChange->length - 1;
  1639. X        selWindow = thisChange->w;
  1640. X        showChange();
  1641. X        (void)deleteChars( thisChange->fileId, UPDATEWINDOWS, 2 );
  1642. X        /* if the next change is an insert at the same position */
  1643. X        /* then redo it also */
  1644. X        if( nextChange == NULL || nextChange->type != CINSERT
  1645. X         || thisChange->position != nextChange->position )
  1646. X            break;
  1647. X        /* else drop through to redo the insert also */
  1648. X        thisChange = nextChange;
  1649. X        SetCurrentChange( ff, thisChange );
  1650. X        thisChange->flags &= ~CHANGE_WAS_UNDONE;
  1651. X
  1652. X    case CINSERT:
  1653. X        copyPieces( thisChange->firstPiece, thisChange->w,
  1654. X                thisChange->position, thisChange->length,
  1655. X                1, 0 );
  1656. X        break;
  1657. X    }
  1658. X}
  1659. X
  1660. X}
  1661. X
  1662. void
  1663. undo( ff, count )
  1664. X    struct openFile * ff;
  1665. X    int count;
  1666. X{
  1667. X    extern char msgBuffer[];
  1668. X    extern struct window *selWindow;
  1669. X    extern Offset selBegin, selEnd;
  1670. X    extern struct window *windowList;
  1671. X    extern int debug;
  1672. X
  1673. X    DoUpdate delAlso;
  1674. X    struct changeItem *thisChange, *prevChange;
  1675. X    struct window *w1;
  1676. X    int blockUndo = 0;
  1677. X
  1678. while( count > 0 || blockUndo ) {
  1679. X    thisChange = GetCurrentChange( ff );
  1680. X    if( thisChange == NULL || thisChange->type == CNULL ) {
  1681. noChanges:
  1682. X        msg("No previous change to undo", 1);
  1683. X        return;
  1684. X    }
  1685. X
  1686. X    /* find the change to undo */
  1687. X    while( 1 ) {
  1688. X        if( thisChange == NULL )
  1689. X            goto noChanges;
  1690. X        if( (thisChange->type) != CNULL
  1691. X         && ( (thisChange->flags)
  1692. X                 & (CHANGE_WAS_UNDONE|FILE_WAS_CLOSED) ) == 0 )
  1693. X            break;
  1694. X        thisChange = thisChange->prev;
  1695. X    }
  1696. X
  1697. X    /* Note that begin and end seem to be reversed here because */
  1698. X    /* the begin comes with the first edit which is earliter than */
  1699. X    /* the last edit.  Since we are going backwards in time here */
  1700. X    /* we encounter the last edit (the BLOCK_UNDO_END) first and */
  1701. X    /* want to undo all the way to the first edit in the block */
  1702. X    /* (the BLOCK_UNDO_BEGIN) */
  1703. X    if( thisChange->flags & BLOCK_UNDO_END ) {
  1704. X        blockUndo = 1;
  1705. X    } else if( (thisChange->flags & BLOCK_UNDO_BEGIN) && blockUndo ) {
  1706. X        blockUndo = 0;
  1707. X        if( --count <= 0 )
  1708. X            break;
  1709. X    } else
  1710. X        --count;
  1711. X
  1712. X    thisChange->flags |= CHANGE_WAS_UNDONE;
  1713. X    prevChange = thisChange->prev;
  1714. X
  1715. X    /* back up the pointer to the last done change */
  1716. X    SetCurrentChange( ff, prevChange );
  1717. X
  1718. X    /* find a window displaying the file the change was made in */
  1719. X    if( thisChange->fileId != selWindow->fileId ) {
  1720. X        w1 = windowList;
  1721. X        while( w1 != NULL && w1->fileId != thisChange->fileId )
  1722. X            w1 = w1->nextWindow;
  1723. X        if( w1 == NULL ) {
  1724. X            msg("Cannot undo. No windows have that file open.",1);
  1725. X            return;
  1726. X        } else
  1727. X            selWindow = w1;
  1728. X    }
  1729. X    
  1730. X    
  1731. X    switch( thisChange->type ) {
  1732. X
  1733. X    case CMOTION:
  1734. X        doGoto( (struct window *)(thisChange->firstPiece),
  1735. X                thisChange->lineNumber, 0 );
  1736. X        break;
  1737. X
  1738. X    case CDELETE:
  1739. X        showChange();
  1740. X        copyPieces( thisChange->firstPiece, selWindow,
  1741. X            thisChange->position, thisChange->length, 1, 0 );
  1742. X        /* see if this is really the DELETE of a CMOVE */
  1743. X        if( prevChange->type != CMOVE )
  1744. X            break;
  1745. X        /* else finish undoing the move by dropping through */
  1746. X        /* to the CCOPY case to delete the MOVEd text */
  1747. X        prevChange->flags |= CHANGE_WAS_UNDONE;
  1748. X        thisChange = prevChange;
  1749. X        SetCurrentChange( ff, thisChange->prev );
  1750. X
  1751. X    case CCOPY:
  1752. X        selBegin = thisChange->position;
  1753. X        selEnd = selBegin + thisChange->length - 1;
  1754. X        showChange();
  1755. X        (void)deleteChars( thisChange->fileId, UPDATEWINDOWS, 2 );
  1756. X        break;
  1757. X
  1758. X    case CINSERT:
  1759. X        /* delete the characters inserted */
  1760. X        selBegin = thisChange->position;
  1761. X        selEnd = selBegin + thisChange->length - 1;
  1762. X        /* test this first so we can avoid updating the */
  1763. X        /* screen twice once for the delete and again for */
  1764. X        /* the copy to follow */
  1765. X        if( thisChange->position == prevChange->position 
  1766. X         && prevChange->type == CDELETE )
  1767. X            delAlso = NOUPDATE;
  1768. X        else
  1769. X            delAlso = UPDATEWINDOWS;
  1770. X        showChange();
  1771. X        (void)deleteChars( thisChange->fileId, delAlso, 2 );
  1772. X        /* see if there is a previous, related delete to undo */
  1773. X        if( delAlso == NOUPDATE ) {
  1774. X            prevChange->flags |= CHANGE_WAS_UNDONE;
  1775. X            SetCurrentChange( ff, prevChange->prev );
  1776. X            copyPieces( prevChange->firstPiece, selWindow,
  1777. X                selBegin, prevChange->length, 1, 0 );
  1778. X        }
  1779. X        break;
  1780. X    }
  1781. X}
  1782. X}
  1783. X
  1784. X
  1785. X/* make sure the change is visible */
  1786. void
  1787. showChange()
  1788. X{
  1789. X    extern Offset selBegin, selEnd;
  1790. X    extern struct window *selWindow;
  1791. X    extern struct window *windowList;
  1792. X    
  1793. X    /* if the selection window is not on top */
  1794. X    /* or if the selection is not in the window */
  1795. X    /* then move the window to show the selection */
  1796. X    if( windowList != selWindow  || selBegin < selWindow->posTopline
  1797. X                    || selEnd > selWindow->posBotline )
  1798. X         doGoSel(selWindow);
  1799. X}
  1800. END_OF_FILE
  1801. if test 15116 -ne `wc -c <'undoredo.c'`; then
  1802.     echo shar: \"'undoredo.c'\" unpacked with wrong size!
  1803. fi
  1804. # end of 'undoredo.c'
  1805. fi
  1806. echo shar: End of archive 6 \(of 15\).
  1807. cp /dev/null ark6isdone
  1808. MISSING=""
  1809. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ; do
  1810.     if test ! -f ark${I}isdone ; then
  1811.     MISSING="${MISSING} ${I}"
  1812.     fi
  1813. done
  1814. if test "${MISSING}" = "" ; then
  1815.     echo You have unpacked all 15 archives.
  1816.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1817. else
  1818.     echo You still need to unpack the following archives:
  1819.     echo "        " ${MISSING}
  1820. fi
  1821. ##  End of shell archive.
  1822. exit 0
  1823. -- 
  1824. --
  1825. Molecular Simulations, Inc.            mail: dcmartin@msi.com
  1826. 796 N. Pastoria Avenue                uucp: uunet!dcmartin
  1827. Sunnyvale, California 94086            at&t: 408/522-9236
  1828.