~ubuntu-branches/ubuntu/quantal/less/quantal

« back to all changes in this revision

Viewing changes to cmdbuf.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Schoepf
  • Date: 2002-04-04 16:43:52 UTC
  • Revision ID: james.westby@ubuntu.com-20020404164352-qldq048yoc7x5sd5
Tags: upstream-374
ImportĀ upstreamĀ versionĀ 374

Show diffs side-by-side

added added

removed removed

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