Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ie/edit.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1984-2011 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
* Pat Sullivan *
19
* *
20
***********************************************************************/
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 Bell Laboratories AT&T Bell Laboratories
26
* Room 3C-526B Room 1B-286
27
* Murray Hill, N. J. 07974 Columbus, OH 43213
28
* Tel. x7975 Tel. x 2655
29
*
30
* Coded April 1983.
31
*/
32
33
#ifdef KSHELL
34
# include "defs.h"
35
# include "terminal.h"
36
# include "builtins.h"
37
# include "sym.h"
38
#else
39
# include "io.h"
40
# include "terminal.h"
41
# undef SIG_NORESTART
42
# define SIG_NORESTART 1
43
# define _sobuf ed_errbuf
44
extern char ed_errbuf[];
45
const char e_version[] = "\n@(#)$Id: edit library (AT&T Research) 1988-11-16 i $\0\n";
46
#endif /* KSHELL */
47
#include "history.h"
48
#include "edit.h"
49
50
#include <error.h>
51
52
#define BAD -1
53
#define GOOD 0
54
#define SYSERR -1
55
56
#ifdef OLDTERMIO
57
# undef tcgetattr
58
# undef tcsetattr
59
#endif /* OLDTERMIO */
60
61
#ifdef RT
62
# define VENIX 1
63
#endif /* RT */
64
65
#define lookahead editb.e_index
66
#define env editb.e_env
67
#define previous editb.e_lbuf
68
#define fildes editb.e_fd
69
#define in_raw editb.e_addnl
70
71
72
#ifdef _hdr_sgtty
73
# ifdef TIOCGETP
74
static int l_mask;
75
static struct tchars l_ttychars;
76
static struct ltchars l_chars;
77
static char l_changed; /* set if mode bits changed */
78
# define L_CHARS 4
79
# define T_CHARS 2
80
# define L_MASK 1
81
# endif /* TIOCGETP */
82
#endif /* _hdr_sgtty */
83
84
#ifndef IODELAY
85
# undef _SELECT5_
86
#endif /* IODELAY */
87
#ifdef _SELECT5_
88
# ifndef included_sys_time
89
# define included_sys_time 1
90
# include <sys/time.h>
91
# endif /* included_sys_time */
92
static int delay;
93
# ifndef KSHELL
94
int tty_speeds[] = {0, 50, 75, 110, 134, 150, 200, 300,
95
600,1200,1800,2400,9600,19200,0};
96
# endif /* KSHELL */
97
#endif /* _SELECT5_ */
98
99
#ifdef KSHELL
100
extern char *sh_tilde();
101
static char macro[] = "_??";
102
# define slowsig() (sh.trapnote&SIGSLOW)
103
#else
104
struct edit editb = { 0 };
105
# define slowsig() (0)
106
#endif /* KSHELL */
107
108
109
static struct termios savetty;
110
static int savefd = -1;
111
#ifdef future
112
static int compare();
113
#endif
114
#if VSH || ESH
115
static struct termios ttyparm; /* initial tty parameters */
116
static struct termios nttyparm; /* raw tty parameters */
117
static char bellchr[] = "\7"; /* bell char */
118
# define tenex 1
119
# ifdef tenex
120
static char *overlay();
121
# endif /* tenex */
122
#endif /* VSH || ESH */
123
124
125
/*
126
* This routine returns true if fd refers to a terminal
127
* This should be equivalent to isatty
128
*/
129
130
int tty_check(fd)
131
int fd;
132
{
133
savefd = -1;
134
return(tty_get(fd,(struct termios*)0)==0);
135
}
136
137
/*
138
* Get the current terminal attributes
139
* This routine remembers the attributes and just returns them if it
140
* is called again without an intervening tty_set()
141
*/
142
143
int tty_get(fd, tty)
144
int fd;
145
struct termios *tty;
146
{
147
if(fd != savefd)
148
{
149
#ifndef SIG_NORESTART
150
VOID (*savint)() = st.intfn;
151
st.intfn = 0;
152
#endif /* SIG_NORESTART */
153
while(tcgetattr(fd,&savetty) == SYSERR)
154
{
155
if(errno !=EINTR)
156
{
157
#ifndef SIG_NORESTART
158
st.intfn = savint;
159
#endif /* SIG_NORESTART */
160
return(SYSERR);
161
}
162
errno = 0;
163
}
164
#ifndef SIG_NORESTART
165
st.intfn = savint;
166
#endif /* SIG_NORESTART */
167
savefd = fd;
168
}
169
if(tty)
170
*tty = savetty;
171
return(0);
172
}
173
174
/*
175
* Set the terminal attributes
176
* If fd<0, then current attributes are invalidated
177
*/
178
179
/* VARARGS 2 */
180
int tty_set(fd, action, tty)
181
int fd, action;
182
struct termios *tty;
183
{
184
if(fd >=0)
185
{
186
#ifndef SIG_NORESTART
187
VOID (*savint)() = st.intfn;
188
#endif /* SIG_NORESTART */
189
#ifdef future
190
if(savefd>=0 && compare(&savetty,tty,sizeof(struct termios)))
191
return(0);
192
#endif
193
#ifndef SIG_NORESTART
194
st.intfn = 0;
195
#endif /* SIG_NORESTART */
196
while(tcsetattr(fd, action, tty) == SYSERR)
197
{
198
if(errno !=EINTR)
199
{
200
#ifndef SIG_NORESTART
201
st.intfn = savint;
202
#endif /* SIG_NORESTART */
203
return(SYSERR);
204
}
205
errno = 0;
206
}
207
#ifndef SIG_NORESTART
208
st.intfn = savint;
209
#endif /* SIG_NORESTART */
210
savetty = *tty;
211
}
212
savefd = fd;
213
return(0);
214
}
215
216
#if ESH || VSH
217
/*{ TTY_COOKED( fd )
218
*
219
* This routine will set the tty in cooked mode.
220
* It is also called by error.done().
221
*
222
}*/
223
224
void tty_cooked(fd)
225
register int fd;
226
{
227
228
if(editb.e_raw==0)
229
return;
230
if(fd < 0)
231
fd = savefd;
232
#ifdef L_MASK
233
/* restore flags */
234
if(l_changed&L_MASK)
235
ioctl(fd,TIOCLSET,&l_mask);
236
if(l_changed&T_CHARS)
237
/* restore alternate break character */
238
ioctl(fd,TIOCSETC,&l_ttychars);
239
if(l_changed&L_CHARS)
240
/* restore alternate break character */
241
ioctl(fd,TIOCSLTC,&l_chars);
242
l_changed = 0;
243
#endif /* L_MASK */
244
/*** don't do tty_set unless ttyparm has valid data ***/
245
if(savefd<0 || tty_set(fd, TCSANOW, &ttyparm) == SYSERR)
246
return;
247
editb.e_raw = 0;
248
return;
249
}
250
251
/*{ TTY_RAW( fd )
252
*
253
* This routine will set the tty in raw mode.
254
*
255
}*/
256
257
int tty_raw(fd)
258
register int fd;
259
{
260
#ifdef L_MASK
261
struct ltchars lchars;
262
#endif /* L_MASK */
263
if(editb.e_raw==RAWMODE)
264
return(GOOD);
265
#ifndef RAWONLY
266
if(editb.e_raw != ALTMODE)
267
#endif /* RAWONLY */
268
{
269
if(tty_get(fd,&ttyparm) == SYSERR)
270
return(BAD);
271
}
272
#if L_MASK || VENIX
273
if(!(ttyparm.sg_flags&ECHO) || (ttyparm.sg_flags&LCASE))
274
return(BAD);
275
nttyparm = ttyparm;
276
nttyparm.sg_flags &= ~(ECHO | TBDELAY);
277
# ifdef CBREAK
278
nttyparm.sg_flags |= CBREAK;
279
# else
280
nttyparm.sg_flags |= RAW;
281
# endif /* CBREAK */
282
editb.e_erase = ttyparm.sg_erase;
283
editb.e_kill = ttyparm.sg_kill;
284
editb.e_eof = cntl('D');
285
if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
286
return(BAD);
287
editb.e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
288
# ifdef _SELECT5_
289
delay = tty_speeds[ttyparm.sg_ospeed];
290
# endif /* _SELECT5_ */
291
# ifdef TIOCGLTC
292
/* try to remove effect of ^V and ^Y and ^O */
293
if(ioctl(fd,TIOCGLTC,&l_chars) != SYSERR)
294
{
295
lchars = l_chars;
296
lchars.t_lnextc = -1;
297
lchars.t_flushc = -1;
298
lchars.t_dsuspc = -1; /* no delayed stop process signal */
299
if(ioctl(fd,TIOCSLTC,&lchars) != SYSERR)
300
l_changed |= L_CHARS;
301
}
302
# endif /* TIOCGLTC */
303
#else
304
305
if (!(ttyparm.c_lflag & ECHO ))
306
return(BAD);
307
308
# ifdef FLUSHO
309
ttyparm.c_lflag &= ~FLUSHO;
310
# endif /* FLUSHO */
311
nttyparm = ttyparm;
312
# ifndef u370
313
nttyparm.c_iflag &= ~(IGNPAR|PARMRK|INLCR|IGNCR|ICRNL);
314
nttyparm.c_iflag |= BRKINT;
315
# else
316
nttyparm.c_iflag &=
317
~(IGNBRK|PARMRK|INLCR|IGNCR|ICRNL|INPCK);
318
nttyparm.c_iflag |= (BRKINT|IGNPAR);
319
# endif /* u370 */
320
nttyparm.c_lflag &= ~(ICANON|ECHO|ECHOK);
321
nttyparm.c_cc[VTIME] = 0;
322
nttyparm.c_cc[VMIN] = 1;
323
# ifdef VDISCARD
324
nttyparm.c_cc[VDISCARD] = 0;
325
# endif /* VDISCARD */
326
# ifdef VWERASE
327
nttyparm.c_cc[VWERASE] = 0;
328
# endif /* VWERASE */
329
# ifdef VLNEXT
330
nttyparm.c_cc[VLNEXT] = 0;
331
# endif /* VLNEXT */
332
editb.e_eof = ttyparm.c_cc[VEOF];
333
editb.e_erase = ttyparm.c_cc[VERASE];
334
editb.e_kill = ttyparm.c_cc[VKILL];
335
if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
336
return(BAD);
337
editb.e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW);
338
#endif
339
editb.e_raw = RAWMODE;
340
return(GOOD);
341
}
342
343
#ifndef RAWONLY
344
345
/*
346
*
347
* Get tty parameters and make ESC and '\r' wakeup characters.
348
*
349
*/
350
351
# ifdef TIOCGETC
352
int tty_alt(fd)
353
register int fd;
354
{
355
int mask;
356
struct tchars ttychars;
357
if(editb.e_raw==ALTMODE)
358
return(GOOD);
359
if(editb.e_raw==RAWMODE)
360
tty_cooked(fd);
361
l_changed = 0;
362
if( editb.e_ttyspeed == 0)
363
{
364
if((tty_get(fd,&ttyparm) != SYSERR))
365
editb.e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
366
editb.e_raw = ALTMODE;
367
}
368
if(ioctl(fd,TIOCGETC,&l_ttychars) == SYSERR)
369
return(BAD);
370
if(ioctl(fd,TIOCLGET,&l_mask)==SYSERR)
371
return(BAD);
372
ttychars = l_ttychars;
373
mask = LCRTBS|LCRTERA|LCTLECH|LPENDIN|LCRTKIL;
374
if((l_mask|mask) != l_mask)
375
l_changed = L_MASK;
376
if(ioctl(fd,TIOCLBIS,&mask)==SYSERR)
377
return(BAD);
378
if(ttychars.t_brkc!=ESC)
379
{
380
ttychars.t_brkc = ESC;
381
l_changed |= T_CHARS;
382
if(ioctl(fd,TIOCSETC,&ttychars) == SYSERR)
383
return(BAD);
384
}
385
return(GOOD);
386
}
387
# else
388
# ifndef PENDIN
389
# define PENDIN 0
390
# endif /* PENDIN */
391
# ifndef IEXTEN
392
# define IEXTEN 0
393
# endif /* IEXTEN */
394
int tty_alt(fd)
395
register int fd;
396
{
397
if(editb.e_raw==ALTMODE)
398
return(GOOD);
399
if(editb.e_raw==RAWMODE)
400
tty_cooked(fd);
401
if((tty_get(fd, &ttyparm)==SYSERR) || (!(ttyparm.c_lflag&ECHO)))
402
return(BAD);
403
# ifdef FLUSHO
404
ttyparm.c_lflag &= ~FLUSHO;
405
# endif /* FLUSHO */
406
nttyparm = ttyparm;
407
editb.e_eof = ttyparm.c_cc[VEOF];
408
# ifdef ECHOCTL
409
/* escape character echos as ^[ */
410
nttyparm.c_lflag |= (ECHOE|ECHOK|ECHOCTL|PENDIN|IEXTEN);
411
nttyparm.c_cc[VEOL2] = ESC;
412
# else
413
/* switch VEOL2 and EOF, since EOF isn't echo'd by driver */
414
nttyparm.c_iflag &= ~(IGNCR|ICRNL);
415
nttyparm.c_iflag |= INLCR;
416
nttyparm.c_lflag |= (ECHOE|ECHOK);
417
nttyparm.c_cc[VEOF] = ESC; /* make ESC the eof char */
418
nttyparm.c_cc[VEOL] = '\r'; /* make CR an eol char */
419
nttyparm.c_cc[VEOL2] = editb.e_eof; /* make EOF an eol char */
420
# endif /* ECHOCTL */
421
# ifdef VWERASE
422
nttyparm.c_cc[VWERASE] = cntl('W');
423
# endif /* VWERASE */
424
# ifdef VLNEXT
425
nttyparm.c_cc[VLNEXT] = cntl('V');
426
# endif /* VLNEXT */
427
editb.e_erase = ttyparm.c_cc[VERASE];
428
editb.e_kill = ttyparm.c_cc[VKILL];
429
if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR )
430
return(BAD);
431
editb.e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW);
432
editb.e_raw = ALTMODE;
433
return(GOOD);
434
}
435
436
# endif /* TIOCGETC */
437
#endif /* RAWONLY */
438
439
/*
440
* ED_WINDOW()
441
*
442
* return the window size
443
*/
444
445
#ifdef _sys_stream
446
# include <sys/stream.h>
447
#endif /* _sys_stream */
448
#ifdef _sys_ptem
449
# include <sys/ptem.h>
450
#endif /* _sys_ptem */
451
#ifdef _sys_jioctl
452
# include <sys/jioctl.h>
453
# define winsize jwinsize
454
# define ws_col bytesx
455
# ifdef TIOCGWINSZ
456
# undef TIOCGWINSZ
457
# endif /* TIOCGWINSZ */
458
# define TIOCGWINSZ JWINSIZE
459
#endif /* _sys_jioctl */
460
461
int ed_window()
462
{
463
register int n = DFLTWINDOW-1;
464
register char *cp = nam_strval(COLUMNS);
465
if(cp)
466
{
467
n = (int)strtol(cp, (char**)0, 10)-1;
468
if(n > MAXWINDOW)
469
n = MAXWINDOW;
470
}
471
#ifdef TIOCGWINSZ
472
else
473
{
474
/* for 5620's and 630's */
475
struct winsize size;
476
if (ioctl(ERRIO, TIOCGWINSZ, &size) != -1)
477
if(size.ws_col > 0)
478
n = size.ws_col - 1;
479
}
480
#endif /*TIOCGWINSZ */
481
if(n < MINWINDOW)
482
n = MINWINDOW;
483
return(n);
484
}
485
486
/* E_FLUSH()
487
*
488
* Flush the output buffer.
489
*
490
*/
491
492
void ed_flush()
493
{
494
register int n = editb.e_outptr-editb.e_outbase;
495
register int fd = ERRIO;
496
if(n<=0)
497
return;
498
write(fd,editb.e_outbase,(unsigned)n);
499
editb.e_outptr = editb.e_outbase;
500
#ifdef _SELECT5_
501
if(delay && n > delay/100)
502
{
503
/* delay until output drains */
504
struct timeval timeloc;
505
n *= 10;
506
timeloc.tv_sec = n/delay;
507
timeloc.tv_usec = (1000000*(n%delay))/delay;
508
select(0,(fd_set*)0,(fd_set*)0,(fd_set*)0,&timeloc);
509
}
510
#else
511
# ifdef IODELAY
512
if(editb.e_raw==RAWMODE && n > 16)
513
tty_set(fd, TCSADRAIN, &nttyparm);
514
# endif /* IODELAY */
515
#endif /* _SELECT5_ */
516
}
517
518
/*
519
* send the bell character ^G to the terminal
520
*/
521
522
void ed_ringbell()
523
{
524
write(ERRIO,bellchr,1);
525
}
526
527
/*
528
* send a carriage return line feed to the terminal
529
*/
530
531
void ed_crlf()
532
{
533
#ifdef cray
534
ed_putchar('\r');
535
#endif /* cray */
536
#ifdef u370
537
ed_putchar('\r');
538
#endif /* u370 */
539
#ifdef VENIX
540
ed_putchar('\r');
541
#endif /* VENIX */
542
ed_putchar('\n');
543
ed_flush();
544
}
545
546
/* E_SETUP( max_prompt_size )
547
*
548
* This routine sets up the prompt string
549
* The following is an unadvertised feature.
550
* Escape sequences in the prompt can be excluded from the calculated
551
* prompt length. This is accomplished as follows:
552
* - if the prompt string starts with "%\r, or contains \r%\r", where %
553
* represents any char, then % is taken to be the quote character.
554
* - strings enclosed by this quote character, and the quote character,
555
* are not counted as part of the prompt length.
556
*/
557
558
void ed_setup(fd)
559
int fd;
560
{
561
register char *pp;
562
register char *last;
563
char *ppmax;
564
int myquote = 0;
565
int qlen = 1;
566
char inquote = 0;
567
editb.e_fd = fd;
568
p_setout(ERRIO);
569
#ifdef KSHELL
570
last = _sobuf;
571
#else
572
last = editb.e_prbuff;
573
#endif /* KSHELL */
574
if(hist_ptr)
575
{
576
register struct history *fp = hist_ptr;
577
editb.e_hismax = fp->fixind;
578
editb.e_hloff = 0;
579
editb.e_hismin = fp->fixind-fp->fixmax;
580
if(editb.e_hismin<0)
581
editb.e_hismin = 0;
582
}
583
else
584
{
585
editb.e_hismax = editb.e_hismin = editb.e_hloff = 0;
586
}
587
editb.e_hline = editb.e_hismax;
588
editb.e_wsize = ed_window()-2;
589
editb.e_crlf = (*last?YES:NO);
590
pp = editb.e_prompt;
591
ppmax = pp+PRSIZE-1;
592
*pp++ = '\r';
593
{
594
register int c;
595
while(c= *last++) switch(c)
596
{
597
case '\r':
598
if(pp == (editb.e_prompt+2)) /* quote char */
599
myquote = *(pp-1);
600
/*FALLTHROUGH*/
601
602
case '\n':
603
/* start again */
604
editb.e_crlf = YES;
605
qlen = 1;
606
inquote = 0;
607
pp = editb.e_prompt+1;
608
break;
609
610
case '\t':
611
/* expand tabs */
612
while((pp-editb.e_prompt)%TABSIZE)
613
{
614
if(pp >= ppmax)
615
break;
616
*pp++ = ' ';
617
}
618
break;
619
620
case BELL:
621
/* cut out bells */
622
break;
623
624
default:
625
if(c==myquote)
626
{
627
qlen += inquote;
628
inquote ^= 1;
629
}
630
if(pp < ppmax)
631
{
632
qlen += inquote;
633
*pp++ = c;
634
if(!inquote && !isprint(c))
635
editb.e_crlf = NO;
636
}
637
}
638
}
639
editb.e_plen = pp - editb.e_prompt - qlen;
640
*pp = 0;
641
if((editb.e_wsize -= editb.e_plen) < 7)
642
{
643
register int shift = 7-editb.e_wsize;
644
editb.e_wsize = 7;
645
pp = editb.e_prompt+1;
646
strcpy(pp,pp+shift);
647
editb.e_plen -= shift;
648
last[-editb.e_plen-2] = '\r';
649
}
650
p_flush();
651
editb.e_outptr = _sobuf;
652
editb.e_outbase = editb.e_outptr;
653
editb.e_outlast = editb.e_outptr + IOBSIZE-3;
654
}
655
656
#ifdef KSHELL
657
/*
658
* look for edit macro named _i
659
* if found, puts the macro definition into lookahead buffer and returns 1
660
*/
661
662
ed_macro(i)
663
register int i;
664
{
665
register char *out;
666
struct namnod *np;
667
genchar buff[LOOKAHEAD+1];
668
if(i != '@')
669
macro[1] = i;
670
/* undocumented feature, macros of the form <ESC>[c evoke alias __c */
671
if(i=='_')
672
macro[2] = ed_getchar();
673
else
674
macro[2] = 0;
675
if (isalnum(i)&&(np=nam_search(macro,sh.alias_tree,N_NOSCOPE))&&(out=nam_strval(np)))
676
{
677
#ifdef MULTIBYTE
678
/* copy to buff in internal representation */
679
int c = out[LOOKAHEAD];
680
out[LOOKAHEAD] = 0;
681
i = ed_internal(out,buff);
682
out[LOOKAHEAD] = c;
683
#else
684
strncpy((char*)buff,out,LOOKAHEAD);
685
i = strlen((char*)buff);
686
#endif /* MULTIBYTE */
687
while(i-- > 0)
688
ed_ungetchar(buff[i]);
689
return(1);
690
}
691
return(0);
692
}
693
/*
694
* file name generation for edit modes
695
* non-zero exit for error, <0 ring bell
696
* don't search back past beginning of the buffer
697
* mode is '*' for inline expansion,
698
* mode is '\' for filename completion
699
* mode is '=' cause files to be listed in select format
700
*/
701
702
ed_expand(outbuff,cur,eol,mode)
703
char outbuff[];
704
int *cur;
705
int *eol;
706
int mode;
707
{
708
int offset = staktell();
709
char *staksav = stakptr(0);
710
struct comnod *comptr = (struct comnod*)stakalloc(sizeof(struct comnod));
711
struct argnod *ap = (struct argnod*)stakseek(ARGVAL);
712
register char *out;
713
char *begin;
714
int addstar;
715
int istilde = 0;
716
int rval = 0;
717
int strip;
718
optflag savflags = opt_flags;
719
#ifdef MULTIBYTE
720
{
721
register int c = *cur;
722
register genchar *cp;
723
/* adjust cur */
724
cp = (genchar *)outbuff + *cur;
725
c = *cp;
726
*cp = 0;
727
*cur = ed_external((genchar*)outbuff,(char*)stakptr(0));
728
*cp = c;
729
*eol = ed_external((genchar*)outbuff,outbuff);
730
}
731
#endif /* MULTIBYTE */
732
out = outbuff + *cur;
733
comptr->comtyp = COMSCAN;
734
comptr->comarg = ap;
735
ap->argflag = (A_MAC|A_EXP);
736
ap->argnxt.ap = 0;
737
{
738
register int c;
739
int chktilde;
740
char *cp;
741
if(out>outbuff)
742
{
743
/* go to beginning of word */
744
do
745
{
746
out--;
747
c = *(unsigned char*)out;
748
}
749
while(out>outbuff && !isqmeta(c));
750
/* copy word into arg */
751
if(isqmeta(c))
752
out++;
753
}
754
else
755
out = outbuff;
756
begin = out;
757
chktilde = (*out=='~');
758
/* addstar set to zero if * should not be added */
759
addstar = '*';
760
strip = 1;
761
/* copy word to arg and do ~ expansion */
762
do
763
{
764
c = *(unsigned char*)out;
765
if(isexp(c))
766
addstar = 0;
767
if ((c == '/') && (addstar == 0))
768
strip = 0;
769
stakputc(c);
770
if(chktilde && (c==0 || c == '/'))
771
{
772
chktilde=0;
773
*out = 0;
774
if(cp=sh_tilde(begin))
775
{
776
istilde++;
777
stakseek(ARGVAL);
778
stakputs(cp);
779
stakputc(c);
780
if(c==0)
781
{
782
addstar = 0;
783
strip = 0;
784
}
785
}
786
*out = c;
787
}
788
out++;
789
} while (c && !isqmeta(c));
790
791
out--;
792
#ifdef tenex
793
if(mode=='\\')
794
addstar = '*';
795
#endif /* tenex */
796
*stakptr(staktell()-1) = addstar;
797
stakfreeze(1);
798
}
799
if(mode!='*')
800
on_option(MARKDIR);
801
{
802
register char **com;
803
int narg;
804
register int size;
805
VOID (*savfn)();
806
savfn = st.intfn;
807
com = arg_build(&narg,comptr);
808
st.intfn = savfn;
809
/* match? */
810
if (*com==0 || (!istilde && narg <= 1 && eq(ap->argval,*com)))
811
{
812
rval = -1;
813
goto done;
814
}
815
if(mode=='=')
816
{
817
if (strip)
818
{
819
register char **ptrcom;
820
for(ptrcom=com;*ptrcom;ptrcom++)
821
/* trim directory prefix */
822
*ptrcom = path_basename(*ptrcom);
823
}
824
p_setout(ERRIO);
825
newline();
826
p_list(narg,com);
827
p_flush();
828
goto done;
829
}
830
/* see if there is enough room */
831
size = *eol - (out-begin);
832
#ifdef tenex
833
if(mode=='\\')
834
{
835
/* just expand until name is unique */
836
size += strlen(*com);
837
}
838
else
839
#endif
840
{
841
size += narg;
842
{
843
char **savcom = com;
844
while (*com)
845
size += strlen(*com++);
846
com = savcom;
847
}
848
}
849
/* see if room for expansion */
850
if(outbuff+size >= &outbuff[MAXLINE])
851
{
852
com[0] = ap->argval;
853
com[1] = 0;
854
}
855
/* save remainder of the buffer */
856
strcpy(stakptr(0),out);
857
out = sh_copy(*com++, begin);
858
#ifdef tenex
859
if(mode=='\\')
860
{
861
if(*com==0 && out[-1]!='/')
862
*out++ = ' ';
863
while (*com && *begin)
864
out = overlay(begin,*com++);
865
if(*begin==0)
866
ed_ringbell();
867
}
868
else
869
#endif
870
while (*com)
871
{
872
*out++ = ' ';
873
out = sh_copy(*com++,out);
874
}
875
*cur = (out-outbuff);
876
/* restore rest of buffer */
877
out = sh_copy(stakptr(0),out);
878
*eol = (out-outbuff);
879
}
880
done:
881
stakset(staksav,offset);
882
opt_flags = savflags;
883
#ifdef MULTIBYTE
884
{
885
register int c;
886
/* first re-adjust cur */
887
out = outbuff + *cur;
888
c = *out;
889
*out = 0;
890
*cur = ed_internal(outbuff,(genchar*)stakptr(0));
891
*out = c;
892
outbuff[*eol+1] = 0;
893
*eol = ed_internal(outbuff,(genchar*)outbuff);
894
}
895
#endif /* MULTIBYTE */
896
return(rval);
897
}
898
899
# ifdef tenex
900
static char *overlay(str,newstr)
901
register char *str,*newstr;
902
{
903
while(*str && *str == *newstr++)
904
str++;
905
*str = 0;
906
return(str);
907
}
908
# endif
909
910
/*
911
* Enter the fc command on the current history line
912
*/
913
ed_fulledit()
914
{
915
register char *cp;
916
if(!hist_ptr || (st.states&BUILTIN))
917
return(BAD);
918
/* use EDITOR on current command */
919
if(editb.e_hline == editb.e_hismax)
920
{
921
if(editb.e_eol<=0)
922
return(BAD);
923
editb.e_inbuf[editb.e_eol+1] = 0;
924
p_setout(hist_ptr->fixfd);
925
p_str((char*)editb.e_inbuf,0);
926
st.states |= FIXFLG;
927
hist_flush();
928
}
929
cp = sh_copy(e_runvi, (char*)editb.e_inbuf);
930
cp = sh_copy(sh_itos(editb.e_hline), cp);
931
editb.e_eol = (unsigned char*)cp - (unsigned char*)editb.e_inbuf;
932
return(GOOD);
933
}
934
#endif /* KSHELL */
935
936
937
/*
938
* routine to perform read from terminal for vi and emacs mode
939
*/
940
941
942
int
943
ed_getchar()
944
{
945
register int i;
946
register int c;
947
register int maxtry = MAXTRY;
948
unsigned nchar = READAHEAD; /* number of characters to read at a time */
949
#ifdef MULTIBYTE
950
static int curchar;
951
static int cursize;
952
#endif /* MULTIBYTE */
953
char readin[LOOKAHEAD] ;
954
if (lookahead)
955
{
956
c = previous[--lookahead];
957
/*** map '\r' to '\n' ***/
958
if(c == '\r' && !in_raw)
959
c = '\n';
960
return(c);
961
}
962
963
ed_flush() ;
964
/*
965
* you can't chance read ahead at the end of line
966
* or when the input is a pipe
967
*/
968
#ifdef KSHELL
969
if((editb.e_cur>=editb.e_eol) || fnobuff(io_ftable[fildes]))
970
#else
971
if(editb.e_cur>=editb.e_eol)
972
#endif /* KSHELL */
973
nchar = 1;
974
/* Set 'i' to indicate read failed, in case intr set */
975
#ifdef MULTIBYTE
976
retry:
977
#endif /* MULTIBYTE */
978
i = -1;
979
errno = 0;
980
editb.e_inmacro = 0;
981
while(slowsig()==0 && maxtry--)
982
{
983
errno=0;
984
if ((i = read(fildes,readin, nchar)) != -1)
985
break;
986
}
987
#ifdef MULTIBYTE
988
lookahead = maxtry = i;
989
i = 0;
990
while (i < maxtry)
991
{
992
c = readin[i++] & STRIP;
993
next:
994
if(cursize-- > 0)
995
{
996
curchar = (curchar<<7) | (c&~HIGHBIT);
997
if(cursize==0)
998
{
999
c = curchar;
1000
goto gotit;
1001
}
1002
else if(i>=maxtry)
1003
goto retry;
1004
continue;
1005
}
1006
else if(curchar = echarset(c))
1007
{
1008
cursize = in_csize(curchar);
1009
if(curchar != 1)
1010
c = 0;
1011
curchar <<= 7*(ESS_MAXCHAR-cursize);
1012
if(c)
1013
goto next;
1014
else if(i>=maxtry)
1015
goto retry;
1016
continue;
1017
}
1018
gotit:
1019
previous[--lookahead] = c;
1020
#else
1021
while (i > 0)
1022
{
1023
c = readin[--i] & STRIP;
1024
previous[lookahead++] = c;
1025
#endif /* MULTIBYTE */
1026
#ifndef CBREAK
1027
if( c == '\0' )
1028
{
1029
/*** user break key ***/
1030
lookahead = 0;
1031
# ifdef KSHELL
1032
sh_fault(SIGINT);
1033
LONGJMP(env, UINTR);
1034
# endif /* KSHELL */
1035
}
1036
#endif /* !CBREAK */
1037
}
1038
#ifdef MULTIBYTE
1039
/* shift lookahead buffer if necessary */
1040
if(lookahead)
1041
{
1042
for(i=lookahead;i < maxtry;i++)
1043
previous[i-lookahead] = previous[i];
1044
}
1045
lookahead = maxtry-lookahead;
1046
#endif /* MULTIBYTE */
1047
if (lookahead > 0)
1048
return(ed_getchar());
1049
LONGJMP(env,(i==0?UEOF:UINTR)); /* What a mess! Give up */
1050
return(0);
1051
/* NOTREACHED */
1052
}
1053
1054
void ed_ungetchar(c)
1055
register int c;
1056
{
1057
if (lookahead < LOOKAHEAD)
1058
previous[lookahead++] = c;
1059
return;
1060
}
1061
1062
/*
1063
* put a character into the output buffer
1064
*/
1065
1066
void ed_putchar(c)
1067
register int c;
1068
{
1069
register char *dp = editb.e_outptr;
1070
#ifdef MULTIBYTE
1071
register int d;
1072
/* check for place holder */
1073
if(c == MARKER)
1074
return;
1075
if(d = icharset(c))
1076
{
1077
if(d == 2)
1078
*dp++ = ESS2;
1079
else if(d == 3)
1080
*dp++ = ESS3;
1081
d = in_csize(d);
1082
while(--d>0)
1083
*dp++ = HIGHBIT|(c>>(7*d));
1084
c |= HIGHBIT;
1085
}
1086
#endif /* MULTIBYTE */
1087
if (c == '_')
1088
{
1089
*dp++ = ' ';
1090
*dp++ = '\b';
1091
}
1092
*dp++ = c;
1093
*dp = '\0';
1094
if(dp >= editb.e_outlast)
1095
ed_flush();
1096
else
1097
editb.e_outptr = dp;
1098
}
1099
1100
/*
1101
* copy virtual to physical and return the index for cursor in physical buffer
1102
*/
1103
int ed_virt_to_phys(virt,phys,cur,voff,poff)
1104
genchar *virt;
1105
genchar *phys;
1106
int cur, voff, poff;
1107
{
1108
register genchar *sp = virt;
1109
register genchar *dp = phys;
1110
register int c;
1111
genchar *curp = sp + cur;
1112
genchar *dpmax = phys+MAXLINE;
1113
int r;
1114
#ifdef MULTIBYTE
1115
int d;
1116
#endif /* MULTIBYTE */
1117
sp += voff;
1118
dp += poff;
1119
for(r=poff;c= *sp;sp++)
1120
{
1121
if(curp == sp)
1122
r = dp - phys;
1123
#ifdef MULTIBYTE
1124
d = out_csize(icharset(c));
1125
if(d>1)
1126
{
1127
/* multiple width character put in place holders */
1128
*dp++ = c;
1129
while(--d >0)
1130
*dp++ = MARKER;
1131
/* in vi mode the cursor is at the last character */
1132
if(dp>=dpmax)
1133
break;
1134
continue;
1135
}
1136
else
1137
#endif /* MULTIBYTE */
1138
if(!isprint(c))
1139
{
1140
if(c=='\t')
1141
{
1142
c = dp-phys;
1143
if(is_option(EDITVI))
1144
c += editb.e_plen;
1145
c = TABSIZE - c%TABSIZE;
1146
while(--c>0)
1147
*dp++ = ' ';
1148
c = ' ';
1149
}
1150
else
1151
{
1152
*dp++ = '^';
1153
c ^= TO_PRINT;
1154
}
1155
/* in vi mode the cursor is at the last character */
1156
if(curp == sp && is_option(EDITVI))
1157
r = dp - phys;
1158
}
1159
*dp++ = c;
1160
if(dp>=dpmax)
1161
break;
1162
}
1163
*dp = 0;
1164
return(r);
1165
}
1166
1167
#ifdef MULTIBYTE
1168
/*
1169
* convert external representation <src> to an array of genchars <dest>
1170
* <src> and <dest> can be the same
1171
* returns number of chars in dest
1172
*/
1173
1174
int ed_internal(src,dest)
1175
register unsigned char *src;
1176
genchar *dest;
1177
{
1178
register int c;
1179
register genchar *dp = dest;
1180
register int d;
1181
register int size;
1182
if((unsigned char*)dest == src)
1183
{
1184
genchar buffer[MAXLINE];
1185
c = ed_internal(src,buffer);
1186
ed_gencpy(dp,buffer);
1187
return(c);
1188
}
1189
while(c = *src++)
1190
{
1191
if(size = echarset(c))
1192
{
1193
d = (size==1?c:0);
1194
c = size;
1195
size = in_csize(c);
1196
c <<= 7*(ESS_MAXCHAR-size);
1197
if(d)
1198
{
1199
size--;
1200
c = (c<<7) | (d&~HIGHBIT);
1201
}
1202
while(size-- >0)
1203
c = (c<<7) | ((*src++)&~HIGHBIT);
1204
}
1205
*dp++ = c;
1206
}
1207
*dp = 0;
1208
return(dp-dest);
1209
}
1210
1211
/*
1212
* convert internal representation <src> into character array <dest>.
1213
* The <src> and <dest> may be the same.
1214
* returns number of chars in dest.
1215
*/
1216
1217
int ed_external(src,dest)
1218
genchar *src;
1219
char *dest;
1220
{
1221
register int c;
1222
register char *dp = dest;
1223
register int d;
1224
char *dpmax = dp+sizeof(genchar)*MAXLINE-2;
1225
if((char*)src == dp)
1226
{
1227
char buffer[MAXLINE*sizeof(genchar)];
1228
c = ed_external(src,buffer);
1229
strcpy(dest,buffer);
1230
return(c);
1231
}
1232
while((c = *src++) && dp<dpmax)
1233
{
1234
if(d = icharset(c))
1235
{
1236
if(d == 2)
1237
*dp++ = ESS2;
1238
else if(d == 3)
1239
*dp++ = ESS3;
1240
d = in_csize(d);
1241
while(--d>0)
1242
*dp++ = HIGHBIT|(c>>(7*d));
1243
c |= HIGHBIT;
1244
}
1245
*dp++ = c;
1246
}
1247
*dp = 0;
1248
return(dp-dest);
1249
}
1250
1251
/*
1252
* copy <sp> to <dp>
1253
*/
1254
1255
int ed_gencpy(dp,sp)
1256
register genchar *dp;
1257
register genchar *sp;
1258
{
1259
while(*dp++ = *sp++);
1260
}
1261
1262
/*
1263
* copy at most <n> items from <sp> to <dp>
1264
*/
1265
1266
int ed_genncpy(dp,sp, n)
1267
register genchar *dp;
1268
register genchar *sp;
1269
register int n;
1270
{
1271
while(n-->0 && (*dp++ = *sp++));
1272
}
1273
1274
/*
1275
* find the string length of <str>
1276
*/
1277
1278
int ed_genlen(str)
1279
register genchar *str;
1280
{
1281
register genchar *sp = str;
1282
while(*sp++);
1283
return(sp-str-1);
1284
}
1285
#endif /* MULTIBYTE */
1286
#endif /* ESH || VSH */
1287
1288
#ifdef MULTIBYTE
1289
/*
1290
* set the multibyte widths
1291
* format of string is x1[:y1][,x2[:y2][,x3[:y3]]]
1292
* returns 1 if string in not in this format, 0 otherwise.
1293
*/
1294
1295
extern char int_charsize[];
1296
ed_setwidth(string)
1297
char *string;
1298
{
1299
register int indx = 0;
1300
register int state = 0;
1301
register int c;
1302
register int n = 0;
1303
static char widths[6] = {1,1};
1304
while(1) switch(c = *string++)
1305
{
1306
case ':':
1307
if(state!=1)
1308
return(1);
1309
state++;
1310
/* fall through */
1311
1312
case 0:
1313
case ',':
1314
if(state==0)
1315
return(1);
1316
widths[indx++] = n;
1317
if(state==1)
1318
widths[indx++] = n;
1319
if(c==0)
1320
{
1321
for(n=1;n<= 3;n++)
1322
{
1323
int_charsize[n] = widths[c++];
1324
int_charsize[n+4] = widths[c++];
1325
}
1326
return(0);
1327
}
1328
else if(c==',')
1329
state = 0;
1330
n = 0;
1331
break;
1332
1333
case '0': case '1': case '2': case '3': case '4':
1334
if(state&1)
1335
return(1);
1336
n = c - '0';
1337
state++;
1338
break;
1339
1340
default:
1341
return(1);
1342
}
1343
/* NOTREACHED */
1344
}
1345
#endif /* MULTIBYTE */
1346
1347
#ifdef future
1348
/*
1349
* returns 1 when <n> bytes starting at <a> and <b> are equal
1350
*/
1351
static int compare(a,b,n)
1352
register char *a;
1353
register char *b;
1354
register int n;
1355
{
1356
while(n-->0)
1357
{
1358
if(*a++ != *b++)
1359
return(0);
1360
}
1361
return(1);
1362
}
1363
#endif
1364
1365
#ifdef OLDTERMIO
1366
1367
# include <sys/termio.h>
1368
1369
#ifndef ECHOCTL
1370
# define ECHOCTL 0
1371
#endif /* !ECHOCTL */
1372
char echoctl;
1373
static char tcgeta;
1374
static struct termio ott;
1375
1376
/*
1377
* For backward compatibility only
1378
* This version will use termios when possible, otherwise termio
1379
*/
1380
1381
1382
tcgetattr(fd,tt)
1383
struct termios *tt;
1384
{
1385
register int r;
1386
register int i;
1387
tcgeta = 0;
1388
echoctl = (ECHOCTL!=0);
1389
if((r=ioctl(fd,TCGETS,tt))>=0 || errno!=EINVAL)
1390
return(r);
1391
if((r=ioctl(fd,TCGETA,&ott)) >= 0)
1392
{
1393
tt->c_lflag = ott.c_lflag;
1394
tt->c_oflag = ott.c_oflag;
1395
tt->c_iflag = ott.c_iflag;
1396
tt->c_cflag = ott.c_cflag;
1397
for(i=0; i<NCC; i++)
1398
tt->c_cc[i] = ott.c_cc[i];
1399
tcgeta++;
1400
echoctl = 0;
1401
}
1402
return(r);
1403
}
1404
1405
tcsetattr(fd,mode,tt)
1406
register int mode;
1407
struct termios *tt;
1408
{
1409
register int r;
1410
if(tcgeta)
1411
{
1412
register int i;
1413
ott.c_lflag = tt->c_lflag;
1414
ott.c_oflag = tt->c_oflag;
1415
ott.c_iflag = tt->c_iflag;
1416
ott.c_cflag = tt->c_cflag;
1417
for(i=0; i<NCC; i++)
1418
ott.c_cc[i] = tt->c_cc[i];
1419
if(tt->c_lflag&ECHOCTL)
1420
{
1421
ott.c_lflag &= ~(ECHOCTL|IEXTEN);
1422
ott.c_iflag &= ~(IGNCR|ICRNL);
1423
ott.c_iflag |= INLCR;
1424
ott.c_cc[VEOF]= ESC; /* ESC -> eof char */
1425
ott.c_cc[VEOL] = '\r'; /* CR -> eol char */
1426
ott.c_cc[VEOL2] = tt->c_cc[VEOF]; /* EOF -> eol char */
1427
}
1428
switch(mode)
1429
{
1430
case TCSANOW:
1431
mode = TCSETA;
1432
break;
1433
case TCSADRAIN:
1434
mode = TCSETAW;
1435
break;
1436
case TCSAFLUSH:
1437
mode = TCSETAF;
1438
}
1439
return(ioctl(fd,mode,&ott));
1440
}
1441
return(ioctl(fd,mode,tt));
1442
}
1443
#endif /* OLDTERMIO */
1444
1445