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: }