1 /* This file is for functions having to do with key bindings,
2 descriptions, help commands and startup file.
3
4 written 11-feb-86 by Daniel Lawrence
5 */
6
7 #include <stdio.h>
8 #include "estruct.h"
9 #include "eproto.h"
10 #include "edef.h"
11 #include "elang.h"
12 #include "epath.h"
13
help(f,n)14 PASCAL NEAR help(f, n) /* give me some help!!!!
15 bring up a fake buffer and read the help file
16 into it with view mode */
17
18 int f,n; /* prefix flag and argument */
19
20 {
21 register BUFFER *bp; /* buffer pointer to help */
22 char *fname; /* file name of help file */
23
24 /* first check if we are already here */
25 bp = bfind("emacs.hlp", FALSE, BFINVS);
26
27 if (bp == NULL) {
28 fname = flook(pathname[1], FALSE);
29 if (fname == NULL) {
30 mlwrite(TEXT12);
31 /* "[Help file is not online]" */
32 return(FALSE);
33 }
34 }
35
36 /* split the current window to make room for the help stuff */
37 if (splitwind(FALSE, 1) == FALSE)
38 return(FALSE);
39
40 if (bp == NULL) {
41 /* and read the stuff in */
42 if (getfile(fname, FALSE) == FALSE)
43 return(FALSE);
44 } else
45 swbuffer(bp);
46
47 /* make this window in VIEW mode, update all mode lines */
48 curwp->w_bufp->b_mode |= MDVIEW;
49 curwp->w_bufp->b_flag |= BFINVS;
50 upmode();
51 return(TRUE);
52 }
53
deskey(f,n)54 PASCAL NEAR deskey(f, n) /* describe the command for a certain key */
55
56 int f,n; /* prefix flag and argument */
57
58 {
59 register int c; /* key to describe */
60 register char *ptr; /* string pointer to scan output strings */
61 char outseq[NSTRING]; /* output buffer for command sequence */
62
63 /* prompt the user to type us a key to describe */
64 mlwrite(TEXT13);
65 /* ": describe-key " */
66
67 /* get the command sequence to describe
68 change it to something we can print as well */
69 /* and dump it out */
70 ostring(cmdstr(c = getckey(FALSE), &outseq[0]));
71 ostring(" ");
72
73 /* find the right ->function */
74 if ((ptr = getfname(getbind(c))) == NULL)
75 ptr = "Not Bound";
76
77 /* output the command sequence */
78 ostring(ptr);
79 return(TRUE);
80 }
81
82 /* bindtokey: add a new key to the key binding table */
83
bindtokey(f,n)84 PASCAL NEAR bindtokey(f, n)
85
86 int f, n; /* command arguments [IGNORED] */
87
88 {
89 register unsigned int c;/* command key to bind */
90 register int (PASCAL NEAR *kfunc)();/* ptr to the requested function to bind to */
91 register KEYTAB *ktp; /* pointer into the command table */
92 register int found; /* matched command flag */
93 char outseq[80]; /* output buffer for keystroke sequence */
94
95 /* prompt the user to type in a key to bind */
96 /* get the function name to bind it to */
97 kfunc = getname(TEXT15);
98 /* ": bind-to-key " */
99 if (kfunc == NULL) {
100 mlwrite(TEXT16);
101 /* "[No such function]" */
102 return(FALSE);
103 }
104 if (clexec == FALSE) {
105 ostring(" ");
106 TTflush();
107 }
108
109 /* get the command sequence to bind */
110 c = getckey((kfunc == meta) || (kfunc == cex) ||
111 (kfunc == unarg) || (kfunc == ctrlg));
112
113 if (clexec == FALSE) {
114
115 /* change it to something we can print as well */
116 /* and dump it out */
117 ostring(cmdstr(c, &outseq[0]));
118 }
119
120 /* if the function is a unique prefix key */
121 if (kfunc == unarg || kfunc == ctrlg || kfunc == quote) {
122
123 /* search for an existing binding for the prefix key */
124 ktp = &keytab[0];
125 while (ktp->k_type != BINDNUL) {
126 if (ktp->k_type == BINDFNC && ktp->k_ptr.fp == kfunc)
127 unbindchar(ktp->k_code);
128 ++ktp;
129 }
130
131 /* reset the appropriate global prefix variable */
132 if (kfunc == unarg)
133 reptc = c;
134 if (kfunc == ctrlg)
135 abortc = c;
136 if (kfunc == quote)
137 quotec = c;
138 }
139
140 /* search the table to see if it exists */
141 ktp = &keytab[0];
142 found = FALSE;
143 while (ktp->k_type != BINDNUL) {
144 if (ktp->k_code == c) {
145 found = TRUE;
146 break;
147 }
148 ++ktp;
149 }
150
151 if (found) { /* it exists, just change it then */
152 ktp->k_ptr.fp = kfunc;
153 ktp->k_type = BINDFNC;
154 } else { /* otherwise we need to add it to the end */
155 /* if we run out of binding room, bitch */
156 if (ktp >= &keytab[NBINDS]) {
157 mlwrite(TEXT17);
158 /* "Binding table FULL!" */
159 return(FALSE);
160 }
161
162 ktp->k_code = c; /* add keycode */
163 ktp->k_ptr.fp = kfunc; /* and the function pointer */
164 ktp->k_type = BINDFNC; /* and the binding type */
165 ++ktp; /* and make sure the next is null */
166 ktp->k_code = 0;
167 ktp->k_type = BINDNUL;
168 ktp->k_ptr.fp = NULL;
169 }
170
171 /* if we have rebound the meta key, make the
172 search terminators follow it */
173 if (kfunc == meta) {
174 sterm = c;
175 isterm = c;
176 }
177
178 return(TRUE);
179 }
180
181 /* macrotokey: Bind a key to a macro in the key binding table */
182
macrotokey(f,n)183 PASCAL NEAR macrotokey(f, n)
184
185 int f, n; /* command arguments [IGNORED] */
186
187 {
188 register unsigned int c;/* command key to bind */
189 register BUFFER *kmacro;/* ptr to buffer of macro to bind to key */
190 register KEYTAB *ktp; /* pointer into the command table */
191 register int found; /* matched command flag */
192 register int status; /* error return */
193 char outseq[80]; /* output buffer for keystroke sequence */
194 char bufn[NBUFN]; /* buffer to hold macro name */
195
196 /* get the buffer name to use */
197 if ((status=mlreply(TEXT215, &bufn[1], NBUFN-2)) != TRUE)
198 /* ": macro-to-key " */
199 return(status);
200
201 /* build the responce string for later */
202 strcpy(outseq, TEXT215);
203 /* ": macro-to-key " */
204 strcat(outseq, &bufn[1]);
205
206 /* translate it to a buffer pointer */
207 bufn[0] = '[';
208 strcat(bufn, "]");
209 if ((kmacro=bfind(bufn, FALSE, 0)) == NULL) {
210 mlwrite(TEXT130);
211 /* "Macro not defined"*/
212 return(FALSE);
213 }
214
215 strcat(outseq, " ");
216 mlwrite(outseq);
217
218 /* get the command sequence to bind */
219 c = getckey(FALSE);
220
221 /* change it to something we can print as well */
222 /* and dump it out */
223 ostring(cmdstr(c, &outseq[0]));
224
225 /* search the table to see if it exists */
226 ktp = &keytab[0];
227 found = FALSE;
228 while (ktp->k_type != BINDNUL) {
229 if (ktp->k_code == c) {
230 found = TRUE;
231 break;
232 }
233 ++ktp;
234 }
235
236 if (found) { /* it exists, just change it then */
237 ktp->k_ptr.buf = kmacro;
238 ktp->k_type = BINDBUF;
239 } else { /* otherwise we need to add it to the end */
240 /* if we run out of binding room, bitch */
241 if (ktp >= &keytab[NBINDS]) {
242 mlwrite(TEXT17);
243 /* "Binding table FULL!" */
244 return(FALSE);
245 }
246
247 ktp->k_code = c; /* add keycode */
248 ktp->k_ptr.buf = kmacro; /* and the function pointer */
249 ktp->k_type = BINDBUF; /* and the binding type */
250 ++ktp; /* and make sure the next is null */
251 ktp->k_code = 0;
252 ktp->k_type = BINDNUL;
253 ktp->k_ptr.fp = NULL;
254 }
255
256 return(TRUE);
257 }
258
259 /* unbindkey: delete a key from the key binding table */
260
unbindkey(f,n)261 PASCAL NEAR unbindkey(f, n)
262
263 int f, n; /* command arguments [IGNORED] */
264
265 {
266 register int c; /* command key to unbind */
267 char outseq[80]; /* output buffer for keystroke sequence */
268
269 /* prompt the user to type in a key to unbind */
270 mlwrite(TEXT18);
271 /* ": unbind-key " */
272
273 /* get the command sequence to unbind */
274 c = getckey(FALSE); /* get a command sequence */
275
276 /* change it to something we can print as well */
277 /* and dump it out */
278 ostring(cmdstr(c, &outseq[0]));
279
280 /* if it isn't bound, bitch */
281 if (unbindchar(c) == FALSE) {
282 mlwrite(TEXT19);
283 /* "[Key not bound]" */
284 return(FALSE);
285 }
286 return(TRUE);
287 }
288
unbindchar(c)289 PASCAL NEAR unbindchar(c)
290
291 int c; /* command key to unbind */
292
293 {
294 register KEYTAB *ktp; /* pointer into the command table */
295 register KEYTAB *sktp; /* saved pointer into the command table */
296 register int found; /* matched command flag */
297
298 /* search the table to see if the key exists */
299 ktp = &keytab[0];
300 found = FALSE;
301 while (ktp->k_type != BINDNUL) {
302 if (ktp->k_code == c) {
303 found = TRUE;
304 break;
305 }
306 ++ktp;
307 }
308
309 /* if it isn't bound, bitch */
310 if (!found)
311 return(FALSE);
312
313 /* save the pointer and scan to the end of the table */
314 sktp = ktp;
315 while (ktp->k_type != BINDNUL)
316 ++ktp;
317 --ktp; /* backup to the last legit entry */
318
319 /* copy the last entry to the current one */
320 sktp->k_code = ktp->k_code;
321 sktp->k_type = ktp->k_type;
322 if (sktp->k_type == BINDFNC)
323 sktp->k_ptr.fp = ktp->k_ptr.fp;
324 else if (sktp->k_type == BINDBUF)
325 sktp->k_ptr.buf = ktp->k_ptr.buf;
326
327 /* null out the last one */
328 ktp->k_code = 0;
329 ktp->k_type = BINDNUL;
330 ktp->k_ptr.fp = NULL;
331 return(TRUE);
332 }
333
334 /* unbind all the keys bound to a buffer (which we can then delete */
335
unbind_buf(bp)336 VOID PASCAL NEAR unbind_buf(bp)
337
338 BUFFER *bp; /* buffer to unbind all keys connected to */
339
340 {
341 register KEYTAB *ktp; /* pointer into the command table */
342
343 /* search the table to see if the key exists */
344 ktp = &keytab[0];
345 while (ktp->k_type != BINDNUL) {
346 if (ktp->k_type == BINDBUF) {
347 if (ktp->k_ptr.buf == bp) {
348 unbindchar(ktp->k_code);
349 --ktp;
350 }
351 }
352 ++ktp;
353 }
354 }
355
356 /* Describe bindings:
357
358 bring up a fake buffer and list the key bindings
359 into it with view mode
360 */
361
desbind(f,n)362 PASCAL NEAR desbind(f, n)
363
364 int f,n; /* prefix flag and argument */
365
366 {
367 return(buildlist(TRUE, ""));
368 }
369
apro(f,n)370 PASCAL NEAR apro(f, n) /* Apropos (List functions that match a substring) */
371
372 int f,n; /* prefix flag and argument */
373
374 {
375 char mstring[NSTRING]; /* string to match cmd names to */
376 int status; /* status return */
377
378 status = mlreply(TEXT20, mstring, NSTRING - 1);
379 /* "Apropos string: " */
380 if (status != TRUE)
381 return(status);
382
383 return(buildlist(FALSE, mstring));
384 }
385
buildlist(type,mstring)386 PASCAL NEAR buildlist(type, mstring) /* build a binding list (limited or full) */
387
388 int type; /* true = full list, false = partial list */
389 char *mstring; /* match string if a partial list */
390
391 {
392 register KEYTAB *ktp; /* pointer into the command table */
393 register NBIND *nptr; /* pointer into the name binding table */
394 register BUFFER *listbuf;/* buffer to put binding list into */
395 register BUFFER *bp; /* buffer ptr for function scan */
396 int cpos; /* current position to use in outseq */
397 char outseq[80]; /* output buffer for keystroke sequence */
398 int first_entry; /* is this the first macro listing? */
399
400 /* get a buffer for the binding list */
401 listbuf = bfind(TEXT21, TRUE, BFINVS);
402 /* "Binding list" */
403 if (listbuf == NULL || bclear(listbuf) == FALSE) {
404 mlwrite(TEXT22);
405 /* "Can not display binding list" */
406 return(FALSE);
407 }
408
409 /* let us know this is in progress */
410 mlwrite(TEXT23);
411 /* "[Building binding list]" */
412
413 /* build the contents of this window, inserting it line by line */
414 nptr = &names[0];
415 while (nptr->n_func != NULL) {
416
417 /* add in the command name */
418 strcpy(outseq, nptr->n_name);
419 cpos = strlen(outseq);
420
421 /* if we are executing an apropos command..... */
422 if (type == FALSE &&
423 /* and current string doesn't include the search string */
424 strinc(outseq, mstring) == FALSE)
425 goto fail;
426
427 /* search down any keys bound to this */
428 ktp = &keytab[0];
429 while (ktp->k_type != BINDNUL) {
430 if (ktp->k_type == BINDFNC &&
431 ktp->k_ptr.fp == nptr->n_func) {
432 /* padd out some spaces */
433 while (cpos < 25)
434 outseq[cpos++] = ' ';
435
436 /* add in the command sequence */
437 cmdstr(ktp->k_code, &outseq[cpos]);
438
439 /* and add it as a line into the buffer */
440 if (addline(listbuf, outseq) != TRUE)
441 return(FALSE);
442
443 cpos = 0; /* and clear the line */
444 }
445 ++ktp;
446 }
447
448 /* if no key was bound, we need to dump it anyway */
449 if (cpos > 0) {
450 outseq[cpos] = 0;
451 if (addline(listbuf, outseq) != TRUE)
452 return(FALSE);
453 }
454
455 fail: /* and on to the next name */
456 ++nptr;
457 }
458
459 /* scan all buffers looking for macroes and their bindings */
460 first_entry = TRUE;
461 bp = bheadp;
462 while (bp) {
463
464 /* is this buffer a macro? */
465 if (bp->b_bname[0] != '[')
466 goto bfail;
467
468 /* add in the command name */
469 strcpy(outseq, bp->b_bname);
470 cpos = strlen(outseq);
471
472 /* if we are executing an apropos command..... */
473 if (type == FALSE &&
474 /* and current string doesn't include the search string */
475 strinc(outseq, mstring) == FALSE)
476 goto bfail;
477
478 /* search down any keys bound to this macro */
479 ktp = &keytab[0];
480 while (ktp->k_type != BINDNUL) {
481 if (ktp->k_type == BINDBUF &&
482 ktp->k_ptr.buf == bp) {
483 /* padd out some spaces */
484 while (cpos < 25)
485 outseq[cpos++] = ' ';
486
487 /* add in the command sequence */
488 cmdstr(ktp->k_code, &outseq[cpos]);
489
490 /* and add it as a line into the buffer */
491 if (addline(listbuf, outseq) != TRUE)
492 return(FALSE);
493
494 cpos = 0; /* and clear the line */
495 }
496 ++ktp;
497 }
498
499 /* add a blank line between the key and macro lists */
500 if (first_entry == TRUE) {
501 if (addline(listbuf, "") != TRUE)
502 return(FALSE);
503 first_entry = FALSE;
504 }
505
506 /* if no key was bound, we need to dump it anyway */
507 if (cpos > 0) {
508 outseq[cpos] = 0;
509 if (addline(listbuf, outseq) != TRUE)
510 return(FALSE);
511 }
512
513 bfail: /* and on to the next buffer */
514 bp = bp->b_bufp;
515 }
516
517 wpopup(listbuf);
518 mlerase(); /* clear the mode line */
519 return(TRUE);
520 }
521
strinc(source,sub)522 PASCAL NEAR strinc(source, sub) /* does source include sub? */
523
524 char *source; /* string to search in */
525 char *sub; /* substring to look for */
526
527 {
528 char *sp; /* ptr into source */
529 char *nxtsp; /* next ptr into source */
530 char *tp; /* ptr into substring */
531
532 /* for each character in the source string */
533 sp = source;
534 while (*sp) {
535 tp = sub;
536 nxtsp = sp;
537
538 /* is the substring here? */
539 while (*tp) {
540 if (*nxtsp++ != *tp)
541 break;
542 else
543 tp++;
544 }
545
546 /* yes, return a success */
547 if (*tp == 0)
548 return(TRUE);
549
550 /* no, onward */
551 sp++;
552 }
553 return(FALSE);
554 }
555
556 /* get a command key sequence from the keyboard */
557
getckey(mflag)558 unsigned int PASCAL NEAR getckey(mflag)
559
560 int mflag; /* going for a meta sequence? */
561
562 {
563 register unsigned int c; /* character fetched */
564 char tok[NSTRING]; /* command incoming */
565
566 /* check to see if we are executing a command line */
567 if (clexec) {
568 macarg(tok); /* get the next token */
569 return(stock(tok));
570 }
571
572 /* or the normal way */
573 if (mflag)
574 c = get_key();
575 else
576 c = getcmd();
577 return(c);
578 }
579
580 /* execute the startup file */
581
startup(sfname)582 PASCAL NEAR startup(sfname)
583
584 char *sfname; /* name of startup file (null if default) */
585
586 {
587 char *fname; /* resulting file name to execute */
588 char name[NSTRING]; /* name with extention */
589
590 /* look up the startup file */
591 if (*sfname != 0) {
592
593 /* default the extention */
594 strcpy(name, sfname);
595 if (sindex(name, ".") == 0)
596 strcat(name, ".cmd");
597
598 fname = flook(name, TRUE);
599 } else
600 fname = flook(pathname[0], TRUE);
601
602 /* if it isn't around, don't sweat it */
603 if (fname == NULL)
604 return(TRUE);
605
606 /* otherwise, execute the sucker */
607 return(dofile(fname));
608 }
609
610 /* Look up the existance of a file along the normal or PATH
611 environment variable.
612
613 LOOKUP ORDER:
614
615 if contains path:
616
617 absolute
618
619 else
620
621 HOME environment directory
622 all directories along PATH environment
623 directories in table from EPATH.H
624 */
625
flook(fname,hflag)626 char *PASCAL NEAR flook(fname, hflag)
627
628 char *fname; /* base file name to search for */
629 int hflag; /* Look in the HOME environment variable first? */
630
631 {
632 register char *home; /* path to home directory */
633 register char *path; /* environmental PATH variable */
634 register char *sp; /* pointer into path spec */
635 register int i; /* index */
636 static char fspec[NFILEN]; /* full path spec to search */
637 char patha[NFILEN];
638
639 /* if we have an absolute path.. check only there! */
640 sp = fname;
641 while (*sp) {
642 if (*sp == ':' || *sp == '\\' || *sp == '/') {
643 if (ffropen(fname) == FIOSUC) {
644 ffclose();
645 return(fname);
646 } else
647 return(NULL);
648 }
649 ++sp;
650 }
651
652 #if ENVFUNC
653
654 if (hflag) {
655 #if WMCS
656 home = getenv("SYS$HOME");
657 #else
658 home = getenv("HOME");
659 #endif
660 if (home != NULL) {
661 /* build home dir file spec */
662 strcpy(fspec, home);
663 #if WMCS
664 strcat(fspec,fname);
665 #else
666 strcat(fspec, DIRSEPSTR);
667 strcat(fspec, fname);
668 #endif
669
670 /* and try it out */
671 if (ffropen(fspec) == FIOSUC) {
672 ffclose();
673 return(fspec);
674 }
675 }
676 }
677 #endif
678
679 /* current directory now overides everything except HOME var */
680 if (ffropen(fname) == FIOSUC) {
681 ffclose();
682 return(fname);
683 }
684
685 #if ENVFUNC
686 /* get the PATH variable */
687 #if WMCS
688 path = getenv("OPT$PATH");
689 #else
690 #if OS2
691 path = getenv("DPATH");
692 #else
693 strncpy(patha, getenv("PATH"), NFILEN - 25);
694 strcat(patha, ":/usr/local/share/uemacs");
695 #endif
696 #endif
697 path = patha;
698 if (path != NULL)
699 while (*path) {
700
701 /* build next possible file spec */
702 sp = fspec;
703 #if TOS
704 while (*path && (*path != PATHCHR) && (*path != ','))
705 #else
706 while (*path && (*path != PATHCHR))
707 #endif
708 *sp++ = *path++;
709
710 /* add a terminating dir separator if we need it */
711 if ((sp != fspec) && (*(sp-1) != DIRSEPCHAR))
712 *sp++ = DIRSEPCHAR;
713 *sp = 0;
714 strcat(fspec, fname);
715
716 /* and try it out */
717 if (ffropen(fspec) == FIOSUC) {
718 ffclose();
719 return(fspec);
720 }
721
722 #if TOS && MWC
723 if ((*path == PATHCHR) || (*path == ','))
724 #else
725 if (*path == PATHCHR)
726 #endif
727 ++path;
728 }
729 #endif
730
731 /* look it up via the old table method */
732 for (i=2; i < NPNAMES; i++) {
733 strcpy(fspec, pathname[i]);
734 strcat(fspec, fname);
735
736 /* and try it out */
737 if (ffropen(fspec) == FIOSUC) {
738 ffclose();
739 return(fspec);
740 }
741 }
742
743 return(NULL); /* no such luck */
744 }
745
746 /* Change a key command to a string we can print out.
747 * Return the string passed in.
748 */
cmdstr(c,seq)749 char *PASCAL NEAR cmdstr(c, seq)
750
751 int c; /* sequence to translate */
752 char *seq; /* destination string for sequence */
753
754 {
755 char *ptr; /* pointer into current position in sequence */
756
757 ptr = seq;
758
759 /* apply ^X sequence if needed */
760 if (c & CTLX) {
761 *ptr++ = '^';
762 *ptr++ = 'X';
763 }
764
765 /* apply ALT key sequence if needed */
766 if (c & ALTD) {
767 *ptr++ = 'A';
768 *ptr++ = '-';
769 }
770
771 /* apply Shifted sequence if needed */
772 if (c & SHFT) {
773 *ptr++ = 'S';
774 *ptr++ = '-';
775 }
776
777 /* apply MOUS sequence if needed */
778 if (c & MOUS) {
779 *ptr++ = 'M';
780 *ptr++ = 'S';
781 }
782
783 /* apply meta sequence if needed */
784 if (c & META) {
785 *ptr++ = 'M';
786 *ptr++ = '-';
787 }
788
789 /* apply SPEC sequence if needed */
790 if (c & SPEC) {
791 *ptr++ = 'F';
792 *ptr++ = 'N';
793 }
794
795 /* apply control sequence if needed */
796 if (c & CTRL) {
797
798 /* non normal spaces look like @ */
799 if (ptr == seq && ((c & 255) == ' '))
800 c = '@';
801
802 *ptr++ = '^';
803 }
804
805 c = c & 255; /* strip the prefixes */
806
807 /* and output the final sequence */
808 *ptr++ = c;
809 *ptr = 0; /* terminate the string */
810 return (seq);
811 }
812
813 /* This function looks a key binding up in the binding table */
814
getbind(c)815 KEYTAB *getbind(c)
816
817 register int c; /* key to find what is bound to it */
818
819 {
820 register KEYTAB *ktp;
821
822 /* scan through the binding table, looking for the key's entry */
823 ktp = &keytab[0];
824 while (ktp->k_type != BINDNUL) {
825 if (ktp->k_code == c)
826 return(ktp);
827 ++ktp;
828 }
829
830 /* no such binding */
831 return((KEYTAB *)NULL);
832 }
833
834 /* getfname: This function takes a ptr to KEYTAB entry and gets the name
835 associated with it
836 */
837
getfname(key)838 char *PASCAL NEAR getfname(key)
839
840 KEYTAB *key; /* key binding to return a name of */
841
842 {
843 int (PASCAL NEAR *func)(); /* ptr to the requested function */
844 register NBIND *nptr; /* pointer into the name binding table */
845 register BUFFER *bp; /* ptr to buffer to test */
846 register BUFFER *kbuf; /* ptr to requested buffer */
847
848 /* if this isn't a valid key, it has no name */
849 if (key == NULL)
850 return(NULL);
851
852 /* skim through the binding table, looking for a match */
853 if (key->k_type == BINDFNC) {
854 func = key->k_ptr.fp;
855 nptr = &names[0];
856 while (nptr->n_func != NULL) {
857 if (nptr->n_func == func)
858 return(nptr->n_name);
859 ++nptr;
860 }
861 return(NULL);
862 }
863
864 /* skim through the buffer list looking for a match */
865 if (key->k_type == BINDBUF) {
866 kbuf = key->k_ptr.buf;
867 bp = bheadp;
868 while (bp) {
869 if (bp == kbuf)
870 return(bp->b_bname);
871 bp = bp->b_bufp;
872 }
873 return(NULL);
874 }
875 return(NULL);
876 }
877
878 /* fncmatch: match fname to a function in the names table and return
879 any match or NULL if none */
880
881 #if MSC
882 int (PASCAL NEAR *PASCAL NEAR fncmatch(char *fname))(void)
883 #else
884 int (PASCAL NEAR *PASCAL NEAR fncmatch(fname))()
885
886 char *fname; /* name to attempt to match */
887 #endif
888
889 {
890 int nval;
891
892 if ((nval = binary(fname, namval, numfunc, NSTRING)) == -1)
893 return(NULL);
894 else
895 return(names[nval].n_func);
896 }
897
namval(index)898 char *PASCAL NEAR namval(index)
899
900 int index; /* index of name to fetch out of the name table */
901
902 {
903 return(names[index].n_name);
904 }
905
906 /* stock() String key name TO Command Key
907
908 A key binding consists of one or more prefix functions followed by
909 a keystroke. Allowable prefixes must be in the following order:
910
911 ^X preceeding control-X
912 A- similtaneous ALT key (on PCs mainly)
913 S- shifted function key
914 MS mouse generated keystroke
915 M- Preceding META key
916 FN function key
917 ^ control key
918
919 Meta and ^X prefix of lower case letters are converted to upper
920 case. Real control characters are automatically converted to
921 the ^A form.
922 */
923
stock(keyname)924 unsigned int PASCAL NEAR stock(keyname)
925
926 unsigned char *keyname; /* name of key to translate to Command key form */
927
928 {
929 register unsigned int c; /* key sequence to return */
930
931 /* parse it up */
932 c = 0;
933
934 /* Do ^X prefix */
935 if(*keyname == '^' && *(keyname+1) == 'X') {
936 if(*(keyname+2) != 0) { /* Key is not bare ^X */
937 c |= CTLX;
938 keyname += 2;
939 }
940 }
941
942 /* and the ALT key prefix */
943 if (*keyname == 'A' && *(keyname+1) == '-') {
944 c |= ALTD;
945 keyname += 2;
946 }
947
948 /* and the SHIFTED prefix */
949 if (*keyname == 'S' && *(keyname+1) == '-') {
950 c |= SHFT;
951 keyname += 2;
952 }
953
954 /* and the mouse (MOUS) prefix */
955 if (*keyname == 'M' && *(keyname+1) == 'S') {
956 c |= MOUS;
957 keyname += 2;
958 }
959
960 /* then the META prefix */
961 if (*keyname == 'M' && *(keyname+1) == '-') {
962 c |= META;
963 keyname += 2;
964 }
965
966 /* next the function prefix */
967 if (*keyname == 'F' && *(keyname+1) == 'N') {
968 c |= SPEC;
969 keyname += 2;
970 }
971
972 /* a control char? (NOT Always upper case anymore) */
973 if (*keyname == '^' && *(keyname+1) != 0) {
974 c |= CTRL;
975 ++keyname;
976 if (*keyname == '@')
977 *keyname = ' ';
978 }
979
980 /* A literal control character? (Boo, hiss) */
981 if (*keyname < 32) {
982 c |= CTRL;
983 *keyname += '@';
984 }
985
986 /* make sure we are not lower case if used with ^X or M- */
987 if(!(c & (MOUS|SPEC|ALTD|SHFT))) /* If not a special key */
988 if( c & (CTLX|META)) /* If is a prefix */
989 uppercase((unsigned char *)keyname); /* Then make sure it's upper case */
990
991 /* the final sequence... */
992 c |= *keyname;
993 return(c);
994 }
995
transbind(skey)996 char *PASCAL NEAR transbind(skey) /* string key name to binding name.... */
997
998 char *skey; /* name of key to get binding for */
999
1000 {
1001 char *bindname;
1002
1003 bindname = getfname(getbind(stock(skey)));
1004 if (bindname == NULL)
1005 bindname = errorm;
1006
1007 return(bindname);
1008 }
1009
execkey(key,f,n)1010 int PASCAL NEAR execkey(key, f, n) /* execute a function bound to a key */
1011
1012 KEYTAB *key; /* key to execute */
1013 int f, n; /* agruments to C function */
1014
1015 {
1016 register int status; /* error return */
1017
1018 if (key->k_type == BINDFNC) {
1019 undo_insert(OP_CMND, 1, obj);
1020 return((*(key->k_ptr.fp))(f, n));
1021 }
1022 if (key->k_type == BINDBUF) {
1023 while (n--) {
1024 status = dobuf(key->k_ptr.buf);
1025 if (status != TRUE)
1026 return(status);
1027 }
1028 }
1029 return(TRUE);
1030 }
1031
1032 /* set a KEYTAB to the given name of the given type */
1033
1034 #if PROTO
set_key(KEYTAB * key,char * name)1035 int set_key(KEYTAB *key, char *name)
1036 #else
1037 set_key(key, name)
1038
1039 KEYTAB *key; /* ptr to key to set */
1040 char *name; /* name of function or buffer */
1041 #endif
1042 {
1043 int (PASCAL NEAR *ktemp)(); /* temp function pointer to assign */
1044 register BUFFER *kmacro; /* ptr to buffer of macro to bind to key */
1045 char bufn[NBUFN]; /* buffer to hold macro name */
1046
1047 /* are we unbinding it? */
1048 if (*name == 0) {
1049 key->k_type = BINDNUL;
1050 return(TRUE);
1051 }
1052
1053 /* bind to a built in function? */
1054 if ((ktemp = fncmatch(name)) != NULL) {
1055 key->k_ptr.fp = ktemp;
1056 key->k_type = BINDFNC;
1057 return(TRUE);
1058 }
1059
1060 /* is it a procedure/macro? */
1061 strcpy(bufn, "[");
1062 strcat(bufn, name);
1063 strcat(bufn, "]");
1064 if ((kmacro=bfind(bufn, FALSE, 0)) != NULL) {
1065 key->k_ptr.buf = kmacro;
1066 key->k_type = BINDBUF;
1067 return(TRUE);
1068 }
1069
1070 /* not anything we can bind to */
1071 mlwrite(TEXT16);
1072 /* "[No such function]" */
1073 return(FALSE);
1074 }
1075
1076