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