1/*-
2 * Copyright (c) 1992, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 * Copyright (c) 1992, 1993, 1994, 1995, 1996
5 *	Keith Bostic.  All rights reserved.
6 *
7 * See the LICENSE file for redistribution information.
8 */
9
10#include "config.h"
11
12#ifndef lint
13static const char sccsid[] = "$Id: ex_cmd.c,v 10.26 2011/07/14 15:11:16 zy Exp $";
14#endif /* not lint */
15
16#include <sys/types.h>
17#include <sys/queue.h>
18#include <sys/time.h>
19
20#include <bitstring.h>
21#include <limits.h>
22#include <stdio.h>
23
24#include "../common/common.h"
25
26/*
27 * This array maps ex command names to command functions.
28 *
29 * The order in which command names are listed below is important --
30 * ambiguous abbreviations are resolved to be the first possible match,
31 * e.g. "r" means "read", not "rewind", because "read" is listed before
32 * "rewind".
33 *
34 * The syntax of the ex commands is unbelievably irregular, and a special
35 * case from beginning to end.  Each command has an associated "syntax
36 * script" which describes the "arguments" that are possible.  The script
37 * syntax is as follows:
38 *
39 *	!		-- ! flag
40 *	1		-- flags: [+-]*[pl#][+-]*
41 *	2		-- flags: [-.+^]
42 *	3		-- flags: [-.+^=]
43 *	b		-- buffer
44 *	c[01+a]		-- count (0-N, 1-N, signed 1-N, address offset)
45 *	f[N#][or]	-- file (a number or N, optional or required)
46 *	l		-- line
47 *	S		-- string with file name expansion
48 *	s		-- string
49 *	W		-- word string
50 *	w[N#][or]	-- word (a number or N, optional or required)
51 */
52EXCMDLIST const cmds[] = {
53/* C_SCROLL */
54	{L("\004"),	ex_pr,		E_ADDR2,
55	    "",
56	    "^D",
57	    "scroll lines"},
58/* C_BANG */
59	{L("!"),		ex_bang,	E_ADDR2_NONE|E_SECURE,
60	    "S",
61	    "[line [,line]] ! command",
62	    "filter lines through commands or run commands"},
63/* C_HASH */
64	{L("#"),		ex_number,	E_ADDR2|E_CLRFLAG,
65	    "ca1",
66	    "[line [,line]] # [count] [l]",
67	    "display numbered lines"},
68/* C_SUBAGAIN */
69	{L("&"),		ex_subagain,	E_ADDR2|E_ADDR_ZERO,
70	    "s",
71	    "[line [,line]] & [cgr] [count] [#lp]",
72	    "repeat the last subsitution"},
73/* C_STAR */
74	{L("*"),		ex_at,		0,
75	    "b",
76	    "* [buffer]",
77	    "execute a buffer"},
78/* C_SHIFTL */
79	{L("<"),		ex_shiftl,	E_ADDR2|E_AUTOPRINT,
80	    "ca1",
81	    "[line [,line]] <[<...] [count] [flags]",
82	    "shift lines left"},
83/* C_EQUAL */
84	{L("="),		ex_equal,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
85	    "1",
86	    "[line] = [flags]",
87	    "display line number"},
88/* C_SHIFTR */
89	{L(">"),		ex_shiftr,	E_ADDR2|E_AUTOPRINT,
90	    "ca1",
91	    "[line [,line]] >[>...] [count] [flags]",
92	    "shift lines right"},
93/* C_AT */
94	{L("@"),		ex_at,		E_ADDR2,
95	    "b",
96	    "@ [buffer]",
97	    "execute a buffer"},
98/* C_APPEND */
99	{L("append"),	ex_append,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
100	    "!",
101	    "[line] a[ppend][!]",
102	    "append input to a line"},
103/* C_ABBR */
104	{L("abbreviate"), 	ex_abbr,	0,
105	    "W",
106	    "ab[brev] [word replace]",
107	    "specify an input abbreviation"},
108/* C_ARGS */
109	{L("args"),	ex_args,	0,
110	    "",
111	    "ar[gs]",
112	    "display file argument list"},
113/* C_BG */
114	{L("bg"),		ex_bg,		E_VIONLY,
115	    "",
116	    "bg",
117	    "put a foreground screen into the background"},
118/* C_CHANGE */
119	{L("change"),	ex_change,	E_ADDR2|E_ADDR_ZERODEF,
120	    "!ca",
121	    "[line [,line]] c[hange][!] [count]",
122	    "change lines to input"},
123/* C_CD */
124	{L("cd"),		ex_cd,		0,
125	    "!f1o",
126	    "cd[!] [directory]",
127	    "change the current directory"},
128/* C_CHDIR */
129	{L("chdir"),	ex_cd,		0,
130	    "!f1o",
131	    "chd[ir][!] [directory]",
132	    "change the current directory"},
133/* C_COPY */
134	{L("copy"),	ex_copy,	E_ADDR2|E_AUTOPRINT,
135	    "l1",
136	    "[line [,line]] co[py] line [flags]",
137	    "copy lines elsewhere in the file"},
138/* C_CSCOPE */
139	{L("cscope"),      ex_cscope,      0,
140	    "!s",
141	    "cs[cope] command [args]",
142	    "create a set of tags using a cscope command"},
143/*
144 * !!!
145 * Adding new commands starting with 'd' may break the delete command code
146 * in ex_cmd() (the ex parser).  Read through the comments there, first.
147 */
148/* C_DELETE */
149	{L("delete"),	ex_delete,	E_ADDR2|E_AUTOPRINT,
150	    "bca1",
151	    "[line [,line]] d[elete][flags] [buffer] [count] [flags]",
152	    "delete lines from the file"},
153/* C_DISPLAY */
154	{L("display"),	ex_display,	0,
155	    "w1r",
156	    "display b[uffers] | c[onnections] | s[creens] | t[ags]",
157	    "display buffers, connections, screens or tags"},
158/* C_EDIT */
159	{L("edit"),	ex_edit,	E_NEWSCREEN,
160	    "f1o",
161	    "[Ee][dit][!] [+cmd] [file]",
162	    "begin editing another file"},
163/* C_EX */
164	{L("ex"),		ex_edit,	E_NEWSCREEN,
165	    "f1o",
166	    "[Ee]x[!] [+cmd] [file]",
167	    "begin editing another file"},
168/* C_EXUSAGE */
169	{L("exusage"),	ex_usage,	0,
170	    "w1o",
171	    "[exu]sage [command]",
172	    "display ex command usage statement"},
173/* C_FILE */
174	{L("file"),	ex_file,	0,
175	    "f1o",
176	    "f[ile] [name]",
177	    "display (and optionally set) file name"},
178/* C_FG */
179	{L("fg"),		ex_fg,		E_NEWSCREEN|E_VIONLY,
180	    "f1o",
181	    "[Ff]g [file]",
182	    "bring a backgrounded screen into the foreground"},
183/* C_GLOBAL */
184	{L("global"),	ex_global,	E_ADDR2_ALL,
185	    "!s",
186	    "[line [,line]] g[lobal][!] [;/]RE[;/] [commands]",
187	    "execute a global command on lines matching an RE"},
188/* C_HELP */
189	{L("help"),	ex_help,	0,
190	    "",
191	    "he[lp]",
192	    "display help statement"},
193/* C_INSERT */
194	{L("insert"),	ex_insert,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
195	    "!",
196	    "[line] i[nsert][!]",
197	    "insert input before a line"},
198/* C_JOIN */
199	{L("join"),	ex_join,	E_ADDR2|E_AUTOPRINT,
200	    "!ca1",
201	    "[line [,line]] j[oin][!] [count] [flags]",
202	    "join lines into a single line"},
203/* C_K */
204	{L("k"),		ex_mark,	E_ADDR1,
205	    "w1r",
206	    "[line] k key",
207	    "mark a line position"},
208/* C_LIST */
209	{L("list"),	ex_list,	E_ADDR2|E_CLRFLAG,
210	    "ca1",
211	    "[line [,line]] l[ist] [count] [#]",
212	    "display lines in an unambiguous form"},
213/* C_MOVE */
214	{L("move"),	ex_move,	E_ADDR2|E_AUTOPRINT,
215	    "l",
216	    "[line [,line]] m[ove] line",
217	    "move lines elsewhere in the file"},
218/* C_MARK */
219	{L("mark"),	ex_mark,	E_ADDR1,
220	    "w1r",
221	    "[line] ma[rk] key",
222	    "mark a line position"},
223/* C_MAP */
224	{L("map"),		ex_map,		0,
225	    "!W",
226	    "map[!] [keys replace]",
227	    "map input or commands to one or more keys"},
228/* C_MKEXRC */
229	{L("mkexrc"),	ex_mkexrc,	0,
230	    "!f1r",
231	    "mkexrc[!] file",
232	    "write a .exrc file"},
233/* C_NEXT */
234	{L("next"),	ex_next,	E_NEWSCREEN,
235	    "!fN",
236	    "[Nn][ext][!] [+cmd] [file ...]",
237	    "edit (and optionally specify) the next file"},
238/* C_NUMBER */
239	{L("number"),	ex_number,	E_ADDR2|E_CLRFLAG,
240	    "ca1",
241	    "[line [,line]] nu[mber] [count] [l]",
242	    "change display to number lines"},
243/* C_OPEN */
244	{L("open"),	ex_open,	E_ADDR1,
245	    "s",
246	    "[line] o[pen] [/RE/] [flags]",
247	    "enter \"open\" mode (not implemented)"},
248/* C_PRINT */
249	{L("print"),	ex_pr,		E_ADDR2|E_CLRFLAG,
250	    "ca1",
251	    "[line [,line]] p[rint] [count] [#l]",
252	    "display lines"},
253/* C_PRESERVE */
254	{L("preserve"),	ex_preserve,	0,
255	    "",
256	    "pre[serve]",
257	    "preserve an edit session for recovery"},
258/* C_PREVIOUS */
259	{L("previous"),	ex_prev,	E_NEWSCREEN,
260	    "!",
261	    "[Pp]rev[ious][!]",
262	    "edit the previous file in the file argument list"},
263/* C_PUT */
264	{L("put"),		ex_put,
265	    E_ADDR1|E_AUTOPRINT|E_ADDR_ZERO|E_ADDR_ZERODEF,
266	    "b",
267	    "[line] pu[t] [buffer]",
268	    "append a cut buffer to the line"},
269/* C_QUIT */
270	{L("quit"),	ex_quit,	0,
271	    "!",
272	    "q[uit][!]",
273	    "exit ex/vi"},
274/* C_READ */
275	{L("read"),	ex_read,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
276	    "s",
277	    "[line] r[ead] [!cmd | [file]]",
278	    "append input from a command or file to the line"},
279/* C_RECOVER */
280	{L("recover"),	ex_recover,	0,
281	    "!f1r",
282	    "recover[!] file",
283	    "recover a saved file"},
284/* C_RESIZE */
285	{L("resize"),	ex_resize,	E_VIONLY,
286	    "c+",
287	    "resize [+-]rows",
288	    "grow or shrink the current screen"},
289/* C_REWIND */
290	{L("rewind"),	ex_rew,		0,
291	    "!",
292	    "rew[ind][!]",
293	    "re-edit all the files in the file argument list"},
294/*
295 * !!!
296 * Adding new commands starting with 's' may break the substitute command code
297 * in ex_cmd() (the ex parser).  Read through the comments there, first.
298 */
299/* C_SUBSTITUTE */
300	{L("s"),		ex_s,		E_ADDR2|E_ADDR_ZERO,
301	    "s",
302	    "[line [,line]] s [[/;]RE[/;]repl[/;] [cgr] [count] [#lp]]",
303	    "substitute on lines matching an RE"},
304/* C_SCRIPT */
305	{L("script"),	ex_script,	E_SECURE,
306	    "!f1o",
307	    "sc[ript][!] [file]",
308	    "run a shell in a screen"},
309/* C_SET */
310	{L("set"),		ex_set,		0,
311	    "wN",
312	    "se[t] [option[=[value]]...] [nooption ...] [option? ...] [all]",
313	    "set options (use \":set all\" to see all options)"},
314/* C_SHELL */
315	{L("shell"),	ex_shell,	E_SECURE,
316	    "",
317	    "sh[ell]",
318	    "suspend editing and run a shell"},
319/* C_SOURCE */
320	{L("source"),	ex_source,	0,
321	    "f1r",
322	    "so[urce] file",
323	    "read a file of ex commands"},
324/* C_STOP */
325	{L("stop"),	ex_stop,	E_SECURE,
326	    "!",
327	    "st[op][!]",
328	    "suspend the edit session"},
329/* C_SUSPEND */
330	{L("suspend"),	ex_stop,	E_SECURE,
331	    "!",
332	    "su[spend][!]",
333	    "suspend the edit session"},
334/* C_T */
335	{L("t"),		ex_copy,	E_ADDR2|E_AUTOPRINT,
336	    "l1",
337	    "[line [,line]] t line [flags]",
338	    "copy lines elsewhere in the file"},
339/* C_TAG */
340	{L("tag"),		ex_tag_push,	E_NEWSCREEN,
341	    "!w1o",
342	    "[Tt]a[g][!] [string]",
343	    "edit the file containing the tag"},
344/* C_TAGNEXT */
345	{L("tagnext"),	ex_tag_next,	0,
346	    "!",
347	    "tagn[ext][!]",
348	    "move to the next tag"},
349/* C_TAGPOP */
350	{L("tagpop"),	ex_tag_pop,	0,
351	    "!w1o",
352	    "tagp[op][!] [number | file]",
353	    "return to the previous group of tags"},
354/* C_TAGPREV */
355	{L("tagprev"),	ex_tag_prev,	0,
356	    "!",
357	    "tagpr[ev][!]",
358	    "move to the previous tag"},
359/* C_TAGTOP */
360	{L("tagtop"),	ex_tag_top,	0,
361	    "!",
362	    "tagt[op][!]",
363	    "discard all tags"},
364/* C_UNDO */
365	{L("undo"),	ex_undo,	E_AUTOPRINT,
366	    "",
367	    "u[ndo]",
368	    "undo the most recent change"},
369/* C_UNABBREVIATE */
370	{L("unabbreviate"),ex_unabbr,	0,
371	    "w1r",
372	    "una[bbrev] word",
373	    "delete an abbreviation"},
374/* C_UNMAP */
375	{L("unmap"),	ex_unmap,	0,
376	    "!w1r",
377	    "unm[ap][!] word",
378	    "delete an input or command map"},
379/* C_V */
380	{L("v"),		ex_v,		E_ADDR2_ALL,
381	    "s",
382	    "[line [,line]] v [;/]RE[;/] [commands]",
383	    "execute a global command on lines NOT matching an RE"},
384/* C_VERSION */
385	{L("version"),	ex_version,	0,
386	    "",
387	    "version",
388	    "display the program version information"},
389/* C_VISUAL_EX */
390	{L("visual"),	ex_visual,	E_ADDR1|E_ADDR_ZERODEF,
391	    "2c11",
392	    "[line] vi[sual] [-|.|+|^] [window_size] [flags]",
393	    "enter visual (vi) mode from ex mode"},
394/* C_VISUAL_VI */
395	{L("visual"),	ex_edit,	E_NEWSCREEN,
396	    "f1o",
397	    "[Vv]i[sual][!] [+cmd] [file]",
398	    "edit another file (from vi mode only)"},
399/* C_VIUSAGE */
400	{L("viusage"),	ex_viusage,	0,
401	    "w1o",
402	    "[viu]sage [key]",
403	    "display vi key usage statement"},
404/* C_VSPLIT */
405	{L("vsplit"),	ex_edit,	E_VIONLY,
406	    "f1o",
407	    "vs[plit] [+cmd] [file]",
408	    "split the current screen vertically"},
409/* C_WRITE */
410	{L("write"),	ex_write,	E_ADDR2_ALL|E_ADDR_ZERODEF,
411	    "!s",
412	    "[line [,line]] w[rite][!] [ !cmd | [>>] [file]]",
413	    "write the file"},
414/* C_WN */
415	{L("wn"),		ex_wn,		E_ADDR2_ALL|E_ADDR_ZERODEF,
416	    "!s",
417	    "[line [,line]] wn[!] [>>] [file]",
418	    "write the file and switch to the next file"},
419/* C_WQ */
420	{L("wq"),		ex_wq,		E_ADDR2_ALL|E_ADDR_ZERODEF,
421	    "!s",
422	    "[line [,line]] wq[!] [>>] [file]",
423	    "write the file and exit"},
424/* C_XIT */
425	{L("xit"),		ex_xit,		E_ADDR2_ALL|E_ADDR_ZERODEF,
426	    "!f1o",
427	    "[line [,line]] x[it][!] [file]",
428	    "exit"},
429/* C_YANK */
430	{L("yank"),	ex_yank,	E_ADDR2,
431	    "bca",
432	    "[line [,line]] ya[nk] [buffer] [count]",
433	    "copy lines to a cut buffer"},
434/* C_Z */
435	{L("z"),		ex_z,		E_ADDR1,
436	    "3c01",
437	    "[line] z [-|.|+|^|=] [count] [flags]",
438	    "display different screens of the file"},
439/* C_SUBTILDE */
440	{L("~"),		ex_subtilde,	E_ADDR2|E_ADDR_ZERO,
441	    "s",
442	    "[line [,line]] ~ [cgr] [count] [#lp]",
443	    "replace previous RE with previous replacement string,"},
444	{NULL},
445};
446