Annotation of src/usr.bin/mg/random.c, Revision 1.25
1.25 ! kjell 1: /* $OpenBSD: random.c,v 1.24 2007/02/08 21:40:38 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.18 kjell 122: undo_add_boundary();
1.23 kjell 123: undo_boundary_enable(FALSE);
1.2 millert 124: if (doto == llength(dotp)) {
125: if (--doto <= 0)
1.11 db 126: return (FALSE);
1.19 kjell 127: (void)backchar(FFRAND, 1);
1.18 kjell 128: fudge = TRUE;
1.1 deraadt 129: } else {
1.2 millert 130: if (doto == 0)
1.11 db 131: return (FALSE);
1.1 deraadt 132: }
1.18 kjell 133: cr = lgetc(dotp, doto - 1);
1.19 kjell 134: (void)backdel(FFRAND, 1);
135: (void)forwchar(FFRAND, 1);
1.18 kjell 136: linsert(1, cr);
137: if (fudge != TRUE)
1.19 kjell 138: (void)backchar(FFRAND, 1);
1.23 kjell 139: undo_boundary_enable(TRUE);
1.18 kjell 140: undo_add_boundary();
1.1 deraadt 141: lchange(WFEDIT);
1.11 db 142: return (TRUE);
1.1 deraadt 143: }
144:
145: /*
1.6 mickey 146: * Open up some blank space. The basic plan is to insert a bunch of
147: * newlines, and then back up over them. Everything is done by the
1.11 db 148: * subcommand processors. They even handle the looping. Normally this
1.3 millert 149: * is bound to "C-O".
1.1 deraadt 150: */
1.2 millert 151: /* ARGSUSED */
1.3 millert 152: int
1.10 cloder 153: openline(int f, int n)
1.1 deraadt 154: {
1.11 db 155: int i, s;
1.1 deraadt 156:
157: if (n < 0)
1.11 db 158: return (FALSE);
1.1 deraadt 159: if (n == 0)
1.11 db 160: return (TRUE);
1.3 millert 161:
162: /* insert newlines */
163: i = n;
1.1 deraadt 164: do {
165: s = lnewline();
1.2 millert 166: } while (s == TRUE && --i);
1.3 millert 167:
168: /* then go back up overtop of them all */
169: if (s == TRUE)
170: s = backchar(f | FFRAND, n);
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.5 art 228: (void)delwhite(f, n);
1.11 db 229: return (linsert(1, ' '));
1.1 deraadt 230: }
1.3 millert 231:
1.1 deraadt 232: /*
233: * Delete any whitespace around dot.
234: */
1.2 millert 235: /* ARGSUSED */
1.3 millert 236: int
1.10 cloder 237: delwhite(int f, int n)
1.1 deraadt 238: {
1.25 ! kjell 239: int col, s;
1.1 deraadt 240:
241: col = curwp->w_doto;
1.3 millert 242:
1.8 vincent 243: while (col < llength(curwp->w_dotp) &&
1.25 ! kjell 244: (isspace(lgetc(curwp->w_dotp, col))))
1.1 deraadt 245: ++col;
246: do {
247: if (curwp->w_doto == 0) {
248: s = FALSE;
249: break;
250: }
1.2 millert 251: if ((s = backchar(FFRAND, 1)) != TRUE)
252: break;
1.25 ! kjell 253: } while (isspace(lgetc(curwp->w_dotp, curwp->w_doto)));
1.1 deraadt 254:
1.2 millert 255: if (s == TRUE)
1.5 art 256: (void)forwchar(FFRAND, 1);
257: (void)ldelete((RSIZE)(col - curwp->w_doto), KNONE);
1.11 db 258: return (TRUE);
1.1 deraadt 259: }
1.3 millert 260:
1.1 deraadt 261: /*
1.25 ! kjell 262: * Delete any leading whitespace on the current line
! 263: */
! 264: int
! 265: delleadwhite(int f, int n)
! 266: {
! 267: int soff, ls;
! 268: struct line *slp;
! 269:
! 270: /* Save current position */
! 271: slp = curwp->w_dotp;
! 272: soff = curwp->w_doto;
! 273:
! 274: for (ls = 0; ls < llength(slp); ls++)
! 275: if (!isspace(lgetc(slp, ls)))
! 276: break;
! 277: gotobol(FFRAND, 1);
! 278: forwdel(FFRAND, ls);
! 279: soff -= ls;
! 280: if (soff < 0)
! 281: soff = 0;
! 282: forwchar(FFRAND, soff);
! 283:
! 284: return (TRUE);
! 285: }
! 286:
! 287: /*
! 288: * Delete any trailing whitespace on the current line
! 289: */
! 290: int
! 291: deltrailwhite(int f, int n)
! 292: {
! 293: int soff;
! 294:
! 295: /* Save current position */
! 296: soff = curwp->w_doto;
! 297:
! 298: gotoeol(FFRAND, 1);
! 299: delwhite(FFRAND, 1);
! 300:
! 301: /* restore original position, if possible */
! 302: if (soff < curwp->w_doto)
! 303: curwp->w_doto = soff;
! 304:
! 305: return (TRUE);
! 306: }
! 307:
! 308:
! 309:
! 310: /*
1.3 millert 311: * Insert a newline, then enough tabs and spaces to duplicate the indentation
1.6 mickey 312: * of the previous line. Assumes tabs are every eight characters. Quite
313: * simple. Figure out the indentation of the current line. Insert a newline
314: * by calling the standard routine. Insert the indentation by inserting the
315: * right number of tabs and spaces. Return TRUE if all ok. Return FALSE if
1.24 kjell 316: * one of the subcommands failed. Normally bound to "C-M".
1.1 deraadt 317: */
1.2 millert 318: /* ARGSUSED */
1.3 millert 319: int
1.25 ! kjell 320: lfindent(int f, int n)
1.1 deraadt 321: {
1.11 db 322: int c, i, nicol;
1.1 deraadt 323:
1.2 millert 324: if (n < 0)
325: return (FALSE);
1.3 millert 326:
1.1 deraadt 327: while (n--) {
328: nicol = 0;
1.2 millert 329: for (i = 0; i < llength(curwp->w_dotp); ++i) {
1.1 deraadt 330: c = lgetc(curwp->w_dotp, i);
1.2 millert 331: if (c != ' ' && c != '\t')
1.1 deraadt 332: break;
333: if (c == '\t')
334: nicol |= 0x07;
335: ++nicol;
336: }
337: if (lnewline() == FALSE || ((
338: #ifdef NOTAB
1.3 millert 339: curbp->b_flag & BFNOTAB) ? linsert(nicol, ' ') == FALSE : (
340: #endif /* NOTAB */
341: ((i = nicol / 8) != 0 && linsert(i, '\t') == FALSE) ||
342: ((i = nicol % 8) != 0 && linsert(i, ' ') == FALSE))))
1.11 db 343: return (FALSE);
1.1 deraadt 344: }
1.11 db 345: return (TRUE);
1.1 deraadt 346: }
1.25 ! kjell 347:
! 348: /*
! 349: * Indent the current line. Delete existing leading whitespace,
! 350: * and use tabs/spaces to achieve correct indentation. Try
! 351: * to leave dot where it started.
! 352: */
! 353: int
! 354: indent(int f, int n)
! 355: {
! 356: int soff, i;
! 357:
! 358: if (n < 0)
! 359: return (FALSE);
! 360:
! 361: delleadwhite(FFRAND, 1);
! 362:
! 363: /* If not invoked with a numerical argument, done */
! 364: if (!(f & FFARG))
! 365: return (TRUE);
! 366:
! 367: /* insert appropriate whitespace */
! 368: soff = curwp->w_doto;
! 369: (void)gotobol(FFRAND, 1);
! 370: if (
! 371: #ifdef NOTAB
! 372: curbp->b_flag & BFNOTAB) ? linsert(n, ' ') == FALSE :
! 373: #endif /* NOTAB */
! 374: (((i = n / 8) != 0 && linsert(i, '\t') == FALSE) ||
! 375: ((i = n % 8) != 0 && linsert(i, ' ') == FALSE)))
! 376: return (FALSE);
! 377:
! 378: forwchar(FFRAND, soff);
! 379:
! 380: return (TRUE);
! 381: }
! 382:
1.1 deraadt 383:
384: /*
1.3 millert 385: * Delete forward. This is real easy, because the basic delete routine does
1.6 mickey 386: * all of the work. Watches for negative arguments, and does the right thing.
387: * If any argument is present, it kills rather than deletes, to prevent loss
1.3 millert 388: * of text if typed with a big argument. Normally bound to "C-D".
1.1 deraadt 389: */
1.2 millert 390: /* ARGSUSED */
1.3 millert 391: int
1.10 cloder 392: forwdel(int f, int n)
1.1 deraadt 393: {
394: if (n < 0)
1.11 db 395: return (backdel(f | FFRAND, -n));
1.3 millert 396:
397: /* really a kill */
398: if (f & FFARG) {
1.2 millert 399: if ((lastflag & CFKILL) == 0)
1.1 deraadt 400: kdelete();
401: thisflag |= CFKILL;
402: }
1.3 millert 403:
1.11 db 404: return (ldelete((RSIZE) n, (f & FFARG) ? KFORW : KNONE));
1.1 deraadt 405: }
406:
407: /*
1.6 mickey 408: * Delete backwards. This is quite easy too, because it's all done with
409: * other functions. Just move the cursor back, and delete forwards. Like
1.3 millert 410: * delete forward, this actually does a kill if presented with an argument.
1.1 deraadt 411: */
1.2 millert 412: /* ARGSUSED */
1.3 millert 413: int
1.10 cloder 414: backdel(int f, int n)
1.1 deraadt 415: {
1.3 millert 416: int s;
1.1 deraadt 417:
418: if (n < 0)
1.11 db 419: return (forwdel(f | FFRAND, -n));
1.3 millert 420:
421: /* really a kill */
422: if (f & FFARG) {
1.2 millert 423: if ((lastflag & CFKILL) == 0)
1.1 deraadt 424: kdelete();
425: thisflag |= CFKILL;
426: }
1.2 millert 427: if ((s = backchar(f | FFRAND, n)) == TRUE)
1.3 millert 428: s = ldelete((RSIZE)n, (f & FFARG) ? KFORW : KNONE);
429:
1.11 db 430: return (s);
1.1 deraadt 431: }
432:
433: #ifdef NOTAB
1.2 millert 434: /* ARGSUSED */
1.3 millert 435: int
1.10 cloder 436: space_to_tabstop(int f, int n)
1.1 deraadt 437: {
1.2 millert 438: if (n < 0)
1.11 db 439: return (FALSE);
1.2 millert 440: if (n == 0)
1.11 db 441: return (TRUE);
442: return (linsert((n << 3) - (curwp->w_doto & 7), ' '));
1.1 deraadt 443: }
1.3 millert 444: #endif /* NOTAB */