cmdbuf.c revision 60786
160786Sps/* 260786Sps * Copyright (C) 1984-2000 Mark Nudelman 360786Sps * 460786Sps * You may distribute under the terms of either the GNU General Public 560786Sps * License or the Less License, as specified in the README file. 660786Sps * 760786Sps * For more information about less, or for information on how to 860786Sps * contact the author, see the README file. 960786Sps */ 1060786Sps 1160786Sps 1260786Sps/* 1360786Sps * Functions which manipulate the command buffer. 1460786Sps * Used only by command() and related functions. 1560786Sps */ 1660786Sps 1760786Sps#include "less.h" 1860786Sps#include "cmd.h" 1960786Sps 2060786Spsextern int sc_width; 2160786Sps 2260786Spsstatic char cmdbuf[CMDBUF_SIZE]; /* Buffer for holding a multi-char command */ 2360786Spsstatic int cmd_col; /* Current column of the cursor */ 2460786Spsstatic int prompt_col; /* Column of cursor just after prompt */ 2560786Spsstatic char *cp; /* Pointer into cmdbuf */ 2660786Spsstatic int cmd_offset; /* Index into cmdbuf of first displayed char */ 2760786Spsstatic int literal; /* Next input char should not be interpreted */ 2860786Sps 2960786Sps#if TAB_COMPLETE_FILENAME 3060786Spsstatic int cmd_complete(); 3160786Sps/* 3260786Sps * These variables are statics used by cmd_complete. 3360786Sps */ 3460786Spsstatic int in_completion = 0; 3560786Spsstatic char *tk_text; 3660786Spsstatic char *tk_original; 3760786Spsstatic char *tk_ipoint; 3860786Spsstatic char *tk_trial; 3960786Spsstatic struct textlist tk_tlist; 4060786Sps#endif 4160786Sps 4260786Spsstatic int cmd_left(); 4360786Spsstatic int cmd_right(); 4460786Sps 4560786Sps#if SPACES_IN_FILENAMES 4660786Spspublic char openquote = '"'; 4760786Spspublic char closequote = '"'; 4860786Sps#endif 4960786Sps 5060786Sps#if CMD_HISTORY 5160786Sps/* 5260786Sps * A mlist structure represents a command history. 5360786Sps */ 5460786Spsstruct mlist 5560786Sps{ 5660786Sps struct mlist *next; 5760786Sps struct mlist *prev; 5860786Sps struct mlist *curr_mp; 5960786Sps char *string; 6060786Sps}; 6160786Sps 6260786Sps/* 6360786Sps * These are the various command histories that exist. 6460786Sps */ 6560786Spsstruct mlist mlist_search = 6660786Sps { &mlist_search, &mlist_search, &mlist_search, NULL }; 6760786Spspublic void constant *ml_search = (void *) &mlist_search; 6860786Sps 6960786Spsstruct mlist mlist_examine = 7060786Sps { &mlist_examine, &mlist_examine, &mlist_examine, NULL }; 7160786Spspublic void constant *ml_examine = (void *) &mlist_examine; 7260786Sps 7360786Sps#if SHELL_ESCAPE || PIPEC 7460786Spsstruct mlist mlist_shell = 7560786Sps { &mlist_shell, &mlist_shell, &mlist_shell, NULL }; 7660786Spspublic void constant *ml_shell = (void *) &mlist_shell; 7760786Sps#endif 7860786Sps 7960786Sps#else /* CMD_HISTORY */ 8060786Sps 8160786Sps/* If CMD_HISTORY is off, these are just flags. */ 8260786Spspublic void constant *ml_search = (void *)1; 8360786Spspublic void constant *ml_examine = (void *)2; 8460786Sps#if SHELL_ESCAPE || PIPEC 8560786Spspublic void constant *ml_shell = (void *)3; 8660786Sps#endif 8760786Sps 8860786Sps#endif /* CMD_HISTORY */ 8960786Sps 9060786Sps/* 9160786Sps * History for the current command. 9260786Sps */ 9360786Spsstatic struct mlist *curr_mlist = NULL; 9460786Spsstatic int curr_cmdflags; 9560786Sps 9660786Sps 9760786Sps/* 9860786Sps * Reset command buffer (to empty). 9960786Sps */ 10060786Sps public void 10160786Spscmd_reset() 10260786Sps{ 10360786Sps cp = cmdbuf; 10460786Sps *cp = '\0'; 10560786Sps cmd_col = 0; 10660786Sps cmd_offset = 0; 10760786Sps literal = 0; 10860786Sps} 10960786Sps 11060786Sps/* 11160786Sps * Clear command line on display. 11260786Sps */ 11360786Sps public void 11460786Spsclear_cmd() 11560786Sps{ 11660786Sps clear_bot(); 11760786Sps cmd_col = prompt_col = 0; 11860786Sps} 11960786Sps 12060786Sps/* 12160786Sps * Display a string, usually as a prompt for input into the command buffer. 12260786Sps */ 12360786Sps public void 12460786Spscmd_putstr(s) 12560786Sps char *s; 12660786Sps{ 12760786Sps putstr(s); 12860786Sps cmd_col += strlen(s); 12960786Sps prompt_col += strlen(s); 13060786Sps} 13160786Sps 13260786Sps/* 13360786Sps * How many characters are in the command buffer? 13460786Sps */ 13560786Sps public int 13660786Spslen_cmdbuf() 13760786Sps{ 13860786Sps return (strlen(cmdbuf)); 13960786Sps} 14060786Sps 14160786Sps/* 14260786Sps * Repaint the line from cp onwards. 14360786Sps * Then position the cursor just after the char old_cp (a pointer into cmdbuf). 14460786Sps */ 14560786Sps static void 14660786Spscmd_repaint(old_cp) 14760786Sps char *old_cp; 14860786Sps{ 14960786Sps char *p; 15060786Sps 15160786Sps /* 15260786Sps * Repaint the line from the current position. 15360786Sps */ 15460786Sps clear_eol(); 15560786Sps for ( ; *cp != '\0'; cp++) 15660786Sps { 15760786Sps p = prchar(*cp); 15860786Sps if (cmd_col + strlen(p) >= sc_width) 15960786Sps break; 16060786Sps putstr(p); 16160786Sps cmd_col += strlen(p); 16260786Sps } 16360786Sps 16460786Sps /* 16560786Sps * Back up the cursor to the correct position. 16660786Sps */ 16760786Sps while (cp > old_cp) 16860786Sps cmd_left(); 16960786Sps} 17060786Sps 17160786Sps/* 17260786Sps * Put the cursor at "home" (just after the prompt), 17360786Sps * and set cp to the corresponding char in cmdbuf. 17460786Sps */ 17560786Sps static void 17660786Spscmd_home() 17760786Sps{ 17860786Sps while (cmd_col > prompt_col) 17960786Sps { 18060786Sps putbs(); 18160786Sps cmd_col--; 18260786Sps } 18360786Sps 18460786Sps cp = &cmdbuf[cmd_offset]; 18560786Sps} 18660786Sps 18760786Sps/* 18860786Sps * Shift the cmdbuf display left a half-screen. 18960786Sps */ 19060786Sps static void 19160786Spscmd_lshift() 19260786Sps{ 19360786Sps char *s; 19460786Sps char *save_cp; 19560786Sps int cols; 19660786Sps 19760786Sps /* 19860786Sps * Start at the first displayed char, count how far to the 19960786Sps * right we'd have to move to reach the center of the screen. 20060786Sps */ 20160786Sps s = cmdbuf + cmd_offset; 20260786Sps cols = 0; 20360786Sps while (cols < (sc_width - prompt_col) / 2 && *s != '\0') 20460786Sps cols += strlen(prchar(*s++)); 20560786Sps 20660786Sps cmd_offset = s - cmdbuf; 20760786Sps save_cp = cp; 20860786Sps cmd_home(); 20960786Sps cmd_repaint(save_cp); 21060786Sps} 21160786Sps 21260786Sps/* 21360786Sps * Shift the cmdbuf display right a half-screen. 21460786Sps */ 21560786Sps static void 21660786Spscmd_rshift() 21760786Sps{ 21860786Sps char *s; 21960786Sps char *p; 22060786Sps char *save_cp; 22160786Sps int cols; 22260786Sps 22360786Sps /* 22460786Sps * Start at the first displayed char, count how far to the 22560786Sps * left we'd have to move to traverse a half-screen width 22660786Sps * of displayed characters. 22760786Sps */ 22860786Sps s = cmdbuf + cmd_offset; 22960786Sps cols = 0; 23060786Sps while (cols < (sc_width - prompt_col) / 2 && s > cmdbuf) 23160786Sps { 23260786Sps p = prchar(*--s); 23360786Sps cols += strlen(p); 23460786Sps } 23560786Sps 23660786Sps cmd_offset = s - cmdbuf; 23760786Sps save_cp = cp; 23860786Sps cmd_home(); 23960786Sps cmd_repaint(save_cp); 24060786Sps} 24160786Sps 24260786Sps/* 24360786Sps * Move cursor right one character. 24460786Sps */ 24560786Sps static int 24660786Spscmd_right() 24760786Sps{ 24860786Sps char *p; 24960786Sps 25060786Sps if (*cp == '\0') 25160786Sps { 25260786Sps /* 25360786Sps * Already at the end of the line. 25460786Sps */ 25560786Sps return (CC_OK); 25660786Sps } 25760786Sps p = prchar(*cp); 25860786Sps if (cmd_col + strlen(p) >= sc_width) 25960786Sps cmd_lshift(); 26060786Sps else if (cmd_col + strlen(p) == sc_width - 1 && cp[1] != '\0') 26160786Sps cmd_lshift(); 26260786Sps cp++; 26360786Sps putstr(p); 26460786Sps cmd_col += strlen(p); 26560786Sps return (CC_OK); 26660786Sps} 26760786Sps 26860786Sps/* 26960786Sps * Move cursor left one character. 27060786Sps */ 27160786Sps static int 27260786Spscmd_left() 27360786Sps{ 27460786Sps char *p; 27560786Sps 27660786Sps if (cp <= cmdbuf) 27760786Sps { 27860786Sps /* Already at the beginning of the line */ 27960786Sps return (CC_OK); 28060786Sps } 28160786Sps p = prchar(cp[-1]); 28260786Sps if (cmd_col < prompt_col + strlen(p)) 28360786Sps cmd_rshift(); 28460786Sps cp--; 28560786Sps cmd_col -= strlen(p); 28660786Sps while (*p++ != '\0') 28760786Sps putbs(); 28860786Sps return (CC_OK); 28960786Sps} 29060786Sps 29160786Sps/* 29260786Sps * Insert a char into the command buffer, at the current position. 29360786Sps */ 29460786Sps static int 29560786Spscmd_ichar(c) 29660786Sps int c; 29760786Sps{ 29860786Sps char *s; 29960786Sps 30060786Sps if (strlen(cmdbuf) >= sizeof(cmdbuf)-2) 30160786Sps { 30260786Sps /* 30360786Sps * No room in the command buffer for another char. 30460786Sps */ 30560786Sps bell(); 30660786Sps return (CC_ERROR); 30760786Sps } 30860786Sps 30960786Sps /* 31060786Sps * Insert the character into the buffer. 31160786Sps */ 31260786Sps for (s = &cmdbuf[strlen(cmdbuf)]; s >= cp; s--) 31360786Sps s[1] = s[0]; 31460786Sps *cp = c; 31560786Sps /* 31660786Sps * Reprint the tail of the line from the inserted char. 31760786Sps */ 31860786Sps cmd_repaint(cp); 31960786Sps cmd_right(); 32060786Sps return (CC_OK); 32160786Sps} 32260786Sps 32360786Sps/* 32460786Sps * Backspace in the command buffer. 32560786Sps * Delete the char to the left of the cursor. 32660786Sps */ 32760786Sps static int 32860786Spscmd_erase() 32960786Sps{ 33060786Sps register char *s; 33160786Sps 33260786Sps if (cp == cmdbuf) 33360786Sps { 33460786Sps /* 33560786Sps * Backspace past beginning of the buffer: 33660786Sps * this usually means abort the command. 33760786Sps */ 33860786Sps return (CC_QUIT); 33960786Sps } 34060786Sps /* 34160786Sps * Move cursor left (to the char being erased). 34260786Sps */ 34360786Sps cmd_left(); 34460786Sps /* 34560786Sps * Remove the char from the buffer (shift the buffer left). 34660786Sps */ 34760786Sps for (s = cp; *s != '\0'; s++) 34860786Sps s[0] = s[1]; 34960786Sps /* 35060786Sps * Repaint the buffer after the erased char. 35160786Sps */ 35260786Sps cmd_repaint(cp); 35360786Sps 35460786Sps /* 35560786Sps * We say that erasing the entire command string causes us 35660786Sps * to abort the current command, if CF_QUIT_ON_ERASE is set. 35760786Sps */ 35860786Sps if ((curr_cmdflags & CF_QUIT_ON_ERASE) && cp == cmdbuf && *cp == '\0') 35960786Sps return (CC_QUIT); 36060786Sps return (CC_OK); 36160786Sps} 36260786Sps 36360786Sps/* 36460786Sps * Delete the char under the cursor. 36560786Sps */ 36660786Sps static int 36760786Spscmd_delete() 36860786Sps{ 36960786Sps if (*cp == '\0') 37060786Sps { 37160786Sps /* 37260786Sps * At end of string; there is no char under the cursor. 37360786Sps */ 37460786Sps return (CC_OK); 37560786Sps } 37660786Sps /* 37760786Sps * Move right, then use cmd_erase. 37860786Sps */ 37960786Sps cmd_right(); 38060786Sps cmd_erase(); 38160786Sps return (CC_OK); 38260786Sps} 38360786Sps 38460786Sps/* 38560786Sps * Delete the "word" to the left of the cursor. 38660786Sps */ 38760786Sps static int 38860786Spscmd_werase() 38960786Sps{ 39060786Sps if (cp > cmdbuf && cp[-1] == ' ') 39160786Sps { 39260786Sps /* 39360786Sps * If the char left of cursor is a space, 39460786Sps * erase all the spaces left of cursor (to the first non-space). 39560786Sps */ 39660786Sps while (cp > cmdbuf && cp[-1] == ' ') 39760786Sps (void) cmd_erase(); 39860786Sps } else 39960786Sps { 40060786Sps /* 40160786Sps * If the char left of cursor is not a space, 40260786Sps * erase all the nonspaces left of cursor (the whole "word"). 40360786Sps */ 40460786Sps while (cp > cmdbuf && cp[-1] != ' ') 40560786Sps (void) cmd_erase(); 40660786Sps } 40760786Sps return (CC_OK); 40860786Sps} 40960786Sps 41060786Sps/* 41160786Sps * Delete the "word" under the cursor. 41260786Sps */ 41360786Sps static int 41460786Spscmd_wdelete() 41560786Sps{ 41660786Sps if (*cp == ' ') 41760786Sps { 41860786Sps /* 41960786Sps * If the char under the cursor is a space, 42060786Sps * delete it and all the spaces right of cursor. 42160786Sps */ 42260786Sps while (*cp == ' ') 42360786Sps (void) cmd_delete(); 42460786Sps } else 42560786Sps { 42660786Sps /* 42760786Sps * If the char under the cursor is not a space, 42860786Sps * delete it and all nonspaces right of cursor (the whole word). 42960786Sps */ 43060786Sps while (*cp != ' ' && *cp != '\0') 43160786Sps (void) cmd_delete(); 43260786Sps } 43360786Sps return (CC_OK); 43460786Sps} 43560786Sps 43660786Sps/* 43760786Sps * Delete all chars in the command buffer. 43860786Sps */ 43960786Sps static int 44060786Spscmd_kill() 44160786Sps{ 44260786Sps if (cmdbuf[0] == '\0') 44360786Sps { 44460786Sps /* 44560786Sps * Buffer is already empty; abort the current command. 44660786Sps */ 44760786Sps return (CC_QUIT); 44860786Sps } 44960786Sps cmd_offset = 0; 45060786Sps cmd_home(); 45160786Sps *cp = '\0'; 45260786Sps cmd_repaint(cp); 45360786Sps 45460786Sps /* 45560786Sps * We say that erasing the entire command string causes us 45660786Sps * to abort the current command, if CF_QUIT_ON_ERASE is set. 45760786Sps */ 45860786Sps if (curr_cmdflags & CF_QUIT_ON_ERASE) 45960786Sps return (CC_QUIT); 46060786Sps return (CC_OK); 46160786Sps} 46260786Sps 46360786Sps/* 46460786Sps * Select an mlist structure to be the current command history. 46560786Sps */ 46660786Sps public void 46760786Spsset_mlist(mlist, cmdflags) 46860786Sps void *mlist; 46960786Sps int cmdflags; 47060786Sps{ 47160786Sps curr_mlist = (struct mlist *) mlist; 47260786Sps curr_cmdflags = cmdflags; 47360786Sps} 47460786Sps 47560786Sps#if CMD_HISTORY 47660786Sps/* 47760786Sps * Move up or down in the currently selected command history list. 47860786Sps */ 47960786Sps static int 48060786Spscmd_updown(action) 48160786Sps int action; 48260786Sps{ 48360786Sps char *s; 48460786Sps 48560786Sps if (curr_mlist == NULL) 48660786Sps { 48760786Sps /* 48860786Sps * The current command has no history list. 48960786Sps */ 49060786Sps bell(); 49160786Sps return (CC_OK); 49260786Sps } 49360786Sps cmd_home(); 49460786Sps clear_eol(); 49560786Sps /* 49660786Sps * Move curr_mp to the next/prev entry. 49760786Sps */ 49860786Sps if (action == EC_UP) 49960786Sps curr_mlist->curr_mp = curr_mlist->curr_mp->prev; 50060786Sps else 50160786Sps curr_mlist->curr_mp = curr_mlist->curr_mp->next; 50260786Sps /* 50360786Sps * Copy the entry into cmdbuf and echo it on the screen. 50460786Sps */ 50560786Sps s = curr_mlist->curr_mp->string; 50660786Sps if (s == NULL) 50760786Sps s = ""; 50860786Sps for (cp = cmdbuf; *s != '\0'; s++) 50960786Sps { 51060786Sps *cp = *s; 51160786Sps cmd_right(); 51260786Sps } 51360786Sps *cp = '\0'; 51460786Sps return (CC_OK); 51560786Sps} 51660786Sps#endif 51760786Sps 51860786Sps/* 51960786Sps * Add a string to a history list. 52060786Sps */ 52160786Sps public void 52260786Spscmd_addhist(mlist, cmd) 52360786Sps struct mlist *mlist; 52460786Sps char *cmd; 52560786Sps{ 52660786Sps#if CMD_HISTORY 52760786Sps struct mlist *ml; 52860786Sps 52960786Sps /* 53060786Sps * Don't save a trivial command. 53160786Sps */ 53260786Sps if (strlen(cmd) == 0) 53360786Sps return; 53460786Sps /* 53560786Sps * Don't save if a duplicate of a command which is already 53660786Sps * in the history. 53760786Sps * But select the one already in the history to be current. 53860786Sps */ 53960786Sps for (ml = mlist->next; ml != mlist; ml = ml->next) 54060786Sps { 54160786Sps if (strcmp(ml->string, cmd) == 0) 54260786Sps break; 54360786Sps } 54460786Sps if (ml == mlist) 54560786Sps { 54660786Sps /* 54760786Sps * Did not find command in history. 54860786Sps * Save the command and put it at the end of the history list. 54960786Sps */ 55060786Sps ml = (struct mlist *) ecalloc(1, sizeof(struct mlist)); 55160786Sps ml->string = save(cmd); 55260786Sps ml->next = mlist; 55360786Sps ml->prev = mlist->prev; 55460786Sps mlist->prev->next = ml; 55560786Sps mlist->prev = ml; 55660786Sps } 55760786Sps /* 55860786Sps * Point to the cmd just after the just-accepted command. 55960786Sps * Thus, an UPARROW will always retrieve the previous command. 56060786Sps */ 56160786Sps mlist->curr_mp = ml->next; 56260786Sps#endif 56360786Sps} 56460786Sps 56560786Sps/* 56660786Sps * Accept the command in the command buffer. 56760786Sps * Add it to the currently selected history list. 56860786Sps */ 56960786Sps public void 57060786Spscmd_accept() 57160786Sps{ 57260786Sps#if CMD_HISTORY 57360786Sps /* 57460786Sps * Nothing to do if there is no currently selected history list. 57560786Sps */ 57660786Sps if (curr_mlist == NULL) 57760786Sps return; 57860786Sps cmd_addhist(curr_mlist, cmdbuf); 57960786Sps#endif 58060786Sps} 58160786Sps 58260786Sps/* 58360786Sps * Try to perform a line-edit function on the command buffer, 58460786Sps * using a specified char as a line-editing command. 58560786Sps * Returns: 58660786Sps * CC_PASS The char does not invoke a line edit function. 58760786Sps * CC_OK Line edit function done. 58860786Sps * CC_QUIT The char requests the current command to be aborted. 58960786Sps */ 59060786Sps static int 59160786Spscmd_edit(c) 59260786Sps int c; 59360786Sps{ 59460786Sps int action; 59560786Sps int flags; 59660786Sps 59760786Sps#if TAB_COMPLETE_FILENAME 59860786Sps#define not_in_completion() in_completion = 0 59960786Sps#else 60060786Sps#define not_in_completion() 60160786Sps#endif 60260786Sps 60360786Sps /* 60460786Sps * See if the char is indeed a line-editing command. 60560786Sps */ 60660786Sps flags = 0; 60760786Sps#if CMD_HISTORY 60860786Sps if (curr_mlist == NULL) 60960786Sps /* 61060786Sps * No current history; don't accept history manipulation cmds. 61160786Sps */ 61260786Sps flags |= EC_NOHISTORY; 61360786Sps#endif 61460786Sps#if TAB_COMPLETE_FILENAME 61560786Sps if (curr_mlist == ml_search) 61660786Sps /* 61760786Sps * In a search command; don't accept file-completion cmds. 61860786Sps */ 61960786Sps flags |= EC_NOCOMPLETE; 62060786Sps#endif 62160786Sps 62260786Sps action = editchar(c, flags); 62360786Sps 62460786Sps switch (action) 62560786Sps { 62660786Sps case EC_RIGHT: 62760786Sps not_in_completion(); 62860786Sps return (cmd_right()); 62960786Sps case EC_LEFT: 63060786Sps not_in_completion(); 63160786Sps return (cmd_left()); 63260786Sps case EC_W_RIGHT: 63360786Sps not_in_completion(); 63460786Sps while (*cp != '\0' && *cp != ' ') 63560786Sps cmd_right(); 63660786Sps while (*cp == ' ') 63760786Sps cmd_right(); 63860786Sps return (CC_OK); 63960786Sps case EC_W_LEFT: 64060786Sps not_in_completion(); 64160786Sps while (cp > cmdbuf && cp[-1] == ' ') 64260786Sps cmd_left(); 64360786Sps while (cp > cmdbuf && cp[-1] != ' ') 64460786Sps cmd_left(); 64560786Sps return (CC_OK); 64660786Sps case EC_HOME: 64760786Sps not_in_completion(); 64860786Sps cmd_offset = 0; 64960786Sps cmd_home(); 65060786Sps cmd_repaint(cp); 65160786Sps return (CC_OK); 65260786Sps case EC_END: 65360786Sps not_in_completion(); 65460786Sps while (*cp != '\0') 65560786Sps cmd_right(); 65660786Sps return (CC_OK); 65760786Sps case EC_INSERT: 65860786Sps not_in_completion(); 65960786Sps return (CC_OK); 66060786Sps case EC_BACKSPACE: 66160786Sps not_in_completion(); 66260786Sps return (cmd_erase()); 66360786Sps case EC_LINEKILL: 66460786Sps not_in_completion(); 66560786Sps return (cmd_kill()); 66660786Sps case EC_W_BACKSPACE: 66760786Sps not_in_completion(); 66860786Sps return (cmd_werase()); 66960786Sps case EC_DELETE: 67060786Sps not_in_completion(); 67160786Sps return (cmd_delete()); 67260786Sps case EC_W_DELETE: 67360786Sps not_in_completion(); 67460786Sps return (cmd_wdelete()); 67560786Sps case EC_LITERAL: 67660786Sps literal = 1; 67760786Sps return (CC_OK); 67860786Sps#if CMD_HISTORY 67960786Sps case EC_UP: 68060786Sps case EC_DOWN: 68160786Sps not_in_completion(); 68260786Sps return (cmd_updown(action)); 68360786Sps#endif 68460786Sps#if TAB_COMPLETE_FILENAME 68560786Sps case EC_F_COMPLETE: 68660786Sps case EC_B_COMPLETE: 68760786Sps case EC_EXPAND: 68860786Sps return (cmd_complete(action)); 68960786Sps#endif 69060786Sps case EC_NOACTION: 69160786Sps return (CC_OK); 69260786Sps default: 69360786Sps not_in_completion(); 69460786Sps return (CC_PASS); 69560786Sps } 69660786Sps} 69760786Sps 69860786Sps#if TAB_COMPLETE_FILENAME 69960786Sps/* 70060786Sps * Insert a string into the command buffer, at the current position. 70160786Sps */ 70260786Sps static int 70360786Spscmd_istr(str) 70460786Sps char *str; 70560786Sps{ 70660786Sps char *s; 70760786Sps int action; 70860786Sps 70960786Sps for (s = str; *s != '\0'; s++) 71060786Sps { 71160786Sps action = cmd_ichar(*s); 71260786Sps if (action != CC_OK) 71360786Sps { 71460786Sps bell(); 71560786Sps return (action); 71660786Sps } 71760786Sps } 71860786Sps return (CC_OK); 71960786Sps} 72060786Sps 72160786Sps/* 72260786Sps * Find the beginning and end of the "current" word. 72360786Sps * This is the word which the cursor (cp) is inside or at the end of. 72460786Sps * Return pointer to the beginning of the word and put the 72560786Sps * cursor at the end of the word. 72660786Sps */ 72760786Sps static char * 72860786Spsdelimit_word() 72960786Sps{ 73060786Sps char *word; 73160786Sps#if SPACES_IN_FILENAMES 73260786Sps char *p; 73360786Sps int quoted; 73460786Sps#endif 73560786Sps 73660786Sps /* 73760786Sps * Move cursor to end of word. 73860786Sps */ 73960786Sps if (*cp != ' ' && *cp != '\0') 74060786Sps { 74160786Sps /* 74260786Sps * Cursor is on a nonspace. 74360786Sps * Move cursor right to the next space. 74460786Sps */ 74560786Sps while (*cp != ' ' && *cp != '\0') 74660786Sps cmd_right(); 74760786Sps } else if (cp > cmdbuf && cp[-1] != ' ') 74860786Sps { 74960786Sps /* 75060786Sps * Cursor is on a space, and char to the left is a nonspace. 75160786Sps * We're already at the end of the word. 75260786Sps */ 75360786Sps ; 75460786Sps } else 75560786Sps { 75660786Sps /* 75760786Sps * Cursor is on a space and char to the left is a space. 75860786Sps * Huh? There's no word here. 75960786Sps */ 76060786Sps return (NULL); 76160786Sps } 76260786Sps /* 76360786Sps * Search backwards for beginning of the word. 76460786Sps */ 76560786Sps if (cp == cmdbuf) 76660786Sps return (NULL); 76760786Sps#if SPACES_IN_FILENAMES 76860786Sps /* 76960786Sps * If we have an unbalanced quote (that is, an open quote 77060786Sps * without a corresponding close quote), we return everything 77160786Sps * from the open quote, including spaces. 77260786Sps */ 77360786Sps quoted = 0; 77460786Sps for (p = cmdbuf; p < cp; p++) 77560786Sps { 77660786Sps if (!quoted && *p == openquote) 77760786Sps { 77860786Sps quoted = 1; 77960786Sps word = p; 78060786Sps } else if (quoted && *p == closequote) 78160786Sps { 78260786Sps quoted = 0; 78360786Sps } 78460786Sps } 78560786Sps if (quoted) 78660786Sps return (word); 78760786Sps#endif 78860786Sps for (word = cp-1; word > cmdbuf; word--) 78960786Sps if (word[-1] == ' ') 79060786Sps break; 79160786Sps return (word); 79260786Sps} 79360786Sps 79460786Sps/* 79560786Sps * Set things up to enter completion mode. 79660786Sps * Expand the word under the cursor into a list of filenames 79760786Sps * which start with that word, and set tk_text to that list. 79860786Sps */ 79960786Sps static void 80060786Spsinit_compl() 80160786Sps{ 80260786Sps char *word; 80360786Sps char c; 80460786Sps 80560786Sps /* 80660786Sps * Get rid of any previous tk_text. 80760786Sps */ 80860786Sps if (tk_text != NULL) 80960786Sps { 81060786Sps free(tk_text); 81160786Sps tk_text = NULL; 81260786Sps } 81360786Sps /* 81460786Sps * Find the original (uncompleted) word in the command buffer. 81560786Sps */ 81660786Sps word = delimit_word(); 81760786Sps if (word == NULL) 81860786Sps return; 81960786Sps /* 82060786Sps * Set the insertion point to the point in the command buffer 82160786Sps * where the original (uncompleted) word now sits. 82260786Sps */ 82360786Sps tk_ipoint = word; 82460786Sps /* 82560786Sps * Save the original (uncompleted) word 82660786Sps */ 82760786Sps if (tk_original != NULL) 82860786Sps free(tk_original); 82960786Sps tk_original = (char *) ecalloc(cp-word+1, sizeof(char)); 83060786Sps strncpy(tk_original, word, cp-word); 83160786Sps /* 83260786Sps * Get the expanded filename. 83360786Sps * This may result in a single filename, or 83460786Sps * a blank-separated list of filenames. 83560786Sps */ 83660786Sps c = *cp; 83760786Sps *cp = '\0'; 83860786Sps#if SPACES_IN_FILENAMES 83960786Sps if (*word == openquote) 84060786Sps word++; 84160786Sps#endif 84260786Sps tk_text = fcomplete(word); 84360786Sps *cp = c; 84460786Sps} 84560786Sps 84660786Sps/* 84760786Sps * Return the next word in the current completion list. 84860786Sps */ 84960786Sps static char * 85060786Spsnext_compl(action, prev) 85160786Sps int action; 85260786Sps char *prev; 85360786Sps{ 85460786Sps switch (action) 85560786Sps { 85660786Sps case EC_F_COMPLETE: 85760786Sps return (forw_textlist(&tk_tlist, prev)); 85860786Sps case EC_B_COMPLETE: 85960786Sps return (back_textlist(&tk_tlist, prev)); 86060786Sps } 86160786Sps /* Cannot happen */ 86260786Sps return ("?"); 86360786Sps} 86460786Sps 86560786Sps/* 86660786Sps * Complete the filename before (or under) the cursor. 86760786Sps * cmd_complete may be called multiple times. The global in_completion 86860786Sps * remembers whether this call is the first time (create the list), 86960786Sps * or a subsequent time (step thru the list). 87060786Sps */ 87160786Sps static int 87260786Spscmd_complete(action) 87360786Sps int action; 87460786Sps{ 87560786Sps char *s; 87660786Sps 87760786Sps if (!in_completion || action == EC_EXPAND) 87860786Sps { 87960786Sps /* 88060786Sps * Expand the word under the cursor and 88160786Sps * use the first word in the expansion 88260786Sps * (or the entire expansion if we're doing EC_EXPAND). 88360786Sps */ 88460786Sps init_compl(); 88560786Sps if (tk_text == NULL) 88660786Sps { 88760786Sps bell(); 88860786Sps return (CC_OK); 88960786Sps } 89060786Sps if (action == EC_EXPAND) 89160786Sps { 89260786Sps /* 89360786Sps * Use the whole list. 89460786Sps */ 89560786Sps tk_trial = tk_text; 89660786Sps } else 89760786Sps { 89860786Sps /* 89960786Sps * Use the first filename in the list. 90060786Sps */ 90160786Sps in_completion = 1; 90260786Sps init_textlist(&tk_tlist, tk_text); 90360786Sps tk_trial = next_compl(action, (char*)NULL); 90460786Sps } 90560786Sps } else 90660786Sps { 90760786Sps /* 90860786Sps * We already have a completion list. 90960786Sps * Use the next/previous filename from the list. 91060786Sps */ 91160786Sps tk_trial = next_compl(action, tk_trial); 91260786Sps } 91360786Sps 91460786Sps /* 91560786Sps * Remove the original word, or the previous trial completion. 91660786Sps */ 91760786Sps while (cp > tk_ipoint) 91860786Sps (void) cmd_erase(); 91960786Sps 92060786Sps if (tk_trial == NULL) 92160786Sps { 92260786Sps /* 92360786Sps * There are no more trial completions. 92460786Sps * Insert the original (uncompleted) filename. 92560786Sps */ 92660786Sps in_completion = 0; 92760786Sps if (cmd_istr(tk_original) != CC_OK) 92860786Sps goto fail; 92960786Sps } else 93060786Sps { 93160786Sps /* 93260786Sps * Insert trial completion. 93360786Sps */ 93460786Sps if (cmd_istr(tk_trial) != CC_OK) 93560786Sps goto fail; 93660786Sps /* 93760786Sps * If it is a directory, append a slash. 93860786Sps */ 93960786Sps if (is_dir(tk_trial)) 94060786Sps { 94160786Sps if (cp > cmdbuf && cp[-1] == closequote) 94260786Sps (void) cmd_erase(); 94360786Sps s = lgetenv("LESSSEPARATOR"); 94460786Sps if (s == NULL) 94560786Sps s = PATHNAME_SEP; 94660786Sps if (cmd_istr(s) != CC_OK) 94760786Sps goto fail; 94860786Sps } 94960786Sps } 95060786Sps 95160786Sps return (CC_OK); 95260786Sps 95360786Spsfail: 95460786Sps in_completion = 0; 95560786Sps bell(); 95660786Sps return (CC_OK); 95760786Sps} 95860786Sps 95960786Sps#endif /* TAB_COMPLETE_FILENAME */ 96060786Sps 96160786Sps/* 96260786Sps * Process a single character of a multi-character command, such as 96360786Sps * a number, or the pattern of a search command. 96460786Sps * Returns: 96560786Sps * CC_OK The char was accepted. 96660786Sps * CC_QUIT The char requests the command to be aborted. 96760786Sps * CC_ERROR The char could not be accepted due to an error. 96860786Sps */ 96960786Sps public int 97060786Spscmd_char(c) 97160786Sps int c; 97260786Sps{ 97360786Sps int action; 97460786Sps 97560786Sps if (literal) 97660786Sps { 97760786Sps /* 97860786Sps * Insert the char, even if it is a line-editing char. 97960786Sps */ 98060786Sps literal = 0; 98160786Sps return (cmd_ichar(c)); 98260786Sps } 98360786Sps 98460786Sps /* 98560786Sps * See if it is a special line-editing character. 98660786Sps */ 98760786Sps if (in_mca()) 98860786Sps { 98960786Sps action = cmd_edit(c); 99060786Sps switch (action) 99160786Sps { 99260786Sps case CC_OK: 99360786Sps case CC_QUIT: 99460786Sps return (action); 99560786Sps case CC_PASS: 99660786Sps break; 99760786Sps } 99860786Sps } 99960786Sps 100060786Sps /* 100160786Sps * Insert the char into the command buffer. 100260786Sps */ 100360786Sps return (cmd_ichar(c)); 100460786Sps} 100560786Sps 100660786Sps/* 100760786Sps * Return the number currently in the command buffer. 100860786Sps */ 100960786Sps public int 101060786Spscmd_int() 101160786Sps{ 101260786Sps return (atoi(cmdbuf)); 101360786Sps} 101460786Sps 101560786Sps/* 101660786Sps * Return a pointer to the command buffer. 101760786Sps */ 101860786Sps public char * 101960786Spsget_cmdbuf() 102060786Sps{ 102160786Sps return (cmdbuf); 102260786Sps} 1023