1427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes/*	$OpenBSD: edit.c,v 1.39 2013/12/17 16:37:05 deraadt Exp $	*/
203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*	$OpenBSD: edit.h,v 1.9 2011/05/30 17:14:35 martynas Exp $	*/
3427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes/*	$OpenBSD: emacs.c,v 1.48 2013/12/17 16:37:05 deraadt Exp $	*/
4427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes/*	$OpenBSD: vi.c,v 1.28 2013/12/18 16:45:46 deraadt Exp $	*/
55155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
65155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*-
7c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
8427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes *		 2011, 2012, 2013, 2014
95155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	Thorsten Glaser <tg@mirbsd.org>
105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Provided that these terms and disclaimer and all copyright notices
125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * are retained or reproduced in an accompanying document, permission
135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * is granted to deal in this work without restriction, including un-
145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * limited rights to use, publicly perform, distribute, sell, modify,
155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * merge, give away, or sublicence.
165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * the utmost extent permitted by applicable law, neither express nor
195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * implied; without malicious intent or gross negligence. In no event
205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * may a licensor, author or contributor be held liable for indirect,
215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * direct, other damage, loss, or other issues arising in any way out
225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of dealing in the work, even if advised of the possibility of such
235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * damage or existence of a defect, except proven that it results out
245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of said person's immediate fault when using the work as intended.
255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include "sh.h"
285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
29c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifndef MKSH_NO_CMDLINE_EDITING
30c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
31b4542e99ca8562aa584e15df8ef35356ff8c10feElliott Hughes__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.276 2014/07/13 11:34:28 tg Exp $");
325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * in later versions we might use libtermcap for this, but since external
355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * dependencies are problematic, this has not yet been decided on; another
365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * good string is "\033c" except on hardware terminals like the DEC VT420
375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * which do a full power cycle then...
385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifndef MKSH_CLS_STRING
405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define MKSH_CLS_STRING		"\033[;H\033[J"
415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifndef MKSH_CLRTOEOL_STRING
435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define MKSH_CLRTOEOL_STRING	"\033[K"
445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* tty driver characters we are interested in */
475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querutypedef struct {
485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int erase;
495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int kill;
505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int werase;
515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int intr;
525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int quit;
535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int eof;
545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} X_chars;
555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic X_chars edchars;
575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* x_cf_glob() flags */
595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define XCF_COMMAND	BIT(0)	/* Do command completion */
605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define XCF_FILE	BIT(1)	/* Do file completion */
615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define XCF_FULLPATH	BIT(2)	/* command completion: store full path */
6203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define XCF_COMMAND_FILE (XCF_COMMAND | XCF_FILE)
6303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define XCF_IS_COMMAND	BIT(3)	/* return flag: is command */
64c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#define XCF_IS_NOSPACE	BIT(4)	/* return flag: do not append a space */
655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic char editmode;
675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int xx_cols;			/* for Emacs mode */
685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int modified;			/* buffer has been "modified" */
69811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaserstatic char *holdbufp;			/* place to hold last edit buffer */
705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int x_getc(void);
725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void x_putcf(int);
73c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic void x_modified(void);
7403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic void x_mode(bool);
7503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic int x_do_comment(char *, ssize_t, ssize_t *);
76c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic void x_print_expansions(int, char * const *, bool);
7703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic int x_cf_glob(int *, const char *, int, int, int *, int *, char ***);
78c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic size_t x_longest_prefix(int, char * const *);
79c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic void x_glob_hlp_add_qchar(char *);
80c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic char *x_glob_hlp_tilde_and_rem_qchar(char *, bool);
815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int x_basename(const char *, const char *);
825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void x_free_words(int, char **);
835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int x_escape(const char *, size_t, int (*)(const char *, size_t));
84811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaserstatic int x_emacs(char *);
85427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughesstatic void x_init_prompt(bool);
865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if !MKSH_S_NOVI
87811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaserstatic int x_vi(char *);
885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define x_flush()	shf_flush(shl_out)
91c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define x_putc(c)	x_putcf(c)
935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#else
945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define x_putc(c)	shf_putc((c), shl_out)
955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
97c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic int path_order_cmp(const void *, const void *);
985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void glob_table(const char *, XPtrV *, struct table *);
99c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic void glob_path(int, const char *, XPtrV *, const char *);
100c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic int x_file_glob(int *, char *, char ***);
10103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic int x_command_glob(int, char *, char ***);
1025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int x_locate_word(const char *, int, int, int *, bool *);
1035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int x_e_getmbc(char *);
1055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int x_e_rebuildline(const char *);
1065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* +++ generic editing functions +++ */
1085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
1105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * read an edited command line
1115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
1125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
113811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaserx_read(char *buf)
1145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int i;
1165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	x_mode(true);
1185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	modified = 1;
1195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (Flag(FEMACS) || Flag(FGMACS))
120811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		i = x_emacs(buf);
1215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if !MKSH_S_NOVI
1225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (Flag(FVI))
123811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		i = x_vi(buf);
1245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
1255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else
12603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* internal error */
12703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		i = -1;
1285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	editmode = 0;
1295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	x_mode(false);
1305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (i);
1315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* tty I/O */
1345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
1365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querux_getc(void)
1375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char c;
13903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ssize_t n;
1405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while ((n = blocking_read(STDIN_FILENO, &c, 1)) < 0 && errno == EINTR)
1425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (trap) {
1435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			x_mode(false);
1445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			runtraps(0);
1455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifdef SIGWINCH
1465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (got_winch) {
1475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				change_winsz();
1485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (x_cols != xx_cols && editmode == 1) {
1495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					/* redraw line in Emacs mode */
1505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					xx_cols = x_cols;
151427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes					x_init_prompt(false);
1525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					x_e_rebuildline(MKSH_CLRTOEOL_STRING);
1535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
1545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
1555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
1565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			x_mode(true);
1575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return ((n == 1) ? (int)(unsigned char)c : -1);
1595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
1625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querux_putcf(int c)
1635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf_putc(c, shl_out);
1655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*********************************
1685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Misc common code for vi/emacs *
1695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *********************************/
1705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*-
17203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Handle the commenting/uncommenting of a line.
1735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Returns:
1745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	1 if a carriage return is indicated (comment added)
1755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	0 if no return (comment removed)
1765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	-1 if there is an error (not enough room for comment chars)
1775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * If successful, *lenp contains the new length. Note: cursor should be
1785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * moved to the start of the line after (un)commenting.
1795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
1805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
18103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrax_do_comment(char *buf, ssize_t bsize, ssize_t *lenp)
1825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
18303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ssize_t i, j, len = *lenp;
1845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (len == 0)
18603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* somewhat arbitrary - it's what AT&T ksh does */
18703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (1);
1885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Already commented? */
1905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (buf[0] == '#') {
1915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		bool saw_nl = false;
1925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (j = 0, i = 1; i < len; i++) {
1945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!saw_nl || buf[i] != '#')
1955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				buf[j++] = buf[i];
1965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			saw_nl = buf[i] == '\n';
1975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*lenp = j;
1995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (0);
2005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
2015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		int n = 1;
2025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* See if there's room for the #s - 1 per \n */
2045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (i = 0; i < len; i++)
2055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (buf[i] == '\n')
2065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				n++;
2075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (len + n >= bsize)
2085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (-1);
2095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Now add them... */
2105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (i = len, j = len + n; --i >= 0; ) {
2115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (buf[i] == '\n')
2125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				buf[--j] = '#';
2135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			buf[--j] = buf[i];
2145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
2155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		buf[0] = '#';
2165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*lenp += n;
2175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (1);
2185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
2205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/****************************************************
2225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Common file/command completion code for vi/emacs *
2235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru ****************************************************/
2245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
2265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querux_print_expansions(int nwords, char * const *words, bool is_command)
2275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
2285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	bool use_copy = false;
2295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int prefix_len;
230c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	XPtrV l = { NULL, 0, 0 };
2315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
23203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
23303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * Check if all matches are in the same directory (in this
2345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * case, we want to omit the directory name)
2355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
2365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!is_command &&
2375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    (prefix_len = x_longest_prefix(nwords, words)) > 0) {
2385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		int i;
2395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Special case for 1 match (prefix is whole word) */
2415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (nwords == 1)
2425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			prefix_len = x_basename(words[0], NULL);
2435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Any (non-trailing) slashes in non-common word suffixes? */
2445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (i = 0; i < nwords; i++)
2455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (x_basename(words[i] + prefix_len, NULL) >
2465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    prefix_len)
2475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
2485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* All in same directory? */
2495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (i == nwords) {
2505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			while (prefix_len > 0 && words[0][prefix_len - 1] != '/')
2515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				prefix_len--;
2525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			use_copy = true;
2535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			XPinit(l, nwords + 1);
2545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			for (i = 0; i < nwords; i++)
2555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				XPput(l, words[i] + prefix_len);
2565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			XPput(l, NULL);
2575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
2585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/*
2605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * Enumerate expansions
2615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
2625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	x_putc('\r');
2635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	x_putc('\n');
2645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	pr_list(use_copy ? (char **)XPptrv(l) : words);
2655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (use_copy)
26703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* not x_free_words() */
26803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		XPfree(l);
2695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
2705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
271c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser/*
272c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Convert backslash-escaped string to QCHAR-escaped
273c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * string useful for globbing; loses QCHAR unless it
274c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * can squeeze in, eg. by previous loss of backslash
275c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser */
276c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic void
277c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserx_glob_hlp_add_qchar(char *cp)
278c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser{
279c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	char ch, *dp = cp;
280c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	bool escaping = false;
281c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
282c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	while ((ch = *cp++)) {
283c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (ch == '\\' && !escaping) {
284c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			escaping = true;
285c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			continue;
286c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		}
287c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (escaping || (ch == QCHAR && (cp - dp) > 1)) {
288c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/*
289c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			 * empirically made list of chars to escape
290c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			 * for globbing as well as QCHAR itself
291c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			 */
292c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			switch (ch) {
293c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			case QCHAR:
294c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			case '$':
295c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			case '*':
296c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			case '?':
297c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			case '[':
298c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			case '\\':
299c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			case '`':
300c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				*dp++ = QCHAR;
301c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				break;
302c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			}
303c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			escaping = false;
304c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		}
305c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		*dp++ = ch;
306c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	}
307c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	*dp = '\0';
308c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser}
309c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
310c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser/*
311c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Run tilde expansion on argument string, return the result
312c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * after unescaping; if the flag is set, the original string
313c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * is freed if changed and assumed backslash-escaped, if not
314c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * it is assumed QCHAR-escaped
315c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser */
316c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic char *
317c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserx_glob_hlp_tilde_and_rem_qchar(char *s, bool magic_flag)
318c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser{
319c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	char ch, *cp, *dp;
320c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
321c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/*
322c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	 * On the string, check whether we have a tilde expansion,
323c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	 * and if so, discern "~foo/bar" and "~/baz" from "~blah";
324c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	 * if we have a directory part (the former), try to expand
325c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	 */
326c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (*s == '~' && (cp = strchr(s, '/')) != NULL) {
327c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* ok, so split into "~foo"/"bar" or "~"/"baz" */
328c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		*cp++ = 0;
329c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* try to expand the tilde */
330c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (!(dp = tilde(s + 1))) {
331c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* nope, revert damage */
332c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			*--cp = '/';
333c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		} else {
334c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* ok, expand and replace */
335c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			cp = shf_smprintf("%s/%s", dp, cp);
336c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			if (magic_flag)
337c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				afree(s, ATEMP);
338