Annotation of src/usr.bin/mg/random.c, Revision 1.1
1.1 ! deraadt 1: /*
! 2: * Assorted commands.
! 3: * The file contains the command
! 4: * processors for a large assortment of unrelated
! 5: * commands. The only thing they have in common is
! 6: * that they are all command processors.
! 7: */
! 8: #include "def.h"
! 9:
! 10: /*
! 11: * Display a bunch of useful information about
! 12: * the current location of dot. The character under the
! 13: * cursor (in octal), the current line, row, and column, and
! 14: * approximate position of the cursor in the file (as a percentage)
! 15: * is displayed. The column position assumes an infinite position
! 16: * display; it does not truncate just because the screen does.
! 17: * This is normally bound to "C-X =".
! 18: */
! 19: /*ARGSUSED*/
! 20: showcpos(f, n)
! 21: {
! 22: register LINE *clp;
! 23: register long nchar;
! 24: long cchar;
! 25: register int nline, row;
! 26: int cline, cbyte; /* Current line/char/byte */
! 27: int ratio;
! 28:
! 29: clp = lforw(curbp->b_linep); /* Collect the data. */
! 30: nchar = 0;
! 31: nline = 0;
! 32: for (;;) {
! 33: ++nline; /* Count this line */
! 34: if (clp == curwp->w_dotp) {
! 35: cline = nline; /* Mark line */
! 36: cchar = nchar + curwp->w_doto;
! 37: if (curwp->w_doto == llength(clp))
! 38: cbyte = '\n';
! 39: else
! 40: cbyte = lgetc(clp, curwp->w_doto);
! 41: }
! 42: nchar += llength(clp); /* Now count the chars */
! 43: clp = lforw(clp);
! 44: if (clp == curbp->b_linep) break;
! 45: nchar++; /* count the newline */
! 46: }
! 47: row = curwp->w_toprow + 1; /* Determine row. */
! 48: clp = curwp->w_linep;
! 49: while (clp!=curbp->b_linep && clp!=curwp->w_dotp) {
! 50: ++row;
! 51: clp = lforw(clp);
! 52: }
! 53: /*NOSTRICT*/
! 54: ratio = nchar ? (100L*cchar) / nchar : 100;
! 55: ewprintf("Char: %c (0%o) point=%ld(%d%%) line=%d row=%d col=%d",
! 56: cbyte, cbyte, cchar, ratio, cline, row, getcolpos());
! 57: return TRUE;
! 58: }
! 59:
! 60: getcolpos() {
! 61: register int col, i, c;
! 62:
! 63: col = 1; /* Determine column. */
! 64: for (i=0; i<curwp->w_doto; ++i) {
! 65: c = lgetc(curwp->w_dotp, i);
! 66: if (c == '\t'
! 67: #ifdef NOTAB
! 68: && !(curbp->b_flag & BFNOTAB)
! 69: #endif
! 70: ) {
! 71: col |= 0x07;
! 72: ++col;
! 73: } else if (ISCTRL(c) != FALSE)
! 74: ++col;
! 75: ++col;
! 76: }
! 77: return col;
! 78: }
! 79: /*
! 80: * Twiddle the two characters on either side of
! 81: * dot. If dot is at the end of the line twiddle the
! 82: * two characters before it. Return with an error if dot
! 83: * is at the beginning of line; it seems to be a bit
! 84: * pointless to make this work. This fixes up a very
! 85: * common typo with a single stroke. Normally bound
! 86: * to "C-T". This always works within a line, so
! 87: * "WFEDIT" is good enough.
! 88: */
! 89: /*ARGSUSED*/
! 90: twiddle(f, n)
! 91: {
! 92: register LINE *dotp;
! 93: register int doto;
! 94: register int cr;
! 95: VOID lchange();
! 96:
! 97: dotp = curwp->w_dotp;
! 98: doto = curwp->w_doto;
! 99: if(doto==llength(dotp)) {
! 100: if(--doto<=0) return FALSE;
! 101: } else {
! 102: if(doto==0) return FALSE;
! 103: ++curwp->w_doto;
! 104: }
! 105: cr = lgetc(dotp, doto--);
! 106: lputc(dotp, doto+1, lgetc(dotp, doto));
! 107: lputc(dotp, doto, cr);
! 108: lchange(WFEDIT);
! 109: return TRUE;
! 110: }
! 111:
! 112: /*
! 113: * Open up some blank space. The basic plan
! 114: * is to insert a bunch of newlines, and then back
! 115: * up over them. Everything is done by the subcommand
! 116: * procerssors. They even handle the looping. Normally
! 117: * this is bound to "C-O".
! 118: */
! 119: /*ARGSUSED*/
! 120: openline(f, n)
! 121: {
! 122: register int i;
! 123: register int s;
! 124:
! 125: if (n < 0)
! 126: return FALSE;
! 127: if (n == 0)
! 128: return TRUE;
! 129: i = n; /* Insert newlines. */
! 130: do {
! 131: s = lnewline();
! 132: } while (s==TRUE && --i);
! 133: if (s == TRUE) /* Then back up overtop */
! 134: s = backchar(f | FFRAND, n); /* of them all. */
! 135: return s;
! 136: }
! 137:
! 138: /*
! 139: * Insert a newline.
! 140: * [following "feature" not present in current version of
! 141: * Gnu, and now disabled here too]
! 142: * If you are at the end of the line and the
! 143: * next line is a blank line, just move into the
! 144: * blank line. This makes "C-O" and "C-X C-O" work
! 145: * nicely, and reduces the ammount of screen
! 146: * update that has to be done. This would not be
! 147: * as critical if screen update were a lot
! 148: * more efficient.
! 149: */
! 150: /*ARGSUSED*/
! 151: newline(f, n)
! 152: {
! 153: register LINE *lp;
! 154: register int s;
! 155:
! 156: if (n < 0) return FALSE;
! 157: while (n--) {
! 158: lp = curwp->w_dotp;
! 159: #ifdef undef
! 160: if (llength(lp) == curwp->w_doto
! 161: && lforw(lp) != curbp->b_linep
! 162: && llength(lforw(lp)) == 0) {
! 163: if ((s=forwchar(FFRAND, 1)) != TRUE)
! 164: return s;
! 165: } else
! 166: #endif
! 167: if ((s=lnewline()) != TRUE)
! 168: return s;
! 169: }
! 170: return TRUE;
! 171: }
! 172:
! 173: /*
! 174: * Delete blank lines around dot.
! 175: * What this command does depends if dot is
! 176: * sitting on a blank line. If dot is sitting on a
! 177: * blank line, this command deletes all the blank lines
! 178: * above and below the current line. If it is sitting
! 179: * on a non blank line then it deletes all of the
! 180: * blank lines after the line. Normally this command
! 181: * is bound to "C-X C-O". Any argument is ignored.
! 182: */
! 183: /*ARGSUSED*/
! 184: deblank(f, n)
! 185: {
! 186: register LINE *lp1;
! 187: register LINE *lp2;
! 188: register RSIZE nld;
! 189:
! 190: lp1 = curwp->w_dotp;
! 191: while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep)
! 192: lp1 = lp2;
! 193: lp2 = lp1;
! 194: nld = (RSIZE) 0;
! 195: while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0)
! 196: ++nld;
! 197: if (nld == 0)
! 198: return (TRUE);
! 199: curwp->w_dotp = lforw(lp1);
! 200: curwp->w_doto = 0;
! 201: return ldelete((RSIZE)nld, KNONE);
! 202: }
! 203:
! 204: /*
! 205: * Delete any whitespace around dot, then insert a space.
! 206: */
! 207: justone(f, n) {
! 208: (VOID) delwhite(f, n);
! 209: return linsert(1, ' ');
! 210: }
! 211: /*
! 212: * Delete any whitespace around dot.
! 213: */
! 214: /*ARGSUSED*/
! 215: delwhite(f, n)
! 216: {
! 217: register int col, c, s;
! 218:
! 219: col = curwp->w_doto;
! 220: while (((c = lgetc(curwp->w_dotp, col)) == ' ' || c == '\t')
! 221: && col < llength(curwp->w_dotp))
! 222: ++col;
! 223: do {
! 224: if (curwp->w_doto == 0) {
! 225: s = FALSE;
! 226: break;
! 227: }
! 228: if ((s = backchar(FFRAND, 1)) != TRUE) break;
! 229: } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' || c == '\t');
! 230:
! 231: if (s == TRUE) (VOID) forwchar(FFRAND, 1);
! 232: (VOID) ldelete((RSIZE)(col - curwp->w_doto), KNONE);
! 233: return TRUE;
! 234: }
! 235: /*
! 236: * Insert a newline, then enough
! 237: * tabs and spaces to duplicate the indentation
! 238: * of the previous line. Assumes tabs are every eight
! 239: * characters. Quite simple. Figure out the indentation
! 240: * of the current line. Insert a newline by calling
! 241: * the standard routine. Insert the indentation by
! 242: * inserting the right number of tabs and spaces.
! 243: * Return TRUE if all ok. Return FALSE if one
! 244: * of the subcomands failed. Normally bound
! 245: * to "C-J".
! 246: */
! 247: /*ARGSUSED*/
! 248: indent(f, n)
! 249: {
! 250: register int nicol;
! 251: register int c;
! 252: register int i;
! 253:
! 254: if (n < 0) return (FALSE);
! 255: while (n--) {
! 256: nicol = 0;
! 257: for (i=0; i<llength(curwp->w_dotp); ++i) {
! 258: c = lgetc(curwp->w_dotp, i);
! 259: if (c!=' ' && c!='\t')
! 260: break;
! 261: if (c == '\t')
! 262: nicol |= 0x07;
! 263: ++nicol;
! 264: }
! 265: if (lnewline() == FALSE || ((
! 266: #ifdef NOTAB
! 267: curbp->b_flag&BFNOTAB) ?
! 268: linsert(nicol, ' ') == FALSE : (
! 269: #endif
! 270: ((i=nicol/8)!=0 && linsert(i, '\t')==FALSE) ||
! 271: ((i=nicol%8)!=0 && linsert(i, ' ')==FALSE))))
! 272: return FALSE;
! 273: }
! 274: return TRUE;
! 275: }
! 276:
! 277: /*
! 278: * Delete forward. This is real
! 279: * easy, because the basic delete routine does
! 280: * all of the work. Watches for negative arguments,
! 281: * and does the right thing. If any argument is
! 282: * present, it kills rather than deletes, to prevent
! 283: * loss of text if typed with a big argument.
! 284: * Normally bound to "C-D".
! 285: */
! 286: /*ARGSUSED*/
! 287: forwdel(f, n)
! 288: {
! 289: if (n < 0)
! 290: return backdel(f | FFRAND, -n);
! 291: if (f & FFARG) { /* Really a kill. */
! 292: if ((lastflag&CFKILL) == 0)
! 293: kdelete();
! 294: thisflag |= CFKILL;
! 295: }
! 296: return ldelete((RSIZE) n, (f & FFARG) ? KFORW : KNONE);
! 297: }
! 298:
! 299: /*
! 300: * Delete backwards. This is quite easy too,
! 301: * because it's all done with other functions. Just
! 302: * move the cursor back, and delete forwards.
! 303: * Like delete forward, this actually does a kill
! 304: * if presented with an argument.
! 305: */
! 306: /*ARGSUSED*/
! 307: backdel(f, n)
! 308: {
! 309: register int s;
! 310:
! 311: if (n < 0)
! 312: return forwdel(f | FFRAND, -n);
! 313: if (f & FFARG) { /* Really a kill. */
! 314: if ((lastflag&CFKILL) == 0)
! 315: kdelete();
! 316: thisflag |= CFKILL;
! 317: }
! 318: if ((s=backchar(f | FFRAND, n)) == TRUE)
! 319: s = ldelete((RSIZE) n, (f & FFARG) ? KFORW : KNONE);
! 320: return s;
! 321: }
! 322:
! 323: /*
! 324: * Kill line. If called without an argument,
! 325: * it kills from dot to the end of the line, unless it
! 326: * is at the end of the line, when it kills the newline.
! 327: * If called with an argument of 0, it kills from the
! 328: * start of the line to dot. If called with a positive
! 329: * argument, it kills from dot forward over that number
! 330: * of newlines. If called with a negative argument it
! 331: * kills any text before dot on the current line,
! 332: * then it kills back abs(arg) lines.
! 333: */
! 334: /*ARGSUSED*/
! 335: killline(f, n) {
! 336: register RSIZE chunk;
! 337: register LINE *nextp;
! 338: register int i, c;
! 339: VOID kdelete();
! 340:
! 341: if ((lastflag&CFKILL) == 0) /* Clear kill buffer if */
! 342: kdelete(); /* last wasn't a kill. */
! 343: thisflag |= CFKILL;
! 344: if (!(f & FFARG)) {
! 345: for (i = curwp->w_doto; i < llength(curwp->w_dotp); ++i)
! 346: if ((c = lgetc(curwp->w_dotp, i)) != ' ' && c != '\t')
! 347: break;
! 348: if (i == llength(curwp->w_dotp))
! 349: chunk = llength(curwp->w_dotp)-curwp->w_doto + 1;
! 350: else {
! 351: chunk = llength(curwp->w_dotp)-curwp->w_doto;
! 352: if (chunk == 0)
! 353: chunk = 1;
! 354: }
! 355: } else if (n > 0) {
! 356: chunk = llength(curwp->w_dotp)-curwp->w_doto+1;
! 357: nextp = lforw(curwp->w_dotp);
! 358: i = n;
! 359: while (--i) {
! 360: if (nextp == curbp->b_linep)
! 361: break;
! 362: chunk += llength(nextp)+1;
! 363: nextp = lforw(nextp);
! 364: }
! 365: } else { /* n <= 0 */
! 366: chunk = curwp->w_doto;
! 367: curwp->w_doto = 0;
! 368: i = n;
! 369: while (i++) {
! 370: if (lback(curwp->w_dotp) == curbp->b_linep)
! 371: break;
! 372: curwp->w_dotp = lback(curwp->w_dotp);
! 373: curwp->w_flag |= WFMOVE;
! 374: chunk += llength(curwp->w_dotp)+1;
! 375: }
! 376: }
! 377: /*
! 378: * KFORW here is a bug. Should be KBACK/KFORW, but we need to
! 379: * rewrite the ldelete code (later)?
! 380: */
! 381: return (ldelete(chunk, KFORW));
! 382: }
! 383:
! 384: /*
! 385: * Yank text back from the kill buffer. This
! 386: * is really easy. All of the work is done by the
! 387: * standard insert routines. All you do is run the loop,
! 388: * and check for errors. The blank
! 389: * lines are inserted with a call to "newline"
! 390: * instead of a call to "lnewline" so that the magic
! 391: * stuff that happens when you type a carriage
! 392: * return also happens when a carriage return is
! 393: * yanked back from the kill buffer.
! 394: * An attempt has been made to fix the cosmetic bug
! 395: * associated with a yank when dot is on the top line of
! 396: * the window (nothing moves, because all of the new
! 397: * text landed off screen).
! 398: */
! 399: /*ARGSUSED*/
! 400: yank(f, n)
! 401: {
! 402: register int c;
! 403: register int i;
! 404: register LINE *lp;
! 405: register int nline;
! 406: VOID isetmark();
! 407:
! 408: if (n < 0) return FALSE;
! 409: nline = 0; /* Newline counting. */
! 410: while (n--) {
! 411: isetmark(); /* mark around last yank */
! 412: i = 0;
! 413: while ((c=kremove(i)) >= 0) {
! 414: if (c == '\n') {
! 415: if (newline(FFRAND, 1) == FALSE)
! 416: return FALSE;
! 417: ++nline;
! 418: } else {
! 419: if (linsert(1, c) == FALSE)
! 420: return FALSE;
! 421: }
! 422: ++i;
! 423: }
! 424: }
! 425: lp = curwp->w_linep; /* Cosmetic adjustment */
! 426: if (curwp->w_dotp == lp) { /* if offscreen insert. */
! 427: while (nline-- && lback(lp)!=curbp->b_linep)
! 428: lp = lback(lp);
! 429: curwp->w_linep = lp; /* Adjust framing. */
! 430: curwp->w_flag |= WFHARD;
! 431: }
! 432: return TRUE;
! 433: }
! 434:
! 435: #ifdef NOTAB
! 436: /*ARGSUSED*/
! 437: space_to_tabstop(f, n)
! 438: int f, n;
! 439: {
! 440: if(n<0) return FALSE;
! 441: if(n==0) return TRUE;
! 442: return linsert((n<<3) - (curwp->w_doto & 7), ' ');
! 443: }
! 444: #endif