Annotation of src/usr.bin/mg/region.c, Revision 1.24
1.24 ! kjell 1: /* $OpenBSD: region.c,v 1.23 2006/07/08 17:50:30 kjell Exp $ */
1.17 kjell 2:
3: /* This file is in the public domain. */
1.4 niklas 4:
1.1 deraadt 5: /*
6: * Region based commands.
1.6 mickey 7: * The routines in this file deal with the region, that magic space between
1.3 millert 8: * "." and mark. Some functions are commands. Some functions are just for
1.1 deraadt 9: * internal use.
10: */
1.3 millert 11:
12: #include "def.h"
13:
1.19 deraadt 14: static int getregion(struct region *);
15: static int setsize(struct region *, RSIZE);
1.1 deraadt 16:
17: /*
1.3 millert 18: * Kill the region. Ask "getregion" to figure out the bounds of the region.
1.1 deraadt 19: * Move "." to the start, and kill the characters.
20: */
1.2 millert 21: /* ARGSUSED */
1.3 millert 22: int
1.12 cloder 23: killregion(int f, int n)
1.1 deraadt 24: {
1.3 millert 25: int s;
1.19 deraadt 26: struct region region;
1.1 deraadt 27:
1.2 millert 28: if ((s = getregion(®ion)) != TRUE)
1.1 deraadt 29: return (s);
1.3 millert 30: /* This is a kill-type command, so do magic kill buffer stuff. */
31: if ((lastflag & CFKILL) == 0)
32: kdelete();
33: thisflag |= CFKILL;
1.1 deraadt 34: curwp->w_dotp = region.r_linep;
35: curwp->w_doto = region.r_offset;
1.23 kjell 36: s = ldelete(region.r_size, KFORW);
37: if (s == TRUE && curwp->w_dotline > curwp->w_markline)
38: curwp->w_dotline = curwp->w_markline;
39: return (s);
1.1 deraadt 40: }
41:
42: /*
1.6 mickey 43: * Copy all of the characters in the region to the kill buffer. Don't move
1.3 millert 44: * dot at all. This is a bit like a kill region followed by a yank.
1.1 deraadt 45: */
1.2 millert 46: /* ARGSUSED */
1.3 millert 47: int
1.12 cloder 48: copyregion(int f, int n)
1.1 deraadt 49: {
1.19 deraadt 50: struct line *linep;
51: struct region region;
1.3 millert 52: int loffs;
53: int s;
1.1 deraadt 54:
1.2 millert 55: if ((s = getregion(®ion)) != TRUE)
1.15 db 56: return (s);
1.3 millert 57:
58: /* kill type command */
59: if ((lastflag & CFKILL) == 0)
1.1 deraadt 60: kdelete();
61: thisflag |= CFKILL;
1.3 millert 62:
63: /* current line */
64: linep = region.r_linep;
65:
66: /* current offset */
67: loffs = region.r_offset;
68:
1.1 deraadt 69: while (region.r_size--) {
1.2 millert 70: if (loffs == llength(linep)) { /* End of line. */
71: if ((s = kinsert('\n', KFORW)) != TRUE)
1.1 deraadt 72: return (s);
73: linep = lforw(linep);
74: loffs = 0;
1.3 millert 75: } else { /* Middle of line. */
1.2 millert 76: if ((s = kinsert(lgetc(linep, loffs), KFORW)) != TRUE)
1.15 db 77: return (s);
1.1 deraadt 78: ++loffs;
79: }
80: }
1.15 db 81: return (TRUE);
1.1 deraadt 82: }
83:
84: /*
1.6 mickey 85: * Lower case region. Zap all of the upper case characters in the region to
86: * lower case. Use the region code to set the limits. Scan the buffer, doing
87: * the changes. Call "lchange" to ensure that redisplay is done in all
1.3 millert 88: * buffers.
1.1 deraadt 89: */
1.2 millert 90: /* ARGSUSED */
1.3 millert 91: int
1.12 cloder 92: lowerregion(int f, int n)
1.1 deraadt 93: {
1.19 deraadt 94: struct line *linep;
95: struct region region;
1.3 millert 96: int loffs, c, s;
1.1 deraadt 97:
1.10 vincent 98: if (curbp->b_flag & BFREADONLY) {
99: ewprintf("Buffer is read-only");
100: return (FALSE);
101: }
102:
1.2 millert 103: if ((s = getregion(®ion)) != TRUE)
1.15 db 104: return (s);
1.9 vincent 105:
106: undo_add_change(region.r_linep, region.r_offset, region.r_size);
1.11 deraadt 107:
1.22 kjell 108: lchange(WFFULL);
1.1 deraadt 109: linep = region.r_linep;
110: loffs = region.r_offset;
111: while (region.r_size--) {
112: if (loffs == llength(linep)) {
113: linep = lforw(linep);
114: loffs = 0;
115: } else {
116: c = lgetc(linep, loffs);
117: if (ISUPPER(c) != FALSE)
118: lputc(linep, loffs, TOLOWER(c));
119: ++loffs;
120: }
121: }
1.15 db 122: return (TRUE);
1.1 deraadt 123: }
124:
125: /*
1.6 mickey 126: * Upper case region. Zap all of the lower case characters in the region to
1.3 millert 127: * upper case. Use the region code to set the limits. Scan the buffer,
1.6 mickey 128: * doing the changes. Call "lchange" to ensure that redisplay is done in all
1.3 millert 129: * buffers.
1.1 deraadt 130: */
1.2 millert 131: /* ARGSUSED */
1.3 millert 132: int
1.12 cloder 133: upperregion(int f, int n)
1.1 deraadt 134: {
1.19 deraadt 135: struct line *linep;
136: struct region region;
1.3 millert 137: int loffs, c, s;
1.1 deraadt 138:
1.10 vincent 139: if (curbp->b_flag & BFREADONLY) {
140: ewprintf("Buffer is read-only");
141: return (FALSE);
142: }
1.2 millert 143: if ((s = getregion(®ion)) != TRUE)
1.15 db 144: return (s);
1.11 deraadt 145:
1.9 vincent 146: undo_add_change(region.r_linep, region.r_offset, region.r_size);
1.11 deraadt 147:
1.22 kjell 148: lchange(WFFULL);
1.1 deraadt 149: linep = region.r_linep;
150: loffs = region.r_offset;
151: while (region.r_size--) {
152: if (loffs == llength(linep)) {
153: linep = lforw(linep);
154: loffs = 0;
155: } else {
156: c = lgetc(linep, loffs);
157: if (ISLOWER(c) != FALSE)
158: lputc(linep, loffs, TOUPPER(c));
159: ++loffs;
160: }
161: }
1.15 db 162: return (TRUE);
1.1 deraadt 163: }
164:
165: /*
1.6 mickey 166: * This routine figures out the bound of the region in the current window,
167: * and stores the results into the fields of the REGION structure. Dot and
168: * mark are usually close together, but I don't know the order, so I scan
169: * outward from dot, in both directions, looking for mark. The size is kept
170: * in a long. At the end, after the size is figured out, it is assigned to
171: * the size field of the region structure. If this assignment loses any bits,
172: * then we print an error. This is "type independent" overflow checking. All
173: * of the callers of this routine should be ready to get an ABORT status,
1.15 db 174: * because I might add a "if regions is big, ask before clobbering" flag.
1.1 deraadt 175: */
1.3 millert 176: static int
1.19 deraadt 177: getregion(struct region *rp)
1.2 millert 178: {
1.19 deraadt 179: struct line *flp, *blp;
1.3 millert 180: long fsize, bsize;
1.1 deraadt 181:
182: if (curwp->w_markp == NULL) {
183: ewprintf("No mark set in this window");
184: return (FALSE);
185: }
1.3 millert 186:
187: /* "r_size" always ok */
188: if (curwp->w_dotp == curwp->w_markp) {
1.1 deraadt 189: rp->r_linep = curwp->w_dotp;
190: if (curwp->w_doto < curwp->w_marko) {
191: rp->r_offset = curwp->w_doto;
1.3 millert 192: rp->r_size = (RSIZE)(curwp->w_marko - curwp->w_doto);
1.1 deraadt 193: } else {
194: rp->r_offset = curwp->w_marko;
1.3 millert 195: rp->r_size = (RSIZE)(curwp->w_doto - curwp->w_marko);
1.1 deraadt 196: }
1.15 db 197: return (TRUE);
1.1 deraadt 198: }
1.3 millert 199: /* get region size */
200: flp = blp = curwp->w_dotp;
1.1 deraadt 201: bsize = curwp->w_doto;
1.2 millert 202: fsize = llength(flp) - curwp->w_doto + 1;
1.24 ! kjell 203: while (lforw(flp) != curbp->b_headp || lback(blp) != curbp->b_headp) {
! 204: if (lforw(flp) != curbp->b_headp) {
1.1 deraadt 205: flp = lforw(flp);
206: if (flp == curwp->w_markp) {
207: rp->r_linep = curwp->w_dotp;
208: rp->r_offset = curwp->w_doto;
209: return (setsize(rp,
1.3 millert 210: (RSIZE)(fsize + curwp->w_marko)));
1.1 deraadt 211: }
1.2 millert 212: fsize += llength(flp) + 1;
1.1 deraadt 213: }
1.24 ! kjell 214: if (lback(blp) != curbp->b_headp) {
1.1 deraadt 215: blp = lback(blp);
1.2 millert 216: bsize += llength(blp) + 1;
1.1 deraadt 217: if (blp == curwp->w_markp) {
218: rp->r_linep = blp;
219: rp->r_offset = curwp->w_marko;
220: return (setsize(rp,
1.3 millert 221: (RSIZE)(bsize - curwp->w_marko)));
1.1 deraadt 222: }
223: }
224: }
1.3 millert 225: ewprintf("Bug: lost mark");
1.15 db 226: return (FALSE);
1.1 deraadt 227: }
228:
229: /*
230: * Set size, and check for overflow.
231: */
1.3 millert 232: static int
1.19 deraadt 233: setsize(struct region *rp, RSIZE size)
1.2 millert 234: {
1.1 deraadt 235: rp->r_size = size;
236: if (rp->r_size != size) {
237: ewprintf("Region is too large");
1.15 db 238: return (FALSE);
1.1 deraadt 239: }
1.15 db 240: return (TRUE);
1.1 deraadt 241: }
242:
1.3 millert 243: #ifdef PREFIXREGION
1.1 deraadt 244: /*
245: * Implements one of my favorite keyboard macros; put a string at the
246: * beginning of a number of lines in a buffer. The quote string is
247: * settable by using set-prefix-string. Great for quoting mail, which
248: * is the real reason I wrote it, but also has uses for creating bar
249: * comments (like the one you're reading) in C code.
250: */
251:
252: #define PREFIXLENGTH 40
1.3 millert 253: static char prefix_string[PREFIXLENGTH] = {'>', '\0'};
1.1 deraadt 254:
255: /*
1.6 mickey 256: * Prefix the region with whatever is in prefix_string. Leaves dot at the
257: * beginning of the line after the end of the region. If an argument is
1.3 millert 258: * given, prompts for the line prefix string.
1.1 deraadt 259: */
1.2 millert 260: /* ARGSUSED */
1.3 millert 261: int
1.12 cloder 262: prefixregion(int f, int n)
1.1 deraadt 263: {
1.19 deraadt 264: struct line *first, *last;
265: struct region region;
1.3 millert 266: char *prefix = prefix_string;
267: int nline;
268: int s;
1.1 deraadt 269:
1.10 vincent 270: if (curbp->b_flag & BFREADONLY) {
271: ewprintf("Buffer is read-only");
272: return (FALSE);
273: }
1.1 deraadt 274: if ((f == TRUE) && ((s = setprefix(FFRAND, 1)) != TRUE))
1.15 db 275: return (s);
1.1 deraadt 276:
277: /* get # of lines to affect */
278: if ((s = getregion(®ion)) != TRUE)
279: return (s);
280: first = region.r_linep;
281: last = (first == curwp->w_dotp) ? curwp->w_markp : curwp->w_dotp;
282: for (nline = 1; first != last; nline++)
283: first = lforw(first);
284:
1.2 millert 285: /* move to beginning of region */
1.1 deraadt 286: curwp->w_dotp = region.r_linep;
287: curwp->w_doto = region.r_offset;
288:
289: /* for each line, go to beginning and insert the prefix string */
290: while (nline--) {
1.5 art 291: (void)gotobol(FFRAND, 1);
1.1 deraadt 292: for (prefix = prefix_string; *prefix; prefix++)
1.5 art 293: (void)linsert(1, *prefix);
294: (void)forwline(FFRAND, 1);
1.1 deraadt 295: }
1.5 art 296: (void)gotobol(FFRAND, 1);
1.15 db 297: return (TRUE);
1.1 deraadt 298: }
299:
300: /*
1.3 millert 301: * Set line prefix string.
1.1 deraadt 302: */
1.2 millert 303: /* ARGSUSED */
1.3 millert 304: int
1.12 cloder 305: setprefix(int f, int n)
1.1 deraadt 306: {
1.14 vincent 307: char buf[PREFIXLENGTH], *rep;
1.15 db 308: int retval;
1.1 deraadt 309:
310: if (prefix_string[0] == '\0')
1.18 kjell 311: rep = eread("Prefix string: ", buf, sizeof(buf),
312: EFNEW | EFCR);
1.1 deraadt 313: else
1.18 kjell 314: rep = eread("Prefix string (default %s): ", buf, sizeof(buf),
315: EFNUL | EFNEW | EFCR, prefix_string);
316: if (rep == NULL)
317: return (ABORT);
318: if (rep[0] != '\0') {
1.15 db 319: (void)strlcpy(prefix_string, rep, sizeof(prefix_string));
1.14 vincent 320: retval = TRUE;
1.18 kjell 321: } else if (rep[0] == '\0' && prefix_string[0] != '\0') {
1.14 vincent 322: /* CR -- use old one */
323: retval = TRUE;
324: } else
325: retval = FALSE;
1.15 db 326: return (retval);
1.1 deraadt 327: }
1.3 millert 328: #endif /* PREFIXREGION */
1.9 vincent 329:
330: int
1.19 deraadt 331: region_get_data(struct region *reg, char *buf, int len)
1.9 vincent 332: {
1.15 db 333: int i, off;
1.19 deraadt 334: struct line *lp;
1.11 deraadt 335:
1.9 vincent 336: off = reg->r_offset;
337: lp = reg->r_linep;
1.13 vincent 338: for (i = 0; i < len; i++) {
1.9 vincent 339: if (off == llength(lp)) {
340: lp = lforw(lp);
1.24 ! kjell 341: if (lp == curbp->b_headp)
1.9 vincent 342: break;
343: off = 0;
344: buf[i] = '\n';
345: } else {
346: buf[i] = lgetc(lp, off);
347: off++;
348: }
349: }
1.13 vincent 350: buf[i] = '\0';
1.15 db 351: return (i);
1.9 vincent 352: }
353:
1.20 kjell 354: void
1.9 vincent 355: region_put_data(const char *buf, int len)
356: {
357: int i;
358:
1.21 kjell 359: for (i = 0; buf[i] != '\0' && i < len; i++) {
1.9 vincent 360: if (buf[i] == '\n')
361: lnewline();
362: else
363: linsert(1, buf[i]);
364: }
365: }