home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume16 / fep / part03 < prev    next >
Encoding:
Internet Message Format  |  1988-11-09  |  38.6 KB

  1. Subject:  v16i063:  Front end editor program, Part03/05
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Kazumasa Utashiro <kddlab!sra.junet!utashiro>
  7. Posting-number: Volume 16, Issue 63
  8. Archive-name: fep/part03
  9.  
  10. #!/bin/sh
  11. # to extract, remove the header and type "sh filename"
  12. if `test ! -s ./fep_edit.c`
  13. then
  14. echo "writing ./fep_edit.c"
  15. cat > ./fep_edit.c << '\End\Of\File\'
  16. /*    Copyright (c) 1987, 1988 by Software Research Associates, Inc.    */
  17.  
  18. #ifndef lint
  19. static char rcsid[]=
  20. "$Header: fep_edit.c,v 4.0 88/08/05 20:22:06 utashiro Rel $ (SRA)";
  21. #endif lint
  22.  
  23. #include <stdio.h>
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include <sgtty.h>
  27. #include <sys/time.h>
  28. #include <ctype.h>
  29. #include <sys/dir.h>
  30. #include <sys/file.h>
  31. #include <setjmp.h>
  32. #include "fep_defs.h"
  33. #include "fep_glob.h"
  34. #include "fep_funcs.h"
  35.  
  36. CHAR        *CommandLine;        /* pointer to command line buffer */
  37. CHAR        *KillBuffer;        /* pointer to kill buffer */
  38. int        CurrentPosition;    /* current cursor position */
  39. int        MarkPosition = -1;    /* Marked position */
  40. EDITMODE    editmode = NOTYET;    /* edtimode EMACS, VI */
  41. EDITSTATUS    editstatus;        /* EDITING, NOTEDITING */
  42.  
  43. int    maxline = MAXCOMLEN;        /* maximum length of command line */
  44. int    NeedNewLine;            /* add new line flag */
  45. int    NeedSave;            /* need to save to history */
  46. int    Transparency = OFF;        /* transparent flag */
  47. int    eof_occured = 0;        /* eof has been occured */
  48. jmp_buf    jbuf;                /* jump buffer */
  49.  
  50. FUNC    *curFuncTab;            /* current function table */
  51. FUNC    *altFuncTab;            /* alternative function table */
  52.  
  53. /*
  54.  * Default binding table
  55.  */
  56. BINDENT emacsBindings[] = {
  57.     /* NULL        */    {"\0",        mark},
  58.     /* ^A        */    {"\\^A",    beginning_of_line},
  59.     /* ^B        */    {"\\^B",    backward_character},
  60.     /* ^D        */    {"\\^D",    delete_next_character},
  61.     /* ^E        */    {"\\^E",    end_of_line},
  62.     /* ^F        */    {"\\^F",    forward_character},
  63.     /* ^I        */    {"\\^I",    insert_tab},
  64.     /* ^J        */    {"\\^J",    new_line},
  65.     /* ^K        */    {"\\^K",    kill_to_end_of_line},
  66.     /* ^L        */    {"\\^L",    clear_screen},
  67.     /* ^M        */    {"\\^M",    new_line},
  68.     /* ^N        */    {"\\^N",    next_history},
  69.     /* ^P        */    {"\\^P",    previous_history},
  70.     /* ^T        */    {"\\^T",    previous_history},
  71.     /* ^Y        */    {"\\^Y",    yank_from_kill_buffer},
  72.     /* ^^        */    {"\\^^",    toggle_transparency},
  73.     /* esc-b    */    {"\\^[b",    backward_word},
  74.     /* esc-B    */    {"\\^[B",    backward_Word},
  75.     /* esc-d    */    {"\\^[d",    delete_next_word},
  76.     /* esc-D    */    {"\\^[D",    delete_next_Word},
  77.     /* esc-f    */    {"\\^[f",    forward_word},
  78.     /* esc-F    */    {"\\^[F",    forward_Word},
  79.     /* esc-h    */    {"\\^[h",    delete_previous_word},
  80.     /* esc-H    */    {"\\^[H",    delete_previous_Word},
  81.     /* esc-l    */    {"\\^[l",    list_file_name},
  82.     /* esc-L    */    {"\\^[L",    list_file_name},
  83.         /* esc-esc    */    {"\\^[\\^[",    expand_file_name},
  84.     /* esc-"-"    */    {"\\^[-",    toggle_transparency},
  85.     /* esc-_    */    {"\\^[_",    invoke_shell},
  86.     /* esc-<    */    {"\\^[<",    search_reverse},
  87.     /* esc->    */    {"\\^[>",    search_forward},
  88.     /* esc-?    */    {"\\^[?",    show_help},
  89.     /* ^X-^B    */    {"\\^X\\^B",    show_bindings},
  90.     /* ^X-B        */    {"\\^XB",    show_bindings},
  91.     /* ^X-b        */    {"\\^Xb",    show_bindings},
  92.     /* ^X-^H    */    {"\\^X\\^H",    show_history},
  93.     /* ^X-H        */    {"\\^XH",    show_history},
  94.     /* ^X-h        */    {"\\^Xh",    show_history},
  95.     /* ^X-^K    */    {"\\^X\\^K",    kill_to_top_of_line},
  96.     /* ^X-^L    */    {"\\^X\\^L",    fep_repaint},
  97.     /* ^X-^C    */    {"\\^X\\^C",    terminate},
  98.     /* ^X-^D    */    {"\\^X\\^D",    send_eof},
  99.     /* ^X-(        */    {"\\^X(",    fep_start_script},
  100.     /* ^X-)        */    {"\\^X)",    fep_end_script},
  101.     /*        */    {NULL,        NULL}
  102. };
  103.  
  104. /*
  105.  * Initialize function table buffer
  106.  */
  107. init_bind_table ()
  108. {
  109.  
  110.     curFuncTab = (FUNC *) calloc (sizeof (FUNC), 256);
  111.     altFuncTab = (FUNC *) calloc (sizeof (FUNC), 256);
  112.     if (curFuncTab == 0 || altFuncTab == 0) {
  113.     printf ("Can't allocate space for function table\n");
  114.     exit (1);
  115.     }
  116. }
  117.  
  118. /*
  119.  * Initialize function table
  120.  */
  121. char strspace [256], *strspace_addr = strspace;
  122.  
  123. init_edit_params ()
  124. {
  125.     struct indirect *idp;
  126.     char *cp, *getenv();
  127.     char sbuf[2048], *term, *tgetstr();
  128.  
  129.     if (term = look_var ("term")) {
  130.     if (tgetent (sbuf, term) == 1) {
  131.         if (lines == 0)
  132.         lines = tgetnum ("li");
  133.         if (columns == 0)
  134.         columns = tgetnum ("co");
  135.         term_clear = tgetstr ("cl", &strspace_addr);
  136.     }
  137.     }
  138.  
  139.     if (lines == 0)
  140.     lines = 24;
  141.     if (columns == 0)
  142.     columns = 80;
  143.  
  144.     sprintf (sbuf, "%d", lines);
  145.     set_var ("crt", sbuf);
  146.  
  147.     if (editmode == NOTYET) {
  148.     if (look_var ("editmode"))
  149.         set_var ("editmode", look_var ("editmode"));
  150.     else
  151.         set_var ("editmode", "emacs");
  152.     }
  153.  
  154.     set_var ("showhist", itoa (lines - 1));
  155.  
  156.     /*
  157.      * Read startup file
  158.      */
  159.     sourceRcFile ();
  160.  
  161.     /*
  162.      * Read history if 'history-file' is set
  163.      */
  164.     {
  165.     char *cp, *mk_home_relative ();
  166.  
  167.     if (look_var ("savehist") && (cp = look_var ("history-file"))) {
  168.         cp = mk_home_relative (cp);
  169.  
  170.         if (access (cp, R_OK) == 0)
  171.         read_history (cp);
  172.     }
  173.     }
  174.  
  175.     /*
  176.      * Initialize command line buffer
  177.      */
  178.     CommandLine = (CHAR *) calloc (maxline, 1);
  179.     KillBuffer = (CHAR *) calloc (maxline, 1);
  180.     if (CommandLine == 0 || KillBuffer == 0) {
  181.     perror ("Edit line buffer");
  182.     exit (1);
  183.     }
  184.     (void) strcpy (CommandLine, "");
  185.     (void) strcpy (KillBuffer, "");
  186.     CurrentPosition = 0;
  187. }
  188.  
  189. /*
  190.  * Initialize emacs bindings
  191.  */
  192. initEmacsBindings (cft, aft)
  193.     FUNC cft[], aft[];
  194. {
  195.     register int i;
  196.     BINDENT *ftp;
  197.  
  198.     for (i = 0; i < 256; i++)
  199.     cft[i] = self_insert;
  200.     for (ftp = emacsBindings; ftp->bt_s; ftp++) {
  201.     bind_key (cft, ftp->bt_func, ftp->bt_s, abort);
  202.     }
  203.  
  204.     /* Now, using cbreak mode
  205.     cft[(int) tchars_buf.t_startc] = ignore;
  206.     cft[(int) tchars_buf.t_stopc] = ignore;
  207.     */
  208.     cft[(int) tchars_buf.t_intrc] = insert_and_flush;
  209.     cft[(int) tchars_buf.t_quitc] = insert_and_flush;
  210.     /* Now, EOF will be sent on empty line.
  211.     cft[(int) tchars_buf.t_eofc] = send_eof;
  212.     */
  213.     cft[(int) tchars_buf.t_brkc] = insert_and_flush;
  214.     cft[(int) ltchars_buf.t_suspc] = insert_and_flush;
  215.     /* ^Y is used for yank-from-kill-buffer
  216.     cft[(int) ltchars_buf.t_dsuspc] = self_insert;
  217.     */
  218.     cft[(int) ltchars_buf.t_rprntc] = reprint;
  219.     cft[(int) ltchars_buf.t_flushc] = self_insert;
  220.     cft[(int) ltchars_buf.t_werasc] = delete_previous_word;
  221.     cft[(int) ltchars_buf.t_lnextc] = literal_next;
  222.     cft[(int) initial_ttymode.sg_erase] = delete_previous_character;
  223.     cft[(int) initial_ttymode.sg_kill] = delete_line;
  224. }
  225.  
  226. /*
  227.  * Main function of front end program
  228.  */
  229. CHAR *
  230. getline()
  231. {
  232.     int c;
  233.     CHAR *execute_command, *check_alias();
  234.  
  235.     (void) strcpy (CommandLine, "");
  236.     CurrentPosition = 0;
  237.     resetCurrentHistory ();
  238.  
  239. RETRY:
  240.     (void) fflush (stdout);
  241.     NeedNewLine = 0;
  242.     NeedSave = 0;
  243.     editstatus = EDITING;
  244.     setjmp (jbuf);
  245.  
  246.     /*
  247.      * If there is file pointer for I/O redirection,
  248.      * read input from the pointer and return
  249.      */
  250.     if (redirect_fp) {
  251.  
  252.     /*
  253.      * Check output from sub-process
  254.      */
  255.     swallow_output();
  256.  
  257.     if (fgets (CommandLine, MAXCOMLEN, redirect_fp)) {
  258.         ++redirect_line;
  259.         execute_command = CommandLine;
  260.         goto RETURN;        
  261.     }
  262.     else {
  263.         if (look_var ("verbose"))
  264.         printf ("%d lines redirected\n", redirect_line);
  265.         errorBell ();
  266.         if (redirect_pid) {
  267.         pclose (redirect_fp);
  268.         redirect_pid = 0;
  269.         }
  270.         else
  271.         fclose (redirect_fp);
  272.         redirect_fp = NULL;
  273.     }
  274.     }
  275.  
  276.     while ((c = getcharacter ()) >= (CHAR) 0) {
  277.     int status;
  278.  
  279.     /*
  280.      * In transparet mode
  281.      */
  282.     if (Transparency == ON) {
  283.         if (*curFuncTab[(int) c] == toggle_transparency ||
  284.             *curFuncTab[(int) c] == fix_transparency) {
  285.         (*curFuncTab[(int) c])();
  286.         goto RETRY;
  287.         }
  288.         else {
  289.         CommandLine[CurrentPosition] = c;
  290.         CommandLine[CurrentPosition + 1] = '\0';
  291.         return (CommandLine);
  292.         }
  293.     }
  294.  
  295.     /*
  296.      * If find EOF character on top of empty line
  297.      * and the variable "send-eof-on-empty-line" is set
  298.      * call send_eof
  299.      */
  300.     if (
  301.         c == tchars_buf.t_eofc
  302.         && curFuncTab[c] != send_eof
  303.         && ! look_var ("ignore-eof")
  304.         && CommandLine [0] == '\0'
  305.     ) {
  306.         if (!eof_occured && look_var ("alarm-on-eof")) {
  307.         eof_occured = 1;
  308.         status = alarm_on_eof (c);        
  309.         }
  310.         else
  311.         status = send_eof (c);
  312.     }
  313.     else {
  314.         eof_occured = 0;
  315.         status = callfunc (curFuncTab, c);
  316.     }
  317.  
  318.     (void) fflush (stdout);
  319.     if (status == 1)    /* end of line editing */
  320.         break;
  321.     else            /* continue line editing */
  322.         continue;
  323.     }
  324.     editstatus = NOTEDITING;
  325.  
  326.     /*
  327.      * Check command line refer history or not
  328.      */
  329.     if (refer_history () == PROCESSED)
  330.     goto RETRY;
  331.  
  332.     /*
  333.      * Check alias list
  334.      */
  335.     if (!look_var ("noalias")
  336.     && (execute_command = check_alias (CommandLine))
  337.     ) {
  338.     if (look_var ("verbose"))
  339.         printf ("%s\n", execute_command);
  340.     }
  341.     else
  342.     execute_command = CommandLine;
  343.     
  344.  
  345.     /*
  346.      * Check builtin function, and execute it.
  347.      */
  348.     if (executeBuiltInFunction (execute_command) == PROCESSED) {
  349.     addHistory (CommandLine);
  350.     CommandLine[0] = '\0';
  351.     CurrentPosition = 0;
  352.     if (!redirect_fp)
  353.         fputs (prompt, stdout);
  354.     goto RETRY;
  355.     }
  356.  
  357.     if (NeedSave) {
  358.     if (!is_empty_line (CommandLine) || !look_var ("ignore-empty-line"))
  359.         addHistory (CommandLine);
  360.     /*
  361.      * put string to buffer
  362.      */
  363.     buf_put (output_buffer, CommandLine);
  364.     if (NeedNewLine == 1)
  365.         buf_put (output_buffer, "\n");
  366.     }
  367.  
  368.     if (NeedNewLine == 1)
  369.     (void) strcat (execute_command, "\n");
  370.  
  371. RETURN:
  372.     return (execute_command);
  373. }
  374.  
  375. /*
  376.  * Invoke appropliate function according to fucntion table
  377.  * Return value 1 means exit from line editing
  378.  */
  379. callfunc (ft, c)
  380.     FUNC ft[];
  381.     int c;
  382. {
  383.  
  384.     if (isIndirect(ft[(int) c])) {
  385.     FUNC *nft = maskIndirect (ft[(int)c]);
  386.     char nc;
  387.  
  388.     nc = (CHAR) getcharacter();
  389.     return (callfunc (nft, nc));
  390.     }
  391.     else
  392.     return ((*ft[(int) c]) (c));
  393. }
  394.  
  395. /*
  396.  * Beep and do nothing
  397.  */
  398. abort()
  399. {
  400.     (void) errorBell ();
  401.     return (0);
  402. }
  403.  
  404. /*
  405.  * Insert the character self
  406.  */
  407. self_insert(c)
  408.     CHAR c;
  409. {
  410.     register int i, nbyte = 1, currentNull;
  411. #ifdef KANJI
  412.     CHAR byte2;
  413. #endif KANJI
  414.  
  415.     currentNull = strlen (CommandLine);
  416.  
  417.     if (currentNull >= maxline) {
  418.         errorBell();
  419.     return (0);
  420.     }
  421.  
  422.     if (isctlchar(CommandLine[CurrentPosition]))
  423.     (void) putchar (BS);
  424. #ifdef KANJI
  425.     if (iskanji (c)) {
  426.     byte2 = (CHAR) getcharacter ();
  427.     putchar (c);
  428.     putchar (byte2);
  429.     nbyte = 2;
  430.     }
  431.     else
  432. #endif KANJI
  433.     putChar (c);
  434.     reverse_strcpy (
  435.     &CommandLine[CurrentPosition] + nbyte,
  436.     &CommandLine[CurrentPosition]
  437.     );
  438.     CurrentPosition += nbyte;
  439.     CommandLine[CurrentPosition - nbyte] = c;
  440. #ifdef KANJI
  441.     if (nbyte > 1) {
  442.     CommandLine[CurrentPosition - 1] = byte2;
  443.     }
  444. #endif KANJI
  445.     printS (&CommandLine [CurrentPosition]);
  446.  
  447.     if (CommandLine[CurrentPosition] != '\0') {
  448.     repeat (BS, howlong (&CommandLine[CurrentPosition + 1], 0));
  449.     (void) putchar (BS);
  450.     }
  451.     return (0);
  452. }
  453.  
  454. /*
  455.  * Insert string in current position
  456.  */
  457. insert_string (s)
  458.     CHAR *s;
  459. {
  460.     register int i, nbyte = strlen (s), currentNull;
  461.  
  462.     currentNull = strlen (CommandLine);
  463.  
  464.     if (currentNull + nbyte >= maxline - 1) {
  465.         errorBell();
  466.     return (0);
  467.     }
  468.  
  469.     if (isctlchar(CommandLine[CurrentPosition]))
  470.     (void) putchar (BS);
  471.     printS (s);
  472.     reverse_strcpy (
  473.     &CommandLine[CurrentPosition] + nbyte,    /* to */ 
  474.     &CommandLine[CurrentPosition]        /* from */
  475.     );
  476.     bcopy (s, &CommandLine[CurrentPosition], nbyte);
  477.     CurrentPosition += nbyte;
  478.  
  479.     if (CommandLine[CurrentPosition] != '\0') {
  480.     printS (&CommandLine[CurrentPosition]);
  481.     repeat (BS, howlong (&CommandLine[CurrentPosition], 0));
  482.     }
  483.     return (0);
  484. }
  485.  
  486. /*
  487.  * Yank string from kill buffer.
  488.  */
  489. yank_from_kill_buffer ()
  490. {
  491.     insert_string (KillBuffer);
  492. }
  493.  
  494. /*
  495.  * Set mark to current position
  496.  */
  497. mark ()
  498. {
  499.     set_mark (CurrentPosition);
  500.     return (0);
  501. }
  502.  
  503. /*
  504.  * Set mark to specified position
  505.  */
  506. set_mark (pos)
  507.     int pos;
  508. {
  509.     MarkPosition = pos;
  510.     return (0);
  511. }
  512.  
  513. /*
  514.  * Delete area from mark to current position to kill buffer
  515.  */
  516. delete_to_kill_buffer ()
  517. {
  518.     int n = abs (CurrentPosition - MarkPosition);
  519.  
  520.     if (MarkPosition < 0) {
  521.     errorBell();
  522.     return (0);
  523.     }
  524.  
  525.     if (CurrentPosition == MarkPosition)
  526.     return;
  527.  
  528.     if (CurrentPosition > MarkPosition) {
  529.     (void) moveto (MarkPosition);
  530.     }
  531.  
  532.     return (delete_next_n_character (n));
  533. }
  534.  
  535. /*
  536.  * Move to specified position.
  537.  */
  538. moveto (position)
  539. {
  540.     if (position < CurrentPosition)
  541.     while (position < CurrentPosition)
  542.         (void) backward_n_character (1);
  543.     else
  544.     while (position > CurrentPosition
  545. #ifdef KANJI
  546.         && !(CurrentPosition + 1 == position
  547.             && iskanji (CommandLine[CurrentPosition]))
  548. #endif KANJI
  549.     )
  550.         (void) forward_n_character (1);
  551. }
  552.  
  553. /*
  554.  * Move cursor to top of line
  555.  */
  556. beginning_of_line()
  557. {
  558.     register int i;
  559.  
  560.     for (i = CurrentPosition; i > 0; i--) {
  561.     if (isctlchar (CommandLine[i]))
  562.         (void) putchar (BS);
  563.     (void) putchar (BS);
  564.     }
  565.     CurrentPosition = 0;
  566.     return (0);
  567. }
  568.  
  569. #ifdef KANJI
  570. #define INC(i) if(iskanji(CommandLine[i])) i+=2; else i++;
  571. #define DEC(i) if(i>=2 && iskanji_in_string(CommandLine, i-2)) i-=2; else i--;
  572. #else KANJI
  573. #define INC(i) i++
  574. #define DEC(i) i--
  575. #endif KANJI
  576.  
  577. /*
  578.  * Move cursor to end of line
  579.  */
  580. end_of_line()
  581. {
  582.     register int    i;
  583.  
  584.     for (i = CurrentPosition; CommandLine[i]; i++) {
  585.     if (isctlchar (CommandLine[i]))
  586.         (void) putchar (unctl(CommandLine[i]));
  587.     else
  588.         (void) putchar (CommandLine[i]);
  589.     if (isctlchar(CommandLine[i+1]))
  590.         (void) putchar ('^');
  591.     }
  592.     CurrentPosition = i;
  593.     return (0);
  594. }
  595.  
  596. /*
  597.  * Move cursor left one space
  598.  */
  599. backward_character()
  600. {
  601.  
  602.     return (backward_n_character (1));
  603. }
  604.  
  605. /*
  606.  * Move cursor left "n" space
  607.  */
  608. backward_n_character(n)
  609.     int n;
  610. {
  611.     int space;
  612.     int i = CurrentPosition;
  613.  
  614.     if (n == 0)
  615.     return (0);
  616.     else if (n < 0)
  617.     return (forward_n_character (-n));
  618.     else if (n > CurrentPosition) {
  619.     errorBell ();
  620.     return (0);
  621.     }
  622.  
  623.     while (n-- && i >= 0) {
  624.     if (isctlchar (CommandLine[i]))
  625.         putchar (BS);
  626. #ifdef KANJI
  627.     if (i > 0 && iskanji_in_string (CommandLine, i-2)) {
  628.         (void) putchar (BS);
  629.         (void) putchar (BS);
  630.         i--;
  631.     }
  632.     else
  633. #endif KANJI
  634.     putchar (BS);
  635.     i--;
  636.     }
  637.     CurrentPosition = i;
  638.     return (0);
  639. }
  640.  
  641. /*
  642.  * Move cursor backward one word
  643.  */
  644. backward_word ()
  645. {
  646.  
  647.     return (backward_n_word (1));
  648. }
  649.  
  650. /*
  651.  * Move cursor backward n word
  652.  */
  653. backward_n_word (n)
  654.     int n;
  655. {
  656.     register int i = CurrentPosition, nchars = 0;
  657.  
  658.     if (i == 0) {
  659.     errorBell ();
  660.     return (0);
  661.     }
  662.  
  663. #ifdef KANJI
  664.     while (n--) {
  665.     DEC(i);
  666.     nchars++;
  667.  
  668.     while (1) {
  669.         if (i >= 2 && iskanji_in_string (CommandLine, i-2))
  670.         break;
  671.         else if (i > 0 && !iswordchar (CommandLine[i]))
  672.         i -= 1;
  673.         else
  674.         break;
  675.         
  676.         nchars++;
  677.     }
  678.     while (1) {
  679.         if (i >= 2 && iskanji_in_string (CommandLine, i - 2))
  680.         i -= 2;
  681.         else if (i > 0 && iswordchar (CommandLine [i -1]))
  682.         i -= 1;
  683.         else
  684.         break;
  685.         nchars++;
  686.     }
  687.     }
  688. #else KANJI
  689.     while (n--) {
  690.     i--, nchars++;
  691.     while (i > 0 && !iswordchar (CommandLine [i])) {
  692.         i--, nchars++;
  693.     }
  694.     while (i > 0 && iswordchar (CommandLine [i - 1])) {
  695.         i--, nchars++;
  696.     }
  697.     }
  698. #endif KANJI
  699.     return (backward_n_character (nchars));
  700. }
  701.  
  702. /*
  703.  * Move cursor backward one Word
  704.  */
  705. backward_Word ()
  706. {
  707.  
  708.     return (backward_n_Word (1));
  709. }
  710.  
  711. /*
  712.  * Move cursor backward n Word
  713.  */
  714. backward_n_Word (n)
  715.     int n;
  716. {
  717.     register int i = CurrentPosition, nchars = 0;
  718.  
  719.     if (i == 0) {
  720.     errorBell ();
  721.     return (0);
  722.     }
  723.  
  724. #ifdef KANJI
  725.     while (n--) {
  726.     DEC(i);
  727.     nchars++;
  728.  
  729.     while (1) {
  730.         if (i > 1 && iskanji_in_string (CommandLine, i - 2))
  731.         break;
  732.         else if (i > 0 && !iswordchar (CommandLine[i]))
  733.         i -= 1;
  734.         else
  735.         break;
  736.         
  737.         nchars++;
  738.     }
  739.     while (1) {
  740.         if (i > 2 && iskanji_in_string (CommandLine, i - 2))
  741.         i -= 2;
  742.         else if (i > 0 && iswordchar (CommandLine [i - 1]))
  743.         i -= 1;
  744.         else
  745.         break;
  746.         nchars++;
  747.     }
  748.     }
  749. #else KANJI
  750.     while (n--) {
  751.     i--, nchars++;
  752.     while (i > 0 && !isWordchar (CommandLine [i]))
  753.         i--, nchars++;
  754.     while (i > 0 && isWordchar (CommandLine [i - 1]))
  755.         i--, nchars++;
  756.     }
  757. #endif KANJI
  758.     return (backward_n_character (nchars));
  759. }
  760.  
  761. /*
  762.  * Move cursor forward one character
  763.  */
  764. forward_character()
  765. {
  766.  
  767.     return (forward_n_character (1));
  768. }
  769.  
  770. /*
  771.  * Move cursor forward n character
  772.  */
  773. forward_n_character(n)
  774.     int n;
  775. {
  776.     int space;
  777.     register int i = CurrentPosition;
  778.  
  779.     if (n == 0)
  780.     return (0);
  781.     else if (n < 0)
  782.     return (backward_n_character (-n));
  783.  
  784.     if (CommandLine [CurrentPosition] == '\0') {
  785.     errorBell ();
  786.     return (0);
  787.     }
  788.  
  789. #ifdef KANJI
  790.     if (iskanji (CommandLine[i])) {
  791.     (void) putchar (CommandLine[i++]);
  792.     (void) putchar (CommandLine[i++]);
  793.     }
  794.     else
  795. #endif KANJI
  796.     if (isctlchar(CommandLine[i]))
  797.     (void) putchar (unctl (CommandLine [i++]));
  798.     else
  799.     (void) putchar (CommandLine[i++]);
  800.  
  801.     while (--n && CommandLine [i]) {
  802. #ifdef KANJI
  803.     if (iskanji (CommandLine[i])) {
  804.         (void) putchar (CommandLine[i++]);
  805.         (void) putchar (CommandLine[i++]);
  806.     }
  807.     else
  808. #endif KANJI
  809.     putChar (CommandLine [i++]);
  810.     }
  811.  
  812.     if (isctlchar (CommandLine [i]))
  813.     putchar ('^');
  814.  
  815.     CurrentPosition = i;
  816.  
  817.     return (0);
  818. }
  819.  
  820. /*
  821.  * Move cursor forward one word
  822.  */
  823. forward_word ()
  824. {
  825.     return (forward_n_word (1));
  826. }
  827.  
  828. /*
  829.  * Move cursor forward n word
  830.  */
  831. forward_n_word (n)
  832.     int n;
  833. {
  834.     register int i = CurrentPosition, nchars = 0;
  835.  
  836.     if (CommandLine [i] == '\0') {
  837.     errorBell ();
  838.     return (0);
  839.     }
  840.  
  841.     while (n--) {
  842.     while (CommandLine [i] && iswordchar (CommandLine [i])) {
  843.         INC(i);
  844.         nchars++;
  845.     }
  846.     while (CommandLine [i] && !iswordchar (CommandLine [i])) {
  847.         INC(i);
  848.         nchars++;
  849.     }
  850.     }
  851.     return (forward_n_character (nchars));
  852. }
  853.  
  854. /*
  855.  * Move cursor forward one word
  856.  */
  857. forward_Word ()
  858. {
  859.     return (forward_n_Word (1));
  860. }
  861.  
  862. /*
  863.  * Move cursor forward n word
  864.  */
  865. forward_n_Word (n)
  866.     int n;
  867. {
  868.     register int i = CurrentPosition, nchars = 0;
  869.  
  870.     if (CommandLine [i] == '\0') {
  871.     errorBell ();
  872.     return (0);
  873.     }
  874.  
  875.     while (n--) {
  876.     while (CommandLine [i] && isWordchar (CommandLine [i])) {
  877.         INC(i);
  878.          nchars++;
  879.     }
  880.     while (CommandLine [i] && !isWordchar (CommandLine [i])) {
  881.         INC(i);
  882.          nchars++;
  883.     }
  884.     }
  885.     return (forward_n_character (nchars));
  886. }
  887.  
  888. /*
  889.  * Forward to end of word
  890.  */
  891. forward_to_end_of_word ()
  892. {
  893.  
  894.     return (forward_to_end_of_n_word (1));
  895. }
  896.  
  897. /*
  898.  * Forward to end of n word
  899.  */
  900. forward_to_end_of_n_word (n)
  901. {    
  902.     register int i = CurrentPosition, nchars = 0;
  903.  
  904.     if (CommandLine [i] == '\0') {
  905.     errorBell ();
  906.     return (0);
  907.     }
  908.  
  909.     INC(i);
  910.     while (n--) {
  911.     while (CommandLine [i] && !iswordchar (CommandLine [i])) {
  912.         INC(i);
  913.         nchars++;
  914.     }
  915.     while (CommandLine [i] && iswordchar (CommandLine [i])) {
  916.         INC(i);
  917.         nchars++;
  918.     }
  919.     }
  920.     DEC(i);
  921.     return (forward_n_character (nchars));
  922. }
  923.  
  924. /*
  925.  * Forward to end of word
  926.  */
  927. forward_to_end_of_Word ()
  928. {
  929.  
  930.     return (forward_to_end_of_n_Word (1));
  931. }
  932.  
  933. /*
  934.  * Forward to end of n word
  935.  */
  936. forward_to_end_of_n_Word (n)
  937. {    
  938.     register int i = CurrentPosition, nchars = 0;
  939.  
  940.     if (CommandLine [i] == '\0') {
  941.     errorBell ();
  942.     return (0);
  943.     }
  944.  
  945.     INC(i);
  946.     while (n--) {
  947.     while (CommandLine [i] && !isWordchar (CommandLine [i])) {
  948.         INC(i);
  949.         nchars++;
  950.     }
  951.     while (CommandLine [i] && isWordchar (CommandLine [i])) {
  952.         INC(i);
  953.         nchars++;
  954.     }
  955.     }
  956.     DEC(i);
  957.     return (forward_n_character (nchars));
  958. }
  959.  
  960. /*
  961.  * Delete previous one character
  962.  */
  963. delete_previous_character()
  964. {
  965.  
  966.     return (delete_previous_n_character (1));
  967. }
  968.  
  969. /*
  970.  * Delete previous n characters
  971.  */
  972. delete_previous_n_character(n)
  973.     int n;
  974. {
  975.     register int i, nbyte;
  976.     int deleteArea, restArea;
  977.  
  978.     if (CurrentPosition < n) {
  979.     errorBell ();
  980.     return (0);
  981.     }
  982.  
  983. #ifdef KANJI
  984.     for (nbyte = 0, i = CurrentPosition; n-- > 0 && i;)
  985.     if (i > 1 && iskanji_in_string (CommandLine, i - 2))
  986.         i -= 2, nbyte += 2;
  987.     else
  988.         i -= 1, nbyte += 1;
  989. #else KANJI
  990.     nbyte = n;
  991. #endif KANJI
  992.  
  993.     deleteArea = howlong (&CommandLine[CurrentPosition - nbyte], nbyte);
  994.     restArea = howlong (&CommandLine[CurrentPosition], 0);
  995.     if (isctlchar(CommandLine[CurrentPosition]))
  996.     (void) putchar (BS);
  997.     repeat(BS, deleteArea);
  998.     CurrentPosition -= nbyte;
  999.     strcpy (KillBuffer, &CommandLine [CurrentPosition]);
  1000.     KillBuffer [nbyte] = '\0';
  1001.     for (i = CurrentPosition; CommandLine[i + nbyte]; i++) {
  1002.     CommandLine[i] = CommandLine[i + nbyte];
  1003.     putChar (CommandLine[i]);
  1004.     }
  1005.     CommandLine[i] = '\0';
  1006.     repeat(SP, deleteArea);
  1007.     repeat(BS, deleteArea);
  1008.     if (isctlchar (CommandLine[CurrentPosition]))
  1009.     repeat(BS, restArea - 1);
  1010.     else
  1011.     repeat(BS, restArea);
  1012.     
  1013.     return (0);
  1014. }
  1015.  
  1016. /*
  1017.  * Delete previous one word
  1018.  */
  1019. delete_previous_word()
  1020. {
  1021.     
  1022.     return (delete_previous_n_word (1));
  1023. }
  1024.  
  1025. /*
  1026.  * Delete previous n word
  1027.  */
  1028. delete_previous_n_word(n)
  1029.     int n;
  1030. {
  1031.     register int i = CurrentPosition, nchars = 0;
  1032.  
  1033.     if (i == 0) {
  1034.     errorBell();
  1035.     return (0);
  1036.     }
  1037.  
  1038. #ifdef KANJI
  1039.     while (n--) {
  1040.     if (i>1 && iskanji_in_string (CommandLine, i-2))
  1041.         i--;
  1042.     i--, nchars++;
  1043.  
  1044.     while (1) {
  1045.         if (i > 1 && iskanji_in_string (CommandLine, i-2))
  1046.         break;
  1047.         else if (i > 0 && !iswordchar (CommandLine[i]))
  1048.         i -= 1;
  1049.         else
  1050.         break;
  1051.         
  1052.         nchars++;
  1053.     }
  1054.     while (1) {
  1055.         if (i > 2 && iskanji_in_string (CommandLine, i - 2))
  1056.         i -= 2;
  1057.         else if (i > 0 && iswordchar (CommandLine [i -1]))
  1058.         i -= 1;
  1059.         else
  1060.         break;
  1061.         nchars++;
  1062.     }
  1063.     }
  1064. #else KANJI
  1065.     while (n--) {
  1066.     i--, nchars++;
  1067.     while (i > 0 && !iswordchar (CommandLine [i]))
  1068.         i--, nchars++;
  1069.     while (i > 0 && iswordchar (CommandLine [i - 1]))
  1070.         i--, nchars++;
  1071.     }
  1072. #endif KANJI
  1073.  
  1074.     return (delete_previous_n_character (nchars));
  1075. }
  1076.  
  1077. /*
  1078.  * Delete previous one word
  1079.  */
  1080. delete_previous_Word()
  1081. {
  1082.     
  1083.     return (delete_previous_n_Word (1));
  1084. }
  1085.  
  1086. /*
  1087.  * Delete previous n word
  1088.  */
  1089. delete_previous_n_Word(n)
  1090.     int n;
  1091. {
  1092.     register int i = CurrentPosition, nchars = 0;
  1093.  
  1094.     if (i == 0) {
  1095.     errorBell();
  1096.     return (0);
  1097.     }
  1098.  
  1099. #ifdef KANJI
  1100.     while (n--) {
  1101.     if (i>1 && iskanji_in_string (CommandLine, i-2))
  1102.         i--;
  1103.     i--, nchars++;
  1104.  
  1105.     while (1) {
  1106.         if (i > 1 && iskanji_in_string (CommandLine, i-2))
  1107.         break;
  1108.         else if (i > 0 && !isWordchar (CommandLine[i]))
  1109.         i -= 1;
  1110.         else
  1111.         break;
  1112.         
  1113.         nchars++;
  1114.     }
  1115.     while (1) {
  1116.         if (i > 2 && iskanji_in_string (CommandLine, i - 2))
  1117.         i -= 2;
  1118.         else if (i > 0 && isWordchar (CommandLine [i -1]))
  1119.         i -= 1;
  1120.         else
  1121.         break;
  1122.         nchars++;
  1123.     }
  1124.     }
  1125. #else KANJI
  1126.     while (n--) {
  1127.     i--, nchars++;
  1128.     while (i > 0 && !isWordchar (CommandLine [i]))
  1129.         i--, nchars++;
  1130.     while (i > 0 && isWordchar (CommandLine [i - 1]))
  1131.         i--, nchars++;
  1132.     }
  1133. #endif KANJI
  1134.  
  1135.     return (delete_previous_n_character (nchars));
  1136. }
  1137.  
  1138. /*
  1139.  * Delete next one character
  1140.  */
  1141. delete_next_character ()
  1142. {
  1143.  
  1144.     return (delete_next_n_character (1));
  1145. }
  1146.  
  1147. /*
  1148.  * Delete next n character
  1149.  */
  1150. delete_next_n_character (n)
  1151.     int n;
  1152. {
  1153.     register int i, nbyte;
  1154.     int deleteArea, restArea;
  1155.  
  1156.     if (strlen (&CommandLine [CurrentPosition]) < n) {
  1157.     errorBell ();
  1158.     return (0);
  1159.     }
  1160.  
  1161. #ifdef KANJI
  1162.     {
  1163.     register CHAR *cp = &CommandLine[CurrentPosition];
  1164.  
  1165.     nbyte = 0;
  1166.     while (n-- > 0 && *cp)
  1167.         if (iskanji (*cp))
  1168.         cp += 2, nbyte += 2;
  1169.         else
  1170.         cp++, nbyte++;
  1171.     }
  1172. #else KANJI
  1173.     nbyte = n;
  1174. #endif KANJI
  1175.  
  1176.     deleteArea = howlong (&CommandLine[CurrentPosition], nbyte);
  1177.     restArea = howlong (&CommandLine[CurrentPosition + nbyte], 0);
  1178.     if (isctlchar(CommandLine[CurrentPosition]))
  1179.     (void) putchar (BS);
  1180.     strcpy (KillBuffer, CommandLine + CurrentPosition);
  1181.     KillBuffer [nbyte] = '\0';
  1182.     for (i = CurrentPosition; CommandLine[i + nbyte]; i++) {
  1183.     CommandLine[i] = CommandLine[i + nbyte];
  1184.     putChar (CommandLine[i]);
  1185.     }
  1186.     CommandLine[i] = '\0';
  1187.     repeat(SP, deleteArea);
  1188.     repeat(BS, deleteArea);
  1189.     if (isctlchar (CommandLine[CurrentPosition]))
  1190.     repeat(BS, restArea - 1);
  1191.     else
  1192.     repeat(BS, restArea);
  1193.     
  1194.     return (0);
  1195. }
  1196.  
  1197. /*
  1198.  * Delete next one word
  1199.  */
  1200. delete_next_word ()
  1201. {
  1202.     return (delete_next_n_word (1));
  1203. }
  1204.  
  1205. /*
  1206.  * Delete next n word
  1207.  */
  1208. delete_next_n_word (n)
  1209.     int n;
  1210. {
  1211.     register int i = CurrentPosition, nchars = 0;
  1212.  
  1213.     if (CommandLine [i] == '\0') {
  1214.     errorBell ();
  1215.     return (0);
  1216.     }
  1217.  
  1218.     while (n--) {
  1219.     while (CommandLine [i] && iswordchar (CommandLine [i])) {
  1220.         INC(i);
  1221.         nchars++;
  1222.     }
  1223.     while (CommandLine [i] && !iswordchar (CommandLine [i])) {
  1224.         INC(i);
  1225.         nchars++;
  1226.     }
  1227.     }
  1228.     return (delete_next_n_character (nchars));
  1229. }
  1230.  
  1231. /*
  1232.  * Delete next one word
  1233.  */
  1234. delete_next_Word ()
  1235. {
  1236.     return (delete_next_n_Word (1));
  1237. }
  1238.  
  1239. /*
  1240.  * Delete next n word
  1241.  */
  1242. delete_next_n_Word (n)
  1243.     int n;
  1244. {
  1245.     register int i = CurrentPosition, nchars = 0;
  1246.  
  1247.     if (CommandLine [i] == '\0') {
  1248.     errorBell ();
  1249.     return (0);
  1250.     }
  1251.  
  1252.     while (n--) {
  1253.     while (CommandLine [i] && isWordchar (CommandLine [i])) {
  1254.         INC(i);
  1255.         nchars++;
  1256.     }
  1257.     while (CommandLine [i] && !isWordchar (CommandLine [i])) {
  1258.         INC(i);
  1259.         nchars++;
  1260.     }
  1261.     }
  1262.     return (delete_next_n_character (nchars));
  1263. }
  1264.  
  1265. /*
  1266.  * Erase whole line
  1267.  */
  1268. delete_line()
  1269. {
  1270.     register int i = CurrentPosition;
  1271.     register int len;
  1272.  
  1273.     len = howlong (CommandLine, 0);
  1274.  
  1275.     /*
  1276.      * If cursor is there right part of line, move it to end of line
  1277.      * and erase character by character from end
  1278.      */
  1279.     if (howlong (CommandLine, CurrentPosition + 1) > len / 2) {
  1280.     (void) end_of_line ();
  1281.     repeat_string ("\b \b", len);
  1282.     }
  1283.     /*
  1284.      * If cursor is there on left part of line, move it to top of line
  1285.      * and erase line at once
  1286.      */
  1287.     else {
  1288.     (void) beginning_of_line ();
  1289.     if (isctlchar (CommandLine[0]))
  1290.         putchar (BS);
  1291.     repeat (SP, len);
  1292.     repeat (BS, len);
  1293.     }
  1294.     strcpy (KillBuffer, CommandLine);
  1295.     CurrentPosition = 0;
  1296.     CommandLine [0] = '\0';
  1297.     return (0);
  1298. }
  1299.  
  1300. /*
  1301.  * Delete characters from current position to top of line
  1302.  */
  1303. kill_to_top_of_line()
  1304. {
  1305.     int i = CurrentPosition;
  1306.  
  1307.     (void) beginning_of_line();
  1308.     return (delete_next_n_character (i));
  1309. }
  1310.  
  1311. /*
  1312.  * Delete characters from current position to end of line
  1313.  */
  1314. kill_to_end_of_line()
  1315. {
  1316.     register int    i, backCnt = 0;
  1317.  
  1318.     if (isctlchar(CommandLine[CurrentPosition])) {
  1319.         (void) putchar(BS);
  1320.     }
  1321.     for (i = CurrentPosition; CommandLine[i]; i++) {
  1322.     if (isctlchar(CommandLine[i])) {
  1323.         fputs("  ", stdout);
  1324.         backCnt++;
  1325.     }
  1326.     else
  1327.         (void) putchar (SP);
  1328.     backCnt++;
  1329.     }
  1330.     for (; backCnt; backCnt--)
  1331.     (void) putchar (BS);
  1332.     strcpy (KillBuffer, CommandLine + CurrentPosition);
  1333.     CommandLine[CurrentPosition] = '\0';
  1334.     return (0);
  1335. }
  1336.  
  1337. /*
  1338.  * Insert tab to current cursor position
  1339.  */
  1340. insert_tab()
  1341. {
  1342.  
  1343.     /* sorry, not implemented */
  1344.     return (self_insert ('\t'));
  1345. }
  1346.  
  1347. /*
  1348.  * Process new line
  1349.  */
  1350. new_line()
  1351. {
  1352.  
  1353.     (void) end_of_line;
  1354.     fputs ("\r\n", stdout);
  1355.     NeedNewLine = 1;
  1356.     NeedSave = 1;
  1357.  
  1358.     return (1);
  1359. }
  1360.  
  1361. /*
  1362.  * Check current position is top-of-line
  1363.  */
  1364. is_tol()
  1365. {
  1366.     return (CurrentPosition == 0);
  1367. }
  1368.  
  1369. /*
  1370.  * Check current position is end-of-line
  1371.  */
  1372. is_eol()
  1373. {
  1374.     return (CommandLine [CurrentPosition] == '\0');
  1375. }
  1376.  
  1377. /*
  1378.  * Check command line if it refer history or not
  1379.  */
  1380. refer_history()
  1381. {
  1382.     char   *historyExtract ();
  1383.     char   *his;
  1384.  
  1385.     if (CommandLine[0] != '!')
  1386.     return (NOT_PROCESSED);
  1387.  
  1388.     if (his = historyExtract (CommandLine)) {
  1389.     (void) strcpy (CommandLine, his);
  1390.     CurrentPosition = strlen (CommandLine);
  1391.     }
  1392.     else {
  1393.     fputs (CommandLine, stdout);
  1394.     fputs (" : Event not found.\r\n", stdout);
  1395.     (void) strcpy (CommandLine, "");
  1396.     CurrentPosition = 0;
  1397.     }
  1398.     fputs (prompt, stdout);
  1399.     print_com_line ();
  1400.     return (PROCESSED);
  1401. }
  1402.  
  1403. #define FORWARD        1
  1404. #define REVERSE        2
  1405.  
  1406. search_reverse ()
  1407. {
  1408.     return (search_history (REVERSE));
  1409. }
  1410.  
  1411. search_forward ()
  1412. {
  1413.     return (search_history (FORWARD));
  1414. }
  1415.  
  1416. search_history (direct)
  1417.     int direct;
  1418. {
  1419.     char *his, *search_reverse_history(), *search_forward_history();
  1420.     char *(*func)();
  1421.  
  1422.     if (direct == FORWARD)
  1423.     func = search_forward_history;
  1424.     else
  1425.     func = search_reverse_history;
  1426.  
  1427. AGAIN:
  1428.     if (his = (*func) (0)) {
  1429.     if (eq (his, CommandLine))
  1430.         goto AGAIN;
  1431.  
  1432.     (void) delete_line ();
  1433.     (void) insert_string (his);
  1434.     CurrentPosition = strlen (CommandLine);
  1435.     }
  1436.     else {
  1437.     (void) errorBell ();
  1438.  
  1439.     if (look_var ("verbose")) {
  1440.         char *cp;
  1441.  
  1442.         if ((cp = look_var ("search-string")) == NULL)
  1443.         cp = "";
  1444.         (void) clear_edit_line ();
  1445.         fprintf (stdout, "\"%s\": No match.\r\n", cp);
  1446.         (void) recover_edit_line ();
  1447.     }
  1448.     }
  1449.  
  1450.     return 0;
  1451. }
  1452.  
  1453.  
  1454. /*
  1455.  * Insert the character and flush buffer
  1456.  */
  1457. insert_and_flush(c)
  1458.     char c;
  1459. {
  1460.     (void) self_insert (c);
  1461.     return (1);
  1462. }
  1463.  
  1464. /*
  1465.  * Insert the character, but it means EOL. Therefore move cursor backward and
  1466.  * flush buffer
  1467.  */
  1468. send_eof()
  1469. {
  1470.     char c = tchars_buf.t_eofc;
  1471.  
  1472.     (void) self_insert (c);
  1473.     if (isctlchar (c))
  1474.     fputs ("\b\b", stdout);
  1475.     else
  1476.     fputs ("\b", stdout);
  1477.     return (1);
  1478. }
  1479.  
  1480. /*
  1481.  * Alarm for EOF on only the first time finding eof character
  1482.  */
  1483. alarm_on_eof ()
  1484. {
  1485.  
  1486.     errorBell ();
  1487.     (void) clear_edit_line ();
  1488.     printf ("EOF -- one more eof character to send eof to the process.\n");
  1489.     (void) recover_edit_line ();
  1490. }
  1491.  
  1492. /*
  1493.  * Clear screen
  1494.  */
  1495. clear_screen()
  1496. {
  1497.  
  1498.  
  1499.     if (term_clear) {
  1500.     (void) clear_edit_line ();
  1501.     fputs (term_clear, stdout);
  1502.     (void) recover_edit_line ();
  1503.     }
  1504.     else
  1505.     errorBell ();
  1506.  
  1507.     return (0);
  1508. }
  1509.  
  1510. /*
  1511.  * Get next history entry
  1512.  */
  1513. next_history()
  1514. {
  1515.     register char  *cp;
  1516.     char   *getNextHistory ();
  1517.     int diff;
  1518.  
  1519.     if ((cp = getNextHistory ()) == (char *)0) {
  1520.     errorBell ();
  1521.     return (0);
  1522.     }
  1523.     diff = howlong (CommandLine, 0) - howlong (cp, 0);
  1524.     (void) beginning_of_line ();
  1525.     if (isctlchar (CommandLine[0]))
  1526.     putchar (BS);
  1527.     printS (cp);
  1528.     if (diff > 0) {
  1529.     repeat (SP, diff);
  1530.     repeat (BS, diff);
  1531.     }
  1532.     (void) strcpy (CommandLine, cp);
  1533.     CurrentPosition = strlen (CommandLine);
  1534.     return (0);
  1535. }
  1536.  
  1537. /*
  1538.  * Get previous history
  1539.  */
  1540. previous_history()
  1541. {
  1542.     register char *cp;
  1543.     char *getPreviousHistory ();
  1544.     int diff;
  1545.  
  1546.     if ((cp = getPreviousHistory ()) == (char *)0) {
  1547.     errorBell ();
  1548.     return (0);
  1549.     }
  1550.  
  1551.     diff = howlong (CommandLine, 0) - howlong (cp, 0);
  1552.     (void) beginning_of_line ();
  1553.     if (isctlchar (CommandLine[0]))
  1554.     putchar (BS);
  1555.     printS (cp);
  1556.     if (diff > 0) {
  1557.     repeat (SP, diff);
  1558.     repeat (BS, diff);
  1559.     }
  1560.     (void) strcpy (CommandLine, cp);
  1561.     CurrentPosition = strlen (CommandLine);
  1562.     return (0);
  1563. }
  1564.  
  1565. /*
  1566.  * Show history
  1567.  */
  1568. show_history()
  1569. {
  1570.     int saveCP = CurrentPosition;
  1571.     char *cp;
  1572.     char *getHistory ();
  1573.     int showhist;
  1574.     
  1575.     (void) end_of_line ();
  1576.     CurrentPosition = saveCP;
  1577.     fputs("\r\n", stdout);
  1578.  
  1579.     hist_showHistory (lookd_var ("showhist"));
  1580.  
  1581.     fputs (prompt, stdout);
  1582.     (void) print_com_line();
  1583. }
  1584.  
  1585. /*
  1586.  * Do nothing
  1587.  */
  1588. ignore()
  1589. {
  1590.     return(0);
  1591. }
  1592.  
  1593. /*
  1594.  * Next character is literal
  1595.  */
  1596. literal_next()
  1597. {
  1598.  
  1599.     return (self_insert (getcharacter ()));
  1600. }
  1601.  
  1602. /*
  1603.  * Reprint command line
  1604.  */
  1605. reprint()
  1606. {
  1607.  
  1608.     (void) clear_edit_line ();
  1609.     (void) recover_edit_line ();
  1610.     return (0);
  1611. }
  1612.  
  1613. /*
  1614.  * Print whole command line and move cursor to the current position
  1615.  */
  1616. print_com_line()
  1617. {
  1618.  
  1619.     printS (CommandLine);
  1620.     if (CommandLine[CurrentPosition] != '\0') {
  1621.     repeat (BS, howlong(&CommandLine[CurrentPosition + 1], 0));
  1622.     (void) putchar (BS);
  1623.     }
  1624. }
  1625.  
  1626. /*
  1627.  * Calcurate space of string using "^" for control character
  1628.  */
  1629. howlong(s, n)
  1630.     char *s;
  1631.     int n;
  1632. {
  1633.     register char *sp;
  1634.     register int area = 0;
  1635.  
  1636.     if (n == 0)
  1637.     n = -1;
  1638.     for (sp = s; *sp && n; sp++, n--) {
  1639.     if (isctlchar(*sp))
  1640.         area += 2;
  1641.     else
  1642.         area += 1;
  1643.     }
  1644.     return (area);
  1645. }
  1646.  
  1647. /*
  1648.  * Repeat puting character n times
  1649.  */
  1650. repeat(c, n)
  1651.     char c;
  1652.     register int n;
  1653. {
  1654.     for (n = n; n; n--)
  1655.     (void) putchar(c);
  1656. }
  1657.  
  1658. /*
  1659.  * Repeat putting string n times
  1660.  */
  1661. repeat_string(s, n)
  1662.     char *s;
  1663.     register int n;
  1664. {
  1665.     for (n = n; n; n--)
  1666.     fputs(s, stdout);
  1667. }
  1668.  
  1669. /*
  1670.  * Expand file name
  1671.  */
  1672. expand_file_name ()
  1673. {
  1674.     CHAR *cp, *start_expand;
  1675.     char *x_dirname();
  1676.     char dir[256];
  1677.     char *fileList[256];
  1678.     CHAR line[256];
  1679.     DIR *dirp, *x_opendir();
  1680.     struct direct *dp;
  1681.     int found = 0;
  1682.     int i;
  1683.     int tilde_expanded = 0;
  1684.     CHAR *index(), *rindex();
  1685.     
  1686.     if (delimiters == NULL)
  1687.         delimiters = DEFAULT_DELIMITERS;
  1688.     strcpy (line, CommandLine);
  1689.     for (cp = &line[CurrentPosition] - 1; cp > line ; --cp) {
  1690.         if (index (delimiters, *(cp - 1)))
  1691.         break;
  1692.     }
  1693.     start_expand = cp;
  1694.     if (any ('/', cp)) {
  1695.     (void) strcpy (dir, cp);
  1696.     *(rindex (dir, '/') + 1) = '\0';
  1697.     cp = (CHAR *) (rindex (cp, '/') + 1);
  1698.     }
  1699.     else
  1700.     strcpy (dir, ".");
  1701.  
  1702.     if ((dirp = x_opendir (dir)) == NULL) {
  1703.     errorBell ();
  1704.     return (0);
  1705.     }
  1706.  
  1707.     for (dp = readdir(dirp), i = 0; dp != NULL; dp = readdir(dirp)) {
  1708.  
  1709.     if (*cp == '\0')
  1710.         break;
  1711.  
  1712.     if (*cp != '.' && *(dp->d_name) == '.')
  1713.         continue;
  1714.  
  1715.     if (prefix (cp, dp->d_name)) {
  1716.         char *fcp;
  1717.  
  1718. # ifdef ALLOCA
  1719.           fcp = (char *) alloca (strlen (dp->d_name) + 1);
  1720. # else ALLOCA
  1721.           fcp = (char *) malloc (strlen (dp->d_name) + 1);
  1722. # endif ALLOCA
  1723.         if (fcp == 0) {
  1724.         fputs ("\r\n", stdout);
  1725.         perror ("alloca:");
  1726.         reprint ();
  1727.         longjmp (jbuf);
  1728.         }
  1729.         strcpy (fcp, dp->d_name);
  1730.         fileList [i++] = fcp;
  1731.     }
  1732.     }
  1733.     fileList [i] = (char *) 0;
  1734.  
  1735.     if (*start_expand == '~' && look_var ("expand-tilde")) {
  1736.     char *buf [256], *p;
  1737.  
  1738.     strcpy (buf, start_expand);
  1739.     p = x_dirname (buf);
  1740.     if (!eq (p, buf)) {
  1741.         (void) moveto (start_expand - line);
  1742.         (void) kill_to_end_of_line ();
  1743.         (void) insert_string (x_dirname (buf));
  1744.         tilde_expanded = 1;
  1745.     }
  1746.     }
  1747.  
  1748.     switch (i) {
  1749.  
  1750.     case 0:
  1751.         if (tilde_expanded == 0)
  1752.         errorBell ();
  1753.         break;
  1754.  
  1755.     case 1:
  1756.         (void) end_of_line ();
  1757.         (void) insert_string (fileList[0] + strlen (cp));
  1758.         break;
  1759.  
  1760.     default:
  1761.         {
  1762.         char *one, *other;
  1763.         char *c1, *c2;
  1764.         int i;
  1765.  
  1766.         one = fileList [0];
  1767.         for (i = 1; other = fileList [i]; i++) {
  1768.             for (c1 = one, c2 = other; *c1 && *c2; c1++, c2++)
  1769.             if (*c1 != *c2)
  1770.                 break;
  1771.             *c1 = '\0';
  1772.         }
  1773.         errorBell ();
  1774.         (void) end_of_line ();
  1775.         (void) insert_string (fileList[0] + strlen (cp));
  1776.         }
  1777.         break;
  1778.     }
  1779.  
  1780. # ifndef ALLOCA
  1781.     for (i = 0; fileList [i]; i++)
  1782.     free (fileList [i]);
  1783. # endif ALLOCA
  1784.  
  1785.     closedir(dirp);
  1786.     return (0);
  1787. }
  1788.  
  1789. /*
  1790.  * List file name
  1791.  */
  1792. list_file_name ()
  1793. {
  1794.     CHAR *cp;
  1795.     char dir[256];
  1796.     DIR *dirp, *x_opendir();
  1797.     CHAR *index(), *rindex();
  1798.  
  1799.     if (delimiters == NULL)
  1800.         delimiters = DEFAULT_DELIMITERS;
  1801.     for (cp = (CHAR *) index (CommandLine, '\0'); cp > CommandLine ; --cp) {
  1802.         if (index (delimiters, *(cp - 1))) {
  1803.         break;
  1804.     }
  1805.     }
  1806. #ifdef RINFO
  1807.     /*
  1808.      * This is an experimental code for rinfod, which serves remote
  1809.      * information about file, process, etc.
  1810.      */
  1811.     if (any (':', cp)) {
  1812.     char *host, *pattern;
  1813.  
  1814.     (void) strcpy (dir, cp);
  1815.     host = dir;
  1816.     *(index (host, ':')) = '\0';
  1817.     pattern = (index (cp, ':') + 1);;
  1818.  
  1819.     (void) clear_edit_line();
  1820.     list_remote_file (host, pattern);
  1821.     (void) recover_edit_line();
  1822.     return;
  1823.     }
  1824. #endif
  1825.     if (any ('/', cp)) {
  1826.     (void) strcpy (dir, cp);
  1827.     *(rindex (dir, '/') + 1) = '\0';
  1828.     cp = (CHAR *) (rindex (cp, '/') + 1);
  1829.     }
  1830.     else
  1831.     strcpy (dir, ".");
  1832.  
  1833.  
  1834.     if ((dirp = x_opendir (dir)) == NULL) {
  1835.     errorBell ();
  1836.     return (0);
  1837.     }
  1838.  
  1839.     (void) clear_edit_line();
  1840.     ls (dirp, cp);
  1841.     closedir(dirp);
  1842.     (void) recover_edit_line();
  1843.  
  1844.     return (0);
  1845. }
  1846.  
  1847. int    rememberPosition;
  1848.  
  1849. clear_edit_line ()
  1850. {
  1851.  
  1852.     if (editstatus == NOTEDITING)
  1853.     return;
  1854.  
  1855.     rememberPosition = CurrentPosition;
  1856.     (void) end_of_line ();
  1857.     (void) fputs ("\r\n", stdout);
  1858. }
  1859.  
  1860. recover_edit_line ()
  1861. {
  1862.  
  1863.     if (editstatus == NOTEDITING)
  1864.     return;
  1865.  
  1866.     if (rememberPosition < 0)
  1867.     return;
  1868.     CurrentPosition = rememberPosition;
  1869.     rememberPosition = -1;
  1870.     if (prompt)
  1871.     fputs (prompt, stdout);
  1872.     (void) print_com_line();
  1873. }
  1874.  
  1875. #define MAXFILES 256
  1876.  
  1877. /*
  1878.  * Do ls
  1879.  */
  1880. ls (dirp, prefixstring)
  1881.     DIR *dirp;
  1882.     char *prefixstring;
  1883. {
  1884.     struct direct *dp;
  1885.     char *fileList[MAXFILES + 1];
  1886.     int i, j;
  1887.     int maxlen = 0;
  1888.     int files;        /* number of file */
  1889.     int fpl;        /* file par line */
  1890.     int cpf;        /* column par file */
  1891.     int fpc;        /* file par column */
  1892.     int COL = 80;
  1893.     char format[10];
  1894.     int scmp();
  1895.     
  1896.     for (dp = readdir(dirp), i = 0; dp != NULL; dp = readdir(dirp)) {
  1897.     char *fcp;
  1898.  
  1899.     if (i >= MAXFILES) {
  1900.         printf ("Too many files\n");
  1901.         break;
  1902.     }
  1903.  
  1904.     if (dp->d_ino == (unsigned long) 0
  1905.             || (prefixstring[0] != '.' && dp->d_name[0] == '.'))
  1906.         continue;
  1907.     if (prefix (prefixstring, dp->d_name)) {
  1908. # ifdef ALLOCA
  1909.           fcp = (char *) alloca (strlen (dp->d_name) + 1);
  1910. # else ALLOCA
  1911.           fcp = (char *) malloc (strlen (dp->d_name) + 1);
  1912. # endif ALLOCA
  1913.         if (fcp == 0) {
  1914.         fputs ("\r\n", stdout);
  1915.         perror ("alloca:");
  1916.         reprint ();
  1917.         longjmp (jbuf);
  1918.         }
  1919.         strcpy (fcp, dp->d_name);
  1920.         fileList [i++] = fcp;
  1921.         maxlen = max (maxlen, strlen (dp->d_name));
  1922.     }
  1923.     }
  1924.     fileList [i] = (char *) 0;
  1925.  
  1926.     if (i == 0)
  1927.     goto BACK;
  1928.  
  1929.     files = i;
  1930.  
  1931.     qsort (fileList, i, sizeof (char *), scmp);
  1932.  
  1933.     if (debug)
  1934.     printf ("%d files\n", files);
  1935.  
  1936.     cpf = maxlen + 1;
  1937.     fpl = COL / cpf;
  1938.     if (fpl == 0) fpl = 1;
  1939.     fpc = (files + fpl - 1) / fpl;
  1940.  
  1941.     sprintf (format, "%%-%ds", cpf);
  1942.     for (i = 0; i < fpc; i++) {
  1943.     for (j = 0; j < fpl - 1; j++)
  1944.         if (i + j * fpc < files)
  1945.         printf (format, fileList[i + (j * fpc)]);
  1946.     if (i + (fpc * (fpl - 1)) < files)
  1947.         printf ("%s", fileList[i + (fpc * (fpl - 1))]);
  1948.     fputs ("\n", stdout);
  1949.     }
  1950.  
  1951. BACK:
  1952.  
  1953. # ifndef ALLOCA
  1954.     for (i = 0; fileList [i]; i++)
  1955.     free (fileList [i]);
  1956. # endif ALLOCA
  1957.     return;
  1958. }
  1959.  
  1960. #ifdef RINFO
  1961.  
  1962. #include "../rinfo/rinfo.h"
  1963.  
  1964. list_remote_file (host, pattern)
  1965.     char *host, *pattern;
  1966. {
  1967.     struct slist *slp, *getfilelist();
  1968.     int i, j;
  1969.     char format [64];
  1970.     int COL = 80;
  1971.     int  maxlen, cpf, fpl, fpc;
  1972.     int files;
  1973.  
  1974.     slp = getfilelist (host, pattern);
  1975.     files = slp->s_cnt;
  1976.  
  1977.     COL = 80;
  1978.     maxlen = 0;
  1979.     for (i = 0; i < files; i++) {
  1980.     int len;
  1981.  
  1982.     if ((len = strlen (*(slp->s_list + i))) > maxlen)
  1983.         maxlen = len;
  1984.     }
  1985.  
  1986.     cpf = maxlen + 1;
  1987.     fpl = COL / cpf;
  1988.     if (fpl == 0)
  1989.     fpl = 1;
  1990.     fpc = (files + fpl - 1) / fpl;
  1991.  
  1992.     sprintf (format, "%%-%ds", cpf);
  1993.     for (i = 0; i < fpc; i++) {
  1994.     for (j = 0; j < fpl - 1; j++) {
  1995.         if (i + j * fpc < slp->s_cnt)
  1996.         printf (format, *(slp->s_list + (i + (j * fpc))));
  1997.     }
  1998.     if (i + (fpc * (fpl - 1)) < files)
  1999.         printf ("%s", slp->s_list[i + (fpc * (fpl - 1))]);
  2000.     fputs ("\n", stdout);
  2001.     }
  2002. }
  2003. #endif RINFO
  2004.  
  2005. bind_key (ft, func, s, dfunc)
  2006.     FUNC ft[];        /* Function table */
  2007.     FUNC func;        /* Function to be binded */
  2008.     char *s;        /* String to bind */
  2009.     FUNC dfunc;        /* Default function for table allocating */
  2010. {
  2011.     char tmps[16];
  2012.  
  2013.     if (s[0] == '\\' && s[1] == '^' && s[2] != NULL) {
  2014.     tmps[0] = toctrl (s[2]);
  2015.     strcpy (&tmps[1], &s[3]);
  2016.     s = tmps;
  2017.     }
  2018.  
  2019.     /*
  2020.      * If the string contain only one character, put the function to
  2021.      * appropriate position in the table.
  2022.      */
  2023.     if (*(s+1) == NULL) {
  2024.     if (isIndirect (ft[(int) *s]))
  2025.         free (maskIndirect (ft[(int) *s]));
  2026.  
  2027.     ft[(int) *s] = func;
  2028.     return (1);
  2029.     }
  2030.     else {
  2031.     FUNC *nft = (FUNC *) 0;
  2032.     int status;
  2033.  
  2034.     /*
  2035.      * If the entry doesn't have indirect function table, allocate it.
  2036.      */
  2037.     if (! (isIndirect (ft[(int) *s]))) {
  2038.         register int i;
  2039.  
  2040.         nft = (FUNC *) calloc (sizeof (FUNC), 256);
  2041.         /*
  2042.          * If failed in allocating, return 0.
  2043.          */
  2044.         if (nft == 0)
  2045.         return (0);
  2046.  
  2047.         /*
  2048.          * Initialize the table with default function
  2049.          */
  2050.         for (i = 0; i < 256; i++)
  2051.         nft [i] = dfunc;
  2052.         ft[(int) *s] = setIndirect (nft);
  2053.     }
  2054.  
  2055.     status = bind_key (maskIndirect (ft[(int) *s]), func, s+1, dfunc);
  2056.     /*
  2057.      * If the binding failed and the table was allocated in this function
  2058.      * free the table and return with same status.
  2059.      */
  2060.     if (status == 0 && nft)
  2061.         free (nft);
  2062.     return (status);
  2063.     }
  2064. }
  2065. \End\Of\File\
  2066. else
  2067.   echo "will not over write ./fep_edit.c"
  2068. fi
  2069. echo "Finished archive 3 of 5"
  2070. exit
  2071.  
  2072.