home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / less-321-src.tgz / tar.out / fsf / less / cmdbuf.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  19KB  |  985 lines

  1. /*
  2.  * Copyright (c) 1984,1985,1989,1994,1995,1996  Mark Nudelman
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice in the documentation and/or other materials provided with 
  12.  *    the distribution.
  13.  *
  14.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
  15.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  17.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
  18.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  19.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
  20.  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
  21.  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
  22.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
  23.  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 
  24.  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25.  */
  26.  
  27.  
  28. /*
  29.  * Functions which manipulate the command buffer.
  30.  * Used only by command() and related functions.
  31.  */
  32.  
  33. #include "less.h"
  34. #include "cmd.h"
  35.  
  36. extern int sc_width;
  37.  
  38. static char cmdbuf[CMDBUF_SIZE]; /* Buffer for holding a multi-char command */
  39. static int cmd_col;        /* Current column of the cursor */
  40. static int prompt_col;        /* Column of cursor just after prompt */
  41. static char *cp;        /* Pointer into cmdbuf */
  42. static int cmd_offset;        /* Index into cmdbuf of first displayed char */
  43. static int literal;        /* Next input char should not be interpreted */
  44.  
  45. #if TAB_COMPLETE_FILENAME
  46. static int cmd_complete();
  47. /*
  48.  * These variables are statics used by cmd_complete.
  49.  */
  50. static int in_completion = 0;
  51. static char *tk_text;
  52. static char *tk_original;
  53. static char *tk_ipoint;
  54. static char *tk_trial;
  55. static struct textlist tk_tlist;
  56. #endif
  57.  
  58. static int cmd_left();
  59. static int cmd_right();
  60.  
  61. #if CMD_HISTORY
  62. /*
  63.  * A mlist structure represents a command history.
  64.  */
  65. struct mlist
  66. {
  67.     struct mlist *next;
  68.     struct mlist *prev;
  69.     struct mlist *curr_mp;
  70.     char *string;
  71. };
  72.  
  73. /*
  74.  * These are the various command histories that exist.
  75.  */
  76. struct mlist mlist_search =  
  77.     { &mlist_search,  &mlist_search,  &mlist_search,  NULL };
  78. public void constant *ml_search = (void *) &mlist_search;
  79.  
  80. struct mlist mlist_examine = 
  81.     { &mlist_examine, &mlist_examine, &mlist_examine, NULL };
  82. public void constant *ml_examine = (void *) &mlist_examine;
  83.  
  84. #if SHELL_ESCAPE || PIPEC
  85. struct mlist mlist_shell =   
  86.     { &mlist_shell,   &mlist_shell,   &mlist_shell,   NULL };
  87. public void constant *ml_shell = (void *) &mlist_shell;
  88. #endif
  89.  
  90. #else /* CMD_HISTORY */
  91.  
  92. /* If CMD_HISTORY is off, these are just flags. */
  93. public void constant *ml_search = (void *)1;
  94. public void constant *ml_examine = (void *)2;
  95. #if SHELL_ESCAPE || PIPEC
  96. public void constant *ml_shell = (void *)3;
  97. #endif
  98.  
  99. #endif /* CMD_HISTORY */
  100.  
  101. /*
  102.  * History for the current command.
  103.  */
  104. static struct mlist *curr_mlist = NULL;
  105.  
  106.  
  107. /*
  108.  * Reset command buffer (to empty).
  109.  */
  110.     public void
  111. cmd_reset()
  112. {
  113.     cp = cmdbuf;
  114.     *cp = '\0';
  115.     cmd_col = 0;
  116.     cmd_offset = 0;
  117.     literal = 0;
  118. }
  119.  
  120. /*
  121.  * Clear command line on display.
  122.  */
  123.     public void
  124. clear_cmd()
  125. {
  126.     clear_bot();
  127.     cmd_col = prompt_col = 0;
  128. }
  129.  
  130. /*
  131.  * Display a string, usually as a prompt for input into the command buffer.
  132.  */
  133.     public void
  134. cmd_putstr(s)
  135.     char *s;
  136. {
  137.     putstr(s);
  138.     cmd_col += strlen(s);
  139.     prompt_col += strlen(s);
  140. }
  141.  
  142. /*
  143.  * How many characters are in the command buffer?
  144.  */
  145.     public int
  146. len_cmdbuf()
  147. {
  148.     return (strlen(cmdbuf));
  149. }
  150.  
  151. /*
  152.  * Repaint the line from cp onwards.
  153.  * Then position the cursor just after the char old_cp (a pointer into cmdbuf).
  154.  */
  155.     static void
  156. cmd_repaint(old_cp)
  157.     char *old_cp;
  158. {
  159.     char *p;
  160.  
  161.     /*
  162.      * Repaint the line from the current position.
  163.      */
  164.     clear_eol();
  165.     for ( ;  *cp != '\0';  cp++)
  166.     {
  167.         p = prchar(*cp);
  168.         if (cmd_col + strlen(p) >= sc_width)
  169.             break;
  170.         putstr(p);
  171.         cmd_col += strlen(p);
  172.     }
  173.  
  174.     /*
  175.      * Back up the cursor to the correct position.
  176.      */
  177.     while (cp > old_cp)
  178.         cmd_left();
  179. }
  180.  
  181. /*
  182.  * Put the cursor at "home" (just after the prompt),
  183.  * and set cp to the corresponding char in cmdbuf.
  184.  */
  185.     static void
  186. cmd_home()
  187. {
  188.     while (cmd_col > prompt_col)
  189.     {
  190.         putbs();
  191.         cmd_col--;
  192.     }
  193.  
  194.     cp = &cmdbuf[cmd_offset];
  195. }
  196.  
  197. /*
  198.  * Shift the cmdbuf display left a half-screen.
  199.  */
  200.     static void
  201. cmd_lshift()
  202. {
  203.     char *s;
  204.     char *save_cp;
  205.     int cols;
  206.  
  207.     /*
  208.      * Start at the first displayed char, count how far to the
  209.      * right we'd have to move to reach the center of the screen.
  210.      */
  211.     s = cmdbuf + cmd_offset;
  212.     cols = 0;
  213.     while (cols < (sc_width - prompt_col) / 2 && *s != '\0')
  214.         cols += strlen(prchar(*s++));
  215.  
  216.     cmd_offset = s - cmdbuf;
  217.     save_cp = cp;
  218.     cmd_home();
  219.     cmd_repaint(save_cp);
  220. }
  221.  
  222. /*
  223.  * Shift the cmdbuf display right a half-screen.
  224.  */
  225.     static void
  226. cmd_rshift()
  227. {
  228.     char *s;
  229.     char *p;
  230.     char *save_cp;
  231.     int cols;
  232.  
  233.     /*
  234.      * Start at the first displayed char, count how far to the
  235.      * left we'd have to move to traverse a half-screen width
  236.      * of displayed characters.
  237.      */
  238.     s = cmdbuf + cmd_offset;
  239.     cols = 0;
  240.     while (cols < (sc_width - prompt_col) / 2 && s > cmdbuf)
  241.     {
  242.         p = prchar(*--s);
  243.         cols += strlen(p);
  244.     }
  245.  
  246.     cmd_offset = s - cmdbuf;
  247.     save_cp = cp;
  248.     cmd_home();
  249.     cmd_repaint(save_cp);
  250. }
  251.  
  252. /*
  253.  * Move cursor right one character.
  254.  */
  255.     static int
  256. cmd_right()
  257. {
  258.     char *p;
  259.     
  260.     if (*cp == '\0')
  261.     {
  262.         /* 
  263.          * Already at the end of the line.
  264.          */
  265.         return (CC_OK);
  266.     }
  267.     p = prchar(*cp);
  268.     if (cmd_col + strlen(p) >= sc_width)
  269.         cmd_lshift();
  270.     else if (cmd_col + strlen(p) == sc_width - 1 && cp[1] != '\0')
  271.         cmd_lshift();
  272.     cp++;
  273.     putstr(p);
  274.     cmd_col += strlen(p);
  275.     return (CC_OK);
  276. }
  277.  
  278. /*
  279.  * Move cursor left one character.
  280.  */
  281.     static int
  282. cmd_left()
  283. {
  284.     char *p;
  285.     
  286.     if (cp <= cmdbuf)
  287.     {
  288.         /* Already at the beginning of the line */
  289.         return (CC_OK);
  290.     }
  291.     p = prchar(cp[-1]);
  292.     if (cmd_col < prompt_col + strlen(p))
  293.         cmd_rshift();
  294.     cp--;
  295.     cmd_col -= strlen(p);
  296.     while (*p++ != '\0')
  297.         putbs();
  298.     return (CC_OK);
  299. }
  300.  
  301. /*
  302.  * Insert a char into the command buffer, at the current position.
  303.  */
  304.     static int
  305. cmd_ichar(c)
  306.     int c;
  307. {
  308.     int col;
  309.     char *s;
  310.     
  311.     if (strlen(cmdbuf) >= sizeof(cmdbuf)-2)
  312.     {
  313.         /*
  314.          * No room in the command buffer for another char.
  315.          */
  316.         bell();
  317.         return (CC_ERROR);
  318.     }
  319.         
  320.     /*
  321.      * Insert the character into the buffer.
  322.      */
  323.     for (s = &cmdbuf[strlen(cmdbuf)];  s >= cp;  s--)
  324.         s[1] = s[0];
  325.     *cp = c;
  326.     /*
  327.      * Reprint the tail of the line from the inserted char.
  328.      */
  329.     cmd_repaint(cp);
  330.     cmd_right();
  331.     return (CC_OK);
  332. }
  333.  
  334. /*
  335.  * Backspace in the command buffer.
  336.  * Delete the char to the left of the cursor.
  337.  */
  338.     static int
  339. cmd_erase()
  340. {
  341.     register char *s;
  342.     char *p;
  343.     int col;
  344.  
  345.     if (cp == cmdbuf)
  346.     {
  347.         /*
  348.          * Backspace past beginning of the buffer:
  349.          * this usually means abort the command.
  350.          */
  351.         return (CC_QUIT);
  352.     }
  353.     /*
  354.      * Move cursor left (to the char being erased).
  355.      */
  356.     cmd_left();
  357.     /*
  358.      * Remove the char from the buffer (shift the buffer left).
  359.      */
  360.     for (s = cp;  *s != '\0';  s++)
  361.         s[0] = s[1];
  362.     /*
  363.      * Repaint the buffer after the erased char.
  364.      */
  365.     cmd_repaint(cp);
  366.     
  367.     /*
  368.      * This is rather weird.
  369.      * We say that erasing the entire command string causes us
  370.      * to abort the current command, BUT ONLY IF there is no history
  371.      * for this type of command.  This causes commands like search (/)
  372.      * and edit (:e) to stay active even if we erase the entire string,
  373.      * but commands like <digit> and - go away when we erase the string.
  374.      * (See same thing in cmd_kill.)
  375.      */
  376.     if (curr_mlist == NULL && cp == cmdbuf && *cp == '\0')
  377.         return (CC_QUIT);
  378.     return (CC_OK);
  379. }
  380.  
  381. /*
  382.  * Delete the char under the cursor.
  383.  */
  384.     static int
  385. cmd_delete()
  386. {
  387.     char *p;
  388.     
  389.     if (*cp == '\0')
  390.     {
  391.         /*
  392.          * At end of string; there is no char under the cursor.
  393.          */
  394.         return (CC_OK);
  395.     }
  396.     /*
  397.      * Move right, then use cmd_erase.
  398.      */
  399.     cmd_right();
  400.     cmd_erase();
  401.     return (CC_OK);
  402. }
  403.  
  404. /*
  405.  * Delete the "word" to the left of the cursor.
  406.  */
  407.     static int
  408. cmd_werase()
  409. {
  410.     if (cp > cmdbuf && cp[-1] == ' ')
  411.     {
  412.         /*
  413.          * If the char left of cursor is a space,
  414.          * erase all the spaces left of cursor (to the first non-space).
  415.          */
  416.         while (cp > cmdbuf && cp[-1] == ' ')
  417.             (void) cmd_erase();
  418.     } else
  419.     {
  420.         /*
  421.          * If the char left of cursor is not a space,
  422.          * erase all the nonspaces left of cursor (the whole "word").
  423.          */
  424.         while (cp > cmdbuf && cp[-1] != ' ')
  425.             (void) cmd_erase();
  426.     }
  427.     return (CC_OK);
  428. }
  429.  
  430. /*
  431.  * Delete the "word" under the cursor.
  432.  */
  433.     static int
  434. cmd_wdelete()
  435. {
  436.     if (*cp == ' ')
  437.     {
  438.         /*
  439.          * If the char under the cursor is a space,
  440.          * delete it and all the spaces right of cursor.
  441.          */
  442.         while (*cp == ' ')
  443.             (void) cmd_delete();
  444.     } else
  445.     {
  446.         /*
  447.          * If the char under the cursor is not a space,
  448.          * delete it and all nonspaces right of cursor (the whole word).
  449.          */
  450.         while (*cp != ' ' && *cp != '\0')
  451.             (void) cmd_delete();
  452.     }
  453.     return (CC_OK);
  454. }
  455.  
  456. /*
  457.  * Delete all chars in the command buffer.
  458.  */
  459.     static int
  460. cmd_kill()
  461. {
  462.     if (cmdbuf[0] == '\0')
  463.     {
  464.         /*
  465.          * Buffer is already empty; abort the current command.
  466.          */
  467.         return (CC_QUIT);
  468.     }
  469.     cmd_offset = 0;
  470.     cmd_home();
  471.     *cp = '\0';
  472.     cmd_repaint(cp);
  473.     /*
  474.      * Same weirdness as in cmd_erase.
  475.      * If the current command has no history, abort the current command.
  476.      */
  477.     if (curr_mlist == NULL)
  478.         return (CC_QUIT);
  479.     return (CC_OK);
  480. }
  481.  
  482. /*
  483.  * Select an mlist structure to be the current command history.
  484.  */
  485.     public void
  486. set_mlist(mlist)
  487.     void *mlist;
  488. {
  489.     curr_mlist = (struct mlist *) mlist;
  490. }
  491.  
  492. #if CMD_HISTORY
  493. /*
  494.  * Move up or down in the currently selected command history list.
  495.  */
  496.     static int
  497. cmd_updown(action)
  498.     int action;
  499. {
  500.     char *p;
  501.     char *s;
  502.     
  503.     if (curr_mlist == NULL)
  504.     {
  505.         /*
  506.          * The current command has no history list.
  507.          */
  508.         bell();
  509.         return (CC_OK);
  510.     }
  511.     cmd_home();
  512.     clear_eol();
  513.     /*
  514.      * Move curr_mp to the next/prev entry.
  515.      */
  516.     if (action == EC_UP)
  517.         curr_mlist->curr_mp = curr_mlist->curr_mp->prev;
  518.     else
  519.         curr_mlist->curr_mp = curr_mlist->curr_mp->next;
  520.     /*
  521.      * Copy the entry into cmdbuf and echo it on the screen.
  522.      */
  523.     s = curr_mlist->curr_mp->string;
  524.     if (s == NULL)
  525.         s = "";
  526.     for (cp = cmdbuf;  *s != '\0';  s++)
  527.     {
  528.         *cp = *s;
  529.         cmd_right();
  530.     }
  531.     *cp = '\0';
  532.     return (CC_OK);
  533. }
  534. #endif
  535.  
  536. /*
  537.  * Accept the command in the command buffer.
  538.  * Add it to the currently selected history list.
  539.  */
  540.     public void
  541. cmd_accept()
  542. {
  543. #if CMD_HISTORY
  544.     struct mlist *ml;
  545.     
  546.     /*
  547.      * Nothing to do if there is no currently selected history list.
  548.      */
  549.     if (curr_mlist == NULL)
  550.         return;
  551.     /*
  552.      * Don't save a trivial command.
  553.      */
  554.     if (strlen(cmdbuf) == 0)
  555.         return;
  556.     /*
  557.      * Don't save if a duplicate of a command which is already in the history.
  558.      * But select the one already in the history to be current.
  559.      */
  560.     for (ml = curr_mlist->next;  ml != curr_mlist;  ml = ml->next)
  561.     {
  562.         if (strcmp(ml->string, cmdbuf) == 0)
  563.             break;
  564.     }
  565.     if (ml == curr_mlist)
  566.     {
  567.         /*
  568.          * Did not find command in history.
  569.          * Save the command and put it at the end of the history list.
  570.          */
  571.         ml = (struct mlist *) ecalloc(1, sizeof(struct mlist));
  572.         ml->string = save(cmdbuf);
  573.         ml->next = curr_mlist;
  574.         ml->prev = curr_mlist->prev;
  575.         curr_mlist->prev->next = ml;
  576.         curr_mlist->prev = ml;
  577.     }
  578.     /*
  579.      * Point to the cmd just after the just-accepted command.
  580.      * Thus, an UPARROW will always retrieve the previous command.
  581.      */
  582.     curr_mlist->curr_mp = ml->next;
  583. #endif
  584. }
  585.  
  586. /*
  587.  * Try to perform a line-edit function on the command buffer,
  588.  * using a specified char as a line-editing command.
  589.  * Returns:
  590.  *    CC_PASS    The char does not invoke a line edit function.
  591.  *    CC_OK    Line edit function done.
  592.  *    CC_QUIT    The char requests the current command to be aborted.
  593.  */
  594.     static int
  595. cmd_edit(c)
  596.     int c;
  597. {
  598.     int action;
  599.     int flags;
  600.  
  601. #if TAB_COMPLETE_FILENAME
  602. #define    not_in_completion()    in_completion = 0
  603. #else
  604. #define    not_in_completion()
  605. #endif
  606.     
  607.     /*
  608.      * See if the char is indeed a line-editing command.
  609.      */
  610.     flags = 0;
  611. #if CMD_HISTORY
  612.     if (curr_mlist == NULL)
  613.         /*
  614.          * No current history; don't accept history manipulation cmds.
  615.          */
  616.         flags |= EC_NOHISTORY;
  617. #endif
  618. #if TAB_COMPLETE_FILENAME
  619.     if (curr_mlist == ml_search)
  620.         /*
  621.          * In a search command; don't accept file-completion cmds.
  622.          */
  623.         flags |= EC_NOCOMPLETE;
  624. #endif
  625.  
  626.     action = editchar(c, flags);
  627.  
  628.     switch (action)
  629.     {
  630.     case EC_RIGHT:
  631.         not_in_completion();
  632.         return (cmd_right());
  633.     case EC_LEFT:
  634.         not_in_completion();
  635.         return (cmd_left());
  636.     case EC_W_RIGHT:
  637.         not_in_completion();
  638.         while (*cp != '\0' && *cp != ' ')
  639.             cmd_right();
  640.         while (*cp == ' ')
  641.             cmd_right();
  642.         return (CC_OK);
  643.     case EC_W_LEFT:
  644.         not_in_completion();
  645.         while (cp > cmdbuf && cp[-1] == ' ')
  646.             cmd_left();
  647.         while (cp > cmdbuf && cp[-1] != ' ')
  648.             cmd_left();
  649.         return (CC_OK);
  650.     case EC_HOME:
  651.         not_in_completion();
  652.         cmd_offset = 0;
  653.         cmd_home();
  654.         cmd_repaint(cp);
  655.         return (CC_OK);
  656.     case EC_END:
  657.         not_in_completion();
  658.         while (*cp != '\0')
  659.             cmd_right();
  660.         return (CC_OK);
  661.     case EC_INSERT:
  662.         not_in_completion();
  663.         return (CC_OK);
  664.     case EC_BACKSPACE:
  665.         not_in_completion();
  666.         return (cmd_erase());
  667.     case EC_LINEKILL:
  668.         not_in_completion();
  669.         return (cmd_kill());
  670.     case EC_W_BACKSPACE:
  671.         not_in_completion();
  672.         return (cmd_werase());
  673.     case EC_DELETE:
  674.         not_in_completion();
  675.         return (cmd_delete());
  676.     case EC_W_DELETE:
  677.         not_in_completion();
  678.         return (cmd_wdelete());
  679.     case EC_LITERAL:
  680.         literal = 1;
  681.         return (CC_OK);
  682. #if CMD_HISTORY
  683.     case EC_UP:
  684.     case EC_DOWN:
  685.         not_in_completion();
  686.         return (cmd_updown(action));
  687. #endif
  688. #if TAB_COMPLETE_FILENAME
  689.     case EC_F_COMPLETE:
  690.     case EC_B_COMPLETE:
  691.     case EC_EXPAND:
  692.         return (cmd_complete(action));
  693. #endif
  694.     default:
  695.         not_in_completion();
  696.         return (CC_PASS);
  697.     }
  698. }
  699.  
  700. #if TAB_COMPLETE_FILENAME
  701. /*
  702.  * Insert a string into the command buffer, at the current position.
  703.  */
  704.     static int
  705. cmd_istr(str)
  706.     char *str;
  707. {
  708.     char *s;
  709.     int action;
  710.     
  711.     for (s = str;  *s != '\0';  s++)
  712.     {
  713.         action = cmd_ichar(*s);
  714.         if (action != CC_OK)
  715.         {
  716.             bell();
  717.             return (action);
  718.         }
  719.     }
  720.     return (CC_OK);
  721. }
  722.  
  723. /*
  724.  * Find the beginning and end of the "current" word.
  725.  * This is the word which the cursor (cp) is inside or at the end of.
  726.  * Return pointer to the beginning of the word and put the
  727.  * cursor at the end of the word.
  728.  */
  729.     static char *
  730. delimit_word()
  731. {
  732.     char *word;
  733.     
  734.     /*
  735.      * Move cursor to end of word.
  736.      */
  737.     if (*cp != ' ' && *cp != '\0')
  738.     {
  739.         /*
  740.          * Cursor is on a nonspace.
  741.          * Move cursor right to the next space.
  742.          */
  743.         while (*cp != ' ' && *cp != '\0')
  744.             cmd_right();
  745.     } else if (cp > cmdbuf && cp[-1] != ' ')
  746.     {
  747.         /*
  748.          * Cursor is on a space, and char to the left is a nonspace.
  749.          * We're already at the end of the word.
  750.          */
  751.         ;
  752.     } else
  753.     {
  754.         /*
  755.          * Cursor is on a space and char to the left is a space.
  756.          * Huh? There's no word here.
  757.          */
  758.         return (NULL);
  759.     }
  760.     /*
  761.      * Search backwards for beginning of the word.
  762.      */
  763.     if (cp == cmdbuf)
  764.         return (NULL);
  765.     for (word = cp-1;  word > cmdbuf;  word--)
  766.         if (word[-1] == ' ')
  767.             break;
  768.     return (word);
  769. }
  770.  
  771. /*
  772.  * Set things up to enter completion mode.
  773.  * Expand the word under the cursor into a list of filenames 
  774.  * which start with that word, and set tk_text to that list.
  775.  */
  776.     static void
  777. init_compl()
  778. {
  779.     char *word;
  780.     char c;
  781.     
  782.     /*
  783.      * Get rid of any previous tk_text.
  784.      */
  785.     if (tk_text != NULL)
  786.     {
  787.         free(tk_text);
  788.         tk_text = NULL;
  789.     }
  790.     /*
  791.      * Find the original (uncompleted) word in the command buffer.
  792.      */
  793.     word = delimit_word();
  794.     if (word == NULL)
  795.         return;
  796.     /*
  797.      * Set the insertion point to the point in the command buffer
  798.      * where the original (uncompleted) word now sits.
  799.      */
  800.     tk_ipoint = word;
  801.     /*
  802.      * Save the original (uncompleted) word
  803.      */
  804.     if (tk_original != NULL)
  805.         free(tk_original);
  806.     tk_original = (char *) ecalloc(cp-word+1, sizeof(char));
  807.     strncpy(tk_original, word, cp-word);
  808.     /*
  809.      * Get the expanded filename.
  810.      * This may result in a single filename, or
  811.      * a blank-separated list of filenames.
  812.      */
  813.     c = *cp;
  814.     *cp = '\0';
  815.     tk_text = fcomplete(word);
  816.     *cp = c;
  817. }
  818.  
  819. /*
  820.  * Return the next word in the current completion list.
  821.  */
  822.     static char *
  823. next_compl(action, prev)
  824.          int action;
  825.     char *prev;
  826. {
  827.     switch (action)
  828.     {
  829.     case EC_F_COMPLETE:
  830.         return (forw_textlist(&tk_tlist, prev));
  831.     case EC_B_COMPLETE:
  832.         return (back_textlist(&tk_tlist, prev));
  833.     }
  834.     /* Cannot happen */
  835.     return ("?");
  836. }
  837.  
  838. /*
  839.  * Complete the filename before (or under) the cursor.
  840.  * cmd_complete may be called multiple times.  The global in_completion
  841.  * remembers whether this call is the first time (create the list),
  842.  * or a subsequent time (step thru the list).
  843.  */
  844.     static int
  845. cmd_complete(action)
  846.     int action;
  847. {
  848.  
  849.     if (!in_completion || action == EC_EXPAND)
  850.     {
  851.         /*
  852.          * Expand the word under the cursor and 
  853.          * use the first word in the expansion 
  854.          * (or the entire expansion if we're doing EC_EXPAND).
  855.          */
  856.         init_compl();
  857.         if (tk_text == NULL)
  858.         {
  859.             bell();
  860.             return (CC_OK);
  861.         }
  862.         if (action == EC_EXPAND)
  863.         {
  864.             /*
  865.              * Use the whole list.
  866.              */
  867.             tk_trial = tk_text;
  868.         } else
  869.         {
  870.             /*
  871.              * Use the first filename in the list.
  872.              */
  873.             in_completion = 1;
  874.             init_textlist(&tk_tlist, tk_text);
  875.             tk_trial = next_compl(action, (char*)NULL);
  876.         }
  877.     } else
  878.     {
  879.         /*
  880.          * We already have a completion list.
  881.          * Use the next/previous filename from the list.
  882.          */
  883.         tk_trial = next_compl(action, tk_trial);
  884.     }
  885.     
  886.       /*
  887.        * Remove the original word, or the previous trial completion.
  888.        */
  889.     while (cp > tk_ipoint)
  890.         (void) cmd_erase();
  891.     
  892.     if (tk_trial == NULL)
  893.     {
  894.         /*
  895.          * There are no more trial completions.
  896.          * Insert the original (uncompleted) filename.
  897.          */
  898.         in_completion = 0;
  899.         if (cmd_istr(tk_original) != CC_OK)
  900.             goto fail;
  901.     } else
  902.     {
  903.         /*
  904.          * Insert trial completion.
  905.          */
  906.         if (cmd_istr(tk_trial) != CC_OK)
  907.             goto fail;
  908.     }
  909.     
  910.     return (CC_OK);
  911.     
  912. fail:
  913.     in_completion = 0;
  914.     bell();
  915.     return (CC_OK);
  916. }
  917.  
  918. #endif /* TAB_COMPLETE_FILENAME */
  919.  
  920. /*
  921.  * Process a single character of a multi-character command, such as
  922.  * a number, or the pattern of a search command.
  923.  * Returns:
  924.  *    CC_OK        The char was accepted.
  925.  *    CC_QUIT        The char requests the command to be aborted.
  926.  *    CC_ERROR    The char could not be accepted due to an error.
  927.  */
  928.     public int
  929. cmd_char(c)
  930.     int c;
  931. {
  932.     int action;
  933.  
  934.     if (literal)
  935.     {
  936.         /*
  937.          * Insert the char, even if it is a line-editing char.
  938.          */
  939.         literal = 0;
  940.         return (cmd_ichar(c));
  941.     }
  942.         
  943.     /*
  944.      * See if it is a special line-editing character.
  945.      */
  946.     if (in_mca())
  947.     {
  948.         action = cmd_edit(c);
  949.         switch (action)
  950.         {
  951.         case CC_OK:
  952.         case CC_QUIT:
  953.             return (action);
  954.         case CC_PASS:
  955.             break;
  956.         }
  957.     }
  958.     
  959.     /*
  960.      * Insert the char into the command buffer.
  961.      */
  962.     action = cmd_ichar(c);
  963.     if (action != CC_OK)
  964.         return (action);
  965.     return (CC_OK);
  966. }
  967.  
  968. /*
  969.  * Return the number currently in the command buffer.
  970.  */
  971.     public int
  972. cmd_int()
  973. {
  974.     return (atoi(cmdbuf));
  975. }
  976.  
  977. /*
  978.  * Return a pointer to the command buffer.
  979.  */
  980.     public char *
  981. get_cmdbuf()
  982. {
  983.     return (cmdbuf);
  984. }
  985.