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