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.

897 lines
26 KiB

  1. /* $Header: /nw/tony/src/stevie/src/RCS/cmdline.c,v 1.20 89/08/13 11:41:23 tony Exp $
  2. *
  3. * Routines to parse and execute "command line" commands, such as searches
  4. * or colon commands.
  5. */
  6. #include "stevie.h"
  7. static char *altfile = NULL; /* alternate file */
  8. static int altline; /* line # in alternate file */
  9. static char *nowrtmsg = "No write since last change (use ! to override)";
  10. static char *nooutfile = "No output file";
  11. static char *morefiles = "more files to edit";
  12. extern char **files; /* used for "n" and "rew" */
  13. extern int numfiles, curfile;
  14. #define CMDSZ 100 /* size of the command buffer */
  15. bool_t rangeerr;
  16. static bool_t doecmd(char*arg, bool_t force);
  17. static void badcmd(void);
  18. static void get_range(char**cp, LNPTR*lower, LNPTR*upper);
  19. static LNPTR *get_line(char**cp);
  20. void ex_delete(LINE *l,LINE *u);
  21. void dolist(LINE *l,LINE *u);
  22. extern char *lastcmd; /* in dofilter */
  23. /*
  24. * getcmdln() - read a command line from the terminal
  25. *
  26. * Reads a command line started by typing '/', '?', '!', or ':'. Returns a
  27. * pointer to the string that was read. For searches, an optional trailing
  28. * '/' or '?' is removed.
  29. */
  30. char *
  31. getcmdln(firstc)
  32. char firstc;
  33. {
  34. static char buff[CMDSZ];
  35. register char *p = buff;
  36. register int c;
  37. register char *q;
  38. gotocmd(TRUE, firstc);
  39. /* collect the command string, handling '\b' and @ */
  40. do {
  41. switch (c = vgetc()) {
  42. default: /* a normal character */
  43. outchar(c);
  44. *p++ = (char)c;
  45. break;
  46. case BS:
  47. if (p > buff) {
  48. /*
  49. * this is gross, but it relies
  50. * only on 'gotocmd'
  51. */
  52. p--;
  53. gotocmd(TRUE, firstc);
  54. for (q = buff; q < p ;q++)
  55. outchar(*q);
  56. } else {
  57. msg("");
  58. return NULL; /* back to cmd mode */
  59. }
  60. break;
  61. #if 0
  62. case '@': /* line kill */
  63. p = buff;
  64. gotocmd(TRUE, firstc);
  65. break;
  66. #endif
  67. case NL: /* done reading the line */
  68. case CR:
  69. break;
  70. }
  71. } while (c != NL && c != CR);
  72. *p = '\0';
  73. if (firstc == '/' || firstc == '?') { /* did we do a search? */
  74. /*
  75. * Look for a terminating '/' or '?'. This will be the first
  76. * one that isn't quoted. Truncate the search string there.
  77. */
  78. for (p = buff; *p ;) {
  79. if (*p == firstc) { /* we're done */
  80. *p = '\0';
  81. break;
  82. } else if (*p == '\\') /* next char quoted */
  83. p += 2;
  84. else
  85. p++; /* normal char */
  86. }
  87. }
  88. return buff;
  89. }
  90. /*
  91. * docmdln() - handle a colon command
  92. *
  93. * Handles a colon command received interactively by getcmdln() or from
  94. * the environment variable "EXINIT" (or eventually .virc).
  95. */
  96. void
  97. docmdln(cmdline)
  98. char *cmdline;
  99. {
  100. char buff[CMDSZ];
  101. char cmdbuf[CMDSZ];
  102. char argbuf[CMDSZ];
  103. char *cmd, *arg;
  104. register char *p;
  105. /*
  106. * The next two variables contain the bounds of any range given in a
  107. * command. If no range was given, both contain null line pointers.
  108. * If only a single line was given, u_pos will contain a null line
  109. * pointer.
  110. */
  111. LNPTR l_pos, u_pos;
  112. /*
  113. * Clear the range variables.
  114. */
  115. l_pos.linep = (struct line *) NULL;
  116. u_pos.linep = (struct line *) NULL;
  117. if (cmdline == NULL)
  118. return;
  119. if (strlen(cmdline) > CMDSZ-2) {
  120. msg("Error: command line too long");
  121. return;
  122. }
  123. strcpy(buff, cmdline);
  124. /* skip any initial white space */
  125. for (cmd = buff; *cmd != NUL && isspace(*cmd) ;cmd++)
  126. ;
  127. if (*cmd == '%') { /* change '%' to "1,$" */
  128. strcpy(cmdbuf, "1,$"); /* kind of gross... */
  129. strcat(cmdbuf, cmd+1);
  130. strcpy(cmd, cmdbuf);
  131. }
  132. while ((p=strchr(cmd, '%')) != NULL && *(p-1) != '\\') {
  133. /* change '%' to Filename */
  134. if (Filename == NULL) {
  135. emsg("No filename");
  136. return;
  137. }
  138. *p= NUL;
  139. strcpy (cmdbuf, cmd);
  140. strcat (cmdbuf, Filename);
  141. strcat (cmdbuf, p+1);
  142. strcpy(cmd, cmdbuf);
  143. msg(cmd); /*repeat */
  144. }
  145. while ((p=strchr(cmd, '#')) != NULL && *(p-1) != '\\') {
  146. /* change '#' to Altname */
  147. if (altfile == NULL) {
  148. emsg("No alternate file");
  149. return;
  150. }
  151. *p= NUL;
  152. strcpy (cmdbuf, cmd);
  153. strcat (cmdbuf, altfile);
  154. strcat (cmdbuf, p+1);
  155. strcpy(cmd, cmdbuf);
  156. msg(cmd); /*repeat */
  157. }
  158. /*
  159. * Parse a range, if present (and update the cmd pointer).
  160. */
  161. rangeerr = FALSE;
  162. get_range(&cmd, &l_pos, &u_pos);
  163. if(rangeerr) {
  164. return;
  165. }
  166. if (l_pos.linep != NULL) {
  167. if (LINEOF(&l_pos) > LINEOF(&u_pos)) {
  168. emsg("Invalid range");
  169. return;
  170. }
  171. }
  172. strcpy(cmdbuf, cmd); /* save the unmodified command */
  173. /* isolate the command and find any argument */
  174. for ( p=cmd; *p != NUL && ! isspace(*p); p++ )
  175. ;
  176. if ( *p == NUL )
  177. arg = NULL;
  178. else {
  179. *p = NUL;
  180. for (p++; *p != NUL && isspace(*p) ;p++)
  181. ;
  182. if (*p == NUL)
  183. arg = NULL;
  184. else {
  185. strcpy(argbuf, p);
  186. arg = argbuf;
  187. }
  188. }
  189. if (strcmp(cmd,"q!") == 0)
  190. getout();
  191. if (strcmp(cmd,"q") == 0) {
  192. if (Changed)
  193. emsg(nowrtmsg);
  194. else {
  195. if ((curfile + 1) < numfiles)
  196. emsg(morefiles);
  197. else
  198. getout();
  199. }
  200. return;
  201. }
  202. if ((strcmp(cmd,"w") == 0) ||
  203. (strcmp(cmd,"w!") == 0)) {
  204. if (arg == NULL) {
  205. if (Filename != NULL) {
  206. writeit(Filename, &l_pos, &u_pos);
  207. } else
  208. emsg(nooutfile);
  209. }
  210. else {
  211. if (altfile)
  212. free(altfile);
  213. altfile = strsave(arg);
  214. writeit(arg, &l_pos, &u_pos);
  215. }
  216. return;
  217. }
  218. if (strcmp(cmd,"wq") == 0) {
  219. if (Filename != NULL) {
  220. if (writeit(Filename, (LNPTR *)NULL, (LNPTR *)NULL))
  221. getout();
  222. } else
  223. emsg(nooutfile);
  224. return;
  225. }
  226. if (strcmp(cmd, "x") == 0) {
  227. doxit();
  228. return;
  229. }
  230. if (strcmp(cmd,"f") == 0 && arg == NULL) {
  231. fileinfo();
  232. return;
  233. }
  234. if (*cmd == 'n') {
  235. if ((curfile + 1) < numfiles) {
  236. /*
  237. * stuff ":e[!] FILE\n"
  238. */
  239. stuffin(":e");
  240. if (cmd[1] == '!')
  241. stuffin("!");
  242. stuffin(" ");
  243. stuffin(files[++curfile]);
  244. stuffin("\n");
  245. } else
  246. emsg("No more files!");
  247. return;
  248. }
  249. if (*cmd == 'N') {
  250. if (curfile > 0) {
  251. /*
  252. * stuff ":e[!] FILE\n"
  253. */
  254. stuffin(":e");
  255. if (cmd[1] == '!')
  256. stuffin("!");
  257. stuffin(" ");
  258. stuffin(files[--curfile]);
  259. stuffin("\n");
  260. } else
  261. emsg("No more files!");
  262. return;
  263. }
  264. if(*cmd == 'l' || !strncmp(cmd,"li",2)) {
  265. if(arg != NULL) {
  266. msg("extra characters at end of \"list\" command");
  267. } else {
  268. dolist(l_pos.linep,u_pos.linep);
  269. }
  270. return;
  271. }
  272. if (strncmp(cmd, "rew", 3) == 0) {
  273. if (numfiles <= 1) /* nothing to rewind */
  274. return;
  275. curfile = 0;
  276. /*
  277. * stuff ":e[!] FILE\n"
  278. */
  279. stuffin(":e");
  280. if (cmd[3] == '!')
  281. stuffin("!");
  282. stuffin(" ");
  283. stuffin(files[0]);
  284. stuffin("\n");
  285. return;
  286. }
  287. if (strcmp(cmd,"e") == 0 || strcmp(cmd,"e!") == 0) {
  288. (void) doecmd(arg, cmd[1] == '!');
  289. return;
  290. }
  291. /*
  292. * The command ":e#" gets expanded to something like ":efile", so
  293. * detect that case here.
  294. */
  295. if (*cmd == 'e' && arg == NULL) {
  296. if (cmd[1] == '!')
  297. (void) doecmd(&cmd[2], TRUE);
  298. else
  299. (void) doecmd(&cmd[1], FALSE);
  300. return;
  301. }
  302. if (strcmp(cmd,"f") == 0) {
  303. Filename = strsave(arg);
  304. setviconsoletitle();
  305. filemess("");
  306. return;
  307. }
  308. if (strcmp(cmd,"r") == 0) {
  309. if (arg == NULL) {
  310. badcmd();
  311. return;
  312. }
  313. if (readfile(arg, Curschar, 1)) {
  314. emsg("Can't open file");
  315. return;
  316. }
  317. updatescreen();
  318. CHANGED;
  319. return;
  320. }
  321. if (*cmd == 'd') {
  322. if(arg != NULL) {
  323. msg("extra characters at end of \"delete\" command");
  324. } else {
  325. ex_delete(l_pos.linep,u_pos.linep);
  326. }
  327. return;
  328. }
  329. if (strcmp(cmd,"=") == 0) {
  330. smsg("%d", cntllines(Filemem, &l_pos));
  331. return;
  332. }
  333. if (strncmp(cmd,"ta", 2) == 0) {
  334. dotag(arg, cmd[2] == '!');
  335. return;
  336. }
  337. if (strncmp(cmd,"set", 2) == 0) {
  338. doset(arg);
  339. return;
  340. }
  341. if (strcmp(cmd,"help") == 0) {
  342. if (help()) {
  343. screenclear();
  344. updatescreen();
  345. }
  346. return;
  347. }
  348. if (strncmp(cmd, "ve", 2) == 0) {
  349. extern char *Version;
  350. msg(Version);
  351. return;
  352. }
  353. if (strcmp(cmd, "sh") == 0) {
  354. doshell(NULL, FALSE);
  355. return;
  356. }
  357. if (strcmp(cmd, "source") == 0 ||
  358. strcmp(cmd, "so") == 0) {
  359. if(l_pos.linep != NULL) {
  360. emsg("No range allowed on this command");
  361. } else {
  362. dosource(arg,TRUE);
  363. }
  364. return;
  365. }
  366. if (*cmd == '!' || *cmd == '@') {
  367. if (*(cmd+1) == *cmd) {
  368. if (lastcmd == (char*)NULL) {
  369. emsg("No previous command");
  370. return;
  371. }
  372. msg(lastcmd);
  373. doshell(lastcmd, *cmd == '@');
  374. }
  375. else {
  376. doshell(cmdbuf+1, *cmd == '@');
  377. if (lastcmd == (char*)NULL)
  378. lastcmd = (char*)alloc(CMDSZ);
  379. strcpy(lastcmd, cmdbuf+1);
  380. }
  381. return;
  382. }
  383. if (strncmp(cmd, "s/", 2) == 0) {
  384. dosub(&l_pos, &u_pos, cmdbuf+1);
  385. return;
  386. }
  387. if (strncmp(cmd, "g/", 2) == 0) {
  388. doglob(&l_pos, &u_pos, cmdbuf+1);
  389. return;
  390. }
  391. if (strcmp(cmd, "cd") == 0) {
  392. dochdir(arg);
  393. return;
  394. }
  395. /*
  396. * If we got a line, but no command, then go to the line.
  397. */
  398. if (*cmd == NUL && l_pos.linep != NULL) {
  399. *Curschar = l_pos;
  400. return;
  401. }
  402. badcmd();
  403. }
  404. void doxit()
  405. {
  406. if (Changed) {
  407. if (Filename != NULL) {
  408. if (!writeit(Filename, (LNPTR *)NULL, (LNPTR *)NULL))
  409. return;
  410. } else {
  411. emsg(nooutfile);
  412. return;
  413. }
  414. }
  415. if ((curfile + 1) < numfiles)
  416. emsg(morefiles);
  417. else
  418. getout();
  419. }
  420. void dosource(char *arg,bool_t giveerror)
  421. {
  422. FILE *f;
  423. char string[256];
  424. if(arg == NULL) {
  425. emsg("No filename given");
  426. return;
  427. }
  428. if((f = fopen(arg,"r")) == NULL) {
  429. if(giveerror) {
  430. emsg("No such file or error opening file");
  431. }
  432. } else {
  433. while(fgets(string,sizeof(string),f) != NULL) {
  434. docmdln(string);
  435. }
  436. }
  437. }
  438. void ex_delete(LINE *l,LINE *u)
  439. {
  440. int ndone = 0;
  441. LINE *cp;
  442. LINE *np;
  443. LNPTR savep;
  444. if (l == NULL) { // no address? use current line.
  445. l = u = Curschar->linep;
  446. }
  447. u_save(l->prev,u->next); // save for undo
  448. for(cp = l; cp != NULL && !got_int; cp = np) {
  449. np = cp->next; // set next before we delete the line
  450. if(Curschar->linep != cp) {
  451. savep = *Curschar;
  452. Curschar->linep = cp;
  453. Curschar->index = 0;
  454. delline(1,FALSE);
  455. *Curschar = savep;
  456. } else {
  457. delline(1,FALSE);
  458. }
  459. ndone++;
  460. if(cp == u) {
  461. break;
  462. }
  463. }
  464. updatescreen();
  465. if((ndone >= P(P_RP)) || got_int) {
  466. smsg("%s%d fewer line%c",
  467. got_int ? "Interrupt: " : "",
  468. ndone,
  469. ndone == 1 ? ' ' : 's');
  470. }
  471. }
  472. void dolist(LINE *l,LINE *u)
  473. {
  474. LINE *cp;
  475. char ch;
  476. char *txt;
  477. if(l == NULL) {
  478. l = u = Curschar->linep;
  479. }
  480. puts(""); // scroll one line
  481. for(cp = l; cp != NULL && !got_int; cp = cp->next) {
  482. for(txt = cp->s,ch = *txt; ch; ch = *(++txt)) {
  483. if(chars[ch].ch_size > 1) {
  484. outstr(chars[ch].ch_str);
  485. } else {
  486. outchar(ch);
  487. }
  488. }
  489. outstr("$\n");
  490. if(cp == u) {
  491. break;
  492. }
  493. }
  494. if(got_int) {
  495. puts("Interrupt");
  496. }
  497. wait_return();
  498. }
  499. /*
  500. * get_range - parse a range specifier
  501. *
  502. * Ranges are of the form:
  503. *
  504. * addr[,addr]
  505. *
  506. * where 'addr' is:
  507. *
  508. * $ [+- NUM]
  509. * 'x [+- NUM] (where x denotes a currently defined mark)
  510. * . [+- NUM]
  511. * NUM
  512. *
  513. * The pointer *cp is updated to point to the first character following
  514. * the range spec. If an initial address is found, but no second, the
  515. * upper bound is equal to the lower.
  516. */
  517. static void
  518. get_range(cp, lower, upper)
  519. register char **cp;
  520. LNPTR *lower, *upper;
  521. {
  522. register LNPTR *l;
  523. register char *p;
  524. if ((l = get_line(cp)) == NULL)
  525. return;
  526. *lower = *l;
  527. for (p = *cp; *p != NUL && isspace(*p) ;p++)
  528. ;
  529. *cp = p;
  530. if (*p != ',') { /* is there another line spec ? */
  531. *upper = *lower;
  532. return;
  533. }
  534. *cp = ++p;
  535. if ((l = get_line(cp)) == NULL) {
  536. *upper = *lower;
  537. return;
  538. }
  539. *upper = *l;
  540. }
  541. static LNPTR *
  542. get_line(cp)
  543. char **cp;
  544. {
  545. static LNPTR pos;
  546. LNPTR *lp;
  547. register char *p, c;
  548. register int lnum;
  549. pos.index = 0; /* shouldn't matter... check back later */
  550. p = *cp;
  551. /*
  552. * Determine the basic form, if present.
  553. */
  554. switch (c = *p++) {
  555. case '$':
  556. pos.linep = Fileend->linep->prev;
  557. break;
  558. case '.':
  559. pos.linep = Curschar->linep;
  560. break;
  561. case '\'':
  562. if ((lp = getmark(*p++)) == NULL) {
  563. emsg("Unknown mark");
  564. rangeerr = TRUE;
  565. return (LNPTR *) NULL;
  566. }
  567. pos = *lp;
  568. break;
  569. case '0': case '1': case '2': case '3': case '4':
  570. case '5': case '6': case '7': case '8': case '9':
  571. for (lnum = c - '0'; isdigit(*p) ;p++)
  572. lnum = (lnum * 10) + (*p - '0');
  573. pos = *gotoline(lnum);
  574. break;
  575. default:
  576. return (LNPTR *) NULL;
  577. }
  578. while (*p != NUL && isspace(*p))
  579. p++;
  580. if (*p == '-' || *p == '+') {
  581. bool_t neg = (*p++ == '-');
  582. for (lnum = 0; isdigit(*p) ;p++)
  583. lnum = (lnum * 10) + (*p - '0');
  584. if (neg)
  585. lnum = -lnum;
  586. pos = *gotoline( cntllines(Filemem, &pos) + lnum );
  587. }
  588. *cp = p;
  589. return &pos;
  590. }
  591. static void
  592. badcmd()
  593. {
  594. emsg("Unrecognized command");
  595. }
  596. #define LSIZE 256 /* max. size of a line in the tags file */
  597. /*
  598. * dotag(tag, force) - goto tag
  599. */
  600. void
  601. dotag(tag, force)
  602. char *tag;
  603. bool_t force;
  604. {
  605. FILE *tp;
  606. char lbuf[LSIZE]; /* line buffer */
  607. char pbuf[LSIZE]; /* search pattern buffer */
  608. bool_t match;
  609. register char *fname, *str;
  610. register char *p;
  611. if ((tp = fopen("tags", "r")) == NULL) {
  612. emsg("Can't open tags file");
  613. return;
  614. }
  615. while (fgets(lbuf, LSIZE, tp) != NULL) {
  616. if (lbuf[0] == ';') {
  617. /* Allow comment line. */
  618. continue;
  619. }
  620. if ((fname = strchr(lbuf, TAB)) == NULL) {
  621. emsg("Format error in tags file");
  622. return;
  623. }
  624. *fname++ = '\0';
  625. if ((str = strchr(fname, TAB)) == NULL) {
  626. emsg("Format error in tags file");
  627. return;
  628. }
  629. *str++ = '\0';
  630. if (P(P_IC)) {
  631. match = _stricmp(lbuf, tag) == 0;
  632. } else {
  633. match = strcmp(lbuf, tag) == 0;
  634. }
  635. if (match) {
  636. /*
  637. * Scan through the search string. If we see a magic
  638. * char, we have to quote it. This lets us use "real"
  639. * implementations of ctags.
  640. */
  641. p = pbuf;
  642. *p++ = *str++; /* copy the '/' or '?' */
  643. *p++ = *str++; /* copy the '^' */
  644. for (; *str != NUL ;str++) {
  645. if (*str == '\\') {
  646. *p++ = *str++;
  647. *p++ = *str;
  648. } else if (strchr("/?", *str) != NULL) {
  649. if (str[1] != '\n') {
  650. *p++ = '\\';
  651. *p++ = *str;
  652. } else
  653. *p++ = *str;
  654. } else if (strchr("^()*.", *str) != NULL) {
  655. *p++ = '\\';
  656. *p++ = *str;
  657. } else
  658. *p++ = *str;
  659. }
  660. *p = NUL;
  661. /*
  662. * This looks out of order, but by calling stuffin()
  663. * before doecmd() we keep an extra screen update
  664. * from occuring. This stuffins() have no effect
  665. * until we get back to the main loop, anyway.
  666. */
  667. stuffin(pbuf); /* str has \n at end */
  668. stuffin("\007"); /* CTRL('g') */
  669. if (doecmd(fname, force)) {
  670. fclose(tp);
  671. return;
  672. } else
  673. stuffin(NULL); /* clear the input */
  674. }
  675. }
  676. emsg("tag not found");
  677. fclose(tp);
  678. }
  679. static bool_t
  680. doecmd(arg, force)
  681. char *arg;
  682. bool_t force;
  683. {
  684. int line = 1; /* line # to go to in new file */
  685. if (!force && Changed) {
  686. emsg(nowrtmsg);
  687. if ( arg != NULL ) {
  688. if (altfile)
  689. free(altfile);
  690. altfile = strsave(arg);
  691. }
  692. return FALSE;
  693. }
  694. if (arg != NULL) {
  695. /*
  696. * First detect a ":e" on the current file. This is mainly
  697. * for ":ta" commands where the destination is within the
  698. * current file.
  699. */
  700. if (Filename != NULL && strcmp(arg, Filename) == 0) {
  701. if (!Changed || (Changed && !force))
  702. return TRUE;
  703. }
  704. if (altfile) {
  705. if (strcmp (arg, altfile) == 0)
  706. line = altline;
  707. free(altfile);
  708. }
  709. altfile = Filename;
  710. altline = cntllines(Filemem, Curschar);
  711. Filename = strsave(arg);
  712. }
  713. if (Filename == NULL) {
  714. emsg("No filename");
  715. return FALSE;
  716. }
  717. /* clear mem and read file */
  718. freeall();
  719. filealloc();
  720. UNCHANGED;
  721. if (readfile(Filename, Filemem, 0))
  722. filemess("[New File]");
  723. setviconsoletitle();
  724. *Topchar = *Curschar;
  725. if (line != 1) {
  726. stuffnum(line);
  727. stuffin("G");
  728. }
  729. do_mlines();
  730. setpcmark();
  731. updatescreen();
  732. return TRUE;
  733. }
  734. void
  735. gotocmd(clr, firstc)
  736. bool_t clr;
  737. char firstc;
  738. {
  739. windgoto(Rows-1,0);
  740. if (clr)
  741. EraseLine(); /* clear the bottom line */
  742. if (firstc)
  743. outchar(firstc);
  744. }
  745. /*
  746. * msg(s) - displays the string 's' on the status line
  747. */
  748. void
  749. msg(s)
  750. char *s;
  751. {
  752. gotocmd(TRUE, 0);
  753. outstr(s);
  754. flushbuf();
  755. }
  756. /*VARARGS1*/
  757. void
  758. smsg(s, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)
  759. char *s;
  760. int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16;
  761. {
  762. char sbuf[256]; /* Status line, > 80 chars to allow wrap. */
  763. sprintf(sbuf, s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16);
  764. msg(sbuf);
  765. }
  766. /*
  767. * emsg() - display an error message
  768. *
  769. * Rings the bell, if appropriate, and calls message() to do the real work
  770. */
  771. void
  772. emsg(s)
  773. char *s;
  774. {
  775. if (P(P_EB))
  776. beep();
  777. msg(s);
  778. }
  779. int
  780. wait_return0()
  781. {
  782. register char c;
  783. if (got_int)
  784. outstr("Interrupt: ");
  785. outstr("Press RETURN to continue");
  786. do {
  787. c = (char)vgetc();
  788. } while (c != CR && c != NL && c != ' ' && c != ':');
  789. return c;
  790. }
  791. void
  792. wait_return()
  793. {
  794. char c = (char)wait_return0();
  795. if (c == ':') {
  796. outchar(NL);
  797. docmdln(getcmdln(c));
  798. } else
  799. screenclear();
  800. updatescreen();
  801. }