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