Merge from vendor branch DIFFUTILS:
[dragonfly.git] / contrib / nvi / 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[] = "@(#)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 };