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

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

1.21    ! guenther    1: /*     $OpenBSD: word.c,v 1.20 2022/12/26 19:16:02 jmc Exp $   */
1.10      kjell       2:
                      3: /* This file is in the public domain. */
1.4       niklas      4:
1.1       deraadt     5: /*
                      6:  *             Word mode commands.
1.5       mickey      7:  * The routines in this file implement commands that work word at a time.
1.3       millert     8:  * There are all sorts of word mode commands.
                      9:  */
1.17      bcallah    10:
                     11: #include <sys/queue.h>
                     12: #include <signal.h>
1.18      lum        13: #include <errno.h>
1.17      bcallah    14: #include <stdio.h>
1.18      lum        15: #include <stdlib.h>
                     16: #include <string.h>
1.3       millert    17:
                     18: #include "def.h"
1.1       deraadt    19:
1.11      kjell      20: RSIZE  countfword(void);
1.18      lum        21: int    grabword(char **);
1.11      kjell      22:
1.1       deraadt    23: /*
1.5       mickey     24:  * Move the cursor backward by "n" words. All of the details of motion are
1.3       millert    25:  * performed by the "backchar" and "forwchar" routines.
1.1       deraadt    26:  */
1.3       millert    27: int
1.8       cloder     28: backword(int f, int n)
1.1       deraadt    29: {
1.2       millert    30:        if (n < 0)
1.9       db         31:                return (forwword(f | FFRAND, -n));
1.1       deraadt    32:        if (backchar(FFRAND, 1) == FALSE)
1.9       db         33:                return (FALSE);
1.1       deraadt    34:        while (n--) {
                     35:                while (inword() == FALSE) {
                     36:                        if (backchar(FFRAND, 1) == FALSE)
1.9       db         37:                                return (TRUE);
1.1       deraadt    38:                }
                     39:                while (inword() != FALSE) {
                     40:                        if (backchar(FFRAND, 1) == FALSE)
1.9       db         41:                                return (TRUE);
1.1       deraadt    42:                }
                     43:        }
1.9       db         44:        return (forwchar(FFRAND, 1));
1.1       deraadt    45: }
                     46:
                     47: /*
1.3       millert    48:  * Move the cursor forward by the specified number of words.  All of the
1.1       deraadt    49:  * motion is done by "forwchar".
                     50:  */
