Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ksh93/edit/edit.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1982-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* David Korn <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* edit.c - common routines for vi and emacs one line editors in shell
23
*
24
* David Korn P.D. Sullivan
25
* AT&T Labs
26
*
27
* Coded April 1983.
28
*/
29
30
#include <ast.h>
31
#include <errno.h>
32
#include <ccode.h>
33
#include "FEATURE/options"
34
#include "FEATURE/time"
35
#include "FEATURE/cmds"
36
#ifdef _hdr_utime
37
# include <utime.h>
38
# include <ls.h>
39
#endif
40
41
#if KSHELL
42
# include "defs.h"
43
# include "variables.h"
44
#else
45
# include <ctype.h>
46
extern char ed_errbuf[];
47
char e_version[] = "\n@(#)$Id: Editlib version 1993-12-28 r $\0\n";
48
#endif /* KSHELL */
49
#include "io.h"
50
#include "terminal.h"
51
#include "history.h"
52
#include "edit.h"
53
54
static char CURSOR_UP[20] = { ESC, '[', 'A', 0 };
55
static char KILL_LINE[20] = { ESC, '[', 'J', 0 };
56
57
58
59
#if SHOPT_MULTIBYTE
60
# define is_cntrl(c) ((c<=STRIP) && iscntrl(c))
61
# define is_print(c) ((c&~STRIP) || isprint(c))
62
#else
63
# define is_cntrl(c) iscntrl(c)
64
# define is_print(c) isprint(c)
65
#endif
66
67
#if (CC_NATIVE == CC_ASCII)
68
# define printchar(c) ((c) ^ ('A'-cntl('A')))
69
#else
70
static int printchar(int c)
71
{
72
switch(c)
73
{
74
75
case cntl('A'): return('A');
76
case cntl('B'): return('B');
77
case cntl('C'): return('C');
78
case cntl('D'): return('D');
79
case cntl('E'): return('E');
80
case cntl('F'): return('F');
81
case cntl('G'): return('G');
82
case cntl('H'): return('H');
83
case cntl('I'): return('I');
84
case cntl('J'): return('J');
85
case cntl('K'): return('K');
86
case cntl('L'): return('L');
87
case cntl('M'): return('M');
88
case cntl('N'): return('N');
89
case cntl('O'): return('O');
90
case cntl('P'): return('P');
91
case cntl('Q'): return('Q');
92
case cntl('R'): return('R');
93
case cntl('S'): return('S');
94
case cntl('T'): return('T');
95
case cntl('U'): return('U');
96
case cntl('V'): return('V');
97
case cntl('W'): return('W');
98
case cntl('X'): return('X');
99
case cntl('Y'): return('Y');
100
case cntl('Z'): return('Z');
101
case cntl(']'): return(']');
102
case cntl('['): return('[');
103
}
104
return('?');
105
}
106
#endif
107
#define MINWINDOW 15 /* minimum width window */
108
#define DFLTWINDOW 80 /* default window width */
109
#define RAWMODE 1
110
#define ALTMODE 2
111
#define ECHOMODE 3
112
#define SYSERR -1
113
114
#if SHOPT_OLDTERMIO
115
# undef tcgetattr
116
# undef tcsetattr
117
#endif /* SHOPT_OLDTERMIO */
118
119
#ifdef RT
120
# define VENIX 1
121
#endif /* RT */
122
123
124
#ifdef _hdr_sgtty
125
# ifdef TIOCGETP
126
static int l_mask;
127
static struct tchars l_ttychars;
128
static struct ltchars l_chars;
129
static char l_changed; /* set if mode bits changed */
130
# define L_CHARS 4
131
# define T_CHARS 2
132
# define L_MASK 1
133
# endif /* TIOCGETP */
134
#endif /* _hdr_sgtty */
135
136
#if KSHELL
137
static int keytrap(Edit_t *,char*, int, int, int);
138
#else
139
Edit_t editb;
140
#endif /* KSHELL */
141
142
143
#ifndef _POSIX_DISABLE
144
# define _POSIX_DISABLE 0
145
#endif
146
147
#ifdef future
148
static int compare(const char*, const char*, int);
149
#endif /* future */
150
#if SHOPT_VSH || SHOPT_ESH
151
# define ttyparm (ep->e_ttyparm)
152
# define nttyparm (ep->e_nttyparm)
153
static const char bellchr[] = "\a"; /* bell char */
154
#endif /* SHOPT_VSH || SHOPT_ESH */
155
156
157
/*
158
* This routine returns true if fd refers to a terminal
159
* This should be equivalent to isatty
160
*/
161
int tty_check(int fd)
162
{
163
register Edit_t *ep = (Edit_t*)(shgd->ed_context);
164
struct termios tty;
165
ep->e_savefd = -1;
166
return(tty_get(fd,&tty)==0);
167
}
168
169
/*
170
* Get the current terminal attributes
171
* This routine remembers the attributes and just returns them if it
172
* is called again without an intervening tty_set()
173
*/
174
175
int tty_get(register int fd, register struct termios *tty)
176
{
177
register Edit_t *ep = (Edit_t*)(shgd->ed_context);
178
if(fd == ep->e_savefd)
179
*tty = ep->e_savetty;
180
else
181
{
182
while(tcgetattr(fd,tty) == SYSERR)
183
{
184
if(errno !=EINTR)
185
return(SYSERR);
186
errno = 0;
187
}
188
/* save terminal settings if in cannonical state */
189
if(ep->e_raw==0)
190
{
191
ep->e_savetty = *tty;
192
ep->e_savefd = fd;
193
}
194
}
195
return(0);
196
}
197
198
/*
199
* Set the terminal attributes
200
* If fd<0, then current attributes are invalidated
201
*/
202
203
int tty_set(int fd, int action, struct termios *tty)
204
{
205
register Edit_t *ep = (Edit_t*)(shgd->ed_context);
206
if(fd >=0)
207
{
208
#ifdef future
209
if(ep->e_savefd>=0 && compare(&ep->e_savetty,tty,sizeof(struct termios)))
210
return(0);
211
#endif
212
while(tcsetattr(fd, action, tty) == SYSERR)
213
{
214
if(errno !=EINTR)
215
return(SYSERR);
216
errno = 0;
217
}
218
ep->e_savetty = *tty;
219
}
220
ep->e_savefd = fd;
221
return(0);
222
}
223
224
#if SHOPT_ESH || SHOPT_VSH
225
/*{ TTY_COOKED( fd )
226
*
227
* This routine will set the tty in cooked mode.
228
* It is also called by error.done().
229
*
230
}*/
231
232
void tty_cooked(register int fd)
233
{
234
register Edit_t *ep = (Edit_t*)(shgd->ed_context);
235
ep->e_keytrap = 0;
236
if(ep->e_raw==0)
237
return;
238
if(fd < 0)
239
fd = ep->e_savefd;
240
#ifdef L_MASK
241
/* restore flags */
242
if(l_changed&L_MASK)
243
ioctl(fd,TIOCLSET,&l_mask);
244
if(l_changed&T_CHARS)
245
/* restore alternate break character */
246
ioctl(fd,TIOCSETC,&l_ttychars);
247
if(l_changed&L_CHARS)
248
/* restore alternate break character */
249
ioctl(fd,TIOCSLTC,&l_chars);
250
l_changed = 0;
251
#endif /* L_MASK */
252
/*** don't do tty_set unless ttyparm has valid data ***/
253
if(tty_set(fd, TCSANOW, &ttyparm) == SYSERR)
254
return;
255
ep->e_raw = 0;
256
return;
257
}
258
259
/*{ TTY_RAW( fd )
260
*
261
* This routine will set the tty in raw mode.
262
*
263
}*/
264
265
int tty_raw(register int fd, int echomode)
266
{
267
int echo = echomode;
268
#ifdef L_MASK
269
struct ltchars lchars;
270
#endif /* L_MASK */
271
register Edit_t *ep = (Edit_t*)(shgd->ed_context);
272
if(ep->e_raw==RAWMODE)
273
return(echo?-1:0);
274
else if(ep->e_raw==ECHOMODE)
275
return(echo?0:-1);
276
#if !SHOPT_RAWONLY
277
if(ep->e_raw != ALTMODE)
278
#endif /* SHOPT_RAWONLY */
279
{
280
if(tty_get(fd,&ttyparm) == SYSERR)
281
return(-1);
282
}
283
#if L_MASK || VENIX
284
if(ttyparm.sg_flags&LCASE)
285
return(-1);
286
if(!(ttyparm.sg_flags&ECHO))
287
{
288
if(!echomode)
289
return(-1);
290
echo = 0;
291
}
292
nttyparm = ttyparm;
293
if(!echo)
294
nttyparm.sg_flags &= ~(ECHO | TBDELAY);
295
# ifdef CBREAK
296
nttyparm.sg_flags |= CBREAK;
297
# else
298
nttyparm.sg_flags |= RAW;
299
# endif /* CBREAK */
300
ep->e_erase = ttyparm.sg_erase;
301
ep->e_kill = ttyparm.sg_kill;
302
ep->e_eof = cntl('D');
303
ep->e_werase = cntl('W');
304
ep->e_lnext = cntl('V');
305
if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
306
return(-1);
307
ep->e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
308
# ifdef TIOCGLTC
309
/* try to remove effect of ^V and ^Y and ^O */
310
if(ioctl(fd,TIOCGLTC,&l_chars) != SYSERR)
311
{
312
lchars = l_chars;
313
lchars.t_lnextc = -1;
314
lchars.t_flushc = -1;
315
lchars.t_dsuspc = -1; /* no delayed stop process signal */
316
if(ioctl(fd,TIOCSLTC,&lchars) != SYSERR)
317
l_changed |= L_CHARS;
318
}
319
# endif /* TIOCGLTC */
320
#else
321
if (!(ttyparm.c_lflag & ECHO ))
322
{
323
if(!echomode)
324
return(-1);
325
echo = 0;
326
}
327
# ifdef FLUSHO
328
ttyparm.c_lflag &= ~FLUSHO;
329
# endif /* FLUSHO */
330
nttyparm = ttyparm;
331
# ifndef u370
332
nttyparm.c_iflag &= ~(IGNPAR|PARMRK|INLCR|IGNCR|ICRNL);
333
nttyparm.c_iflag |= BRKINT;
334
# else
335
nttyparm.c_iflag &=
336
~(IGNBRK|PARMRK|INLCR|IGNCR|ICRNL|INPCK);
337
nttyparm.c_iflag |= (BRKINT|IGNPAR);
338
# endif /* u370 */
339
if(echo)
340
nttyparm.c_lflag &= ~(ICANON);
341
else
342
nttyparm.c_lflag &= ~(ICANON|ISIG|ECHO|ECHOK);
343
nttyparm.c_cc[VTIME] = 0;
344
nttyparm.c_cc[VMIN] = 1;
345
# ifdef VREPRINT
346
nttyparm.c_cc[VREPRINT] = _POSIX_DISABLE;
347
# endif /* VREPRINT */
348
# ifdef VDISCARD
349
nttyparm.c_cc[VDISCARD] = _POSIX_DISABLE;
350
# endif /* VDISCARD */
351
# ifdef VDSUSP
352
nttyparm.c_cc[VDSUSP] = _POSIX_DISABLE;
353
# endif /* VDSUSP */
354
# ifdef VWERASE
355
if(ttyparm.c_cc[VWERASE] == _POSIX_DISABLE)
356
ep->e_werase = cntl('W');
357
else
358
ep->e_werase = nttyparm.c_cc[VWERASE];
359
nttyparm.c_cc[VWERASE] = _POSIX_DISABLE;
360
# else
361
ep->e_werase = cntl('W');
362
# endif /* VWERASE */
363
# ifdef VLNEXT
364
if(ttyparm.c_cc[VLNEXT] == _POSIX_DISABLE )
365
ep->e_lnext = cntl('V');
366
else
367
ep->e_lnext = nttyparm.c_cc[VLNEXT];
368
nttyparm.c_cc[VLNEXT] = _POSIX_DISABLE;
369
# else
370
ep->e_lnext = cntl('V');
371
# endif /* VLNEXT */
372
ep->e_intr = ttyparm.c_cc[VINTR];
373
ep->e_eof = ttyparm.c_cc[VEOF];
374
ep->e_erase = ttyparm.c_cc[VERASE];
375
ep->e_kill = ttyparm.c_cc[VKILL];
376
if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
377
return(-1);
378
ep->e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW);
379
#endif
380
ep->e_raw = (echomode?ECHOMODE:RAWMODE);
381
return(0);
382
}
383
384
#if !SHOPT_RAWONLY
385
386
/*
387
*
388
* Get tty parameters and make ESC and '\r' wakeup characters.
389
*
390
*/
391
392
# ifdef TIOCGETC
393
int tty_alt(register int fd)
394
{
395
register Edit_t *ep = (Edit_t*)(shgd->ed_context);
396
int mask;
397
struct tchars ttychars;
398
switch(ep->e_raw)
399
{
400
case ECHOMODE:
401
return(-1);
402
case ALTMODE:
403
return(0);
404
case RAWMODE:
405
tty_cooked(fd);
406
}
407
l_changed = 0;
408
if( ep->e_ttyspeed == 0)
409
{
410
if((tty_get(fd,&ttyparm) != SYSERR))
411
ep->e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
412
ep->e_raw = ALTMODE;
413
}
414
if(ioctl(fd,TIOCGETC,&l_ttychars) == SYSERR)
415
return(-1);
416
if(ioctl(fd,TIOCLGET,&l_mask)==SYSERR)
417
return(-1);
418
ttychars = l_ttychars;
419
mask = LCRTBS|LCRTERA|LCTLECH|LPENDIN|LCRTKIL;
420
if((l_mask|mask) != l_mask)
421
l_changed = L_MASK;
422
if(ioctl(fd,TIOCLBIS,&mask)==SYSERR)
423
return(-1);
424
if(ttychars.t_brkc!=ESC)
425
{
426
ttychars.t_brkc = ESC;
427
l_changed |= T_CHARS;
428
if(ioctl(fd,TIOCSETC,&ttychars) == SYSERR)
429
return(-1);
430
}
431
return(0);
432
}
433
# else
434
# ifndef PENDIN
435
# define PENDIN 0
436
# endif /* PENDIN */
437
# ifndef IEXTEN
438
# define IEXTEN 0
439
# endif /* IEXTEN */
440
441
int tty_alt(register int fd)
442
{
443
register Edit_t *ep = (Edit_t*)(shgd->ed_context);
444
switch(ep->e_raw)
445
{
446
case ECHOMODE:
447
return(-1);
448
case ALTMODE:
449
return(0);
450
case RAWMODE:
451
tty_cooked(fd);
452
}
453
if((tty_get(fd, &ttyparm)==SYSERR) || (!(ttyparm.c_lflag&ECHO)))
454
return(-1);
455
# ifdef FLUSHO
456
ttyparm.c_lflag &= ~FLUSHO;
457
# endif /* FLUSHO */
458
nttyparm = ttyparm;
459
ep->e_eof = ttyparm.c_cc[VEOF];
460
# ifdef ECHOCTL
461
/* escape character echos as ^[ */
462
nttyparm.c_lflag |= (ECHOE|ECHOK|ECHOCTL|PENDIN|IEXTEN);
463
nttyparm.c_cc[VEOL] = ESC;
464
# else
465
/* switch VEOL2 and EOF, since EOF isn't echo'd by driver */
466
nttyparm.c_lflag |= (ECHOE|ECHOK);
467
nttyparm.c_cc[VEOF] = ESC; /* make ESC the eof char */
468
# ifdef VEOL2
469
nttyparm.c_iflag &= ~(IGNCR|ICRNL);
470
nttyparm.c_iflag |= INLCR;
471
nttyparm.c_cc[VEOL] = '\r'; /* make CR an eol char */
472
nttyparm.c_cc[VEOL2] = ep->e_eof; /* make EOF an eol char */
473
# else
474
nttyparm.c_cc[VEOL] = ep->e_eof; /* make EOF an eol char */
475
# endif /* VEOL2 */
476
# endif /* ECHOCTL */
477
# ifdef VREPRINT
478
nttyparm.c_cc[VREPRINT] = _POSIX_DISABLE;
479
# endif /* VREPRINT */
480
# ifdef VDISCARD
481
nttyparm.c_cc[VDISCARD] = _POSIX_DISABLE;
482
# endif /* VDISCARD */
483
# ifdef VWERASE
484
if(ttyparm.c_cc[VWERASE] == _POSIX_DISABLE)
485
nttyparm.c_cc[VWERASE] = cntl('W');
486
ep->e_werase = nttyparm.c_cc[VWERASE];
487
# else
488
ep->e_werase = cntl('W');
489
# endif /* VWERASE */
490
# ifdef VLNEXT
491
if(ttyparm.c_cc[VLNEXT] == _POSIX_DISABLE )
492
nttyparm.c_cc[VLNEXT] = cntl('V');
493
ep->e_lnext = nttyparm.c_cc[VLNEXT];
494
# else
495
ep->e_lnext = cntl('V');
496
# endif /* VLNEXT */
497
ep->e_erase = ttyparm.c_cc[VERASE];
498
ep->e_kill = ttyparm.c_cc[VKILL];
499
if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
500
return(-1);
501
ep->e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW);
502
ep->e_raw = ALTMODE;
503
return(0);
504
}
505
506
# endif /* TIOCGETC */
507
#endif /* SHOPT_RAWONLY */
508
509
/*
510
* ED_WINDOW()
511
*
512
* return the window size
513
*/
514
int ed_window(void)
515
{
516
int rows,cols;
517
register char *cp = nv_getval(COLUMNS);
518
if(cp)
519
cols = (int)strtol(cp, (char**)0, 10)-1;
520
else
521
{
522
astwinsize(2,&rows,&cols);
523
if(--cols <0)
524
cols = DFLTWINDOW-1;
525
}
526
if(cols < MINWINDOW)
527
cols = MINWINDOW;
528
else if(cols > MAXWINDOW)
529
cols = MAXWINDOW;
530
return(cols);
531
}
532
533
/* E_FLUSH()
534
*
535
* Flush the output buffer.
536
*
537
*/
538
539
void ed_flush(Edit_t *ep)
540
{
541
register int n = ep->e_outptr-ep->e_outbase;
542
register int fd = ERRIO;
543
if(n<=0)
544
return;
545
write(fd,ep->e_outbase,(unsigned)n);
546
ep->e_outptr = ep->e_outbase;
547
}
548
549
/*
550
* send the bell character ^G to the terminal
551
*/
552
553
void ed_ringbell(void)
554
{
555
write(ERRIO,bellchr,1);
556
}
557
558
/*
559
* send a carriage return line feed to the terminal
560
*/
561
562
void ed_crlf(register Edit_t *ep)
563
{
564
#ifdef cray
565
ed_putchar(ep,'\r');
566
#endif /* cray */
567
#ifdef u370
568
ed_putchar(ep,'\r');
569
#endif /* u370 */
570
#ifdef VENIX
571
ed_putchar(ep,'\r');
572
#endif /* VENIX */
573
ed_putchar(ep,'\n');
574
ed_flush(ep);
575
}
576
577
/* ED_SETUP( max_prompt_size )
578
*
579
* This routine sets up the prompt string
580
* The following is an unadvertised feature.
581
* Escape sequences in the prompt can be excluded from the calculated
582
* prompt length. This is accomplished as follows:
583
* - if the prompt string starts with "%\r, or contains \r%\r", where %
584
* represents any char, then % is taken to be the quote character.
585
* - strings enclosed by this quote character, and the quote character,
586
* are not counted as part of the prompt length.
587
*/
588
589
void ed_setup(register Edit_t *ep, int fd, int reedit)
590
{
591
Shell_t *shp = ep->sh;
592
register char *pp;
593
register char *last, *prev;
594
char *ppmax;
595
int myquote = 0, n;
596
register int qlen = 1, qwid;
597
char inquote = 0;
598
ep->e_fd = fd;
599
ep->e_multiline = sh_isoption(SH_MULTILINE)!=0;
600
#ifdef SIGWINCH
601
if(!(shp->sigflag[SIGWINCH]&SH_SIGFAULT))
602
{
603
signal(SIGWINCH,sh_fault);
604
shp->sigflag[SIGWINCH] |= SH_SIGFAULT;
605
}
606
pp = shp->st.trapcom[SIGWINCH];
607
shp->st.trapcom[SIGWINCH] = 0;
608
sh_fault(SIGWINCH);
609
shp->st.trapcom[SIGWINCH] = pp;
610
ep->sh->winch = 0;
611
#endif
612
#if SHOPT_EDPREDICT
613
ep->hlist = 0;
614
ep->nhlist = 0;
615
ep->hoff = 0;
616
#endif /* SHOPT_EDPREDICT */
617
#if KSHELL
618
ep->e_stkptr = stakptr(0);
619
ep->e_stkoff = staktell();
620
if(!(last = shp->prompt))
621
last = "";
622
shp->prompt = 0;
623
#else
624
last = ep->e_prbuff;
625
#endif /* KSHELL */
626
if(shp->gd->hist_ptr)
627
{
628
register History_t *hp = shp->gd->hist_ptr;
629
ep->e_hismax = hist_max(hp);
630
ep->e_hismin = hist_min(hp);
631
}
632
else
633
{
634
ep->e_hismax = ep->e_hismin = ep->e_hloff = 0;
635
}
636
ep->e_hline = ep->e_hismax;
637
if(!sh_isoption(SH_VI) && !sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS))
638
ep->e_wsize = MAXLINE;
639
else
640
ep->e_wsize = ed_window()-2;
641
ep->e_winsz = ep->e_wsize+2;
642
ep->e_crlf = 1;
643
ep->e_plen = 0;
644
pp = ep->e_prompt;
645
ppmax = pp+PRSIZE-1;
646
*pp++ = '\r';
647
{
648
register int c;
649
while(prev = last, c = mbchar(last)) switch(c)
650
{
651
case ESC:
652
{
653
int skip=0;
654
ep->e_crlf = 0;
655
*pp++ = c;
656
for(n=1; c = *last++; n++)
657
{
658
if(pp < ppmax)
659
*pp++ = c;
660
if(c=='\a' || c==ESC || c=='\r')
661
break;
662
if(skip || (c>='0' && c<='9'))
663
{
664
skip = 0;
665
continue;
666
}
667
if(n>1 && c==';')
668
skip = 1;
669
else if(n>2 || (c!= '[' && c!= ']'))
670
break;
671
}
672
if(c==0 || c==ESC || c=='\r')
673
last--;
674
qlen += (n+1);
675
break;
676
}
677
case '\b':
678
if(pp>ep->e_prompt+1)
679
pp--;
680
break;
681
case '\r':
682
if(pp == (ep->e_prompt+2)) /* quote char */
683
myquote = *(pp-1);
684
/*FALLTHROUGH*/
685
686
case '\n':
687
/* start again */
688
ep->e_crlf = 1;
689
qlen = 1;
690
inquote = 0;
691
pp = ep->e_prompt+1;
692
break;
693
694
case '\t':
695
/* expand tabs */
696
while((pp-ep->e_prompt)%TABSIZE)
697
{
698
if(pp >= ppmax)
699
break;
700
*pp++ = ' ';
701
}
702
break;
703
704
case '\a':
705
/* cut out bells */
706
break;
707
708
default:
709
if(c==myquote)
710
{
711
qlen += inquote;
712
inquote ^= 1;
713
}
714
if(pp < ppmax)
715
{
716
if(inquote)
717
qlen++;
718
else if(!is_print(c))
719
ep->e_crlf = 0;
720
if((qwid = last - prev) > 1)
721
qlen += qwid - mbwidth(c);
722
while(prev < last && pp < ppmax)
723
*pp++ = *prev++;
724
}
725
break;
726
}
727
}
728
if(pp-ep->e_prompt > qlen)
729
ep->e_plen = pp - ep->e_prompt - qlen;
730
*pp = 0;
731
if(!ep->e_multiline && (ep->e_wsize -= ep->e_plen) < 7)
732
{
733
register int shift = 7-ep->e_wsize;
734
ep->e_wsize = 7;
735
pp = ep->e_prompt+1;
736
strcpy(pp,pp+shift);
737
ep->e_plen -= shift;
738
last[-ep->e_plen-2] = '\r';
739
}
740
sfsync(sfstderr);
741
if(fd == sffileno(sfstderr))
742
{
743
/* can't use output buffer when reading from stderr */
744
static char *buff;
745
if(!buff)
746
buff = (char*)malloc(MAXLINE);
747
ep->e_outbase = ep->e_outptr = buff;
748
ep->e_outlast = ep->e_outptr + MAXLINE;
749
return;
750
}
751
qlen = sfset(sfstderr,SF_READ,0);
752
/* make sure SF_READ not on */
753
ep->e_outbase = ep->e_outptr = (char*)sfreserve(sfstderr,SF_UNBOUND,SF_LOCKR);
754
ep->e_outlast = ep->e_outptr + sfvalue(sfstderr);
755
if(qlen)
756
sfset(sfstderr,SF_READ,1);
757
sfwrite(sfstderr,ep->e_outptr,0);
758
ep->e_eol = reedit;
759
if(ep->e_multiline)
760
{
761
#ifdef _cmd_tput
762
char *term;
763
if(!ep->e_term)
764
ep->e_term = nv_search("TERM",shp->var_tree,0);
765
if(ep->e_term && (term=nv_getval(ep->e_term)) && strlen(term)<sizeof(ep->e_termname) && strcmp(term,ep->e_termname))
766
{
767
sh_trap(".sh.subscript=$(tput cuu1 2>/dev/null)",0);
768
if(pp=nv_getval(SH_SUBSCRNOD))
769
strncpy(CURSOR_UP,pp,sizeof(CURSOR_UP)-1);
770
nv_unset(SH_SUBSCRNOD);
771
strcpy(ep->e_termname,term);
772
}
773
#endif
774
ep->e_wsize = MAXLINE - (ep->e_plen+1);
775
}
776
if(ep->e_default && (pp = nv_getval(ep->e_default)))
777
{
778
n = strlen(pp);
779
if(n > LOOKAHEAD)
780
n = LOOKAHEAD;
781
ep->e_lookahead = n;
782
while(n-- > 0)
783
ep->e_lbuf[n] = *pp++;
784
ep->e_default = 0;
785
}
786
}
787
788
static void ed_putstring(register Edit_t *ep, const char *str)
789
{
790
register int c;
791
while(c = *str++)
792
ed_putchar(ep,c);
793
}
794
795
static void ed_nputchar(register Edit_t *ep, int n, int c)
796
{
797
while(n-->0)
798
ed_putchar(ep,c);
799
}
800
801
/*
802
* Do read, restart on interrupt unless SH_SIGSET or SH_SIGTRAP is set
803
* Use sfpkrd() to poll() or select() to wait for input if possible
804
* Unfortunately, systems that get interrupted from slow reads update
805
* this access time for for the terminal (in violation of POSIX).
806
* The fixtime() macro, resets the time to the time at entry in
807
* this case. This is not necessary for systems that can handle
808
* sfpkrd() correctly (i,e., those that support poll() or select()
809
*/
810
int ed_read(void *context, int fd, char *buff, int size, int reedit)
811
{
812
register Edit_t *ep = (Edit_t*)context;
813
register int rv= -1;
814
register int delim = ((ep->e_raw&RAWMODE)?nttyparm.c_cc[VEOL]:'\n');
815
Shell_t *shp = ep->sh;
816
int mode = -1;
817
int (*waitevent)(int,long,int) = shp->gd->waitevent;
818
if(ep->e_raw==ALTMODE)
819
mode = 1;
820
if(size < 0)
821
{
822
mode = 1;
823
size = -size;
824
}
825
sh_onstate(SH_TTYWAIT);
826
errno = EINTR;
827
shp->gd->waitevent = 0;
828
while(rv<0 && errno==EINTR)
829
{
830
if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
831
goto done;
832
if(ep->sh->winch && sh_isstate(SH_INTERACTIVE) && (sh_isoption(SH_VI) || sh_isoption(SH_EMACS)))
833
{
834
Edpos_t lastpos;
835
int n, rows, newsize;
836
/* move cursor to start of first line */
837
ed_putchar(ep,'\r');
838
ed_flush(ep);
839
astwinsize(2,&rows,&newsize);
840
n = (ep->e_plen+ep->e_cur)/++ep->e_winsz;
841
while(n--)
842
ed_putstring(ep,CURSOR_UP);
843
if(ep->e_multiline && newsize>ep->e_winsz && (lastpos.line=(ep->e_plen+ep->e_peol)/ep->e_winsz))
844
{
845
/* clear the current command line */
846
n = lastpos.line;
847
while(lastpos.line--)
848
{
849
ed_nputchar(ep,ep->e_winsz,' ');
850
ed_putchar(ep,'\n');
851
}
852
ed_nputchar(ep,ep->e_winsz,' ');
853
while(n--)
854
ed_putstring(ep,CURSOR_UP);
855
}
856
ep->sh->winch = 0;
857
ed_flush(ep);
858
sh_delay(.05);
859
astwinsize(2,&rows,&newsize);
860
ep->e_winsz = newsize-1;
861
if(ep->e_winsz < MINWINDOW)
862
ep->e_winsz = MINWINDOW;
863
if(!ep->e_multiline && ep->e_wsize < MAXLINE)
864
ep->e_wsize = ep->e_winsz-2;
865
ep->e_nocrnl=1;
866
if(*ep->e_vi_insert)
867
{
868
buff[0] = ESC;
869
buff[1] = cntl('L');
870
buff[2] = 'a';
871
return(3);
872
}
873
if(sh_isoption(SH_EMACS) || sh_isoption(SH_VI))
874
buff[0] = cntl('L');
875
return(1);
876
}
877
else
878
ep->sh->winch = 0;
879
/* an interrupt that should be ignored */
880
errno = 0;
881
if(!waitevent || (rv=(*waitevent)(fd,-1L,0))>=0)
882
rv = sfpkrd(fd,buff,size,delim,-1L,mode);
883
}
884
if(rv < 0)
885
{
886
#ifdef _hdr_utime
887
# define fixtime() if(isdevtty)utime(ep->e_tty,&utimes)
888
int isdevtty=0;
889
struct stat statb;
890
struct utimbuf utimes;
891
if(errno==0 && !ep->e_tty)
892
{
893
if((ep->e_tty=ttyname(fd)) && stat(ep->e_tty,&statb)>=0)
894
{
895
ep->e_tty_ino = statb.st_ino;
896
ep->e_tty_dev = statb.st_dev;
897
}
898
}
899
if(ep->e_tty_ino && fstat(fd,&statb)>=0 && statb.st_ino==ep->e_tty_ino && statb.st_dev==ep->e_tty_dev)
900
{
901
utimes.actime = statb.st_atime;
902
utimes.modtime = statb.st_mtime;
903
isdevtty=1;
904
}
905
#else
906
# define fixtime()
907
#endif /* _hdr_utime */
908
while(1)
909
{
910
rv = read(fd,buff,size);
911
if(rv>=0 || errno!=EINTR)
912
break;
913
if(shp->trapnote&(SH_SIGSET|SH_SIGTRAP))
914
goto done;
915
/* an interrupt that should be ignored */
916
fixtime();
917
}
918
}
919
else if(rv>=0 && mode>0)
920
rv = read(fd,buff,rv>0?rv:1);
921
done:
922
shp->gd->waitevent = waitevent;
923
sh_offstate(SH_TTYWAIT);
924
return(rv);
925
}
926
927
928
/*
929
* put <string> of length <nbyte> onto lookahead stack
930
* if <type> is non-zero, the negation of the character is put
931
* onto the stack so that it can be checked for KEYTRAP
932
* putstack() returns 1 except when in the middle of a multi-byte char
933
*/
934
static int putstack(Edit_t *ep,char string[], register int nbyte, int type)
935
{
936
register int c;
937
#if SHOPT_MULTIBYTE
938
char *endp, *p=string;
939
int size, offset = ep->e_lookahead + nbyte;
940
*(endp = &p[nbyte]) = 0;
941
endp = &p[nbyte];
942
do
943
{
944
c = (int)((*p) & STRIP);
945
if(c< 0x80 && c!='<')
946
{
947
if (type)
948
c = -c;
949
# ifndef CBREAK
950
if(c == '\0')
951
{
952
/*** user break key ***/
953
ep->e_lookahead = 0;
954
# if KSHELL
955
sh_fault(SIGINT);
956
siglongjmp(ep->e_env, UINTR);
957
# endif /* KSHELL */
958
}
959
# endif /* CBREAK */
960
961
}
962
else
963
{
964
again:
965
if((c=mbchar(p)) >=0)
966
{
967
p--; /* incremented below */
968
if(type)
969
c = -c;
970
}
971
#ifdef EILSEQ
972
else if(errno == EILSEQ)
973
errno = 0;
974
#endif
975
else if((endp-p) < mbmax())
976
{
977
if ((c=ed_read(ep,ep->e_fd,endp, 1,0)) == 1)
978
{
979
*++endp = 0;
980
goto again;
981
}
982
return(c);
983
}
984
else
985
{
986
ed_ringbell();
987
c = -(int)((*p) & STRIP);
988
offset += mbmax()-1;
989
}
990
}
991
ep->e_lbuf[--offset] = c;
992
p++;
993
}
994
while (p < endp);
995
/* shift lookahead buffer if necessary */
996
if(offset -= ep->e_lookahead)
997
{
998
for(size=offset;size < nbyte;size++)
999
ep->e_lbuf[ep->e_lookahead+size-offset] = ep->e_lbuf[ep->e_lookahead+size];
1000
}
1001
ep->e_lookahead += nbyte-offset;
1002
#else
1003
while (nbyte > 0)
1004
{
1005
c = string[--nbyte] & STRIP;
1006
ep->e_lbuf[ep->e_lookahead++] = (type?-c:c);
1007
# ifndef CBREAK
1008
if( c == '\0' )
1009
{
1010
/*** user break key ***/
1011
ep->e_lookahead = 0;
1012
# if KSHELL
1013
sh_fault(SIGINT);
1014
siglongjmp(ep->e_env, UINTR);
1015
# endif /* KSHELL */
1016
}
1017
# endif /* CBREAK */
1018
}
1019
#endif /* SHOPT_MULTIBYTE */
1020
return(1);
1021
}
1022
1023
/*
1024
* routine to perform read from terminal for vi and emacs mode
1025
* <mode> can be one of the following:
1026
* -2 vi insert mode - key binding is in effect
1027
* -1 vi control mode - key binding is in effect
1028
* 0 normal command mode - key binding is in effect
1029
* 1 edit keys not mapped
1030
* 2 Next key is literal
1031
*/
1032
int ed_getchar(register Edit_t *ep,int mode)
1033
{
1034
register int n, c;
1035
char readin[LOOKAHEAD+1];
1036
if(!ep->e_lookahead)
1037
{
1038
ed_flush(ep);
1039
ep->e_inmacro = 0;
1040
/* The while is necessary for reads of partial multbyte chars */
1041
*ep->e_vi_insert = (mode==-2);
1042
if((n=ed_read(ep,ep->e_fd,readin,-LOOKAHEAD,0)) > 0)
1043
n = putstack(ep,readin,n,1);
1044
*ep->e_vi_insert = 0;
1045
}
1046
if(ep->e_lookahead)
1047
{
1048
/* check for possible key mapping */
1049
if((c = ep->e_lbuf[--ep->e_lookahead]) < 0)
1050
{
1051
if(mode<=0 && -c == ep->e_intr)
1052
{
1053
sh_fault(SIGINT);
1054
siglongjmp(ep->e_env, UINTR);
1055
}
1056
if(mode<=0 && ep->sh->st.trap[SH_KEYTRAP])
1057
{
1058
ep->e_keytrap = 1;
1059
n=1;
1060
if((readin[0]= -c) == ESC)
1061
{
1062
while(1)
1063
{
1064
if(!ep->e_lookahead)
1065
{
1066
if((c=sfpkrd(ep->e_fd,readin+n,1,'\r',(mode?400L:-1L),0))>0)
1067
putstack(ep,readin+n,c,1);
1068
}
1069
if(!ep->e_lookahead)
1070
break;
1071
if((c=ep->e_lbuf[--ep->e_lookahead])>=0)
1072
{
1073
ep->e_lookahead++;
1074
break;
1075
}
1076
c = -c;
1077
readin[n++] = c;
1078
if(c>='0' && c<='9' && n>2)
1079
continue;
1080
if(n>2 || (c!= '[' && c!= 'O'))
1081
break;
1082
}
1083
}
1084
if(n=keytrap(ep,readin,n,LOOKAHEAD-n,mode))
1085
{
1086
putstack(ep,readin,n,0);
1087
c = ep->e_lbuf[--ep->e_lookahead];
1088
}
1089
else
1090
c = ed_getchar(ep,mode);
1091
ep->e_keytrap = 0;
1092
}
1093
else
1094
c = -c;
1095
}
1096
/*** map '\r' to '\n' ***/
1097
if(c == '\r' && mode!=2)
1098
c = '\n';
1099
if(ep->e_tabcount && !(c=='\t'||c==ESC || c=='\\' || c=='=' || c==cntl('L') || isdigit(c)))
1100
ep->e_tabcount = 0;
1101
}
1102
else
1103
siglongjmp(ep->e_env,(n==0?UEOF:UINTR));
1104
return(c);
1105
}
1106
1107
void ed_ungetchar(Edit_t *ep,register int c)
1108
{
1109
if (ep->e_lookahead < LOOKAHEAD)
1110
ep->e_lbuf[ep->e_lookahead++] = c;
1111
return;
1112
}
1113
1114
/*
1115
* put a character into the output buffer
1116
*/
1117
1118
void ed_putchar(register Edit_t *ep,register int c)
1119
{
1120
char buf[8];
1121
register char *dp = ep->e_outptr;
1122
register int i,size=1;
1123
if(!dp)
1124
return;
1125
buf[0] = c;
1126
#if SHOPT_MULTIBYTE
1127
/* check for place holder */
1128
if(c == MARKER)
1129
return;
1130
if((size = mbconv(buf, (wchar_t)c)) > 1)
1131
{
1132
for (i = 0; i < (size-1); i++)
1133
*dp++ = buf[i];
1134
c = buf[i];
1135
}
1136
else
1137
{
1138
buf[0] = c;
1139
size = 1;
1140
}
1141
#endif /* SHOPT_MULTIBYTE */
1142
if (buf[0] == '_' && size==1)
1143
{
1144
*dp++ = ' ';
1145
*dp++ = '\b';
1146
}
1147
*dp++ = c;
1148
*dp = '\0';
1149
if(dp >= ep->e_outlast)
1150
ed_flush(ep);
1151
else
1152
ep->e_outptr = dp;
1153
}
1154
1155
/*
1156
* returns the line and column corresponding to offset <off> in the physical buffer
1157
* if <cur> is non-zero and <= <off>, then correspodning <curpos> will start the search
1158
*/
1159
Edpos_t ed_curpos(Edit_t *ep,genchar *phys, int off, int cur, Edpos_t curpos)
1160
{
1161
register genchar *sp=phys;
1162
register int c=1, col=ep->e_plen;
1163
Edpos_t pos;
1164
#if SHOPT_MULTIBYTE
1165
char p[16];
1166
#endif /* SHOPT_MULTIBYTE */
1167
if(cur && off>=cur)
1168
{
1169
sp += cur;
1170
off -= cur;
1171
pos = curpos;
1172
col = pos.col;
1173
}
1174
else
1175
{
1176
pos.line = 0;
1177
while(col > ep->e_winsz)
1178
{
1179
pos.line++;
1180
col -= (ep->e_winsz+1);
1181
}
1182
}
1183
while(off-->0)
1184
{
1185
if(c)
1186
c = *sp++;
1187
#if SHOPT_MULTIBYTE
1188
if(c && (mbconv(p, (wchar_t)c))==1 && p[0]=='\n')
1189
#else
1190
if(c=='\n')
1191
#endif /* SHOPT_MULTIBYTE */
1192
col = 0;
1193
else
1194
col++;
1195
if(col > ep->e_winsz)
1196
col = 0;
1197
if(col==0)
1198
pos.line++;
1199
}
1200
pos.col = col;
1201
return(pos);
1202
}
1203
1204
int ed_setcursor(register Edit_t *ep,genchar *physical,register int old,register int new,int first)
1205
{
1206
static int oldline;
1207
register int delta;
1208
int clear = 0;
1209
Edpos_t newpos;
1210
1211
delta = new - old;
1212
if(first < 0)
1213
{
1214
first = 0;
1215
clear = 1;
1216
}
1217
if( delta == 0 && !clear)
1218
return(new);
1219
if(ep->e_multiline)
1220
{
1221
ep->e_curpos = ed_curpos(ep, physical, old,0,ep->e_curpos);
1222
if(clear && old>=ep->e_peol && (clear=ep->e_winsz-ep->e_curpos.col)>0)
1223
{
1224
ed_nputchar(ep,clear,' ');
1225
ed_nputchar(ep,clear,'\b');
1226
return(new);
1227
}
1228
newpos = ed_curpos(ep, physical, new,old,ep->e_curpos);
1229
if(ep->e_curpos.col==0 && ep->e_curpos.line>0 && oldline<ep->e_curpos.line && delta<0)
1230
ed_putstring(ep,"\r\n");
1231
oldline = newpos.line;
1232
if(ep->e_curpos.line > newpos.line)
1233
{
1234
int n,pline,plen=ep->e_plen;
1235
for(;ep->e_curpos.line > newpos.line; ep->e_curpos.line--)
1236
ed_putstring(ep,CURSOR_UP);
1237
pline = plen/(ep->e_winsz+1);
1238
if(newpos.line <= pline)
1239
plen -= pline*(ep->e_winsz+1);
1240
else
1241
plen = 0;
1242
if((n=plen- ep->e_curpos.col)>0)
1243
{
1244
ep->e_curpos.col += n;
1245
ed_putchar(ep,'\r');
1246
if(!ep->e_crlf && pline==0)
1247
ed_putstring(ep,ep->e_prompt);
1248
else
1249
{
1250
int m = ep->e_winsz+1-plen;
1251
ed_putchar(ep,'\n');
1252
n = plen;
1253
if(m < ed_genlen(physical))
1254
{
1255
while(physical[m] && n-->0)
1256
ed_putchar(ep,physical[m++]);
1257
}
1258
ed_nputchar(ep,n,' ');
1259
ed_putstring(ep,CURSOR_UP);
1260
}
1261
}
1262
}
1263
else if(ep->e_curpos.line < newpos.line)
1264
{
1265
ed_nputchar(ep, newpos.line-ep->e_curpos.line,'\n');
1266
ep->e_curpos.line = newpos.line;
1267
ed_putchar(ep,'\r');
1268
ep->e_curpos.col = 0;
1269
}
1270
delta = newpos.col - ep->e_curpos.col;
1271
old = new - delta;
1272
}
1273
else
1274
newpos.line=0;
1275
if(delta<0)
1276
{
1277
int bs= newpos.line && ep->e_plen>ep->e_winsz;
1278
/*** move to left ***/
1279
delta = -delta;
1280
/*** attempt to optimize cursor movement ***/
1281
if(!ep->e_crlf || bs || (2*delta <= ((old-first)+(newpos.line?0:ep->e_plen))) )
1282
{
1283
ed_nputchar(ep,delta,'\b');
1284
delta = 0;
1285
}
1286
else
1287
{
1288
if(newpos.line==0)
1289
ed_putstring(ep,ep->e_prompt);
1290
else
1291
{
1292
first = 1+(newpos.line*ep->e_winsz - ep->e_plen);
1293
ed_putchar(ep,'\r');
1294
}
1295
old = first;
1296
delta = new-first;
1297
}
1298
}
1299
while(delta-->0)
1300
ed_putchar(ep,physical[old++]);
1301
return(new);
1302
}
1303
1304
/*
1305
* copy virtual to physical and return the index for cursor in physical buffer
1306
*/
1307
int ed_virt_to_phys(Edit_t *ep,genchar *virt,genchar *phys,int cur,int voff,int poff)
1308
{
1309
register genchar *sp = virt;
1310
register genchar *dp = phys;
1311
register int c;
1312
genchar *curp = sp + cur;
1313
genchar *dpmax = phys+MAXLINE;
1314
int d, r;
1315
sp += voff;
1316
dp += poff;
1317
for(r=poff;c= *sp;sp++)
1318
{
1319
if(curp == sp)
1320
r = dp - phys;
1321
#if SHOPT_MULTIBYTE
1322
d = mbwidth((wchar_t)c);
1323
if(d==1 && is_cntrl(c))
1324
d = -1;
1325
if(d>1)
1326
{
1327
/* multiple width character put in place holders */
1328
*dp++ = c;
1329
while(--d >0)
1330
*dp++ = MARKER;
1331
/* in vi mode the cursor is at the last character */
1332
if(dp>=dpmax)
1333
break;
1334
continue;
1335
}
1336
else
1337
#else
1338
d = (is_cntrl(c)?-1:1);
1339
#endif /* SHOPT_MULTIBYTE */
1340
if(d<0)
1341
{
1342
if(c=='\t')
1343
{
1344
c = dp-phys;
1345
if(sh_isoption(SH_VI))
1346
c += ep->e_plen;
1347
c = TABSIZE - c%TABSIZE;
1348
while(--c>0)
1349
*dp++ = ' ';
1350
c = ' ';
1351
}
1352
else
1353
{
1354
*dp++ = '^';
1355
c = printchar(c);
1356
}
1357
/* in vi mode the cursor is at the last character */
1358
if(curp == sp && sh_isoption(SH_VI))
1359
r = dp - phys;
1360
}
1361
*dp++ = c;
1362
if(dp>=dpmax)
1363
break;
1364
}
1365
*dp = 0;
1366
ep->e_peol = dp-phys;
1367
return(r);
1368
}
1369
1370
#if SHOPT_MULTIBYTE
1371
/*
1372
* convert external representation <src> to an array of genchars <dest>
1373
* <src> and <dest> can be the same
1374
* returns number of chars in dest
1375
*/
1376
1377
int ed_internal(const char *src, genchar *dest)
1378
{
1379
register const unsigned char *cp = (unsigned char *)src;
1380
register int c;
1381
register wchar_t *dp = (wchar_t*)dest;
1382
if(dest == (genchar*)roundof(cp-(unsigned char*)0,sizeof(genchar)))
1383
{
1384
genchar buffer[MAXLINE];
1385
c = ed_internal(src,buffer);
1386
ed_gencpy((genchar*)dp,buffer);
1387
return(c);
1388
}
1389
while(*cp)
1390
*dp++ = mbchar(cp);
1391
*dp = 0;
1392
return(dp-(wchar_t*)dest);
1393
}
1394
1395
/*
1396
* convert internal representation <src> into character array <dest>.
1397
* The <src> and <dest> may be the same.
1398
* returns number of chars in dest.
1399
*/
1400
1401
int ed_external(const genchar *src, char *dest)
1402
{
1403
register genchar wc;
1404
register int c,size;
1405
register char *dp = dest;
1406
char *dpmax = dp+sizeof(genchar)*MAXLINE-2;
1407
if((char*)src == dp)
1408
{
1409
char buffer[MAXLINE*sizeof(genchar)];
1410
c = ed_external(src,buffer);
1411
1412
#ifdef _lib_wcscpy
1413
wcscpy((wchar_t *)dest,(const wchar_t *)buffer);
1414
#else
1415
strcpy(dest,buffer);
1416
#endif
1417
return(c);
1418
}
1419
while((wc = *src++) && dp<dpmax)
1420
{
1421
if((size = mbconv(dp, wc)) < 0)
1422
{
1423
/* copy the character as is */
1424
size = 1;
1425
*dp = wc;
1426
}
1427
dp += size;
1428
}
1429
*dp = 0;
1430
return(dp-dest);
1431
}
1432
1433
/*
1434
* copy <sp> to <dp>
1435
*/
1436
1437
void ed_gencpy(genchar *dp,const genchar *sp)
1438
{
1439
dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
1440
sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
1441
while(*dp++ = *sp++);
1442
}
1443
1444
/*
1445
* copy at most <n> items from <sp> to <dp>
1446
*/
1447
1448
void ed_genncpy(register genchar *dp,register const genchar *sp, int n)
1449
{
1450
dp = (genchar*)roundof((char*)dp-(char*)0,sizeof(genchar));
1451
sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
1452
while(n-->0 && (*dp++ = *sp++));
1453
}
1454
1455
#endif /* SHOPT_MULTIBYTE */
1456
/*
1457
* find the string length of <str>
1458
*/
1459
1460
int ed_genlen(register const genchar *str)
1461
{
1462
register const genchar *sp = str;
1463
sp = (const genchar*)roundof((char*)sp-(char*)0,sizeof(genchar));
1464
while(*sp++);
1465
return(sp-str-1);
1466
}
1467
#endif /* SHOPT_ESH || SHOPT_VSH */
1468
1469
#ifdef future
1470
/*
1471
* returns 1 when <n> bytes starting at <a> and <b> are equal
1472
*/
1473
static int compare(register const char *a,register const char *b,register int n)
1474
{
1475
while(n-->0)
1476
{
1477
if(*a++ != *b++)
1478
return(0);
1479
}
1480
return(1);
1481
}
1482
#endif
1483
1484
#if SHOPT_OLDTERMIO
1485
1486
# include <sys/termio.h>
1487
1488
#ifndef ECHOCTL
1489
# define ECHOCTL 0
1490
#endif /* !ECHOCTL */
1491
#define ott ep->e_ott
1492
1493
/*
1494
* For backward compatibility only
1495
* This version will use termios when possible, otherwise termio
1496
*/
1497
1498
int tcgetattr(int fd, struct termios *tt)
1499
{
1500
register Edit_t *ep = (Edit_t*)(shgd->ed_context);
1501
register int r,i;
1502
ep->e_tcgeta = 0;
1503
ep->e_echoctl = (ECHOCTL!=0);
1504
if((r=ioctl(fd,TCGETS,tt))>=0 || errno!=EINVAL)
1505
return(r);
1506
if((r=ioctl(fd,TCGETA,&ott)) >= 0)
1507
{
1508
tt->c_lflag = ott.c_lflag;
1509
tt->c_oflag = ott.c_oflag;
1510
tt->c_iflag = ott.c_iflag;
1511
tt->c_cflag = ott.c_cflag;
1512
for(i=0; i<NCC; i++)
1513
tt->c_cc[i] = ott.c_cc[i];
1514
ep->e_tcgeta++;
1515
ep->e_echoctl = 0;
1516
}
1517
return(r);
1518
}
1519
1520
int tcsetattr(int fd,int mode,struct termios *tt)
1521
{
1522
register Edit_t *ep = (Edit_t*)(shgd->ed_context);
1523
register int r;
1524
if(ep->e_tcgeta)
1525
{
1526
register int i;
1527
ott.c_lflag = tt->c_lflag;
1528
ott.c_oflag = tt->c_oflag;
1529
ott.c_iflag = tt->c_iflag;
1530
ott.c_cflag = tt->c_cflag;
1531
for(i=0; i<NCC; i++)
1532
ott.c_cc[i] = tt->c_cc[i];
1533
if(tt->c_lflag&ECHOCTL)
1534
{
1535
ott.c_lflag &= ~(ECHOCTL|IEXTEN);
1536
ott.c_iflag &= ~(IGNCR|ICRNL);
1537
ott.c_iflag |= INLCR;
1538
ott.c_cc[VEOF]= ESC; /* ESC -> eof char */
1539
ott.c_cc[VEOL] = '\r'; /* CR -> eol char */
1540
ott.c_cc[VEOL2] = tt->c_cc[VEOF]; /* EOF -> eol char */
1541
}
1542
switch(mode)
1543
{
1544
case TCSANOW:
1545
mode = TCSETA;
1546
break;
1547
case TCSADRAIN:
1548
mode = TCSETAW;
1549
break;
1550
case TCSAFLUSH:
1551
mode = TCSETAF;
1552
}
1553
return(ioctl(fd,mode,&ott));
1554
}
1555
return(ioctl(fd,mode,tt));
1556
}
1557
#endif /* SHOPT_OLDTERMIO */
1558
1559
#if KSHELL
1560
/*
1561
* Execute keyboard trap on given buffer <inbuff> of given size <isize>
1562
* <mode> < 0 for vi insert mode
1563
*/
1564
static int keytrap(Edit_t *ep,char *inbuff,register int insize, int bufsize, int mode)
1565
{
1566
register char *cp;
1567
int savexit;
1568
Shell_t *shp = ep->sh;
1569
#if SHOPT_MULTIBYTE
1570
char buff[MAXLINE];
1571
ed_external(ep->e_inbuf,cp=buff);
1572
#else
1573
cp = ep->e_inbuf;
1574
#endif /* SHOPT_MULTIBYTE */
1575
inbuff[insize] = 0;
1576
ep->e_col = ep->e_cur;
1577
if(mode== -2)
1578
{
1579
ep->e_col++;
1580
*ep->e_vi_insert = ESC;
1581
}
1582
else
1583
*ep->e_vi_insert = 0;
1584
nv_putval(ED_CHRNOD,inbuff,NV_NOFREE);
1585
nv_putval(ED_COLNOD,(char*)&ep->e_col,NV_NOFREE|NV_INTEGER);
1586
nv_putval(ED_TXTNOD,(char*)cp,NV_NOFREE);
1587
nv_putval(ED_MODENOD,ep->e_vi_insert,NV_NOFREE);
1588
savexit = shp->savexit;
1589
sh_trap(shp->st.trap[SH_KEYTRAP],0);
1590
shp->savexit = savexit;
1591
if((cp = nv_getval(ED_CHRNOD)) == inbuff)
1592
nv_unset(ED_CHRNOD);
1593
else if(bufsize>0)
1594
{
1595
strncpy(inbuff,cp,bufsize);
1596
inbuff[bufsize-1]='\0';
1597
insize = strlen(inbuff);
1598
}
1599
else
1600
insize = 0;
1601
nv_unset(ED_TXTNOD);
1602
return(insize);
1603
}
1604
#endif /* KSHELL */
1605
1606
#if SHOPT_EDPREDICT
1607
static int ed_sortdata(const char *s1, const char *s2)
1608
{
1609
Histmatch_t *m1 = (Histmatch_t*)s1;
1610
Histmatch_t *m2 = (Histmatch_t*)s2;
1611
return(strcmp(m1->data,m2->data));
1612
}
1613
1614
static int ed_sortindex(const char *s1, const char *s2)
1615
{
1616
Histmatch_t *m1 = (Histmatch_t*)s1;
1617
Histmatch_t *m2 = (Histmatch_t*)s2;
1618
return(m2->index-m1->index);
1619
}
1620
1621
static int ed_histlencopy(const char *cp, char *dp)
1622
{
1623
int c,n=1,col=1;
1624
const char *oldcp=cp;
1625
for(n=0;c = mbchar(cp);oldcp=cp,col++)
1626
{
1627
if(c=='\n' && *cp)
1628
{
1629
n += 2;
1630
if(dp)
1631
{
1632
*dp++ = '^';
1633
*dp++ = 'J';
1634
col +=2;
1635
}
1636
}
1637
else if(c=='\t')
1638
{
1639
n++;
1640
if(dp)
1641
*dp++ = ' ';
1642
}
1643
else
1644
{
1645
n += cp-oldcp;
1646
if(dp)
1647
{
1648
while(oldcp < cp)
1649
*dp++ = *oldcp++;
1650
}
1651
}
1652
1653
}
1654
return(n);
1655
}
1656
1657
int ed_histgen(Edit_t *ep,const char *pattern)
1658
{
1659
Histmatch_t *mp,*mplast=0;
1660
History_t *hp;
1661
off_t offset;
1662
int ac=0,l,n,index1,index2;
1663
size_t m;
1664
char *cp, **argv=0, **av, **ar;
1665
static int maxmatch;
1666
if(!(hp=ep->sh->gd->hist_ptr) && (!nv_getval(HISTFILE) || !sh_histinit(ep->sh)))
1667
return(0);
1668
if(ep->e_cur <=2)
1669
maxmatch = 0;
1670
else if(maxmatch && ep->e_cur > maxmatch)
1671
{
1672
ep->hlist = 0;
1673
ep->hfirst = 0;
1674
return(0);
1675
}
1676
hp = ep->sh->gd->hist_ptr;
1677
if(*pattern=='#' && *++pattern=='#')
1678
return(0);
1679
cp = stakalloc(m=strlen(pattern)+6);
1680
sfsprintf(cp,m,"@(%s)*%c",pattern,0);
1681
if(ep->hlist)
1682
{
1683
m = strlen(ep->hpat)-4;
1684
if(memcmp(pattern,ep->hpat+2,m)==0)
1685
{
1686
n = strcmp(cp,ep->hpat)==0;
1687
for(argv=av=(char**)ep->hlist,mp=ep->hfirst; mp;mp= mp->next)
1688
{
1689
if(n || strmatch(mp->data,cp))
1690
*av++ = (char*)mp;
1691
}
1692
*av = 0;
1693
ep->hmax = av-argv;
1694
if(ep->hmax==0)
1695
maxmatch = ep->e_cur;
1696
return(ep->hmax=av-argv);
1697
}
1698
stakset(ep->e_stkptr,ep->e_stkoff);
1699
}
1700
if((m=strlen(cp)) >= sizeof(ep->hpat))
1701
m = sizeof(ep->hpat)-1;
1702
memcpy(ep->hpat,cp,m);
1703
ep->hpat[m] = 0;
1704
pattern = cp;
1705
index1 = (int)hp->histind;
1706
for(index2=index1-hp->histsize; index1>index2; index1--)
1707
{
1708
offset = hist_tell(hp,index1);
1709
sfseek(hp->histfp,offset,SEEK_SET);
1710
if(!(cp = sfgetr(hp->histfp,0,0)))
1711
continue;
1712
if(*cp=='#')
1713
continue;
1714
if(strmatch(cp,pattern))
1715
{
1716
l = ed_histlencopy(cp,(char*)0);
1717
mp = (Histmatch_t*)stakalloc(sizeof(Histmatch_t)+l);
1718
mp->next = mplast;
1719
mplast = mp;
1720
mp->len = l;
1721
ed_histlencopy(cp,mp->data);
1722
mp->count = 1;
1723
mp->data[l] = 0;
1724
mp->index = index1;
1725
ac++;
1726
}
1727
}
1728
if(ac>0)
1729
{
1730
l = ac;
1731
argv = av = (char**)stakalloc((ac+1)*sizeof(char*));
1732
for(mplast=0; l>=0 && (*av= (char*)mp); mplast=mp,mp=mp->next,av++)
1733
{
1734
l--;
1735
}
1736
*av = 0;
1737
strsort(argv,ac,ed_sortdata);
1738
mplast = (Histmatch_t*)argv[0];
1739
for(ar= av= &argv[1]; mp=(Histmatch_t*)*av; av++)
1740
{
1741
if(strcmp(mp->data,mplast->data)==0)
1742
{
1743
mplast->count++;
1744
if(mp->index> mplast->index)
1745
mplast->index = mp->index;
1746
continue;
1747
}
1748
*ar++ = (char*)(mplast=mp);
1749
}
1750
*ar = 0;
1751
mplast->next = 0;
1752
ac = ar-argv;
1753
strsort(argv,ac,ed_sortindex);
1754
mplast = (Histmatch_t*)argv[0];
1755
for(av= &argv[1]; mp=(Histmatch_t*)*av; av++, mplast=mp)
1756
mplast->next = mp;
1757
mplast->next = 0;
1758
}
1759
ep->hlist = (Histmatch_t**)argv;
1760
ep->hfirst = ep->hlist?ep->hlist[0]:0;
1761
return(ep->hmax=ac);
1762
}
1763
1764
void ed_histlist(Edit_t *ep,int n)
1765
{
1766
Histmatch_t *mp,**mpp = ep->hlist+ep->hoff;
1767
int i,last=0,save[2];
1768
if(n)
1769
{
1770
/* don't bother updating the screen if there is typeahead */
1771
if(!ep->e_lookahead && sfpkrd(ep->e_fd,save,1,'\r',200L,-1)>0)
1772
ed_ungetchar(ep,save[0]);
1773
if(ep->e_lookahead)
1774
return;
1775
ed_putchar(ep,'\n');
1776
ed_putchar(ep,'\r');
1777
}
1778
else
1779
{
1780
stakset(ep->e_stkptr,ep->e_stkoff);
1781
ep->hlist = 0;
1782
ep->nhlist = 0;
1783
}
1784
ed_putstring(ep,KILL_LINE);
1785
if(n)
1786
{
1787
for(i=1; (mp= *mpp) && i <= 16 ; i++,mpp++)
1788
{
1789
last = 0;
1790
if(mp->len >= ep->e_winsz-4)
1791
{
1792
last = ep->e_winsz-4;
1793
save[0] = mp->data[last-1];
1794
save[1] = mp->data[last];
1795
mp->data[last-1] = '\n';
1796
mp->data[last] = 0;
1797
}
1798
ed_putchar(ep,i<10?' ':'1');
1799
ed_putchar(ep,i<10?'0'+i:'0'+i-10);
1800
ed_putchar(ep,')');
1801
ed_putchar(ep,' ');
1802
ed_putstring(ep,mp->data);
1803
if(last)
1804
{
1805
mp->data[last-1] = save[0];
1806
mp->data[last] = save[1];
1807
}
1808
ep->nhlist = i;
1809
}
1810
last = i-1;
1811
while(i-->0)
1812
ed_putstring(ep,CURSOR_UP);
1813
}
1814
ed_flush(ep);
1815
}
1816
#endif /* SHOPT_EDPREDICT */
1817
1818
void *ed_open(Shell_t *shp)
1819
{
1820
Edit_t *ed = newof(0,Edit_t,1,0);
1821
ed->sh = shp;
1822
strcpy(ed->e_macro,"_??");
1823
return((void*)ed);
1824
}
1825
1826
#undef ioctl
1827
int sh_ioctl(int fd, int cmd, void* val, int sz)
1828
{
1829
int r,err=errno;
1830
if(sz == sizeof(void*))
1831
{
1832
while((r=ioctl(fd,cmd,val)) < 0 && errno==EINTR)
1833
errno = err;
1834
}
1835
else
1836
{
1837
Sflong_t l = (Sflong_t)val;
1838
if(sizeof(val)==sizeof(long))
1839
{
1840
while((r=ioctl(fd,cmd,(unsigned long)l)) < 0 && errno==EINTR)
1841
errno = err;
1842
}
1843
else if(sizeof(int)!=sizeof(long))
1844
{
1845
while((r=ioctl(fd,cmd,(unsigned int)l)) < 0 && errno==EINTR)
1846
errno = err;
1847
}
1848
}
1849
return(r);
1850
}
1851
1852
#ifdef _lib_tcgetattr
1853
# undef tcgetattr
1854
sh_tcgetattr(int fd, struct termios *tty)
1855
{
1856
int r,err = errno;
1857
while((r=tcgetattr(fd,tty)) < 0 && errno==EINTR)
1858
errno = err;
1859
return(r);
1860
}
1861
1862
# undef tcsetattr
1863
sh_tcsetattr(int fd, int cmd, struct termios *tty)
1864
{
1865
int r,err = errno;
1866
while((r=tcsetattr(fd,cmd,tty)) < 0 && errno==EINTR)
1867
errno = err;
1868
return(r);
1869
}
1870
#endif
1871
1872