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