xref: /freebsd/contrib/nvi/ex/ex_cmd.c (revision fcb560670601b2a4d87bb31d7531c8dcc37ee71b)
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
13 static 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  */
52 EXCMDLIST 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