xref: /openbsd-src/usr.bin/vi/ex/ex_usage.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: ex_usage.c,v 1.7 2009/10/27 23:59:47 deraadt Exp $	*/
2 
3 /*-
4  * Copyright (c) 1992, 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  * Copyright (c) 1992, 1993, 1994, 1995, 1996
7  *	Keith Bostic.  All rights reserved.
8  *
9  * See the LICENSE file for redistribution information.
10  */
11 
12 #include "config.h"
13 
14 #include <sys/types.h>
15 #include <sys/queue.h>
16 #include <sys/time.h>
17 
18 #include <bitstring.h>
19 #include <ctype.h>
20 #include <limits.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "../common/common.h"
26 #include "../vi/vi.h"
27 
28 /*
29  * ex_help -- :help
30  *	Display help message.
31  *
32  * PUBLIC: int ex_help(SCR *, EXCMD *);
33  */
34 int
35 ex_help(sp, cmdp)
36 	SCR *sp;
37 	EXCMD *cmdp;
38 {
39 	(void)ex_puts(sp,
40 	    "To see the list of vi commands, enter \":viusage<CR>\"\n");
41 	(void)ex_puts(sp,
42 	    "To see the list of ex commands, enter \":exusage<CR>\"\n");
43 	(void)ex_puts(sp,
44 	    "For an ex command usage statement enter \":exusage [cmd]<CR>\"\n");
45 	(void)ex_puts(sp,
46 	    "For a vi key usage statement enter \":viusage [key]<CR>\"\n");
47 	(void)ex_puts(sp, "To exit, enter \":q!\"\n");
48 	return (0);
49 }
50 
51 /*
52  * ex_usage -- :exusage [cmd]
53  *	Display ex usage strings.
54  *
55  * PUBLIC: int ex_usage(SCR *, EXCMD *);
56  */
57 int
58 ex_usage(sp, cmdp)
59 	SCR *sp;
60 	EXCMD *cmdp;
61 {
62 	ARGS *ap;
63 	EXCMDLIST const *cp;
64 	int newscreen;
65 	char *name, *p, nb[MAXCMDNAMELEN + 5];
66 
67 	switch (cmdp->argc) {
68 	case 1:
69 		ap = cmdp->argv[0];
70 		if (isupper(ap->bp[0])) {
71 			newscreen = 1;
72 			ap->bp[0] = tolower(ap->bp[0]);
73 		} else
74 			newscreen = 0;
75 		for (cp = cmds; cp->name != NULL &&
76 		    memcmp(ap->bp, cp->name, ap->len); ++cp);
77 		if (cp->name == NULL ||
78 		    (newscreen && !F_ISSET(cp, E_NEWSCREEN))) {
79 			if (newscreen)
80 				ap->bp[0] = toupper(ap->bp[0]);
81 			(void)ex_printf(sp, "The %.*s command is unknown\n",
82 			    (int)ap->len, ap->bp);
83 		} else {
84 			(void)ex_printf(sp,
85 			    "Command: %s\n  Usage: %s\n", cp->help, cp->usage);
86 			/*
87 			 * !!!
88 			 * The "visual" command has two modes, one from ex,
89 			 * one from the vi colon line.  Don't ask.
90 			 */
91 			if (cp != &cmds[C_VISUAL_EX] &&
92 			    cp != &cmds[C_VISUAL_VI])
93 				break;
94 			if (cp == &cmds[C_VISUAL_EX])
95 				cp = &cmds[C_VISUAL_VI];
96 			else
97 				cp = &cmds[C_VISUAL_EX];
98 			(void)ex_printf(sp,
99 			    "Command: %s\n  Usage: %s\n", cp->help, cp->usage);
100 		}
101 		break;
102 	case 0:
103 		for (cp = cmds; cp->name != NULL && !INTERRUPTED(sp); ++cp) {
104 			/*
105 			 * The ^D command has an unprintable name.
106 			 *
107 			 * XXX
108 			 * We display both capital and lower-case versions of
109 			 * the appropriate commands -- no need to add in extra
110 			 * room, they're all short names.
111 			 */
112 			if (cp == &cmds[C_SCROLL])
113 				name = "^D";
114 			else if (F_ISSET(cp, E_NEWSCREEN)) {
115 				nb[0] = '[';
116 				nb[1] = toupper(cp->name[0]);
117 				nb[2] = cp->name[0];
118 				nb[3] = ']';
119 				for (name = cp->name + 1,
120 				    p = nb + 4; (*p++ = *name++) != '\0';);
121 				name = nb;
122 			} else
123 				name = cp->name;
124 			(void)ex_printf(sp,
125 			    "%*s: %s\n", MAXCMDNAMELEN, name, cp->help);
126 		}
127 		break;
128 	default:
129 		abort();
130 	}
131 	return (0);
132 }
133 
134 /*
135  * ex_viusage -- :viusage [key]
136  *	Display vi usage strings.
137  *
138  * PUBLIC: int ex_viusage(SCR *, EXCMD *);
139  */
140 int
141 ex_viusage(sp, cmdp)
142 	SCR *sp;
143 	EXCMD *cmdp;
144 {
145 	VIKEYS const *kp;
146 	int key;
147 
148 	switch (cmdp->argc) {
149 	case 1:
150 		if (cmdp->argv[0]->len != 1) {
151 			ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
152 			return (1);
153 		}
154 		key = cmdp->argv[0]->bp[0];
155 		if (key > MAXVIKEY)
156 			goto nokey;
157 
158 		/* Special case: '[' and ']' commands. */
159 		if ((key == '[' || key == ']') && cmdp->argv[0]->bp[1] != key)
160 			goto nokey;
161 
162 		/* Special case: ~ command. */
163 		if (key == '~' && O_ISSET(sp, O_TILDEOP))
164 			kp = &tmotion;
165 		else
166 			kp = &vikeys[key];
167 
168 		if (kp->usage == NULL)
169 nokey:			(void)ex_printf(sp,
170 			    "The %s key has no current meaning\n",
171 			    KEY_NAME(sp, key));
172 		else
173 			(void)ex_printf(sp,
174 			    "  Key:%s%s\nUsage: %s\n",
175 			    isblank(*kp->help) ? "" : " ", kp->help, kp->usage);
176 		break;
177 	case 0:
178 		for (key = 0; key <= MAXVIKEY && !INTERRUPTED(sp); ++key) {
179 			/* Special case: ~ command. */
180 			if (key == '~' && O_ISSET(sp, O_TILDEOP))
181 				kp = &tmotion;
182 			else
183 				kp = &vikeys[key];
184 			if (kp->help != NULL)
185 				(void)ex_printf(sp, "%s\n", kp->help);
186 		}
187 		break;
188 	default:
189 		abort();
190 	}
191 	return (0);
192 }
193