[BACK]Return to region.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

Annotation of src/usr.bin/mg/region.c, Revision 1.21

1.21    ! kjell       1: /*     $OpenBSD: region.c,v 1.20 2005/12/13 05:23:03 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(&region)) != 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.19      deraadt    47:        struct line     *linep;
                     48:        struct region    region;
1.3       millert    49:        int      loffs;
                     50:        int      s;
1.1       deraadt    51:
1.2       millert    52:        if ((s = getregion(&region)) != 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.19      deraadt    91:        struct line     *linep;
                     92:        struct region    region;
1.3       millert    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(&region)) != 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.19      deraadt   132:        struct line      *linep;
                    133:        struct region     region;
1.3       millert   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(&region)) != 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.19      deraadt   174: getregion(struct region *rp)
1.2       millert   175: {
1.19      deraadt   176:        struct line     *flp, *blp;
1.3       millert   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.19      deraadt   230: setsize(struct 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.19      deraadt   261:        struct line     *first, *last;
                    262:        struct region    region;
1.3       millert   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(&region)) != 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
1.19      deraadt   328: region_get_data(struct region *reg, char *buf, int len)
1.9       vincent   329: {
1.15      db        330:        int      i, off;
1.19      deraadt   331:        struct 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:
1.20      kjell     351: void
1.9       vincent   352: region_put_data(const char *buf, int len)
                    353: {
                    354:        int i;
                    355:
1.21    ! kjell     356:        for (i = 0; buf[i] != '\0' && i < len; i++) {
1.9       vincent   357:                if (buf[i] == '\n')
                    358:                        lnewline();
                    359:                else
                    360:                        linsert(1, buf[i]);
                    361:        }
                    362: }