-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathguitcap.c
2344 lines (2090 loc) · 58.7 KB
/
guitcap.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* guitcap.c */
#include "elvis.h"
#ifdef GUI_TERMCAP
#include <signal.h>
/* This file contains a termcap-based user interface. It is derived from the
* "curses.c" file of elvis 1.8.
*/
#define MINHEIGHT 4
/* Some termcap packages require the application code to supply a "BC"
* variable. Others (particularly ncurses) forbid it. The nice ones
* supply one if you don't, so they'll work either way.
*/
#ifdef NEED_BC
char *BC; /* :bc=: move cursor left */
#else
extern char *BC; /* :bc=: move cursor left */
#endif
/* HP-UX, and maybe some others, require the application code to supply
* an "ospeed" variable.
*/
#ifdef NEED_OSPEED
# ifdef NEED_SPEED_T
speed_t ospeed;
# else
short ospeed;
# endif
#endif
/* This macro is used to reset attributes and colors to normal values. */
#define revert(tw) if ((tw) == current)\
change(colorinfo[COLOR_FONT_NORMAL].fg,\
colorinfo[COLOR_FONT_NORMAL].bg,\
colorinfo[COLOR_FONT_NORMAL].da.bits);\
else\
change(colorinfo[COLOR_FONT_IDLE].fg,\
colorinfo[COLOR_FONT_IDLE].bg,\
colorinfo[COLOR_FONT_IDLE].da.bits)
/* Structs of this type are used to remember the location and size of each
* window. In the termcap interface, all windows must be as wide as the
* screen, and the sum of all windows' heights must equal the screen size.
*/
typedef struct twin_s
{
struct twin_s *next; /* some other window on this screen */
int height; /* size of the window */
int pos; /* position of the window */
int newheight; /* height after screen is rearranged */
int newpos; /* position after screen is rearranged */
int cursx, cursy; /* logical cursor position */
ELVCURSOR shape; /* logical cursor shape */
} TWIN;
static TWIN *twins; /* list of windows */
static TWIN *current; /* window with keyboard focus */
#if USE_PROTOTYPES
static ELVBOOL clrtoeol(GUIWIN *gw);
static ELVBOOL color(int fontcode, CHAR *colornam, ELVBOOL isfg, long *colorptr, unsigned char rgb[3]);
static ELVBOOL creategw(char *name,char * attributes);
static ELVBOOL focusgw(GUIWIN *gw);
static ELVBOOL scroll(GUIWIN *gw, int qty, ELVBOOL notlast);
static ELVBOOL shift(GUIWIN *gw, int qty, int rows);
static ELVBOOL tabcmd(GUIWIN *gw, _CHAR_ key2, long count);
static char *manynames(char *names);
static int init(int argc, char **argv);
static int keylabel(CHAR *given, int givenlen, CHAR **label, CHAR **rawptr);
static int test(void);
static int ttych(int ch);
static void beep(GUIWIN *gw);
static void destroygw(GUIWIN *gw, ELVBOOL force);
static void drawgraphic(GUIWIN *gw, long fg, long bg, int bits, CHAR *text, int len);
static void draw(GUIWIN *gw, long fg, long bg, int bits, CHAR *text, int len);
#ifdef FEATURE_SPLIT
static void drawborder(TWIN *tw);
#endif
static void endtcap(void);
static void flush(void);
static void loop(void);
static void mayhave(char **T, char *s);
static void movecurs(TWIN *tw);
static void moveto(GUIWIN *gw, int column, int row);
static void musthave(char **T, char *s);
static void pair(char **T, char **U, char *sT, char *sU);
static void change(long fg, long bg, int bits);
static void starttcap(void);
static void term(void);
static void ttyflush(void);
static void ttygetsize(void);
static ELVBOOL ttyprgopen(char *command, ELVBOOL willwrite, ELVBOOL willread);
static int ttyprgclose(void);
static RESULT stop(ELVBOOL alwaysfork);
#endif
static void reset P_((void));
static void chgsize P_((TWIN *tw, int newheight, ELVBOOL winch));
static void cursorshape P_((ELVCURSOR shape));
/* termcap values */
static ELVBOOL AM; /* :am: boolean: auto margins? */
static ELVBOOL PT; /* :pt: boolean: physical tabs? */
char PC; /* :pc=: pad character (not a string var!) */
static char *VB; /* :vb=: visible bell */
char *UP; /* :up=: move cursor up */
static char *AF; /* :AF=: change the foreground color */
static char *SO; /* :so=: standout start */
static char *SE; /* :se=: standout end */
static char *US; /* :us=: underline start */
static char *UE; /* :ue=: underline end */
static char *MD; /* :md=: bold start */
static char *ME; /* :me=: bold and half-bright end */
static char *MH; /* :mh=: half-bright start */
static char *CM; /* :cm=: cursor movement */
static char *DO; /* :do=: move down one line */
static char *DOmany; /* :DO=: move down many lines */
static char *CE; /* :ce=: clear to end of line */
static char *AL; /* :al=: add a line */
static char *ALmany; /* :AL=: add many lines */
static char *DL; /* :dl=: delete a line */
static char *DLmany; /* :DL=: delete many lines */
static char *SRev; /* :sr=: scroll reverse */
static char *KS; /* :ks=: init string for cursor */
static char *KE; /* :ke=: restore string for cursor */
static char *IC; /* :ic=: insert following char */
static char *ICmany; /* :IC=: insert many characters */
static char *DC; /* :dc=: delete a character */
static char *DCmany; /* :DC=: delete many characters */
static char *TI; /* :ti=: terminal init */
static char *TE; /* :te=: terminal exit */
static char *SC; /* :sc=: save cursor position & attribute */
static char *RC; /* :rc=: restore cursor position & attribute */
static char *CQ; /* :cQ=: normal cursor */
static char *CX; /* :cX=: cursor used for EX command/entry */
static char *CV; /* :cV=: cursor used for VI command mode */
static char *CI; /* :cI=: cursor used for VI input mode */
static char *CR; /* :cR=: cursor used for VI replace mode */
#ifdef FEATURE_MISC
static char *GS; /* :GS=:as=: start graphic character mode */
static char *GE; /* :GE=:ae=: end graphic character mode */
static char GC_V; /* vertical bar character */
static char GC_H; /* horizontal bar character */
static char GC_1; /* lower left corner character */
static char GC_2; /* horizontal line with up-tick character */
static char GC_3; /* lower right corner character */
static char GC_4; /* vertical line with right-tick character */
static char GC_5; /* center cross character */
static char GC_6; /* vertical line with left-tick character */
static char GC_7; /* upper left corner character */
static char GC_8; /* horizontal line with down-tick character */
static char GC_9; /* upper right corner character */
#endif
/* This is a table of keys which should be mapped, if present */
static struct
{
char *label; /* keytop legend of the key */
char *capnames; /* name(s) of the key's capability */
char *cooked; /* what the key should map to (if anything) */
MAPFLAGS flags; /* when the map should be effective */
char *rawin; /* raw characters sent by key */
}
keys[] =
{
{"<Up>", "ku", "k", MAP_NOSAVE|MAP_ALL},
{"<Down>", "kd", "j", MAP_NOSAVE|MAP_ALL},
{"<Left>", "kl", "h", MAP_NOSAVE|MAP_ALL},
{"<Right>", "kr", "l", MAP_NOSAVE|MAP_ALL},
{"<PgUp>", "PUkPk2", "\002", MAP_NOSAVE|MAP_ALL},
{"<PgDn>", "PDkNk5", "\006", MAP_NOSAVE|MAP_ALL},
{"<Home>", "HMkhK1", "^", MAP_NOSAVE|MAP_ALL},
{"<End>", "ENkHK5@7", "$", MAP_NOSAVE|MAP_ALL},
{"<Insert>", "kI", "i", MAP_NOSAVE|MAP_ALL},
#ifdef FEATURE_MISC
{"<Delete>", "kD", "x", MAP_NOSAVE|MAP_ALL},
{"<Compose>", "k+", "\013", MAP_NOSAVE|MAP_INPUT},
{"<C-Left>", "#4KL", "B", MAP_NOSAVE|MAP_ALL},
{"<C-Right>", "%iKR", "W", MAP_NOSAVE|MAP_ALL},
{"<S-Tab>", "kB", "g\t", MAP_NOSAVE|MAP_COMMAND},
#endif
{"#1", "k1"},
{"#2", "k2"},
{"#3", "k3"},
{"#4", "k4"},
{"#5", "k5"},
{"#6", "k6"},
{"#7", "k7"},
{"#8", "k8"},
{"#9", "k9"},
{"#10", "k0kak;"},
#ifdef FEATURE_MISC
{"#11", "F1"},
{"#12", "F2"},
{"#1s", "s1F3"},
{"#2s", "s2F4"},
{"#3s", "s3F5"},
{"#4s", "s4F6"},
{"#5s", "s5F7"},
{"#6s", "s6F8"},
{"#7s", "s7F9"},
{"#8s", "s8FA"},
{"#9s", "s9FB"},
{"#10s", "s0FC"},
{"#11s", "FD"},
{"#12s", "FE"},
{"#1c", "c1FF"},
{"#2c", "c2FG"},
{"#3c", "c3FH"},
{"#4c", "c4FI"},
{"#5c", "c5FJ"},
{"#6c", "c6FK"},
{"#7c", "c7FL"},
{"#8c", "c8FM"},
{"#9c", "c9FN"},
{"#10c", "c0FO"},
{"#11c", "FP"},
{"#12c", "FQ"},
{"#1a", "a1"},
{"#2a", "a2"},
{"#3a", "a3"},
{"#4a", "a4"},
{"#5a", "a5"},
{"#6a", "a6"},
{"#7a", "a7"},
{"#8a", "a8"},
{"#9a", "a9"},
{"#10a", "a0"}
#endif
};
/* These are GUI-dependent global options */
static OPTDESC goptdesc[] =
{
{"term", "ttytype", optsstring, optisstring},
{"ttyrows", "ttylines", optnstring, optisnumber},
{"ttycolumns", "ttycolumns", optnstring, optisnumber},
{"ttyunderline", "ttyu", NULL, NULL },
{"ttyitalic", "ttyi", NULL, NULL },
{"ttywrap", "ttyw", NULL, NULL }
};
struct ttygoptvals_s ttygoptvals;
/*----------------------------------------------------------------------------*/
/* These are mid-level terminal I/O functions. They buffer the output, but
* don't do much more than that.
*/
static char ttybuf[1500]; /* the output buffer */
static int ttycount; /* number of characters in ttybuf */
static char ttyerasekey; /* taken from the ioctl structure */
long ttycaught; /* bitmap of recently-received signals */
/* This indicates whether we've found the termcap entry yet */
static int gotentry = 0;
/* This function writes the contents of ttybuf() to the screen */
static void ttyflush()
{
if (ttycount > 0)
{
ttywrite(ttybuf, ttycount);
ttycount = 0;
}
}
/* This function is used internally. It is passed to the tputs() function
* which uses it to output individual characters. This function saves the
* characters in a buffer and outputs them in a bunch.
*/
static int ttych(ch)
int ch; /* character to be output */
{
ttybuf[ttycount++] = ch;
if (ttycount >= QTY(ttybuf))
ttyflush();
#ifndef NDEBUG
ttybuf[ttycount] = '\0';
#endif
return ch;
}
/* These store masks for resetting COLOR_XXX attribute bits. Although each
* of these is intended to reset only its own attribute bits, it is possible
* that some terminals will use a single string for resetting multiple
* attributes, so the masks must be computed at run time, after the termcap
* entry has been read.
*/
static int UEmask; /* attributes reset by :ue=: -- normally UNDERLINE */
static int SEmask; /* attributes reset by :se=: -- normally SET (standout) */
static int MEmask; /* attributes reset by :me=: -- normally BOLD and ITALIC */
static ELVBOOL fgcolored; /* have foreground colors been set? */
static ELVBOOL bgcolored; /* have background colors been set? */
static long currentfg; /* foreground color code */
static long currentbg; /* background color code */
static int currentbits; /* bitmap of other attributes */
static int viscreen; /* is terminal switched to edit screen yet? */
/* Change attributes. The color support assumes your terminal is ANSI-like
* (which is safe since color() only allows you to set colors for ANSI-like
* terminals) but the rest of the code is purely termcap-driven.
*/
static void change(fg, bg, bits)
long fg; /* new foreground color, if fgcolored */
long bg; /* new background color, if bgcolored */
int bits; /* attribute bits */
{
char ansicolor[50];
int resetting, setting;
/* Don't change colors while the other screen is being displayed */
if (!viscreen)
return;
/* If foreground is set to a bright color, then we want to convert it
* to either white + bold (if bold was already set), or
* to a dim color + bold (if bold wasn't set already).
*/
if (fgcolored && fg >= 10)
{
if (bits & COLOR_BOLD)
fg = 7;
else
fg -= 10, bits |= COLOR_BOLD;
}
/* Italic is disabled if "nottyitalic" */
if (!o_ttyitalic)
bits &= ~COLOR_ITALIC;
/* Italics are shown via underlining, if there is no :mh=: string */
if (!MH && (bits & COLOR_ITALIC))
bits = (bits & ~COLOR_ITALIC) | COLOR_UNDERLINED;
/* Underlining is disabled if "nottyunderline" and we have bg color */
/* If "nottyitalic", then never use underline ever */
if (!o_ttyunderline && (!o_ttyitalic || bgcolored))
bits &= ~COLOR_UNDERLINED;
/* Termcap doesn't allow bold & italics to mix. If attempting to mix,
* then use plain bold.
*/
if ((bits & (COLOR_BOLD|COLOR_ITALIC)) == (COLOR_BOLD|COLOR_ITALIC))
bits &= ~COLOR_ITALIC;
/* Okay, we are finally ready to begin outputting escape sequences.
* This proceeds in three phases: First we turn off any attributes
* that must be off, then we change colors, and finally we turn on
* any attributes which should be on. We do it this way because
* sometimes turning off an attribute will affect colors or other
* attributes.
*/
/* Decide which attributes to turn off. */
resetting = currentbits & ~bits;
if ((resetting & (COLOR_BOLD|COLOR_ITALIC)) && ME)
{
tputs(ME, 1, ttych);
currentbits &= MEmask;
currentfg = currentbg = -1;
}
if ((resetting & COLOR_UNDERLINED) && UE)
{
tputs(UE, 1, ttych);
currentbits &= UEmask;
currentfg = currentbg = -1;
}
if ((resetting & (COLOR_BOXED|COLOR_LEFTBOX|COLOR_RIGHTBOX)) && SE)
{
tputs(SE, 1, ttych);
currentbits &= SEmask;
currentfg = currentbg = -1;
}
/* Change foreground, if set & different */
if (fgcolored && fg != currentfg)
{
/* Try to fold bold & bg into the change */
if (bgcolored && bg != currentbg)
{
if (bg < 8)
sprintf(ansicolor, "\033[%ld;%ld%sm", bg + 40,
fg + 30, bits & COLOR_BOLD ? ";1" : "");
else
{
sprintf(ansicolor, "\033[m\033[%ld%sm",
fg + 30, bits & COLOR_BOLD ? ";1" : "");
currentbits = 0;
}
tputs(ansicolor, 1, ttych);
currentbits |= (bits & COLOR_BOLD);
currentbg = bg;
}
else
{
sprintf(ansicolor, "\033[%ld%sm",
fg + 30, bits & COLOR_BOLD ? ";1" : "");
tputs(ansicolor, 1, ttych);
currentbits |= (bits & COLOR_BOLD);
}
currentfg = fg;
}
/* Change background, if set & different */
if (bgcolored && bg != currentbg)
{
/* Just change the background */
if (bg < 8)
sprintf(ansicolor, "\033[%ldm", bg + 40);
else
{
strcpy(ansicolor, "\033[m");
currentbits = 0;
}
tputs(ansicolor, 1, ttych);
currentbg = bg;
}
/* Set attributes */
setting = bits & ~currentbits;
if ((setting & COLOR_BOLD) && MD)
tputs(MD, 1, ttych);
if ((setting & COLOR_ITALIC) && MH)
tputs(MH, 1, ttych);
if ((setting & COLOR_UNDERLINED) && US)
tputs(US, 1, ttych);
if ((setting & (COLOR_BOXED|COLOR_LEFTBOX|COLOR_RIGHTBOX)) && SO)
tputs(SO, 1, ttych);
currentbits = bits;
}
/* Send any required termination strings. Turn off "raw" mode. */
void ttysuspend()
{
/* revert to the normal font */
revert(NULL);
/* restore some things */
if (CQ) tputs(CQ, 1, ttych); /* restore cursor shape */
if (TE) tputs(TE, 1, ttych); /* restore terminal mode/page */
viscreen = 0;
if (KE) tputs(KE, 1, ttych); /* restore keypad mode */
if (RC) tputs(RC, 1, ttych); /* restore cursor & attributes */
/* no cursor movement for terminals with te capability */
if (!TE)
{
/* Move the cursor to the bottom of the screen */
tputs(tgoto(CM, 0, (int)o_ttyrows - 1), 0, ttych);
ttych('\n');
}
ttyflush();
/* change the terminal mode back the way it was */
ttynormal();
}
/* Put the terminal in RAW mode. Send any required strings */
void ttyresume(sendstr)
ELVBOOL sendstr; /* send strings? */
{
/* change the terminal mode to cbreak/noecho */
ttyerasekey = ELVCTRL('H');/* the default */
ttyraw(&ttyerasekey);
/* send the initialization strings */
if (sendstr)
{
ttych('\r');
tputs(CE, (int)o_ttycolumns, ttych);
if (TI) tputs(TI, 1, ttych);
viscreen = 1;
if (KS) tputs(KS, 1, ttych);
}
/* reset, so we don't try any suspicious optimizations */
reset();
}
/* This function determines the screen size. It does this by calling the
* OS-dependent ttysize() function if possible, or from the termcap entry
* otherwise.
*/
static void ttygetsize()
{
int lines;
int cols;
char *tmp;
/* get the window size, one way or another. */
lines = cols = 0;
if (!ttysize(&lines, &cols) || lines < 2 || cols < 30)
{
/* get lines from $LINES or :li#: */
tmp = getenv("LINES");
if (tmp)
lines = atoi(tmp);
else
lines = tgetnum("li");
if (lines <= 0)
lines = 24;
/* get columns from $COLUMNS or :co#: */
tmp = getenv("COLUMNS");
if (tmp)
cols = atoi(tmp);
else
cols = tgetnum("co");
if (cols <= 0)
cols = 80;
}
/* did we get a realistic value? */
if (lines >= 2 && cols >= 30)
{
o_ttyrows = lines;
o_ttycolumns = cols;
}
optflags(o_ttyrows) |= OPT_HIDE;
optflags(o_ttycolumns) |= OPT_HIDE;
}
/* end of low-level terminal control */
/*----------------------------------------------------------------------------*/
/* start of termcap operations */
static char *capbuf;/* used for allocation space for termcap strings */
/* This function fetches an optional string from termcap */
static void mayhave(T, s)
char **T; /* where to store the returned pointer */
char *s; /* name of the capability */
{
char *val;
val = tgetstr(s, &capbuf);
if (val)
{
*T = val;
}
}
/* This function fetches a required string from termcap */
static void musthave(T, s)
char **T; /* where to store the returned pointer */
char *s; /* name of the capability */
{
mayhave(T, s);
if (!*T)
{
msg(MSG_FATAL, "[s]termcap needs $1", s);
}
}
/* This function fetches a pair of strings from termcap. If one of them is
* missing, then the other one is ignored.
*/
static void pair(T, U, sT, sU)
char **T; /* where to store the first pointer */
char **U; /* where to store the second pointer */
char *sT; /* name of the first capability */
char *sU; /* name of the second capability */
{
mayhave(T, sT);
mayhave(U, sU);
if (!*T || !*U)
{
*T = *U = "";
}
}
/* This function gets a single termcap string in a special static buffer.
* Returns the string if successful, or NULL if unsuccessful.
*/
static char *manynames(names)
char *names; /* possible names (each pair of chars is one name) */
{
char name[3];
int i;
char *value;
/* for each possible name... */
for (i = 0; names[i]; i += 2)
{
/* see if the termcap string can be found */
name[0] = names[i];
name[1] = names[i + 1];
name[2] = '\0';
value = tgetstr(name, &capbuf);
if (value)
{
/* found! */
return value;
}
}
return NULL;
}
/* get termcap values */
static void starttcap()
{
static char cbmem[800];
char *str = NULL;
int i;
/* make sure TERM variable is set */
o_term = toCHAR(ttytermtype());
if (!o_term)
{
o_term = toCHAR("unknown");
}
optflags(o_term) |= OPT_SET|OPT_LOCK|OPT_NODFLT;
/* If the background option wasn't set via the $ELVISBG environment
* variable, then we should try to guess whether this terminal has
* a light or dark background. Our guess: The background is probably
* dark unless this is an xterm-like terminal emulator, or KDE's "kvt"
* which breaks a lot of xterm conventions, or has a name that ends
* with "-r" or "-rv" -- those two suffixes commonly denote reverse
* video versions of termcap/terminfo entries.
*/
if (getenv("ELVISBG") == NULL)
{
o_background = 'd'; /* "dark" */
if (getenv("WINDOWID") != NULL
|| !CHARcmp(o_term, toCHAR("kvt"))
|| !CHARcmp(o_term, toCHAR("xterm"))
|| ((str = strrchr(tochar8(o_term), '-')) != NULL
&& str[1] == 'r'))
{
o_background = 'l'; /* "light" */
}
}
/* allocate memory for capbuf */
capbuf = cbmem;
/* get the termcap entry */
if (!gotentry)
{
switch (tgetent(ttybuf, tochar8(o_term)))
{
case -1: msg(MSG_FATAL, "termcap database unreadable");
case 0: msg(MSG_FATAL, "[S]TERM=$1 unknown", o_term);
}
}
/* get strings */
musthave(&UP, "up");
BC = "\b";
mayhave(&BC, "bc");
mayhave(&VB, "vb");
musthave(&CM, "cm");
DO = "\n";
mayhave(&DO, "do");
mayhave(&DOmany, "DO");
mayhave(&TI, "ti");
mayhave(&TE, "te");
pair(&SC, &RC, "sc", "rc"); /* cursor save/restore */
pair(&KS, &KE, "ks", "ke"); /* keypad enable/disable */
mayhave(&AF, "AF");
if (tgetnum("sg") <= 0)
{
pair(&SO, &SE, "so", "se");
}
if (tgetnum("ug") <= 0)
{
pair(&US, &UE, "us", "ue");
/* bor: some terminals don't have :md:, but _do_ have :me:
Check, that we can switch attribute off before using it
*/
mayhave(&ME, "me");
if (ME && *ME)
{
mayhave(&MD, "md");
mayhave(&MH, "mh");
mayhave(&str, "mr");
if (str && (!SO || !strcmp(str, SO)))
{
SO = str;
SE = ME;
}
}
}
mayhave(&ICmany, "IC");
mayhave(&IC, "ic");
mayhave(&DCmany, "DC");
mayhave(&DC, "dc");
mayhave(&ALmany, "AL");
mayhave(&AL, "al");
mayhave(&DLmany, "DL");
mayhave(&DL, "dl");
musthave(&CE, "ce");
mayhave(&SRev, "sr");
/* cursor shapes */
CQ = tgetstr("cQ", &capbuf);
if (CQ)
{
CX = tgetstr("cX", &capbuf);
if (!CX) CX = CQ;
CV = tgetstr("cV", &capbuf);
if (!CV) CV = CQ;
CI = tgetstr("cI", &capbuf);
if (!CI) CI = CQ;
CR = tgetstr("cR", &capbuf);
if (!CR) CR = CQ;
}
else
{
CQ = CV = "";
pair(&CQ, &CV, "ve", "vs");
CX = CI = CQ;
CR = CV;
}
#ifdef FEATURE_MISC
/* graphic characters */
str = tgetstr("ac", &capbuf);
if (str)
{
/* apparently we're using the :as=:ae=:ac=: style */
pair(&GS, &GE, "as", "ae");
for (i = 0; str[i] && str[i + 1]; i += 2)
{
switch (str[i])
{
case 'q': GC_H = str[i + 1]; break;
case 'x': GC_V = str[i + 1]; break;
case 'm': GC_1 = str[i + 1]; break;
case 'v': GC_2 = str[i + 1]; break;
case 'j': GC_3 = str[i + 1]; break;
case 't': GC_4 = str[i + 1]; break;
case 'n': GC_5 = str[i + 1]; break;
case 'u': GC_6 = str[i + 1]; break;
case 'l': GC_7 = str[i + 1]; break;
case 'w': GC_8 = str[i + 1]; break;
case 'k': GC_9 = str[i + 1]; break;
}
}
}
else
{
/* maybe we have :GH=:GV=:... strings? */
if ((str = tgetstr("GH", &capbuf)) != NULL) GC_H = *str;
if ((str = tgetstr("GV", &capbuf)) != NULL) GC_V = *str;
if ((str = tgetstr("G3", &capbuf)) != NULL) GC_1 = *str;
if ((str = tgetstr("GU", &capbuf)) != NULL) GC_2 = *str;
if ((str = tgetstr("G4", &capbuf)) != NULL) GC_3 = *str;
if ((str = tgetstr("GR", &capbuf)) != NULL) GC_4 = *str;
if ((str = tgetstr("GC", &capbuf)) != NULL) GC_5 = *str;
if ((str = tgetstr("GL", &capbuf)) != NULL) GC_6 = *str;
if ((str = tgetstr("G2", &capbuf)) != NULL) GC_7 = *str;
if ((str = tgetstr("GD", &capbuf)) != NULL) GC_8 = *str;
if ((str = tgetstr("G1", &capbuf)) != NULL) GC_9 = *str;
pair(&GS, &GE, "GS", "GE");
/* if we have no :GS=:GE=: strings, then set MSB of chars */
if (!GS || !*GS)
{
if (GC_H) GC_H |= 0x80;
if (GC_V) GC_V |= 0x80;
if (GC_1) GC_1 |= 0x80;
if (GC_2) GC_2 |= 0x80;
if (GC_3) GC_3 |= 0x80;
if (GC_4) GC_4 |= 0x80;
if (GC_5) GC_5 |= 0x80;
if (GC_6) GC_6 |= 0x80;
if (GC_7) GC_7 |= 0x80;
if (GC_8) GC_8 |= 0x80;
if (GC_9) GC_9 |= 0x80;
}
}
#endif /* FEATURE_MISC */
/* key strings */
for (i = 0; i < QTY(keys); i++)
{
keys[i].rawin = manynames(keys[i].capnames);
}
/* other termcap stuff */
AM = (ELVBOOL)(tgetflag("am") && !tgetflag("xn"));
PT = (ELVBOOL)tgetflag("pt");
/* Compute the attribute resetting masks. Sometimes the same string
* will reset more than one attribute, so we need to check for identical
* strings and combine their effect on attributes.
*/
SEmask = ~(COLOR_BOXED|COLOR_LEFTBOX|COLOR_RIGHTBOX);
UEmask = ~COLOR_UNDERLINED;
MEmask = ~(COLOR_BOLD|COLOR_ITALIC);
if (SE && UE && !strcmp(SE, UE))
SEmask = UEmask &= SEmask;
if (SE && ME && !strcmp(SE, ME))
SEmask = MEmask &= SEmask;
if (UE && ME && !strcmp(UE, ME))
UEmask = MEmask &= UEmask;
/* change the terminal mode to cbreak/noecho */
ttyinit();
if (SC) tputs(SC, 1, ttych);
ttyresume(ElvTrue);
/* try to get true screen size, from the operating system */
ttygetsize();
}
static void endtcap()
{
/* change the terminal mode back the way it was */
ttysuspend();
}
/* end of termcap operations */
/*----------------------------------------------------------------------------*/
/* start of GUI functions */
static int afterprg; /* expose windows (after running prg) */
static int afterscrl; /* number of status lines (after running prg) */
static int physx, physy; /* physical cursor position */
static int nwindows; /* number of windows allocated */
/*----------------------------------------------------------------------------*/
/* This is an internal function which moves the physical cursor to the logical
* position of the cursor in a given window, if it isn't there already.
*/
static void movecurs(tw)
TWIN *tw; /* window whose cursor is to be moved */
{
int y = tw->pos + tw->cursy;
int i;
/* maybe we don't need to move at all? */
/* JohnW 13/08/96 > 1 was > 0 */
if ((afterprg > 1 && y <= o_ttyrows - afterscrl)
|| (y == physy && tw->cursx == physx))
{
/* already there */
return;
}
if (afterprg == 1) /* JohnW 13/08/96 - only use the bottom line */
{
/* We get the 'bottom' line by adding the difference between
* the window's bottom line and the screen's bottom line. This
* then allows scrolling of an input line and moving back onto
* the penultimate line */
tputs(tgoto(CM, tw->cursx, y + ((int)o_ttyrows - (tw->pos + tw->height))), 1, ttych);
physx = tw->cursx;
return;
}
else
/* Try some simple alternatives to the CM string */
if (y >= physy
&& (y - physy < gui->movecost || DOmany)
&& (tw->cursx == 0 || tw->cursx == physx))
{
/* output a bunch of newlines, and maybe a carriage return */
if (y - physy > 1 && DOmany)
tputs(tgoto(DOmany, y - physy, y - physy), 1, ttych);
else
for (i = y - physy; i > 0; i--)
tputs(DO, 1, ttych);
if (tw->cursx != physx)
ttych('\r');
}
else if (y == physy && tw->cursx < physx && physx - tw->cursx < gui->movecost)
{
/* output a bunch of backspaces */
for (i = physx - tw->cursx; i > 0; i--)
tputs(BC, 0, ttych);
}
/* many other special cases could be handled here */
else
{
/* revert to the normal font */
revert(tw);
/* move it the hard way */
tputs(tgoto(CM, tw->cursx, y), 1, ttych);
}
/* done! */
physx = tw->cursx;
physy = tw->cursy + tw->pos;
}
/* clear to end of line */
static ELVBOOL clrtoeol(gw)
GUIWIN *gw; /* window whose row is to be cleared */
{
TWIN *tw = (TWIN *)gw;
/* after running a program, disable the :ce: string for a while. */
/* JohnW 13/08/96 Not disabled for the bottom line of window */
if (afterprg && tw->cursy != (int)tw->height - 1)
return ElvTrue;
/* if we're on the bottom row of a window which doesn't end at the
* bottom of the screen, then fail. This will cause elvis to output
* a bunch of spaces instead. The draw() function will convert those
* spaces to underscore characters so the window has a border.
*/
if ( !afterprg && /* JohnW 13/08/96 Not after a prog... */
tw->cursy == tw->height - 1 && tw->pos + tw->height != o_ttyrows)
{
return ElvFalse;
}
/* revert to the normal font */
revert(tw);
/* move the physical cursor to where the window thinks it should be */
movecurs(tw);
/* output the clear-to-eol string */
tputs(CE, (int)(o_ttycolumns - tw->cursx), ttych);
return ElvTrue;
}
/* insert or delete columns */
static ELVBOOL shift(gw, qty, rows)
GUIWIN *gw; /* window to be shifted */
int qty; /* columns to insert (may be negative to delete) */
int rows; /* number of rows affected (always 1 for this GUI) */
{
/* revert to the normal font */
revert((TWIN *)gw);
/* move the physical cursor to where this window thinks it is */
movecurs((TWIN *)gw);
if (qty > 0)
{
/* can we do many at once? */
if (qty > 1 && ICmany)
{
tputs(tgoto(ICmany, qty, qty), 1, ttych);
}
else if (IC)
{
for (; qty > 0; qty--)
{
tputs(IC, 1, ttych);
}
}
else
{
/* don't know how to insert */
return ElvFalse;
}
}
else
{
/* take the absolute value of qty */
qty = -qty;
/* can we do many deletions at once? */
if (qty > 1 && DCmany)
{
tputs(tgoto(DCmany, qty, qty), 1, ttych);
}
else if (DC)
{
for (; qty > 0; qty--)
{
tputs(DC, 1, ttych);
}
}
else
{
/* don't know how to delete */
return ElvFalse;
}
}
return ElvTrue;
}
/* insert or delete rows. qty is positive to insert, negative to delete */
static ELVBOOL scroll(gw, qty, notlast)
GUIWIN *gw; /* window to be scrolled */
int qty; /* rows to insert (may be nagative to delete) */