PageRenderTime 72ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 0ms

/usr/src/lib/libshell/common/edit/emacs.c

https://bitbucket.org/a3217055/illumos-gate
C | 1483 lines | 1285 code | 90 blank | 108 comment | 222 complexity | 30ee22ff6cbff96a2613c9d752f0fba4 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, LGPL-2.0, 0BSD, AGPL-3.0, GPL-2.0, GPL-3.0, LGPL-2.1, LGPL-3.0, BSD-3-Clause-No-Nuclear-License-2014, MPL-2.0-no-copyleft-exception, AGPL-1.0
  1. /***********************************************************************
  2. * *
  3. * This software is part of the ast package *
  4. * Copyright (c) 1982-2010 AT&T Intellectual Property *
  5. * and is licensed under the *
  6. * Common Public License, Version 1.0 *
  7. * by AT&T Intellectual Property *
  8. * *
  9. * A copy of the License is available at *
  10. * http://www.opensource.org/licenses/cpl1.0.txt *
  11. * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
  12. * *
  13. * Information and Software Systems Research *
  14. * AT&T Research *
  15. * Florham Park NJ *
  16. * *
  17. * David Korn <dgk@research.att.com> *
  18. * *
  19. ***********************************************************************/
  20. #pragma prototyped
  21. /* Original version by Michael T. Veach
  22. * Adapted for ksh by David Korn */
  23. /* EMACS_MODES: c tabstop=4
  24. One line screen editor for any program
  25. */
  26. /* The following is provided by:
  27. *
  28. * Matthijs N. Melchior
  29. * AT&T Network Systems International
  30. * APT Nederland
  31. * HV BZ335 x2962
  32. * hvlpb!mmelchio
  33. *
  34. * These are now on by default
  35. *
  36. * ESH_NFIRST
  37. * - A ^N as first history related command after the prompt will move
  38. * to the next command relative to the last known history position.
  39. * It will not start at the position where the last command was entered
  40. * as is done by the ^P command. Every history related command will
  41. * set both the current and last position. Executing a command will
  42. * only set the current position.
  43. *
  44. * ESH_KAPPEND
  45. * - Successive kill and delete commands will accumulate their data
  46. * in the kill buffer, by appending or prepending as appropriate.
  47. * This mode will be reset by any command not adding something to the
  48. * kill buffer.
  49. *
  50. * ESH_BETTER
  51. * - Some enhancements:
  52. * - argument for a macro is passed to its replacement
  53. * - ^X^H command to find out about history position (debugging)
  54. * - ^X^D command to show any debugging info
  55. *
  56. * I do not pretend these for changes are completely independent,
  57. * but you can use them to seperate features.
  58. */
  59. #include <ast.h>
  60. #include "FEATURE/cmds"
  61. #if KSHELL
  62. # include "defs.h"
  63. #else
  64. # include <ctype.h>
  65. #endif /* KSHELL */
  66. #include "io.h"
  67. #include "history.h"
  68. #include "edit.h"
  69. #include "terminal.h"
  70. #define ESH_NFIRST
  71. #define ESH_KAPPEND
  72. #define ESH_BETTER
  73. #undef putchar
  74. #define putchar(ed,c) ed_putchar(ed,c)
  75. #define beep() ed_ringbell()
  76. #if SHOPT_MULTIBYTE
  77. # define gencpy(a,b) ed_gencpy(a,b)
  78. # define genncpy(a,b,n) ed_genncpy(a,b,n)
  79. # define genlen(str) ed_genlen(str)
  80. static int print(int);
  81. static int _isword(int);
  82. # define isword(c) _isword(out[c])
  83. #else
  84. # define gencpy(a,b) strcpy((char*)(a),(char*)(b))
  85. # define genncpy(a,b,n) strncpy((char*)(a),(char*)(b),n)
  86. # define genlen(str) strlen(str)
  87. # define print(c) isprint(c)
  88. # define isword(c) (isalnum(out[c]) || (out[c]=='_'))
  89. #endif /*SHOPT_MULTIBYTE */
  90. typedef struct _emacs_
  91. {
  92. genchar *screen; /* pointer to window buffer */
  93. genchar *cursor; /* Cursor in real screen */
  94. int mark;
  95. int in_mult;
  96. char cr_ok;
  97. char CntrlO;
  98. char overflow; /* Screen overflow flag set */
  99. char scvalid; /* Screen is up to date */
  100. char lastdraw; /* last update type */
  101. int offset; /* Screen offset */
  102. enum
  103. {
  104. CRT=0, /* Crt terminal */
  105. PAPER /* Paper terminal */
  106. } terminal;
  107. Histloc_t _location;
  108. int prevdirection;
  109. Edit_t *ed; /* pointer to edit data */
  110. } Emacs_t;
  111. #define editb (*ep->ed)
  112. #define eol editb.e_eol
  113. #define cur editb.e_cur
  114. #define hline editb.e_hline
  115. #define hloff editb.e_hloff
  116. #define hismin editb.e_hismin
  117. #define usrkill editb.e_kill
  118. #define usrlnext editb.e_lnext
  119. #define usreof editb.e_eof
  120. #define usrerase editb.e_erase
  121. #define crallowed editb.e_crlf
  122. #define Prompt editb.e_prompt
  123. #define plen editb.e_plen
  124. #define kstack editb.e_killbuf
  125. #define lstring editb.e_search
  126. #define lookahead editb.e_lookahead
  127. #define env editb.e_env
  128. #define raw editb.e_raw
  129. #define histlines editb.e_hismax
  130. #define w_size editb.e_wsize
  131. #define drawbuff editb.e_inbuf
  132. #define killing editb.e_mode
  133. #define location ep->_location
  134. #define LBUF 100
  135. #define KILLCHAR UKILL
  136. #define ERASECHAR UERASE
  137. #define EOFCHAR UEOF
  138. #define LNEXTCHAR ULNEXT
  139. #define DELETE ('a'==97?0177:7)
  140. /**********************
  141. A large lookahead helps when the user is inserting
  142. characters in the middle of the line.
  143. ************************/
  144. typedef enum
  145. {
  146. FIRST, /* First time thru for logical line, prompt on screen */
  147. REFRESH, /* Redraw entire screen */
  148. APPEND, /* Append char before cursor to screen */
  149. UPDATE, /* Update the screen as need be */
  150. FINAL /* Update screen even if pending look ahead */
  151. } Draw_t;
  152. static void draw(Emacs_t*,Draw_t);
  153. static int escape(Emacs_t*,genchar*, int);
  154. static void putstring(Emacs_t*,char*);
  155. static void search(Emacs_t*,genchar*,int);
  156. static void setcursor(Emacs_t*,int, int);
  157. static void show_info(Emacs_t*,const char*);
  158. static void xcommands(Emacs_t*,int);
  159. int ed_emacsread(void *context, int fd,char *buff,int scend, int reedit)
  160. {
  161. Edit_t *ed = (Edit_t*)context;
  162. register int c;
  163. register int i;
  164. register genchar *out;
  165. register int count;
  166. register Emacs_t *ep = ed->e_emacs;
  167. int adjust,oadjust;
  168. char backslash;
  169. genchar *kptr;
  170. char prompt[PRSIZE];
  171. genchar Screen[MAXLINE];
  172. if(!ep)
  173. {
  174. ep = ed->e_emacs = newof(0,Emacs_t,1,0);
  175. ep->ed = ed;
  176. ep->prevdirection = 1;
  177. location.hist_command = -5;
  178. }
  179. Prompt = prompt;
  180. ep->screen = Screen;
  181. ep->lastdraw = FINAL;
  182. if(tty_raw(ERRIO,0) < 0)
  183. {
  184. return(reedit?reedit:ed_read(context, fd,buff,scend,0));
  185. }
  186. raw = 1;
  187. /* This mess in case the read system call fails */
  188. ed_setup(ep->ed,fd,reedit);
  189. out = (genchar*)buff;
  190. #if SHOPT_MULTIBYTE
  191. out = (genchar*)roundof(buff-(char*)0,sizeof(genchar));
  192. if(reedit)
  193. ed_internal(buff,out);
  194. #endif /* SHOPT_MULTIBYTE */
  195. if(!kstack)
  196. {
  197. kstack = (genchar*)malloc(CHARSIZE*MAXLINE);
  198. kstack[0] = '\0';
  199. }
  200. drawbuff = out;
  201. #ifdef ESH_NFIRST
  202. if (location.hist_command == -5) /* to be initialized */
  203. {
  204. kstack[0] = '\0'; /* also clear kstack... */
  205. location.hist_command = hline;
  206. location.hist_line = hloff;
  207. }
  208. if (location.hist_command <= hismin) /* don't start below minimum */
  209. {
  210. location.hist_command = hismin + 1;
  211. location.hist_line = 0;
  212. }
  213. ep->in_mult = hloff; /* save pos in last command */
  214. #endif /* ESH_NFIRST */
  215. i = sigsetjmp(env,0);
  216. if (i !=0)
  217. {
  218. if(ep->ed->e_multiline)
  219. {
  220. cur = eol;
  221. draw(ep,FINAL);
  222. ed_flush(ep->ed);
  223. }
  224. tty_cooked(ERRIO);
  225. if (i == UEOF)
  226. {
  227. return(0); /* EOF */
  228. }
  229. return(-1); /* some other error */
  230. }
  231. out[reedit] = 0;
  232. if(scend+plen > (MAXLINE-2))
  233. scend = (MAXLINE-2)-plen;
  234. ep->mark = 0;
  235. cur = eol;
  236. draw(ep,reedit?REFRESH:FIRST);
  237. adjust = -1;
  238. backslash = 0;
  239. if (ep->CntrlO)
  240. {
  241. #ifdef ESH_NFIRST
  242. ed_ungetchar(ep->ed,cntl('N'));
  243. #else
  244. location = hist_locate(sh.hist_ptr,location.hist_command,location.hist_line,1);
  245. if (location.hist_command < histlines)
  246. {
  247. hline = location.hist_command;
  248. hloff = location.hist_line;
  249. hist_copy((char*)kstack,MAXLINE, hline,hloff);
  250. # if SHOPT_MULTIBYTE
  251. ed_internal((char*)kstack,kstack);
  252. # endif /* SHOPT_MULTIBYTE */
  253. ed_ungetchar(ep->ed,cntl('Y'));
  254. }
  255. #endif /* ESH_NFIRST */
  256. }
  257. ep->CntrlO = 0;
  258. while ((c = ed_getchar(ep->ed,0)) != (-1))
  259. {
  260. if (backslash)
  261. {
  262. backslash = 0;
  263. if (c==usrerase||c==usrkill||(!print(c) &&
  264. (c!='\r'&&c!='\n')))
  265. {
  266. /* accept a backslashed character */
  267. cur--;
  268. out[cur++] = c;
  269. out[eol] = '\0';
  270. draw(ep,APPEND);
  271. continue;
  272. }
  273. }
  274. if (c == usrkill)
  275. {
  276. c = KILLCHAR ;
  277. }
  278. else if (c == usrerase)
  279. {
  280. c = ERASECHAR ;
  281. }
  282. else if (c == usrlnext)
  283. {
  284. c = LNEXTCHAR ;
  285. }
  286. else if ((c == usreof)&&(eol == 0))
  287. {
  288. c = EOFCHAR;
  289. }
  290. #ifdef ESH_KAPPEND
  291. if (--killing <= 0) /* reset killing flag */
  292. killing = 0;
  293. #endif
  294. oadjust = count = adjust;
  295. if(count<0)
  296. count = 1;
  297. adjust = -1;
  298. i = cur;
  299. switch(c)
  300. {
  301. case LNEXTCHAR:
  302. c = ed_getchar(ep->ed,2);
  303. goto do_default_processing;
  304. case cntl('V'):
  305. show_info(ep,fmtident(e_version));
  306. continue;
  307. case '\0':
  308. ep->mark = i;
  309. continue;
  310. case cntl('X'):
  311. xcommands(ep,count);
  312. continue;
  313. case EOFCHAR:
  314. ed_flush(ep->ed);
  315. tty_cooked(ERRIO);
  316. return(0);
  317. #ifdef u370
  318. case cntl('S') :
  319. case cntl('Q') :
  320. continue;
  321. #endif /* u370 */
  322. case '\t':
  323. if(cur>0 && ep->ed->sh->nextprompt)
  324. {
  325. if(ep->ed->e_tabcount==0)
  326. {
  327. ep->ed->e_tabcount=1;
  328. ed_ungetchar(ep->ed,ESC);
  329. goto do_escape;
  330. }
  331. else if(ep->ed->e_tabcount==1)
  332. {
  333. ed_ungetchar(ep->ed,'=');
  334. goto do_escape;
  335. }
  336. ep->ed->e_tabcount = 0;
  337. }
  338. do_default_processing:
  339. default:
  340. if ((eol+1) >= (scend)) /* will not fit on line */
  341. {
  342. ed_ungetchar(ep->ed,c); /* save character for next line */
  343. goto process;
  344. }
  345. for(i= ++eol; i>cur; i--)
  346. out[i] = out[i-1];
  347. backslash = (c == '\\');
  348. out[cur++] = c;
  349. draw(ep,APPEND);
  350. continue;
  351. case cntl('Y') :
  352. {
  353. c = genlen(kstack);
  354. if ((c + eol) > scend)
  355. {
  356. beep();
  357. continue;
  358. }
  359. ep->mark = i;
  360. for(i=eol;i>=cur;i--)
  361. out[c+i] = out[i];
  362. kptr=kstack;
  363. while (i = *kptr++)
  364. out[cur++] = i;
  365. draw(ep,UPDATE);
  366. eol = genlen(out);
  367. continue;
  368. }
  369. case '\n':
  370. case '\r':
  371. c = '\n';
  372. goto process;
  373. case DELETE: /* delete char 0x7f */
  374. case '\b': /* backspace, ^h */
  375. case ERASECHAR :
  376. if (count > i)
  377. count = i;
  378. #ifdef ESH_KAPPEND
  379. kptr = &kstack[count]; /* move old contents here */
  380. if (killing) /* prepend to killbuf */
  381. {
  382. c = genlen(kstack) + CHARSIZE; /* include '\0' */
  383. while(c--) /* copy stuff */
  384. kptr[c] = kstack[c];
  385. }
  386. else
  387. *kptr = 0; /* this is end of data */
  388. killing = 2; /* we are killing */
  389. i -= count;
  390. eol -= count;
  391. genncpy(kstack,out+i,cur-i);
  392. #else
  393. while ((count--)&&(i>0))
  394. {
  395. i--;
  396. eol--;
  397. }
  398. genncpy(kstack,out+i,cur-i);
  399. kstack[cur-i] = 0;
  400. #endif /* ESH_KAPPEND */
  401. gencpy(out+i,out+cur);
  402. ep->mark = i;
  403. goto update;
  404. case cntl('W') :
  405. #ifdef ESH_KAPPEND
  406. ++killing; /* keep killing flag */
  407. #endif
  408. if (ep->mark > eol )
  409. ep->mark = eol;
  410. if (ep->mark == i)
  411. continue;
  412. if (ep->mark > i)
  413. {
  414. adjust = ep->mark - i;
  415. ed_ungetchar(ep->ed,cntl('D'));
  416. continue;
  417. }
  418. adjust = i - ep->mark;
  419. ed_ungetchar(ep->ed,usrerase);
  420. continue;
  421. case cntl('D') :
  422. ep->mark = i;
  423. #ifdef ESH_KAPPEND
  424. if (killing)
  425. kptr = &kstack[genlen(kstack)]; /* append here */
  426. else
  427. kptr = kstack;
  428. killing = 2; /* we are now killing */
  429. #else
  430. kptr = kstack;
  431. #endif /* ESH_KAPPEND */
  432. while ((count--)&&(eol>0)&&(i<eol))
  433. {
  434. *kptr++ = out[i];
  435. eol--;
  436. while(1)
  437. {
  438. if ((out[i] = out[(i+1)])==0)
  439. break;
  440. i++;
  441. }
  442. i = cur;
  443. }
  444. *kptr = '\0';
  445. goto update;
  446. case cntl('C') :
  447. case cntl('F') :
  448. {
  449. int cntlC = (c==cntl('C'));
  450. while (count-- && eol>i)
  451. {
  452. if (cntlC)
  453. {
  454. c = out[i];
  455. #if SHOPT_MULTIBYTE
  456. if((c&~STRIP)==0 && islower(c))
  457. #else
  458. if(islower(c))
  459. #endif /* SHOPT_MULTIBYTE */
  460. {
  461. c += 'A' - 'a';
  462. out[i] = c;
  463. }
  464. }
  465. i++;
  466. }
  467. goto update;
  468. }
  469. case cntl(']') :
  470. c = ed_getchar(ep->ed,1);
  471. if ((count == 0) || (count > eol))
  472. {
  473. beep();
  474. continue;
  475. }
  476. if (out[i])
  477. i++;
  478. while (i < eol)
  479. {
  480. if (out[i] == c && --count==0)
  481. goto update;
  482. i++;
  483. }
  484. i = 0;
  485. while (i < cur)
  486. {
  487. if (out[i] == c && --count==0)
  488. break;
  489. i++;
  490. };
  491. update:
  492. cur = i;
  493. draw(ep,UPDATE);
  494. continue;
  495. case cntl('B') :
  496. if (count > i)
  497. count = i;
  498. i -= count;
  499. goto update;
  500. case cntl('T') :
  501. if ((sh_isoption(SH_EMACS))&& (eol!=i))
  502. i++;
  503. if (i >= 2)
  504. {
  505. c = out[i - 1];
  506. out[i-1] = out[i-2];
  507. out[i-2] = c;
  508. }
  509. else
  510. {
  511. if(sh_isoption(SH_EMACS))
  512. i--;
  513. beep();
  514. continue;
  515. }
  516. goto update;
  517. case cntl('A') :
  518. i = 0;
  519. goto update;
  520. case cntl('E') :
  521. i = eol;
  522. goto update;
  523. case cntl('U') :
  524. adjust = 4*count;
  525. continue;
  526. case KILLCHAR :
  527. cur = 0;
  528. oadjust = -1;
  529. case cntl('K') :
  530. if(oadjust >= 0)
  531. {
  532. #ifdef ESH_KAPPEND
  533. killing = 2; /* set killing signal */
  534. #endif
  535. ep->mark = count;
  536. ed_ungetchar(ep->ed,cntl('W'));
  537. continue;
  538. }
  539. i = cur;
  540. eol = i;
  541. ep->mark = i;
  542. #ifdef ESH_KAPPEND
  543. if (killing) /* append to kill buffer */
  544. gencpy(&kstack[genlen(kstack)], &out[i]);
  545. else
  546. gencpy(kstack,&out[i]);
  547. killing = 2; /* set killing signal */
  548. #else
  549. gencpy(kstack,&out[i]);
  550. #endif /* ESH_KAPPEND */
  551. out[i] = 0;
  552. draw(ep,UPDATE);
  553. if (c == KILLCHAR)
  554. {
  555. if (ep->terminal == PAPER)
  556. {
  557. putchar(ep->ed,'\n');
  558. putstring(ep,Prompt);
  559. }
  560. c = ed_getchar(ep->ed,0);
  561. if (c != usrkill)
  562. {
  563. ed_ungetchar(ep->ed,c);
  564. continue;
  565. }
  566. if (ep->terminal == PAPER)
  567. ep->terminal = CRT;
  568. else
  569. {
  570. ep->terminal = PAPER;
  571. putchar(ep->ed,'\n');
  572. putstring(ep,Prompt);
  573. }
  574. }
  575. continue;
  576. case cntl('L'):
  577. if(!ep->ed->e_nocrnl)
  578. ed_crlf(ep->ed);
  579. draw(ep,REFRESH);
  580. ep->ed->e_nocrnl = 0;
  581. continue;
  582. case cntl('[') :
  583. do_escape:
  584. adjust = escape(ep,out,oadjust);
  585. continue;
  586. case cntl('R') :
  587. search(ep,out,count);
  588. goto drawline;
  589. case cntl('P') :
  590. if (count <= hloff)
  591. hloff -= count;
  592. else
  593. {
  594. hline -= count - hloff;
  595. hloff = 0;
  596. }
  597. #ifdef ESH_NFIRST
  598. if (hline <= hismin)
  599. #else
  600. if (hline < hismin)
  601. #endif /* ESH_NFIRST */
  602. {
  603. hline = hismin+1;
  604. beep();
  605. #ifndef ESH_NFIRST
  606. continue;
  607. #endif
  608. }
  609. goto common;
  610. case cntl('O') :
  611. location.hist_command = hline;
  612. location.hist_line = hloff;
  613. ep->CntrlO = 1;
  614. c = '\n';
  615. goto process;
  616. case cntl('N') :
  617. #ifdef ESH_NFIRST
  618. hline = location.hist_command; /* start at saved position */
  619. hloff = location.hist_line;
  620. #endif /* ESH_NFIRST */
  621. location = hist_locate(sh.hist_ptr,hline,hloff,count);
  622. if (location.hist_command > histlines)
  623. {
  624. beep();
  625. #ifdef ESH_NFIRST
  626. location.hist_command = histlines;
  627. location.hist_line = ep->in_mult;
  628. #else
  629. continue;
  630. #endif /* ESH_NFIRST */
  631. }
  632. hline = location.hist_command;
  633. hloff = location.hist_line;
  634. common:
  635. #ifdef ESH_NFIRST
  636. location.hist_command = hline; /* save current position */
  637. location.hist_line = hloff;
  638. #endif
  639. cur = 0;
  640. draw(ep,UPDATE);
  641. hist_copy((char*)out,MAXLINE, hline,hloff);
  642. #if SHOPT_MULTIBYTE
  643. ed_internal((char*)(out),out);
  644. #endif /* SHOPT_MULTIBYTE */
  645. drawline:
  646. eol = genlen(out);
  647. cur = eol;
  648. draw(ep,UPDATE);
  649. continue;
  650. }
  651. }
  652. process:
  653. if (c == (-1))
  654. {
  655. lookahead = 0;
  656. beep();
  657. *out = '\0';
  658. }
  659. draw(ep,FINAL);
  660. tty_cooked(ERRIO);
  661. if(ed->e_nlist)
  662. {
  663. ed->e_nlist = 0;
  664. stakset(ed->e_stkptr,ed->e_stkoff);
  665. }
  666. if(c == '\n')
  667. {
  668. out[eol++] = '\n';
  669. out[eol] = '\0';
  670. ed_crlf(ep->ed);
  671. }
  672. #if SHOPT_MULTIBYTE
  673. ed_external(out,buff);
  674. #endif /* SHOPT_MULTIBYTE */
  675. i = strlen(buff);
  676. if (i)
  677. return(i);
  678. return(-1);
  679. }
  680. static void show_info(Emacs_t *ep,const char *str)
  681. {
  682. register genchar *out = drawbuff;
  683. register int c;
  684. genchar string[LBUF];
  685. int sav_cur = cur;
  686. /* save current line */
  687. genncpy(string,out,sizeof(string)/sizeof(*string));
  688. *out = 0;
  689. cur = 0;
  690. #if SHOPT_MULTIBYTE
  691. ed_internal(str,out);
  692. #else
  693. gencpy(out,str);
  694. #endif /* SHOPT_MULTIBYTE */
  695. draw(ep,UPDATE);
  696. c = ed_getchar(ep->ed,0);
  697. if(c!=' ')
  698. ed_ungetchar(ep->ed,c);
  699. /* restore line */
  700. cur = sav_cur;
  701. genncpy(out,string,sizeof(string)/sizeof(*string));
  702. draw(ep,UPDATE);
  703. }
  704. static void putstring(Emacs_t* ep,register char *sp)
  705. {
  706. register int c;
  707. while (c= *sp++)
  708. putchar(ep->ed,c);
  709. }
  710. static int escape(register Emacs_t* ep,register genchar *out,int count)
  711. {
  712. register int i,value;
  713. int digit,ch;
  714. digit = 0;
  715. value = 0;
  716. while ((i=ed_getchar(ep->ed,0)),isdigit(i))
  717. {
  718. value *= 10;
  719. value += (i - '0');
  720. digit = 1;
  721. }
  722. if (digit)
  723. {
  724. ed_ungetchar(ep->ed,i) ;
  725. #ifdef ESH_KAPPEND
  726. ++killing; /* don't modify killing signal */
  727. #endif
  728. return(value);
  729. }
  730. value = count;
  731. if(value<0)
  732. value = 1;
  733. switch(ch=i)
  734. {
  735. case cntl('V'):
  736. show_info(ep,fmtident(e_version));
  737. return(-1);
  738. case ' ':
  739. ep->mark = cur;
  740. return(-1);
  741. #ifdef ESH_KAPPEND
  742. case '+': /* M-+ = append next kill */
  743. killing = 2;
  744. return -1; /* no argument for next command */
  745. #endif
  746. case 'p': /* M-p == ^W^Y (copy stack == kill & yank) */
  747. ed_ungetchar(ep->ed,cntl('Y'));
  748. ed_ungetchar(ep->ed,cntl('W'));
  749. #ifdef ESH_KAPPEND
  750. killing = 0; /* start fresh */
  751. #endif
  752. return(-1);
  753. case 'l': /* M-l == lower-case */
  754. case 'd':
  755. case 'c':
  756. case 'f':
  757. {
  758. i = cur;
  759. while(value-- && i<eol)
  760. {
  761. while ((out[i])&&(!isword(i)))
  762. i++;
  763. while ((out[i])&&(isword(i)))
  764. i++;
  765. }
  766. if(ch=='l')
  767. {
  768. value = i-cur;
  769. while (value-- > 0)
  770. {
  771. i = out[cur];
  772. #if SHOPT_MULTIBYTE
  773. if((i&~STRIP)==0 && isupper(i))
  774. #else
  775. if(isupper(i))
  776. #endif /* SHOPT_MULTIBYTE */
  777. {
  778. i += 'a' - 'A';
  779. out[cur] = i;
  780. }
  781. cur++;
  782. }
  783. draw(ep,UPDATE);
  784. return(-1);
  785. }
  786. else if(ch=='f')
  787. goto update;
  788. else if(ch=='c')
  789. {
  790. ed_ungetchar(ep->ed,cntl('C'));
  791. return(i-cur);
  792. }
  793. else
  794. {
  795. if (i-cur)
  796. {
  797. ed_ungetchar(ep->ed,cntl('D'));
  798. #ifdef ESH_KAPPEND
  799. ++killing; /* keep killing signal */
  800. #endif
  801. return(i-cur);
  802. }
  803. beep();
  804. return(-1);
  805. }
  806. }
  807. case 'b':
  808. case DELETE :
  809. case '\b':
  810. case 'h':
  811. {
  812. i = cur;
  813. while(value-- && i>0)
  814. {
  815. i--;
  816. while ((i>0)&&(!isword(i)))
  817. i--;
  818. while ((i>0)&&(isword(i-1)))
  819. i--;
  820. }
  821. if(ch=='b')
  822. goto update;
  823. else
  824. {
  825. ed_ungetchar(ep->ed,usrerase);
  826. #ifdef ESH_KAPPEND
  827. ++killing;
  828. #endif
  829. return(cur-i);
  830. }
  831. }
  832. case '>':
  833. ed_ungetchar(ep->ed,cntl('N'));
  834. #ifdef ESH_NFIRST
  835. if (ep->in_mult)
  836. {
  837. location.hist_command = histlines;
  838. location.hist_line = ep->in_mult - 1;
  839. }
  840. else
  841. {
  842. location.hist_command = histlines - 1;
  843. location.hist_line = 0;
  844. }
  845. #else
  846. hline = histlines-1;
  847. hloff = 0;
  848. #endif /* ESH_NFIRST */
  849. return(0);
  850. case '<':
  851. ed_ungetchar(ep->ed,cntl('P'));
  852. hloff = 0;
  853. #ifdef ESH_NFIRST
  854. hline = hismin + 1;
  855. return 0;
  856. #else
  857. return(hline-hismin);
  858. #endif /* ESH_NFIRST */
  859. case '#':
  860. ed_ungetchar(ep->ed,'\n');
  861. ed_ungetchar(ep->ed,(out[0]=='#')?cntl('D'):'#');
  862. ed_ungetchar(ep->ed,cntl('A'));
  863. return(-1);
  864. case '_' :
  865. case '.' :
  866. {
  867. genchar name[MAXLINE];
  868. char buf[MAXLINE];
  869. char *ptr;
  870. ptr = hist_word(buf,MAXLINE,(count?count:-1));
  871. if(ptr==0)
  872. {
  873. beep();
  874. break;
  875. }
  876. if ((eol - cur) >= sizeof(name))
  877. {
  878. beep();
  879. return(-1);
  880. }
  881. ep->mark = cur;
  882. gencpy(name,&out[cur]);
  883. while(*ptr)
  884. {
  885. out[cur++] = *ptr++;
  886. eol++;
  887. }
  888. gencpy(&out[cur],name);
  889. draw(ep,UPDATE);
  890. return(-1);
  891. }
  892. #if KSHELL
  893. /* file name expansion */
  894. case cntl('[') : /* filename completion */
  895. i = '\\';
  896. case '*': /* filename expansion */
  897. case '=': /* escape = - list all matching file names */
  898. ep->mark = cur;
  899. if(ed_expand(ep->ed,(char*)out,&cur,&eol,i,count) < 0)
  900. {
  901. if(ep->ed->e_tabcount==1)
  902. {
  903. ep->ed->e_tabcount=2;
  904. ed_ungetchar(ep->ed,cntl('\t'));
  905. return(-1);
  906. }
  907. beep();
  908. }
  909. else if(i=='=')
  910. {
  911. draw(ep,REFRESH);
  912. if(count>0)
  913. ep->ed->e_tabcount=0;
  914. else
  915. {
  916. i=ed_getchar(ep->ed,0);
  917. ed_ungetchar(ep->ed,i);
  918. if(isdigit(i))
  919. ed_ungetchar(ep->ed,ESC);
  920. }
  921. }
  922. else
  923. {
  924. if(i=='\\' && cur>ep->mark && (out[cur-1]=='/' || out[cur-1]==' '))
  925. ep->ed->e_tabcount=0;
  926. draw(ep,UPDATE);
  927. }
  928. return(-1);
  929. /* search back for character */
  930. case cntl(']'): /* feature not in book */
  931. {
  932. int c = ed_getchar(ep->ed,1);
  933. if ((value == 0) || (value > eol))
  934. {
  935. beep();
  936. return(-1);
  937. }
  938. i = cur;
  939. if (i > 0)
  940. i--;
  941. while (i >= 0)
  942. {
  943. if (out[i] == c && --value==0)
  944. goto update;
  945. i--;
  946. }
  947. i = eol;
  948. while (i > cur)
  949. {
  950. if (out[i] == c && --value==0)
  951. break;
  952. i--;
  953. };
  954. }
  955. update:
  956. cur = i;
  957. draw(ep,UPDATE);
  958. return(-1);
  959. #ifdef _cmd_tput
  960. case cntl('L'): /* clear screen */
  961. sh_trap("tput clear", 0);
  962. draw(ep,REFRESH);
  963. return(-1);
  964. #endif
  965. case '[': /* feature not in book */
  966. switch(i=ed_getchar(ep->ed,1))
  967. {
  968. case 'A':
  969. if(cur>0 && eol==cur && (cur<(SEARCHSIZE-2) || ep->prevdirection == -2))
  970. {
  971. if(ep->lastdraw==APPEND && ep->prevdirection != -2)
  972. {
  973. out[cur] = 0;
  974. gencpy(&((genchar*)lstring)[1],out);
  975. #if SHOPT_MULTIBYTE
  976. ed_external(&((genchar*)lstring)[1],lstring+1);
  977. #endif /* SHOPT_MULTIBYTE */
  978. *lstring = '^';
  979. ep->prevdirection = -2;
  980. }
  981. if(*lstring)
  982. {
  983. ed_ungetchar(ep->ed,'\r');
  984. ed_ungetchar(ep->ed,cntl('R'));
  985. return(-1);
  986. }
  987. }
  988. *lstring = 0;
  989. ed_ungetchar(ep->ed,cntl('P'));
  990. return(-1);
  991. case 'B':
  992. ed_ungetchar(ep->ed,cntl('N'));
  993. return(-1);
  994. case 'C':
  995. ed_ungetchar(ep->ed,cntl('F'));
  996. return(-1);
  997. case 'D':
  998. ed_ungetchar(ep->ed,cntl('B'));
  999. return(-1);
  1000. case 'H':
  1001. ed_ungetchar(ep->ed,cntl('A'));
  1002. return(-1);
  1003. case 'Y':
  1004. ed_ungetchar(ep->ed,cntl('E'));
  1005. return(-1);
  1006. default:
  1007. ed_ungetchar(ep->ed,i);
  1008. }
  1009. i = '_';
  1010. default:
  1011. /* look for user defined macro definitions */
  1012. if(ed_macro(ep->ed,i))
  1013. # ifdef ESH_BETTER
  1014. return(count); /* pass argument to macro */
  1015. # else
  1016. return(-1);
  1017. # endif /* ESH_BETTER */
  1018. #else
  1019. update:
  1020. cur = i;
  1021. draw(ep,UPDATE);
  1022. return(-1);
  1023. default:
  1024. #endif /* KSHELL */
  1025. beep();
  1026. return(-1);
  1027. }
  1028. return(-1);
  1029. }
  1030. /*
  1031. * This routine process all commands starting with ^X
  1032. */
  1033. static void xcommands(register Emacs_t *ep,int count)
  1034. {
  1035. register int i = ed_getchar(ep->ed,0);
  1036. NOT_USED(count);
  1037. switch(i)
  1038. {
  1039. case cntl('X'): /* exchange dot and mark */
  1040. if (ep->mark > eol)
  1041. ep->mark = eol;
  1042. i = ep->mark;
  1043. ep->mark = cur;
  1044. cur = i;
  1045. draw(ep,UPDATE);
  1046. return;
  1047. #if KSHELL
  1048. # ifdef ESH_BETTER
  1049. case cntl('E'): /* invoke emacs on current command */
  1050. if(ed_fulledit(ep->ed)==-1)
  1051. beep();
  1052. else
  1053. {
  1054. #if SHOPT_MULTIBYTE
  1055. ed_internal((char*)drawbuff,drawbuff);
  1056. #endif /* SHOPT_MULTIBYTE */
  1057. ed_ungetchar(ep->ed,'\n');
  1058. }
  1059. return;
  1060. # define itos(i) fmtbase((long)(i),0,0)/* want signed conversion */
  1061. case cntl('H'): /* ^X^H show history info */
  1062. {
  1063. char hbuf[MAXLINE];
  1064. strcpy(hbuf, "Current command ");
  1065. strcat(hbuf, itos(hline));
  1066. if (hloff)
  1067. {
  1068. strcat(hbuf, " (line ");
  1069. strcat(hbuf, itos(hloff+1));
  1070. strcat(hbuf, ")");
  1071. }
  1072. if ((hline != location.hist_command) ||
  1073. (hloff != location.hist_line))
  1074. {
  1075. strcat(hbuf, "; Previous command ");
  1076. strcat(hbuf, itos(location.hist_command));
  1077. if (location.hist_line)
  1078. {
  1079. strcat(hbuf, " (line ");
  1080. strcat(hbuf, itos(location.hist_line+1));
  1081. strcat(hbuf, ")");
  1082. }
  1083. }
  1084. show_info(ep,hbuf);
  1085. return;
  1086. }
  1087. # if 0 /* debugging, modify as required */
  1088. case cntl('D'): /* ^X^D show debugging info */
  1089. {
  1090. char debugbuf[MAXLINE];
  1091. strcpy(debugbuf, "count=");
  1092. strcat(debugbuf, itos(count));
  1093. strcat(debugbuf, " eol=");
  1094. strcat(debugbuf, itos(eol));
  1095. strcat(debugbuf, " cur=");
  1096. strcat(debugbuf, itos(cur));
  1097. strcat(debugbuf, " crallowed=");
  1098. strcat(debugbuf, itos(crallowed));
  1099. strcat(debugbuf, " plen=");
  1100. strcat(debugbuf, itos(plen));
  1101. strcat(debugbuf, " w_size=");
  1102. strcat(debugbuf, itos(w_size));
  1103. show_info(ep,debugbuf);
  1104. return;
  1105. }
  1106. # endif /* debugging code */
  1107. # endif /* ESH_BETTER */
  1108. #endif /* KSHELL */
  1109. default:
  1110. beep();
  1111. return;
  1112. }
  1113. }
  1114. static void search(Emacs_t* ep,genchar *out,int direction)
  1115. {
  1116. #ifndef ESH_NFIRST
  1117. Histloc_t location;
  1118. #endif
  1119. register int i,sl;
  1120. genchar str_buff[LBUF];
  1121. register genchar *string = drawbuff;
  1122. /* save current line */
  1123. int sav_cur = cur;
  1124. genncpy(str_buff,string,sizeof(str_buff)/sizeof(*str_buff));
  1125. string[0] = '^';
  1126. string[1] = 'R';
  1127. string[2] = '\0';
  1128. sl = 2;
  1129. cur = sl;
  1130. draw(ep,UPDATE);
  1131. while ((i = ed_getchar(ep->ed,1))&&(i != '\r')&&(i != '\n'))
  1132. {
  1133. if (i==usrerase || i==DELETE || i=='\b' || i==ERASECHAR)
  1134. {
  1135. if (sl > 2)
  1136. {
  1137. string[--sl] = '\0';
  1138. cur = sl;
  1139. draw(ep,UPDATE);
  1140. }
  1141. else
  1142. beep();
  1143. continue;
  1144. }
  1145. if (i==usrkill)
  1146. {
  1147. beep();
  1148. goto restore;
  1149. }
  1150. if (i == '\\')
  1151. {
  1152. string[sl++] = '\\';
  1153. string[sl] = '\0';
  1154. cur = sl;
  1155. draw(ep,APPEND);
  1156. i = ed_getchar(ep->ed,1);
  1157. string[--sl] = '\0';
  1158. }
  1159. string[sl++] = i;
  1160. string[sl] = '\0';
  1161. cur = sl;
  1162. draw(ep,APPEND);
  1163. }
  1164. i = genlen(string);
  1165. if(ep->prevdirection == -2 && i!=2 || direction!=1)
  1166. ep->prevdirection = -1;
  1167. if (direction < 1)
  1168. {
  1169. ep->prevdirection = -ep->prevdirection;
  1170. direction = 1;
  1171. }
  1172. else
  1173. direction = -1;
  1174. if (i != 2)
  1175. {
  1176. #if SHOPT_MULTIBYTE
  1177. ed_external(string,(char*)string);
  1178. #endif /* SHOPT_MULTIBYTE */
  1179. strncpy(lstring,((char*)string)+2,SEARCHSIZE);
  1180. ep->prevdirection = direction;
  1181. }
  1182. else
  1183. direction = ep->prevdirection ;
  1184. location = hist_find(sh.hist_ptr,(char*)lstring,hline,1,direction);
  1185. i = location.hist_command;
  1186. if(i>0)
  1187. {
  1188. hline = i;
  1189. #ifdef ESH_NFIRST
  1190. hloff = location.hist_line = 0; /* display first line of multi line command */
  1191. #else
  1192. hloff = location.hist_line;
  1193. #endif /* ESH_NFIRST */
  1194. hist_copy((char*)out,MAXLINE, hline,hloff);
  1195. #if SHOPT_MULTIBYTE
  1196. ed_internal((char*)out,out);
  1197. #endif /* SHOPT_MULTIBYTE */
  1198. return;
  1199. }
  1200. if (i < 0)
  1201. {
  1202. beep();
  1203. #ifdef ESH_NFIRST
  1204. location.hist_command = hline;
  1205. location.hist_line = hloff;
  1206. #else
  1207. hloff = 0;
  1208. hline = histlines;
  1209. #endif /* ESH_NFIRST */
  1210. }
  1211. restore:
  1212. genncpy(string,str_buff,sizeof(str_buff)/sizeof(*str_buff));
  1213. cur = sav_cur;
  1214. return;
  1215. }
  1216. /* Adjust screen to agree with inputs: logical line and cursor */
  1217. /* If 'first' assume screen is blank */
  1218. /* Prompt is always kept on the screen */
  1219. static void draw(register Emacs_t *ep,Draw_t option)
  1220. {
  1221. #define NORMAL ' '
  1222. #define LOWER '<'
  1223. #define BOTH '*'
  1224. #define UPPER '>'
  1225. register genchar *sptr; /* Pointer within screen */
  1226. genchar nscreen[2*MAXLINE]; /* New entire screen */
  1227. genchar *ncursor; /* New cursor */
  1228. register genchar *nptr; /* Pointer to New screen */
  1229. char longline; /* Line overflow */
  1230. genchar *logcursor;
  1231. genchar *nscend; /* end of logical screen */
  1232. register int i;
  1233. nptr = nscreen;
  1234. sptr = drawbuff;
  1235. logcursor = sptr + cur;
  1236. longline = NORMAL;
  1237. ep->lastdraw = option;
  1238. if (option == FIRST || option == REFRESH)
  1239. {
  1240. ep->overflow = NORMAL;
  1241. ep->cursor = ep->screen;
  1242. ep->offset = 0;
  1243. ep->cr_ok = crallowed;
  1244. if (option == FIRST)
  1245. {
  1246. ep->scvalid = 1;
  1247. return;
  1248. }
  1249. *ep->cursor = '\0';
  1250. putstring(ep,Prompt); /* start with prompt */
  1251. }
  1252. /*********************
  1253. Do not update screen if pending characters
  1254. **********************/
  1255. if ((lookahead)&&(option != FINAL))
  1256. {
  1257. ep->scvalid = 0; /* Screen is out of date, APPEND will not work */
  1258. return;
  1259. }
  1260. /***************************************
  1261. If in append mode, cursor at end of line, screen up to date,
  1262. the previous character was a 'normal' character,
  1263. and the window has room for another character.
  1264. Then output the character and adjust the screen only.
  1265. *****************************************/
  1266. i = *(logcursor-1); /* last character inserted */
  1267. if ((option == APPEND)&&(ep->scvalid)&&(*logcursor == '\0')&&
  1268. print(i)&&((ep->cursor-ep->screen)<(w_size-1)))
  1269. {
  1270. putchar(ep->ed,i);
  1271. *ep->cursor++ = i;
  1272. *ep->cursor = '\0';
  1273. return;
  1274. }
  1275. /* copy the line */
  1276. ncursor = nptr + ed_virt_to_phys(ep->ed,sptr,nptr,cur,0,0);
  1277. nptr += genlen(nptr);
  1278. sptr += genlen(sptr);
  1279. nscend = nptr - 1;
  1280. if(sptr == logcursor)
  1281. ncursor = nptr;
  1282. /*********************
  1283. Does ncursor appear on the screen?
  1284. If not, adjust the screen offset so it does.
  1285. **********************/
  1286. i = ncursor - nscreen;
  1287. if ((ep->offset && i<=ep->offset)||(i >= (ep->offset+w_size)))
  1288. {
  1289. /* Center the cursor on the screen */
  1290. ep->offset = i - (w_size>>1);
  1291. if (--ep->offset < 0)
  1292. ep->offset = 0;
  1293. }
  1294. /*********************
  1295. Is the range of screen[0] thru screen[w_size] up-to-date
  1296. with nscreen[offset] thru nscreen[offset+w_size] ?
  1297. If not, update as need be.
  1298. ***********************/
  1299. nptr = &nscreen[ep->offset];
  1300. sptr = ep->screen;
  1301. i = w_size;
  1302. while (i-- > 0)
  1303. {
  1304. if (*nptr == '\0')
  1305. {
  1306. *(nptr + 1) = '\0';
  1307. *nptr = ' ';
  1308. }
  1309. if (*sptr == '\0')
  1310. {
  1311. *(sptr + 1) = '\0';
  1312. *sptr = ' ';
  1313. }
  1314. if (*nptr == *sptr)
  1315. {
  1316. nptr++;
  1317. sptr++;
  1318. continue;
  1319. }
  1320. setcursor(ep,sptr-ep->screen,*nptr);
  1321. *sptr++ = *nptr++;
  1322. #if SHOPT_MULTIBYTE
  1323. while(*nptr==MARKER)
  1324. {
  1325. if(*sptr=='\0')
  1326. *(sptr + 1) = '\0';
  1327. *sptr++ = *nptr++;
  1328. i--;
  1329. ep->cursor++;
  1330. }
  1331. #endif /* SHOPT_MULTIBYTE */
  1332. }
  1333. if(ep->ed->e_multiline && option == REFRESH && ep->ed->e_nocrnl==0)
  1334. ed_setcursor(ep->ed, ep->screen, ep->cursor-ep->screen, ep->ed->e_peol, -1);
  1335. /******************
  1336. Screen overflow checks
  1337. ********************/
  1338. if (nscend >= &nscreen[ep->offset+w_size])
  1339. {
  1340. if (ep->offset > 0)
  1341. longline = BOTH;
  1342. else
  1343. longline = UPPER;
  1344. }
  1345. else
  1346. {
  1347. if (ep->offset > 0)
  1348. longline = LOWER;
  1349. }
  1350. /* Update screen overflow indicator if need be */
  1351. if (longline != ep->overflow)
  1352. {
  1353. setcursor(ep,w_size,longline);
  1354. ep->overflow = longline;
  1355. }
  1356. i = (ncursor-nscreen) - ep->offset;
  1357. setcursor(ep,i,0);
  1358. if(option==FINAL && ep->ed->e_multiline)
  1359. setcursor(ep,nscend+1-nscreen,0);
  1360. ep->scvalid = 1;
  1361. return;
  1362. }
  1363. /*
  1364. * put the cursor to the <newp> position within screen buffer
  1365. * if <c> is non-zero then output this character
  1366. * cursor is set to reflect the change
  1367. */
  1368. static void setcursor(register Emacs_t *ep,register int newp,int c)
  1369. {
  1370. register int oldp = ep->cursor - ep->screen;
  1371. newp = ed_setcursor(ep->ed, ep->screen, oldp, newp, 0);
  1372. if(c)
  1373. {
  1374. putchar(ep->ed,c);
  1375. newp++;
  1376. }
  1377. ep->cursor = ep->screen+newp;
  1378. return;
  1379. }
  1380. #if SHOPT_MULTIBYTE
  1381. static int print(register int c)
  1382. {
  1383. return((c&~STRIP)==0 && isprint(c));
  1384. }
  1385. static int _isword(register int c)
  1386. {
  1387. return((c&~STRIP) || isalnum(c) || c=='_');
  1388. }
  1389. #endif /* SHOPT_MULTIBYTE */