|
|
1.1 ! root 1: /* @(microEMACS)random.c ! 2: * ! 3: * This file contains the command processing functions for a number of ! 4: * random commands. There is no functional grouping here, for sure. ! 5: */ ! 6: #include <stdio.h> ! 7: #include "ed.h" ! 8: ! 9: /* ! 10: * Return current column. Stop at first non-blank given TRUE argument. ! 11: */ ! 12: getccol(bflg) ! 13: int bflg; ! 14: { ! 15: register int i; ! 16: register int col = 0; ! 17: register WINDOW *lcurwp; ! 18: unsigned c; ! 19: ! 20: lcurwp = curwp; ! 21: for (i=0; i<lcurwp->w_doto; ++i) { ! 22: c = lgetc(lcurwp->w_dotp, i); ! 23: if (c != ' ' && c != '\t' && bflg) ! 24: break; ! 25: switch (dblchr(c)) { ! 26: case 2: ! 27: taber(col); ! 28: break; ! 29: case 1: ! 30: ++col; ! 31: } ! 32: ++col; ! 33: } ! 34: return (col); ! 35: } ! 36: ! 37: /* ! 38: * Set fill column to n, if given, otherwise use the current cursor ! 39: * column. Either way, tell user where the fill column really is. ! 40: */ ! 41: setfillcol(f, n) ! 42: register int n; ! 43: { ! 44: if (!n) ! 45: bind.fillcol = 0; ! 46: else if (n == 1) ! 47: bind.fillcol = getccol(FALSE); ! 48: else ! 49: bind.fillcol = n - 1; ! 50: ! 51: if (bind.fillcol) ! 52: mlwrite("[Wrap at column %d]", bind.fillcol+1); ! 53: else ! 54: mlwrite("Word wrap turned off"); ! 55: return (TRUE); ! 56: } ! 57: ! 58: /* ! 59: * Display the current position of the cursor, ! 60: * in origin 1 X-Y coordinates, the character that is ! 61: * under the cursor (in hex), and the fraction of the ! 62: * text that is before the cursor. The displayed column ! 63: * is not the current column, but the column that would ! 64: * be used on an infinite width display. Normally this ! 65: * is bound to "C-X =". ! 66: */ ! 67: showcpos(f, n) ! 68: { ! 69: register LINE *clp; ! 70: register long nch = 0L; ! 71: register long nbc; ! 72: register int cbo = 0; ! 73: register int linecnt = 1; ! 74: register int cac; ! 75: register int curline = 0; ! 76: int ratio; ! 77: int col; ! 78: ! 79: clp = lforw(curbp->b_linep); /* Grovel the data. */ ! 80: ! 81: for (;;) { ! 82: if (clp==curwp->w_dotp && cbo==curwp->w_doto) { ! 83: curline = linecnt; ! 84: nbc = nch; ! 85: if (cbo == llength(clp)) ! 86: cac = '\n'; ! 87: else ! 88: cac = lgetc(clp, cbo); ! 89: } ! 90: if (cbo == llength(clp)) { ! 91: if (clp == curbp->b_linep) ! 92: break; ! 93: clp = lforw(clp); ! 94: ++linecnt; ! 95: cbo = 0; ! 96: } else ! 97: ++cbo; ! 98: ++nch; ! 99: } ! 100: col = getccol(FALSE)+1; /* Get real column. */ ! 101: ratio = 0; /* Ratio before dot. */ ! 102: if (nch != 0) ! 103: ratio = (100L*nbc) / nch; ! 104: mlwrite("X=%d Y=%d CH=0x%x .=%ld (%d%% of %ld) line %d of %d", ! 105: col, currow+1, cac, nbc, ratio, nch, curline, linecnt); ! 106: return (TRUE); ! 107: } ! 108: ! 109: /* ! 110: * Twiddle the two characters on either side of ! 111: * dot. If dot is at the end of the line twiddle the ! 112: * two characters before it. Return with an error if dot ! 113: * is at the beginning of line; it seems to be a bit ! 114: * pointless to make this work. This fixes up a very ! 115: * common typo with a single stroke. Normally bound ! 116: * to "C-T". This always works within a line, so ! 117: * "WFEDIT" is good enough. ! 118: */ ! 119: twiddle(f, n) ! 120: { ! 121: register WINDOW *lcurwp; ! 122: register LINE *dotp; ! 123: register int doto; ! 124: register int cl; ! 125: register int cr; ! 126: ! 127: lcurwp = curwp; ! 128: dotp = lcurwp->w_dotp; ! 129: doto = lcurwp->w_doto; ! 130: if (doto==llength(dotp) && --doto<0) ! 131: return (FALSE); ! 132: cr = lgetc(dotp, doto); ! 133: if (--doto < 0) ! 134: return (FALSE); ! 135: cl = lgetc(dotp, doto); ! 136: lputc(dotp, doto+0, cr); ! 137: lputc(dotp, doto+1, cl); ! 138: lchange(WFEDIT); ! 139: return (TRUE); ! 140: } ! 141: ! 142: /* ! 143: * Quote the next character, and insert it into the buffer. All the characters ! 144: * are taken literally, with the exception of the newline, which always has ! 145: * its line splitting meaning. The character is always read, even if it is ! 146: * inserted 0 times, for regularity. If executing a macro, get the character ! 147: * from memory, otherwise, get it from the keyboard. ! 148: * Bound to "C-Q" ! 149: */ ! 150: quote(f, n) ! 151: register int n; ! 152: { ! 153: register int s; ! 154: register int c; ! 155: ! 156: if (kbdmop != NULL) /* if in a macro, get from memory */ ! 157: c = *kbdmop++; /* fixes a bug in an old version */ ! 158: else /* where the quoted character was */ ! 159: c = tgetc(); /* not remembered. */ ! 160: if (kbdmip != NULL) ! 161: *kbdmip++ = c; /* if defining a macro, remember */ ! 162: if (n < 0) ! 163: return (FALSE); ! 164: if (n == 0) ! 165: return (TRUE); ! 166: if (c == '\n') { ! 167: do { ! 168: s = lnewline(); ! 169: } while (s==TRUE && --n); ! 170: return (s); ! 171: } ! 172: return (linsert(n, c)); ! 173: } ! 174: ! 175: /* ! 176: * Get character by value, and insert it into the buffer. All the characters ! 177: * are taken literally, with the exception of the newline, which always has ! 178: * its line splitting meaning. The character is always read, even if it is ! 179: * inserted 0 times, for regularity. ! 180: * Bound to "M-Q" ! 181: */ ! 182: quoteval(f, n) ! 183: register int n; ! 184: { ! 185: register int s; ! 186: register int c; ! 187: char buf[10]; /* big enough */ ! 188: ! 189: if (TRUE != (s = mlreply("value of char to insert ", buf, sizeof(buf)))) ! 190: return (s); ! 191: ! 192: if (n < 0) ! 193: return (FALSE); ! 194: if (n == 0) ! 195: return (TRUE); ! 196: ! 197: c = atoi(buf); ! 198: if (c == '\n') { ! 199: do { ! 200: s = lnewline(); ! 201: } while (s==TRUE && --n); ! 202: return (s); ! 203: } ! 204: return (linsert(n, c)); ! 205: } ! 206: ! 207: /* ! 208: * Toggle autoindent flag. ! 209: */ ! 210: autoind(f, n) ! 211: { ! 212: bind.autoindent ^= 1; ! 213: } ! 214: ! 215: /* ! 216: * Set tab size if given non-default argument (n <> 1). Otherwise, insert a ! 217: * tab into file. If given argument, n, of zero, change to true tabs. ! 218: * If n > 1, simulate tab stop every n-characters using spaces. ! 219: * This has to be done in this slightly funny way because the ! 220: * tab (in ASCII) has been turned into "C-I" (in 10 ! 221: * bit code) already. Bound to "C-I". ! 222: */ ! 223: tab(f, n) ! 224: register int n; ! 225: { ! 226: if (n == 1) /* normal tabbing */ ! 227: return (bind.tabsize ? ! 228: linsert(bind.tabsize - (getccol(FALSE)%bind.tabsize),' ') : ! 229: linsert(1, '\t')); ! 230: ! 231: if (n < 0) { /* change the meaning of tab character */ ! 232: bind.tabsiz = -n; ! 233: curwp->w_flag |= WFMODE|WFFORCE|WFHARD; ! 234: return (TRUE); ! 235: } ! 236: ! 237: /* change the meaning of tab key */ ! 238: if (!(bind.tabsize = n)) { ! 239: bind.tabsiz = 8; /* back to the default for 0 */ ! 240: curwp->w_flag |= WFMODE|WFFORCE|WFHARD; ! 241: } ! 242: return (TRUE); ! 243: } ! 244: ! 245: /* ! 246: * Open up some blank space. The basic plan ! 247: * is to insert a bunch of newlines, and then back ! 248: * up over them. Everything is done by the subcommand ! 249: * procerssors. They even handle the looping. Normally ! 250: * this is bound to "C-O". ! 251: */ ! 252: openline(f, n) ! 253: register int n; ! 254: { ! 255: register int i; ! 256: register int s; ! 257: ! 258: if (n < 0) ! 259: return (FALSE); ! 260: if (n == 0) ! 261: return (TRUE); ! 262: i = n; /* Insert newlines. */ ! 263: do { ! 264: s = lnewline(); ! 265: } while (s==TRUE && --i); ! 266: if (s == TRUE) /* Then back up overtop */ ! 267: s = backchar(f, n); /* of them all. */ ! 268: return (s); ! 269: } ! 270: ! 271: /* ! 272: * Insert a newline. Bound to "C-M". ! 273: * If you are at the end of the line and the ! 274: * next line is a blank line, just move into the ! 275: * blank line. This makes "C-O" and "C-X C-O" work ! 276: * nicely, and reduces the ammount of screen ! 277: * update that has to be done. This would not be ! 278: * as critical if screen update were a lot ! 279: * more efficient. ! 280: */ ! 281: newline(f, n) ! 282: register int n; ! 283: { ! 284: register LINE *lp; ! 285: register int s; ! 286: ! 287: if (n < 0) ! 288: return (FALSE); ! 289: while (n--) { ! 290: lp = curwp->w_dotp; ! 291: if (llength(lp) == curwp->w_doto ! 292: && lp != curbp->b_linep ! 293: && llength(lforw(lp)) == 0) { ! 294: if ((s=forwchar(FALSE, 1)) != TRUE) ! 295: return (s); ! 296: } else if ((s=lnewline()) != TRUE) ! 297: return (s); ! 298: } ! 299: return (TRUE); ! 300: } ! 301: ! 302: /* ! 303: * Delete blank lines around dot. ! 304: * What this command does depends if dot is ! 305: * sitting on a blank line. If dot is sitting on a ! 306: * blank line, this command deletes all the blank lines ! 307: * above and below the current line. If it is sitting ! 308: * on a non blank line then it deletes all of the ! 309: * blank lines after the line. Normally this command ! 310: * is bound to "C-X C-O". Any argument is ignored. ! 311: */ ! 312: deblank(f, n) ! 313: { ! 314: register LINE *lp1; ! 315: register LINE *lp2; ! 316: register int nld; ! 317: register WINDOW *lcurwp; ! 318: ! 319: lcurwp = curwp; ! 320: lp1 = lcurwp->w_dotp; ! 321: while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep) ! 322: lp1 = lp2; ! 323: lp2 = lp1; ! 324: nld = 0; ! 325: while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0) ! 326: ++nld; ! 327: if (nld == 0) ! 328: return (TRUE); ! 329: lcurwp->w_dotp = lforw(lp1); ! 330: lcurwp->w_doto = 0; ! 331: return (ldelete(nld, FALSE)); ! 332: } ! 333: ! 334: /* ! 335: * Insert a newline, then enough ! 336: * tabs and spaces to duplicate the indentation ! 337: * of the previous line. Assumes tabs are every eight ! 338: * characters. Quite simple. Figure out the indentation ! 339: * of the current line. Insert a newline by calling ! 340: * the standard routine. Insert the indentation by ! 341: * inserting the right number of tabs and spaces. ! 342: * Return TRUE if all ok. Return FALSE if one ! 343: * of the subcomands failed. Normally bound ! 344: * to "C-J". ! 345: */ ! 346: indent(f, n) ! 347: { ! 348: register int nicol; ! 349: register int c; ! 350: register int i; ! 351: ! 352: if (n < 0) ! 353: return (FALSE); ! 354: while (n--) { ! 355: nicol = 0; ! 356: for (i=0; i<llength(curwp->w_dotp); ++i) { ! 357: c = lgetc(curwp->w_dotp, i); ! 358: if (c!=' ' && c!='\t') ! 359: break; ! 360: if (c == '\t') ! 361: taber(nicol); ! 362: ++nicol; ! 363: } ! 364: if (lnewline() == FALSE ! 365: || ((i=nicol/bind.tabsiz)!=0 && linsert(i, '\t')==FALSE) ! 366: || ((i=nicol%bind.tabsiz)!=0 && linsert(i, ' ')==FALSE)) ! 367: return (FALSE); ! 368: } ! 369: return (TRUE); ! 370: } ! 371: ! 372: /* ! 373: * Delete forward. This is real ! 374: * easy, because the basic delete routine does ! 375: * all of the work. Watches for negative arguments, ! 376: * and does the right thing. If any argument is ! 377: * present, it kills rather than deletes, to prevent ! 378: * loss of text if typed with a big argument. ! 379: * Normally bound to "C-D". ! 380: */ ! 381: forwdel(f, n) ! 382: { ! 383: if (n < 0) ! 384: return (backdel(f, -n)); ! 385: if (f != FALSE) { /* Really a kill. */ ! 386: if ((lastflag&CFKILL) == 0) ! 387: kdelete(); ! 388: thisflag |= CFKILL; ! 389: } ! 390: return (ldelete(n, f)); ! 391: } ! 392: ! 393: /* ! 394: * Delete backwards. This is quite easy too, ! 395: * because it's all done with other functions. Just ! 396: * move the cursor back, and delete forwards. ! 397: * Like delete forward, this actually does a kill ! 398: * if presented with an argument. Bound to both ! 399: * "RUBOUT" and "C-H". ! 400: */ ! 401: backdel(f, n) ! 402: { ! 403: register int s; ! 404: ! 405: if (n < 0) ! 406: return (forwdel(f, -n)); ! 407: if (f != FALSE) { /* Really a kill. */ ! 408: if ((lastflag&CFKILL) == 0) ! 409: kdelete(); ! 410: thisflag |= CFKILL; ! 411: } ! 412: if ((s=backchar(f, n)) == TRUE) ! 413: s = ldelete(n, f); ! 414: return (s); ! 415: } ! 416: ! 417: /* ! 418: * Kill text. If called without an argument, ! 419: * it kills from dot to the end of the line, unless it ! 420: * is at the end of the line, when it kills the newline. ! 421: * If called with an argument of 0, it kills from the ! 422: * start of the line to dot. If called with a positive ! 423: * argument, it kills from dot forward over that number ! 424: * of newlines. If called with a negative argument it ! 425: * kills backwards that number of newlines. Normally ! 426: * bound to "C-K". ! 427: */ ! 428: kill(f, n) ! 429: { ! 430: register int chunk; ! 431: register LINE *nextp; ! 432: ! 433: if ((lastflag&CFKILL) == 0) /* Clear kill buffer if */ ! 434: kdelete(); /* last wasn't a kill. */ ! 435: thisflag |= CFKILL; ! 436: if (f == FALSE) { ! 437: chunk = llength(curwp->w_dotp)-curwp->w_doto; ! 438: if (chunk == 0) ! 439: chunk = 1; ! 440: } else if (n == 0) { ! 441: chunk = curwp->w_doto; ! 442: curwp->w_doto = 0; ! 443: } else if (n > 0) { ! 444: chunk = llength(curwp->w_dotp)-curwp->w_doto+1; ! 445: nextp = lforw(curwp->w_dotp); ! 446: while (--n) { ! 447: if (nextp == curbp->b_linep) ! 448: return (FALSE); ! 449: chunk += llength(nextp)+1; ! 450: nextp = lforw(nextp); ! 451: } ! 452: } else { ! 453: mlwrite("neg kill"); ! 454: return (FALSE); ! 455: } ! 456: return (ldelete(chunk, TRUE)); ! 457: } ! 458: ! 459: /* ! 460: * Yank text back from the kill buffer. This ! 461: * is really easy. All of the work is done by the ! 462: * standard insert routines. All you do is run the loop, ! 463: * and check for errors. Bound to "C-Y". The blank ! 464: * lines are inserted with a call to "newline" ! 465: * instead of a call to "lnewline" so that the magic ! 466: * stuff that happens when you type a carriage ! 467: * return also happens when a carriage return is ! 468: * yanked back from the kill buffer. ! 469: */ ! 470: yank(f, n) ! 471: { ! 472: register int c; ! 473: register int i; ! 474: extern int kused; ! 475: ! 476: if (n < 0) ! 477: return (FALSE); ! 478: while (n--) { ! 479: i = 0; ! 480: while ((c=kremove(i)) >= 0) { ! 481: if (c == '\n') { ! 482: if (newline(FALSE, 1) == FALSE) ! 483: return (FALSE); ! 484: } else { ! 485: if (linsert(1, c) == FALSE) ! 486: return (FALSE); ! 487: } ! 488: ++i; ! 489: } ! 490: } ! 491: return (TRUE); ! 492: } ! 493: ! 494: #if GEM ! 495: /* ! 496: * singlecase the characters in the given buffer. this is used for ! 497: * buffer and file names on the ST, since everything becomes uppercase ! 498: * (whether you like it or not) from the desktop and in file names. ! 499: * this routine assumes ASCII. ! 500: */ ! 501: fixname(bp) ! 502: register uchar *bp; ! 503: { ! 504: register unsigned c; ! 505: ! 506: while (c = *bp) ! 507: #if UPPERNM ! 508: if (c >= 'a' && c <= 'z') ! 509: *bp++ = c & ~0x20; /* Lower to upper case */ ! 510: #else ! 511: if (c >= 'A' && c <= 'Z') ! 512: *bp++ = c | 0x20; /* Upper to lower case */ ! 513: #endif ! 514: else ! 515: ++bp; ! 516: } ! 517: #endif ! 518: ! 519: setfold(f,n) ! 520: { ! 521: if (f) ! 522: bind.ffold = n; ! 523: else ! 524: bind.ffold = !bind.ffold; ! 525: if (bind.ffold) ! 526: mlwrite("[Case fold on search]"); ! 527: else ! 528: mlwrite("[Match case on search]"); ! 529: return TRUE; ! 530: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.