Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1069 lines
32 KiB

  1. /*
  2. *
  3. * Contains the main routine for processing characters in command mode.
  4. * Communicates closely with the code in ops.c to handle the operators.
  5. */
  6. #include "stevie.h"
  7. #include "ops.h"
  8. /*
  9. * Generally speaking, every command in normal() should either clear any
  10. * pending operator (with CLEAROP), or set the motion type variable.
  11. */
  12. #define CLEAROP (operator=NOP, namedbuff = -1) /* clear any pending operator */
  13. int operator = NOP; /* current pending operator */
  14. int mtype; /* type of the current cursor motion */
  15. bool_t mincl; /* true if char motion is inclusive */
  16. LNPTR startop; /* cursor pos. at start of operator */
  17. /*
  18. * Operators can have counts either before the operator, or between the
  19. * operator and the following cursor motion as in:
  20. *
  21. * d3w or 3dw
  22. *
  23. * If a count is given before the operator, it is saved in opnum. If
  24. * normal() is called with a pending operator, the count in opnum (if
  25. * present) overrides any count that came later.
  26. */
  27. static int opnum = 0;
  28. #define DEFAULT1(x) (((x) == 0) ? 1 : (x))
  29. void HighlightCheck();
  30. /*
  31. * normal(c)
  32. *
  33. * Execute a command in command mode.
  34. *
  35. * This is basically a big switch with the cases arranged in rough categories
  36. * in the following order:
  37. *
  38. * 1. File positioning commands
  39. * 2. Control commands (e.g. ^G, Z, screen redraw, etc)
  40. * 3. Character motions
  41. * 4. Search commands (of various kinds)
  42. * 5. Edit commands (e.g. J, x, X)
  43. * 6. Insert commands (e.g. i, o, O, A)
  44. * 7. Operators
  45. * 8. Abbreviations (e.g. D, C)
  46. * 9. Marks
  47. */
  48. void
  49. normal(c)
  50. register int c;
  51. {
  52. register int n;
  53. register char *s; /* temporary variable for misc. strings */
  54. bool_t flag = FALSE;
  55. int type = 0; /* used in some operations to modify type */
  56. int dir = FORWARD; /* search direction */
  57. int nchar = NUL;
  58. bool_t finish_op;
  59. /*
  60. * If there is an operator pending, then the command we take
  61. * this time will terminate it. Finish_op tells us to finish
  62. * the operation before returning this time (unless the operation
  63. * was cancelled.
  64. */
  65. finish_op = (operator != NOP);
  66. /*
  67. * If we're in the middle of an operator AND we had a count before
  68. * the operator, then that count overrides the current value of
  69. * Prenum. What this means effectively, is that commands like
  70. * "3dw" get turned into "d3w" which makes things fall into place
  71. * pretty neatly.
  72. */
  73. if (finish_op) {
  74. if (opnum != 0)
  75. Prenum = opnum;
  76. } else {
  77. opnum = 0;
  78. }
  79. u_lcheck(); /* clear the "line undo" buffer if we've moved */
  80. HighlightCheck();
  81. switch (c & 0xff) {
  82. /*
  83. * named buffer support
  84. */
  85. case('"'):
  86. // not allowed anywhere but at the beginning of a command
  87. if(finish_op || !isalpha(namedbuff = vgetc())) {
  88. CLEAROP;
  89. beep();
  90. } else {
  91. }
  92. break;
  93. /*
  94. * Screen positioning commands
  95. */
  96. case CTRL('D'):
  97. CLEAROP;
  98. if (Prenum)
  99. P(P_SS) = (Prenum > Rows-1) ? Rows-1 : Prenum;
  100. scrollup(P(P_SS));
  101. onedown(P(P_SS));
  102. updatescreen();
  103. break;
  104. case CTRL('U'):
  105. CLEAROP;
  106. if (Prenum)
  107. P(P_SS) = (Prenum > Rows-1) ? Rows-1 : Prenum;
  108. scrolldown(P(P_SS));
  109. oneup(P(P_SS));
  110. updatescreen();
  111. break;
  112. /*
  113. * This is kind of a hack. If we're moving by one page, the calls
  114. * to stuffin() do exactly the right thing in terms of leaving
  115. * some context, and so on. If a count was given, we don't have
  116. * to worry about these issues.
  117. */
  118. case K_PAGEDOWN:
  119. case CTRL('F'):
  120. CLEAROP;
  121. n = DEFAULT1(Prenum);
  122. if (n > 1) {
  123. if ( ! onedown(Rows * n) )
  124. beep();
  125. cursupdate();
  126. } else {
  127. screenclear();
  128. stuffin("Lz\nM");
  129. }
  130. break;
  131. case K_PAGEUP:
  132. case CTRL('B'):
  133. CLEAROP;
  134. n = DEFAULT1(Prenum);
  135. if (n > 1) {
  136. if ( ! oneup(Rows * n) )
  137. beep();
  138. cursupdate();
  139. } else {
  140. screenclear();
  141. stuffin("Hz-M");
  142. }
  143. break;
  144. case CTRL('E'):
  145. CLEAROP;
  146. scrollup(DEFAULT1(Prenum));
  147. updatescreen();
  148. break;
  149. case CTRL('Y'):
  150. CLEAROP;
  151. scrolldown(DEFAULT1(Prenum));
  152. updatescreen();
  153. break;
  154. case 'z':
  155. CLEAROP;
  156. switch (vgetc()) {
  157. case NL: /* put Curschar at top of screen */
  158. case CR:
  159. *Topchar = *Curschar;
  160. Topchar->index = 0;
  161. updatescreen();
  162. break;
  163. case '.': /* put Curschar in middle of screen */
  164. n = Rows/2;
  165. goto dozcmd;
  166. case '-': /* put Curschar at bottom of screen */
  167. n = Rows-1;
  168. /* fall through */
  169. dozcmd:
  170. {
  171. register LNPTR *lp = Curschar;
  172. register int l = 0;
  173. while ((l < n) && (lp != NULL)) {
  174. l += plines(lp);
  175. *Topchar = *lp;
  176. lp = prevline(lp);
  177. }
  178. }
  179. Topchar->index = 0;
  180. updatescreen();
  181. break;
  182. default:
  183. beep();
  184. }
  185. break;
  186. /*
  187. * Control commands
  188. */
  189. case ':':
  190. CLEAROP;
  191. if ((s = getcmdln(c)) != NULL)
  192. docmdln(s);
  193. break;
  194. case CTRL('L'):
  195. CLEAROP;
  196. screenclear();
  197. updatescreen();
  198. break;
  199. case CTRL('O'): /* ignored */
  200. /*
  201. * A command that's ignored can be useful. We use it at
  202. * times when we want to postpone redraws. By stuffing
  203. * in a control-o, redraws get suspended until the editor
  204. * gets back around to processing input.
  205. */
  206. break;
  207. case CTRL('G'):
  208. CLEAROP;
  209. fileinfo();
  210. break;
  211. case K_CGRAVE: /* shorthand command */
  212. CLEAROP;
  213. stuffin(":e #\n");
  214. break;
  215. case 'Z': /* write, if changed, and exit */
  216. if (vgetc() != 'Z') {
  217. beep();
  218. break;
  219. }
  220. doxit();
  221. break;
  222. /*
  223. * Macro evaluates true if char 'c' is a valid identifier character
  224. */
  225. # define IDCHAR(c) (isalpha(c) || isdigit(c) || (c) == '_')
  226. case CTRL(']'): /* :ta to current identifier */
  227. CLEAROP;
  228. {
  229. char ch;
  230. LNPTR save;
  231. save = *Curschar;
  232. /*
  233. * First back up to start of identifier. This
  234. * doesn't match the real vi but I like it a
  235. * little better and it shouldn't bother anyone.
  236. */
  237. ch = (char)gchar(Curschar);
  238. while (IDCHAR(ch)) {
  239. if (!oneleft())
  240. break;
  241. ch = (char)gchar(Curschar);
  242. }
  243. if (!IDCHAR(ch))
  244. oneright();
  245. stuffin(":ta ");
  246. /*
  247. * Now grab the chars in the identifier
  248. */
  249. ch = (char)gchar(Curschar);
  250. while (IDCHAR(ch)) {
  251. stuffin(mkstr(ch));
  252. if (!oneright())
  253. break;
  254. ch = (char)gchar(Curschar);
  255. }
  256. stuffin("\n");
  257. *Curschar = save; /* restore, in case of error */
  258. }
  259. break;
  260. /*
  261. * Character motion commands
  262. */
  263. case 'G':
  264. mtype = MLINE;
  265. *Curschar = *gotoline(Prenum);
  266. beginline(TRUE);
  267. break;
  268. case 'H':
  269. mtype = MLINE;
  270. *Curschar = *Topchar;
  271. for (n = Prenum; n && onedown(1) ;n--)
  272. ;
  273. beginline(TRUE);
  274. break;
  275. case 'M':
  276. mtype = MLINE;
  277. *Curschar = *Topchar;
  278. for (n = 0; n < Rows/2 && onedown(1) ;n++)
  279. ;
  280. beginline(TRUE);
  281. break;
  282. case 'L':
  283. mtype = MLINE;
  284. *Curschar = *prevline(Botchar);
  285. for (n = Prenum; n && oneup(1) ;n--)
  286. ;
  287. beginline(TRUE);
  288. break;
  289. case 'l':
  290. case K_RARROW:
  291. case ' ':
  292. mtype = MCHAR;
  293. mincl = FALSE;
  294. n = DEFAULT1(Prenum);
  295. while (n--) {
  296. if ( ! oneright() )
  297. beep();
  298. }
  299. set_want_col = TRUE;
  300. break;
  301. case 'h':
  302. case K_LARROW:
  303. case CTRL('H'):
  304. mtype = MCHAR;
  305. mincl = FALSE;
  306. n = DEFAULT1(Prenum);
  307. while (n--) {
  308. if ( ! oneleft() )
  309. beep();
  310. }
  311. set_want_col = TRUE;
  312. break;
  313. case '-':
  314. flag = TRUE;
  315. /* fall through */
  316. case 'k':
  317. case K_UARROW:
  318. case CTRL('P'):
  319. mtype = MLINE;
  320. if ( ! oneup(DEFAULT1(Prenum)) )
  321. beep();
  322. if (flag)
  323. beginline(TRUE);
  324. break;
  325. case '+':
  326. case CR:
  327. case NL:
  328. flag = TRUE;
  329. /* fall through */
  330. case 'j':
  331. case K_DARROW:
  332. case CTRL('N'):
  333. mtype = MLINE;
  334. if ( ! onedown(DEFAULT1(Prenum)) )
  335. beep();
  336. if (flag)
  337. beginline(TRUE);
  338. break;
  339. /*
  340. * This is a strange motion command that helps make operators
  341. * more logical. It is actually implemented, but not documented
  342. * in the real 'vi'. This motion command actually refers to "the
  343. * current line". Commands like "dd" and "yy" are really an alternate
  344. * form of "d_" and "y_". It does accept a count, so "d3_" works to
  345. * delete 3 lines.
  346. */
  347. case '_':
  348. lineop:
  349. mtype = MLINE;
  350. onedown(DEFAULT1(Prenum)-1);
  351. break;
  352. case '|':
  353. mtype = MCHAR;
  354. mincl = TRUE;
  355. beginline(FALSE);
  356. if (Prenum > 0)
  357. *Curschar = *coladvance(Curschar, Prenum-1);
  358. Curswant = Prenum - 1;
  359. break;
  360. /*
  361. * Word Motions
  362. */
  363. case 'B':
  364. type = 1;
  365. /* fall through */
  366. case 'b':
  367. mtype = MCHAR;
  368. mincl = FALSE;
  369. set_want_col = TRUE;
  370. for (n = DEFAULT1(Prenum); n > 0 ;n--) {
  371. LNPTR *pos;
  372. if ((pos = bck_word(Curschar, type)) == NULL) {
  373. beep();
  374. CLEAROP;
  375. break;
  376. } else
  377. *Curschar = *pos;
  378. }
  379. break;
  380. case 'W':
  381. type = 1;
  382. /* fall through */
  383. case 'w':
  384. /*
  385. * This is a little strange. To match what the real vi
  386. * does, we effectively map 'cw' to 'ce', and 'cW' to 'cE'.
  387. * This seems impolite at first, but it's really more
  388. * what we mean when we say 'cw'.
  389. */
  390. if (operator == CHANGE)
  391. goto doecmd;
  392. mtype = MCHAR;
  393. mincl = FALSE;
  394. set_want_col = TRUE;
  395. for (n = DEFAULT1(Prenum); n > 0 ;n--) {
  396. LNPTR *pos;
  397. if ((pos = fwd_word(Curschar, type)) == NULL) {
  398. beep();
  399. CLEAROP;
  400. break;
  401. } else
  402. *Curschar = *pos;
  403. }
  404. break;
  405. case 'E':
  406. type = 1;
  407. /* fall through */
  408. case 'e':
  409. doecmd:
  410. mtype = MCHAR;
  411. mincl = TRUE;
  412. set_want_col = TRUE;
  413. for (n = DEFAULT1(Prenum); n > 0 ;n--) {
  414. LNPTR *pos;
  415. /*
  416. * The first motion gets special treatment if we're
  417. * do a 'CHANGE'.
  418. */
  419. if (n == DEFAULT1(Prenum))
  420. pos = end_word(Curschar,type,operator==CHANGE);
  421. else
  422. pos = end_word(Curschar, type, FALSE);
  423. if (pos == NULL) {
  424. beep();
  425. CLEAROP;
  426. break;
  427. } else
  428. *Curschar = *pos;
  429. }
  430. break;
  431. case '$':
  432. mtype = MCHAR;
  433. mincl = TRUE;
  434. while ( oneright() )
  435. ;
  436. Curswant = 999; /* so we stay at the end */
  437. break;
  438. case '^':
  439. mtype = MCHAR;
  440. mincl = FALSE;
  441. beginline(TRUE);
  442. break;
  443. case '0':
  444. mtype = MCHAR;
  445. mincl = TRUE;
  446. beginline(FALSE);
  447. break;
  448. /*
  449. * Searches of various kinds
  450. */
  451. case '?':
  452. case '/':
  453. s = getcmdln(c); /* get the search string */
  454. /*
  455. * If they backspaced out of the search command,
  456. * just bag everything.
  457. */
  458. if (s == NULL) {
  459. CLEAROP;
  460. break;
  461. }
  462. mtype = MCHAR;
  463. mincl = FALSE;
  464. set_want_col = TRUE;
  465. /*
  466. * If no string given, pass NULL to repeat the prior search.
  467. * If the search fails, abort any pending operator.
  468. */
  469. if (!dosearch(
  470. (c == '/') ? FORWARD : BACKWARD,
  471. (*s == NUL) ? NULL : s
  472. ))
  473. CLEAROP;
  474. break;
  475. case 'n':
  476. mtype = MCHAR;
  477. mincl = FALSE;
  478. set_want_col = TRUE;
  479. if (!repsearch(0))
  480. CLEAROP;
  481. break;
  482. case 'N':
  483. mtype = MCHAR;
  484. mincl = FALSE;
  485. set_want_col = TRUE;
  486. if (!repsearch(1))
  487. CLEAROP;
  488. break;
  489. /*
  490. * Character searches
  491. */
  492. case 'T':
  493. dir = BACKWARD;
  494. /* fall through */
  495. case 't':
  496. type = 1;
  497. goto docsearch;
  498. case 'F':
  499. dir = BACKWARD;
  500. /* fall through */
  501. case 'f':
  502. docsearch:
  503. mtype = MCHAR;
  504. mincl = TRUE;
  505. set_want_col = TRUE;
  506. if ((nchar = vgetc()) == ESC) /* search char */
  507. break;
  508. for (n = DEFAULT1(Prenum); n > 0 ;n--) {
  509. if (!searchc(nchar, dir, type)) {
  510. CLEAROP;
  511. beep();
  512. }
  513. }
  514. break;
  515. case ',':
  516. flag = 1;
  517. /* fall through */
  518. case ';':
  519. mtype = MCHAR;
  520. mincl = TRUE;
  521. set_want_col = TRUE;
  522. for (n = DEFAULT1(Prenum); n > 0 ;n--) {
  523. if (!crepsearch(flag)) {
  524. CLEAROP;
  525. beep();
  526. }
  527. }
  528. break;
  529. case '[': /* function searches */
  530. dir = BACKWARD;
  531. /* fall through */
  532. case ']':
  533. mtype = MLINE;
  534. set_want_col = TRUE;
  535. if (vgetc() != c) {
  536. beep();
  537. CLEAROP;
  538. break;
  539. }
  540. if (!findfunc(dir)) {
  541. beep();
  542. CLEAROP;
  543. }
  544. break;
  545. case '%':
  546. {
  547. char initc;
  548. LNPTR *pos;
  549. LNPTR save;
  550. int done = 0;
  551. mtype = MCHAR;
  552. mincl = TRUE;
  553. save = *Curschar; /* save position in case we fail */
  554. while (!done) {
  555. initc = (char)gchar(Curschar);
  556. switch (initc) {
  557. case '(':
  558. case ')':
  559. case '{':
  560. case '}':
  561. case '[':
  562. case ']':
  563. //
  564. // Currently on a showmatch character.
  565. //
  566. done = 1;
  567. break;
  568. default:
  569. //
  570. // Didn't find anything try next character.
  571. //
  572. if (oneright() == FALSE) {
  573. //
  574. // no more on the line. Restore
  575. // location and let the showmatch()
  576. // call fail and beep the user.
  577. //
  578. *Curschar = save;
  579. done = 1;
  580. }
  581. break;
  582. }
  583. }
  584. if ((pos = showmatch()) == NULL) {
  585. beep();
  586. CLEAROP;
  587. } else {
  588. setpcmark();
  589. *Curschar = *pos;
  590. set_want_col = TRUE;
  591. }
  592. break;
  593. }
  594. /*
  595. * Edits
  596. */
  597. case '.': /* repeat last change (usually) */
  598. /*
  599. * If a delete is in effect, we let '.' help out the same
  600. * way that '_' helps for some line operations. It's like
  601. * an 'l', but subtracts one from the count and is inclusive.
  602. */
  603. if (operator == DELETE || operator == CHANGE) {
  604. if (Prenum != 0) {
  605. n = DEFAULT1(Prenum) - 1;
  606. while (n--)
  607. if (! oneright())
  608. break;
  609. }
  610. mtype = MCHAR;
  611. mincl = TRUE;
  612. } else { /* a normal 'redo' */
  613. CLEAROP;
  614. stuffin(Redobuff);
  615. }
  616. break;
  617. case 'u':
  618. CLEAROP;
  619. u_undo();
  620. break;
  621. case 'U':
  622. CLEAROP;
  623. u_lundo();
  624. break;
  625. case 'x':
  626. CLEAROP;
  627. if (lineempty()) /* can't do it on a blank line */
  628. beep();
  629. if (Prenum)
  630. stuffnum(Prenum);
  631. stuffin("d.");
  632. break;
  633. case 'X':
  634. CLEAROP;
  635. if (!oneleft())
  636. beep();
  637. else {
  638. u_saveline();
  639. if (Prenum) {
  640. int i=Prenum;
  641. sprintf(Redobuff, "%dX", i);
  642. while (--i)
  643. oneleft();
  644. stuffnum(Prenum);
  645. stuffin("d.");
  646. }
  647. else {
  648. strcpy(Redobuff, "X");
  649. delchar(TRUE);
  650. updateline();
  651. }
  652. }
  653. break;
  654. case 'r':
  655. CLEAROP;
  656. if (lineempty()) { /* Nothing to replace */
  657. beep();
  658. break;
  659. }
  660. if ((nchar = vgetc()) == ESC)
  661. break;
  662. if ((nchar & 0x80) || nchar == CR || nchar == NL) {
  663. beep();
  664. break;
  665. }
  666. u_saveline();
  667. /* Change current character. */
  668. pchar(Curschar, nchar);
  669. /* Save stuff necessary to redo it */
  670. sprintf(Redobuff, "r%c", nchar);
  671. CHANGED;
  672. updateline();
  673. break;
  674. case '~': /* swap case */
  675. if (!P(P_TO)) {
  676. CLEAROP;
  677. if (lineempty()) {
  678. beep();
  679. break;
  680. }
  681. c = gchar(Curschar);
  682. if (isalpha(c)) {
  683. if (islower(c))
  684. c = toupper(c);
  685. else
  686. c = tolower(c);
  687. }
  688. u_saveline();
  689. pchar(Curschar, c); /* Change current character. */
  690. oneright();
  691. strcpy(Redobuff, "~");
  692. CHANGED;
  693. updateline();
  694. }
  695. #ifdef TILDEOP
  696. else {
  697. if (operator == TILDE) /* handle '~~' */
  698. goto lineop;
  699. if (Prenum != 0)
  700. opnum = Prenum;
  701. startop = *Curschar;
  702. operator = TILDE;
  703. }
  704. #endif
  705. break;
  706. case 'J':
  707. CLEAROP;
  708. u_save(Curschar->linep->prev, Curschar->linep->next->next);
  709. if (!dojoin(TRUE))
  710. beep();
  711. strcpy(Redobuff, "J");
  712. updatescreen();
  713. break;
  714. /*
  715. * Inserts
  716. */
  717. case 'A':
  718. set_want_col = TRUE;
  719. while (oneright())
  720. ;
  721. /* fall through */
  722. case 'a':
  723. CLEAROP;
  724. /* Works just like an 'i'nsert on the next character. */
  725. if (!lineempty())
  726. inc(Curschar);
  727. u_saveline();
  728. startinsert(mkstr(c), FALSE);
  729. break;
  730. case 'I':
  731. beginline(TRUE);
  732. /* fall through */
  733. case 'i':
  734. case K_INSERT:
  735. CLEAROP;
  736. u_saveline();
  737. startinsert(mkstr(c), FALSE);
  738. break;
  739. case 'o':
  740. CLEAROP;
  741. u_save(Curschar->linep, Curschar->linep->next);
  742. opencmd(FORWARD, TRUE);
  743. startinsert("o", TRUE);
  744. break;
  745. case 'O':
  746. CLEAROP;
  747. u_save(Curschar->linep->prev, Curschar->linep);
  748. opencmd(BACKWARD, TRUE);
  749. startinsert("O", TRUE);
  750. break;
  751. case 'R':
  752. CLEAROP;
  753. u_saveline();
  754. startinsert("R", FALSE);
  755. break;
  756. /*
  757. * Operators
  758. */
  759. case 'd':
  760. if (operator == DELETE) /* handle 'dd' */
  761. goto lineop;
  762. if (Prenum != 0)
  763. opnum = Prenum;
  764. startop = *Curschar;
  765. operator = DELETE;
  766. break;
  767. case 'c':
  768. if (operator == CHANGE) /* handle 'cc' */
  769. goto lineop;
  770. if (Prenum != 0)
  771. opnum = Prenum;
  772. startop = *Curschar;
  773. operator = CHANGE;
  774. break;
  775. case 'y':
  776. if (operator == YANK) /* handle 'yy' */
  777. goto lineop;
  778. if (Prenum != 0)
  779. opnum = Prenum;
  780. startop = *Curschar;
  781. operator = YANK;
  782. break;
  783. case '>':
  784. if (operator == RSHIFT) /* handle >> */
  785. goto lineop;
  786. if (Prenum != 0)
  787. opnum = Prenum;
  788. startop = *Curschar;
  789. operator = RSHIFT;
  790. break;
  791. case '<':
  792. if (operator == LSHIFT) /* handle << */
  793. goto lineop;
  794. if (Prenum != 0)
  795. opnum = Prenum;
  796. startop = *Curschar; /* save current position */
  797. operator = LSHIFT;
  798. break;
  799. case '!':
  800. if (operator == FILTER) /* handle '!!' */
  801. goto lineop;
  802. if (Prenum != 0)
  803. opnum = Prenum;
  804. startop = *Curschar;
  805. operator = FILTER;
  806. break;
  807. case 'p':
  808. doput(FORWARD);
  809. break;
  810. case 'P':
  811. doput(BACKWARD);
  812. break;
  813. case 'v':
  814. if (operator == LOWERCASE) /* handle 'vv' */
  815. goto lineop;
  816. if (Prenum != 0)
  817. opnum = Prenum;
  818. startop = *Curschar;
  819. operator = LOWERCASE;
  820. break;
  821. case 'V':
  822. if (operator == UPPERCASE) /* handle 'VV' */
  823. goto lineop;
  824. if (Prenum != 0)
  825. opnum = Prenum;
  826. startop = *Curschar;
  827. operator = UPPERCASE;
  828. break;
  829. /*
  830. * Abbreviations
  831. */
  832. case 'D':
  833. stuffin("d$");
  834. break;
  835. case 'Y':
  836. if (Prenum)
  837. stuffnum(Prenum);
  838. stuffin("yy");
  839. break;
  840. case 'C':
  841. stuffin("c$");
  842. break;
  843. case 's': /* substitute characters */
  844. if (Prenum)
  845. stuffnum(Prenum);
  846. stuffin("c.");
  847. break;
  848. /*
  849. * Marks
  850. */
  851. case 'm':
  852. CLEAROP;
  853. if (!setmark(vgetc()))
  854. beep();
  855. break;
  856. case '\'':
  857. flag = TRUE;
  858. /* fall through */
  859. case '`':
  860. {
  861. LNPTR mtmp, *mark = getmark(vgetc());
  862. if (mark == NULL) {
  863. beep();
  864. CLEAROP;
  865. } else {
  866. mtmp = *mark;
  867. setpcmark();
  868. *Curschar = mtmp;
  869. if (flag)
  870. beginline(TRUE);
  871. }
  872. mtype = flag ? MLINE : MCHAR;
  873. mincl = TRUE; /* ignored if not MCHAR */
  874. set_want_col = TRUE;
  875. }
  876. break;
  877. default:
  878. CLEAROP;
  879. beep();
  880. break;
  881. }
  882. /*
  883. * If an operation is pending, handle it...
  884. */
  885. if (finish_op) { /* we just finished an operator */
  886. if (operator == NOP) /* ... but it was cancelled */
  887. return;
  888. switch (operator) {
  889. case LSHIFT:
  890. case RSHIFT:
  891. doshift(operator, c, nchar, Prenum);
  892. break;
  893. case DELETE:
  894. dodelete(c, nchar, Prenum);
  895. break;
  896. case YANK:
  897. (void) doyank(); /* no redo on yank... */
  898. break;
  899. case CHANGE:
  900. dochange(c, nchar, Prenum);
  901. break;
  902. case FILTER:
  903. dofilter(c, nchar, Prenum);
  904. break;
  905. #ifdef TILDEOP
  906. case TILDE:
  907. dotilde(c, nchar, Prenum);
  908. break;
  909. #endif
  910. case LOWERCASE:
  911. case UPPERCASE:
  912. docasechange((char)c,
  913. (char)nchar,
  914. Prenum,
  915. operator == UPPERCASE);
  916. break;
  917. default:
  918. beep();
  919. }
  920. operator = NOP;
  921. }
  922. }