1.3       millert    51: int
1.8       cloder     52: forwword(int f, int n)
1.1       deraadt    53: {
                     54:        if (n < 0)
1.9       db         55:                return (backword(f | FFRAND, -n));
1.1       deraadt    56:        while (n--) {
                     57:                while (inword() == FALSE) {
                     58:                        if (forwchar(FFRAND, 1) == FALSE)
1.9       db         59:                                return (TRUE);
1.1       deraadt    60:                }
                     61:                while (inword() != FALSE) {
                     62:                        if (forwchar(FFRAND, 1) == FALSE)
1.9       db         63:                                return (TRUE);
1.1       deraadt    64:                }
                     65:        }
1.18      lum        66:        return (TRUE);
                     67: }
                     68:
                     69: /*
                     70:  * Transpose 2 words.
1.20      jmc        71:  * The function below is artificially restricted to only a maximum of 1 iteration
1.18      lum        72:  * at the moment because the 'undo' functionality within mg needs amended for
                     73:  * multiple movements of point, backwards and forwards.
                     74:  */
                     75: int
                     76: transposeword(int f, int n)
                     77: {
                     78:        struct line     *tmp1_w_dotp = NULL;
                     79:        struct line     *tmp2_w_dotp = NULL;
                     80:        int              tmp2_w_doto = 0;
                     81:        int              tmp1_w_dotline = 0;
                     82:        int              tmp2_w_dotline = 0;
                     83:        int              tmp1_w_doto;
                     84:        int              i;             /* start-of-line space counter */
                     85:        int              ret, s;
                     86:        int              newline;
                     87:        int              leave = 0;
                     88:        int              tmp_len;
                     89:        char            *word1 = NULL;
                     90:        char            *word2 = NULL;
                     91:        char            *chr;
                     92:
                     93:        if (n == 0)
                     94:                return (TRUE);
                     95:
                     96:        n = 1; /* remove this line to allow muliple-iterations */
                     97:
                     98:        if ((s = checkdirty(curbp)) != TRUE)
                     99:                return (s);
                    100:        if (curbp->b_flag & BFREADONLY) {
                    101:                dobeep();
                    102:                ewprintf("Buffer is read-only");
                    103:                return (FALSE);
                    104:        }
                    105:        undo_boundary_enable(FFRAND, 0);
                    106:
                    107:        /* go backwards to find the start of a word to transpose. */
                    108:        (void)backword(FFRAND, 1);
                    109:        ret = grabword(&word1);
                    110:        if (ret == ABORT) {
                    111:                ewprintf("No word to the left to tranpose.");
                    112:                return (FALSE);
                    113:        }
                    114:        if (ret < 0) {
                    115:                dobeep();
                    116:                ewprintf("Error copying word: %s", strerror(ret));
                    117:                free(word1);
                    118:                return (FALSE);
                    119:        }
                    120:
                    121:        while (n-- > 0) {
                    122:                i = 0;
                    123:                newline = 0;
                    124:
                    125:                tmp1_w_doto = curwp->w_doto;
                    126:                tmp1_w_dotline = curwp->w_dotline;
                    127:                tmp1_w_dotp = curwp->w_dotp;
                    128:
                    129:                /* go forward and find next word. */
                    130:                while (inword() == FALSE) {
                    131:                        if (forwchar(FFRAND, 1) == FALSE) {
                    132:                                leave = 1;
                    133:                                if (tmp1_w_dotline < curwp->w_dotline)
                    134:                                        curwp->w_dotline--;
                    135:                                ewprintf("Don't have two things to transpose");
                    136:                                break;
                    137:                        }
                    138:                        if (curwp->w_doto == 0) {
                    139:                                newline = 1;
                    140:                                i = 0;
                    141:                        } else if (newline)
                    142:                                i++;
                    143:                }
                    144:                if (leave) {
                    145:                        tmp2_w_doto = tmp1_w_doto;
                    146:                        tmp2_w_dotline = tmp1_w_dotline;
                    147:                        tmp2_w_dotp = tmp1_w_dotp;
                    148:                        break;
                    149:                }
                    150:                tmp2_w_doto = curwp->w_doto;
                    151:                tmp2_w_dotline = curwp->w_dotline;
                    152:                tmp2_w_dotp = curwp->w_dotp;
                    153:
                    154:                ret = grabword(&word2);
1.19      lum       155:                if (ret < 0 || ret == ABORT) {
1.18      lum       156:                        dobeep();
                    157:                        ewprintf("Error copying word: %s", strerror(ret));
                    158:                        free(word1);
                    159:                        return (FALSE);
                    160:                }
                    161:                tmp_len = strlen(word2);
                    162:                tmp2_w_doto += tmp_len;
                    163:
                    164:                curwp->w_doto = tmp1_w_doto;
                    165:                curwp->w_dotline = tmp1_w_dotline;
                    166:                curwp->w_dotp = tmp1_w_dotp;
                    167:
                    168:                /* insert shuffled along word */
                    169:                for (chr = word2; *chr != '\0'; ++chr)
                    170:                        linsert(1, *chr);
                    171:
                    172:                if (newline)
                    173:                        tmp2_w_doto = i;
                    174:
                    175:                curwp->w_doto = tmp2_w_doto;
                    176:                curwp->w_dotline = tmp2_w_dotline;
                    177:                curwp->w_dotp = tmp2_w_dotp;
                    178:
                    179:                word2 = NULL;
                    180:        }
                    181:        curwp->w_doto = tmp2_w_doto;
                    182:        curwp->w_dotline = tmp2_w_dotline;
                    183:        curwp->w_dotp = tmp2_w_dotp;
                    184:
                    185:        /* insert very first word in its new position */
                    186:        for (chr = word1; *chr != '\0'; ++chr)
                    187:                linsert(1, *chr);
                    188:
                    189:        if (leave)
                    190:                (void)backword(FFRAND, 1);
                    191:
                    192:        free(word1);
                    193:        free(word2);
                    194:
                    195:        undo_boundary_enable(FFRAND, 1);
                    196:
                    197:        return (TRUE);
                    198: }
                    199:
                    200: /*
                    201:  * copy and delete word.
                    202: */
                    203: int
                    204: grabword(char **word)
                    205: {
                    206:        int c;
                    207:
                    208:        while (inword() == TRUE) {
                    209:                c = lgetc(curwp->w_dotp, curwp->w_doto);
                    210:                if (*word == NULL) {
                    211:                        if (asprintf(word, "%c", c) == -1)
                    212:                                return (errno);
                    213:                } else {
                    214:                        if (asprintf(word, "%s%c", *word, c) == -1)
                    215:                                return (errno);
                    216:                }
                    217:                (void)forwdel(FFRAND, 1);
                    218:        }
                    219:        if (*word == NULL)
                    220:                return (ABORT);
1.9       db        221:        return (TRUE);
1.1       deraadt   222: }
                    223:
                    224: /*
1.3       millert   225:  * Move the cursor forward by the specified number of words.  As you move,
1.1       deraadt   226:  * convert any characters to upper case.
                    227:  */
