|
|
1.1 ! root 1: /* ex.c */ ! 2: ! 3: /* Author: ! 4: * Steve Kirkendall ! 5: * 14407 SW Teal Blvd. #C ! 6: * Beaverton, OR 97005 ! 7: * [email protected] ! 8: */ ! 9: ! 10: ! 11: /* This file contains the code for reading ex commands. */ ! 12: ! 13: #include "config.h" ! 14: #include "ctype.h" ! 15: #include "vi.h" ! 16: ! 17: /* This data type is used to describe the possible argument combinations */ ! 18: typedef short ARGT; ! 19: #define FROM 1 /* allow a linespec */ ! 20: #define TO 2 /* allow a second linespec */ ! 21: #define BANG 4 /* allow a ! after the command name */ ! 22: #define EXTRA 8 /* allow extra args after command name */ ! 23: #define XFILE 16 /* expand wildcards in extra part */ ! 24: #define NOSPC 32 /* no spaces allowed in the extra part */ ! 25: #define DFLALL 64 /* default file range is 1,$ */ ! 26: #define DFLNONE 128 /* no default file range */ ! 27: #define NODFL 256 /* do not default to the current file name */ ! 28: #define EXRCOK 512 /* can be in a .exrc file */ ! 29: #define NL 1024 /* if mode!=MODE_EX, then write a newline first */ ! 30: #define PLUS 2048 /* allow a line number, as in ":e +32 foo" */ ! 31: #define ZERO 4096 /* allow 0 to be given as a line number */ ! 32: #define NOBAR 8192 /* treat following '|' chars as normal */ ! 33: #define FILES (XFILE + EXTRA) /* multiple extra files allowed */ ! 34: #define WORD1 (EXTRA + NOSPC) /* one extra word allowed */ ! 35: #define FILE1 (FILES + NOSPC) /* 1 file allowed, defaults to current file */ ! 36: #define NAMEDF (FILE1 + NODFL) /* 1 file allowed, defaults to "" */ ! 37: #define NAMEDFS (FILES + NODFL) /* multiple files allowed, default is "" */ ! 38: #define RANGE (FROM + TO) /* range of linespecs allowed */ ! 39: #define NONE 0 /* no args allowed at all */ ! 40: ! 41: /* This array maps ex command names to command codes. The order in which ! 42: * command names are listed below is significant -- ambiguous abbreviations ! 43: * are always resolved to be the first possible match. (e.g. "r" is taken ! 44: * to mean "read", not "rewind", because "read" comes before "rewind") ! 45: */ ! 46: static struct ! 47: { ! 48: char *name; /* name of the command */ ! 49: CMD code; /* enum code of the command */ ! 50: void (*fn)();/* function which executes the command */ ! 51: ARGT argt; /* command line arguments permitted/needed/used */ ! 52: } ! 53: cmdnames[] = ! 54: { /* cmd name cmd code function arguments */ ! 55: {"append", CMD_APPEND, cmd_append, FROM+ZERO+BANG }, ! 56: #ifdef DEBUG ! 57: {"bug", CMD_DEBUG, cmd_debug, RANGE+BANG+EXTRA+NL}, ! 58: #endif ! 59: {"change", CMD_CHANGE, cmd_append, RANGE+BANG }, ! 60: {"delete", CMD_DELETE, cmd_delete, RANGE+WORD1 }, ! 61: {"edit", CMD_EDIT, cmd_edit, BANG+FILE1+PLUS }, ! 62: {"file", CMD_FILE, cmd_file, NAMEDF }, ! 63: {"global", CMD_GLOBAL, cmd_global, RANGE+BANG+EXTRA+DFLALL+NOBAR}, ! 64: {"insert", CMD_INSERT, cmd_append, FROM+BANG }, ! 65: {"join", CMD_INSERT, cmd_join, RANGE+BANG }, ! 66: {"k", CMD_MARK, cmd_mark, FROM+WORD1 }, ! 67: {"list", CMD_LIST, cmd_print, RANGE+NL }, ! 68: {"move", CMD_MOVE, cmd_move, RANGE+EXTRA }, ! 69: {"next", CMD_NEXT, cmd_next, BANG+NAMEDFS }, ! 70: {"Next", CMD_PREVIOUS, cmd_next, BANG }, ! 71: {"print", CMD_PRINT, cmd_print, RANGE+NL }, ! 72: {"quit", CMD_QUIT, cmd_xit, BANG }, ! 73: {"read", CMD_READ, cmd_read, FROM+ZERO+NAMEDF}, ! 74: {"substitute", CMD_SUBSTITUTE, cmd_substitute, RANGE+EXTRA }, ! 75: {"to", CMD_COPY, cmd_move, RANGE+EXTRA }, ! 76: {"undo", CMD_UNDO, cmd_undo, NONE }, ! 77: {"vglobal", CMD_VGLOBAL, cmd_global, RANGE+EXTRA+DFLALL+NOBAR}, ! 78: {"write", CMD_WRITE, cmd_write, RANGE+BANG+FILE1+DFLALL}, ! 79: {"xit", CMD_XIT, cmd_xit, BANG+NL }, ! 80: {"yank", CMD_YANK, cmd_delete, RANGE+WORD1 }, ! 81: ! 82: {"!", CMD_BANG, cmd_shell, EXRCOK+RANGE+NAMEDFS+DFLNONE+NL+NOBAR}, ! 83: {"#", CMD_NUMBER, cmd_print, RANGE+NL }, ! 84: {"<", CMD_SHIFTL, cmd_shift, RANGE }, ! 85: {">", CMD_SHIFTR, cmd_shift, RANGE }, ! 86: {"=", CMD_EQUAL, cmd_file, RANGE }, ! 87: {"&", CMD_SUBAGAIN, cmd_substitute, RANGE }, ! 88: #ifndef NO_AT ! 89: {"@", CMD_AT, cmd_at, EXTRA }, ! 90: #endif ! 91: ! 92: #ifndef NO_ABBR ! 93: {"abbreviate", CMD_ABBR, cmd_map, EXRCOK+BANG+EXTRA}, ! 94: #endif ! 95: {"args", CMD_ARGS, cmd_args, EXRCOK+NAMEDFS }, ! 96: #ifndef NO_ERRLIST ! 97: {"cc", CMD_CC, cmd_make, BANG+FILES }, ! 98: #endif ! 99: {"cd", CMD_CD, cmd_cd, EXRCOK+BANG+NAMEDF}, ! 100: {"copy", CMD_COPY, cmd_move, RANGE+EXTRA }, ! 101: #ifndef NO_DIGRAPH ! 102: {"digraph", CMD_DIGRAPH, cmd_digraph, EXRCOK+BANG+EXTRA}, ! 103: #endif ! 104: #ifndef NO_ERRLIST ! 105: {"errlist", CMD_ERRLIST, cmd_errlist, BANG+NAMEDF }, ! 106: #endif ! 107: {"ex", CMD_EDIT, cmd_edit, BANG+FILE1 }, ! 108: {"mark", CMD_MARK, cmd_mark, FROM+WORD1 }, ! 109: #ifndef NO_MKEXRC ! 110: {"mkexrc", CMD_MKEXRC, cmd_mkexrc, NAMEDF }, ! 111: #endif ! 112: {"number", CMD_NUMBER, cmd_print, RANGE+NL }, ! 113: {"put", CMD_PUT, cmd_put, FROM+ZERO+WORD1 }, ! 114: {"set", CMD_SET, cmd_set, EXRCOK+EXTRA }, ! 115: {"shell", CMD_SHELL, cmd_shell, NL }, ! 116: {"source", CMD_SOURCE, cmd_source, EXRCOK+NAMEDF }, ! 117: #ifdef SIGTSTP ! 118: {"stop", CMD_STOP, cmd_suspend, NONE }, ! 119: #endif ! 120: {"tag", CMD_TAG, cmd_tag, BANG+WORD1 }, ! 121: {"version", CMD_VERSION, cmd_version, EXRCOK+NONE }, ! 122: {"visual", CMD_VISUAL, cmd_edit, BANG+NAMEDF }, ! 123: {"wq", CMD_WQUIT, cmd_xit, NL }, ! 124: ! 125: #ifdef DEBUG ! 126: {"debug", CMD_DEBUG, cmd_debug, RANGE+BANG+EXTRA+NL}, ! 127: {"validate", CMD_VALIDATE, cmd_validate, BANG+NL }, ! 128: #endif ! 129: {"chdir", CMD_CD, cmd_cd, EXRCOK+BANG+NAMEDF}, ! 130: #ifndef NO_COLOR ! 131: {"color", CMD_COLOR, cmd_color, EXRCOK+EXTRA }, ! 132: #endif ! 133: #ifndef NO_ERRLIST ! 134: {"make", CMD_MAKE, cmd_make, BANG+NAMEDFS }, ! 135: #endif ! 136: {"map", CMD_MAP, cmd_map, EXRCOK+BANG+EXTRA}, ! 137: {"previous", CMD_PREVIOUS, cmd_next, BANG }, ! 138: {"rewind", CMD_REWIND, cmd_next, BANG }, ! 139: #ifdef SIGTSTP ! 140: {"suspend", CMD_SUSPEND, cmd_suspend, NONE }, ! 141: #endif ! 142: {"unmap", CMD_UNMAP, cmd_map, EXRCOK+BANG+EXTRA}, ! 143: #ifndef NO_ABBR ! 144: {"unabbreviate",CMD_UNABBR, cmd_map, EXRCOK+WORD1 }, ! 145: #endif ! 146: ! 147: {(char *)0} ! 148: }; ! 149: ! 150: ! 151: /* This function parses a search pattern - given a pointer to a / or ?, ! 152: * it replaces the ending / or ? with a \0, and returns a pointer to the ! 153: * stuff that came after the pattern. ! 154: */ ! 155: char *parseptrn(ptrn) ! 156: REG char *ptrn; ! 157: { ! 158: REG char *scan; ! 159: ! 160: for (scan = ptrn + 1; ! 161: *scan && *scan != *ptrn; ! 162: scan++) ! 163: { ! 164: /* allow backslashed versions of / and ? in the pattern */ ! 165: if (*scan == '\\' && scan[1] != '\0') ! 166: { ! 167: scan++; ! 168: } ! 169: } ! 170: if (*scan) ! 171: { ! 172: *scan++ = '\0'; ! 173: } ! 174: ! 175: return scan; ! 176: } ! 177: ! 178: ! 179: /* This function parses a line specifier for ex commands */ ! 180: char *linespec(s, markptr) ! 181: REG char *s; /* start of the line specifier */ ! 182: MARK *markptr; /* where to store the mark's value */ ! 183: { ! 184: long num; ! 185: REG char *t; ! 186: ! 187: /* parse each ;-delimited clause of this linespec */ ! 188: do ! 189: { ! 190: /* skip an initial ';', if any */ ! 191: if (*s == ';') ! 192: { ! 193: s++; ! 194: } ! 195: ! 196: /* skip leading spaces */ ! 197: while (isspace(*s)) ! 198: { ! 199: s++; ! 200: } ! 201: ! 202: /* dot means current position */ ! 203: if (*s == '.') ! 204: { ! 205: s++; ! 206: *markptr = cursor; ! 207: } ! 208: /* '$' means the last line */ ! 209: else if (*s == '$') ! 210: { ! 211: s++; ! 212: *markptr = MARK_LAST; ! 213: } ! 214: /* digit means an absolute line number */ ! 215: else if (isdigit(*s)) ! 216: { ! 217: for (num = 0; isdigit(*s); s++) ! 218: { ! 219: num = num * 10 + *s - '0'; ! 220: } ! 221: *markptr = MARK_AT_LINE(num); ! 222: } ! 223: /* appostrophe means go to a set mark */ ! 224: else if (*s == '\'') ! 225: { ! 226: s++; ! 227: *markptr = m_tomark(cursor, 1L, (int)*s); ! 228: s++; ! 229: } ! 230: /* slash means do a search */ ! 231: else if (*s == '/' || *s == '?') ! 232: { ! 233: /* put a '\0' at the end of the search pattern */ ! 234: t = parseptrn(s); ! 235: ! 236: /* search for the pattern */ ! 237: *markptr &= ~(BLKSIZE - 1); ! 238: if (*s == '/') ! 239: { ! 240: pfetch(markline(*markptr)); ! 241: if (plen > 0) ! 242: *markptr += plen - 1; ! 243: *markptr = m_fsrch(*markptr, s); ! 244: } ! 245: else ! 246: { ! 247: *markptr = m_bsrch(*markptr, s); ! 248: } ! 249: ! 250: /* adjust command string pointer */ ! 251: s = t; ! 252: } ! 253: ! 254: /* if linespec was faulty, quit now */ ! 255: if (!*markptr) ! 256: { ! 257: return s; ! 258: } ! 259: ! 260: /* maybe add an offset */ ! 261: t = s; ! 262: if (*t == '-' || *t == '+') ! 263: { ! 264: s++; ! 265: for (num = 0; isdigit(*s); s++) ! 266: { ! 267: num = num * 10 + *s - '0'; ! 268: } ! 269: if (num == 0) ! 270: { ! 271: num = 1; ! 272: } ! 273: *markptr = m_updnto(*markptr, num, *t); ! 274: } ! 275: } while (*s == ';' || *s == '+' || *s == '-'); ! 276: ! 277: /* protect against invalid line numbers */ ! 278: num = markline(*markptr); ! 279: if (num < 1L || num > nlines) ! 280: { ! 281: msg("Invalid line number -- must be from 1 to %ld", nlines); ! 282: *markptr = MARK_UNSET; ! 283: } ! 284: ! 285: return s; ! 286: } ! 287: ! 288: ! 289: ! 290: /* This function reads an ex command and executes it. */ ! 291: void ex() ! 292: { ! 293: char cmdbuf[150]; ! 294: REG int cmdlen; ! 295: static long oldline; ! 296: ! 297: significant = FALSE; ! 298: oldline = markline(cursor); ! 299: ! 300: while (mode == MODE_EX) ! 301: { ! 302: /* read a line */ ! 303: #ifdef CRUNCH ! 304: cmdlen = vgets(':', cmdbuf, sizeof(cmdbuf)); ! 305: #else ! 306: cmdlen = vgets(*o_prompt ? ':' : '\0', cmdbuf, sizeof(cmdbuf)); ! 307: #endif ! 308: if (cmdlen < 0) ! 309: { ! 310: return; ! 311: } ! 312: ! 313: /* if empty line, assume ".+1" */ ! 314: if (cmdlen == 0) ! 315: { ! 316: strcpy(cmdbuf, ".+1"); ! 317: qaddch('\r'); ! 318: clrtoeol(); ! 319: } ! 320: else ! 321: { ! 322: addch('\n'); ! 323: } ! 324: refresh(); ! 325: ! 326: /* parse & execute the command */ ! 327: doexcmd(cmdbuf); ! 328: ! 329: /* handle autoprint */ ! 330: if (significant || markline(cursor) != oldline) ! 331: { ! 332: significant = FALSE; ! 333: oldline = markline(cursor); ! 334: if (*o_autoprint && mode == MODE_EX) ! 335: { ! 336: cmd_print(cursor, cursor, CMD_PRINT, FALSE, ""); ! 337: } ! 338: } ! 339: } ! 340: } ! 341: ! 342: void doexcmd(cmdbuf) ! 343: char *cmdbuf; /* string containing an ex command */ ! 344: { ! 345: REG char *scan; /* used to scan thru cmdbuf */ ! 346: MARK frommark; /* first linespec */ ! 347: MARK tomark; /* second linespec */ ! 348: REG int cmdlen; /* length of the command name given */ ! 349: CMD cmd; /* what command is this? */ ! 350: ARGT argt; /* argument types for this command */ ! 351: short forceit; /* bang version of a command? */ ! 352: REG int cmdidx; /* index of command */ ! 353: REG char *build; /* used while copying filenames */ ! 354: int iswild; /* boolean: filenames use wildcards? */ ! 355: int isdfl; /* using default line ranges? */ ! 356: int didsub; /* did we substitute file names for % or # */ ! 357: ! 358: /* ex commands can't be undone via the shift-U command */ ! 359: U_line = 0L; ! 360: ! 361: /* permit extra colons at the start of the line */ ! 362: for (; *cmdbuf == ':'; cmdbuf++) ! 363: { ! 364: } ! 365: ! 366: /* ignore command lines that start with a double-quote */ ! 367: if (*cmdbuf == '"') ! 368: { ! 369: return; ! 370: } ! 371: scan = cmdbuf; ! 372: ! 373: /* parse the line specifier */ ! 374: if (nlines < 1) ! 375: { ! 376: /* no file, so don't allow addresses */ ! 377: } ! 378: else if (*scan == '%') ! 379: { ! 380: /* '%' means all lines */ ! 381: frommark = MARK_FIRST; ! 382: tomark = MARK_LAST; ! 383: scan++; ! 384: } ! 385: else if (*scan == '0') ! 386: { ! 387: scan++; ! 388: frommark = tomark = (*scan ? MARK_UNSET : MARK_FIRST); ! 389: } ! 390: else ! 391: { ! 392: frommark = cursor; ! 393: scan = linespec(scan, &frommark); ! 394: tomark = frommark; ! 395: if (frommark && *scan == ',') ! 396: { ! 397: scan++; ! 398: scan = linespec(scan, &tomark); ! 399: } ! 400: if (!tomark) ! 401: { ! 402: /* faulty line spec -- fault already described */ ! 403: return; ! 404: } ! 405: if (frommark > tomark) ! 406: { ! 407: msg("first address exceeds the second"); ! 408: return; ! 409: } ! 410: } ! 411: isdfl = (scan == cmdbuf); ! 412: ! 413: /* skip whitespace */ ! 414: while (isspace(*scan)) ! 415: { ! 416: scan++; ! 417: } ! 418: ! 419: /* if no command, then just move the cursor to the mark */ ! 420: if (!*scan) ! 421: { ! 422: if (tomark != MARK_UNSET) ! 423: cursor = tomark; ! 424: return; ! 425: } ! 426: ! 427: /* figure out how long the command name is */ ! 428: if (!isalpha(*scan)) ! 429: { ! 430: cmdlen = 1; ! 431: } ! 432: else ! 433: { ! 434: for (cmdlen = 1; ! 435: isalpha(scan[cmdlen]); ! 436: cmdlen++) ! 437: { ! 438: } ! 439: } ! 440: ! 441: /* lookup the command code */ ! 442: for (cmdidx = 0; ! 443: cmdnames[cmdidx].name && strncmp(scan, cmdnames[cmdidx].name, cmdlen); ! 444: cmdidx++) ! 445: { ! 446: } ! 447: argt = cmdnames[cmdidx].argt; ! 448: cmd = cmdnames[cmdidx].code; ! 449: if (cmd == CMD_NULL) ! 450: { ! 451: msg("Unknown command \"%.*s\"", cmdlen, scan); ! 452: return; ! 453: } ! 454: ! 455: /* !!! if the command doesn't have NOBAR set, then replace | with \0 */ ! 456: ! 457: /* if the command ended with a bang, set the forceit flag */ ! 458: scan += cmdlen; ! 459: if ((argt & BANG) && *scan == '!') ! 460: { ! 461: scan++; ! 462: forceit = 1; ! 463: } ! 464: else ! 465: { ! 466: forceit = 0; ! 467: } ! 468: ! 469: /* skip any more whitespace, to leave scan pointing to arguments */ ! 470: while (isspace(*scan)) ! 471: { ! 472: scan++; ! 473: } ! 474: ! 475: /* a couple of special cases for filenames */ ! 476: if (argt & XFILE) ! 477: { ! 478: /* if names were given, process them */ ! 479: if (*scan) ! 480: { ! 481: for (build = tmpblk.c, iswild = didsub = FALSE; *scan; scan++) ! 482: { ! 483: switch (*scan) ! 484: { ! 485: case '\\': ! 486: if (scan[1] == '\\' || scan[1] == '%' || scan[1] == '#') ! 487: { ! 488: *build++ = *++scan; ! 489: } ! 490: else ! 491: { ! 492: *build++ = '\\'; ! 493: } ! 494: break; ! 495: ! 496: case '%': ! 497: if (!*origname) ! 498: { ! 499: msg("No filename to substitute for %%"); ! 500: return; ! 501: } ! 502: strcpy(build, origname); ! 503: while (*build) ! 504: { ! 505: build++; ! 506: } ! 507: didsub = TRUE; ! 508: break; ! 509: ! 510: case '#': ! 511: if (!*prevorig) ! 512: { ! 513: msg("No filename to substitute for #"); ! 514: return; ! 515: } ! 516: strcpy(build, prevorig); ! 517: while (*build) ! 518: { ! 519: build++; ! 520: } ! 521: didsub = TRUE; ! 522: break; ! 523: ! 524: case '*': ! 525: case '?': ! 526: #if !(MSDOS || TOS) ! 527: case '[': ! 528: case '`': ! 529: case '{': /* } */ ! 530: case '$': ! 531: case '~': ! 532: #endif ! 533: *build++ = *scan; ! 534: iswild = TRUE; ! 535: break; ! 536: ! 537: default: ! 538: *build++ = *scan; ! 539: } ! 540: } ! 541: *build = '\0'; ! 542: ! 543: if (cmd == CMD_BANG ! 544: || cmd == CMD_READ && tmpblk.c[0] == '!' ! 545: || cmd == CMD_WRITE && tmpblk.c[0] == '!') ! 546: { ! 547: if (didsub) ! 548: { ! 549: if (mode != MODE_EX) ! 550: { ! 551: addch('\n'); ! 552: } ! 553: addstr(tmpblk.c); ! 554: addch('\n'); ! 555: exrefresh(); ! 556: } ! 557: } ! 558: else ! 559: { ! 560: if (iswild && tmpblk.c[0] != '>') ! 561: { ! 562: scan = wildcard(tmpblk.c); ! 563: } ! 564: } ! 565: } ! 566: else /* no names given, maybe assume origname */ ! 567: { ! 568: if (!(argt & NODFL)) ! 569: { ! 570: strcpy(tmpblk.c, origname); ! 571: } ! 572: else ! 573: { ! 574: *tmpblk.c = '\0'; ! 575: } ! 576: } ! 577: ! 578: scan = tmpblk.c; ! 579: } ! 580: ! 581: /* bad arguments? */ ! 582: if (!(argt & EXRCOK) && nlines < 1L) ! 583: { ! 584: msg("Can't use the \"%s\" command in a %s file", cmdnames[cmdidx].name, EXRC); ! 585: return; ! 586: } ! 587: if (!(argt & (ZERO | EXRCOK)) && frommark == MARK_UNSET) ! 588: { ! 589: msg("Can't use address 0 with \"%s\" command.", cmdnames[cmdidx].name); ! 590: return; ! 591: } ! 592: if (!(argt & FROM) && frommark != cursor && nlines >= 1L) ! 593: { ! 594: msg("Can't use address with \"%s\" command.", cmdnames[cmdidx].name); ! 595: return; ! 596: } ! 597: if (!(argt & TO) && tomark != frommark && nlines >= 1L) ! 598: { ! 599: msg("Can't use a range with \"%s\" command.", cmdnames[cmdidx].name); ! 600: return; ! 601: } ! 602: if (!(argt & EXTRA) && *scan) ! 603: { ! 604: msg("Extra characters after \"%s\" command.", cmdnames[cmdidx].name); ! 605: return; ! 606: } ! 607: if ((argt & NOSPC) && !(cmd == CMD_READ && (forceit || *scan == '!'))) ! 608: { ! 609: build = scan; ! 610: #ifndef CRUNCH ! 611: if ((argt & PLUS) && *build == '+') ! 612: { ! 613: while (*build && !isspace(*build)) ! 614: { ! 615: build++; ! 616: } ! 617: while (*build && isspace(*build)) ! 618: { ! 619: build++; ! 620: } ! 621: } ! 622: #endif /* not CRUNCH */ ! 623: for (; *build; build++) ! 624: { ! 625: if (isspace(*build)) ! 626: { ! 627: msg("Too many %s to \"%s\" command.", ! 628: (argt & XFILE) ? "filenames" : "arguments", ! 629: cmdnames[cmdidx].name); ! 630: return; ! 631: } ! 632: } ! 633: } ! 634: ! 635: /* some commands have special default ranges */ ! 636: if (isdfl && (argt & DFLALL)) ! 637: { ! 638: frommark = MARK_FIRST; ! 639: tomark = MARK_LAST; ! 640: } ! 641: else if (isdfl && (argt & DFLNONE)) ! 642: { ! 643: frommark = tomark = 0L; ! 644: } ! 645: ! 646: /* write a newline if called from visual mode */ ! 647: if ((argt & NL) && mode != MODE_EX && !exwrote) ! 648: { ! 649: addch('\n'); ! 650: exrefresh(); ! 651: } ! 652: ! 653: /* act on the command */ ! 654: (*cmdnames[cmdidx].fn)(frommark, tomark, cmd, forceit, scan); ! 655: } ! 656: ! 657: ! 658: /* This function executes EX commands from a file. It returns 1 normally, or ! 659: * 0 if the file could not be opened for reading. ! 660: */ ! 661: int doexrc(filename) ! 662: char *filename; /* name of a ".exrc" file */ ! 663: { ! 664: int fd; /* file descriptor */ ! 665: int len; /* length of the ".exrc" file */ ! 666: ! 667: #ifdef CRUNCH ! 668: /* small address space - we need to conserve space */ ! 669: ! 670: /* !!! kludge: we use U_text as the buffer. This has the side-effect ! 671: * of interfering with the shift-U visual command. Disable shift-U. ! 672: */ ! 673: U_line = 0L; ! 674: #else ! 675: # if TINYSTACK ! 676: /* small stack - we need to conserve space */ ! 677: ! 678: /* !!! kludge: we use U_text as the buffer. This has the side-effect ! 679: * of interfering with the shift-U visual command. Disable shift-U. ! 680: */ ! 681: U_line = 0L; ! 682: # else ! 683: /* This is how we would *like* to do it -- with a large buffer on the ! 684: * stack, so we can handle large .exrc files and also recursion. ! 685: */ ! 686: char U_text[4096]; ! 687: # endif ! 688: #endif ! 689: ! 690: /* open the file, read it, and close */ ! 691: fd = open(filename, O_RDONLY); ! 692: if (fd < 0) ! 693: { ! 694: return 0; ! 695: } ! 696: len = tread(fd, U_text, sizeof U_text); ! 697: close(fd); ! 698: ! 699: /* execute the string */ ! 700: exstring(U_text, len, ctrl('V')); ! 701: ! 702: return 1; ! 703: } ! 704: ! 705: /* This function executes EX commands from a string. The commands may be ! 706: * separated by newlines or by | characters. It also handles quoting. ! 707: * Each individual command is limited to 132 bytes, but the total string ! 708: * may be longer. ! 709: */ ! 710: void exstring(buf, len, qchar) ! 711: char *buf; /* the commands to execute */ ! 712: int len; /* the length of the string */ ! 713: int qchar; /* the quote character -- ^V for file, or \ for kbd */ ! 714: { ! 715: char single[133]; /* a single command */ ! 716: char *src, *dest; ! 717: int i; ! 718: ! 719: /* find & do each command */ ! 720: for (src = buf; src < &buf[len]; src++) ! 721: { ! 722: /* Copy a single command into single[]. Convert any quoted | ! 723: * into a normal |, and stop at a newline or unquoted |. ! 724: */ ! 725: for (dest = single, i = 0; ! 726: i < 132 && src < &buf[len] && *src != '\n' && *src != '|'; ! 727: src++, i++) ! 728: { ! 729: if (src[0] == qchar && src[1] == '|') ! 730: { ! 731: src++; ! 732: } ! 733: *dest++ = *src; ! 734: } ! 735: *dest = '\0'; ! 736: ! 737: /* do it */ ! 738: doexcmd(single); ! 739: } ! 740: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.