Annotation of src/usr.bin/mg/util.c, Revision 1.24
1.24 ! kjell 1: /* $OpenBSD: random.c,v 1.23 2006/11/17 08:45:31 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.3 millert 239: int col, c, s;
1.1 deraadt 240:
241: col = curwp->w_doto;
1.3 millert 242:
1.8 vincent 243: while (col < llength(curwp->w_dotp) &&
244: ((c = lgetc(curwp->w_dotp, col)) == ' ' || c == '\t'))
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.1 deraadt 253: } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' || c == '\t');
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.3 millert 262: * Insert a newline, then enough tabs and spaces to duplicate the indentation
1.6 mickey 263: * of the previous line. Assumes tabs are every eight characters. Quite
264: * simple. Figure out the indentation of the current line. Insert a newline
265: * by calling the standard routine. Insert the indentation by inserting the
266: * right number of tabs and spaces. Return TRUE if all ok. Return FALSE if
1.24 ! kjell 267: * one of the subcommands failed. Normally bound to "C-M".
1.1 deraadt 268: */
1.2 millert 269: /* ARGSUSED */
1.3 millert 270: int
1.10 cloder 271: indent(int f, int n)
1.1 deraadt 272: {
1.11 db 273: int c, i, nicol;
1.1 deraadt 274:
1.2 millert 275: if (n < 0)
276: return (FALSE);
1.3 millert 277:
1.1 deraadt 278: while (n--) {
279: nicol = 0;
1.2 millert 280: for (i = 0; i < llength(curwp->w_dotp); ++i) {
1.1 deraadt 281: c = lgetc(curwp->w_dotp, i);
1.2 millert 282: if (c != ' ' && c != '\t')
1.1 deraadt 283: break;
284: if (c == '\t')
285: nicol |= 0x07;
286: ++nicol;
287: }
288: if (lnewline() == FALSE || ((
289: #ifdef NOTAB
1.3 millert 290: curbp->b_flag & BFNOTAB) ? linsert(nicol, ' ') == FALSE : (
291: #endif /* NOTAB */
292: ((i = nicol / 8) != 0 && linsert(i, '\t') == FALSE) ||
293: ((i = nicol % 8) != 0 && linsert(i, ' ') == FALSE))))
1.11 db 294: return (FALSE);
1.1 deraadt 295: }
1.11 db 296: return (TRUE);
1.1 deraadt 297: }
298:
299: /*
1.3 millert 300: * Delete forward. This is real easy, because the basic delete routine does
1.6 mickey 301: * all of the work. Watches for negative arguments, and does the right thing.
302: * If any argument is present, it kills rather than deletes, to prevent loss
1.3 millert 303: * of text if typed with a big argument. Normally bound to "C-D".
1.1 deraadt 304: */
1.2 millert 305: /* ARGSUSED */
1.3 millert 306: int
1.10 cloder 307: forwdel(int f, int n)
1.1 deraadt 308: {
309: if (n < 0)
1.11 db 310: return (backdel(f | FFRAND, -n));
1.3 millert 311:
312: /* really a kill */
313: if (f & FFARG) {
1.2 millert 314: if ((lastflag & CFKILL) == 0)
1.1 deraadt 315: kdelete();
316: thisflag |= CFKILL;
317: }
1.3 millert 318:
1.11 db 319: return (ldelete((RSIZE) n, (f & FFARG) ? KFORW : KNONE));
1.1 deraadt 320: }
321:
322: /*
1.6 mickey 323: * Delete backwards. This is quite easy too, because it's all done with
324: * other functions. Just move the cursor back, and delete forwards. Like
1.3 millert 325: * delete forward, this actually does a kill if presented with an argument.
1.1 deraadt 326: */
1.2 millert 327: /* ARGSUSED */
1.3 millert 328: int
1.10 cloder 329: backdel(int f, int n)
1.1 deraadt 330: {
1.3 millert 331: int s;
1.1 deraadt 332:
333: if (n < 0)
1.11 db 334: return (forwdel(f | FFRAND, -n));
1.3 millert 335:
336: /* really a kill */
337: if (f & FFARG) {
1.2 millert 338: if ((lastflag & CFKILL) == 0)
1.1 deraadt 339: kdelete();
340: thisflag |= CFKILL;
341: }
1.2 millert 342: if ((s = backchar(f | FFRAND, n)) == TRUE)
1.3 millert 343: s = ldelete((RSIZE)n, (f & FFARG) ? KFORW : KNONE);
344:
1.11 db 345: return (s);
1.1 deraadt 346: }
347:
348: #ifdef NOTAB
1.2 millert 349: /* ARGSUSED */
1.3 millert 350: int
1.10 cloder 351: space_to_tabstop(int f, int n)
1.1 deraadt 352: {
1.2 millert 353: if (n < 0)
1.11 db 354: return (FALSE);
1.2 millert 355: if (n == 0)
1.11 db 356: return (TRUE);
357: return (linsert((n << 3) - (curwp->w_doto & 7), ' '));
1.1 deraadt 358: }
1.3 millert 359: #endif /* NOTAB */