ledLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:49k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* ledLib.c - line-editing library */
  2. /* Copyright 1984-2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02w,18oct01,fmk  add routine description to fix doc build errors
  8. 02v,27sep01,dcb  Fix SPR 21697.  Free the ledId that was allocated in ledOpen.
  9.                    Compiler warning clean up.
  10. 02u,14jul97,dgp  doc: change ^ to CTRL- in cursor movement descriptions
  11. 02t,31oct96,elp  Replaced symAdd() call by symSAdd() call (symtbls synchro).
  12. 02s,23nov93,jmm  ledRead now ignores NULL characters (spr 2666)
  13. 02r,20jan93,jdi  documentation cleanup for 5.1.
  14. 02q,19oct92,jcf  fixed esc-space garbage.
  15. 02p,23aug92,jcf  fixed esc-k garbage when first commaned.
  16. 02o,20jul92,jmm  added group parameter to symAdd call
  17. 02n,18jul92,smb  Changed errno.h to errnoLib.h.
  18. 02m,26may92,rrr  the tree shuffle
  19. 02l,19mar92,jmm  fixed problem in histAdd and histAll w/long lines in history
  20.                  SPR #1381
  21. 02k,20dec91,gae  stopped blow ups when using history for first time.
  22.  removed nulls from output stream in histAll().
  23. 02j,10dec91,gae  added includes for ANSI.
  24. 02i,04oct91,rrr  passed through the ansification filter
  25.                   -changed functions to ansi style
  26.   -changed includes to have absolute path from h/
  27.   -fixed #else and #endif
  28.   -changed VOID to void
  29.   -changed copyright notice
  30. 02h,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  31.  doc review by gae.
  32. 02g,08feb91,jaa  documentation cleanup.
  33. 02f,25oct90,gae  fixed ignoring of previously set ty options - per Hdei Nunoe.
  34. 02e,10aug90,dnw  changed declaration of ledClose from void to STATUS.
  35. 02d,10aug90,kdl  added forward declarations for functions returning void.
  36. 02c,11may90,yao  added missing modification history (02b) for the last checkin.
  37. 02b,09may90,yao  typecasted malloc to (char *).
  38. 02a,15apr90,jcf  changed symbol type to SYM_TYPE.
  39. 01z,14mar90,jdi  documentation cleanup.
  40. 01y,22feb90,dab  fixed glitch in ledRead()'s 's' cmd. documentation.
  41. 01x,10nov89,dab  fixed 'x' cmd bug in ledRead(). fixed bfill() bug in ledRead().
  42.    fixed EOF bug in ledRead(). added 's' cmd to ledRead()'s vi
  43.    interface.
  44. 01w,13jun89,gae  fixed glitch in 01v caused by histSize not being init'd.
  45. 01v,01may89,dab  histInit() now keeps past history when size is changed.
  46. 01u,24sep88,gae  documentation touchup.
  47. 01t,30aug88,gae  documentation.
  48. 01s,10aug88,gae  fixed "static" bug in histInit()
  49. 01r,22jun88,dnw  changed bmove() to bcopy() since bcopy() now handles
  50.    overlapping buffers.
  51. 01q,30may88,dnw  changed to v4 names.
  52. 01p,09nov87,gae  changed name (again) from kornLib.c.
  53. 01o,03nov87,ecs  documenation.
  54. 01n,02nov87,gae  documenation.
  55. 01m,24oct87,gae  changed name from shellLib.c.  Fixed history mechanism:
  56.    added histInit() and removed built-in "h".
  57. 01l,17aug87,gae  Made re-entrant, viz. useable by programs other than the shell.
  58.  Fixed history bug.  Added symbol name completion.
  59. 01k,24jul87,gae  imported ty{Backspace,DeleteLine,Eof}Char's from tyLib.c
  60.    and used instead of constants.
  61. 01j,07apr87,jlf  deleted shHistDelete, which was unused, to appease lint.
  62. 01i,01apr87,ecs  delinted.
  63. 01h,19mar87,jlf  added copyright.
  64.    +gae  minor fixes for mangen.
  65.  documentation.
  66. 01g,12mar87,gae  little fix in shHistFind() for bug with 'n'.
  67. 01f,02feb87,gae  added writex() so control chars will be printed as '?';
  68.    also done in shHistAll().  Improved motion (maybe);
  69.    added redraw (^L); made undo nicer; allowed replace to
  70.    be cancelled with ESC; fixed shHistFind() bug.
  71.  Added UNIX_DEBUG ability.
  72. 01e,19jan87,gae  included memLib.h to appease lint.
  73. 01d,14jan87,gae  made history use a free list, history search works
  74.    within lines not just at beginning, command mode default
  75.    after search, made history number increment properly;
  76.    saved space by making curLn a pointer to the user's string,
  77.    and more...
  78. 01c,20dec86,dnw  changed to not get include files from default directories.
  79.  replaced spaces[] and bksps[] with writen() (vax compiler
  80.    complained about line too long).
  81. 01b,18dec86,gae  various bug fixes & improvements.
  82. 01a,23oct86,gae  written
  83. */
  84. /*
  85. DESCRIPTION
  86. This library provides a line-editing layer on top of a `tty' device.
  87. The shell uses this interface for its history-editing features.
  88. The shell history mechanism is similar to the UNIX Korn shell history
  89. facility, with a built-in line-editor similar to UNIX f3vifP that allows
  90. previously typed commands to be edited.  The command h() displays the 20
  91. most recent commands typed into the shell; old commands fall off the top
  92. as new ones are entered.
  93. To edit a command, type ESC to enter edit mode, and use the commands
  94. listed below.  The ESC key switches the shell to edit mode.  The RETURN
  95. key always gives the line to the shell from either editing or input mode.
  96. The following list is a summary of the commands available in edit mode.
  97. .TS
  98. tab(|);
  99. l s
  100. lf9 l.
  101. Movement and search commands:
  102. .sp .25
  103. <n>G | - Go to command number <n>.
  104. /<s> | - Search for string <s> backward in history.
  105. ?<s> | - Search for string <s> forward in history.
  106. n | - Repeat last search.
  107. N | - Repeat last search in opposite direction.
  108. <n>k | - Get <n>th previous shell command in history.
  109. <n>- | - Same as "k".
  110. <n>j | - Get <n>th next shell command in history.
  111. <n>+ | - Same as "j".
  112. <n>h | - Move left <n> characters.
  113. CTRL-H | - Same as "h".
  114. <n>l | - Move right <n> characters.
  115. f1SPACEfP | - Same as "l".
  116. <n>w | - Move <n> words forward.
  117. <n>W | - Move <n> blank-separated words forward.
  118. <n>e | - Move to end of the <n>th next word.
  119. <n>E | - Move to end of the <n>th next blank-separated word.
  120. <n>b | - Move back <n> words.
  121. <n>B | - Move back <n> blank-separated words.
  122. f<c> | - Find character <c>, searching forward.
  123. F<c> | - Find character <c>, searching backward.
  124. ^ | - Move cursor to first non-blank character in line.
  125. $ | - Go to end of line.
  126. 0 | - Go to beginning of line.
  127. .T&
  128. l s
  129. lf9 l.
  130. Insert commands (input is expected until an ESC is typed):
  131. .sp .25
  132. a | - Append.
  133. A | - Append at end of line.
  134. c f1SPACEfP | - Change character.
  135. cl | - Change character.
  136. cw | - Change word.
  137. cc | - Change entire line.
  138. c$ | - Change everything from cursor to end of line.
  139. C | - Same as "c$".
  140. S | - Same as "cc".
  141. i | - Insert.
  142. I | - Insert at beginning of line.
  143. R | - Type over characters.
  144. .T&
  145. l s
  146. lf9 l.
  147. Editing commands:
  148. .sp .25
  149. <n>r<c> | - Replace the following <n> characters with <c>.
  150. <n>x | - Delete <n> characters starting at cursor.
  151. <n>X | - Delete <n> characters to the left of the cursor.
  152. d f1SPACEfP | - Delete character.
  153. dl | - Delete character.
  154. dw | - Delete word.
  155. dd | - Delete entire line.
  156. d$ | - Delete everything from cursor to end of line.
  157. D | - Same as "d$".
  158. p | - Put last deletion after the cursor.
  159. P | - Put last deletion before the cursor.
  160. u | - Undo last command.
  161. ~ | - Toggle case, lower to upper or vice versa.
  162. .T&
  163. l s
  164. lf9 l.
  165. Special commands:
  166. .sp .25
  167. CTRL-U | - Delete line and leave edit mode.
  168. CTRL-L | - Redraw line.
  169. CTRL-D | - Complete symbol name.
  170. f1RETURNfP | - Give line to shell and leave edit mode.
  171. .TE
  172. The default value for <n> is 1.
  173. DEFICIENCIES
  174. Since the shell toggles between raw mode and line mode, type-ahead can be
  175. lost.  The ESC, redraw, and non-printable characters are built-in.  The
  176. EOF, backspace, and line-delete are not imported well from tyLib.
  177. Instead, tyLib should supply and/or support these characters
  178. via ioctl().
  179. Some commands do not take counts as users might expect.  For example,
  180. "<n>i" will not insert whatever was entered <n> times.
  181. INCLUDE FILES: ledLib.h
  182. SEE ALSO:
  183. .pG "Shell"
  184. INTERNAL
  185. LINE_LEN should be specifed elsewhere.
  186. In an attempt to economize shell stack space, the "string" parameter is
  187. written in up to LINE_LEN!  An EOS is used at the beginning of the string
  188. as well, thus only LINE_LEN-1 places are returned.
  189. */
  190. #include "vxWorks.h"
  191. #include "ctype.h"
  192. #include "errnoLib.h"
  193. #include "ioLib.h"
  194. #include "lstLib.h"
  195. #include "memLib.h"
  196. #include "stdlib.h"
  197. #include "stdio.h"
  198. #include "unistd.h"
  199. #include "string.h"
  200. #include "iosLib.h"
  201. #include "sysSymTbl.h"
  202. #include "symLib.h"
  203. #include "symbol.h"
  204. /* to debug under UNIX:
  205. cc -O -I$vh -DPORTABLE -c bLib.c
  206. cc -O -I$vh -DUNIX_DEBUG -o ledLib ledLib.c $v/lib/host/vxWorks.a symLib.o bLib.o
  207. */
  208. #ifdef UNIX_DEBUG
  209. #undef EOF
  210. #undef NULL
  211. #include "stdio.h"
  212. char tyBackspaceChar = 0x08; /* default is control-H */
  213. char tyDeleteLineChar = 0x15; /* default is control-U */
  214. char tyEofChar = 0x04; /* default is control-D */
  215. SYMTAB_ID sysSymTbl;
  216. #endif /* UNIX_DEBUG */
  217. IMPORT char tyBackspaceChar; /* default is control-H */
  218. IMPORT char tyDeleteLineChar; /* default is control-U */
  219. IMPORT char tyEofChar; /* default is control-D */
  220. #define CMP_CHAR 0x04 /* symbol name completion */
  221. #define BEL_CHAR 0x07 /* bell */
  222. #define RET_CHAR 'n' /* return */
  223. #define ESC_CHAR 0x1b /* escape */
  224. #define NON_CHAR '?' /* non-printable char. representation */
  225. #define RDW_CHAR 0x0c /* redraw */
  226. #define LINE_LEN 128 /* >= MAX_SHELL_LINE! */
  227. #define BACKWARD (-1)
  228. #define FORWARD 1
  229. #define save()     if (strlen (saveLn) == 0) strcpy (saveLn, curLn)
  230. typedef struct /* CMP_ARG */
  231.     {
  232.     int count;
  233.     int nameLen;
  234.     char *name;
  235.     char *match;
  236.     } CMP_ARG;
  237. typedef struct /* HIST */
  238.     {
  239.     NODE node;
  240.     char line [LINE_LEN+1];
  241.     } HIST;
  242. typedef struct /* LED */
  243.     {
  244.     int inFd;
  245.     int outFd;
  246.     int histSize;
  247.     LIST histFreeList;
  248.     LIST histList;
  249.     HIST *pHist;
  250.     /* XXX the following are not needed between ledRead's
  251.      *     but are used in support routines.
  252.      */
  253.     char *buffer; /* hold deletions from curLn */
  254.     int histNum; /* current history number */
  255.     BOOL cmdMode; /* insert or command mode */
  256.     } LED;
  257. typedef LED *LED_ID;
  258. /* forward static functions */
  259. static void setPreempt (FUNCPTR *catchFunc, FUNCPTR func);
  260. static int preempt (FUNCPTR *catchFunc, char ch, char *curLn, int *curPs, int
  261. *number, LED_ID ledId);
  262. static void redraw (int outFd, char *oldLn, int lastPs, char *curLn, int
  263. *curPs);
  264. static BOOL completeName (char *curLn, int *curPs);
  265. static BOOL findName (char *name, char *value, SYM_TYPE type, CMP_ARG *arg);
  266. static void search (BOOL ignorePunct, BOOL endOfWord, char *curLn, int
  267. *curPs, int dir);
  268. static BOOL find (char ch, char *curLn, int *curPs, int dir);
  269. static STATUS findFwd (char ch, char *curLn, int *curPs, int *number);
  270. static STATUS findBwd (char ch, char *curLn, int *curPs, int *number);
  271. static STATUS change (char ch, char *curLn, int *curPs, int *number, LED_ID
  272. ledId);
  273. static STATUS deletec (char ch, char *curLn, int *curPs, int *number, LED_ID
  274. ledId);
  275. static STATUS replace (char ch, char *curLn, int *curPs, int *number);
  276. static void beep (int outFd);
  277. static int writex (int fd, char buffer [ ], int nbytes);
  278. static int writen (int fd, char ch, int nbytes);
  279. static void histInit (LED_ID ledId, int histSize);
  280. static void histAdd (LED_ID ledId, char *line);
  281. static BOOL histNum (LED_ID ledId, char *line, int n);
  282. static STATUS histNext (LED_ID ledId, char *line);
  283. static STATUS histPrev (LED_ID ledId, char *line);
  284. static BOOL histFind (LED_ID ledId, char *match, char *line);
  285. static void histAll (LED_ID ledId);
  286. /*******************************************************************************
  287. *
  288. * ledOpen - create a new line-editor ID
  289. *
  290. * This routine creates the ID that is used by ledRead(), ledClose(), and
  291. * ledControl().  Storage is allocated for up to <histSize> previously read
  292. * lines.
  293. *
  294. * RETURNS: The line-editor ID, or ERROR if the routine runs out of memory.
  295. *
  296. * SEE ALSO: ledRead(), ledClose(), ledControl()
  297. */
  298. int ledOpen
  299.     (
  300.     int inFd,           /* low-level device input fd */
  301.     int outFd,          /* low-level device output fd */
  302.     int histSize        /* size of history list */
  303.     )
  304.     {
  305.     LED_ID ledId = (LED_ID)calloc (1, sizeof (LED));
  306.     if (ledId == NULL)
  307. return (ERROR);
  308.     if ((ledId->buffer = (char *) malloc (LINE_LEN + 1)) == NULL)
  309. return (ERROR);
  310.     ledId->inFd  = inFd;
  311.     ledId->outFd = outFd;
  312.     lstInit (&ledId->histList);
  313.     lstInit (&ledId->histFreeList);
  314.     histInit (ledId, histSize);
  315.     return ((int) ledId);
  316.     }
  317. /*******************************************************************************
  318. *
  319. * ledClose - discard the line-editor ID
  320. *
  321. * This routine frees resources allocated by ledOpen().  The low-level
  322. * input/output file descriptors are not closed.
  323. *
  324. * RETURNS: OK.
  325. *
  326. * SEE ALSO: ledOpen()
  327. */
  328. STATUS ledClose
  329.     (
  330.     int led_id          /* ID returned by ledOpen */
  331.     )
  332.     {
  333.     FAST LED_ID ledId = (LED_ID)led_id;
  334.     lstFree (&ledId->histList);
  335.     lstFree (&ledId->histFreeList);
  336.     free (ledId->buffer);
  337.     free (ledId);
  338.     
  339.     return (OK);
  340.     }
  341. /*******************************************************************************
  342. *
  343. * ledRead - read a line with line-editing
  344. *
  345. * This routine handles line-editing and history substitutions.
  346. * If the low-level input file descriptor is not in OPT_LINE mode,
  347. * only an ordinary read() routine will be performed.
  348. *
  349. * RETURNS: The number of characters read, or EOF.
  350. */
  351. int ledRead
  352.     (
  353.     int led_id,         /* ID returned by ledOpen */
  354.     char *string,       /* where to return line */
  355.     int maxBytes        /* maximum number of chars to read */
  356.     )
  357.     {
  358.     FAST LED_ID ledId = (LED_ID)led_id;
  359.     FAST int ix; /* the ubiquitous */
  360.     char ch; /* last character entered */
  361.     BOOL overStrike = FALSE; /* in over-strike mode */
  362.     BOOL srchMode = FALSE; /* entering search characters */
  363.     BOOL done = FALSE; /* return has been entered */
  364.     int returnVal = EOF; /* number of characters or EOF */
  365.     int result; /* return value from preempt */
  366.     char oldLn  [LINE_LEN+1]; /* current line before most recent input*/
  367.     char saveLn [LINE_LEN+1]; /* saved version of line before changes */
  368.     char histLn [LINE_LEN+1]; /* last version of historical line */
  369.     char *curLn; /* current line, points to user's string*/
  370.     int curPs = 0; /* current cursor position */
  371.     int lastPs = 0; /* last position cursor was at */
  372.     int number = 0; /* repeat factor */
  373.     FUNCPTR catchFunc; /* preempt routine */
  374. #ifndef UNIX_DEBUG
  375.     int oldoptions = ioctl (ledId->inFd, FIOGETOPTIONS, 0 /*XXX*/);
  376.     /* XXX should be check for ERROR except an option might be 0xff,
  377.      * perhaps inspect errno for valid 'fd', or something.
  378.      */
  379.     /* if not in line mode, just do plain read */
  380.     if (!(oldoptions & OPT_LINE))
  381. return (read (ledId->inFd, string, maxBytes));
  382.     /* turn off echo & line mode */
  383.     ioctl (ledId->inFd, FIOSETOPTIONS, oldoptions & ~(OPT_LINE | OPT_ECHO));
  384. #endif /* UNIX_DEBUG */
  385.     bzero (string, maxBytes);
  386.     string [0] = EOS; /* Beginning Of String */
  387.     curLn = &string [1]; /* reserve position 0 for EOS (BOS) */
  388.     saveLn [0] = EOS;
  389.     histLn [0] = EOS;
  390.     setPreempt (&catchFunc, (FUNCPTR) NULL);
  391.     ledId->buffer [0] = EOS;
  392.     ledId->cmdMode = FALSE;
  393.     bfill (oldLn, LINE_LEN+1, EOS);
  394.     bfill (curLn, maxBytes - 1, EOS); /* -1 cause of BOS */
  395.     /* operation:
  396.      *    redraw line,
  397.      *    read next character,
  398.      *    based on command/input mode perform appropriate action,
  399.      *    loop.
  400.      */
  401.     while (! done)
  402. {
  403. redraw (ledId->outFd, oldLn, lastPs, curLn, &curPs);
  404. lastPs = curPs;
  405. strcpy (oldLn, curLn);
  406. if (read (ledId->inFd, &ch, 1) < 1)
  407.     {
  408.     done = TRUE;
  409.     returnVal = EOF;
  410.     break;
  411.     }
  412. /* Ignore NULL in the input stream */
  413. if (ch == (char)NULL)
  414.     continue;
  415. /* some function wants to preempt? */
  416. result = preempt (&catchFunc, ch, curLn, &curPs, &number, ledId);
  417. if (result == ERROR)
  418.     {
  419.     beep (ledId->outFd);
  420.     continue; /* short-cut loop */
  421.     }
  422. else if (result == OK)
  423.     continue; /* short-cut loop */
  424. if (ledId->cmdMode)
  425.     {
  426.     /* parse command */
  427.     if (ch == tyBackspaceChar)
  428. ch = 'h';
  429.     if (ch == tyDeleteLineChar)
  430. {
  431. ledId->cmdMode = FALSE;
  432. curLn [0] = EOS;
  433. curPs = 0;
  434. }
  435.     else switch (ch)
  436. {
  437. case 'G':
  438.     save();
  439.     if (number < 1)
  440. number = 1;
  441.     if (histNum (ledId, curLn, number))
  442. curPs = 0;
  443.     else
  444. beep (ledId->outFd);
  445.     number = 0;
  446.     break;
  447. case '/':
  448. case '?':
  449.     strcpy (saveLn, curLn);
  450.     srchMode = TRUE;
  451.     ledId->cmdMode = FALSE;
  452.     curLn [0] = ch;
  453.     curLn [1] = EOS;
  454.     curPs = 1;
  455.     break;
  456. case 'n':
  457. case 'N':
  458.     if (histLn [0] == EOS)
  459. {
  460. beep (ledId->outFd);
  461. break;
  462. }
  463.     save ();
  464.     if (ch == 'N')
  465. histLn [0] = histLn [0] == '/' ? '?' : '/';
  466.     if (! histFind (ledId, histLn, curLn))
  467. {
  468. beep (ledId->outFd);
  469. curLn [0] = EOS;
  470. }
  471.     curPs = 0;
  472.     break;
  473. case 'k':
  474. case '-':
  475.     save ();
  476.     do
  477. {
  478. if (histPrev (ledId, curLn) == ERROR)
  479.     {
  480.     beep (ledId->outFd);
  481.     break;
  482.     }
  483. }
  484.     while (--number > 0);
  485.     number = 0;
  486.     curPs = 0;
  487.     break;
  488. case 'j':
  489. case '+':
  490.     save ();
  491.     do
  492. {
  493. if (histNext (ledId, curLn) == ERROR)
  494.     {
  495.     beep (ledId->outFd);
  496.     break;
  497.     }
  498. }
  499.     while (--number > 0);
  500.     number = 0;
  501.     curPs = 0;
  502.     break;
  503. case 'h':
  504.     do
  505. {
  506. if (curPs > 0)
  507.     curPs--;
  508. }
  509.     while (--number > 0);
  510.     number = 0;
  511.     break;
  512. case 'l':
  513. case ' ':
  514.     do
  515. {
  516. if ((strlen (curLn) != 0)&&(curPs < strlen (curLn) - 1))
  517.     curPs++;
  518. }
  519.     while (--number > 0);
  520.     number = 0;
  521.     break;
  522. case 'w':
  523. case 'W': /* ignore punctuation */
  524. case 'b':
  525. case 'B': /* ignore punctuation */
  526. case 'e':
  527. case 'E': /* ignore punctuation */
  528.     {
  529.     int origPs = curPs;
  530.     int dir = (ch == 'b' || ch == 'B') ? BACKWARD :FORWARD;
  531.     BOOL word = ch != 'w' && ch != 'W';
  532.     do
  533. {
  534. search (isupper ((int)ch), word, curLn, &curPs, dir);
  535. }
  536.     while (curPs != origPs && --number > 0);
  537.     number = 0;
  538.     break;
  539.     }
  540. case 'f':
  541. case 't': /* doesn't backward step
  542.  * XXX - not implemented */
  543.     setPreempt (&catchFunc, (FUNCPTR)findFwd);
  544.     break;
  545. case 'F':
  546. case 'T': /* doesn't forward step
  547.  * XXX - not implemented */
  548.     setPreempt (&catchFunc, (FUNCPTR)findBwd);
  549.     break;
  550. case 'r':
  551.     strcpy (saveLn, curLn);
  552.     setPreempt (&catchFunc, (FUNCPTR)replace);
  553.     break;
  554. case 'R':
  555.     strcpy (saveLn, curLn);
  556.     overStrike = TRUE;
  557.     ledId->cmdMode = FALSE;
  558.     break;
  559. case 'A':
  560.     curPs = strlen (curLn);
  561.     /* drop thru */
  562. case 'a':
  563.     ledId->cmdMode = FALSE;
  564.     strcpy (saveLn, curLn);
  565.     if (curPs < strlen (curLn))
  566. curPs++;
  567.     break;
  568. case 'x':
  569.     strcpy (saveLn, curLn);
  570.     number = min (number, strlen (curLn) - curPs);
  571.     ix = 0;
  572.     do
  573. {
  574. ledId->buffer [ix++] = curLn [curPs];
  575. if (curPs < strlen (curLn) - 1)
  576.     strcpy (&curLn [curPs], &curLn [curPs + 1]);
  577. else
  578.     {
  579.     curLn [curPs] = EOS;
  580.     if (curPs > 0)
  581. curPs--;
  582.     else
  583. break;
  584.     }
  585. }
  586.     while (--number > 0);
  587.     number = 0;
  588.     ledId->buffer [ix] = EOS;
  589.     break;
  590. case 'X':
  591.     strcpy (saveLn, curLn);
  592.     ix = 0;
  593.     do
  594. {
  595. if (curPs > 0)
  596.     {
  597.     curPs--;
  598.     ledId->buffer [ix++] = curLn [curPs];
  599.     strcpy (&curLn [curPs], &curLn [curPs + 1]);
  600.     }
  601. else if (strlen (curLn) == 1)
  602.     {
  603.     ledId->buffer [ix++] = curLn [curPs];
  604.     curLn [curPs] = EOS;
  605.     }
  606. else
  607.     break;
  608. }
  609.     while (--number > 0);
  610.     number = 0;
  611.     ledId->buffer [ix] = EOS;
  612.     break;
  613. case 'c':
  614.     strcpy (saveLn, curLn);
  615.     setPreempt (&catchFunc, (FUNCPTR)change);
  616.     break;
  617. case 'C':
  618.     strcpy (saveLn, curLn);
  619.     ledId->cmdMode = FALSE;
  620.     curLn [curPs] = EOS;
  621.     break;
  622.                 case 's':
  623.                     strcpy (saveLn, curLn);
  624.     number = number ? number : 1;
  625.     ix = 0;
  626.                     if (number >= strlen (curLn) - curPs)
  627.                         curLn [curPs] = EOS;
  628.                     else
  629.                         {
  630.                         do
  631.                             {
  632.                             ledId->buffer [ix++] = curLn [curPs];
  633.                             if (curPs < strlen (curLn) - 1)
  634.                                 strcpy (&curLn [curPs], &curLn [curPs + 1]);
  635.                             else
  636.                                 {
  637.                                 curLn [curPs] = EOS;
  638.                                 if (curPs > 0)
  639.                                     curPs--;
  640.                                 else
  641.                                     break;
  642.                                 }
  643.                             }
  644.                         while (--number > 0);
  645.                         }
  646.                     number = 0;
  647.                     ledId->buffer [ix] = EOS;
  648.                     ledId->cmdMode = FALSE;
  649.                     break;
  650. case 'S':
  651.     strcpy (saveLn, curLn);
  652.     if (change ('c', curLn, &curPs, &number, ledId) == ERROR)
  653. beep (ledId->outFd);
  654.     break;
  655. case 'd':
  656.     strcpy (saveLn, curLn);
  657.     setPreempt (&catchFunc, (FUNCPTR)deletec);
  658.     break;
  659. case 'D':
  660.     strcpy (saveLn, curLn);
  661.     strncpy (ledId->buffer, &curLn [curPs],
  662.      strlen (&curLn [curPs]) + 1); /* +EOS */
  663.     curLn [curPs] = EOS;
  664.     if (curPs > 0)
  665. curPs--;
  666.     break;
  667. case 'I':
  668.     curPs = 0;
  669.     /* drop thru */
  670. case 'i':
  671.     strcpy (saveLn, curLn);
  672.     number = 0; /* can't handle "count" */
  673.     ledId->cmdMode = FALSE;
  674.     break;
  675. case 'p':
  676.     if (strlen (ledId->buffer) == 0)
  677. break;
  678.     if (strlen (curLn) == 0)
  679. goto caseP; /* treat like 'P' */
  680.     number = 0; /* can't handle "count" */
  681.     if (strlen (curLn) + strlen (ledId->buffer) < maxBytes)
  682. {
  683. strcpy (saveLn, curLn);
  684. if (++curPs < strlen (curLn))
  685.     {
  686.     /* insert buffer into curLn */
  687.     bcopy (&curLn [curPs],
  688.    &curLn [curPs + strlen (ledId->buffer)],
  689.    strlen (&curLn [curPs]) + 1); /* +EOS */
  690.     bcopy (ledId->buffer, &curLn [curPs],
  691.    strlen (ledId->buffer));
  692.     }
  693. else
  694.     /* buffer goes after curLn */
  695.     strcat (curLn, ledId->buffer);
  696. curPs += strlen (ledId->buffer) - 1;
  697. }
  698.     else
  699. beep (ledId->outFd);
  700.     break;
  701. case 'P':
  702. caseP:
  703.     number = 0; /* can't handle "count" */
  704.     if (strlen (ledId->buffer) == 0)
  705. break;
  706.     if (strlen (curLn) + strlen (ledId->buffer) < maxBytes)
  707. {
  708. strcpy (saveLn, curLn);
  709. /* insert buffer into curLn */
  710. bcopy (&curLn [curPs],
  711.        &curLn [curPs + strlen (ledId->buffer)],
  712.        strlen (&curLn [curPs]) + 1); /* +EOS */
  713. bcopy (ledId->buffer, &curLn [curPs],
  714.        strlen (ledId->buffer));
  715. if (curPs == 0)
  716.     curPs--;
  717. curPs += strlen (ledId->buffer);
  718. }
  719.     else
  720. beep (ledId->outFd);
  721.     break;
  722. case 'u':
  723. case 'U': /* restore original line
  724.  * XXX - not implemented */
  725.     if (strlen (saveLn) != 0)
  726. {
  727. bswap (curLn, saveLn,
  728.        max (strlen (curLn), strlen (saveLn)) + 1);
  729.   /* +EOS */
  730. if (curPs == strlen (saveLn) - 1 ||
  731.     curPs > strlen (curLn))
  732.     {
  733.     curPs = strlen (curLn) - 1;
  734.     }
  735. }
  736.     else
  737. beep (ledId->outFd);
  738.     break;
  739. case RET_CHAR:
  740.     done = TRUE;
  741.     returnVal = strlen (curLn);
  742.     break;
  743. case '$':
  744.     curPs = strlen (curLn) - 1;
  745.     break;
  746. case '0':
  747.     if (number == 0)
  748. {
  749. curPs = 0;
  750. break;
  751. }
  752.     /* drop thru */
  753. case '1': case '2': case '3': case '4':
  754. case '5': case '6': case '7': case '8': case '9':
  755.     if (number < 0)
  756. number = 0;
  757.     number = number * 10 + (ch - '0');
  758.     break;
  759. case '~':
  760.     strcpy (saveLn, curLn);
  761.     ch = curLn [curPs];
  762.     if (isalpha ((int)ch))
  763. curLn [curPs] = islower ((int)ch) ? toupper ((int)ch)
  764.     : tolower (ch);
  765.     if (curPs < strlen (curLn) - 1)
  766. curPs++;
  767.     break;
  768. case '^':
  769.     for (curPs = 0;
  770.  curLn [curPs] != EOS && isspace ((int)curLn[curPs]);
  771.  curPs++)
  772.  ;
  773.     break;
  774. case RDW_CHAR:
  775.     write (ledId->outFd, "n", 1);
  776.     (void)writen (ledId->outFd, ' ', curPs);
  777.     strcpy (oldLn, "");
  778.     break;
  779. case CMP_CHAR:
  780.     strcpy (saveLn, curLn);
  781.     if (! completeName (curLn, &curPs))
  782. beep (ledId->outFd);
  783.     break;
  784. default:
  785.     beep (ledId->outFd);
  786.     break;
  787. }
  788.     }
  789. else
  790.     {
  791.     /* input mode */
  792.     if (ch == tyEofChar && curPs == 0)
  793. {
  794. /* only return EOF when used at the beginning of line */
  795. done = TRUE;
  796. returnVal = EOF;
  797. }
  798.     else if (ch == tyBackspaceChar)
  799. {
  800. if (curPs > 0)
  801.     {
  802.     strcpy (&curLn [curPs - 1], &curLn [curPs]);
  803.     curPs--;
  804.     }
  805. }
  806.     else if (ch == tyDeleteLineChar)
  807. {
  808. curLn [0] = EOS;
  809. curPs = 0;
  810. }
  811.     else switch (ch)
  812. {
  813. case ESC_CHAR:
  814.     overStrike = FALSE;
  815.     if (! srchMode)
  816. {
  817. ledId->cmdMode = TRUE;
  818. if (curPs > 0)
  819.     curPs--;
  820. break;
  821. }
  822.     /* drop thru */
  823. case RET_CHAR:
  824.     if (srchMode)
  825. {
  826. if (strcmp (curLn, "/") == 0 || strcmp (curLn, "?") ==0)
  827.     /* just use previous history search */
  828.     strcpy (curLn, histLn);
  829. else
  830.     /* new history search */
  831.     strcpy (histLn, curLn);
  832. if (! histFind (ledId, histLn, curLn))
  833.     {
  834.     curLn [0] = EOS;
  835.     beep (ledId->outFd);
  836.     }
  837. curPs = 0;
  838. srchMode = FALSE;
  839. ledId->cmdMode = TRUE;
  840. }
  841.     else
  842. {
  843. done = TRUE;
  844. returnVal = strlen (curLn);
  845. }
  846.     break;
  847. case CMP_CHAR:
  848.     strcpy (saveLn, curLn);
  849.     if (! completeName (curLn, &curPs))
  850. beep (ledId->outFd);
  851.     else
  852. /*
  853. if (isalpha(curLn [curPs]) || isdigit(curLn[curPs]) ||
  854. curLn [curPs] == '_')
  855. */
  856. while (isalpha((int)curLn [curPs]) ||
  857. isdigit((int)curLn[curPs]) ||
  858. curLn [curPs] == '_')
  859.     {
  860.     curPs++;
  861.     }
  862.     break;
  863. default:
  864.     if (strlen (curLn) < maxBytes)
  865. {
  866. if (overStrike && curPs < strlen (curLn))
  867.     curLn [curPs++] = ch;
  868. else
  869.     {
  870.     bcopy (&curLn [curPs], &curLn [curPs + 1],
  871.    strlen (&curLn [curPs]) + 1); /* + EOS */
  872.     curLn [curPs++] = ch;
  873.     }
  874. }
  875.     else
  876. beep (ledId->outFd);
  877.     break;
  878. }
  879.     }
  880. }
  881.     if (returnVal == EOF)
  882. {
  883. #ifndef UNIX_DEBUG
  884. /* turn echo & line mode back on */
  885. ioctl(ledId->inFd, FIOSETOPTIONS, oldoptions);
  886. #endif /* UNIX_DEBUG */
  887. return (EOF);
  888. }
  889.     histAdd (ledId, curLn);
  890.     write (ledId->outFd, "n", 1);
  891.     /* must fix up BOS */
  892.     bcopy (&string [1], &string [0], strlen (curLn) + 1); /* +EOS */
  893. #ifndef UNIX_DEBUG
  894.     /* turn echo & line mode back on */
  895.     ioctl (ledId->inFd, FIOSETOPTIONS, oldoptions);
  896. #endif /* UNIX_DEBUG */
  897.     return (returnVal);
  898.     }
  899. /*******************************************************************************
  900. *
  901. * ledControl - change the line-editor ID parameters
  902. *
  903. * This routine changes the input/output file
  904. * descriptor and the size of the history list.
  905. *
  906. * RETURNS: N/A
  907. */
  908. void ledControl
  909.     (
  910.     int led_id,    /* ID returned by ledOpen */
  911.     int inFd,      /* new input fd (NONE = no change) */
  912.     int outFd,     /* new output fd (NONE = no change) */
  913.     int histSize   /* new history list size (NONE = no change), (0 = display) */
  914.     )
  915.     {
  916.     FAST LED_ID ledId = (LED_ID)led_id;
  917.     if (inFd >= 0)
  918. ledId->inFd = inFd;
  919.     if (outFd >= 0)
  920. ledId->outFd = outFd;
  921.     if (histSize == 0)
  922. histAll (ledId);
  923.     if (histSize > 0)
  924. histInit (ledId, histSize);
  925.     }
  926. /*******************************************************************************
  927. *
  928. * setPreempt - set function to use next
  929. */
  930. LOCAL void setPreempt
  931.     (
  932.     FAST FUNCPTR *catchFunc,
  933.     FAST FUNCPTR func
  934.     )
  935.     {
  936.     *catchFunc = func;
  937.     }
  938. /*******************************************************************************
  939. *
  940. * preempt - perform preempt function if set
  941. *
  942. * If <catchFunc> is non-NULL then it is called using the
  943. * remaining arguments.
  944. *
  945. * RETURNS:
  946. *    result of preempt function, or
  947. *    1 if no function called
  948. */
  949. LOCAL int preempt
  950.     (
  951.     FAST FUNCPTR *catchFunc,    /* preempting function */
  952.     char ch,                    /* arguments to be */
  953.     char *curLn,                /* passed to th */
  954.     int *curPs,                 /* routine ... */
  955.     int *number,
  956.     LED_ID ledId
  957.     )
  958.     {
  959.     FUNCPTR tmpFunc = *catchFunc;
  960.     if (*catchFunc == (FUNCPTR)NULL)
  961. return (1); /* no function called */
  962.     /* clear the catch */
  963.     *catchFunc = (FUNCPTR) NULL;
  964.     return ((*tmpFunc) (ch, curLn, curPs, number, ledId));
  965.     }
  966. /*******************************************************************************
  967. *
  968. * redraw - redraw line
  969. *
  970. * From the previous line and position (oldLn & lastPs) redraw line to
  971. * reflect reality (curLn & curPs).
  972. *
  973. * Operation: compare new line with previous line,
  974. * optimize the number of characters redrawn and cursor motion.
  975. */
  976. LOCAL void redraw
  977.     (
  978.     int outFd,
  979.     char *oldLn,
  980.     int lastPs,
  981.     char *curLn,
  982.     int *curPs
  983.     )
  984.     {
  985.     FAST int ok1Ps; /* line is the same up to this position */
  986.     FAST int ok2Ps; /* line is the same from the far end to here */
  987.     /* find first difference */
  988.     for (ok1Ps = 0;
  989.  curLn [ok1Ps] == oldLn [ok1Ps] && curLn [ok1Ps] != EOS;
  990.  ok1Ps++)
  991. ;
  992.     /* find first difference from the far end if same length */
  993.     if (strlen (curLn) == strlen (oldLn))
  994. {
  995. for (ok2Ps = strlen (curLn);
  996.      curLn [ok2Ps] == oldLn [ok2Ps] && ok2Ps > 0;
  997.      ok2Ps--)
  998.     ;
  999. if (ok2Ps < strlen (curLn))
  1000.     ok2Ps++;
  1001. }
  1002.     else
  1003. ok2Ps = strlen (curLn);
  1004.     /* line is bad before cursor position */
  1005.     if (ok1Ps < lastPs)
  1006. {
  1007. /* back up */
  1008. (void)writen (outFd, 'b', lastPs - ok1Ps);
  1009. /* redraw line from ok1Ps to the good portion */
  1010. (void)writex (outFd, &curLn [ok1Ps], ok2Ps - ok1Ps);
  1011. lastPs = ok2Ps;
  1012. }
  1013.     /* line is bad after cursor position */
  1014.     else if (ok2Ps > lastPs)
  1015. {
  1016. /* draw line from lastPs to the good portion */
  1017. (void)writex (outFd, &curLn [lastPs], ok2Ps - lastPs);
  1018. lastPs = ok2Ps;
  1019. }
  1020.     /* line is bad at cursor position */
  1021.     else if (ok2Ps == lastPs && lastPs < strlen (curLn))
  1022. {
  1023. /* draw single character */
  1024. (void)writex (outFd, &curLn [lastPs], 1);
  1025. lastPs++;
  1026. }
  1027.     /* blank out remaining junk if we're at the end of the line */
  1028.     if (lastPs == strlen (curLn))
  1029. {
  1030. int i = strlen (oldLn) - strlen (curLn);
  1031. if (i > 0)
  1032.     {
  1033.     (void)writen (outFd, ' ', i);
  1034.     (void)writen (outFd, 'b', i);
  1035.     }
  1036. }
  1037.     /* now get cursor right */
  1038.     if (lastPs > *curPs)
  1039. (void)writen (outFd, 'b', lastPs - *curPs);
  1040.     else
  1041. (void)writex (outFd, &curLn [lastPs], *curPs - lastPs);
  1042.     }
  1043. /*
  1044.  * Definitions used through remaining routines.
  1045.  */
  1046. #define CUR (curLn [*curPs])
  1047. #define PREV (curLn [*curPs-dir])
  1048. #define NEXT (curLn [*curPs+dir])
  1049. #define INC (*curPs+=dir)
  1050. #define ispunct_nospc(c) (ispunct(c) && !isspace(c))
  1051. #define igpunct(c) (ignorePunct ? ispunct_nospc(c) : FALSE)
  1052. #define isword(c) (isalpha(c) || isdigit(c) || index("*?_-.[]~=",c))
  1053. /*******************************************************************************
  1054. *
  1055. * completeName - complete partial symbol name at current position
  1056. *
  1057. * RETURNS: TRUE if symbol name is completed in any way, otherwise FALSE.
  1058. */
  1059. LOCAL BOOL completeName
  1060.     (
  1061.     FAST char *curLn,
  1062.     int *curPs
  1063.     )
  1064.     {
  1065.     CMP_ARG arg;
  1066.     char saveLn [LINE_LEN+1];
  1067.     char string [100];
  1068.     int count;
  1069.     int dir = FORWARD;
  1070.     int startPs = *curPs;
  1071.     int endPs = *curPs;
  1072.     /* operation:
  1073.      *   isolate begin and end of string at current position,
  1074.      *   if begin and end are equal then no string - return error,
  1075.      *   call support routine to see if string is in symbol table,
  1076.      *     if not then - return error
  1077.      *    otherwise determine symbol up to the last unambiguous character,
  1078.      *     then insert extra characters - return ok.
  1079.      */
  1080.     while (isalpha((int)curLn [startPs-1]) ||
  1081.    isdigit((int)curLn[startPs-1])  ||
  1082.    curLn [startPs-1] == '_')
  1083. {
  1084. startPs--;
  1085. }
  1086.     while (isalpha ((int)curLn [endPs]) ||
  1087.    isdigit ((int)curLn [endPs]) ||
  1088.    curLn [endPs] == '_')
  1089. {
  1090. endPs++;
  1091. }
  1092.     if (endPs == startPs)
  1093. return (FALSE);
  1094.     if (curLn [startPs] == '_')
  1095. startPs++; /* ignore leading underscore */
  1096.     strncpy (string, &curLn [startPs], endPs - startPs);
  1097.     string [endPs - startPs] = EOS;
  1098.     arg.name    = string; /* search string */
  1099.     arg.nameLen = strlen (string); /* optimization */
  1100.     arg.count   = 0; /* reset to zero */
  1101.     symEach (sysSymTbl, (FUNCPTR)findName, (int)&arg);
  1102.     count = arg.count;
  1103.     /* keep looking while match is ambiguous */
  1104.     while (arg.count > 1 && count == arg.count)
  1105. {
  1106. if (strcmp (arg.name, arg.match) == 0)
  1107.     {
  1108.     /* just in case more than one entry with same name,
  1109.      * but hope this first match is different, oh well.
  1110.      */
  1111.     count = 1;
  1112.     break;
  1113.     }
  1114. arg.count = 0; /* reset to zero */
  1115. arg.nameLen++; /* optimization */
  1116. strncpy (arg.name, arg.match, arg.nameLen);
  1117. symEach (sysSymTbl, (FUNCPTR)findName, (int)&arg);
  1118. }
  1119.     /* have to admit we didn't find anything */
  1120.     if (count == 0)
  1121. return (FALSE);
  1122.     if (count > 1)
  1123. {
  1124. /* ambiguous match up 'til second last position */
  1125. arg.name [arg.nameLen - 1] = EOS;
  1126. arg.match = arg.name;
  1127. }
  1128.     /* insert new string, don't forget to save original line */
  1129.     if ((endPs - startPs) + strlen (curLn) + strlen (arg.match) < LINE_LEN)
  1130. {
  1131. strcpy (saveLn, curLn);
  1132. strcpy (&curLn [startPs], arg.match);
  1133. strcat (curLn, &saveLn [endPs]);
  1134. if (isalpha((int)CUR) || isdigit((int)CUR) || CUR == '_')
  1135.     {
  1136.     while (isalpha((int)NEXT) || isdigit((int)NEXT) || NEXT == '_')
  1137. {
  1138. INC;
  1139. }
  1140.     }
  1141. }
  1142.     return (TRUE);
  1143.     }
  1144. /*******************************************************************************
  1145. *
  1146. * findName - support routine for completeName
  1147. *
  1148. * This routine is called for each string in the symbol table.
  1149. *
  1150. * RETURNS: TRUE always.
  1151. *
  1152. * ARGSUSED
  1153. */
  1154. LOCAL BOOL findName
  1155.     (
  1156.     char *name,         /* name of this entry */
  1157.     char *value,        /* symbol table junk */
  1158.     SYM_TYPE type,      /* symbol table junk */
  1159.     CMP_ARG *arg        /* what to match, etc. */
  1160.     )
  1161.     {
  1162.     if (name[0] == '_')
  1163. name++; /* ignore leading underscore */
  1164.     if (strncmp (name, arg->name, arg->nameLen) == 0)
  1165. {
  1166. if (++arg->count == 1 || strlen (name) > strlen (arg->match))
  1167.     arg->match = name;
  1168. }
  1169.     return (TRUE);
  1170.     }
  1171. /*******************************************************************************
  1172. *
  1173. * search - move from current position to matched character position
  1174. *
  1175. * RETURNS: new ptr to current position.
  1176. */
  1177. LOCAL void search
  1178.     (
  1179.     FAST BOOL ignorePunct,              /* ignore punctuation or not */
  1180.     FAST BOOL endOfWord,                /* stop at end of word, or
  1181.                                            when BACKWARD stop at beginning */
  1182.     char *curLn,
  1183.     int *curPs,
  1184.     int dir                     /* direction to search */
  1185.     )
  1186.     {
  1187.     /* make sure we're not already at limits */
  1188.     if (CUR == EOS || NEXT == EOS)
  1189. return;
  1190.     if (isspace ((int)CUR))
  1191. {
  1192. /* just get to a non-space */
  1193. while (NEXT != EOS && isspace ((int)CUR))
  1194.     INC;
  1195. }
  1196.     else if (ispunct ((int)CUR))
  1197. {
  1198. /* just get to the next/previous word */
  1199. while (NEXT != EOS && !isalnum ((int)CUR))
  1200.     INC;
  1201. }
  1202.     else if (endOfWord || dir == BACKWARD)
  1203. {
  1204. /* while space coming */
  1205. while (isspace((int)NEXT))
  1206.     INC;
  1207. /* maybe we've got to punctuation */
  1208. if (ispunct_nospc ((int)NEXT))
  1209.     {
  1210.     do
  1211. {
  1212. INC;
  1213. }
  1214.     while (NEXT != EOS && ispunct_nospc ((int)NEXT));
  1215.     /* while we're on a space advance/retreat */
  1216.     while (NEXT != EOS && isspace ((int)CUR))
  1217. INC;
  1218.     return;
  1219.     }
  1220. /* get to end/beginning of word but not past */
  1221. while (NEXT != EOS && (isalnum ((int)NEXT) || igpunct(((int)NEXT))))
  1222.     INC;
  1223. }
  1224.     else
  1225. {
  1226. /* get past end/beginning of word */
  1227. do
  1228.     {
  1229.     INC;
  1230.     }
  1231. while (NEXT != EOS && (isalnum ((int)CUR) || igpunct((int)CUR)));
  1232. /* while we're on a space advance/retreat */
  1233. while (NEXT != EOS && isspace ((int)CUR))
  1234.     INC;
  1235. }
  1236.     }
  1237. /*******************************************************************************
  1238. *
  1239. * find - a particualar character
  1240. *
  1241. * RETURNS:
  1242. * TRUE if `ch' found, or
  1243. * FALSE if end of line reached first.
  1244. */
  1245. LOCAL BOOL find
  1246.     (
  1247.     char ch,                    /* what to find */
  1248.     char *curLn,
  1249.     int *curPs,
  1250.     int dir                     /* direction to search */
  1251.     )
  1252.     {
  1253.     if (CUR == EOS || NEXT == EOS)
  1254. return (FALSE);
  1255.     do
  1256. {
  1257. INC;
  1258. }
  1259.     while (CUR != ch && NEXT != EOS);
  1260.     return (CUR == ch);
  1261.     }
  1262. /*******************************************************************************
  1263. *
  1264. * findFwd - find <ch> some <number> of times looking forwards
  1265. */
  1266. LOCAL STATUS findFwd
  1267.     (
  1268.     FAST char ch,
  1269.     char *curLn,
  1270.     int *curPs,
  1271.     int *number
  1272.     )
  1273.     {
  1274.     while (find (ch, curLn, curPs, FORWARD) && --*number > 0)
  1275. ;
  1276.     *number = 0;
  1277.     return (OK);
  1278.     }
  1279. /*******************************************************************************
  1280. *
  1281. * findBwd - find <ch> some <number> of times looking backwards
  1282. */
  1283. LOCAL STATUS findBwd
  1284.     (
  1285.     char ch,
  1286.     char *curLn,
  1287.     int *curPs,
  1288.     int *number
  1289.     )
  1290.     {
  1291.     while (find (ch, curLn, curPs, BACKWARD) && --*number > 0)
  1292. ;
  1293.     *number = 0;
  1294.     return (OK);
  1295.     }
  1296. /*******************************************************************************
  1297. *
  1298. * change - change as specified by (w/W/e/E/sp/l/h/c/$/0)
  1299. */
  1300. LOCAL STATUS change
  1301.     (
  1302.     FAST char ch,
  1303.     char *curLn,
  1304.     int *curPs,
  1305.     int *number,
  1306.     LED_ID ledId
  1307.     )
  1308.     {
  1309.     STATUS status = OK;
  1310.     switch (ch)
  1311. {
  1312. case '0':
  1313. case ' ':
  1314. case 'l':
  1315. case 'h':
  1316. case 'w':
  1317. case 'W':
  1318. case 'e':
  1319. case 'E':
  1320. case 'b':
  1321. case 'B':
  1322.     ledId->cmdMode = FALSE;
  1323.     status = deletec (ch, curLn, curPs, number, ledId);
  1324.     break;
  1325. case 'c':
  1326.     *curPs = 0;
  1327.     /* drop through */
  1328. case '$':
  1329.     ledId->cmdMode = FALSE;
  1330.     CUR = EOS;
  1331.     break;
  1332. default:
  1333.     status = ERROR;
  1334.     break;
  1335. }
  1336.     return (status);
  1337.     }
  1338. /*******************************************************************************
  1339. *
  1340. * deletec - delete as specified by (w/W/e/E/b/B/sp/l/h/d/$/0) <number> of times
  1341. *
  1342. * RETURNS: OK or ERROR
  1343. */
  1344. LOCAL STATUS deletec
  1345.     (
  1346.     FAST char ch,
  1347.     char *curLn,
  1348.     int *curPs,
  1349.     int *number,
  1350.     LED_ID ledId
  1351.     )
  1352.     {
  1353.     STATUS status = OK;
  1354.     FAST int tmp = *curPs;
  1355.     FAST int i = 0;
  1356.     int dir = (ch == 'b' || ch == 'B' || ch == 'h') ? BACKWARD : FORWARD;
  1357.     BOOL endOfWord = ch != 'w' && ch != 'W';
  1358.     int fudge; /* fudge factor? */
  1359.     do
  1360. {
  1361. switch (ch)
  1362.     {
  1363.     case 'w':
  1364.     case 'W': /* ignore punctuation */
  1365.     case 'e':
  1366.     case 'E': /* ignore punctuation */
  1367.     case 'b':
  1368.     case 'B': /* ignore punctuation */
  1369. {
  1370. int origPs = *curPs;
  1371. search (isupper ((int)ch), endOfWord, curLn, curPs, dir);
  1372. if (*curPs == origPs)
  1373.     *number = 1; /* get out! */
  1374. fudge = (NEXT == EOS) ? 1 : 0;
  1375. if (dir == FORWARD)
  1376.     {
  1377.     i = *curPs - tmp + fudge;
  1378.     strncpy (ledId->buffer, &curLn [tmp], i);
  1379.     strcpy (&curLn [tmp], &curLn [*curPs+fudge]);
  1380.     *curPs = tmp;
  1381.     }
  1382. else
  1383.     {
  1384.     i = tmp - *curPs + fudge;
  1385.     strncpy (ledId->buffer, &CUR, i);
  1386.     strcpy (&CUR, &curLn [tmp+fudge]);
  1387.     tmp = *curPs - fudge;
  1388.     }
  1389. break;
  1390. }
  1391.     case ' ':
  1392.     case 'l':
  1393. ledId->buffer [i++] = CUR;
  1394. if (*curPs < strlen (curLn) - 1)
  1395.     {
  1396.     strcpy (&CUR, &NEXT);
  1397.     break;
  1398.     }
  1399. else if (*curPs == strlen (curLn) - 1)
  1400.     *number = 1; /* get out! */
  1401. CUR = EOS;
  1402. if (*curPs > 0)
  1403.     (*curPs)--;
  1404. break;
  1405.     case 'd':
  1406. strcpy (ledId->buffer, curLn);
  1407. i = strlen (ledId->buffer);
  1408.     /* don't want 'i' to cause any grief */
  1409. *curPs = 0;
  1410. CUR = EOS;
  1411. *number = 1; /* get out! */
  1412. break;
  1413.     case '$':
  1414. i = strlen (curLn) - *curPs + 1;
  1415. strncpy (ledId->buffer, &CUR, i);
  1416. CUR = EOS;
  1417. *number = 1; /* get out! */
  1418. break;
  1419.     case '0':
  1420. i = *curPs + 1;
  1421. strncpy (ledId->buffer, &curLn [0], i);
  1422. bcopy (&CUR, &curLn [0], strlen (&CUR) + 1); /* +EOS */
  1423. *curPs = 0;
  1424. *number = 1; /* get out! */
  1425. break;
  1426.     case 'h': /* XXX - not implemented */
  1427.     default:
  1428. i = strlen (ledId->buffer);
  1429. *number = 1; /* get out! */
  1430. status = ERROR;
  1431. break;
  1432.     }
  1433. }
  1434.     while (--*number > 0);
  1435.     *number = 0;
  1436.     ledId->buffer [i] = EOS;
  1437.     return (status);
  1438.     }
  1439. /*******************************************************************************
  1440. *
  1441. * replace - replace current position thru count with specified character
  1442. */
  1443. LOCAL STATUS replace
  1444.     (
  1445.     char ch,
  1446.     char *curLn,
  1447.     int *curPs,
  1448.     int *number
  1449.     )
  1450.     {
  1451.     if (*number < 1)
  1452. *number = 1;
  1453.     /* don't do replacement if escape */
  1454.     if (ch != ESC_CHAR)
  1455. bfill (&CUR, min (*number, strlen (&CUR)), ch);
  1456.     *number = 0;
  1457.     return (OK);
  1458.     }
  1459. /*******************************************************************************
  1460. *
  1461. * beep - make a noise
  1462. */
  1463. LOCAL void beep
  1464.     (
  1465.     int outFd
  1466.     )
  1467.     {
  1468.     static char bell = BEL_CHAR;
  1469.     write (outFd, &bell, 1);
  1470.     }
  1471. /*******************************************************************************
  1472. *
  1473. * writex - write bytes to a file but change control chars to '?'
  1474. *
  1475. * RETURNS: number of characters actually written, pretty much like write.
  1476. */
  1477. LOCAL int writex
  1478.     (
  1479.     FAST int fd,
  1480.     char buffer [],
  1481.     FAST int nbytes
  1482.     )
  1483.     {
  1484.     FAST int i;
  1485.     FAST char *pBuf = buffer;
  1486.     char non_ch = NON_CHAR;
  1487.     for (i = 0; i < nbytes; i++, pBuf++)
  1488. {
  1489. if (write (fd, (isprint ((int)(*pBuf)) ? pBuf : &non_ch), 1) != 1)
  1490.     return (ERROR);
  1491. }
  1492.     return (nbytes);
  1493.     }
  1494. /*******************************************************************************
  1495. *
  1496. * writen - write a character n times
  1497. *
  1498. * NOTE: requires n <= (LINE_LEN + 1)
  1499. *
  1500. * RETURNS: number of characters actually written, just like write.
  1501. */
  1502. LOCAL int writen
  1503.     (
  1504.     int fd,
  1505.     char ch,
  1506.     int nbytes
  1507.     )
  1508.     {
  1509.     char buf [LINE_LEN + 1];
  1510.     bfill (buf, nbytes, ch);
  1511.     return (write (fd, buf, nbytes));
  1512.     }
  1513. /*******************************************************************************
  1514. *
  1515. * histInit - initialize history list
  1516. *
  1517. * On successive calls, resets history to new size.
  1518. */
  1519. LOCAL void histInit
  1520.     (
  1521.     LED_ID ledId,
  1522.     int histSize        /* amount of history required */
  1523.     )
  1524.     {
  1525.     int histDiff = histSize - ledId->histSize;
  1526.     HIST *pH;
  1527.     if (ledId->histSize == 0)
  1528. {
  1529. lstFree (&ledId->histList);
  1530. lstFree (&ledId->histFreeList);
  1531. ledId->histNum  = 0;
  1532. lstInit (&ledId->histList);
  1533. lstInit (&ledId->histFreeList);
  1534. }
  1535.     if (histDiff >= 0)
  1536. {
  1537. /* add to history free list */
  1538. while (histDiff-- > 0)
  1539.     {
  1540.     /* allocate history space */
  1541.     ledId->pHist = (HIST *) malloc (sizeof (HIST));
  1542.     if (ledId->pHist == NULL)
  1543. return; /* oh, oh! */
  1544.     ledId->pHist->line[0] = EOS;
  1545.     lstAdd (&ledId->histFreeList, &ledId->pHist->node);
  1546.     }
  1547. }
  1548.     else
  1549. {
  1550. /* free excess histories from history free list */
  1551. while (lstCount (&ledId->histFreeList) > 0 && histDiff++ < 0)
  1552.     {
  1553.     pH = (HIST *) lstGet (&ledId->histFreeList);
  1554.     free ((char *) pH);
  1555.     }
  1556. /* free oldest histories from history list */
  1557. while (lstCount (&ledId->histList) > 0 && histDiff++ < 0)
  1558.     {
  1559.     pH = (HIST *) lstGet (&ledId->histList);
  1560.     free ((char *) pH);
  1561.     }
  1562. }
  1563.     ledId->histSize = histSize;
  1564.     }
  1565. /*******************************************************************************
  1566. *
  1567. * histAdd - add line to history
  1568. */
  1569. LOCAL void histAdd
  1570.     (
  1571.     FAST LED_ID ledId,
  1572.     FAST char *line
  1573.     )
  1574.     {
  1575.     FAST HIST *pH = (HIST *) lstLast (&ledId->histList);
  1576.     FAST int i;
  1577.     ledId->pHist = NULL;
  1578.     /* ignore blank lines */
  1579.     for (i = 0; isspace ((int)line[i]); i++)
  1580. ;
  1581.     /* ignore blank lines & consecutive identical commands */
  1582.     if (i >= strlen (line) || (pH != NULL && strcmp (line, pH->line) == 0))
  1583. return;
  1584.     /* try free list or get from top of history list */
  1585.     if ((pH = (HIST *) lstGet (&ledId->histFreeList)) == NULL &&
  1586. (pH = (HIST *) lstGet (&ledId->histList)) == NULL)
  1587. {
  1588. /* history foul-up! */
  1589. return;
  1590. }
  1591.     /* append to end of history list */
  1592.     lstAdd (&ledId->histList, &pH->node);
  1593.     ledId->histNum++;
  1594.     strncpy (pH->line, line, LINE_LEN);
  1595.     pH->line [LINE_LEN - 1] = EOS;
  1596.     }
  1597. /*******************************************************************************
  1598. *
  1599. * histNum - get historical line number
  1600. *
  1601. * RETURNS: FALSE if no history by that number
  1602. */
  1603. LOCAL BOOL histNum
  1604.     (
  1605.     FAST LED_ID ledId,
  1606.     FAST char *line,            /* where to return historical line */
  1607.     FAST int n                  /* history number */
  1608.     )
  1609.     {
  1610.     int histFirst = ledId->histNum - lstCount (&ledId->histList) + 1;
  1611.     FAST HIST *pH;
  1612.     FAST int i;
  1613.     if (n < histFirst || n > ledId->histNum)
  1614. return (FALSE);
  1615.     for (pH = (HIST *) lstFirst (&ledId->histList), i = histFirst;
  1616.  pH != NULL && i != n;
  1617.  pH = (HIST *) lstNext (&pH->node), i++)
  1618. ;
  1619.     if (pH == NULL)
  1620. return (FALSE);
  1621.     strcpy (line, pH->line);
  1622.     ledId->pHist = pH;
  1623.     return (TRUE);
  1624.     }
  1625. /*******************************************************************************
  1626. *
  1627. * histNext - get next entry in history
  1628. *
  1629. * If line == NULL then just forward history.
  1630. *
  1631. * RETURNS: ERROR if no history
  1632. */
  1633. LOCAL STATUS histNext
  1634.     (
  1635.     FAST LED_ID ledId,
  1636.     FAST char *line             /* where to return historical line */
  1637.     )
  1638.     {
  1639.     if (ledId->pHist == NULL)
  1640. ledId->pHist = (HIST *) lstFirst (&ledId->histList);
  1641.     else if ((ledId->pHist = (HIST *) lstNext (&ledId->pHist->node)) == NULL)
  1642. ledId->pHist = (HIST *) lstFirst (&ledId->histList);
  1643.     if (ledId->pHist == NULL)
  1644. return (ERROR);
  1645.     if (line != NULL)
  1646. strcpy (line, ledId->pHist->line);
  1647.     return (OK);
  1648.     }
  1649. /*******************************************************************************
  1650. *
  1651. * histPrev - get previous entry in history
  1652. *
  1653. * If line == NULL then just forward history.
  1654. *
  1655. * RETURNS: ERROR if no history
  1656. */
  1657. LOCAL STATUS histPrev
  1658.     (
  1659.     FAST LED_ID ledId,
  1660.     FAST char *line             /* where to return historical line */
  1661.     )
  1662.     {
  1663.     if (ledId->pHist == NULL)
  1664. ledId->pHist = (HIST *) lstLast (&ledId->histList);
  1665.     else if ((ledId->pHist = (HIST *) lstPrevious (&ledId->pHist->node))
  1666.     == NULL)
  1667. {
  1668. ledId->pHist = (HIST *) lstLast (&ledId->histList);
  1669. }
  1670.     if (ledId->pHist == NULL)
  1671. return (ERROR);
  1672.     if (line != NULL)
  1673. strcpy (line, ledId->pHist->line);
  1674.     return (OK);
  1675.     }
  1676. /*******************************************************************************
  1677. *
  1678. * histFind - find string in history list
  1679. *
  1680. * Match should be of form: "/test", or "?test" for forward or backward searches.
  1681. *
  1682. * RETURNS: TRUE if history found, line is replaced with historical line
  1683. */
  1684. LOCAL BOOL histFind
  1685.     (
  1686.     FAST LED_ID ledId,
  1687.     FAST char *match,           /* what to match */
  1688.     FAST char *line             /* where to return historical line */
  1689.     )
  1690.     {
  1691.     char *pLine;
  1692.     FAST HIST *pH = ledId->pHist;
  1693.     FAST BOOL forward = match [0] == '?';
  1694.     int i = lstCount (&ledId->histList) + 1;
  1695.     BOOL found = FALSE;
  1696.     if (pH == NULL && (pH = (HIST *) lstLast (&ledId->histList)) == NULL)
  1697. return (FALSE);
  1698.     do
  1699. {
  1700. if (forward)
  1701.     {
  1702.     if ((pH = (HIST *) lstNext (&pH->node)) == NULL &&
  1703. (pH = (HIST *) lstFirst (&ledId->histList)) == NULL)
  1704. return (FALSE);
  1705.     }
  1706. pLine = pH->line;
  1707. while ((pLine = index (pLine, match [1])) != 0)
  1708.     {
  1709.     if (strncmp (pLine, &match [1], strlen (match) - 1) == 0)
  1710. {
  1711. found = TRUE;
  1712. break; /* found it! */
  1713. }
  1714.     else if (*(++pLine) == EOS)
  1715. break;
  1716.     }
  1717. if (!found && !forward)
  1718.     {
  1719.     if ((pH = (HIST *) lstPrevious (&pH->node)) == NULL &&
  1720. (pH = (HIST *) lstLast (&ledId->histList)) == NULL)
  1721. return (FALSE);
  1722.     }
  1723. }
  1724.     while (--i > 0 && !found);
  1725.     /* position 'pHist' correctly for next search */
  1726.     if (!forward)
  1727. {
  1728. if ((ledId->pHist = (HIST *) lstPrevious (&pH->node)) == NULL)
  1729.     ledId->pHist = (HIST *) lstLast (&ledId->histList);
  1730. }
  1731.     else
  1732. ledId->pHist = pH;
  1733.     if (i < 1)
  1734. return (FALSE);
  1735.     strcpy (line, pH->line);
  1736.     return (TRUE);
  1737.     }
  1738. /*******************************************************************************
  1739. *
  1740. * histAll - print all historical lines
  1741. */
  1742. LOCAL void histAll
  1743.     (
  1744.     FAST LED_ID ledId
  1745.     )
  1746.     {
  1747.     FAST int histFirst = ledId->histNum - lstCount (&ledId->histList) + 1;
  1748.     FAST HIST *pH;
  1749.     char buffer [LINE_LEN + 10]; /* Need to add padding for the
  1750.   * line number
  1751.   */
  1752.     for (pH = (HIST *) lstFirst (&ledId->histList);
  1753.  pH != NULL;
  1754.  pH = (HIST *) lstNext (&pH->node))
  1755. {
  1756. sprintf (buffer, "%3d  %s", histFirst++, pH->line);
  1757. (void)writex (ledId->outFd, buffer, strlen (buffer));
  1758. write (ledId->outFd, "n", 1);
  1759. }
  1760.     }
  1761. #ifdef UNIX_DEBUG
  1762. /*******************************************************************************
  1763. *
  1764. * main - UNIX debug module
  1765. *
  1766. * NOMANUAL
  1767. */
  1768. void main ()
  1769.     {
  1770.     static char *junk[] =
  1771.     { "one", "two", "three", "four", "five", "six", "seven",
  1772.       "eight", "nine", "ten", "force", "fits", "fight", "several" };
  1773.     char line [LINE_LEN+1];
  1774.     int i;
  1775.     int ledId;
  1776.     setbuf (stdout, NULL);
  1777.     sysSymTbl = symTblCreate (6);
  1778.     for (i = 0; i < NELEMENTS (junk); i++)
  1779. symSAdd (sysSymTbl, junk[i], 0, 0, symGroupDefault);
  1780.     ledId = ledOpen (0, 1, 20);
  1781.     system ("stty cbreak -echo");
  1782.     printf ("ledLib: UNIX Debugn");
  1783.     printf ("-> ");
  1784.     while (ledRead (ledId, line, LINE_LEN) != EOF)
  1785. {
  1786. printf ("-> ");
  1787. }
  1788.     system ("stty -cbreak echo");
  1789.     }
  1790. /*******************************************************************************
  1791. *
  1792. * errnoSet - bogus edition
  1793. *
  1794. * NOMANUAL
  1795. */
  1796. void errnoSet (status)
  1797.     int status;
  1798.     {
  1799.     printf ("errnoSet: new status 0x%x.n", status);
  1800.     }
  1801. #endif /* UNIX_DEBUG */