|
|
1.1 ! root 1: /* modify.c */ ! 2: ! 3: /* This file contains the low-level file modification functions: ! 4: * delete(frommark, tomark) - removes line or portions of lines ! 5: * add(frommark, text) - inserts new text ! 6: * change(frommark, tomark, text) - delete, then add ! 7: */ ! 8: ! 9: #include "config.h" ! 10: #include "vi.h" ! 11: ! 12: #ifdef DEBUG ! 13: # include <stdio.h> ! 14: static FILE *dbg; ! 15: ! 16: /*VARARGS1*/ ! 17: debout(msg, arg1, arg2, arg3, arg4, arg5) ! 18: char *msg, *arg1, *arg2, *arg3, *arg4, *arg5; ! 19: { ! 20: if (!dbg) ! 21: { ! 22: dbg = fopen("debug.out", "w"); ! 23: setbuf(dbg, (FILE *)0); ! 24: } ! 25: fprintf(dbg, msg, arg1, arg2, arg3, arg4, arg5); ! 26: } ! 27: #endif /* DEBUG */ ! 28: ! 29: /* delete a range of text from the file */ ! 30: void delete(frommark, tomark) ! 31: MARK frommark; /* first char to be deleted */ ! 32: MARK tomark; /* AFTER last char to be deleted */ ! 33: { ! 34: int i; /* used to move thru logical blocks */ ! 35: REG char *scan; /* used to scan thru text of the blk */ ! 36: REG char *cpy; /* used when copying chars */ ! 37: BLK *blk; /* a text block */ ! 38: long l; /* a line number */ ! 39: MARK m; /* a traveling version of frommark */ ! 40: ! 41: #ifdef DEBUG ! 42: debout("delete(%ld.%d, %ld.%d)\n", markline(frommark), markidx(frommark), markline(tomark), markidx(tomark)); ! 43: #endif ! 44: ! 45: /* if not deleting anything, quit now */ ! 46: if (frommark == tomark) ! 47: { ! 48: return; ! 49: } ! 50: ! 51: /* This is a change */ ! 52: changes++; ! 53: significant = TRUE; ! 54: ! 55: /* if this is a multi-line change, then we'll have to redraw */ ! 56: if (markline(frommark) != markline(tomark)) ! 57: { ! 58: mustredraw = TRUE; ! 59: redrawrange(markline(frommark), markline(tomark), markline(frommark)); ! 60: } ! 61: ! 62: /* adjust marks 'a through 'z and '' as needed */ ! 63: l = markline(tomark); ! 64: for (i = 0; i < NMARKS; i++) ! 65: { ! 66: if (mark[i] < frommark) ! 67: { ! 68: continue; ! 69: } ! 70: else if (mark[i] < tomark) ! 71: { ! 72: mark[i] = MARK_UNSET; ! 73: } ! 74: else if (markline(mark[i]) == l) ! 75: { ! 76: if (markline(frommark) == l) ! 77: { ! 78: mark[i] -= markidx(tomark) - markidx(frommark); ! 79: } ! 80: else ! 81: { ! 82: mark[i] -= markidx(tomark); ! 83: } ! 84: } ! 85: else ! 86: { ! 87: mark[i] -= MARK_AT_LINE(l - markline(frommark)); ! 88: } ! 89: } ! 90: ! 91: /* Reporting... */ ! 92: if (markidx(frommark) == 0 && markidx(tomark) == 0) ! 93: { ! 94: rptlines = markline(tomark) - markline(frommark); ! 95: rptlabel = "deleted"; ! 96: } ! 97: ! 98: /* find the block containing frommark */ ! 99: l = markline(frommark); ! 100: for (i = 1; lnum[i] < l; i++) ! 101: { ! 102: } ! 103: ! 104: /* process each affected block... */ ! 105: for (m = frommark; ! 106: m < tomark && lnum[i] < INFINITY; ! 107: m = MARK_AT_LINE(lnum[i - 1] + 1)) ! 108: { ! 109: /* fetch the block */ ! 110: blk = blkget(i); ! 111: ! 112: /* find the mark in the block */ ! 113: scan = blk->c; ! 114: for (l = markline(m) - lnum[i - 1] - 1; l > 0; l--) ! 115: { ! 116: while (*scan++ != '\n') ! 117: { ! 118: } ! 119: } ! 120: scan += markidx(m); ! 121: ! 122: /* figure out where the changes to this block end */ ! 123: if (markline(tomark) > lnum[i]) ! 124: { ! 125: cpy = blk->c + BLKSIZE; ! 126: } ! 127: else if (markline(tomark) == markline(m)) ! 128: { ! 129: cpy = scan - markidx(m) + markidx(tomark); ! 130: } ! 131: else ! 132: { ! 133: cpy = scan; ! 134: for (l = markline(tomark) - markline(m); ! 135: l > 0; ! 136: l--) ! 137: { ! 138: while (*cpy++ != '\n') ! 139: { ! 140: } ! 141: } ! 142: cpy += markidx(tomark); ! 143: } ! 144: ! 145: /* delete the stuff by moving chars within this block */ ! 146: while (cpy < blk->c + BLKSIZE) ! 147: { ! 148: *scan++ = *cpy++; ! 149: } ! 150: while (scan < blk->c + BLKSIZE) ! 151: { ! 152: *scan++ = '\0'; ! 153: } ! 154: ! 155: /* adjust tomark to allow for lines deleted from this block */ ! 156: tomark -= MARK_AT_LINE(lnum[i] + 1 - markline(m)); ! 157: ! 158: /* if this block isn't empty now, then advance i */ ! 159: if (*blk->c) ! 160: { ! 161: i++; ! 162: } ! 163: ! 164: /* the buffer has changed. Update hdr and lnum. */ ! 165: blkdirty(blk); ! 166: } ! 167: ! 168: /* must have at least 1 line */ ! 169: if (nlines == 0) ! 170: { ! 171: blk = blkadd(1); ! 172: blk->c[0] = '\n'; ! 173: blkdirty(blk); ! 174: cursor = MARK_FIRST; ! 175: } ! 176: } ! 177: ! 178: ! 179: /* add some text at a specific place in the file */ ! 180: void add(atmark, newtext) ! 181: MARK atmark; /* where to insert the new text */ ! 182: char *newtext; /* NUL-terminated string to insert */ ! 183: { ! 184: REG char *scan; /* used to move through string */ ! 185: REG char *build; /* used while copying chars */ ! 186: int addlines; /* number of lines we're adding */ ! 187: int lastpart; /* size of last partial line */ ! 188: BLK *blk; /* the block to be modified */ ! 189: int blkno; /* the logical block# of (*blk) */ ! 190: REG char *newptr; /* where new text starts in blk */ ! 191: BLK buf; /* holds chars from orig blk */ ! 192: BLK linebuf; /* holds part of line that didn't fit */ ! 193: BLK *following; /* the BLK following the last BLK */ ! 194: int i; ! 195: long l; ! 196: ! 197: #ifdef DEBUG ! 198: debout("add(%ld.%d, \"%s\")\n", markline(atmark), markidx(atmark), newtext); ! 199: #endif ! 200: #ifdef lint ! 201: buf.c[0] = 0; ! 202: #endif ! 203: /* if not adding anything, return now */ ! 204: if (!*newtext) ! 205: { ! 206: return; ! 207: } ! 208: ! 209: /* This is a change */ ! 210: changes++; ! 211: significant = TRUE; ! 212: ! 213: /* count the number of lines in the new text */ ! 214: for (scan = newtext, lastpart = addlines = 0; *scan; ) ! 215: { ! 216: if (*scan++ == '\n') ! 217: { ! 218: addlines++; ! 219: lastpart = 0; ! 220: } ! 221: else ! 222: { ! 223: lastpart++; ! 224: } ! 225: } ! 226: ! 227: /* Reporting... */ ! 228: if (lastpart == 0 && markidx(atmark) == 0) ! 229: { ! 230: rptlines = addlines; ! 231: rptlabel = "added"; ! 232: } ! 233: ! 234: /* extract the line# from atmark */ ! 235: l = markline(atmark); ! 236: ! 237: /* if more than 0 lines, then we'll have to redraw the screen */ ! 238: if (addlines > 0) ! 239: { ! 240: mustredraw = TRUE; ! 241: if (markidx(atmark) == 0 && lastpart == 0) ! 242: { ! 243: redrawrange(l, l, l + addlines); ! 244: } ! 245: else ! 246: { ! 247: /* make sure the last line gets redrawn -- it was ! 248: * split, so its appearance has changed ! 249: */ ! 250: redrawrange(l, l + 1L, l + addlines + 1L); ! 251: } ! 252: } ! 253: ! 254: /* adjust marks 'a through 'z and '' as needed */ ! 255: for (i = 0; i < NMARKS; i++) ! 256: { ! 257: if (mark[i] < atmark) ! 258: { ! 259: /* earlier line, or earlier in same line: no change */ ! 260: continue; ! 261: } ! 262: else if (markline(mark[i]) > l) ! 263: { ! 264: /* later line: move down a whole number of lines */ ! 265: mark[i] += MARK_AT_LINE(addlines); ! 266: } ! 267: else ! 268: { ! 269: /* later in same line */ ! 270: if (addlines > 0) ! 271: { ! 272: /* multi-line add, which split this line: ! 273: * move down, and possibly left or right, ! 274: * depending on where the split was and how ! 275: * much text was inserted after the last \n ! 276: */ ! 277: mark[i] += MARK_AT_LINE(addlines) + lastpart - markidx(atmark); ! 278: } ! 279: else ! 280: { ! 281: /* totally within this line: move right */ ! 282: mark[i] += lastpart; ! 283: } ! 284: } ! 285: } ! 286: ! 287: /* get the block to be modified */ ! 288: for (blkno = 1; lnum[blkno] < l && lnum[blkno + 1] < INFINITY; blkno++) ! 289: { ! 290: } ! 291: blk = blkget(blkno); ! 292: buf = *blk; ! 293: ! 294: /* figure out where the new text starts */ ! 295: for (newptr = buf.c, l = markline(atmark) - lnum[blkno - 1] - 1; ! 296: l > 0; ! 297: l--) ! 298: { ! 299: while (*newptr++ != '\n') ! 300: { ! 301: } ! 302: } ! 303: newptr += markidx(atmark); ! 304: ! 305: /* keep start of old block */ ! 306: build = blk->c + (newptr - buf.c); ! 307: ! 308: /* fill this block (or blocks) from the newtext string */ ! 309: while (*newtext) ! 310: { ! 311: while (*newtext && build < blk->c + BLKSIZE - 1) ! 312: { ! 313: *build++ = *newtext++; ! 314: } ! 315: if (*newtext) ! 316: { ! 317: /* save the excess */ ! 318: for (scan = linebuf.c + BLKSIZE; ! 319: build > blk->c && build[-1] != '\n'; ! 320: ) ! 321: { ! 322: *--scan = *--build; ! 323: } ! 324: ! 325: /* write the block */ ! 326: while (build < blk->c + BLKSIZE) ! 327: { ! 328: *build++ = '\0'; ! 329: } ! 330: blkdirty(blk); ! 331: ! 332: /* add another block */ ! 333: blkno++; ! 334: blk = blkadd(blkno); ! 335: ! 336: /* copy in the excess from last time */ ! 337: for (build = blk->c; scan < linebuf.c + BLKSIZE; ) ! 338: { ! 339: *build++ = *scan++; ! 340: } ! 341: } ! 342: } ! 343: ! 344: /* fill this block(s) from remainder of orig block */ ! 345: while (newptr < buf.c + BLKSIZE && *newptr) ! 346: { ! 347: while (newptr < buf.c + BLKSIZE ! 348: && *newptr ! 349: && build < blk->c + BLKSIZE - 1) ! 350: { ! 351: *build++ = *newptr++; ! 352: } ! 353: if (newptr < buf.c + BLKSIZE && *newptr) ! 354: { ! 355: /* save the excess */ ! 356: for (scan = linebuf.c + BLKSIZE; ! 357: build > blk->c && build[-1] != '\n'; ! 358: ) ! 359: { ! 360: *--scan = *--build; ! 361: } ! 362: ! 363: /* write the block */ ! 364: while (build < blk->c + BLKSIZE) ! 365: { ! 366: *build++ = '\0'; ! 367: } ! 368: blkdirty(blk); ! 369: ! 370: /* add another block */ ! 371: blkno++; ! 372: blk = blkadd(blkno); ! 373: ! 374: /* copy in the excess from last time */ ! 375: for (build = blk->c; scan < linebuf.c + BLKSIZE; ) ! 376: { ! 377: *build++ = *scan++; ! 378: } ! 379: } ! 380: } ! 381: ! 382: /* see if we can combine our last block with the following block */ ! 383: if (lnum[blkno] < nlines && lnum[blkno + 1] - lnum[blkno] < (BLKSIZE >> 6)) ! 384: { ! 385: /* hey, we probably can! Get the following block & see... */ ! 386: following = blkget(blkno + 1); ! 387: if (strlen(following->c) + (build - blk->c) < BLKSIZE - 1) ! 388: { ! 389: /* we can! Copy text from following to blk */ ! 390: for (scan = following->c; *scan; ) ! 391: { ! 392: *build++ = *scan++; ! 393: } ! 394: while (build < blk->c + BLKSIZE) ! 395: { ! 396: *build++ = '\0'; ! 397: } ! 398: blkdirty(blk); ! 399: ! 400: /* pretend the following was the last blk */ ! 401: blk = following; ! 402: build = blk->c; ! 403: } ! 404: } ! 405: ! 406: /* that last block is dirty by now */ ! 407: while (build < blk->c + BLKSIZE) ! 408: { ! 409: *build++ = '\0'; ! 410: } ! 411: blkdirty(blk); ! 412: } ! 413: ! 414: ! 415: /* change the text of a file */ ! 416: void change(frommark, tomark, newtext) ! 417: MARK frommark, tomark; ! 418: char *newtext; ! 419: { ! 420: int i; ! 421: long l; ! 422: char *text; ! 423: BLK *blk; ! 424: ! 425: #ifdef DEBUG ! 426: debout("change(%ld.%d, %ld.%d, \"%s\")\n", markline(frommark), markidx(frommark), markline(tomark), markidx(tomark), newtext); ! 427: #endif ! 428: ! 429: /* optimize for single-character replacement */ ! 430: if (frommark + 1 == tomark && newtext[0] && !newtext[1] && newtext[0] != '\n') ! 431: { ! 432: /* find the block containing frommark */ ! 433: l = markline(frommark); ! 434: for (i = 1; lnum[i] < l; i++) ! 435: { ! 436: } ! 437: ! 438: /* get the block */ ! 439: blk = blkget(i); ! 440: ! 441: /* find the line within the block */ ! 442: for (text = blk->c, i = l - lnum[i - 1] - 1; i > 0; text++) ! 443: { ! 444: if (*text == '\n') ! 445: { ! 446: i--; ! 447: } ! 448: } ! 449: ! 450: /* replace the char */ ! 451: text += markidx(frommark); ! 452: if (*text == newtext[0]) ! 453: { ! 454: /* no change was needed - same char */ ! 455: return; ! 456: } ! 457: else if (*text != '\n') ! 458: { ! 459: /* This is a change */ ! 460: changes++; ! 461: significant = TRUE; ! 462: ChangeText ! 463: { ! 464: *text = newtext[0]; ! 465: blkdirty(blk); ! 466: } ! 467: return; ! 468: } ! 469: /* else it is a complex change involving newline... */ ! 470: } ! 471: ! 472: /* couldn't optimize, so do delete & add */ ! 473: ChangeText ! 474: { ! 475: delete(frommark, tomark); ! 476: add(frommark, newtext); ! 477: rptlabel = "changed"; ! 478: } ! 479: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.