1.3       millert   228: int
1.8       cloder    229: upperword(int f, int n)
1.1       deraadt   230: {
1.15      kjell     231:        int     c, s;
1.11      kjell     232:        RSIZE   size;
1.1       deraadt   233:
1.15      kjell     234:        if ((s = checkdirty(curbp)) != TRUE)
                    235:                return (s);
1.7       vincent   236:        if (curbp->b_flag & BFREADONLY) {
1.16      lum       237:                dobeep();
1.7       vincent   238:                ewprintf("Buffer is read-only");
                    239:                return (FALSE);
                    240:        }
                    241:
1.2       millert   242:        if (n < 0)
1.9       db        243:                return (FALSE);
1.1       deraadt   244:        while (n--) {
                    245:                while (inword() == FALSE) {
                    246:                        if (forwchar(FFRAND, 1) == FALSE)
1.9       db        247:                                return (TRUE);
1.1       deraadt   248:                }
1.11      kjell     249:                size = countfword();
                    250:                undo_add_change(curwp->w_dotp, curwp->w_doto, size);
1.12      deraadt   251:
1.1       deraadt   252:                while (inword() != FALSE) {
                    253:                        c = lgetc(curwp->w_dotp, curwp->w_doto);
                    254:                        if (ISLOWER(c) != FALSE) {
                    255:                                c = TOUPPER(c);
                    256:                                lputc(curwp->w_dotp, curwp->w_doto, c);
1.14      kjell     257:                                lchange(WFFULL);
1.1       deraadt   258:                        }
                    259:                        if (forwchar(FFRAND, 1) == FALSE)
1.9       db        260:                                return (TRUE);
1.1       deraadt   261:                }
                    262:        }
1.9       db        263:        return (TRUE);
1.1       deraadt   264: }
                    265:
                    266: /*
1.3       millert   267:  * Move the cursor forward by the specified number of words.  As you move
1.1       deraadt   268:  * convert characters to lower case.
                    269:  */
