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