ex_cmd.c revision 256281
128273Ssteve/*-
2124355Srwatson * Copyright (c) 1992, 1993, 1994
328273Ssteve *	The Regents of the University of California.  All rights reserved.
428273Ssteve * Copyright (c) 1992, 1993, 1994, 1995, 1996
528273Ssteve *	Keith Bostic.  All rights reserved.
628273Ssteve *
728273Ssteve * See the LICENSE file for redistribution information.
828273Ssteve */
928273Ssteve
1028273Ssteve#include "config.h"
1128273Ssteve
1228273Ssteve#ifndef lint
1328273Sstevestatic const char sccsid[] = "$Id: ex_cmd.c,v 10.26 2011/07/14 15:11:16 zy Exp $";
1428273Ssteve#endif /* not lint */
1528273Ssteve
1628273Ssteve#include <sys/types.h>
1728273Ssteve#include <sys/queue.h>
1828273Ssteve#include <sys/time.h>
1928273Ssteve
2028273Ssteve#include <bitstring.h>
2128273Ssteve#include <limits.h>
2228273Ssteve#include <stdio.h>
2328273Ssteve
2428273Ssteve#include "../common/common.h"
2528273Ssteve
2669059Sphantom/*
2750476Speter * This array maps ex command names to command functions.
2828273Ssteve *
29224708Srmacklem * The order in which command names are listed below is important --
3028273Ssteve * ambiguous abbreviations are resolved to be the first possible match,
3128273Ssteve * e.g. "r" means "read", not "rewind", because "read" is listed before
3228273Ssteve * "rewind".
3328273Ssteve *
3428273Ssteve * The syntax of the ex commands is unbelievably irregular, and a special
3528273Ssteve * case from beginning to end.  Each command has an associated "syntax
3628273Ssteve * script" which describes the "arguments" that are possible.  The script
3769059Sphantom * syntax is as follows:
3828273Ssteve *
3969059Sphantom *	!		-- ! flag
4028273Ssteve *	1		-- flags: [+-]*[pl#][+-]*
41111447Sru *	2		-- flags: [-.+^]
4228273Ssteve *	3		-- flags: [-.+^=]
4328273Ssteve *	b		-- buffer
4428273Ssteve *	c[01+a]		-- count (0-N, 1-N, signed 1-N, address offset)
4528273Ssteve *	f[N#][or]	-- file (a number or N, optional or required)
4628273Ssteve *	l		-- line
47111447Sru *	S		-- string with file name expansion
4870466Sru *	s		-- string
49111447Sru *	W		-- word string
50108228Sdillon *	w[N#][or]	-- word (a number or N, optional or required)
5170466Sru */
52111447SruEXCMDLIST const cmds[] = {
53111447Sru/* C_SCROLL */
54111447Sru	{L("\004"),	ex_pr,		E_ADDR2,
55111447Sru	    "",
5670466Sru	    "^D",
57111447Sru	    "scroll lines"},
58111447Sru/* C_BANG */
59111447Sru	{L("!"),		ex_bang,	E_ADDR2_NONE|E_SECURE,
6028273Ssteve	    "S",
6128273Ssteve	    "[line [,line]] ! command",
6228273Ssteve	    "filter lines through commands or run commands"},
6328273Ssteve/* C_HASH */
64111447Sru	{L("#"),		ex_number,	E_ADDR2|E_CLRFLAG,
65111447Sru	    "ca1",
66111447Sru	    "[line [,line]] # [count] [l]",
67111447Sru	    "display numbered lines"},
68111447Sru/* C_SUBAGAIN */
69111447Sru	{L("&"),		ex_subagain,	E_ADDR2|E_ADDR_ZERO,
70111447Sru	    "s",
71111447Sru	    "[line [,line]] & [cgr] [count] [#lp]",
72111447Sru	    "repeat the last subsitution"},
73111447Sru/* C_STAR */
74111447Sru	{L("*"),		ex_at,		0,
75111447Sru	    "b",
76108228Sdillon	    "* [buffer]",
77111447Sru	    "execute a buffer"},
78111447Sru/* C_SHIFTL */
79111447Sru	{L("<"),		ex_shiftl,	E_ADDR2|E_AUTOPRINT,
80108228Sdillon	    "ca1",
8128273Ssteve	    "[line [,line]] <[<...] [count] [flags]",
82108228Sdillon	    "shift lines left"},
83111447Sru/* C_EQUAL */
84111447Sru	{L("="),		ex_equal,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
85111447Sru	    "1",
86111447Sru	    "[line] = [flags]",
87111447Sru	    "display line number"},
88111447Sru/* C_SHIFTR */
89111447Sru	{L(">"),		ex_shiftr,	E_ADDR2|E_AUTOPRINT,
90111447Sru	    "ca1",
91111447Sru	    "[line [,line]] >[>...] [count] [flags]",
92111447Sru	    "shift lines right"},
93111447Sru/* C_AT */
94111447Sru	{L("@"),		ex_at,		E_ADDR2,
95111447Sru	    "b",
96111447Sru	    "@ [buffer]",
97111447Sru	    "execute a buffer"},
98111447Sru/* C_APPEND */
99111447Sru	{L("append"),	ex_append,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
100111447Sru	    "!",
101111447Sru	    "[line] a[ppend][!]",
102111447Sru	    "append input to a line"},
103111447Sru/* C_ABBR */
104111447Sru	{L("abbreviate"), 	ex_abbr,	0,
105111447Sru	    "W",
106111447Sru	    "ab[brev] [word replace]",
107111447Sru	    "specify an input abbreviation"},
108108228Sdillon/* C_ARGS */
109151202Syar	{L("args"),	ex_args,	0,
110111447Sru	    "",
111111447Sru	    "ar[gs]",
112111447Sru	    "display file argument list"},
113111447Sru/* C_BG */
114111447Sru	{L("bg"),		ex_bg,		E_VIONLY,
115111447Sru	    "",
116111447Sru	    "bg",
117111447Sru	    "put a foreground screen into the background"},
118111447Sru/* C_CHANGE */
119111447Sru	{L("change"),	ex_change,	E_ADDR2|E_ADDR_ZERODEF,
120111447Sru	    "!ca",
121111447Sru	    "[line [,line]] c[hange][!] [count]",
122108228Sdillon	    "change lines to input"},
123111447Sru/* C_CD */
124111447Sru	{L("cd"),		ex_cd,		0,
125111447Sru	    "!f1o",
126108228Sdillon	    "cd[!] [directory]",
127126005Spjd	    "change the current directory"},
128108228Sdillon/* C_CHDIR */
129108228Sdillon	{L("chdir"),	ex_cd,		0,
130108228Sdillon	    "!f1o",
13128273Ssteve	    "chd[ir][!] [directory]",
132124355Srwatson	    "change the current directory"},
133124355Srwatson/* C_COPY */
134124355Srwatson	{L("copy"),	ex_copy,	E_ADDR2|E_AUTOPRINT,
135130582Sru	    "l1",
136124355Srwatson	    "[line [,line]] co[py] line [flags]",
137124355Srwatson	    "copy lines elsewhere in the file"},
138124355Srwatson/* C_CSCOPE */
139111447Sru	{L("cscope"),      ex_cscope,      0,
140111447Sru	    "!s",
141111447Sru	    "cs[cope] command [args]",
142111447Sru	    "create a set of tags using a cscope command"},
143124355Srwatson/*
144111447Sru * !!!
145111447Sru * Adding new commands starting with 'd' may break the delete command code
146111447Sru * in ex_cmd() (the ex parser).  Read through the comments there, first.
147111447Sru */
148108228Sdillon/* C_DELETE */
149135922Sbrooks	{L("delete"),	ex_delete,	E_ADDR2|E_AUTOPRINT,
150135922Sbrooks	    "bca1",
151153887Sceri	    "[line [,line]] d[elete][flags] [buffer] [count] [flags]",
152108228Sdillon	    "delete lines from the file"},
153153887Sceri/* C_DISPLAY */
15428273Ssteve	{L("display"),	ex_display,	0,
155111447Sru	    "w1r",
156111447Sru	    "display b[uffers] | c[onnections] | s[creens] | t[ags]",
157111447Sru	    "display buffers, connections, screens or tags"},
15876444Sbsd/* C_EDIT */
15970466Sru	{L("edit"),	ex_edit,	E_NEWSCREEN,
160111447Sru	    "f1o",
161111447Sru	    "[Ee][dit][!] [+cmd] [file]",
162111447Sru	    "begin editing another file"},
163111447Sru/* C_EX */
164111447Sru	{L("ex"),		ex_edit,	E_NEWSCREEN,
165111447Sru	    "f1o",
166111447Sru	    "[Ee]x[!] [+cmd] [file]",
167111447Sru	    "begin editing another file"},
16876444Sbsd/* C_EXUSAGE */
16976444Sbsd	{L("exusage"),	ex_usage,	0,
17076444Sbsd	    "w1o",
17176444Sbsd	    "[exu]sage [command]",
17276444Sbsd	    "display ex command usage statement"},
17376444Sbsd/* C_FILE */
174104336Sdd	{L("file"),	ex_file,	0,
175104336Sdd	    "f1o",
17628273Ssteve	    "f[ile] [name]",
17728273Ssteve	    "display (and optionally set) file name"},
17876444Sbsd/* C_FG */
17976444Sbsd	{L("fg"),		ex_fg,		E_NEWSCREEN|E_VIONLY,
180111447Sru	    "f1o",
18176444Sbsd	    "[Ff]g [file]",
18276444Sbsd	    "bring a backgrounded screen into the foreground"},
183111447Sru/* C_GLOBAL */
184108228Sdillon	{L("global"),	ex_global,	E_ADDR2_ALL,
185111447Sru	    "!s",
18676444Sbsd	    "[line [,line]] g[lobal][!] [;/]RE[;/] [commands]",
18770466Sru	    "execute a global command on lines matching an RE"},
188111447Sru/* C_HELP */
18976444Sbsd	{L("help"),	ex_help,	0,
19076444Sbsd	    "",
19176444Sbsd	    "he[lp]",
19276444Sbsd	    "display help statement"},
19376444Sbsd/* C_INSERT */
19476444Sbsd	{L("insert"),	ex_insert,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
19576444Sbsd	    "!",
196111447Sru	    "[line] i[nsert][!]",
19776444Sbsd	    "insert input before a line"},
19876444Sbsd/* C_JOIN */
19976444Sbsd	{L("join"),	ex_join,	E_ADDR2|E_AUTOPRINT,
20076444Sbsd	    "!ca1",
20176444Sbsd	    "[line [,line]] j[oin][!] [count] [flags]",
20276444Sbsd	    "join lines into a single line"},
20376444Sbsd/* C_K */
20476444Sbsd	{L("k"),		ex_mark,	E_ADDR1,
20576444Sbsd	    "w1r",
20676444Sbsd	    "[line] k key",
20776444Sbsd	    "mark a line position"},
20876444Sbsd/* C_LIST */
20976444Sbsd	{L("list"),	ex_list,	E_ADDR2|E_CLRFLAG,
21076444Sbsd	    "ca1",
21128273Ssteve	    "[line [,line]] l[ist] [count] [#]",
21228273Ssteve	    "display lines in an unambiguous form"},
21376444Sbsd/* C_MOVE */
21476444Sbsd	{L("move"),	ex_move,	E_ADDR2|E_AUTOPRINT,
21576444Sbsd	    "l",
21676444Sbsd	    "[line [,line]] m[ove] line",
21776444Sbsd	    "move lines elsewhere in the file"},
21876444Sbsd/* C_MARK */
21970466Sru	{L("mark"),	ex_mark,	E_ADDR1,
220108228Sdillon	    "w1r",
221108228Sdillon	    "[line] ma[rk] key",
222108228Sdillon	    "mark a line position"},
223108228Sdillon/* C_MAP */
224111447Sru	{L("map"),		ex_map,		0,
225111447Sru	    "!W",
226108228Sdillon	    "map[!] [keys replace]",
227108228Sdillon	    "map input or commands to one or more keys"},
228108228Sdillon/* C_MKEXRC */
229108228Sdillon	{L("mkexrc"),	ex_mkexrc,	0,
230108228Sdillon	    "!f1r",
231108228Sdillon	    "mkexrc[!] file",
232108228Sdillon	    "write a .exrc file"},
233108228Sdillon/* C_NEXT */
234111447Sru	{L("next"),	ex_next,	E_NEWSCREEN,
235111447Sru	    "!fN",
236111447Sru	    "[Nn][ext][!] [+cmd] [file ...]",
237111447Sru	    "edit (and optionally specify) the next file"},
238111447Sru/* C_NUMBER */
239111447Sru	{L("number"),	ex_number,	E_ADDR2|E_CLRFLAG,
240108228Sdillon	    "ca1",
241108228Sdillon	    "[line [,line]] nu[mber] [count] [l]",
242108228Sdillon	    "change display to number lines"},
243111447Sru/* C_OPEN */
244153298Sdougb	{L("open"),	ex_open,	E_ADDR1,
245153298Sdougb	    "s",
246153298Sdougb	    "[line] o[pen] [/RE/] [flags]",
247153298Sdougb	    "enter \"open\" mode (not implemented)"},
248153298Sdougb/* C_PRINT */
249153298Sdougb	{L("print"),	ex_pr,		E_ADDR2|E_CLRFLAG,
250153298Sdougb	    "ca1",
251153298Sdougb	    "[line [,line]] p[rint] [count] [#l]",
252153298Sdougb	    "display lines"},
253153298Sdougb/* C_PRESERVE */
254153298Sdougb	{L("preserve"),	ex_preserve,	0,
255153298Sdougb	    "",
256111447Sru	    "pre[serve]",
257108228Sdillon	    "preserve an edit session for recovery"},
258108228Sdillon/* C_PREVIOUS */
259108228Sdillon	{L("previous"),	ex_prev,	E_NEWSCREEN,
260108228Sdillon	    "!",
261108228Sdillon	    "[Pp]rev[ious][!]",
262108228Sdillon	    "edit the previous file in the file argument list"},
263108228Sdillon/* C_PUT */
264108228Sdillon	{L("put"),		ex_put,
265108228Sdillon	    E_ADDR1|E_AUTOPRINT|E_ADDR_ZERO|E_ADDR_ZERODEF,
266108228Sdillon	    "b",
267111447Sru	    "[line] pu[t] [buffer]",
268111447Sru	    "append a cut buffer to the line"},
269111447Sru/* C_QUIT */
270108228Sdillon	{L("quit"),	ex_quit,	0,
271108228Sdillon	    "!",
272111447Sru	    "q[uit][!]",
273111447Sru	    "exit ex/vi"},
274111447Sru/* C_READ */
275108228Sdillon	{L("read"),	ex_read,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
276108228Sdillon	    "s",
277108228Sdillon	    "[line] r[ead] [!cmd | [file]]",
278108228Sdillon	    "append input from a command or file to the line"},
279108228Sdillon/* C_RECOVER */
280108228Sdillon	{L("recover"),	ex_recover,	0,
281111447Sru	    "!f1r",
282111447Sru	    "recover[!] file",
283111447Sru	    "recover a saved file"},
28476445Sbsd/* C_RESIZE */
285108228Sdillon	{L("resize"),	ex_resize,	E_VIONLY,
286108228Sdillon	    "c+",
287111447Sru	    "resize [+-]rows",
288111447Sru	    "grow or shrink the current screen"},
289130844Smpp/* C_REWIND */
290117087Sbrooks	{L("rewind"),	ex_rew,		0,
291117087Sbrooks	    "!",
292117087Sbrooks	    "rew[ind][!]",
293117087Sbrooks	    "re-edit all the files in the file argument list"},
294117087Sbrooks/*
295117087Sbrooks * !!!
296117087Sbrooks * Adding new commands starting with 's' may break the substitute command code
297117087Sbrooks * in ex_cmd() (the ex parser).  Read through the comments there, first.
298117087Sbrooks */
299117087Sbrooks/* C_SUBSTITUTE */
300117087Sbrooks	{L("s"),		ex_s,		E_ADDR2|E_ADDR_ZERO,
301117087Sbrooks	    "s",
302117087Sbrooks	    "[line [,line]] s [[/;]RE[/;]repl[/;] [cgr] [count] [#lp]]",
303130844Smpp	    "substitute on lines matching an RE"},
304117087Sbrooks/* C_SCRIPT */
305117087Sbrooks	{L("script"),	ex_script,	E_SECURE,
306117087Sbrooks	    "!f1o",
307117087Sbrooks	    "sc[ript][!] [file]",
308117087Sbrooks	    "run a shell in a screen"},
309117087Sbrooks/* C_SET */
310111447Sru	{L("set"),		ex_set,		0,
311111447Sru	    "wN",
312130844Smpp	    "se[t] [option[=[value]]...] [nooption ...] [option? ...] [all]",
313111447Sru	    "set options (use \":set all\" to see all options)"},
314111447Sru/* C_SHELL */
315111447Sru	{L("shell"),	ex_shell,	E_SECURE,
316111447Sru	    "",
317108228Sdillon	    "sh[ell]",
318108228Sdillon	    "suspend editing and run a shell"},
319108228Sdillon/* C_SOURCE */
320108228Sdillon	{L("source"),	ex_source,	0,
321108228Sdillon	    "f1r",
322108228Sdillon	    "so[urce] file",
32376445Sbsd	    "read a file of ex commands"},
324111447Sru/* C_STOP */
325111447Sru	{L("stop"),	ex_stop,	E_SECURE,
326111447Sru	    "!",
327108228Sdillon	    "st[op][!]",
328108228Sdillon	    "suspend the edit session"},
329108228Sdillon/* C_SUSPEND */
330111447Sru	{L("suspend"),	ex_stop,	E_SECURE,
331108228Sdillon	    "!",
332108228Sdillon	    "su[spend][!]",
333108228Sdillon	    "suspend the edit session"},
334111447Sru/* C_T */
335111447Sru	{L("t"),		ex_copy,	E_ADDR2|E_AUTOPRINT,
336108228Sdillon	    "l1",
337111447Sru	    "[line [,line]] t line [flags]",
338111447Sru	    "copy lines elsewhere in the file"},
339111447Sru/* C_TAG */
340111447Sru	{L("tag"),		ex_tag_push,	E_NEWSCREEN,
341111447Sru	    "!w1o",
342111447Sru	    "[Tt]a[g][!] [string]",
343111447Sru	    "edit the file containing the tag"},
344108228Sdillon/* C_TAGNEXT */
345108228Sdillon	{L("tagnext"),	ex_tag_next,	0,
346108228Sdillon	    "!",
347108228Sdillon	    "tagn[ext][!]",
348108228Sdillon	    "move to the next tag"},
349108228Sdillon/* C_TAGPOP */
350108228Sdillon	{L("tagpop"),	ex_tag_pop,	0,
35176445Sbsd	    "!w1o",
352108228Sdillon	    "tagp[op][!] [number | file]",
353108228Sdillon	    "return to the previous group of tags"},
354108228Sdillon/* C_TAGPREV */
355108228Sdillon	{L("tagprev"),	ex_tag_prev,	0,
35628273Ssteve	    "!",
357108228Sdillon	    "tagpr[ev][!]",
35876444Sbsd	    "move to the previous tag"},
359108228Sdillon/* C_TAGTOP */
360108228Sdillon	{L("tagtop"),	ex_tag_top,	0,
361111447Sru	    "!",
362111447Sru	    "tagt[op][!]",
363111447Sru	    "discard all tags"},
364108228Sdillon/* C_UNDO */
365108228Sdillon	{L("undo"),	ex_undo,	E_AUTOPRINT,
366108228Sdillon	    "",
367111447Sru	    "u[ndo]",
368111447Sru	    "undo the most recent change"},
369111447Sru/* C_UNABBREVIATE */
370108228Sdillon	{L("unabbreviate"),ex_unabbr,	0,
371108228Sdillon	    "w1r",
372108228Sdillon	    "una[bbrev] word",
37328273Ssteve	    "delete an abbreviation"},
37476444Sbsd/* C_UNMAP */
37576444Sbsd	{L("unmap"),	ex_unmap,	0,
37676444Sbsd	    "!w1r",
37776444Sbsd	    "unm[ap][!] word",
37876444Sbsd	    "delete an input or command map"},
37928273Ssteve/* C_V */
38028273Ssteve	{L("v"),		ex_v,		E_ADDR2_ALL,
381108228Sdillon	    "s",
38276444Sbsd	    "[line [,line]] v [;/]RE[;/] [commands]",
38376444Sbsd	    "execute a global command on lines NOT matching an RE"},
384111447Sru/* C_VERSION */
385111447Sru	{L("version"),	ex_version,	0,
386111447Sru	    "",
387108228Sdillon	    "version",
388108228Sdillon	    "display the program version information"},
389108228Sdillon/* C_VISUAL_EX */
390111447Sru	{L("visual"),	ex_visual,	E_ADDR1|E_ADDR_ZERODEF,
391111447Sru	    "2c11",
392111447Sru	    "[line] vi[sual] [-|.|+|^] [window_size] [flags]",
39328273Ssteve	    "enter visual (vi) mode from ex mode"},
394108228Sdillon/* C_VISUAL_VI */
395108228Sdillon	{L("visual"),	ex_edit,	E_NEWSCREEN,
396108228Sdillon	    "f1o",
39776444Sbsd	    "[Vv]i[sual][!] [+cmd] [file]",
39876444Sbsd	    "edit another file (from vi mode only)"},
39976444Sbsd/* C_VIUSAGE */
40076444Sbsd	{L("viusage"),	ex_viusage,	0,
40176444Sbsd	    "w1o",
40276444Sbsd	    "[viu]sage [key]",
40376444Sbsd	    "display vi key usage statement"},
40476444Sbsd/* C_VSPLIT */
40576444Sbsd	{L("vsplit"),	ex_edit,	E_VIONLY,
40676444Sbsd	    "f1o",
407111447Sru	    "vs[plit] [+cmd] [file]",
408111447Sru	    "split the current screen vertically"},
409111447Sru/* C_WRITE */
41076444Sbsd	{L("write"),	ex_write,	E_ADDR2_ALL|E_ADDR_ZERODEF,
41170466Sru	    "!s",
412111447Sru	    "[line [,line]] w[rite][!] [ !cmd | [>>] [file]]",
413111447Sru	    "write the file"},
414111447Sru/* C_WN */
415111447Sru	{L("wn"),		ex_wn,		E_ADDR2_ALL|E_ADDR_ZERODEF,
416111447Sru	    "!s",
417111447Sru	    "[line [,line]] wn[!] [>>] [file]",
418124355Srwatson	    "write the file and switch to the next file"},
41928273Ssteve/* C_WQ */
420224708Srmacklem	{L("wq"),		ex_wq,		E_ADDR2_ALL|E_ADDR_ZERODEF,
421124355Srwatson	    "!s",
422124355Srwatson	    "[line [,line]] wq[!] [>>] [file]",
423124355Srwatson	    "write the file and exit"},
424124355Srwatson/* C_XIT */
425124355Srwatson	{L("xit"),		ex_xit,		E_ADDR2_ALL|E_ADDR_ZERODEF,
426124355Srwatson	    "!f1o",
427111447Sru	    "[line [,line]] x[it][!] [file]",
428111447Sru	    "exit"},
429111447Sru/* C_YANK */
430111447Sru	{L("yank"),	ex_yank,	E_ADDR2,
431130582Sru	    "bca",
432130582Sru	    "[line [,line]] ya[nk] [buffer] [count]",
433108228Sdillon	    "copy lines to a cut buffer"},
434130582Sru/* C_Z */
435130582Sru	{L("z"),		ex_z,		E_ADDR1,
436130582Sru	    "3c01",
437124355Srwatson	    "[line] z [-|.|+|^|=] [count] [flags]",
438124355Srwatson	    "display different screens of the file"},
439124355Srwatson/* C_SUBTILDE */
440124355Srwatson	{L("~"),		ex_subtilde,	E_ADDR2|E_ADDR_ZERO,
441111447Sru	    "s",
442111447Sru	    "[line [,line]] ~ [cgr] [count] [#lp]",
443111447Sru	    "replace previous RE with previous replacement string,"},
444111447Sru	{NULL},
445111447Sru};
446111447Sru