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