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