summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
authorPeter Stephenson <pws@zsh.org>2015-06-05 11:21:22 +0100
committerPeter Stephenson <pws@zsh.org>2015-06-05 11:21:22 +0100
commit2abba7243a736a2fc626f3cc917d8a67014d4d20 (patch)
treec91850e5786a9a8e0c9ebbedc65abbc3a3131cd0 /Src
parent4804a7c5ff144fc7cc974484d16f2f88cc131264 (diff)
downloadzsh-2abba7243a736a2fc626f3cc917d8a67014d4d20.tar.gz
zsh-2abba7243a736a2fc626f3cc917d8a67014d4d20.zip
35386: expand tabs where useful in builtins outputing function.
Also add to zed -f. Option is -x <numm>.
Diffstat (limited to 'Src')
-rw-r--r--Src/builtin.c50
-rw-r--r--Src/hashtable.c74
-rw-r--r--Src/pattern.c13
-rw-r--r--Src/text.c46
-rw-r--r--Src/utils.c43
-rw-r--r--Src/zsh.h9
6 files changed, 196 insertions, 39 deletions
diff --git a/Src/builtin.c b/Src/builtin.c
index 4b081468d..0d1d00ec3 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -72,7 +72,7 @@ static struct builtin builtins[] =
BUILTIN("fc", 0, bin_fc, 0, -1, BIN_FC, "aAdDe:EfiIlLmnpPrRt:W", NULL),
BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL),
BUILTIN("float", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%Z:%ghlprtux", "E"),
- BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "kmMtTuUz", NULL),
+ BUILTIN("functions", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "kmMtTuUx:z", NULL),
BUILTIN("getln", 0, bin_read, 0, -1, 0, "ecnAlE", "zr"),
BUILTIN("getopts", 0, bin_getopts, 2, -1, 0, NULL, NULL),
BUILTIN("hash", BINF_MAGICEQUALS, bin_hash, 0, -1, 0, "Ldfmrv", NULL),
@@ -128,9 +128,9 @@ static struct builtin builtins[] =
BUILTIN("unset", BINF_PSPECIAL, bin_unset, 1, -1, 0, "fmv", NULL),
BUILTIN("unsetopt", 0, bin_setopt, 0, -1, BIN_UNSETOPT, NULL, NULL),
BUILTIN("wait", 0, bin_fg, 0, -1, BIN_WAIT, NULL, NULL),
- BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsSw", NULL),
- BUILTIN("where", 0, bin_whence, 0, -1, 0, "pmsSw", "ca"),
- BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsSw", "c"),
+ BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsSwx:", NULL),
+ BUILTIN("where", 0, bin_whence, 0, -1, 0, "pmsSwx:", "ca"),
+ BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsSwx:", "c"),
BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "AFRILP:abcfdilmpue", NULL),
BUILTIN("zcompile", 0, bin_zcompile, 0, -1, 0, "tUMRcmzka", NULL),
};
@@ -2749,7 +2749,7 @@ bin_functions(char *name, char **argv, Options ops, int func)
Patprog pprog;
Shfunc shf;
int i, returnval = 0;
- int on = 0, off = 0, pflags = 0, roff;
+ int on = 0, off = 0, pflags = 0, roff, expand = 0;
/* Do we have any flags defined? */
if (OPT_PLUS(ops,'u'))
@@ -2785,11 +2785,23 @@ bin_functions(char *name, char **argv, Options ops, int func)
}
if ((off & PM_UNDEFINED) || (OPT_ISSET(ops,'k') && OPT_ISSET(ops,'z')) ||
+ (OPT_ISSET(ops,'x') && !OPT_HASARG(ops,'x')) ||
(OPT_MINUS(ops,'X') && (OPT_ISSET(ops,'m') || *argv || !scriptname))) {
zwarnnam(name, "invalid option(s)");
return 1;
}
+ if (OPT_ISSET(ops,'x')) {
+ char *eptr;
+ expand = (int)zstrtol(OPT_ARG(ops,'x'), &eptr, 10);
+ if (*eptr) {
+ zwarnnam(name, "number expected after -x");
+ return 1;
+ }
+ if (expand == 0) /* no indentation at all */
+ expand = -1;
+ }
+
if (OPT_PLUS(ops,'f') || roff || OPT_ISSET(ops,'+'))
pflags |= PRINT_NAMEONLY;
@@ -2948,8 +2960,8 @@ bin_functions(char *name, char **argv, Options ops, int func)
} else {
if (OPT_ISSET(ops,'U') && !OPT_ISSET(ops,'u'))
on &= ~PM_UNDEFINED;
- scanhashtable(shfunctab, 1, on|off, DISABLED, shfunctab->printnode,
- pflags);
+ scanshfunc(1, on|off, DISABLED, shfunctab->printnode,
+ pflags, expand);
}
unqueue_signals();
return ret;
@@ -2965,8 +2977,8 @@ bin_functions(char *name, char **argv, Options ops, int func)
/* with no options, just print all functions matching the glob pattern */
queue_signals();
if (!(on|off) && !OPT_ISSET(ops,'X')) {
- scanmatchtable(shfunctab, pprog, 1, 0, DISABLED,
- shfunctab->printnode, pflags);
+ scanmatchshfunc(pprog, 1, 0, DISABLED,
+ shfunctab->printnode, pflags, expand);
} else {
/* apply the options to all functions matching the glob pattern */
for (i = 0; i < shfunctab->hsize; i++) {
@@ -3008,7 +3020,7 @@ bin_functions(char *name, char **argv, Options ops, int func)
returnval = 1;
} else
/* no flags, so just print */
- shfunctab->printnode(&shf->node, pflags);
+ printshfuncexpand(&shf->node, pflags, expand);
} else if (on & PM_UNDEFINED) {
int signum = -1, ok = 1;
@@ -3222,6 +3234,7 @@ bin_whence(char *nam, char **argv, Options ops, int func)
int aliasflags;
int csh, all, v, wd;
int informed = 0;
+ int expand = 0;
char *cnam, **allmatched = 0;
/* Check some option information */
@@ -3230,6 +3243,17 @@ bin_whence(char *nam, char **argv, Options ops, int func)
all = OPT_ISSET(ops,'a');
wd = OPT_ISSET(ops,'w');
+ if (OPT_ISSET(ops,'x')) {
+ char *eptr;
+ expand = (int)zstrtol(OPT_ARG(ops,'x'), &eptr, 10);
+ if (*eptr) {
+ zwarnnam(nam, "number expected after -x");
+ return 1;
+ }
+ if (expand == 0) /* no indentation at all */
+ expand = -1;
+ }
+
if (OPT_ISSET(ops,'w'))
printflags |= PRINT_WHENCE_WORD;
else if (OPT_ISSET(ops,'c'))
@@ -3286,8 +3310,8 @@ bin_whence(char *nam, char **argv, Options ops, int func)
/* and shell functions... */
informed +=
- scanmatchtable(shfunctab, pprog, 1, 0, DISABLED,
- shfunctab->printnode, printflags);
+ scanmatchshfunc(pprog, 1, 0, DISABLED,
+ shfunctab->printnode, printflags, expand);
/* and builtins. */
informed +=
@@ -3342,7 +3366,7 @@ bin_whence(char *nam, char **argv, Options ops, int func)
}
/* Look for shell function */
if ((hn = shfunctab->getnode(shfunctab, *argv))) {
- shfunctab->printnode(hn, printflags);
+ printshfuncexpand(hn, printflags, expand);
informed = 1;
if (!all)
continue;
diff --git a/Src/hashtable.c b/Src/hashtable.c
index ab381cc6a..2b5524999 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -937,13 +937,17 @@ printshfuncnode(HashNode hn, int printflags)
quotedzputs(f->node.nam, stdout);
if (f->funcdef || f->node.flags & PM_UNDEFINED) {
- printf(" () {\n\t");
- if (f->node.flags & PM_UNDEFINED)
- printf("%c undefined\n\t", hashchar);
- else
+ printf(" () {\n");
+ zoutputtab(stdout);
+ if (f->node.flags & PM_UNDEFINED) {
+ printf("%c undefined\n", hashchar);
+ zoutputtab(stdout);
+ } else
t = getpermtext(f->funcdef, NULL, 1);
- if (f->node.flags & (PM_TAGGED|PM_TAGGED_LOCAL))
- printf("%c traced\n\t", hashchar);
+ if (f->node.flags & (PM_TAGGED|PM_TAGGED_LOCAL)) {
+ printf("%c traced\n", hashchar);
+ zoutputtab(stdout);
+ }
if (!t) {
char *fopt = "UtTkz";
int flgs[] = {
@@ -959,11 +963,12 @@ printshfuncnode(HashNode hn, int printflags)
zputs(t, stdout);
zsfree(t);
if (f->funcdef->flags & EF_RUN) {
- printf("\n\t");
+ printf("\n");
+ zoutputtab(stdout);
quotedzputs(f->node.nam, stdout);
printf(" \"$@\"");
}
- }
+ }
printf("\n}");
} else {
printf(" () { }");
@@ -979,6 +984,59 @@ printshfuncnode(HashNode hn, int printflags)
putchar('\n');
}
+/*
+ * Wrap scanmatchtable for shell functions with optional
+ * expansion of leading tabs.
+ * expand = 0 is standard: use hard tabs.
+ * expand > 0 uses that many spaces.
+ * expand < 0 uses no identation.
+ *
+ * Note this function and the following two are called with
+ * interrupts queued, so saving and restoring text_expand_tabs
+ * is safe.
+ */
+
+/**/
+mod_export int
+scanmatchshfunc(Patprog pprog, int sorted, int flags1, int flags2,
+ ScanFunc scanfunc, int scanflags, int expand)
+{
+ int ret, save_expand;
+
+ save_expand = text_expand_tabs;
+ text_expand_tabs = expand;
+ ret = scanmatchtable(shfunctab, pprog, sorted, flags1, flags2,
+ scanfunc, scanflags);
+ text_expand_tabs = save_expand;
+
+ return ret;
+}
+
+/* Wrap scanhashtable to expand tabs for shell functions */
+
+/**/
+mod_export int
+scanshfunc(int sorted, int flags1, int flags2,
+ ScanFunc scanfunc, int scanflags, int expand)
+{
+ return scanmatchshfunc(NULL, sorted, flags1, flags2,
+ scanfunc, scanflags, expand);
+}
+
+/* Wrap shfunctab->printnode to expand tabs */
+
+/**/
+mod_export void
+printshfuncexpand(HashNode hn, int printflags, int expand)
+{
+ int save_expand;
+
+ save_expand = text_expand_tabs;
+ text_expand_tabs = expand;
+ shfunctab->printnode(hn, printflags);
+ text_expand_tabs = save_expand;
+}
+
/**************************************/
/* Reserved Word Hash Table Functions */
/**************************************/
diff --git a/Src/pattern.c b/Src/pattern.c
index 4e5e8a110..7e07548f9 100644
--- a/Src/pattern.c
+++ b/Src/pattern.c
@@ -2202,20 +2202,15 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen,
if ((patglobflags & GF_MATCHREF) &&
!(patflags & PAT_FILE)) {
char *str = ztrduppfx(patinstart, patinlen);
- char *ptr = patinstart;
- int mlen = 0;
+ int mlen;
/*
* Count the characters. We're not using CHARSUB()
- * because the string is still metafied. We're
- * not using mb_metastrlen() because that expects
- * the string to be null terminated.
+ * because the string is still metafied.
*/
MB_METACHARINIT();
- while (ptr < patinstart + patinlen) {
- mlen++;
- ptr += MB_METACHARLEN(ptr);
- }
+ mlen = MB_METASTRLEN2END(patinstart, 0,
+ patinstart + patinlen);
setsparam("MATCH", str);
setiparam("MBEGIN",
diff --git a/Src/text.c b/Src/text.c
index 958303c68..850879699 100644
--- a/Src/text.c
+++ b/Src/text.c
@@ -30,6 +30,16 @@
#include "zsh.mdh"
#include "text.pro"
+/*
+ * If non-zero, expand syntactically significant leading tabs in text
+ * to this number of spaces.
+ *
+ * If negative, don't output leading whitespace at all.
+ */
+
+/**/
+int text_expand_tabs;
+
static char *tptr, *tbuf, *tlim, *tpending;
static int tsiz, tindent, tnewlins, tjob;
@@ -156,8 +166,16 @@ taddnl(int no_semicolon)
if (tnewlins) {
tdopending();
taddchr('\n');
- for (t0 = 0; t0 != tindent; t0++)
- taddchr('\t');
+ for (t0 = 0; t0 != tindent; t0++) {
+ if (text_expand_tabs >= 0) {
+ if (text_expand_tabs) {
+ int t1;
+ for (t1 = 0; t1 < text_expand_tabs; t1++)
+ taddchr(' ');
+ } else
+ taddchr('\t');
+ }
+ }
} else if (no_semicolon) {
taddstr(" ");
} else {
@@ -165,6 +183,30 @@ taddnl(int no_semicolon)
}
}
+/*
+ * Output a tab that may be expanded as part of a leading set.
+ * Note this is not part of the text framework; it's for
+ * code that needs to output its own tabs that are to be
+ * consistent with those from getpermtext().
+ *
+ * Note these tabs are only expected to be useful at the
+ * start of the line, so we make no attempt to count columns.
+ */
+
+/**/
+void
+zoutputtab(FILE *outf)
+{
+ if (text_expand_tabs < 0)
+ return;
+ if (text_expand_tabs) {
+ int i;
+ for (i = 0; i < text_expand_tabs; i++)
+ fputc(' ', outf);
+ } else
+ fputc('\t', outf);
+}
+
/* get a permanent textual representation of n */
/**/
diff --git a/Src/utils.c b/Src/utils.c
index 7409dc876..c33c16d5a 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -4471,9 +4471,37 @@ ztrlen(char const *s)
for (l = 0; *s; l++) {
if (*s++ == Meta) {
#ifdef DEBUG
- if (! *s)
+ if (! *s) {
fprintf(stderr, "BUG: unexpected end of string in ztrlen()\n");
- else
+ break;
+ } else
+#endif
+ s++;
+ }
+ }
+ return l;
+}
+
+#ifndef MULTIBYTE_SUPPORT
+/*
+ * ztrlen() but with explicit end point for non-null-terminated
+ * segments. eptr may not be NULL.
+ */
+
+/**/
+mod_export int
+ztrlenend(char const *s, char const *eptr)
+{
+ int l;
+
+ for (l = 0; s < eptr; l++) {
+ if (*s++ == Meta) {
+#ifdef DEBUG
+ if (! *s) {
+ fprintf(stderr,
+ "BUG: unexpected end of string in ztrlenend()\n");
+ break;
+ } else
#endif
s++;
}
@@ -4481,6 +4509,8 @@ ztrlen(char const *s)
return l;
}
+#endif /* MULTIBYTE_SUPPORT */
+
/* Subtract two pointers in a metafied string. */
/**/
@@ -4879,11 +4909,16 @@ mb_metacharlenconv(const char *s, wint_t *wcp)
* If width is 1, return total character width rather than number.
* If width is greater than 1, return 1 if character has non-zero width,
* else 0.
+ *
+ * Ends if either *ptr is '\0', the normal case (eptr may be NULL for
+ * this), or ptr is eptr (i.e. *eptr is where the null would be if null
+ * terminated) for strings not delimited by nulls --- note these are
+ * still metafied.
*/
/**/
mod_export int
-mb_metastrlen(char *ptr, int width)
+mb_metastrlenend(char *ptr, int width, char *eptr)
{
char inchar, *laststart;
size_t ret;
@@ -4898,7 +4933,7 @@ mb_metastrlen(char *ptr, int width)
num = num_in_char = 0;
memset(&mb_shiftstate, 0, sizeof(mb_shiftstate));
- while (*ptr) {
+ while (*ptr && !(eptr && ptr >= eptr)) {
if (*ptr == Meta)
inchar = *++ptr ^ 32;
else
diff --git a/Src/zsh.h b/Src/zsh.h
index f6e08e28d..c88c2e739 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2926,9 +2926,11 @@ enum {
typedef wint_t convchar_t;
#define MB_METACHARLENCONV(str, cp) mb_metacharlenconv((str), (cp))
#define MB_METACHARLEN(str) mb_metacharlenconv(str, NULL)
-#define MB_METASTRLEN(str) mb_metastrlen(str, 0)
-#define MB_METASTRWIDTH(str) mb_metastrlen(str, 1)
-#define MB_METASTRLEN2(str, widthp) mb_metastrlen(str, widthp)
+#define MB_METASTRLEN(str) mb_metastrlenend(str, 0, NULL)
+#define MB_METASTRWIDTH(str) mb_metastrlenend(str, 1, NULL)
+#define MB_METASTRLEN2(str, widthp) mb_metastrlenend(str, widthp, NULL)
+#define MB_METASTRLEN2END(str, widthp, eptr) \
+ mb_metastrlenend(str, widthp, eptr)
/*
* We replace broken implementations with one that uses Unicode
@@ -3011,6 +3013,7 @@ typedef int convchar_t;
#define MB_METASTRLEN(str) ztrlen(str)
#define MB_METASTRWIDTH(str) ztrlen(str)
#define MB_METASTRLEN2(str, widthp) ztrlen(str)
+#define MB_METASTRLEN2END(str, widthp, eptr) ztrlenend(str, eptr)
#define WCWIDTH_WINT(c) (1)