1.3       millert   270: int
1.8       cloder    271: lowerword(int f, int n)
1.1       deraadt   272: {
1.15      kjell     273:        int     c, s;
1.11      kjell     274:        RSIZE   size;
1.1       deraadt   275:
1.15      kjell     276:        if ((s = checkdirty(curbp)) != TRUE)
                    277:                return (s);
1.7       vincent   278:        if (curbp->b_flag & BFREADONLY) {
1.16      lum       279:                dobeep();
1.7       vincent   280:                ewprintf("Buffer is read-only");
                    281:                return (FALSE);
                    282:        }
1.2       millert   283:        if (n < 0)
1.9       db        284:                return (FALSE);
1.1       deraadt   285:        while (n--) {
                    286:                while (inword() == FALSE) {
                    287:                        if (forwchar(FFRAND, 1) == FALSE)
1.9       db        288:                                return (TRUE);
1.1       deraadt   289:                }
1.11      kjell     290:                size = countfword();
                    291:                undo_add_change(curwp->w_dotp, curwp->w_doto, size);
                    292:
1.1       deraadt   293:                while (inword() != FALSE) {
                    294:                        c = lgetc(curwp->w_dotp, curwp->w_doto);
                    295:                        if (ISUPPER(c) != FALSE) {
                    296:                                c = TOLOWER(c);
                    297:                                lputc(curwp->w_dotp, curwp->w_doto, c);
1.14      kjell     298:                                lchange(WFFULL);
1.1       deraadt   299:                        }
                    300:                        if (forwchar(FFRAND, 1) == FALSE)
1.9       db        301:                                return (TRUE);
1.1       deraadt   302:                }
                    303:        }
1.9       db        304:        return (TRUE);
1.1       deraadt   305: }
                    306:
                    307: /*
1.3       millert   308:  * Move the cursor forward by the specified number of words.  As you move
1.5       mickey    309:  * convert the first character of the word to upper case, and subsequent
                    310:  * characters to lower case.  Error if you try to move past the end of the
1.3       millert   311:  * buffer.
1.1       deraadt   312:  */
1.3       millert   313: int
1.8       cloder    314: capword(int f, int n)
1.1       deraadt   315: {
1.15      kjell     316:        int     c, s;
1.11      kjell     317:        RSIZE   size;
1.1       deraadt   318:
1.15      kjell     319:        if ((s = checkdirty(curbp)) != TRUE)
                    320:                return (s);
1.7       vincent   321:        if (curbp->b_flag & BFREADONLY) {
1.16      lum       322:                dobeep();
1.7       vincent   323:                ewprintf("Buffer is read-only");
                    324:                return (FALSE);
                    325:        }
                    326:
1.2       millert   327:        if (n < 0)
1.9       db        328:                return (FALSE);
1.1       deraadt   329:        while (n--) {
                    330:                while (inword() == FALSE) {
                    331:                        if (forwchar(FFRAND, 1) == FALSE)
1.9       db        332:                                return (TRUE);
1.1       deraadt   333:                }
1.11      kjell     334:                size = countfword();
                    335:                undo_add_change(curwp->w_dotp, curwp->w_doto, size);
                    336:
1.1       deraadt   337:                if (inword() != FALSE) {
                    338:                        c = lgetc(curwp->w_dotp, curwp->w_doto);
                    339:                        if (ISLOWER(c) != FALSE) {
                    340:                                c = TOUPPER(c);
                    341:                                lputc(curwp->w_dotp, curwp->w_doto, c);
1.14      kjell     342:                                lchange(WFFULL);
1.1       deraadt   343:                        }
                    344:                        if (forwchar(FFRAND, 1) == FALSE)
1.9       db        345:                                return (TRUE);
1.1       deraadt   346:                        while (inword() != FALSE) {
                    347:                                c = lgetc(curwp->w_dotp, curwp->w_doto);
                    348:                                if (ISUPPER(c) != FALSE) {
                    349:                                        c = TOLOWER(c);
                    350:                                        lputc(curwp->w_dotp, curwp->w_doto, c);
1.14      kjell     351:                                        lchange(WFFULL);
1.1       deraadt   352:                                }
                    353:                                if (forwchar(FFRAND, 1) == FALSE)
1.9       db        354:                                        return (TRUE);
1.1       deraadt   355:                        }
                    356:                }
                    357:        }
1.9       db        358:        return (TRUE);
1.1       deraadt   359: }
1.11      kjell     360:
                    361: /*
                    362:  * Count characters in word, from current position
                    363:  */
                    364: RSIZE
                    365: countfword()
                    366: {
1.13      deraadt   367:        RSIZE            size;
                    368:        struct line     *dotp;
                    369:        int              doto;
1.11      kjell     370:
                    371:        dotp = curwp->w_dotp;
                    372:        doto = curwp->w_doto;
                    373:        size = 0;
                    374:
                    375:        while (inword() != FALSE) {
                    376:                if (forwchar(FFRAND, 1) == FALSE)
                    377:                        /* hit the end of the buffer */
                    378:                        goto out;
                    379:                ++size;
                    380:        }
                    381: out:
                    382:        curwp->w_dotp = dotp;
                    383:        curwp->w_doto = doto;
                    384:        return (size);
                    385: }
                    386:
1.1       deraadt   387:
                    388: /*
                    389:  * Kill forward by "n" words.
                    390:  */
