Annotation of src/usr.bin/mg/util.c, Revision 1.18
1.18 ! kjell 1: /* $OpenBSD: random.c,v 1.17 2005/11/22 05:02:44 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 */
34: clp = lforw(curbp->b_linep);
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.2 millert 55: if (clp == curbp->b_linep)
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.2 millert 63: while (clp != curbp->b_linep && 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;
78:
79: /* determine column */
1.9 vincent 80: col = 0;
1.1 deraadt 81:
1.2 millert 82: for (i = 0; i < curwp->w_doto; ++i) {
1.1 deraadt 83: c = lgetc(curwp->w_dotp, i);
84: if (c == '\t'
1.3 millert 85: #ifdef NOTAB
1.2 millert 86: && !(curbp->b_flag & BFNOTAB)
1.3 millert 87: #endif /* NOTAB */
1.1 deraadt 88: ) {
1.2 millert 89: col |= 0x07;
1.9 vincent 90: col++;
1.1 deraadt 91: } else if (ISCTRL(c) != FALSE)
1.9 vincent 92: col += 2;
93: else if (isprint(c))
94: col++;
95: else {
96: char tmp[5];
1.11 db 97: snprintf(tmp, sizeof(tmp), "\\%o", c);
1.9 vincent 98: col += strlen(tmp);
99: }
100:
1.1 deraadt 101: }
1.11 db 102: return (col);
1.1 deraadt 103: }
1.3 millert 104:
1.1 deraadt 105: /*
1.6 mickey 106: * Twiddle the two characters on either side of dot. If dot is at the end
107: * of the line twiddle the two characters before it. Return with an error
108: * if dot is at the beginning of line; it seems to be a bit pointless to
109: * make this work. This fixes up a very common typo with a single stroke.
110: * Normally bound to "C-T". This always works within a line, so "WFEDIT"
1.3 millert 111: * is good enough.
1.1 deraadt 112: */
1.2 millert 113: /* ARGSUSED */
1.3 millert 114: int
1.10 cloder 115: twiddle(int f, int n)
1.1 deraadt 116: {
1.15 deraadt 117: struct line *dotp;
1.3 millert 118: int doto, cr;
1.18 ! kjell 119: int fudge = FALSE;
1.1 deraadt 120:
121: dotp = curwp->w_dotp;
122: doto = curwp->w_doto;
1.18 ! kjell 123: undo_add_boundary();
! 124: undo_no_boundary(TRUE);
1.2 millert 125: if (doto == llength(dotp)) {
126: if (--doto <= 0)
1.11 db 127: return (FALSE);
1.18 ! kjell 128: backchar(f, 1);
! 129: fudge = TRUE;
1.1 deraadt 130: } else {
1.2 millert 131: if (doto == 0)
1.11 db 132: return (FALSE);
1.1 deraadt 133: }
1.18 ! kjell 134: cr = lgetc(dotp, doto - 1);
! 135: backdel(f, 1);
! 136: forwchar(f, 1);
! 137: linsert(1, cr);
! 138: if (fudge != TRUE)
! 139: backchar(f, 1);
! 140: undo_no_boundary(FALSE);
! 141: undo_add_boundary();
1.1 deraadt 142: lchange(WFEDIT);
1.11 db 143: return (TRUE);
1.1 deraadt 144: }
145:
146: /*
1.6 mickey 147: * Open up some blank space. The basic plan is to insert a bunch of
148: * newlines, and then back up over them. Everything is done by the
1.11 db 149: * subcommand processors. They even handle the looping. Normally this
1.3 millert 150: * is bound to "C-O".
1.1 deraadt 151: */
1.2 millert 152: /* ARGSUSED */
1.3 millert 153: int
1.10 cloder 154: openline(int f, int n)
1.1 deraadt 155: {
1.11 db 156: int i, s;
1.1 deraadt 157:
158: if (n < 0)
1.11 db 159: return (FALSE);
1.1 deraadt 160: if (n == 0)
1.11 db 161: return (TRUE);
1.3 millert 162:
163: /* insert newlines */
164: i = n;
1.1 deraadt 165: do {
166: s = lnewline();
1.2 millert 167: } while (s == TRUE && --i);
1.3 millert 168:
169: /* then go back up overtop of them all */
170: if (s == TRUE)
171: s = backchar(f | FFRAND, n);
1.11 db 172: return (s);
1.1 deraadt 173: }
174:
175: /*
1.14 kjell 176: * Insert a newline.
1.1 deraadt 177: */
1.2 millert 178: /* ARGSUSED */
1.3 millert 179: int
1.10 cloder 180: newline(int f, int n)
1.1 deraadt 181: {
1.3 millert 182: int s;
1.1 deraadt 183:
1.2 millert 184: if (n < 0)
1.11 db 185: return (FALSE);
1.3 millert 186:
1.1 deraadt 187: while (n--) {
1.2 millert 188: if ((s = lnewline()) != TRUE)
1.11 db 189: return (s);
1.1 deraadt 190: }
1.11 db 191: return (TRUE);
1.1 deraadt 192: }
193:
194: /*
1.3 millert 195: * Delete blank lines around dot. What this command does depends if dot is
1.6 mickey 196: * sitting on a blank line. If dot is sitting on a blank line, this command
197: * deletes all the blank lines above and below the current line. If it is
198: * sitting on a non blank line then it deletes all of the blank lines after
199: * the line. Normally this command is bound to "C-X C-O". Any argument is
1.3 millert 200: * ignored.
1.1 deraadt 201: */
1.2 millert 202: /* ARGSUSED */
1.3 millert 203: int
1.10 cloder 204: deblank(int f, int n)
1.1 deraadt 205: {
1.15 deraadt 206: struct line *lp1, *lp2;
1.3 millert 207: RSIZE nld;
1.1 deraadt 208:
209: lp1 = curwp->w_dotp;
1.2 millert 210: while (llength(lp1) == 0 && (lp2 = lback(lp1)) != curbp->b_linep)
1.1 deraadt 211: lp1 = lp2;
212: lp2 = lp1;
1.3 millert 213: nld = (RSIZE)0;
1.2 millert 214: while ((lp2 = lforw(lp2)) != curbp->b_linep && llength(lp2) == 0)
1.1 deraadt 215: ++nld;
216: if (nld == 0)
217: return (TRUE);
218: curwp->w_dotp = lforw(lp1);
219: curwp->w_doto = 0;
1.11 db 220: return (ldelete((RSIZE)nld, KNONE));
1.1 deraadt 221: }
222:
223: /*
224: * Delete any whitespace around dot, then insert a space.
225: */
1.3 millert 226: int
1.10 cloder 227: justone(int f, int n)
1.2 millert 228: {
1.5 art 229: (void)delwhite(f, n);
1.11 db 230: return (linsert(1, ' '));
1.1 deraadt 231: }
1.3 millert 232:
1.1 deraadt 233: /*
234: * Delete any whitespace around dot.
235: */
1.2 millert 236: /* ARGSUSED */
1.3 millert 237: int
1.10 cloder 238: delwhite(int f, int n)
1.1 deraadt 239: {
1.3 millert 240: int col, c, s;
1.1 deraadt 241:
242: col = curwp->w_doto;
1.3 millert 243:
1.8 vincent 244: while (col < llength(curwp->w_dotp) &&
245: ((c = lgetc(curwp->w_dotp, col)) == ' ' || c == '\t'))
1.1 deraadt 246: ++col;
247: do {
248: if (curwp->w_doto == 0) {
249: s = FALSE;
250: break;
251: }
1.2 millert 252: if ((s = backchar(FFRAND, 1)) != TRUE)
253: break;
1.1 deraadt 254: } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' || c == '\t');
255:
1.2 millert 256: if (s == TRUE)
1.5 art 257: (void)forwchar(FFRAND, 1);
258: (void)ldelete((RSIZE)(col - curwp->w_doto), KNONE);
1.11 db 259: return (TRUE);
1.1 deraadt 260: }
1.3 millert 261:
1.1 deraadt 262: /*
1.3 millert 263: * Insert a newline, then enough tabs and spaces to duplicate the indentation
1.6 mickey 264: * of the previous line. Assumes tabs are every eight characters. Quite
265: * simple. Figure out the indentation of the current line. Insert a newline
266: * by calling the standard routine. Insert the indentation by inserting the
267: * right number of tabs and spaces. Return TRUE if all ok. Return FALSE if
1.11 db 268: * one of the subcommands failed. Normally bound to "C-J".
1.1 deraadt 269: */
1.2 millert 270: /* ARGSUSED */
1.3 millert 271: int
1.10 cloder 272: indent(int f, int n)
1.1 deraadt 273: {
1.11 db 274: int c, i, nicol;
1.1 deraadt 275:
1.2 millert 276: if (n < 0)
277: return (FALSE);
1.3 millert 278:
1.1 deraadt 279: while (n--) {
280: nicol = 0;
1.2 millert 281: for (i = 0; i < llength(curwp->w_dotp); ++i) {
1.1 deraadt 282: c = lgetc(curwp->w_dotp, i);
1.2 millert 283: if (c != ' ' && c != '\t')
1.1 deraadt 284: break;
285: if (c == '\t')
286: nicol |= 0x07;
287: ++nicol;
288: }
289: if (lnewline() == FALSE || ((
290: #ifdef NOTAB
1.3 millert 291: curbp->b_flag & BFNOTAB) ? linsert(nicol, ' ') == FALSE : (
292: #endif /* NOTAB */
293: ((i = nicol / 8) != 0 && linsert(i, '\t') == FALSE) ||
294: ((i = nicol % 8) != 0 && linsert(i, ' ') == FALSE))))
1.11 db 295: return (FALSE);
1.1 deraadt 296: }
1.11 db 297: return (TRUE);
1.1 deraadt 298: }
299:
300: /*
1.3 millert 301: * Delete forward. This is real easy, because the basic delete routine does
1.6 mickey 302: * all of the work. Watches for negative arguments, and does the right thing.
303: * If any argument is present, it kills rather than deletes, to prevent loss
1.3 millert 304: * of text if typed with a big argument. Normally bound to "C-D".
1.1 deraadt 305: */
1.2 millert 306: /* ARGSUSED */
1.3 millert 307: int
1.10 cloder 308: forwdel(int f, int n)
1.1 deraadt 309: {
310: if (n < 0)
1.11 db 311: return (backdel(f | FFRAND, -n));
1.3 millert 312:
313: /* really a kill */
314: if (f & FFARG) {
1.2 millert 315: if ((lastflag & CFKILL) == 0)
1.1 deraadt 316: kdelete();
317: thisflag |= CFKILL;
318: }
1.3 millert 319:
1.11 db 320: return (ldelete((RSIZE) n, (f & FFARG) ? KFORW : KNONE));
1.1 deraadt 321: }
322:
323: /*
1.6 mickey 324: * Delete backwards. This is quite easy too, because it's all done with
325: * other functions. Just move the cursor back, and delete forwards. Like
1.3 millert 326: * delete forward, this actually does a kill if presented with an argument.
1.1 deraadt 327: */
1.2 millert 328: /* ARGSUSED */
1.3 millert 329: int
1.10 cloder 330: backdel(int f, int n)
1.1 deraadt 331: {
1.3 millert 332: int s;
1.1 deraadt 333:
334: if (n < 0)
1.11 db 335: return (forwdel(f | FFRAND, -n));
1.3 millert 336:
337: /* really a kill */
338: if (f & FFARG) {
1.2 millert 339: if ((lastflag & CFKILL) == 0)
1.1 deraadt 340: kdelete();
341: thisflag |= CFKILL;
342: }
1.2 millert 343: if ((s = backchar(f | FFRAND, n)) == TRUE)
1.3 millert 344: s = ldelete((RSIZE)n, (f & FFARG) ? KFORW : KNONE);
345:
1.11 db 346: return (s);
1.1 deraadt 347: }
348:
349: #ifdef NOTAB
1.2 millert 350: /* ARGSUSED */
1.3 millert 351: int
1.10 cloder 352: space_to_tabstop(int f, int n)
1.1 deraadt 353: {
1.2 millert 354: if (n < 0)
1.11 db 355: return (FALSE);
1.2 millert 356: if (n == 0)
1.11 db 357: return (TRUE);
358: return (linsert((n << 3) - (curwp->w_doto & 7), ' '));
1.1 deraadt 359: }
1.3 millert 360: #endif /* NOTAB */