|
|
1.1 ! root 1: /* ! 2: * The functions in this file are a general set of line management utilities. ! 3: * They are the only routines that touch the text. They also touch the buffer ! 4: * and window structures, to make sure that the necessary updating gets done. ! 5: * There are routines in this file that handle the kill buffer too. ! 6: * It isn't here for any good reason. ! 7: * ! 8: * Note that this code only updates the dot and mark values in the window list. ! 9: * Since all the code acts on the current window, the buffer that we are ! 10: * editing must be being displayed, which means that "b_nwnd" is non zero, ! 11: * which means that the dot and mark values in the buffer headers are nonsense. ! 12: */ ! 13: #include <stdio.h> ! 14: #include "ed.h" ! 15: ! 16: #define NBLOCK 16 /* Line block chunk size */ ! 17: #define KBLOCK 256 /* Kill buffer block size */ ! 18: ! 19: uchar *kbufp = NULL; /* Kill buffer data */ ! 20: int kused = 0; /* # of bytes used in KB */ ! 21: int ksize = 0; /* # of bytes allocated in KB */ ! 22: ! 23: /* ! 24: * This routine allocates a block of memory large enough to hold a LINE ! 25: * containing "used" characters. The block is always rounded up a bit. ! 26: * Return a pointer to the new block, or NULL if there isn't any memory left. ! 27: * Print a message in the message line if no space. ! 28: */ ! 29: LINE * ! 30: lalloc(used) ! 31: register int used; ! 32: { ! 33: register LINE *lp; ! 34: register int size; ! 35: ! 36: size = (used+NBLOCK-1) & ~(NBLOCK-1); ! 37: if (size == 0) /* Assume that an empty */ ! 38: size = NBLOCK; /* line is for type-in. */ ! 39: if ((lp = (LINE *) malloc(sizeof(LINE)+size)) == NULL) { ! 40: mlwrite("Cannot allocate %d bytes", size); ! 41: return (NULL); ! 42: } ! 43: lp->l_size = size; ! 44: lp->l_used = used; ! 45: lp->l_lnumber = 0; /* This is a new line... */ ! 46: return (lp); ! 47: } ! 48: ! 49: /* ! 50: * Delete line "lp". Fix all of the links that might point at it (they are ! 51: * moved to offset 0 of the next line. Unlink the line from whatever buffer it ! 52: * might be in. Release the memory. The buffers are updated too; the magic ! 53: * conditions described in the above comments don't hold here. ! 54: */ ! 55: lfree(lp) ! 56: register LINE *lp; ! 57: { ! 58: register BUFFER *bp; ! 59: register WINDOW *wp; ! 60: ! 61: wp = wheadp; ! 62: while (wp != NULL) { ! 63: if (wp->w_linep == lp) ! 64: wp->w_linep = lp->l_fp; ! 65: if (wp->w_dotp == lp) { ! 66: wp->w_dotp = lp->l_fp; ! 67: wp->w_doto = 0; ! 68: } ! 69: if (wp->w_markp == lp) { ! 70: wp->w_markp = lp->l_fp; ! 71: wp->w_marko = 0; ! 72: } ! 73: wp = wp->w_wndp; ! 74: } ! 75: bp = bheadp; ! 76: while (bp != NULL) { ! 77: if (bp->b_nwnd == 0) { ! 78: if (bp->b_dotp == lp) { ! 79: bp->b_dotp = lp->l_fp; ! 80: bp->b_doto = 0; ! 81: } ! 82: if (bp->b_markp == lp) { ! 83: bp->b_markp = lp->l_fp; ! 84: bp->b_marko = 0; ! 85: } ! 86: } ! 87: bp = bp->b_bufp; ! 88: } ! 89: lp->l_bp->l_fp = lp->l_fp; ! 90: lp->l_fp->l_bp = lp->l_bp; ! 91: free((char *) lp); ! 92: } ! 93: ! 94: /* ! 95: * This routine gets called when a character is changed in place in the ! 96: * current buffer. It updates all of the required flags in the buffer and ! 97: * window system. The flag used is passed as an argument; if the buffer is ! 98: * being displayed in more than 1 window we change EDIT to HARD. ! 99: * Set MODE if the mode line needs to be updated (the "*" has to be set). ! 100: */ ! 101: lchange(flag) ! 102: register int flag; ! 103: { ! 104: register WINDOW *wp; ! 105: ! 106: if (curbp->b_nwnd != 1) /* Ensure hard. */ ! 107: flag = WFHARD; ! 108: if ((curbp->b_flag&BFCHG) == 0) { /* First change, so */ ! 109: flag |= WFMODE; /* update mode lines. */ ! 110: curbp->b_flag |= BFCHG; ! 111: } ! 112: wp = wheadp; ! 113: while (wp != NULL) { ! 114: if (wp->w_bufp == curbp) ! 115: wp->w_flag |= flag; ! 116: wp = wp->w_wndp; ! 117: } ! 118: } ! 119: ! 120: /* ! 121: * Insert "n" copies of the character "c" at the current location of dot. ! 122: * In the easy case all that happens is the text is stored in the line. ! 123: * In the hard case, the line has to be reallocated. ! 124: * When the window list is updated, take special care; I screwed it up once. ! 125: * You always update dot in the current window. You update mark, and a ! 126: * dot in another window, if it is greater than the place where you did ! 127: * the insert. ! 128: * Return TRUE if all is well, and FALSE on errors. ! 129: */ ! 130: linsert(n, c) ! 131: { ! 132: register uchar *cp1; ! 133: register uchar *cp2; ! 134: register LINE *lp1; ! 135: register LINE *lp2; ! 136: register LINE *lp3; ! 137: register int doto; ! 138: register int i; ! 139: register WINDOW *wp; ! 140: ! 141: lchange(WFEDIT); ! 142: lp1 = curwp->w_dotp; /* Current line */ ! 143: if (lp1 == curbp->b_linep) { /* At the end: special */ ! 144: if (curwp->w_doto != 0) { ! 145: mlwrite("bug: linsert"); ! 146: return (FALSE); ! 147: } ! 148: if ((lp2=lalloc(n)) == NULL) /* Allocate new line */ ! 149: return (FALSE); ! 150: lp3 = lp1->l_bp; /* Previous line */ ! 151: lp3->l_fp = lp2; /* Link in */ ! 152: lp2->l_fp = lp1; ! 153: lp1->l_bp = lp2; ! 154: lp2->l_bp = lp3; ! 155: for (i=0; i<n; ++i) ! 156: lp2->l_text[i] = c; ! 157: curwp->w_dotp = lp2; ! 158: curwp->w_doto = n; ! 159: return (TRUE); ! 160: } ! 161: doto = curwp->w_doto; /* Save for later. */ ! 162: if (lp1->l_used+n > lp1->l_size) { /* Hard: reallocate */ ! 163: if ((lp2=lalloc(lp1->l_used+n)) == NULL) ! 164: return (FALSE); ! 165: cp1 = &lp1->l_text[0]; ! 166: cp2 = &lp2->l_text[0]; ! 167: while (cp1 != &lp1->l_text[doto]) ! 168: *cp2++ = *cp1++; ! 169: cp2 += n; ! 170: while (cp1 != &lp1->l_text[lp1->l_used]) ! 171: *cp2++ = *cp1++; ! 172: lp1->l_bp->l_fp = lp2; ! 173: lp2->l_fp = lp1->l_fp; ! 174: lp1->l_fp->l_bp = lp2; ! 175: lp2->l_bp = lp1->l_bp; ! 176: free((char *) lp1); ! 177: } else { /* Easy: in place */ ! 178: lp2 = lp1; /* Pretend new line */ ! 179: lp2->l_used += n; ! 180: cp2 = &lp1->l_text[lp1->l_used]; ! 181: cp1 = cp2-n; ! 182: while (cp1 != &lp1->l_text[doto]) ! 183: *--cp2 = *--cp1; ! 184: } ! 185: for (i=0; i<n; ++i) /* Add the characters */ ! 186: lp2->l_text[doto+i] = c; ! 187: wp = wheadp; /* Update windows */ ! 188: while (wp != NULL) { ! 189: if (wp->w_linep == lp1) ! 190: wp->w_linep = lp2; ! 191: if (wp->w_dotp == lp1) { ! 192: wp->w_dotp = lp2; ! 193: if (wp==curwp || wp->w_doto>doto) ! 194: wp->w_doto += n; ! 195: } ! 196: if (wp->w_markp == lp1) { ! 197: wp->w_markp = lp2; ! 198: if (wp->w_marko > doto) ! 199: wp->w_marko += n; ! 200: } ! 201: wp = wp->w_wndp; ! 202: } ! 203: return (TRUE); ! 204: } ! 205: ! 206: /* ! 207: * Insert a newline into the buffer at the current location of dot in the ! 208: * current window. The funny ass-backwards way it does things is not a botch; ! 209: * it just makes the last line in the file not a special case. Return TRUE if ! 210: * everything works out and FALSE on error (memory allocation failure). ! 211: * The update of dot and mark is a bit easier then in the above case, because ! 212: * the split forces more updating. ! 213: */ ! 214: lnewline() ! 215: { ! 216: register uchar *cp1; ! 217: register uchar *cp2; ! 218: register LINE *lp1; ! 219: register LINE *lp2; ! 220: register int doto; ! 221: register WINDOW *wp; ! 222: ! 223: lchange(WFHARD); ! 224: lp1 = curwp->w_dotp; /* Get the address and */ ! 225: doto = curwp->w_doto; /* offset of "." */ ! 226: if ((lp2=lalloc(doto)) == NULL) /* New first half line */ ! 227: return (FALSE); ! 228: cp1 = &lp1->l_text[0]; /* Shuffle text around */ ! 229: cp2 = &lp2->l_text[0]; ! 230: while (cp1 != &lp1->l_text[doto]) ! 231: *cp2++ = *cp1++; ! 232: cp2 = &lp1->l_text[0]; ! 233: while (cp1 != &lp1->l_text[lp1->l_used]) ! 234: *cp2++ = *cp1++; ! 235: lp1->l_used -= doto; ! 236: lp2->l_bp = lp1->l_bp; ! 237: lp1->l_bp = lp2; ! 238: lp2->l_bp->l_fp = lp2; ! 239: lp2->l_fp = lp1; ! 240: wp = wheadp; /* Windows */ ! 241: while (wp != NULL) { ! 242: if (wp->w_linep == lp1) ! 243: wp->w_linep = lp2; ! 244: if (wp->w_dotp == lp1) { ! 245: if (wp->w_doto < doto) ! 246: wp->w_dotp = lp2; ! 247: else ! 248: wp->w_doto -= doto; ! 249: } ! 250: if (wp->w_markp == lp1) { ! 251: if (wp->w_marko < doto) ! 252: wp->w_markp = lp2; ! 253: else ! 254: wp->w_marko -= doto; ! 255: } ! 256: wp = wp->w_wndp; ! 257: } ! 258: return (TRUE); ! 259: } ! 260: ! 261: /* ! 262: * This function deletes "n" bytes, starting at dot. It understands how to deal ! 263: * with end of lines, etc. It returns TRUE if all of the characters were ! 264: * deleted, and FALSE if they were not (because dot ran into the end of ! 265: * the buffer. The "kflag" is TRUE if the text should be put in the kill buffer. ! 266: */ ! 267: ldelete(n, kflag) ! 268: { ! 269: register uchar *cp1; ! 270: register uchar *cp2; ! 271: register LINE *dotp; ! 272: register int doto; ! 273: register int chunk; ! 274: register WINDOW *wp; ! 275: ! 276: while (n != 0) { ! 277: dotp = curwp->w_dotp; ! 278: doto = curwp->w_doto; ! 279: if (dotp == curbp->b_linep) /* Hit end of buffer. */ ! 280: return (FALSE); ! 281: chunk = dotp->l_used-doto; /* Size of chunk. */ ! 282: if (chunk > n) ! 283: chunk = n; ! 284: if (chunk == 0) { /* End of line, merge. */ ! 285: lchange(WFHARD); ! 286: if (ldelnewline() == FALSE ! 287: || (kflag!=FALSE && kinsert('\n')==FALSE)) ! 288: return (FALSE); ! 289: --n; ! 290: continue; ! 291: } ! 292: lchange(WFEDIT); ! 293: cp1 = &dotp->l_text[doto]; /* Scrunch text. */ ! 294: cp2 = cp1 + chunk; ! 295: if (kflag != FALSE) { /* Kill? */ ! 296: while (cp1 != cp2) { ! 297: if (kinsert(*cp1) == FALSE) ! 298: return (FALSE); ! 299: ++cp1; ! 300: } ! 301: cp1 = &dotp->l_text[doto]; ! 302: } ! 303: while (cp2 != &dotp->l_text[dotp->l_used]) ! 304: *cp1++ = *cp2++; ! 305: dotp->l_used -= chunk; ! 306: wp = wheadp; /* Fix windows */ ! 307: while (wp != NULL) { ! 308: if (wp->w_dotp==dotp && wp->w_doto>=doto) { ! 309: wp->w_doto -= chunk; ! 310: if (wp->w_doto < doto) ! 311: wp->w_doto = doto; ! 312: } ! 313: if (wp->w_markp==dotp && wp->w_marko>=doto) { ! 314: wp->w_marko -= chunk; ! 315: if (wp->w_marko < doto) ! 316: wp->w_marko = doto; ! 317: } ! 318: wp = wp->w_wndp; ! 319: } ! 320: n -= chunk; ! 321: } ! 322: return (TRUE); ! 323: } ! 324: ! 325: /* ! 326: * Delete a newline. Join the current line with the next line. If the next ! 327: * line is the magic header line always return TRUE; merging the last line ! 328: * with the header line can be thought of as always being a successful ! 329: * operation, even if nothing is done, and this makes the kill buffer ! 330: * work "right". Easy cases can be done by shuffling data around. ! 331: * Hard cases require that lines be moved about in memory. ! 332: * Return FALSE on error and TRUE if all looks ok. Called by "ldelete" only. ! 333: */ ! 334: ldelnewline() ! 335: { ! 336: register uchar *cp1; ! 337: register uchar *cp2; ! 338: register LINE *lp1; ! 339: register LINE *lp2; ! 340: register LINE *lp3; ! 341: register WINDOW *wp; ! 342: ! 343: lp1 = curwp->w_dotp; /* This line... */ ! 344: lp2 = lp1->l_fp; /* The next line... */ ! 345: ! 346: if (lp2 == curbp->b_linep) { /* At the buffer end. */ ! 347: if (lp1->l_used == 0) /* Blank line. */ ! 348: lfree(lp1); ! 349: return (TRUE); ! 350: } ! 351: /* Fix file-line numbers. */ ! 352: if ((lp1->l_used == 0) || (lp1->l_lnumber == 0)) ! 353: lp1->l_lnumber = lp2->l_lnumber; ! 354: ! 355: if (lp2->l_used <= lp1->l_size-lp1->l_used) { ! 356: cp1 = &lp1->l_text[lp1->l_used]; ! 357: cp2 = &lp2->l_text[0]; ! 358: while (cp2 != &lp2->l_text[lp2->l_used]) ! 359: *cp1++ = *cp2++; ! 360: wp = wheadp; ! 361: while (wp != NULL) { ! 362: if (wp->w_linep == lp2) ! 363: wp->w_linep = lp1; ! 364: if (wp->w_dotp == lp2) { ! 365: wp->w_dotp = lp1; ! 366: wp->w_doto += lp1->l_used; ! 367: } ! 368: if (wp->w_markp == lp2) { ! 369: wp->w_markp = lp1; ! 370: wp->w_marko += lp1->l_used; ! 371: } ! 372: wp = wp->w_wndp; ! 373: } ! 374: lp1->l_used += lp2->l_used; ! 375: lp1->l_fp = lp2->l_fp; ! 376: lp2->l_fp->l_bp = lp1; ! 377: free((char *) lp2); ! 378: return (TRUE); ! 379: } ! 380: if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL) ! 381: return (FALSE); ! 382: cp1 = &lp1->l_text[0]; ! 383: cp2 = &lp3->l_text[0]; ! 384: while (cp1 != &lp1->l_text[lp1->l_used]) ! 385: *cp2++ = *cp1++; ! 386: cp1 = &lp2->l_text[0]; ! 387: while (cp1 != &lp2->l_text[lp2->l_used]) ! 388: *cp2++ = *cp1++; ! 389: lp1->l_bp->l_fp = lp3; ! 390: lp3->l_fp = lp2->l_fp; ! 391: lp2->l_fp->l_bp = lp3; ! 392: lp3->l_bp = lp1->l_bp; ! 393: wp = wheadp; ! 394: while (wp != NULL) { ! 395: if (wp->w_linep==lp1 || wp->w_linep==lp2) ! 396: wp->w_linep = lp3; ! 397: if (wp->w_dotp == lp1) ! 398: wp->w_dotp = lp3; ! 399: else if (wp->w_dotp == lp2) { ! 400: wp->w_dotp = lp3; ! 401: wp->w_doto += lp1->l_used; ! 402: } ! 403: if (wp->w_markp == lp1) ! 404: wp->w_markp = lp3; ! 405: else if (wp->w_markp == lp2) { ! 406: wp->w_markp = lp3; ! 407: wp->w_marko += lp1->l_used; ! 408: } ! 409: wp = wp->w_wndp; ! 410: } ! 411: free((char *) lp1); ! 412: free((char *) lp2); ! 413: return (TRUE); ! 414: } ! 415: ! 416: /* ! 417: * Delete all of the text saved in the kill buffer. Called by commands when ! 418: * a new kill context is being created. The kill buffer array is released, ! 419: * just in case the buffer has grown to immense size. No errors. ! 420: */ ! 421: kdelete() ! 422: { ! 423: if (kbufp != NULL) { ! 424: free((char *) kbufp); ! 425: kbufp = NULL; ! 426: kused = 0; ! 427: ksize = 0; ! 428: } ! 429: } ! 430: ! 431: /* ! 432: * Insert a character to the kill buffer, enlarging the buffer if there ! 433: * isn't any room. Always grow the buffer in chunks, on the assumption ! 434: * that if you put something in the kill buffer you are going to put more ! 435: * stuff there too later. Return TRUE if all is well, and FALSE on errors. ! 436: */ ! 437: kinsert(c) ! 438: { ! 439: register uchar *nbufp; ! 440: register int i; ! 441: ! 442: if (kused == ksize) { ! 443: if ((nbufp=malloc(ksize+KBLOCK)) == NULL) ! 444: return (FALSE); ! 445: for (i=0; i<ksize; ++i) ! 446: nbufp[i] = kbufp[i]; ! 447: if (kbufp != NULL) ! 448: free((char *) kbufp); ! 449: kbufp = nbufp; ! 450: ksize += KBLOCK; ! 451: } ! 452: kbufp[kused++] = c; ! 453: return (TRUE); ! 454: } ! 455: ! 456: /* ! 457: * This function gets characters from the kill buffer. If the character index ! 458: * "n" is off the end, it returns "-1". This lets the caller just scan along ! 459: * until it gets a "-1" back. ! 460: */ ! 461: kremove(n) ! 462: { ! 463: if (n >= kused) ! 464: return (-1); ! 465: else ! 466: return (kbufp[n] & 0xFF); ! 467: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.