1.3       millert   391: int
1.8       cloder    392: delfword(int f, int n)
1.1       deraadt   393: {
1.13      deraadt   394:        RSIZE            size;
                    395:        struct line     *dotp;
                    396:        int              doto;
1.15      kjell     397:        int s;
1.1       deraadt   398:
1.15      kjell     399:        if ((s = checkdirty(curbp)) != TRUE)
                    400:                return (s);
1.7       vincent   401:        if (curbp->b_flag & BFREADONLY) {
1.16      lum       402:                dobeep();
1.7       vincent   403:                ewprintf("Buffer is read-only");
                    404:                return (FALSE);
                    405:        }
1.1       deraadt   406:        if (n < 0)
1.9       db        407:                return (FALSE);
1.3       millert   408:
                    409:        /* purge kill buffer */
                    410:        if ((lastflag & CFKILL) == 0)
1.1       deraadt   411:                kdelete();
1.3       millert   412:
1.1       deraadt   413:        thisflag |= CFKILL;
                    414:        dotp = curwp->w_dotp;
                    415:        doto = curwp->w_doto;
                    416:        size = 0;
1.3       millert   417:
1.1       deraadt   418:        while (n--) {
                    419:                while (inword() == FALSE) {
                    420:                        if (forwchar(FFRAND, 1) == FALSE)
1.3       millert   421:                                /* hit the end of the buffer */
                    422:                                goto out;
1.1       deraadt   423:                        ++size;
                    424:                }
                    425:                while (inword() != FALSE) {
                    426:                        if (forwchar(FFRAND, 1) == FALSE)
1.3       millert   427:                                /* hit the end of the buffer */
                    428:                                goto out;
1.1       deraadt   429:                        ++size;
                    430:                }
                    431:        }
                    432: out:
                    433:        curwp->w_dotp = dotp;
                    434:        curwp->w_doto = doto;
                    435:        return (ldelete(size, KFORW));
                    436: }
                    437:
                    438: /*
1.5       mickey    439:  * Kill backwards by "n" words.  The rules for success and failure are now
                    440:  * different, to prevent strange behavior at the start of the buffer.  The
                    441:  * command only fails if something goes wrong with the actual delete of the
                    442:  * characters.  It is successful even if no characters are deleted, or if you
                    443:  * say delete 5 words, and there are only 4 words left.  I considered making
                    444:  * the first call to "backchar" special, but decided that that would just be
1.3       millert   445:  * weird. Normally this is bound to "M-Rubout" and to "M-Backspace".
1.1       deraadt   446:  */
1.3       millert   447: int
1.8       cloder    448: delbword(int f, int n)
1.1       deraadt   449: {
1.3       millert   450:        RSIZE   size;
1.15      kjell     451:        int s;
1.7       vincent   452:
1.15      kjell     453:        if ((s = checkdirty(curbp)) != TRUE)
                    454:                return (s);
1.7       vincent   455:        if (curbp->b_flag & BFREADONLY) {
1.16      lum       456:                dobeep();
1.7       vincent   457:                ewprintf("Buffer is read-only");
                    458:                return (FALSE);
                    459:        }
1.1       deraadt   460:
1.2       millert   461:        if (n < 0)
1.9       db        462:                return (FALSE);
1.3       millert   463:
                    464:        /* purge kill buffer */
                    465:        if ((lastflag & CFKILL) == 0)
1.1       deraadt   466:                kdelete();
                    467:        thisflag |= CFKILL;
                    468:        if (backchar(FFRAND, 1) == FALSE)
1.3       millert   469:                /* hit buffer start */
                    470:                return (TRUE);
                    471:
                    472:        /* one deleted */
                    473:        size = 1;
1.1       deraadt   474:        while (n--) {
                    475:                while (inword() == FALSE) {
                    476:                        if (backchar(FFRAND, 1) == FALSE)
1.3       millert   477:                                /* hit buffer start */
                    478:                                goto out;
1.1       deraadt   479:                        ++size;
                    480:                }
                    481:                while (inword() != FALSE) {
                    482:                        if (backchar(FFRAND, 1) == FALSE)
1.3       millert   483:                                /* hit buffer start */
                    484:                                goto out;
1.1       deraadt   485:                        ++size;
                    486:                }
                    487:        }
                    488:        if (forwchar(FFRAND, 1) == FALSE)
1.9       db        489:                return (FALSE);
1.3       millert   490:
                    491:        /* undo assumed delete */
                    492:        --size;
1.1       deraadt   493: out:
1.9       db        494:        return (ldelete(size, KBACK));
1.1       deraadt   495: }
                    496:
                    497: /*
1.3       millert   498:  * Return TRUE if the character at dot is a character that is considered to be
1.9       db        499:  * part of a word. The word character list is hard coded. Should be settable.
1.1       deraadt   500:  */
1.3       millert   501: int
1.8       cloder    502: inword(void)
1.2       millert   503: {
                    504:        /* can't use lgetc in ISWORD due to bug in OSK cpp */
1.9       db        505:        return (curwp->w_doto != llength(curwp->w_dotp) &&
                    506:            ISWORD(curwp->w_dotp->l_text[curwp->w_doto]));
1.1       deraadt   507: }