Import nvi2 version 2.1.3 to vendor branch
[dragonfly.git] / contrib / nvi2 / ex / ex_cmd.c
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 };