Annotation of src/usr.bin/mg/util.c, Revision 1.27
1.27 ! kjell 1: /* $OpenBSD: random.c,v 1.26 2008/09/15 16:13:35 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.26 kjell 122: undo_boundary_enable(FFRAND, 0);
1.2 millert 123: if (doto == llength(dotp)) {
124: if (--doto <= 0)
1.11 db 125: return (FALSE);
1.19 kjell 126: (void)backchar(FFRAND, 1);
1.18 kjell 127: fudge = TRUE;
1.1 deraadt 128: } else {
1.2 millert 129: if (doto == 0)
1.11 db 130: return (FALSE);
1.1 deraadt 131: }
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 */
161: i = n;
1.1 deraadt 162: do {
163: s = lnewline();
1.2 millert 164: } while (s == TRUE && --i);
1.3 millert 165:
166: /* then go back up overtop of them all */
167: if (s == TRUE)
168: s = backchar(f | FFRAND, n);
1.11 db 169: return (s);
1.1 deraadt 170: }
171:
172: /*
1.14 kjell 173: * Insert a newline.
1.1 deraadt 174: */
1.2 millert 175: /* ARGSUSED */
1.3 millert 176: int
1.10 cloder 177: newline(int f, int n)
1.1 deraadt 178: {
1.3 millert 179: int s;
1.1 deraadt 180:
1.2 millert 181: if (n < 0)
1.11 db 182: return (FALSE);
1.3 millert 183:
1.1 deraadt 184: while (n--) {
1.2 millert 185: if ((s = lnewline()) != TRUE)
1.11 db 186: return (s);
1.1 deraadt 187: }
1.11 db 188: return (TRUE);
1.1 deraadt 189: }
190:
191: /*
1.3 millert 192: * Delete blank lines around dot. What this command does depends if dot is
1.6 mickey 193: * sitting on a blank line. If dot is sitting on a blank line, this command
194: * deletes all the blank lines above and below the current line. If it is
195: * sitting on a non blank line then it deletes all of the blank lines after
196: * the line. Normally this command is bound to "C-X C-O". Any argument is
1.3 millert 197: * ignored.
1.1 deraadt 198: */
1.2 millert 199: /* ARGSUSED */
1.3 millert 200: int
1.10 cloder 201: deblank(int f, int n)
1.1 deraadt 202: {
1.15 deraadt 203: struct line *lp1, *lp2;
1.3 millert 204: RSIZE nld;
1.1 deraadt 205:
206: lp1 = curwp->w_dotp;
1.21 kjell 207: while (llength(lp1) == 0 && (lp2 = lback(lp1)) != curbp->b_headp)
1.1 deraadt 208: lp1 = lp2;
209: lp2 = lp1;
1.3 millert 210: nld = (RSIZE)0;
1.21 kjell 211: while ((lp2 = lforw(lp2)) != curbp->b_headp && llength(lp2) == 0)
1.1 deraadt 212: ++nld;
213: if (nld == 0)
214: return (TRUE);
215: curwp->w_dotp = lforw(lp1);
216: curwp->w_doto = 0;
1.11 db 217: return (ldelete((RSIZE)nld, KNONE));
1.1 deraadt 218: }
219:
220: /*
221: * Delete any whitespace around dot, then insert a space.
222: */
1.3 millert 223: int
1.10 cloder 224: justone(int f, int n)
1.2 millert 225: {
1.5 art 226: (void)delwhite(f, n);
1.11 db 227: return (linsert(1, ' '));
1.1 deraadt 228: }
1.3 millert 229:
1.1 deraadt 230: /*
231: * Delete any whitespace around dot.
232: */
1.2 millert 233: /* ARGSUSED */
1.3 millert 234: int
1.10 cloder 235: delwhite(int f, int n)
1.1 deraadt 236: {
1.25 kjell 237: int col, s;
1.1 deraadt 238:
239: col = curwp->w_doto;
1.3 millert 240:
1.8 vincent 241: while (col < llength(curwp->w_dotp) &&
1.25 kjell 242: (isspace(lgetc(curwp->w_dotp, col))))
1.1 deraadt 243: ++col;
244: do {
245: if (curwp->w_doto == 0) {
246: s = FALSE;
247: break;
248: }
1.2 millert 249: if ((s = backchar(FFRAND, 1)) != TRUE)
250: break;
1.25 kjell 251: } while (isspace(lgetc(curwp->w_dotp, curwp->w_doto)));
1.1 deraadt 252:
1.2 millert 253: if (s == TRUE)
1.5 art 254: (void)forwchar(FFRAND, 1);
255: (void)ldelete((RSIZE)(col - curwp->w_doto), KNONE);
1.11 db 256: return (TRUE);
1.1 deraadt 257: }
1.3 millert 258:
1.1 deraadt 259: /*
1.25 kjell 260: * Delete any leading whitespace on the current line
261: */
262: int
263: delleadwhite(int f, int n)
264: {
265: int soff, ls;
266: struct line *slp;
267:
268: /* Save current position */
269: slp = curwp->w_dotp;
270: soff = curwp->w_doto;
271:
272: for (ls = 0; ls < llength(slp); ls++)
273: if (!isspace(lgetc(slp, ls)))
274: break;
275: gotobol(FFRAND, 1);
276: forwdel(FFRAND, ls);
277: soff -= ls;
278: if (soff < 0)
279: soff = 0;
280: forwchar(FFRAND, soff);
281:
282: return (TRUE);
283: }
284:
285: /*
286: * Delete any trailing whitespace on the current line
287: */
288: int
289: deltrailwhite(int f, int n)
290: {
291: int soff;
292:
293: /* Save current position */
294: soff = curwp->w_doto;
295:
296: gotoeol(FFRAND, 1);
297: delwhite(FFRAND, 1);
298:
299: /* restore original position, if possible */
300: if (soff < curwp->w_doto)
301: curwp->w_doto = soff;
302:
303: return (TRUE);
304: }
305:
306:
307:
308: /*
1.3 millert 309: * Insert a newline, then enough tabs and spaces to duplicate the indentation
1.6 mickey 310: * of the previous line. Assumes tabs are every eight characters. Quite
311: * simple. Figure out the indentation of the current line. Insert a newline
312: * by calling the standard routine. Insert the indentation by inserting the
313: * right number of tabs and spaces. Return TRUE if all ok. Return FALSE if
1.24 kjell 314: * one of the subcommands failed. Normally bound to "C-M".
1.1 deraadt 315: */
1.2 millert 316: /* ARGSUSED */
1.3 millert 317: int
1.25 kjell 318: lfindent(int f, int n)
1.1 deraadt 319: {
1.11 db 320: int c, i, nicol;
1.1 deraadt 321:
1.2 millert 322: if (n < 0)
323: return (FALSE);
1.3 millert 324:
1.1 deraadt 325: while (n--) {
326: nicol = 0;
1.2 millert 327: for (i = 0; i < llength(curwp->w_dotp); ++i) {
1.1 deraadt 328: c = lgetc(curwp->w_dotp, i);
1.2 millert 329: if (c != ' ' && c != '\t')
1.1 deraadt 330: break;
331: if (c == '\t')
332: nicol |= 0x07;
333: ++nicol;
334: }
335: if (lnewline() == FALSE || ((
336: #ifdef NOTAB
1.3 millert 337: curbp->b_flag & BFNOTAB) ? linsert(nicol, ' ') == FALSE : (
338: #endif /* NOTAB */
339: ((i = nicol / 8) != 0 && linsert(i, '\t') == FALSE) ||
340: ((i = nicol % 8) != 0 && linsert(i, ' ') == FALSE))))
1.11 db 341: return (FALSE);
1.1 deraadt 342: }
1.11 db 343: return (TRUE);
1.1 deraadt 344: }
1.25 kjell 345:
346: /*
347: * Indent the current line. Delete existing leading whitespace,
348: * and use tabs/spaces to achieve correct indentation. Try
349: * to leave dot where it started.
350: */
351: int
352: indent(int f, int n)
353: {
354: int soff, i;
355:
356: if (n < 0)
357: return (FALSE);
358:
359: delleadwhite(FFRAND, 1);
360:
361: /* If not invoked with a numerical argument, done */
362: if (!(f & FFARG))
363: return (TRUE);
364:
365: /* insert appropriate whitespace */
366: soff = curwp->w_doto;
367: (void)gotobol(FFRAND, 1);
368: if (
369: #ifdef NOTAB
370: curbp->b_flag & BFNOTAB) ? linsert(n, ' ') == FALSE :
371: #endif /* NOTAB */
372: (((i = n / 8) != 0 && linsert(i, '\t') == FALSE) ||
373: ((i = n % 8) != 0 && linsert(i, ' ') == FALSE)))
374: return (FALSE);
375:
376: forwchar(FFRAND, soff);
377:
378: return (TRUE);
379: }
380:
1.1 deraadt 381:
382: /*
1.3 millert 383: * Delete forward. This is real easy, because the basic delete routine does
1.6 mickey 384: * all of the work. Watches for negative arguments, and does the right thing.
385: * If any argument is present, it kills rather than deletes, to prevent loss
1.3 millert 386: * of text if typed with a big argument. Normally bound to "C-D".
1.1 deraadt 387: */
1.2 millert 388: /* ARGSUSED */
1.3 millert 389: int
1.10 cloder 390: forwdel(int f, int n)
1.1 deraadt 391: {
392: if (n < 0)
1.11 db 393: return (backdel(f | FFRAND, -n));
1.3 millert 394:
395: /* really a kill */
396: if (f & FFARG) {
1.2 millert 397: if ((lastflag & CFKILL) == 0)
1.1 deraadt 398: kdelete();
399: thisflag |= CFKILL;
400: }
1.3 millert 401:
1.11 db 402: return (ldelete((RSIZE) n, (f & FFARG) ? KFORW : KNONE));
1.1 deraadt 403: }
404:
405: /*
1.6 mickey 406: * Delete backwards. This is quite easy too, because it's all done with
407: * other functions. Just move the cursor back, and delete forwards. Like
1.3 millert 408: * delete forward, this actually does a kill if presented with an argument.
1.1 deraadt 409: */
1.2 millert 410: /* ARGSUSED */
1.3 millert 411: int
1.10 cloder 412: backdel(int f, int n)
1.1 deraadt 413: {
1.3 millert 414: int s;
1.1 deraadt 415:
416: if (n < 0)
1.11 db 417: return (forwdel(f | FFRAND, -n));
1.3 millert 418:
419: /* really a kill */
420: if (f & FFARG) {
1.2 millert 421: if ((lastflag & CFKILL) == 0)
1.1 deraadt 422: kdelete();
423: thisflag |= CFKILL;
424: }
1.2 millert 425: if ((s = backchar(f | FFRAND, n)) == TRUE)
1.3 millert 426: s = ldelete((RSIZE)n, (f & FFARG) ? KFORW : KNONE);
427:
1.11 db 428: return (s);
1.1 deraadt 429: }
430:
431: #ifdef NOTAB
1.2 millert 432: /* ARGSUSED */
1.3 millert 433: int
1.10 cloder 434: space_to_tabstop(int f, int n)
1.1 deraadt 435: {
1.2 millert 436: if (n < 0)
1.11 db 437: return (FALSE);
1.2 millert 438: if (n == 0)
1.11 db 439: return (TRUE);
440: return (linsert((n << 3) - (curwp->w_doto & 7), ' '));
1.1 deraadt 441: }
1.3 millert 442: #endif /* NOTAB */
1.27 ! kjell 443:
! 444: /*
! 445: * Move the dot to the first non-whitespace character of the current line.
! 446: */
! 447: int
! 448: backtoindent(int f, int n)
! 449: {
! 450: gotobol(FFRAND, 1);
! 451: while (curwp->w_doto < llength(curwp->w_dotp) &&
! 452: (isspace(lgetc(curwp->w_dotp, curwp->w_doto))))
! 453: ++curwp->w_doto;
! 454: return (TRUE);
! 455: }