"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "less-424/cmdbuf.c" of archive less-424.tar.gz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 /*
2 * Copyright (C) 1984-2008 Mark Nudelman
3 *
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Less License, as specified in the README file.
6 *
7 * For more information about less, or for information on how to
8 * contact the author, see the README file.
9 */
10
11
12 /*
13 * Functions which manipulate the command buffer.
14 * Used only by command() and related functions.
15 */
16
17 #include "less.h"
18 #include "cmd.h"
19 #include "charset.h"
20 #if HAVE_STAT
21 #include <sys/stat.h>
22 #endif
23
24 extern int sc_width;
25 extern int utf_mode;
26
27 static char cmdbuf[CMDBUF_SIZE]; /* Buffer for holding a multi-char command */
28 static int cmd_col; /* Current column of the cursor */
29 static int prompt_col; /* Column of cursor just after prompt */
30 static char *cp; /* Pointer into cmdbuf */
31 static int cmd_offset; /* Index into cmdbuf of first displayed char */
32 static int literal; /* Next input char should not be interpreted */
33
34 #if TAB_COMPLETE_FILENAME
35 static int cmd_complete();
36 /*
37 * These variables are statics used by cmd_complete.
38 */
39 static int in_completion = 0;
40 static char *tk_text;
41 static char *tk_original;
42 static char *tk_ipoint;
43 static char *tk_trial;
44 static struct textlist tk_tlist;
45 #endif
46
47 static int cmd_left();
48 static int cmd_right();
49
50 #if SPACES_IN_FILENAMES
51 public char openquote = '"';
52 public char closequote = '"';
53 #endif
54
55 #if CMD_HISTORY
56
57 /* History file */
58 #define HISTFILE_FIRST_LINE ".less-history-file:"
59 #define HISTFILE_SEARCH_SECTION ".search"
60 #define HISTFILE_SHELL_SECTION ".shell"
61
62 /*
63 * A mlist structure represents a command history.
64 */
65 struct mlist
66 {
67 struct mlist *next;
68 struct mlist *prev;
69 struct mlist *curr_mp;
70 char *string;
71 int modified;
72 };
73
74 /*
75 * These are the various command histories that exist.
76 */
77 struct mlist mlist_search =
78 { &mlist_search, &mlist_search, &mlist_search, NULL, 0 };
79 public void * constant ml_search = (void *) &mlist_search;
80
81 struct mlist mlist_examine =
82 { &mlist_examine, &mlist_examine, &mlist_examine, NULL, 0 };
83 public void * constant ml_examine = (void *) &mlist_examine;
84
85 #if SHELL_ESCAPE || PIPEC
86 struct mlist mlist_shell =
87 { &mlist_shell, &mlist_shell, &mlist_shell, NULL, 0 };
88 public void * constant ml_shell = (void *) &mlist_shell;
89 #endif
90
91 #else /* CMD_HISTORY */
92
93 /* If CMD_HISTORY is off, these are just flags. */
94 public void * constant ml_search = (void *)1;
95 public void * constant ml_examine = (void *)2;
96 #if SHELL_ESCAPE || PIPEC
97 public void * constant ml_shell = (void *)3;
98 #endif
99
100 #endif /* CMD_HISTORY */
101
102 /*
103 * History for the current command.
104 */
105 static struct mlist *curr_mlist = NULL;
106 static int curr_cmdflags;
107
108 static char cmd_mbc_buf[MAX_UTF_CHAR_LEN];
109 static int cmd_mbc_buf_len;
110 static int cmd_mbc_buf_index;
111
112
113 /*
114 * Reset command buffer (to empty).
115 */
116 public void
117 cmd_reset()
118 {
119 cp = cmdbuf;
120 *cp = '\0';
121 cmd_col = 0;
122 cmd_offset = 0;
123 literal = 0;
124 cmd_mbc_buf_len = 0;
125 }
126
127 /*
128 * Clear command line.
129 */
130 public void
131 clear_cmd()
132 {
133 cmd_col = prompt_col = 0;
134 cmd_mbc_buf_len = 0;
135 }
136
137 /*
138 * Display a string, usually as a prompt for input into the command buffer.
139 */
140 public void
141 cmd_putstr(s)
142 char *s;
143 {
144 LWCHAR prev_ch = 0;
145 LWCHAR ch;
146 char *endline = s + strlen(s);
147 while (*s != '\0')
148 {
149 char *ns = s;
150 ch = step_char(&ns, +1, endline);
151 while (s < ns)
152 putchr(*s++);
153 if (!utf_mode)
154 {
155 cmd_col++;
156 prompt_col++;
157 } else if (!is_composing_char(ch) &&
158 !is_combining_char(prev_ch, ch))
159 {
160 int width = is_wide_char(ch) ? 2 : 1;
161 cmd_col += width;
162 prompt_col += width;
163 }
164 prev_ch = ch;
165 }
166 }
167
168 /*
169 * How many characters are in the command buffer?
170 */
171 public int
172 len_cmdbuf()
173 {
174 char *s = cmdbuf;
175 char *endline = s + strlen(s);
176 int len = 0;
177
178 while (*s != '\0')
179 {
180 step_char(&s, +1, endline);
181 len++;
182 }
183 return (len);
184 }
185
186 /*
187 * Common part of cmd_step_right() and cmd_step_left().
188 */
189 static char *
190 cmd_step_common(p, ch, len, pwidth, bswidth)
191 char *p;
192 LWCHAR ch;
193 int len;
194 int *pwidth;
195 int *bswidth;
196 {
197 char *pr;
198
199 if (len == 1)
200 {
201 pr = prchar((int) ch);
202 if (pwidth != NULL || bswidth != NULL)
203 {
204 int len = strlen(pr);
205 if (pwidth != NULL)
206 *pwidth = len;
207 if (bswidth != NULL)
208 *bswidth = len;
209 }
210 } else
211 {
212 pr = prutfchar(ch);
213 if (pwidth != NULL || bswidth != NULL)
214 {
215 if (is_composing_char(ch))
216 {
217 if (pwidth != NULL)
218 *pwidth = 0;
219 if (bswidth != NULL)
220 *bswidth = 0;
221 } else if (is_ubin_char(ch))
222 {
223 int len = strlen(pr);
224 if (pwidth != NULL)
225 *pwidth = len;
226 if (bswidth != NULL)
227 *bswidth = len;
228 } else
229 {
230 LWCHAR prev_ch = step_char(&p, -1, cmdbuf);
231 if (is_combining_char(prev_ch, ch))
232 {
233 if (pwidth != NULL)
234 *pwidth = 0;
235 if (bswidth != NULL)
236 *bswidth = 0;
237 } else
238 {
239 if (pwidth != NULL)
240 *pwidth = is_wide_char(ch)
241 ? 2
242 : 1;
243 if (bswidth != NULL)
244 *bswidth = 1;
245 }
246 }
247 }
248 }
249
250 return (pr);
251 }
252
253 /*
254 * Step a pointer one character right in the command buffer.
255 */
256 static char *
257 cmd_step_right(pp, pwidth, bswidth)
258 char **pp;
259 int *pwidth;
260 int *bswidth;
261 {
262 char *p = *pp;
263 LWCHAR ch = step_char(pp, +1, p + strlen(p));
264
265 return cmd_step_common(p, ch, *pp - p, pwidth, bswidth);
266 }
267
268 /*
269 * Step a pointer one character left in the command buffer.
270 */
271 static char *
272 cmd_step_left(pp, pwidth, bswidth)
273 char **pp;
274 int *pwidth;
275 int *bswidth;
276 {
277 char *p = *pp;
278 LWCHAR ch = step_char(pp, -1, cmdbuf);
279
280 return cmd_step_common(*pp, ch, p - *pp, pwidth, bswidth);
281 }
282
283 /*
284 * Repaint the line from cp onwards.
285 * Then position the cursor just after the char old_cp (a pointer into cmdbuf).
286 */
287 static void
288 cmd_repaint(old_cp)
289 char *old_cp;
290 {
291 /*
292 * Repaint the line from the current position.
293 */
294 clear_eol();
295 while (*cp != '\0')
296 {
297 char *np = cp;
298 int width;
299 char *pr = cmd_step_right(&np, &width, NULL);
300 if (cmd_col + width >= sc_width)
301 break;
302 cp = np;
303 putstr(pr);
304 cmd_col += width;
305 }
306 while (*cp != '\0')
307 {
308 char *np = cp;
309 int width;
310 char *pr = cmd_step_right(&np, &width, NULL);
311 if (width > 0)
312 break;
313 cp = np;
314 putstr(pr);
315 }
316
317 /*
318 * Back up the cursor to the correct position.
319 */
320 while (cp > old_cp)
321 cmd_left();
322 }
323
324 /*
325 * Put the cursor at "home" (just after the prompt),
326 * and set cp to the corresponding char in cmdbuf.
327 */
328 static void
329 cmd_home()
330 {
331 while (cmd_col > prompt_col)
332 {
333 int width, bswidth;
334
335 cmd_step_left(&cp, &width, &bswidth);
336 while (bswidth-- > 0)
337 putbs();
338 cmd_col -= width;
339 }
340
341 cp = &cmdbuf[cmd_offset];
342 }
343
344 /*
345 * Shift the cmdbuf display left a half-screen.
346 */
347 static void
348 cmd_lshift()
349 {
350 char *s;
351 char *save_cp;
352 int cols;
353
354 /*
355 * Start at the first displayed char, count how far to the
356 * right we'd have to move to reach the center of the screen.
357 */
358 s = cmdbuf + cmd_offset;
359 cols = 0;
360 while (cols < (sc_width - prompt_col) / 2 && *s != '\0')
361 {
362 int width;
363 cmd_step_right(&s, &width, NULL);
364 cols += width;
365 }
366 while (*s != '\0')
367 {
368 int width;
369 char *ns = s;
370 cmd_step_right(&ns, &width, NULL);
371 if (width > 0)
372 break;
373 s = ns;
374 }
375
376 cmd_offset = s - cmdbuf;
377 save_cp = cp;
378 cmd_home();
379 cmd_repaint(save_cp);
380 }
381
382 /*
383 * Shift the cmdbuf display right a half-screen.
384 */
385 static void
386 cmd_rshift()
387 {
388 char *s;
389 char *save_cp;
390 int cols;
391
392 /*
393 * Start at the first displayed char, count how far to the
394 * left we'd have to move to traverse a half-screen width
395 * of displayed characters.
396 */
397 s = cmdbuf + cmd_offset;
398 cols = 0;
399 while (cols < (sc_width - prompt_col) / 2 && s > cmdbuf)
400 {
401 int width;
402 cmd_step_left(&s, &width, NULL);
403 cols += width;
404 }
405
406 cmd_offset = s - cmdbuf;
407 save_cp = cp;
408 cmd_home();
409 cmd_repaint(save_cp);
410 }
411
412 /*
413 * Move cursor right one character.
414 */
415 static int
416 cmd_right()
417 {
418 char *pr;
419 char *ncp;
420 int width;
421
422 if (*cp == '\0')
423 {
424 /* Already at the end of the line. */
425 return (CC_OK);
426 }
427 ncp = cp;
428 pr = cmd_step_right(&ncp, &width, NULL);
429 if (cmd_col + width >= sc_width)
430 cmd_lshift();
431 else if (cmd_col + width == sc_width - 1 && cp[1] != '\0')
432 cmd_lshift();
433 cp = ncp;
434 cmd_col += width;
435 putstr(pr);
436 while (*cp != '\0')
437 {
438 pr = cmd_step_right(&ncp, &width, NULL);
439 if (width > 0)
440 break;
441 putstr(pr);
442 cp = ncp;
443 }
444 return (CC_OK);
445 }
446
447 /*
448 * Move cursor left one character.
449 */
450 static int
451 cmd_left()
452 {
453 char *ncp;
454 int width, bswidth;
455
456 if (cp <= cmdbuf)
457 {
458 /* Already at the beginning of the line */
459 return (CC_OK);
460 }
461 ncp = cp;
462 while (ncp > cmdbuf)
463 {
464 cmd_step_left(&ncp, &width, &bswidth);
465 if (width > 0)
466 break;
467 }
468 if (cmd_col < prompt_col + width)
469 cmd_rshift();
470 cp = ncp;
471 cmd_col -= width;
472 while (bswidth-- > 0)
473 putbs();
474 return (CC_OK);
475 }
476
477 /*
478 * Insert a char into the command buffer, at the current position.
479 */
480 static int
481 cmd_ichar(cs, clen)
482 char *cs;
483 int clen;
484 {
485 char *s;
486
487 if (strlen(cmdbuf) + clen >= sizeof(cmdbuf)-1)
488 {
489 /* No room in the command buffer for another char. */
490 bell();
491 return (CC_ERROR);
492 }
493
494 /*
495 * Make room for the new character (shift the tail of the buffer right).
496 */
497 for (s = &cmdbuf[strlen(cmdbuf)]; s >= cp; s--)
498 s[clen] = s[0];
499 /*
500 * Insert the character into the buffer.
501 */
502 for (s = cp; s < cp + clen; s++)
503 *s = *cs++;
504 /*
505 * Reprint the tail of the line from the inserted char.
506 */
507 cmd_repaint(cp);
508 cmd_right();
509 return (CC_OK);
510 }
511
512 /*
513 * Backspace in the command buffer.
514 * Delete the char to the left of the cursor.
515 */
516 static int
517 cmd_erase()
518 {
519 register char *s;
520 int clen;
521
522 if (cp == cmdbuf)
523 {
524 /*
525 * Backspace past beginning of the buffer:
526 * this usually means abort the command.
527 */
528 return (CC_QUIT);
529 }
530 /*
531 * Move cursor left (to the char being erased).
532 */
533 s = cp;
534 cmd_left();
535 clen = s - cp;
536
537 /*
538 * Remove the char from the buffer (shift the buffer left).
539 */
540 for (s = cp; ; s++)
541 {
542 s[0] = s[clen];
543 if (s[0] == '\0')
544 break;
545 }
546
547 /*
548 * Repaint the buffer after the erased char.
549 */
550 cmd_repaint(cp);
551
552 /*
553 * We say that erasing the entire command string causes us
554 * to abort the current command, if CF_QUIT_ON_ERASE is set.
555 */
556 if ((curr_cmdflags & CF_QUIT_ON_ERASE) && cp == cmdbuf && *cp == '\0')
557 return (CC_QUIT);
558 return (CC_OK);
559 }
560
561 /*
562 * Delete the char under the cursor.
563 */
564 static int
565 cmd_delete()
566 {
567 if (*cp == '\0')
568 {
569 /* At end of string; there is no char under the cursor. */
570 return (CC_OK);
571 }
572 /*
573 * Move right, then use cmd_erase.
574 */
575 cmd_right();
576 cmd_erase();
577 return (CC_OK);
578 }
579
580 /*
581 * Delete the "word" to the left of the cursor.
582 */
583 static int
584 cmd_werase()
585 {
586 if (cp > cmdbuf && cp[-1] == ' ')
587 {
588 /*
589 * If the char left of cursor is a space,
590 * erase all the spaces left of cursor (to the first non-space).
591 */
592 while (cp > cmdbuf && cp[-1] == ' ')
593 (void) cmd_erase();
594 } else
595 {
596 /*
597 * If the char left of cursor is not a space,
598 * erase all the nonspaces left of cursor (the whole "word").
599 */
600 while (cp > cmdbuf && cp[-1] != ' ')
601 (void) cmd_erase();
602 }
603 return (CC_OK);
604 }
605
606 /*
607 * Delete the "word" under the cursor.
608 */
609 static int
610 cmd_wdelete()
611 {
612 if (*cp == ' ')
613 {
614 /*
615 * If the char under the cursor is a space,
616 * delete it and all the spaces right of cursor.
617 */
618 while (*cp == ' ')
619 (void) cmd_delete();
620 } else
621 {
622 /*
623 * If the char under the cursor is not a space,
624 * delete it and all nonspaces right of cursor (the whole word).
625 */
626 while (*cp != ' ' && *cp != '\0')
627 (void) cmd_delete();
628 }
629 return (CC_OK);
630 }
631
632 /*
633 * Delete all chars in the command buffer.
634 */
635 static int
636 cmd_kill()
637 {
638 if (cmdbuf[0] == '\0')
639 {
640 /* Buffer is already empty; abort the current command. */
641 return (CC_QUIT);
642 }
643 cmd_offset = 0;
644 cmd_home();
645 *cp = '\0';
646 cmd_repaint(cp);
647
648 /*
649 * We say that erasing the entire command string causes us
650 * to abort the current command, if CF_QUIT_ON_ERASE is set.
651 */
652 if (curr_cmdflags & CF_QUIT_ON_ERASE)
653 return (CC_QUIT);
654 return (CC_OK);
655 }
656
657 /*
658 * Select an mlist structure to be the current command history.
659 */
660 public void
661 set_mlist(mlist, cmdflags)
662 void *mlist;
663 int cmdflags;
664 {
665 #if CMD_HISTORY
666 curr_mlist = (struct mlist *) mlist;
667 curr_cmdflags = cmdflags;
668
669 /* Make sure the next up-arrow moves to the last string in the mlist. */
670 if (curr_mlist != NULL)
671 curr_mlist->curr_mp = curr_mlist;
672 #endif
673 }
674
675 #if CMD_HISTORY
676 /*
677 * Move up or down in the currently selected command history list.
678 */
679 static int
680 cmd_updown(action)
681 int action;
682 {
683 char *s;
684
685 if (curr_mlist == NULL)
686 {
687 /*
688 * The current command has no history list.
689 */
690 bell();
691 return (CC_OK);
692 }
693 cmd_home();
694 clear_eol();
695 /*
696 * Move curr_mp to the next/prev entry.
697 */
698 if (action == EC_UP)
699 curr_mlist->curr_mp = curr_mlist->curr_mp->prev;
700 else
701 curr_mlist->curr_mp = curr_mlist->curr_mp->next;
702 /*
703 * Copy the entry into cmdbuf and echo it on the screen.
704 */
705 s = curr_mlist->curr_mp->string;
706 if (s == NULL)
707 s = "";
708 strcpy(cmdbuf, s);
709 for (cp = cmdbuf; *cp != '\0'; )
710 cmd_right();
711 return (CC_OK);
712 }
713 #endif
714
715 /*
716 * Add a string to a history list.
717 */
718 public void
719 cmd_addhist(mlist, cmd)
720 struct mlist *mlist;
721 char *cmd;
722 {
723 #if CMD_HISTORY
724 struct mlist *ml;
725
726 /*
727 * Don't save a trivial command.
728 */
729 if (strlen(cmd) == 0)
730 return;
731
732 /*
733 * Save the command unless it's a duplicate of the
734 * last command in the history.
735 */
736 ml = mlist->prev;
737 if (ml == mlist || strcmp(ml->string, cmd) != 0)
738 {
739 /*
740 * Did not find command in history.
741 * Save the command and put it at the end of the history list.
742 */
743 ml = (struct mlist *) ecalloc(1, sizeof(struct mlist));
744 ml->string = save(cmd);
745 ml->next = mlist;
746 ml->prev = mlist->prev;
747 mlist->prev->next = ml;
748 mlist->prev = ml;
749 }
750 /*
751 * Point to the cmd just after the just-accepted command.
752 * Thus, an UPARROW will always retrieve the previous command.
753 */
754 mlist->curr_mp = ml->next;
755 #endif
756 }
757
758 /*
759 * Accept the command in the command buffer.
760 * Add it to the currently selected history list.
761 */
762 public void
763 cmd_accept()
764 {
765 #if CMD_HISTORY
766 /*
767 * Nothing to do if there is no currently selected history list.
768 */
769 if (curr_mlist == NULL)
770 return;
771 cmd_addhist(curr_mlist, cmdbuf);
772 curr_mlist->modified = 1;
773 #endif
774 }
775
776 /*
777 * Try to perform a line-edit function on the command buffer,
778 * using a specified char as a line-editing command.
779 * Returns:
780 * CC_PASS The char does not invoke a line edit function.
781 * CC_OK Line edit function done.
782 * CC_QUIT The char requests the current command to be aborted.
783 */
784 static int
785 cmd_edit(c)
786 int c;
787 {
788 int action;
789 int flags;
790
791 #if TAB_COMPLETE_FILENAME
792 #define not_in_completion() in_completion = 0
793 #else
794 #define not_in_completion()
795 #endif
796
797 /*
798 * See if the char is indeed a line-editing command.
799 */
800 flags = 0;
801 #if CMD_HISTORY
802 if (curr_mlist == NULL)
803 /*
804 * No current history; don't accept history manipulation cmds.
805 */
806 flags |= EC_NOHISTORY;
807 #endif
808 #if TAB_COMPLETE_FILENAME
809 if (curr_mlist == ml_search)
810 /*
811 * In a search command; don't accept file-completion cmds.
812 */
813 flags |= EC_NOCOMPLETE;
814 #endif
815
816 action = editchar(c, flags);
817
818 switch (action)
819 {
820 case EC_RIGHT:
821 not_in_completion();
822 return (cmd_right());
823 case EC_LEFT:
824 not_in_completion();
825 return (cmd_left());
826 case EC_W_RIGHT:
827 not_in_completion();
828 while (*cp != '\0' && *cp != ' ')
829 cmd_right();
830 while (*cp == ' ')
831 cmd_right();
832 return (CC_OK);
833 case EC_W_LEFT:
834 not_in_completion();
835 while (cp > cmdbuf && cp[-1] == ' ')
836 cmd_left();
837 while (cp > cmdbuf && cp[-1] != ' ')
838 cmd_left();
839 return (CC_OK);
840 case EC_HOME:
841 not_in_completion();
842 cmd_offset = 0;
843 cmd_home();
844 cmd_repaint(cp);
845 return (CC_OK);
846 case EC_END:
847 not_in_completion();
848 while (*cp != '\0')
849 cmd_right();
850 return (CC_OK);
851 case EC_INSERT:
852 not_in_completion();
853 return (CC_OK);
854 case EC_BACKSPACE:
855 not_in_completion();
856 return (cmd_erase());
857 case EC_LINEKILL:
858 not_in_completion();
859 return (cmd_kill());
860 case EC_W_BACKSPACE:
861 not_in_completion();
862 return (cmd_werase());
863 case EC_DELETE:
864 not_in_completion();
865 return (cmd_delete());
866 case EC_W_DELETE:
867 not_in_completion();
868 return (cmd_wdelete());
869 case EC_LITERAL:
870 literal = 1;
871 return (CC_OK);
872 #if CMD_HISTORY
873 case EC_UP:
874 case EC_DOWN:
875 not_in_completion();
876 return (cmd_updown(action));
877 #endif
878 #if TAB_COMPLETE_FILENAME
879 case EC_F_COMPLETE:
880 case EC_B_COMPLETE:
881 case EC_EXPAND:
882 return (cmd_complete(action));
883 #endif
884 case EC_NOACTION:
885 return (CC_OK);
886 default:
887 not_in_completion();
888 return (CC_PASS);
889 }
890 }
891
892 #if TAB_COMPLETE_FILENAME
893 /*
894 * Insert a string into the command buffer, at the current position.
895 */
896 static int
897 cmd_istr(str)
898 char *str;
899 {
900 char *s;
901 int action;
902 char *endline = str + strlen(str);
903
904 for (s = str; *s != '\0'; )
905 {
906 char *os = s;
907 step_char(&s, +1, endline);
908 action = cmd_ichar(os, s - os);
909 if (action != CC_OK)
910 {
911 bell();
912 return (action);
913 }
914 }
915 return (CC_OK);
916 }
917
918 /*
919 * Find the beginning and end of the "current" word.
920 * This is the word which the cursor (cp) is inside or at the end of.
921 * Return pointer to the beginning of the word and put the
922 * cursor at the end of the word.
923 */
924 static char *
925 delimit_word()
926 {
927 char *word;
928 #if SPACES_IN_FILENAMES
929 char *p;
930 int delim_quoted = 0;
931 int meta_quoted = 0;
932 char *esc = get_meta_escape();
933 int esclen = strlen(esc);
934 #endif
935
936 /*
937 * Move cursor to end of word.
938 */
939 if (*cp != ' ' && *cp != '\0')
940 {
941 /*
942 * Cursor is on a nonspace.
943 * Move cursor right to the next space.
944 */
945 while (*cp != ' ' && *cp != '\0')
946 cmd_right();
947 } else if (cp > cmdbuf && cp[-1] != ' ')
948 {
949 /*
950 * Cursor is on a space, and char to the left is a nonspace.
951 * We're already at the end of the word.
952 */
953 ;
954 #if 0
955 } else
956 {
957 /*
958 * Cursor is on a space and char to the left is a space.
959 * Huh? There's no word here.
960 */
961 return (NULL);
962 #endif
963 }
964 /*
965 * Find the beginning of the word which the cursor is in.
966 */
967 if (cp == cmdbuf)
968 return (NULL);
969 #if SPACES_IN_FILENAMES
970 /*
971 * If we have an unbalanced quote (that is, an open quote
972 * without a corresponding close quote), we return everything
973 * from the open quote, including spaces.
974 */
975 for (word = cmdbuf; word < cp; word++)
976 if (*word != ' ')
977 break;
978 if (word >= cp)
979 return (cp);
980 for (p = cmdbuf; p < cp; p++)
981 {
982 if (meta_quoted)
983 {
984 meta_quoted = 0;
985 } else if (esclen > 0 && p + esclen < cp &&
986 strncmp(p, esc, esclen) == 0)
987 {
988 meta_quoted = 1;
989 p += esclen - 1;
990 } else if (delim_quoted)
991 {
992 if (*p == closequote)
993 delim_quoted = 0;
994 } else /* (!delim_quoted) */
995 {
996 if (*p == openquote)
997 delim_quoted = 1;
998 else if (*p == ' ')
999 word = p+1;
1000 }
1001 }
1002 #endif
1003 return (word);
1004 }
1005
1006 /*
1007 * Set things up to enter completion mode.
1008 * Expand the word under the cursor into a list of filenames
1009 * which start with that word, and set tk_text to that list.
1010 */
1011 static void
1012 init_compl()
1013 {
1014 char *word;
1015 char c;
1016
1017 /*
1018 * Get rid of any previous tk_text.
1019 */
1020 if (tk_text != NULL)
1021 {
1022 free(tk_text);
1023 tk_text = NULL;
1024 }
1025 /*
1026 * Find the original (uncompleted) word in the command buffer.
1027 */
1028 word = delimit_word();
1029 if (word == NULL)
1030 return;
1031 /*
1032 * Set the insertion point to the point in the command buffer
1033 * where the original (uncompleted) word now sits.
1034 */
1035 tk_ipoint = word;
1036 /*
1037 * Save the original (uncompleted) word
1038 */
1039 if (tk_original != NULL)
1040 free(tk_original);
1041 tk_original = (char *) ecalloc(cp-word+1, sizeof(char));
1042 strncpy(tk_original, word, cp-word);
1043 /*
1044 * Get the expanded filename.
1045 * This may result in a single filename, or
1046 * a blank-separated list of filenames.
1047 */
1048 c = *cp;
1049 *cp = '\0';
1050 if (*word != openquote)
1051 {
1052 tk_text = fcomplete(word);
1053 } else
1054 {
1055 char *qword = shell_quote(word+1);
1056 if (qword == NULL)
1057 tk_text = fcomplete(word+1);
1058 else
1059 {
1060 tk_text = fcomplete(qword);
1061 free(qword);
1062 }
1063 }
1064 *cp = c;
1065 }
1066
1067 /*
1068 * Return the next word in the current completion list.
1069 */
1070 static char *
1071 next_compl(action, prev)
1072 int action;
1073 char *prev;
1074 {
1075 switch (action)
1076 {
1077 case EC_F_COMPLETE:
1078 return (forw_textlist(&tk_tlist, prev));
1079 case EC_B_COMPLETE:
1080 return (back_textlist(&tk_tlist, prev));
1081 }
1082 /* Cannot happen */
1083 return ("?");
1084 }
1085
1086 /*
1087 * Complete the filename before (or under) the cursor.
1088 * cmd_complete may be called multiple times. The global in_completion
1089 * remembers whether this call is the first time (create the list),
1090 * or a subsequent time (step thru the list).
1091 */
1092 static int
1093 cmd_complete(action)
1094 int action;
1095 {
1096 char *s;
1097
1098 if (!in_completion || action == EC_EXPAND)
1099 {
1100 /*
1101 * Expand the word under the cursor and
1102 * use the first word in the expansion
1103 * (or the entire expansion if we're doing EC_EXPAND).
1104 */
1105 init_compl();
1106 if (tk_text == NULL)
1107 {
1108 bell();
1109 return (CC_OK);
1110 }
1111 if (action == EC_EXPAND)
1112 {
1113 /*
1114 * Use the whole list.
1115 */
1116 tk_trial = tk_text;
1117 } else
1118 {
1119 /*
1120 * Use the first filename in the list.
1121 */
1122 in_completion = 1;
1123 init_textlist(&tk_tlist, tk_text);
1124 tk_tri