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