1/*
2 * zle_word.c - word-related editor functions
3 *
4 * This file is part of zsh, the Z shell.
5 *
6 * Copyright (c) 1992-1997 Paul Falstad
7 * All rights reserved.
8 *
9 * Permission is hereby granted, without written agreement and without
10 * license or royalty fees, to use, copy, modify, and distribute this
11 * software and to distribute modified versions of this software for any
12 * purpose, provided that the above copyright notice and the following
13 * two paragraphs appear in all copies of this software.
14 *
15 * In no event shall Paul Falstad or the Zsh Development Group be liable
16 * to any party for direct, indirect, special, incidental, or consequential
17 * damages arising out of the use of this software and its documentation,
18 * even if Paul Falstad and the Zsh Development Group have been advised of
19 * the possibility of such damage.
20 *
21 * Paul Falstad and the Zsh Development Group specifically disclaim any
22 * warranties, including, but not limited to, the implied warranties of
23 * merchantability and fitness for a particular purpose.  The software
24 * provided hereunder is on an "as is" basis, and Paul Falstad and the
25 * Zsh Development Group have no obligation to provide maintenance,
26 * support, updates, enhancements, or modifications.
27 *
28 */
29
30#include "zle.mdh"
31#include "zle_word.pro"
32
33/*
34 * In principle we shouldn't consider a zero-length punctuation
35 * character (i.e. a modifier of some sort) part of the word unless
36 * the base character has.  However, we only consider them part of
37 * a word if we so consider all alphanumerics, so the distinction
38 * only applies if the characters are modifying something they probably
39 * ought not to be modifying.  It's not really clear we need to
40 * be clever about this not very useful case.
41 */
42
43/**/
44int
45forwardword(char **args)
46{
47    int n = zmult;
48
49    if (n < 0) {
50	int ret;
51	zmult = -n;
52	ret = backwardword(args);
53	zmult = n;
54	return ret;
55    }
56    while (n--) {
57	while (zlecs != zlell && ZC_iword(zleline[zlecs]))
58	    INCCS();
59	if (wordflag && !n)
60	    return 0;
61	while (zlecs != zlell && !ZC_iword(zleline[zlecs]))
62	    INCCS();
63    }
64    return 0;
65}
66
67#define Z_vialnum(X) (ZC_ialnum(X) || (ZWC('_') == X))
68
69/**/
70int
71viforwardword(char **args)
72{
73    int n = zmult;
74
75    if (n < 0) {
76	int ret;
77	zmult = -n;
78	ret = backwardword(args);
79	zmult = n;
80	return ret;
81    }
82    while (n--) {
83	if (Z_vialnum(zleline[zlecs]))
84	    while (zlecs != zlell && Z_vialnum(zleline[zlecs]))
85		INCCS();
86	else
87	    while (zlecs != zlell && !Z_vialnum(zleline[zlecs]) && !ZC_iblank(zleline[zlecs]))
88		INCCS();
89	if (wordflag && !n)
90	    return 0;
91	while (zlecs != zlell && ZC_inblank(zleline[zlecs]))
92	    INCCS();
93    }
94    return 0;
95}
96
97/**/
98int
99viforwardblankword(char **args)
100{
101    int n = zmult;
102
103    if (n < 0) {
104	int ret;
105	zmult = -n;
106	ret = vibackwardblankword(args);
107	zmult = n;
108	return ret;
109    }
110    while (n--) {
111	while (zlecs != zlell && !ZC_iblank(zleline[zlecs]))
112	    INCCS();
113	if (wordflag && !n)
114	    return 0;
115	while (zlecs != zlell && ZC_iblank(zleline[zlecs]))
116	    INCCS();
117    }
118    return 0;
119}
120
121/**/
122int
123emacsforwardword(char **args)
124{
125    int n = zmult;
126
127    if (n < 0) {
128	int ret;
129	zmult = -n;
130	ret = emacsbackwardword(args);
131	zmult = n;
132	return ret;
133    }
134    while (n--) {
135	while (zlecs != zlell && !ZC_iword(zleline[zlecs]))
136	    INCCS();
137	if (wordflag && !n)
138	    return 0;
139	while (zlecs != zlell && ZC_iword(zleline[zlecs]))
140	    INCCS();
141    }
142    return 0;
143}
144
145/**/
146int
147viforwardblankwordend(UNUSED(char **args))
148{
149    int n = zmult;
150
151    if (n < 0)
152	return 1;
153    while (n--) {
154	while (zlecs != zlell) {
155	    int pos = zlecs;
156	    INCPOS(pos);
157	    if (!ZC_iblank(zleline[pos]))
158		break;
159	    zlecs = pos;
160	}
161	while (zlecs != zlell) {
162	    int pos = zlecs;
163	    INCPOS(pos);
164	    if (ZC_iblank(zleline[pos]))
165		break;
166	    zlecs = pos;
167	}
168    }
169    if (zlecs != zlell && virangeflag)
170	INCCS();
171    return 0;
172}
173
174/**/
175int
176viforwardwordend(char **args)
177{
178    int n = zmult;
179
180    if (n < 0) {
181	int ret;
182	zmult = -n;
183	ret = backwardword(args);
184	zmult = n;
185	return ret;
186    }
187    while (n--) {
188	int pos;
189	while (zlecs != zlell) {
190	    pos = zlecs;
191	    INCPOS(pos);
192	    if (!ZC_inblank(zleline[pos]))
193		break;
194	    zlecs = pos;
195	}
196	if (zlecs != zlell) {
197	    pos = zlecs;
198	    INCPOS(pos);
199	    if (Z_vialnum(zleline[pos])) {
200		for (;;) {
201		    zlecs = pos;
202		    if (zlecs == zlell)
203			break;
204		    INCPOS(pos);
205		    if (!Z_vialnum(zleline[pos]))
206			break;
207		}
208	    } else {
209		for (;;) {
210		    zlecs = pos;
211		    if (zlecs == zlell)
212			break;
213		    INCPOS(pos);
214		    if (Z_vialnum(zleline[pos]) || ZC_iblank(zleline[pos]))
215			break;
216		}
217	    }
218	}
219    }
220    if (zlecs != zlell && virangeflag)
221	INCCS();
222    return 0;
223}
224
225/**/
226int
227backwardword(char **args)
228{
229    int n = zmult;
230
231    if (n < 0) {
232	int ret;
233	zmult = -n;
234	ret = forwardword(args);
235	zmult = n;
236	return ret;
237    }
238    while (n--) {
239	while (zlecs) {
240	    int pos = zlecs;
241	    DECPOS(pos);
242	    if (ZC_iword(zleline[pos]))
243		break;
244	    zlecs = pos;
245	}
246	while (zlecs) {
247	    int pos = zlecs;
248	    DECPOS(pos);
249	    if (!ZC_iword(zleline[pos]))
250		break;
251	    zlecs = pos;
252	}
253    }
254    return 0;
255}
256
257/**/
258int
259vibackwardword(char **args)
260{
261    int n = zmult;
262
263    if (n < 0) {
264	int ret;
265	zmult = -n;
266	ret = backwardword(args);
267	zmult = n;
268	return ret;
269    }
270    while (n--) {
271	while (zlecs) {
272	    int pos = zlecs;
273	    DECPOS(pos);
274	    if (!ZC_iblank(zleline[pos]))
275		break;
276	    zlecs = pos;
277	}
278	if (zlecs) {
279	    int pos = zlecs;
280	    DECPOS(pos);
281	    if (Z_vialnum(zleline[pos])) {
282		for (;;) {
283		    zlecs = pos;
284		    if (zlecs == 0)
285			break;
286		    DECPOS(pos);
287		    if (!Z_vialnum(zleline[pos]))
288			break;
289		}
290	    } else {
291		for (;;) {
292		    zlecs = pos;
293		    if (zlecs == 0)
294			break;
295		    DECPOS(pos);
296		    if (Z_vialnum(zleline[pos]) || ZC_iblank(zleline[pos]))
297			break;
298		}
299	    }
300	}
301    }
302    return 0;
303}
304
305/**/
306int
307vibackwardblankword(char **args)
308{
309    int n = zmult;
310
311    if (n < 0) {
312	int ret;
313	zmult = -n;
314	ret = viforwardblankword(args);
315	zmult = n;
316	return ret;
317    }
318    while (n--) {
319	while (zlecs) {
320	    int pos = zlecs;
321	    DECPOS(pos);
322	    if (!ZC_iblank(zleline[pos]))
323		break;
324	    zlecs = pos;
325	}
326	while (zlecs) {
327	    int pos = zlecs;
328	    DECPOS(pos);
329	    if (ZC_iblank(zleline[pos]))
330		break;
331	    zlecs = pos;
332	}
333    }
334    return 0;
335}
336
337/**/
338int
339emacsbackwardword(char **args)
340{
341    int n = zmult;
342
343    if (n < 0) {
344	int ret;
345	zmult = -n;
346	ret = emacsforwardword(args);
347	zmult = n;
348	return ret;
349    }
350    while (n--) {
351	while (zlecs) {
352	    int pos = zlecs;
353	    DECPOS(pos);
354	    if (ZC_iword(zleline[pos]))
355		break;
356	    zlecs = pos;
357	}
358	while (zlecs) {
359	    int pos = zlecs;
360	    DECPOS(pos);
361	    if (!ZC_iword(zleline[pos]))
362		break;
363	    zlecs = pos;
364	}
365    }
366    return 0;
367}
368
369/**/
370int
371backwarddeleteword(char **args)
372{
373    int x = zlecs, n = zmult;
374
375    if (n < 0) {
376	int ret;
377	zmult = -n;
378	ret = deleteword(args);
379	zmult = n;
380	return ret;
381    }
382    while (n--) {
383	while (x) {
384	    int pos = x;
385	    DECPOS(pos);
386	    if (ZC_iword(zleline[pos]))
387		break;
388	    x = pos;
389	}
390	while (x) {
391	    int pos = x;
392	    DECPOS(pos);
393	    if (!ZC_iword(zleline[pos]))
394		break;
395	    x = pos;
396	}
397    }
398    backdel(zlecs - x, CUT_RAW);
399    return 0;
400}
401
402/**/
403int
404vibackwardkillword(UNUSED(char **args))
405{
406    int x = zlecs, lim = (viinsbegin > findbol()) ? viinsbegin : findbol();
407    int n = zmult;
408
409    if (n < 0)
410	return 1;
411/* this taken from "vibackwardword" */
412    while (n--) {
413	while (x > lim) {
414	    int pos = x;
415	    DECPOS(pos);
416	    if (!ZC_iblank(zleline[pos]))
417		break;
418	    x = pos;
419	}
420	if (x > lim) {
421	    int pos = x;
422	    DECPOS(pos);
423	    if (Z_vialnum(zleline[pos])) {
424		for (;;) {
425		    x = pos;
426		    if (x <= lim)
427			break;
428		    DECPOS(pos);
429		    if (!Z_vialnum(zleline[pos]))
430			break;
431		}
432	    } else {
433		for (;;) {
434		    x = pos;
435		    if (x <= lim)
436			break;
437		    DECPOS(pos);
438		    if (Z_vialnum(zleline[pos]) || ZC_iblank(zleline[pos]))
439			break;
440		}
441	    }
442	}
443    }
444    backkill(zlecs - x, CUT_FRONT|CUT_RAW);
445    return 0;
446}
447
448/**/
449int
450backwardkillword(char **args)
451{
452    int x = zlecs;
453    int n = zmult;
454
455    if (n < 0) {
456	int ret;
457	zmult = -n;
458	ret = killword(args);
459	zmult = n;
460	return ret;
461    }
462    while (n--) {
463	while (x) {
464	    int pos = x;
465	    DECPOS(pos);
466	    if (ZC_iword(zleline[pos]))
467		break;
468	    x = pos;
469	}
470	while (x) {
471	    int pos = x;
472	    DECPOS(pos);
473	    if (!ZC_iword(zleline[pos]))
474		break;
475	    x = pos;
476	}
477    }
478    backkill(zlecs - x, CUT_FRONT|CUT_RAW);
479    return 0;
480}
481
482/**/
483int
484upcaseword(UNUSED(char **args))
485{
486    int n = zmult;
487    int neg = n < 0, ocs = zlecs;
488
489    if (neg)
490	n = -n;
491    while (n--) {
492	while (zlecs != zlell && !ZC_iword(zleline[zlecs]))
493	    INCCS();
494	while (zlecs != zlell && ZC_iword(zleline[zlecs])) {
495	    zleline[zlecs] = ZC_toupper(zleline[zlecs]);
496	    INCCS();
497	}
498    }
499    if (neg)
500	zlecs = ocs;
501    return 0;
502}
503
504/**/
505int
506downcaseword(UNUSED(char **args))
507{
508    int n = zmult;
509    int neg = n < 0, ocs = zlecs;
510
511    if (neg)
512	n = -n;
513    while (n--) {
514	while (zlecs != zlell && !ZC_iword(zleline[zlecs]))
515	    INCCS();
516	while (zlecs != zlell && ZC_iword(zleline[zlecs])) {
517	    zleline[zlecs] = ZC_tolower(zleline[zlecs]);
518	    INCCS();
519	}
520    }
521    if (neg)
522	zlecs = ocs;
523    return 0;
524}
525
526/**/
527int
528capitalizeword(UNUSED(char **args))
529{
530    int first, n = zmult;
531    int neg = n < 0, ocs = zlecs;
532
533    if (neg)
534	n = -n;
535    while (n--) {
536	first = 1;
537	while (zlecs != zlell && !ZC_iword(zleline[zlecs]))
538	    INCCS();
539	while (zlecs != zlell && ZC_iword(zleline[zlecs]) && !ZC_ialpha(zleline[zlecs]))
540	    INCCS();
541	while (zlecs != zlell && ZC_iword(zleline[zlecs])) {
542	    zleline[zlecs] = (first) ? ZC_toupper(zleline[zlecs]) :
543		ZC_tolower(zleline[zlecs]);
544	    first = 0;
545	    INCCS();
546	}
547    }
548    if (neg)
549	zlecs = ocs;
550    return 0;
551}
552
553/**/
554int
555deleteword(char **args)
556{
557    int x = zlecs;
558    int n = zmult;
559
560    if (n < 0) {
561	int ret;
562	zmult = -n;
563	ret = backwarddeleteword(args);
564	zmult = n;
565	return ret;
566    }
567    while (n--) {
568	while (x != zlell && !ZC_iword(zleline[x]))
569	    INCPOS(x);
570	while (x != zlell && ZC_iword(zleline[x]))
571	    INCPOS(x);
572    }
573    foredel(x - zlecs, CUT_RAW);
574    return 0;
575}
576
577/**/
578int
579killword(char **args)
580{
581    int x = zlecs;
582    int n = zmult;
583
584    if (n < 0) {
585	int ret;
586	zmult = -n;
587	ret = backwardkillword(args);
588	zmult = n;
589	return ret;
590    }
591    while (n--) {
592	while (x != zlell && !ZC_iword(zleline[x]))
593	    INCPOS(x);
594	while (x != zlell && ZC_iword(zleline[x]))
595	    INCPOS(x);
596    }
597    forekill(x - zlecs, CUT_RAW);
598    return 0;
599}
600
601/**/
602int
603transposewords(UNUSED(char **args))
604{
605    int p1, p2, p3, p4, len, x = zlecs, pos;
606    ZLE_STRING_T temp, pp;
607    int n = zmult;
608    int neg = n < 0, ocs = zlecs;
609
610    if (neg)
611	n = -n;
612    while (n--) {
613	while (x != zlell && zleline[x] != ZWC('\n') && !ZC_iword(zleline[x]))
614	    INCPOS(x);
615	if (x == zlell || zleline[x] == ZWC('\n')) {
616	    x = zlecs;
617	    while (x) {
618		if (ZC_iword(zleline[x]))
619		    break;
620		pos = x;
621		DECPOS(pos);
622		if (zleline[pos] == ZWC('\n'))
623		    break;
624		x = pos;
625	    }
626	    if (!x)
627		return 1;
628	    pos = x;
629	    DECPOS(pos);
630	    if (zleline[pos] == ZWC('\n'))
631		return 1;
632	    x = pos;
633	}
634	for (p4 = x; p4 != zlell && ZC_iword(zleline[p4]); INCPOS(p4))
635	    ;
636	for (p3 = p4; p3; ) {
637	    pos = p3;
638	    DECPOS(pos);
639	    if (!ZC_iword(zleline[pos]))
640		break;
641	    p3 = pos;
642	}
643	if (!p3)
644	    return 1;
645	for (p2 = p3; p2; ) {
646	    pos = p2;
647	    DECPOS(pos);
648	    if (ZC_iword(zleline[pos]))
649		break;
650	    p2 = pos;
651	}
652	if (!p2)
653	    return 1;
654	for (p1 = p2; p1; ) {
655	    pos = p1;
656	    DECPOS(pos);
657	    if (!ZC_iword(zleline[pos]))
658		break;
659	    p1 = pos;
660	}
661	pp = temp = (ZLE_STRING_T)zhalloc((p4 - p1)*ZLE_CHAR_SIZE);
662	len = p4 - p3;
663	ZS_memcpy(pp, zleline + p3, len);
664	pp += len;
665	len = p3 - p2;
666	ZS_memcpy(pp, zleline + p2, len);
667	pp += len;
668	ZS_memcpy(pp, zleline + p1, p2 - p1);
669
670	ZS_memcpy(zleline + p1, temp, p4 - p1);
671
672	zlecs = p4;
673    }
674    if (neg)
675	zlecs = ocs;
676    return 0;
677}
678