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