119304Speter/*-
219304Speter * Copyright (c) 1992, 1993, 1994
319304Speter *	The Regents of the University of California.  All rights reserved.
419304Speter * Copyright (c) 1992, 1993, 1994, 1995, 1996
519304Speter *	Keith Bostic.  All rights reserved.
619304Speter *
719304Speter * See the LICENSE file for redistribution information.
819304Speter */
919304Speter
1019304Speter#include "config.h"
1119304Speter
1219304Speter#ifndef lint
1319304Speterstatic const char sccsid[] = "@(#)ex_cmd.c	10.20 (Berkeley) 10/10/96";
1419304Speter#endif /* not lint */
1519304Speter
1619304Speter#include <sys/types.h>
1719304Speter#include <sys/queue.h>
1819304Speter
1919304Speter#include <bitstring.h>
2019304Speter#include <limits.h>
2119304Speter#include <stdio.h>
2219304Speter
2319304Speter#include "../common/common.h"
2419304Speter
2519304Speter/*
2619304Speter * This array maps ex command names to command functions.
2719304Speter *
2819304Speter * The order in which command names are listed below is important --
2919304Speter * ambiguous abbreviations are resolved to be the first possible match,
3019304Speter * e.g. "r" means "read", not "rewind", because "read" is listed before
3119304Speter * "rewind".
3219304Speter *
3319304Speter * The syntax of the ex commands is unbelievably irregular, and a special
3419304Speter * case from beginning to end.  Each command has an associated "syntax
3519304Speter * script" which describes the "arguments" that are possible.  The script
3619304Speter * syntax is as follows:
3719304Speter *
3819304Speter *	!		-- ! flag
3919304Speter *	1		-- flags: [+-]*[pl#][+-]*
4019304Speter *	2		-- flags: [-.+^]
4119304Speter *	3		-- flags: [-.+^=]
4219304Speter *	b		-- buffer
4319304Speter *	c[01+a]		-- count (0-N, 1-N, signed 1-N, address offset)
4419304Speter *	f[N#][or]	-- file (a number or N, optional or required)
4519304Speter *	l		-- line
4619304Speter *	S		-- string with file name expansion
4719304Speter *	s		-- string
4819304Speter *	W		-- word string
4919304Speter *	w[N#][or]	-- word (a number or N, optional or required)
5019304Speter */
5119304SpeterEXCMDLIST const cmds[] = {
5219304Speter/* C_SCROLL */
5319304Speter	{"\004",	ex_pr,		E_ADDR2,
5419304Speter	    "",
5519304Speter	    "^D",
5619304Speter	    "scroll lines"},
5719304Speter/* C_BANG */
5819304Speter	{"!",		ex_bang,	E_ADDR2_NONE | E_SECURE,
5919304Speter	    "S",
6019304Speter	    "[line [,line]] ! command",
6119304Speter	    "filter lines through commands or run commands"},
6219304Speter/* C_HASH */
6319304Speter	{"#",		ex_number,	E_ADDR2|E_CLRFLAG,
6419304Speter	    "ca1",
6519304Speter	    "[line [,line]] # [count] [l]",
6619304Speter	    "display numbered lines"},
6719304Speter/* C_SUBAGAIN */
6819304Speter	{"&",		ex_subagain,	E_ADDR2,
6919304Speter	    "s",
7019304Speter	    "[line [,line]] & [cgr] [count] [#lp]",
71208611Sjh	    "repeat the last substitution"},
7219304Speter/* C_STAR */
7319304Speter	{"*",		ex_at,		0,
7419304Speter	    "b",
7519304Speter	    "* [buffer]",
7619304Speter	    "execute a buffer"},
7719304Speter/* C_SHIFTL */
7819304Speter	{"<",		ex_shiftl,	E_ADDR2|E_AUTOPRINT,
7919304Speter	    "ca1",
8019304Speter	    "[line [,line]] <[<...] [count] [flags]",
8119304Speter	    "shift lines left"},
8219304Speter/* C_EQUAL */
8319304Speter	{"=",		ex_equal,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
8419304Speter	    "1",
8519304Speter	    "[line] = [flags]",
8619304Speter	    "display line number"},
8719304Speter/* C_SHIFTR */
8819304Speter	{">",		ex_shiftr,	E_ADDR2|E_AUTOPRINT,
8919304Speter	    "ca1",
9019304Speter	    "[line [,line]] >[>...] [count] [flags]",
9119304Speter	    "shift lines right"},
9219304Speter/* C_AT */
9319304Speter	{"@",		ex_at,		E_ADDR2,
9419304Speter	    "b",
9519304Speter	    "@ [buffer]",
9619304Speter	    "execute a buffer"},
9719304Speter/* C_APPEND */
9819304Speter	{"append",	ex_append,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
9919304Speter	    "!",
10019304Speter	    "[line] a[ppend][!]",
10119304Speter	    "append input to a line"},
10219304Speter/* C_ABBR */
10319304Speter	{"abbreviate", 	ex_abbr,	0,
10419304Speter	    "W",
10519304Speter	    "ab[brev] [word replace]",
10619304Speter	    "specify an input abbreviation"},
10719304Speter/* C_ARGS */
10819304Speter	{"args",	ex_args,	0,
10919304Speter	    "",
11019304Speter	    "ar[gs]",
11119304Speter	    "display file argument list"},
11219304Speter/* C_BG */
11319304Speter	{"bg",		ex_bg,		E_VIONLY,
11419304Speter	    "",
11519304Speter	    "bg",
11619304Speter	    "put a foreground screen into the background"},
11719304Speter/* C_CHANGE */
11819304Speter	{"change",	ex_change,	E_ADDR2|E_ADDR_ZERODEF,
11919304Speter	    "!ca",
12019304Speter	    "[line [,line]] c[hange][!] [count]",
12119304Speter	    "change lines to input"},
12219304Speter/* C_CD */
12319304Speter	{"cd",		ex_cd,		0,
12419304Speter	    "!f1o",
12519304Speter	    "cd[!] [directory]",
12619304Speter	    "change the current directory"},
12719304Speter/* C_CHDIR */
12819304Speter	{"chdir",	ex_cd,		0,
12919304Speter	    "!f1o",
13019304Speter	    "chd[ir][!] [directory]",
13119304Speter	    "change the current directory"},
13219304Speter/* C_COPY */
13319304Speter	{"copy",	ex_copy,	E_ADDR2|E_AUTOPRINT,
13419304Speter	    "l1",
13519304Speter	    "[line [,line]] co[py] line [flags]",
13619304Speter	    "copy lines elsewhere in the file"},
13719304Speter/* C_CSCOPE */
13819304Speter	{"cscope",      ex_cscope,      0,
13919304Speter	    "!s",
14019304Speter	    "cs[cope] command [args]",
14119304Speter	    "create a set of tags using a cscope command"},
14219304Speter/*
14319304Speter * !!!
14419304Speter * Adding new commands starting with 'd' may break the delete command code
14519304Speter * in ex_cmd() (the ex parser).  Read through the comments there, first.
14619304Speter */
14719304Speter/* C_DELETE */
14819304Speter	{"delete",	ex_delete,	E_ADDR2|E_AUTOPRINT,
14919304Speter	    "bca1",
15019304Speter	    "[line [,line]] d[elete][flags] [buffer] [count] [flags]",
15119304Speter	    "delete lines from the file"},
15219304Speter/* C_DISPLAY */
15319304Speter	{"display",	ex_display,	0,
15419304Speter	    "w1r",
15519304Speter	    "display b[uffers] | c[onnections] | s[creens] | t[ags]",
15619304Speter	    "display buffers, connections, screens or tags"},
15719304Speter/* C_EDIT */
15819304Speter	{"edit",	ex_edit,	E_NEWSCREEN,
15919304Speter	    "f1o",
16019304Speter	    "[Ee][dit][!] [+cmd] [file]",
16119304Speter	    "begin editing another file"},
16219304Speter/* C_EX */
16319304Speter	{"ex",		ex_edit,	E_NEWSCREEN,
16419304Speter	    "f1o",
16519304Speter	    "[Ee]x[!] [+cmd] [file]",
16619304Speter	    "begin editing another file"},
16719304Speter/* C_EXUSAGE */
16819304Speter	{"exusage",	ex_usage,	0,
16919304Speter	    "w1o",
17019304Speter	    "[exu]sage [command]",
17119304Speter	    "display ex command usage statement"},
17219304Speter/* C_FILE */
17319304Speter	{"file",	ex_file,	0,
17419304Speter	    "f1o",
17519304Speter	    "f[ile] [name]",
17619304Speter	    "display (and optionally set) file name"},
17719304Speter/* C_FG */
17819304Speter	{"fg",		ex_fg,		E_NEWSCREEN|E_VIONLY,
17919304Speter	    "f1o",
18019304Speter	    "[Ff]g [file]",
18119304Speter	    "bring a backgrounded screen into the foreground"},
18219304Speter/* C_GLOBAL */
18319304Speter	{"global",	ex_global,	E_ADDR2_ALL,
18419304Speter	    "!s",
18519304Speter	    "[line [,line]] g[lobal][!] [;/]RE[;/] [commands]",
18619304Speter	    "execute a global command on lines matching an RE"},
18719304Speter/* C_HELP */
18819304Speter	{"help",	ex_help,	0,
18919304Speter	    "",
19019304Speter	    "he[lp]",
19119304Speter	    "display help statement"},
19219304Speter/* C_INSERT */
19319304Speter	{"insert",	ex_insert,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
19419304Speter	    "!",
19519304Speter	    "[line] i[nsert][!]",
19619304Speter	    "insert input before a line"},
19719304Speter/* C_JOIN */
19819304Speter	{"join",	ex_join,	E_ADDR2|E_AUTOPRINT,
19919304Speter	    "!ca1",
20019304Speter	    "[line [,line]] j[oin][!] [count] [flags]",
20119304Speter	    "join lines into a single line"},
20219304Speter/* C_K */
20319304Speter	{"k",		ex_mark,	E_ADDR1,
20419304Speter	    "w1r",
20519304Speter	    "[line] k key",
20619304Speter	    "mark a line position"},
20719304Speter/* C_LIST */
20819304Speter	{"list",	ex_list,	E_ADDR2|E_CLRFLAG,
20919304Speter	    "ca1",
21019304Speter	    "[line [,line]] l[ist] [count] [#]",
21119304Speter	    "display lines in an unambiguous form"},
21219304Speter/* C_MOVE */
21319304Speter	{"move",	ex_move,	E_ADDR2|E_AUTOPRINT,
21419304Speter	    "l",
21519304Speter	    "[line [,line]] m[ove] line",
21619304Speter	    "move lines elsewhere in the file"},
21719304Speter/* C_MARK */
21819304Speter	{"mark",	ex_mark,	E_ADDR1,
21919304Speter	    "w1r",
22019304Speter	    "[line] ma[rk] key",
22119304Speter	    "mark a line position"},
22219304Speter/* C_MAP */
22319304Speter	{"map",		ex_map,		0,
22419304Speter	    "!W",
22519304Speter	    "map[!] [keys replace]",
22619304Speter	    "map input or commands to one or more keys"},
22719304Speter/* C_MKEXRC */
22819304Speter	{"mkexrc",	ex_mkexrc,	0,
22919304Speter	    "!f1r",
23019304Speter	    "mkexrc[!] file",
23119304Speter	    "write a .exrc file"},
23219304Speter/* C_NEXT */
23319304Speter	{"next",	ex_next,	E_NEWSCREEN,
23419304Speter	    "!fN",
23519304Speter	    "[Nn][ext][!] [+cmd] [file ...]",
23619304Speter	    "edit (and optionally specify) the next file"},
23719304Speter/* C_NUMBER */
23819304Speter	{"number",	ex_number,	E_ADDR2|E_CLRFLAG,
23919304Speter	    "ca1",
24019304Speter	    "[line [,line]] nu[mber] [count] [l]",
24119304Speter	    "change display to number lines"},
24219304Speter/* C_OPEN */
24319304Speter	{"open",	ex_open,	E_ADDR1,
24419304Speter	    "s",
24519304Speter	    "[line] o[pen] [/RE/] [flags]",
24619304Speter	    "enter \"open\" mode (not implemented)"},
24719304Speter/* C_PRINT */
24819304Speter	{"print",	ex_pr,		E_ADDR2|E_CLRFLAG,
24919304Speter	    "ca1",
25019304Speter	    "[line [,line]] p[rint] [count] [#l]",
25119304Speter	    "display lines"},
25219304Speter/* C_PERLCMD */
25319304Speter	{"perl",	ex_perl,	E_ADDR2_ALL|E_ADDR_ZERO|
25419304Speter					    E_ADDR_ZERODEF|E_SECURE,
25519304Speter	    "s",
25619304Speter	    "pe[rl] cmd",
25719304Speter	    "run the perl interpreter with the command"},
25819304Speter/* C_PERLDOCMD */
25919304Speter	{"perldo",	ex_perl,	E_ADDR2_ALL|E_ADDR_ZERO|
26019304Speter					    E_ADDR_ZERODEF|E_SECURE,
26119304Speter	    "s",
26219304Speter	    "perld[o] cmd",
26319304Speter	    "run the perl interpreter with the command, on each line"},
26419304Speter/* C_PRESERVE */
26519304Speter	{"preserve",	ex_preserve,	0,
26619304Speter	    "",
26719304Speter	    "pre[serve]",
26819304Speter	    "preserve an edit session for recovery"},
26919304Speter/* C_PREVIOUS */
27019304Speter	{"previous",	ex_prev,	E_NEWSCREEN,
27119304Speter	    "!",
27219304Speter	    "[Pp]rev[ious][!]",
27319304Speter	    "edit the previous file in the file argument list"},
27419304Speter/* C_PUT */
27519304Speter	{"put",		ex_put,
27619304Speter	    E_ADDR1|E_AUTOPRINT|E_ADDR_ZERO|E_ADDR_ZERODEF,
27719304Speter	    "b",
27819304Speter	    "[line] pu[t] [buffer]",
27919304Speter	    "append a cut buffer to the line"},
28019304Speter/* C_QUIT */
28119304Speter	{"quit",	ex_quit,	0,
28219304Speter	    "!",
28319304Speter	    "q[uit][!]",
28419304Speter	    "exit ex/vi"},
28519304Speter/* C_READ */
28619304Speter	{"read",	ex_read,	E_ADDR1|E_ADDR_ZERO|E_ADDR_ZERODEF,
28719304Speter	    "s",
28819304Speter	    "[line] r[ead] [!cmd | [file]]",
28919304Speter	    "append input from a command or file to the line"},
29019304Speter/* C_RECOVER */
29119304Speter	{"recover",	ex_recover,	0,
29219304Speter	    "!f1r",
29319304Speter	    "recover[!] file",
29419304Speter	    "recover a saved file"},
29519304Speter/* C_RESIZE */
29619304Speter	{"resize",	ex_resize,	E_VIONLY,
29719304Speter	    "c+",
29819304Speter	    "resize [+-]rows",
29919304Speter	    "grow or shrink the current screen"},
30019304Speter/* C_REWIND */
30119304Speter	{"rewind",	ex_rew,		0,
30219304Speter	    "!",
30319304Speter	    "rew[ind][!]",
30419304Speter	    "re-edit all the files in the file argument list"},
30525011Sjkh#ifdef GTAGS
30625011Sjkh/* C_RTAG */
30725011Sjkh	{"rtag",	ex_rtag_push,	E_NEWSCREEN,
30825011Sjkh	    "!w1o",
30925011Sjkh	    "[Rr]ta[g][!] [string]",
31025011Sjkh	    "edit the file containing the tag"},
31125011Sjkh#endif
31219304Speter/*
31319304Speter * !!!
31419304Speter * Adding new commands starting with 's' may break the substitute command code
31519304Speter * in ex_cmd() (the ex parser).  Read through the comments there, first.
31619304Speter */
31719304Speter/* C_SUBSTITUTE */
31819304Speter	{"s",		ex_s,		E_ADDR2,
31919304Speter	    "s",
32019304Speter	    "[line [,line]] s [[/;]RE[/;]repl[/;] [cgr] [count] [#lp]]",
32119304Speter	    "substitute on lines matching an RE"},
32219304Speter/* C_SCRIPT */
32319304Speter	{"script",	ex_script,	E_SECURE,
32419304Speter	    "!f1o",
32519304Speter	    "sc[ript][!] [file]",
32619304Speter	    "run a shell in a screen"},
32719304Speter/* C_SET */
32819304Speter	{"set",		ex_set,		0,
32919304Speter	    "wN",
33019304Speter	    "se[t] [option[=[value]]...] [nooption ...] [option? ...] [all]",
33119304Speter	    "set options (use \":set all\" to see all options)"},
33219304Speter/* C_SHELL */
33319304Speter	{"shell",	ex_shell,	E_SECURE,
33419304Speter	    "",
33519304Speter	    "sh[ell]",
33619304Speter	    "suspend editing and run a shell"},
33719304Speter/* C_SOURCE */
33819304Speter	{"source",	ex_source,	0,
33919304Speter	    "f1r",
34019304Speter	    "so[urce] file",
34119304Speter	    "read a file of ex commands"},
34219304Speter/* C_STOP */
34319304Speter	{"stop",	ex_stop,	E_SECURE,
34419304Speter	    "!",
34519304Speter	    "st[op][!]",
34619304Speter	    "suspend the edit session"},
34719304Speter/* C_SUSPEND */
34819304Speter	{"suspend",	ex_stop,	E_SECURE,
34919304Speter	    "!",
35019304Speter	    "su[spend][!]",
35119304Speter	    "suspend the edit session"},
35219304Speter/* C_T */
35319304Speter	{"t",		ex_copy,	E_ADDR2|E_AUTOPRINT,
35419304Speter	    "l1",
35519304Speter	    "[line [,line]] t line [flags]",
35619304Speter	    "copy lines elsewhere in the file"},
35719304Speter/* C_TAG */
35819304Speter	{"tag",		ex_tag_push,	E_NEWSCREEN,
35919304Speter	    "!w1o",
36019304Speter	    "[Tt]a[g][!] [string]",
36119304Speter	    "edit the file containing the tag"},
36219304Speter/* C_TAGNEXT */
36319304Speter	{"tagnext",	ex_tag_next,	0,
36419304Speter	    "!",
36519304Speter	    "tagn[ext][!]",
36619304Speter	    "move to the next tag"},
36719304Speter/* C_TAGPOP */
36819304Speter	{"tagpop",	ex_tag_pop,	0,
36919304Speter	    "!w1o",
37019304Speter	    "tagp[op][!] [number | file]",
37119304Speter	    "return to the previous group of tags"},
37219304Speter/* C_TAGPREV */
37319304Speter	{"tagprev",	ex_tag_prev,	0,
37419304Speter	    "!",
37519304Speter	    "tagpr[ev][!]",
37619304Speter	    "move to the previous tag"},
37719304Speter/* C_TAGTOP */
37819304Speter	{"tagtop",	ex_tag_top,	0,
37919304Speter	    "!",
38019304Speter	    "tagt[op][!]",
38119304Speter	    "discard all tags"},
38219304Speter/* C_TCLCMD */
38319304Speter	{"tcl",		ex_tcl,		E_ADDR2_ALL|E_ADDR_ZERO|
38419304Speter					    E_ADDR_ZERODEF|E_SECURE,
38519304Speter	    "s",
38619304Speter	    "tc[l] cmd",
38719304Speter	    "run the tcl interpreter with the command"},
38819304Speter/* C_UNDO */
38919304Speter	{"undo",	ex_undo,	E_AUTOPRINT,
39019304Speter	    "",
39119304Speter	    "u[ndo]",
39219304Speter	    "undo the most recent change"},
39319304Speter/* C_UNABBREVIATE */
39419304Speter	{"unabbreviate",ex_unabbr,	0,
39519304Speter	    "w1r",
39619304Speter	    "una[bbrev] word",
39719304Speter	    "delete an abbreviation"},
39819304Speter/* C_UNMAP */
39919304Speter	{"unmap",	ex_unmap,	0,
40019304Speter	    "!w1r",
40119304Speter	    "unm[ap][!] word",
40219304Speter	    "delete an input or command map"},
40319304Speter/* C_V */
40419304Speter	{"v",		ex_v,		E_ADDR2_ALL,
40519304Speter	    "s",
40619304Speter	    "[line [,line]] v [;/]RE[;/] [commands]",
40719304Speter	    "execute a global command on lines NOT matching an RE"},
40819304Speter/* C_VERSION */
40919304Speter	{"version",	ex_version,	0,
41019304Speter	    "",
41119304Speter	    "version",
41219304Speter	    "display the program version information"},
41319304Speter/* C_VISUAL_EX */
41419304Speter	{"visual",	ex_visual,	E_ADDR1|E_ADDR_ZERODEF,
41519304Speter	    "2c11",
41619304Speter	    "[line] vi[sual] [-|.|+|^] [window_size] [flags]",
41719304Speter	    "enter visual (vi) mode from ex mode"},
41819304Speter/* C_VISUAL_VI */
41919304Speter	{"visual",	ex_edit,	E_NEWSCREEN,
42019304Speter	    "f1o",
42119304Speter	    "[Vv]i[sual][!] [+cmd] [file]",
42219304Speter	    "edit another file (from vi mode only)"},
42319304Speter/* C_VIUSAGE */
42419304Speter	{"viusage",	ex_viusage,	0,
42519304Speter	    "w1o",
42619304Speter	    "[viu]sage [key]",
42719304Speter	    "display vi key usage statement"},
42819304Speter/* C_WRITE */
42919304Speter	{"write",	ex_write,	E_ADDR2_ALL|E_ADDR_ZERODEF,
43019304Speter	    "!s",
43119304Speter	    "[line [,line]] w[rite][!] [ !cmd | [>>] [file]]",
43219304Speter	    "write the file"},
43319304Speter/* C_WN */
43419304Speter	{"wn",		ex_wn,		E_ADDR2_ALL|E_ADDR_ZERODEF,
43519304Speter	    "!s",
43619304Speter	    "[line [,line]] wn[!] [>>] [file]",
43719304Speter	    "write the file and switch to the next file"},
43819304Speter/* C_WQ */
43919304Speter	{"wq",		ex_wq,		E_ADDR2_ALL|E_ADDR_ZERODEF,
44019304Speter	    "!s",
44119304Speter	    "[line [,line]] wq[!] [>>] [file]",
44219304Speter	    "write the file and exit"},
44319304Speter/* C_XIT */
44419304Speter	{"xit",		ex_xit,		E_ADDR2_ALL|E_ADDR_ZERODEF,
44519304Speter	    "!f1o",
44619304Speter	    "[line [,line]] x[it][!] [file]",
44719304Speter	    "exit"},
44819304Speter/* C_YANK */
44919304Speter	{"yank",	ex_yank,	E_ADDR2,
45019304Speter	    "bca",
45119304Speter	    "[line [,line]] ya[nk] [buffer] [count]",
45219304Speter	    "copy lines to a cut buffer"},
45319304Speter/* C_Z */
45419304Speter	{"z",		ex_z,		E_ADDR1,
45519304Speter	    "3c01",
45619304Speter	    "[line] z [-|.|+|^|=] [count] [flags]",
45719304Speter	    "display different screens of the file"},
45819304Speter/* C_SUBTILDE */
45919304Speter	{"~",		ex_subtilde,	E_ADDR2,
46019304Speter	    "s",
46119304Speter	    "[line [,line]] ~ [cgr] [count] [#lp]",
46219304Speter	    "replace previous RE with previous replacement string,"},
46319304Speter	{NULL},
46419304Speter};
465