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