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 }; 446