1 /*	$OpenBSD: help.c,v 1.35 2015/03/19 21:22:15 bcallah Exp $	*/
2 
3 /* This file is in the public domain. */
4 
5 /*
6  * Help functions for Mg 2
7  */
8 
9 #include <sys/queue.h>
10 #include <signal.h>
11 #include <stdio.h>
12 #include <string.h>
13 
14 #include "def.h"
15 #include "funmap.h"
16 #include "kbd.h"
17 #include "key.h"
18 #include "macro.h"
19 
20 static int	showall(struct buffer *, KEYMAP *, char *);
21 static int	findbind(KEYMAP *, PF, char *, size_t);
22 
23 /*
24  * Read a key from the keyboard, and look it up in the keymap.
25  * Display the name of the function currently bound to the key.
26  */
27 /* ARGSUSED */
28 int
desckey(int f,int n)29 desckey(int f, int n)
30 {
31 	KEYMAP	*curmap;
32 	PF	 funct;
33 	int	 c, m, i, num;
34 	char	*pep;
35 	char	 dprompt[80];
36 
37 	if (inmacro)
38 		return (TRUE);	/* ignore inside keyboard macro */
39 
40 	num = strlcpy(dprompt, "Describe key briefly: ", sizeof(dprompt));
41 	if (num >= sizeof(dprompt))
42 		num = sizeof(dprompt) - 1;
43 	pep = dprompt + num;
44 	key.k_count = 0;
45 	m = curbp->b_nmodes;
46 	curmap = curbp->b_modes[m]->p_map;
47 	for (;;) {
48 		for (;;) {
49 			ewprintf("%s", dprompt);
50 			pep[-1] = ' ';
51 			pep = getkeyname(pep, sizeof(dprompt) - (pep - dprompt),
52 			    key.k_chars[key.k_count++] = c = getkey(FALSE));
53 			if ((funct = doscan(curmap, c, &curmap)) != NULL)
54 				break;
55 			*pep++ = '-';
56 			*pep = '\0';
57 		}
58 		if (funct != rescan)
59 			break;
60 		if (ISUPPER(key.k_chars[key.k_count - 1])) {
61 			funct = doscan(curmap,
62 			    TOLOWER(key.k_chars[key.k_count - 1]), &curmap);
63 			if (funct == NULL) {
64 				*pep++ = '-';
65 				*pep = '\0';
66 				continue;
67 			}
68 			if (funct != rescan)
69 				break;
70 		}
71 nextmode:
72 		if (--m < 0)
73 			break;
74 		curmap = curbp->b_modes[m]->p_map;
75 		for (i = 0; i < key.k_count; i++) {
76 			funct = doscan(curmap, key.k_chars[i], &curmap);
77 			if (funct != NULL) {
78 				if (i == key.k_count - 1 && funct != rescan)
79 					goto found;
80 				funct = rescan;
81 				goto nextmode;
82 			}
83 		}
84 		*pep++ = '-';
85 		*pep = '\0';
86 	}
87 found:
88 	if (funct == rescan || funct == selfinsert)
89 		ewprintf("%k is not bound to any function");
90 	else if ((pep = (char *)function_name(funct)) != NULL)
91 		ewprintf("%k runs the command %s", pep);
92 	else
93 		ewprintf("%k is bound to an unnamed function");
94 	return (TRUE);
95 }
96 
97 /*
98  * This function creates a table, listing all of the command
99  * keys and their current bindings, and stores the table in the
100  * *help* pop-up buffer.  This lets Mg produce it's own wall chart.
101  */
102 /* ARGSUSED */
103 int
wallchart(int f,int n)104 wallchart(int f, int n)
105 {
106 	int		 m;
107 	struct buffer		*bp;
108 
109 	bp = bfind("*help*", TRUE);
110 	if (bclear(bp) != TRUE)
111 		/* clear it out */
112 		return (FALSE);
113 	bp->b_flag |= BFREADONLY;
114 	for (m = curbp->b_nmodes; m > 0; m--) {
115 		if ((addlinef(bp, "Local keybindings for mode %s:",
116 				curbp->b_modes[m]->p_name) == FALSE) ||
117 		    (showall(bp, curbp->b_modes[m]->p_map, "") == FALSE) ||
118 		    (addline(bp, "") == FALSE))
119 			return (FALSE);
120 	}
121 	if ((addline(bp, "Global bindings:") == FALSE) ||
122 	    (showall(bp, fundamental_map, "") == FALSE))
123 		return (FALSE);
124 	return (popbuftop(bp, WNONE));
125 }
126 
127 static int
showall(struct buffer * bp,KEYMAP * map,char * prefix)128 showall(struct buffer *bp, KEYMAP *map, char *prefix)
129 {
130 	KEYMAP	*newmap;
131 	char	 buf[80], keybuf[16];
132 	PF	 fun;
133 	int	 c;
134 
135 	if (addline(bp, "") == FALSE)
136 		return (FALSE);
137 
138 	/* XXX - 256 ? */
139 	for (c = 0; c < 256; c++) {
140 		fun = doscan(map, c, &newmap);
141 		if (fun == rescan || fun == selfinsert)
142 			continue;
143 		getkeyname(buf, sizeof(buf), c);
144 		(void)snprintf(keybuf, sizeof(keybuf), "%s%s ", prefix, buf);
145 		if (fun == NULL) {
146 			if (showall(bp, newmap, keybuf) == FALSE)
147 				return (FALSE);
148 		} else {
149 			if (addlinef(bp, "%-16s%s", keybuf,
150 				    function_name(fun)) == FALSE)
151 				return (FALSE);
152 		}
153 	}
154 	return (TRUE);
155 }
156 
157 int
help_help(int f,int n)158 help_help(int f, int n)
159 {
160 	KEYMAP	*kp;
161 	PF	 funct;
162 
163 	if ((kp = name_map("help")) == NULL)
164 		return (FALSE);
165 	ewprintf("a b c: ");
166 	do {
167 		funct = doscan(kp, getkey(FALSE), NULL);
168 	} while (funct == NULL || funct == help_help);
169 
170 	if (macrodef && macrocount < MAXMACRO)
171 		macro[macrocount - 1].m_funct = funct;
172 
173 	return ((*funct)(f, n));
174 }
175 
176 /* ARGSUSED */
177 int
apropos_command(int f,int n)178 apropos_command(int f, int n)
179 {
180 	struct buffer		*bp;
181 	struct list		*fnames, *el;
182 	char		 string[32];
183 
184 	if (eread("apropos: ", string, sizeof(string), EFNUL | EFNEW) == NULL)
185 		return (ABORT);
186 	/* FALSE means we got a 0 character string, which is fine */
187 	bp = bfind("*help*", TRUE);
188 	if (bclear(bp) == FALSE)
189 		return (FALSE);
190 
191 	fnames = complete_function_list("");
192 	for (el = fnames; el != NULL; el = el->l_next) {
193 		char buf[32];
194 
195 		if (strstr(el->l_name, string) == NULL)
196 			continue;
197 
198 		buf[0] = '\0';
199 		findbind(fundamental_map, name_function(el->l_name),
200 		    buf, sizeof(buf));
201 
202 		if (addlinef(bp, "%-32s%s", el->l_name,  buf) == FALSE) {
203 			free_file_list(fnames);
204 			return (FALSE);
205 		}
206 	}
207 	free_file_list(fnames);
208 	return (popbuftop(bp, WNONE));
209 }
210 
211 static int
findbind(KEYMAP * map,PF fun,char * buf,size_t len)212 findbind(KEYMAP *map, PF fun, char *buf, size_t len)
213 {
214 	KEYMAP	*newmap;
215 	PF	 nfun;
216 	char	 buf2[16], keybuf[16];
217 	int	 c;
218 
219 	/* XXX - 256 ? */
220 	for (c = 0; c < 256; c++) {
221 		nfun = doscan(map, c, &newmap);
222 		if (nfun == fun) {
223 			getkeyname(buf, len, c);
224 			return (TRUE);
225 		}
226 		if (nfun == NULL) {
227 			if (findbind(newmap, fun, buf2, sizeof(buf2)) == TRUE) {
228 				getkeyname(keybuf, sizeof(keybuf), c);
229 				(void)snprintf(buf, len, "%s %s", keybuf, buf2);
230 				return (TRUE);
231 			}
232 		}
233 	}
234 	return (FALSE);
235 }
236