Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ie/emacs.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
/* Adapted for ksh by David Korn */
22
/* EMACS_MODES: c tabstop=4
23
24
One line screen editor for any program
25
26
27
Questions and comments should be
28
directed to
29
30
Michael T. Veach
31
IX 1C-341 X1614
32
ihuxl!veach
33
34
*/
35
36
37
/* The following is provided by:
38
*
39
* Matthijs N. Melchior
40
* AT&T Network Systems International
41
* APT Nederland
42
* HV BZ335 x2962
43
* hvlpb!mmelchio
44
*
45
*
46
* If symbol ESHPLUS is defined, the following features is present:
47
*
48
* ESH_NFIRST
49
* - A ^N as first history related command after the prompt will move
50
* to the next command relative to the last known history position.
51
* It will not start at the position where the last command was entered
52
* as is done by the ^P command. Every history related command will
53
* set both the current and last position. Executing a command will
54
* only set the current position.
55
*
56
* ESH_KAPPEND
57
* - Successive kill and delete commands will accumulate their data
58
* in the kill buffer, by appending or prepending as appropriate.
59
* This mode will be reset by any command not adding something to the
60
* kill buffer.
61
*
62
* ESH_BETTER
63
* - Some enhancements:
64
* - argument for a macro is passed to its replacement
65
* - ^X^H command to find out about history position (debugging)
66
* - ^X^D command to show any debugging info
67
*
68
* I do not pretend these for changes are completely independent,
69
* but you can use them to seperate features.
70
*/
71
72
#ifdef DMERT /* 3bcc #undefs RT */
73
# define RT
74
#endif
75
76
#ifdef KSHELL
77
# include "defs.h"
78
#else
79
# include "io.h"
80
#endif /* KSHELL */
81
82
#include "history.h"
83
#include "edit.h"
84
#include "terminal.h"
85
86
#ifdef ESHPLUS
87
# define ESH_NFIRST
88
# define ESH_KAPPEND
89
# define ESH_BETTER
90
#endif /*ESHPLUS */
91
92
#undef blank
93
#undef putchar
94
#define putchar(c) ed_putchar(c)
95
#define beep() ed_ringbell()
96
97
98
#ifdef MULTIBYTE
99
# define gencpy(a,b) ed_gencpy(a,b)
100
# define genncpy(a,b,n) ed_genncpy(a,b,n)
101
# define genlen(str) ed_genlen(str)
102
static int print();
103
static int isword();
104
105
#else
106
# define gencpy(a,b) strcpy((char*)(a),(char*)(b))
107
# define genncpy(a,b,n) strncpy((char*)(a),(char*)(b),n)
108
# define genlen(str) strlen(str)
109
# define print(c) isprint(c)
110
# define isword(c) isalnum(out[c])
111
#endif /*MULTIBYTE */
112
113
#define eol editb.e_eol
114
#define cur editb.e_cur
115
#define mark editb.e_fchar
116
#define hline editb.e_hline
117
#define hloff editb.e_hloff
118
#define hismin editb.e_hismin
119
#define usrkill editb.e_kill
120
#define usreof editb.e_eof
121
#define usrerase editb.e_erase
122
#define crallowed editb.e_crlf
123
#define Prompt editb.e_prompt
124
#define plen editb.e_plen
125
#define kstack editb.e_killbuf
126
#define lstring editb.e_search
127
#define lookahead editb.e_index
128
#define env editb.e_env
129
#define raw editb.e_raw
130
#define histlines editb.e_hismax
131
#define w_size editb.e_wsize
132
#define drawbuff editb.e_inbuf
133
#ifdef ESHPLUS
134
# define killing editb.e_mode
135
# define in_mult editb.e_saved
136
#endif
137
#define NO 0
138
#define YES 1
139
#define LBUF 100
140
#define KILLCHAR UKILL
141
#define ERASECHAR UERASE
142
#define EOFCHAR UEOF
143
144
/**********************
145
A large lookahead helps when the user is inserting
146
characters in the middle of the line.
147
************************/
148
149
150
static genchar *screen; /* pointer to window buffer */
151
static genchar *cursor; /* Cursor in real screen */
152
static enum
153
{
154
CRT=0, /* Crt terminal */
155
PAPER /* Paper terminal */
156
} terminal ;
157
158
typedef enum
159
{
160
FIRST, /* First time thru for logical line, prompt on screen */
161
REFRESH, /* Redraw entire screen */
162
APPEND, /* Append char before cursor to screen */
163
UPDATE, /* Update the screen as need be */
164
FINAL /* Update screen even if pending look ahead */
165
} DRAWTYPE;
166
167
static void draw();
168
static int escape();
169
static void putstring();
170
static void search();
171
static void setcursor();
172
static void show_info();
173
static void xcommands();
174
175
static int cr_ok;
176
static histloc location = { -5, 0 };
177
178
int emacs_read(fd,buff,scend)
179
char *buff;
180
int fd;
181
unsigned scend;
182
{
183
register int c;
184
register int i;
185
register genchar *out;
186
register int count;
187
int adjust,oadjust;
188
char backslash;
189
genchar *kptr;
190
static int CntrlO;
191
char prompt[PRSIZE];
192
genchar Screen[MAXWINDOW];
193
#if KSHELL && (2*CHARSIZE*MAXLINE)<IOBSIZE
194
kstack = buff + MAXLINE*sizeof(genchar);
195
#else
196
if(kstack==0)
197
{
198
kstack = (genchar*)malloc(sizeof(genchar)*(MAXLINE));
199
kstack[0] = '\0';
200
}
201
#endif
202
Prompt = prompt;
203
screen = Screen;
204
drawbuff = out = (genchar*)buff;
205
if(tty_raw(ERRIO) < 0)
206
{
207
p_flush();
208
return(read(fd,buff,scend));
209
}
210
raw = 1;
211
/* This mess in case the read system call fails */
212
213
ed_setup(fd);
214
#ifdef ESH_NFIRST
215
if (hist_ptr) /* hloff cleared by ed_setup, recalculate... */
216
hloff = hist_copy((char*)0, hline, -1);
217
if (location.his_command == -5) /* to be initialized */
218
{
219
kstack[0] = '\0'; /* also clear kstack... */
220
location.his_command = hline;
221
location.his_line = hloff;
222
}
223
if (location.his_command <= hismin) /* don't start below minimum */
224
{
225
location.his_command = hismin + 1;
226
location.his_line = 0;
227
}
228
in_mult = hloff; /* save pos in last command */
229
#endif /* ESH_NFIRST */
230
i = SETJMP(env);
231
if (i)
232
{
233
tty_cooked(ERRIO);
234
if (i == UEOF)
235
{
236
return(0); /* EOF */
237
}
238
return(-1); /* some other error */
239
}
240
*out = 0;
241
if(scend+plen > (MAXLINE-2))
242
scend = (MAXLINE-2)-plen;
243
mark = eol = cur = 0;
244
draw(FIRST);
245
adjust = -1;
246
backslash = 0;
247
if (CntrlO)
248
{
249
#ifdef ESH_NFIRST
250
ed_ungetchar(cntl('N'));
251
#else
252
location = hist_locate(location.his_command,location.his_line,1);
253
if (location.his_command < histlines)
254
{
255
hline = location.his_command;
256
hloff = location.his_line;
257
hist_copy((char*)kstack,hline,hloff);
258
# ifdef MULTIBYTE
259
ed_internal((char*)kstack,kstack);
260
# endif /* MULTIBYTE */
261
ed_ungetchar(cntl('Y'));
262
}
263
#endif /* ESH_NFIRST */
264
}
265
CntrlO = 0;
266
while ((c = ed_getchar()) != (-1))
267
{
268
if (backslash)
269
{
270
backslash = 0;
271
if (c==usrerase||c==usrkill||(!print(c) &&
272
(c!='\r'&&c!='\n')))
273
{
274
/* accept a backslashed character */
275
cur--;
276
out[cur++] = c;
277
out[eol] = '\0';
278
draw(APPEND);
279
continue;
280
}
281
}
282
if (c == usrkill)
283
{
284
c = KILLCHAR ;
285
}
286
else if (c == usrerase)
287
{
288
c = ERASECHAR ;
289
}
290
else if ((c == usreof)&&(eol == 0))
291
{
292
c = EOFCHAR;
293
}
294
#ifdef ESH_KAPPEND
295
if (--killing <= 0) /* reset killing flag */
296
killing = 0;
297
#endif
298
oadjust = count = adjust;
299
if(count<0)
300
count = 1;
301
adjust = -1;
302
i = cur;
303
switch(c)
304
{
305
case cntl('V'):
306
show_info(&e_version[5]);
307
continue;
308
case '\0':
309
mark = i;
310
continue;
311
case cntl('X'):
312
xcommands(count);
313
continue;
314
case EOFCHAR:
315
ed_flush();
316
tty_cooked(ERRIO);
317
return(0);
318
#ifdef u370
319
case cntl('S') :
320
case cntl('Q') :
321
continue;
322
#endif /* u370 */
323
default:
324
i = ++eol;
325
if (i >= (scend)) /* will not fit on line */
326
{
327
eol--;
328
ed_ungetchar(c); /* save character for next line */
329
goto process;
330
}
331
for(i=eol;i>=cur;i--)
332
{
333
out[i] = out[i-1];
334
}
335
backslash = (c == '\\');
336
out[cur++] = c;
337
draw(APPEND);
338
continue;
339
case cntl('Y') :
340
{
341
c = genlen(kstack);
342
if ((c + eol) > scend)
343
{
344
beep();
345
continue;
346
}
347
mark = i;
348
for(i=eol;i>=cur;i--)
349
out[c+i] = out[i];
350
kptr=kstack;
351
while (i = *kptr++)
352
out[cur++] = i;
353
draw(UPDATE);
354
eol = genlen(out);
355
continue;
356
}
357
case '\n':
358
case '\r':
359
c = '\n';
360
goto process;
361
362
case DELETE: /* delete char 0x7f */
363
case '\b': /* backspace, ^h */
364
case ERASECHAR :
365
if (count > i)
366
count = i;
367
#ifdef ESH_KAPPEND
368
kptr = &kstack[count]; /* move old contents here */
369
if (killing) /* prepend to killbuf */
370
{
371
c = genlen(kstack) + CHARSIZE; /* include '\0' */
372
while(c--) /* copy stuff */
373
kptr[c] = kstack[c];
374
}
375
else
376
*kptr = 0; /* this is end of data */
377
killing = 2; /* we are killing */
378
i -= count;
379
eol -= count;
380
genncpy(kstack,out+i,cur-i);
381
#else
382
while ((count--)&&(i>0))
383
{
384
i--;
385
eol--;
386
}
387
genncpy(kstack,out+i,cur-i);
388
kstack[cur-i] = 0;
389
#endif /* ESH_KAPPEND */
390
gencpy(out+i,out+cur);
391
mark = i;
392
goto update;
393
case cntl('W') :
394
#ifdef ESH_KAPPEND
395
++killing; /* keep killing flag */
396
#endif
397
if (mark > eol )
398
mark = eol;
399
if (mark == i)
400
continue;
401
if (mark > i)
402
{
403
adjust = mark - i;
404
ed_ungetchar(cntl('D'));
405
continue;
406
}
407
adjust = i - mark;
408
ed_ungetchar(ERASECHAR);
409
continue;
410
case cntl('D') :
411
mark = i;
412
#ifdef ESH_KAPPEND
413
if (killing)
414
kptr = &kstack[genlen(kstack)]; /* append here */
415
else
416
kptr = kstack;
417
killing = 2; /* we are now killing */
418
#else
419
kptr = kstack;
420
#endif /* ESH_KAPPEND */
421
while ((count--)&&(eol>0)&&(i<eol))
422
{
423
*kptr++ = out[i];
424
eol--;
425
while(1)
426
{
427
if ((out[i] = out[(i+1)])==0)
428
break;
429
i++;
430
}
431
i = cur;
432
}
433
*kptr = '\0';
434
goto update;
435
case cntl('C') :
436
case cntl('F') :
437
{
438
int cntlC = (c==cntl('C'));
439
while (count-- && eol>i)
440
{
441
if (cntlC)
442
{
443
c = out[i];
444
#ifdef MULTIBYTE
445
if((c&~STRIP)==0 && islower(c))
446
#else
447
if(islower(c))
448
#endif /* MULTIBYTE */
449
{
450
c += 'A' - 'a';
451
out[i] = c;
452
}
453
}
454
i++;
455
}
456
goto update;
457
}
458
case cntl(']') :
459
c = ed_getchar();
460
if ((count == 0) || (count > eol))
461
{
462
beep();
463
continue;
464
}
465
if (out[i])
466
i++;
467
while (i < eol)
468
{
469
if (out[i] == c && --count==0)
470
goto update;
471
i++;
472
}
473
i = 0;
474
while (i < cur)
475
{
476
if (out[i] == c && --count==0)
477
break;
478
i++;
479
};
480
481
update:
482
cur = i;
483
draw(UPDATE);
484
continue;
485
486
case cntl('B') :
487
if (count > i)
488
count = i;
489
i -= count;
490
goto update;
491
case cntl('T') :
492
if ((is_option(GMACS))||(eol==i))
493
{
494
if (i >= 2)
495
{
496
c = out[i - 1];
497
out[i-1] = out[i-2];
498
out[i-2] = c;
499
}
500
else
501
{
502
beep();
503
continue;
504
}
505
}
506
else
507
{
508
if (eol>(i+1))
509
{
510
c = out[i];
511
out[i] = out[i+1];
512
out[i+1] = c;
513
i++;
514
}
515
else
516
{
517
beep();
518
continue;
519
}
520
}
521
goto update;
522
case cntl('A') :
523
i = 0;
524
goto update;
525
case cntl('E') :
526
i = eol;
527
goto update;
528
case cntl('U') :
529
adjust = 4*count;
530
continue;
531
case KILLCHAR :
532
cur = 0;
533
oadjust = -1;
534
case cntl('K') :
535
if(oadjust >= 0)
536
{
537
#ifdef ESH_KAPPEND
538
killing = 2; /* set killing signal */
539
#endif
540
mark = count;
541
ed_ungetchar(cntl('W'));
542
continue;
543
}
544
i = cur;
545
eol = i;
546
mark = i;
547
#ifdef ESH_KAPPEND
548
if (killing) /* append to kill buffer */
549
gencpy(&kstack[genlen(kstack)], &out[i]);
550
else
551
gencpy(kstack,&out[i]);
552
killing = 2; /* set killing signal */
553
#else
554
gencpy(kstack,&out[i]);
555
#endif /* ESH_KAPPEND */
556
out[i] = 0;
557
draw(UPDATE);
558
if (c == KILLCHAR)
559
{
560
if (terminal == PAPER)
561
{
562
putchar('\n');
563
putstring(Prompt);
564
}
565
c = ed_getchar();
566
if (c != usrkill)
567
{
568
ed_ungetchar(c);
569
continue;
570
}
571
if (terminal == PAPER)
572
terminal = CRT;
573
else
574
{
575
terminal = PAPER;
576
putchar('\n');
577
putstring(Prompt);
578
}
579
}
580
continue;
581
case cntl('L'):
582
ed_crlf();
583
draw(REFRESH);
584
continue;
585
case cntl('[') :
586
adjust = escape(out,oadjust);
587
continue;
588
case cntl('R') :
589
search(out,count);
590
goto drawline;
591
case cntl('P') :
592
if (count <= hloff)
593
hloff -= count;
594
else
595
{
596
hline -= count - hloff;
597
hloff = 0;
598
}
599
#ifdef ESH_NFIRST
600
if (hline <= hismin)
601
#else
602
if (hline < hismin)
603
#endif /* ESH_NFIRST */
604
{
605
hline = hismin+1;
606
beep();
607
#ifndef ESH_NFIRST
608
continue;
609
#endif
610
}
611
goto common;
612
613
case cntl('O') :
614
location.his_command = hline;
615
location.his_line = hloff;
616
CntrlO = 1;
617
c = '\n';
618
goto process;
619
case cntl('N') :
620
#ifdef ESH_NFIRST
621
hline = location.his_command; /* start at saved position */
622
hloff = location.his_line;
623
#endif /* ESH_NFIRST */
624
location = hist_locate(hline,hloff,count);
625
if (location.his_command > histlines)
626
{
627
beep();
628
#ifdef ESH_NFIRST
629
location.his_command = histlines;
630
location.his_line = in_mult;
631
#else
632
continue;
633
#endif /* ESH_NFIRST */
634
}
635
hline = location.his_command;
636
hloff = location.his_line;
637
common:
638
#ifdef ESH_NFIRST
639
location.his_command = hline; /* save current position */
640
location.his_line = hloff;
641
#endif
642
hist_copy(out,hline,hloff);
643
#ifdef MULTIBYTE
644
ed_internal((char*)(out),out);
645
#endif /* MULTIBYTE */
646
drawline:
647
eol = genlen(out);
648
cur = eol;
649
draw(UPDATE);
650
continue;
651
}
652
653
}
654
655
process:
656
657
if (c == (-1))
658
{
659
lookahead = 0;
660
beep();
661
*out = '\0';
662
}
663
draw(FINAL);
664
tty_cooked(ERRIO);
665
if(c == '\n')
666
{
667
out[eol++] = '\n';
668
out[eol] = '\0';
669
ed_crlf();
670
}
671
else
672
p_flush();
673
#ifdef MULTIBYTE
674
ed_external(out,buff);
675
#endif /* MULTIBYTE */
676
i = strlen(buff);
677
if (i)
678
return(i);
679
return(-1);
680
}
681
682
static void show_info(str)
683
char *str;
684
{
685
register char *out = (char *)drawbuff;
686
register int c;
687
genchar string[LBUF];
688
int sav_cur = cur;
689
/* save current line */
690
genncpy(string,out,sizeof(string)/CHARSIZE-1);
691
*out = 0;
692
cur = 0;
693
#ifdef MULTIBYTE
694
ed_internal(str,out);
695
#else
696
gencpy(out,str);
697
#endif /* MULTIBYTE */
698
draw(UPDATE);
699
c = ed_getchar();
700
if(c!=' ')
701
ed_ungetchar(c);
702
/* restore line */
703
cur = sav_cur;
704
genncpy(out,string,sizeof(string)/CHARSIZE-1);
705
draw(UPDATE);
706
}
707
708
static void
709
putstring(s)
710
register char *s;
711
{
712
register int c;
713
while (c= *s++)
714
putchar(c);
715
}
716
717
718
static int
719
escape(out,count)
720
register genchar *out;
721
int count;
722
{
723
register int i,value;
724
int digit,ch;
725
digit = 0;
726
value = 0;
727
while ((i=ed_getchar()),isdigit(i))
728
{
729
value *= 10;
730
value += (i - '0');
731
digit = 1;
732
}
733
if (digit)
734
{
735
ed_ungetchar(i) ;
736
#ifdef ESH_KAPPEND
737
++killing; /* don't modify killing signal */
738
#endif
739
return(value);
740
}
741
value = count;
742
if(value<0)
743
value = 1;
744
switch(ch=i)
745
{
746
case ' ':
747
mark = cur;
748
return(-1);
749
750
#ifdef ESH_KAPPEND
751
case '+': /* M-+ = append next kill */
752
killing = 2;
753
return -1; /* no argument for next command */
754
#endif
755
756
case 'p': /* M-p == ^W^Y (copy stack == kill & yank) */
757
ed_ungetchar(cntl('Y'));
758
ed_ungetchar(cntl('W'));
759
#ifdef ESH_KAPPEND
760
killing = 0; /* start fresh */
761
#endif
762
return(-1);
763
764
case 'l': /* M-l == lower-case */
765
case 'd':
766
case 'c':
767
case 'f':
768
{
769
i = cur;
770
while(value-- && i<eol)
771
{
772
while ((out[i])&&(!isword(i)))
773
i++;
774
while ((out[i])&&(isword(i)))
775
i++;
776
}
777
if(ch=='l')
778
{
779
value = i-cur;
780
while (value-- > 0)
781
{
782
i = out[cur];
783
#ifdef MULTIBYTE
784
if((i&~STRIP)==0 && isupper(i))
785
#else
786
if(isupper(i))
787
#endif /* MULTIBYTE */
788
{
789
i += 'a' - 'A';
790
out[cur] = i;
791
}
792
cur++;
793
}
794
draw(UPDATE);
795
return(-1);
796
}
797
798
else if(ch=='f')
799
goto update;
800
else if(ch=='c')
801
{
802
ed_ungetchar(cntl('C'));
803
return(i-cur);
804
}
805
else
806
{
807
if (i-cur)
808
{
809
ed_ungetchar(cntl('D'));
810
#ifdef ESH_KAPPEND
811
++killing; /* keep killing signal */
812
#endif
813
return(i-cur);
814
}
815
beep();
816
return(-1);
817
}
818
}
819
820
821
case 'b':
822
case DELETE :
823
case '\b':
824
case 'h':
825
{
826
i = cur;
827
while(value-- && i>0)
828
{
829
i--;
830
while ((i>0)&&(!isword(i)))
831
i--;
832
while ((i>0)&&(isword(i-1)))
833
i--;
834
}
835
if(ch=='b')
836
goto update;
837
else
838
{
839
ed_ungetchar(ERASECHAR);
840
#ifdef ESH_KAPPEND
841
++killing;
842
#endif
843
return(cur-i);
844
}
845
}
846
847
case '>':
848
ed_ungetchar(cntl('N'));
849
#ifdef ESH_NFIRST
850
if (in_mult)
851
{
852
location.his_command = histlines;
853
location.his_line = in_mult - 1;
854
}
855
else
856
{
857
location.his_command = histlines - 1;
858
location.his_line = 0;
859
}
860
#else
861
hline = histlines-1;
862
hloff = 0;
863
#endif /* ESH_NFIRST */
864
return(0);
865
866
case '<':
867
ed_ungetchar(cntl('P'));
868
hloff = 0;
869
#ifdef ESH_NFIRST
870
hline = hismin + 1;
871
return 0;
872
#else
873
return(hline-hismin);
874
#endif /* ESH_NFIRST */
875
876
877
case '#':
878
ed_ungetchar('\n');
879
ed_ungetchar('#');
880
ed_ungetchar(cntl('A'));
881
return(-1);
882
case '_' :
883
case '.' :
884
{
885
genchar name[MAXLINE];
886
char buf[MAXLINE];
887
char *ptr;
888
ptr = hist_word(buf,(count?count:-1));
889
#ifndef KSHELL
890
if(ptr==0)
891
{
892
beep();
893
break;
894
}
895
#endif /* KSHELL */
896
if ((eol - cur) >= sizeof(name))
897
{
898
beep();
899
return(-1);
900
}
901
mark = cur;
902
gencpy(name,&out[cur]);
903
while(*ptr)
904
{
905
out[cur++] = *ptr++;
906
eol++;
907
}
908
gencpy(&out[cur],name);
909
draw(UPDATE);
910
return(-1);
911
}
912
#ifdef KSHELL
913
914
/* file name expansion */
915
case cntl('[') : /* filename completion */
916
i = '\\';
917
case '*': /* filename expansion */
918
case '=': /* escape = - list all matching file names */
919
mark = cur;
920
if(ed_expand(out,&cur,&eol,i) < 0)
921
beep();
922
else if(i=='=')
923
draw(REFRESH);
924
else
925
draw(UPDATE);
926
return(-1);
927
928
/* search back for character */
929
case cntl(']'): /* feature not in book */
930
{
931
int c = ed_getchar();
932
if ((value == 0) || (value > eol))
933
{
934
beep();
935
return(-1);
936
}
937
i = cur;
938
if (i > 0)
939
i--;
940
while (i >= 0)
941
{
942
if (out[i] == c && --value==0)
943
goto update;
944
i--;
945
}
946
i = eol;
947
while (i > cur)
948
{
949
if (out[i] == c && --value==0)
950
break;
951
i--;
952
};
953
954
update:
955
cur = i;
956
draw(UPDATE);
957
return(-1);
958
959
case '[': /* feature not in book */
960
i = '_';
961
962
}
963
default:
964
/* look for user defined macro definitions */
965
if(ed_macro(i))
966
# ifdef ESH_BETTER
967
return(count); /* pass argument to macro */
968
# else
969
return(-1);
970
# endif /* ESH_BETTER */
971
#else
972
update:
973
cur = i;
974
draw(UPDATE);
975
return(-1);
976
977
default:
978
#endif /* KSHELL */
979
beep();
980
return(-1);
981
}
982
beep();
983
return(-1);
984
}
985
986
987
/*
988
* This routine process all commands starting with ^X
989
*/
990
991
static void
992
xcommands(count)
993
int count;
994
{
995
register int i = ed_getchar();
996
(&count,1); /* make sure count gets referenced to avoid warning */
997
switch(i)
998
{
999
case cntl('X'): /* exchange dot and mark */
1000
if (mark > eol)
1001
mark = eol;
1002
i = mark;
1003
mark = cur;
1004
cur = i;
1005
draw(UPDATE);
1006
return;
1007
1008
#ifdef KSHELL
1009
# ifdef ESH_BETTER
1010
case cntl('E'): /* invoke emacs on current command */
1011
if(ed_fulledit()==-1)
1012
beep();
1013
else
1014
ed_ungetchar('\n');
1015
return;
1016
1017
# define itos(i) ltos((long)(i), 10) /* want signed conversion */
1018
1019
case cntl('H'): /* ^X^H show history info */
1020
{
1021
char hbuf[MAXLINE];
1022
1023
strcpy(hbuf, "Current command ");
1024
strcat(hbuf, itos(hline));
1025
if (hloff)
1026
{
1027
strcat(hbuf, " (line ");
1028
strcat(hbuf, itos(hloff+1));
1029
strcat(hbuf, ")");
1030
}
1031
if ((hline != location.his_command) ||
1032
(hloff != location.his_line))
1033
{
1034
strcat(hbuf, "; Previous command ");
1035
strcat(hbuf, itos(location.his_command));
1036
if (location.his_line)
1037
{
1038
strcat(hbuf, " (line ");
1039
strcat(hbuf, itos(location.his_line+1));
1040
strcat(hbuf, ")");
1041
}
1042
}
1043
show_info(hbuf);
1044
return;
1045
}
1046
# if 0 /* debugging, modify as required */
1047
case cntl('D'): /* ^X^D show debugging info */
1048
{
1049
char debugbuf[MAXLINE];
1050
1051
strcpy(debugbuf, "count=");
1052
strcat(debugbuf, itos(count));
1053
strcat(debugbuf, " eol=");
1054
strcat(debugbuf, itos(eol));
1055
strcat(debugbuf, " cur=");
1056
strcat(debugbuf, itos(cur));
1057
strcat(debugbuf, " crallowed=");
1058
strcat(debugbuf, itos(crallowed));
1059
strcat(debugbuf, " plen=");
1060
strcat(debugbuf, itos(plen));
1061
strcat(debugbuf, " w_size=");
1062
strcat(debugbuf, itos(w_size));
1063
1064
show_info(debugbuf);
1065
return;
1066
}
1067
# endif /* debugging code */
1068
# endif /* ESH_BETTER */
1069
#endif /* KSHELL */
1070
1071
default:
1072
beep();
1073
return;
1074
}
1075
}
1076
1077
static void
1078
search(out,direction)
1079
genchar out[];
1080
int direction;
1081
{
1082
static int prevdirection = 1 ;
1083
#ifndef ESH_NFIRST
1084
histloc location;
1085
#endif
1086
register int i,sl;
1087
genchar str_buff[LBUF];
1088
register genchar *string = drawbuff;
1089
/* save current line */
1090
char sav_cur = cur;
1091
genncpy(str_buff,string,sizeof(str_buff)/CHARSIZE-1);
1092
string[0] = '^';
1093
string[1] = 'R';
1094
string[2] = '\0';
1095
sl = 2;
1096
cur = sl;
1097
draw(UPDATE);
1098
while ((i = ed_getchar())&&(i != '\r')&&(i != '\n'))
1099
{
1100
if (i==usrerase)
1101
{
1102
if (sl > 2)
1103
{
1104
string[--sl] = '\0';
1105
cur = sl;
1106
draw(UPDATE);
1107
}
1108
else
1109
beep();
1110
continue;
1111
}
1112
if (i==usrkill)
1113
{
1114
beep();
1115
goto restore;
1116
}
1117
if (i == '\\')
1118
{
1119
string[sl++] = '\\';
1120
string[sl] = '\0';
1121
cur = sl;
1122
draw(APPEND);
1123
i = ed_getchar();
1124
string[--sl] = '\0';
1125
}
1126
string[sl++] = i;
1127
string[sl] = '\0';
1128
cur = sl;
1129
draw(APPEND);
1130
}
1131
i = genlen(string);
1132
1133
if (direction < 1)
1134
{
1135
prevdirection = -prevdirection;
1136
direction = 1;
1137
}
1138
else
1139
direction = -1;
1140
if (i != 2)
1141
{
1142
#ifdef MULTIBYTE
1143
ed_external(string,(char*)string);
1144
#endif /* MULTIBYTE */
1145
strncpy(lstring,((char*)string)+2,SEARCHSIZE);
1146
prevdirection = direction;
1147
}
1148
else
1149
direction = prevdirection ;
1150
location = hist_find((char*)lstring,hline,1,direction);
1151
i = location.his_command;
1152
if(i>0)
1153
{
1154
hline = i;
1155
#ifdef ESH_NFIRST
1156
hloff = location.his_line = 0; /* display first line of multi line command */
1157
#else
1158
hloff = location.his_line;
1159
#endif /* ESH_NFIRST */
1160
hist_copy((char*)out,hline,hloff);
1161
#ifdef MULTIBYTE
1162
ed_internal((char*)out,out);
1163
#endif /* MULTIBYTE */
1164
return;
1165
}
1166
if (i < 0)
1167
{
1168
beep();
1169
#ifdef ESH_NFIRST
1170
location.his_command = hline;
1171
location.his_line = hloff;
1172
#else
1173
hloff = 0;
1174
hline = histlines;
1175
#endif /* ESH_NFIRST */
1176
}
1177
restore:
1178
genncpy(string,str_buff,sizeof(str_buff)/CHARSIZE-1);
1179
cur = sav_cur;
1180
return;
1181
}
1182
1183
1184
/* Adjust screen to agree with inputs: logical line and cursor */
1185
/* If 'first' assume screen is blank */
1186
/* Prompt is always kept on the screen */
1187
1188
static void
1189
draw(option)
1190
DRAWTYPE option;
1191
{
1192
#define NORMAL ' '
1193
#define LOWER '<'
1194
#define BOTH '*'
1195
#define UPPER '>'
1196
#define UNDEF 0
1197
1198
static char overflow; /* Screen overflow flag set */
1199
register genchar *sptr; /* Pointer within screen */
1200
1201
static int offset; /* Screen offset */
1202
static char scvalid; /* Screen is up to date */
1203
1204
genchar nscreen[2*MAXLINE]; /* New entire screen */
1205
genchar *ncursor; /* New cursor */
1206
register genchar *nptr; /* Pointer to New screen */
1207
char longline; /* Line overflow */
1208
genchar *logcursor;
1209
genchar *nscend; /* end of logical screen */
1210
register int i;
1211
1212
nptr = nscreen;
1213
sptr = drawbuff;
1214
logcursor = sptr + cur;
1215
longline = NORMAL;
1216
1217
if (option == FIRST || option == REFRESH)
1218
{
1219
overflow = NORMAL;
1220
cursor = screen;
1221
offset = 0;
1222
cr_ok = crallowed;
1223
if (option == FIRST)
1224
{
1225
scvalid = 1;
1226
return;
1227
}
1228
*cursor = '\0';
1229
putstring(Prompt); /* start with prompt */
1230
}
1231
1232
/*********************
1233
Do not update screen if pending characters
1234
**********************/
1235
1236
if ((lookahead)&&(option != FINAL))
1237
{
1238
1239
scvalid = 0; /* Screen is out of date, APPEND will not work */
1240
1241
return;
1242
}
1243
1244
/***************************************
1245
If in append mode, cursor at end of line, screen up to date,
1246
the previous character was a 'normal' character,
1247
and the window has room for another character.
1248
Then output the character and adjust the screen only.
1249
*****************************************/
1250
1251
1252
i = *(logcursor-1); /* last character inserted */
1253
1254
if ((option == APPEND)&&(scvalid)&&(*logcursor == '\0')&&
1255
print(i)&&((cursor-screen)<(w_size-1)))
1256
{
1257
putchar(i);
1258
*cursor++ = i;
1259
*cursor = '\0';
1260
return;
1261
}
1262
1263
/* copy the line */
1264
ncursor = nptr + ed_virt_to_phys(sptr,nptr,cur,0,0);
1265
nptr += genlen(nptr);
1266
sptr += genlen(sptr);
1267
nscend = nptr - 1;
1268
if(sptr == logcursor)
1269
ncursor = nptr;
1270
1271
/*********************
1272
Does ncursor appear on the screen?
1273
If not, adjust the screen offset so it does.
1274
**********************/
1275
1276
i = ncursor - nscreen;
1277
1278
if ((offset && i<=offset)||(i >= (offset+w_size)))
1279
{
1280
/* Center the cursor on the screen */
1281
offset = i - (w_size>>1);
1282
if (--offset < 0)
1283
offset = 0;
1284
}
1285
1286
/*********************
1287
Is the range of screen[0] thru screen[w_size] up-to-date
1288
with nscreen[offset] thru nscreen[offset+w_size] ?
1289
If not, update as need be.
1290
***********************/
1291
1292
nptr = &nscreen[offset];
1293
sptr = screen;
1294
1295
i = w_size;
1296
1297
while (i-- > 0)
1298
{
1299
1300
if (*nptr == '\0')
1301
{
1302
*(nptr + 1) = '\0';
1303
*nptr = ' ';
1304
}
1305
if (*sptr == '\0')
1306
{
1307
*(sptr + 1) = '\0';
1308
*sptr = ' ';
1309
}
1310
if (*nptr == *sptr)
1311
{
1312
nptr++;
1313
sptr++;
1314
continue;
1315
}
1316
setcursor(sptr-screen,*nptr);
1317
*sptr++ = *nptr++;
1318
#ifdef MULTIBYTE
1319
while(*nptr==MARKER)
1320
{
1321
*sptr++ = *nptr++;
1322
i--;
1323
cursor++;
1324
}
1325
#endif /* MULTIBYTE */
1326
}
1327
1328
/******************
1329
1330
Screen overflow checks
1331
1332
********************/
1333
1334
if (nscend >= &nscreen[offset+w_size])
1335
{
1336
if (offset > 0)
1337
longline = BOTH;
1338
else
1339
longline = UPPER;
1340
}
1341
else
1342
{
1343
if (offset > 0)
1344
longline = LOWER;
1345
}
1346
1347
/* Update screen overflow indicator if need be */
1348
1349
if (longline != overflow)
1350
{
1351
setcursor(w_size,longline);
1352
overflow = longline;
1353
}
1354
i = (ncursor-nscreen) - offset;
1355
setcursor(i,0);
1356
scvalid = 1;
1357
return;
1358
}
1359
1360
/*
1361
* put the cursor to the <new> position within screen buffer
1362
* if <c> is non-zero then output this character
1363
* cursor is set to reflect the change
1364
*/
1365
1366
static void
1367
setcursor(new,c)
1368
register int new,c;
1369
{
1370
register int old = cursor - screen;
1371
if (old > new)
1372
{
1373
if ((cr_ok == NO) || (2*(new+plen)>(old+plen)))
1374
{
1375
while (old > new)
1376
{
1377
putchar('\b');
1378
old--;
1379
}
1380
goto skip;
1381
}
1382
putstring(Prompt);
1383
old = 0;
1384
}
1385
while (new > old)
1386
putchar(screen[old++]);
1387
skip:
1388
if(c)
1389
{
1390
putchar(c);
1391
new++;
1392
}
1393
cursor = screen+new;
1394
return;
1395
}
1396
1397
#ifdef MULTIBYTE
1398
static int print(c)
1399
register int c;
1400
{
1401
return((c&~STRIP)==0 && isprint(c));
1402
}
1403
1404
static int isword(i)
1405
register int i;
1406
{
1407
register int c = drawbuff[i];
1408
return((c&~STRIP) || isalnum(c));
1409
}
1410
#endif /* MULTIBYTE */
1411
1412