about summary refs log tree commit diff
path: root/Src/hist.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/hist.c')
-rw-r--r--Src/hist.c113
1 files changed, 76 insertions, 37 deletions
diff --git a/Src/hist.c b/Src/hist.c
index 6ac581fda..1a00c30ed 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -34,25 +34,25 @@
  * word control. */
 
 /**/
-mod_export int (*hgetc) _((void));
+mod_export int (*hgetc) (void);
 
 /**/
-void (*hungetc) _((int));
+void (*hungetc) (int);
 
 /**/
-void (*hwaddc) _((int));
+void (*hwaddc) (int);
 
 /**/
-void (*hwbegin) _((int));
+void (*hwbegin) (int);
 
 /**/
-void (*hwabort) _((void));
+void (*hwabort) (void);
 
 /**/
-void (*hwend) _((void));
+void (*hwend) (void);
 
 /**/
-void (*addtoline) _((int));
+void (*addtoline) (int);
 
 /* != 0 means history substitution is turned off */
  
@@ -163,6 +163,11 @@ char *hsubl;
 /**/
 char *hsubr;
  
+/* state of histsubstpattern at last substitution */
+
+/**/
+int hsubpatopt;
+
 /* pointer into the history line */
  
 /**/
@@ -624,7 +629,7 @@ histsubchar(int c)
 	    return substfailed();
 	if (!hsubl)
 	    return -1;
-	if (subst(&sline, hsubl, hsubr, gbal))
+	if (subst(&sline, hsubl, hsubr, gbal, 0))
 	    return substfailed();
     } else {
 	/* Line doesn't begin ^foo^bar */
@@ -831,7 +836,7 @@ histsubchar(int c)
 	    if ((c = ingetc()) == 'g') {
 		gbal = 1;
 		c = ingetc();
-		if (c != 's' && c != '&') {
+		if (c != 's' && c != 'S' && c != '&') {
 		    zerr("'s' or '&' modifier expected after 'g'");
 		    return -1;
 		}
@@ -891,11 +896,13 @@ histsubchar(int c)
 		}
 		break;
 	    case 's':
+	    case 'S':
+		hsubpatopt = (c == 'S');
 		if (getsubsargs(sline, &gbal, &cflag))
 		    return -1; /* fall through */
 	    case '&':
 		if (hsubl && hsubr) {
-		    if (subst(&sline, hsubl, hsubr, gbal))
+		    if (subst(&sline, hsubl, hsubr, gbal, hsubpatopt))
 			return substfailed();
 		} else {
 		    herrflush();
@@ -1352,7 +1359,8 @@ putoldhistentryontop(short keep_going)
 	do {
 	    if (max_unique_ct-- <= 0 || he == hist_ring) {
 		max_unique_ct = 0;
-		he = hist_ring->down;
+		if (hist_ring)
+		    he = hist_ring->down;
 		next = hist_ring;
 		break;
 	    }
@@ -1360,12 +1368,16 @@ putoldhistentryontop(short keep_going)
 	    next = he->down;
 	} while (!(he->node.flags & HIST_DUP));
     }
-    if (he != hist_ring->down) {
+    /* Is it really possible for hist_ring to be NULL here? */
+    if (he && (!hist_ring || he != hist_ring->down)) {
 	he->up->down = he->down;
 	he->down->up = he->up;
 	he->up = hist_ring;
-	he->down = hist_ring->down;
-	hist_ring->down = he->down->up = he;
+	if (hist_ring) {
+	    he->down = hist_ring->down;
+	    hist_ring->down = he;
+	}
+	he->down->up = he;
     }
     hist_ring = he;
 }
@@ -1461,7 +1473,7 @@ should_ignore_line(Eprog prog)
 mod_export int
 hend(Eprog prog)
 {
-    int flag, hookret, stack_pos = histsave_stack_pos;
+    int flag, hookret = 0, stack_pos = histsave_stack_pos;
     /*
      * save:
      * 0: don't save
@@ -1643,12 +1655,17 @@ hend(Eprog prog)
 void
 ihwbegin(int offset)
 {
+    int pos = hptr - chline + offset;
     if (stophist == 2 || (histactive & HA_INWORD) ||
 	(inbufflags & (INP_ALIAS|INP_HIST)) == INP_ALIAS)
 	return;
     if (chwordpos%2)
 	chwordpos--;	/* make sure we're on a word start, not end */
-    chwords[chwordpos++] = hptr - chline + offset;
+    DPUTS1(pos < 0, "History word position < 0 in %s",
+	   dupstrpfx(chline, hptr-chline));
+    if (pos < 0)
+	pos = 0;
+    chwords[chwordpos++] = pos;
 }
 
 /* Abort current history word, not needed */
@@ -1861,7 +1878,11 @@ chabspath(char **junkptr)
 	return 1;
 
     if (**junkptr != '/') {
-	*junkptr = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP), "/", *junkptr);
+	char *here = zgetcwd();
+	if (here[strlen(here)-1] != '/')
+	    *junkptr = zhtricat(metafy(here, -1, META_HEAPDUP), "/", *junkptr);
+	else
+	    *junkptr = dyncat(here, *junkptr);
     }
 
     current = *junkptr;
@@ -2231,7 +2252,7 @@ casemodify(char *str, int how)
 		char *mbptr;
 
 		for (mbptr = mbstr; mbptr < mbstr + len2; mbptr++) {
-		    if (imeta(STOUC(*mbptr))) {
+		    if (imeta((unsigned char) *mbptr)) {
 			*ptr2++ = Meta;
 			*ptr2++ = *mbptr ^ 32;
 		    } else
@@ -2248,20 +2269,25 @@ casemodify(char *str, int how)
 #endif
 	while (*str) {
 	    int c;
+	    int mod = 0;
 	    if (*str == Meta) {
-		c = str[1] ^ 32;
+		c = (unsigned char) (str[1] ^ 32);
 		str += 2;
 	    } else
-		c = *str++;
+		c = (unsigned char) *str++;
 	    switch (how) {
 	    case CASMOD_LOWER:
-		if (isupper(c))
+		if (isupper(c)) {
 		    c = tolower(c);
+		    mod = 1;
+		}
 		break;
 
 	    case CASMOD_UPPER:
-		if (islower(c))
+		if (islower(c)) {
 		    c = toupper(c);
+		    mod = 1;
+		}
 		break;
 
 	    case CASMOD_CAPS:
@@ -2269,14 +2295,18 @@ casemodify(char *str, int how)
 		if (!ialnum(c))
 		    nextupper = 1;
 		else if (nextupper) {
-		    if (islower(c))
+		    if (islower(c)) {
 			c = toupper(c);
+			mod = 1;
+		    }
 		    nextupper = 0;
-		} else if (isupper(c))
+		} else if (isupper(c)) {
 		    c = tolower(c);
+		    mod = 1;
+		}
 		break;
 	    }
-	    if (imeta(c)) {
+	    if (mod && imeta(c)) {
 		*ptr2++ = Meta;
 		*ptr2++ = c ^ 32;
 	    } else
@@ -2297,7 +2327,7 @@ casemodify(char *str, int how)
 
 /**/
 int
-subst(char **strptr, char *in, char *out, int gbal)
+subst(char **strptr, char *in, char *out, int gbal, int forcepat)
 {
     char *str = *strptr, *substcut, *sptr;
     int off, inlen, outlen;
@@ -2305,7 +2335,7 @@ subst(char **strptr, char *in, char *out, int gbal)
     if (!*in)
 	in = str, gbal = 0;
 
-    if (isset(HISTSUBSTPATTERN)) {
+    if (isset(HISTSUBSTPATTERN) || forcepat) {
 	int fl = SUB_LONG|SUB_REST|SUB_RETFAIL;
 	char *oldin = in;
 	if (gbal)
@@ -2615,12 +2645,19 @@ readhistline(int start, char **bufp, int *bufsiz, FILE *in, int *readbytes)
 	    }
 	}
 	else {
+	    int spc;
 	    buf[len - 1] = '\0';
 	    if (len > 1 && buf[len - 2] == '\\') {
 		buf[--len - 1] = '\n';
 		if (!feof(in))
 		    return readhistline(len, bufp, bufsiz, in, readbytes);
 	    }
+
+	    spc = len - 2;
+	    while (spc >= 0 && buf[spc] == ' ')
+		spc--;
+	    if (spc != len - 2 && buf[spc] == '\\')
+		buf[--len - 1] = '\0';
 	}
 	return len;
     }
@@ -2984,7 +3021,7 @@ savehistfile(char *fn, int err, int writeflags)
 
 	ret = 0;
 	for (; he && he->histnum <= xcurhist; he = down_histent(he)) {
-	    int count_backslashes = 0;
+	    int end_backslashes = 0;
 
 	    if ((writeflags & HFILE_SKIPDUPS && he->node.flags & HIST_DUP)
 	     || (writeflags & HFILE_SKIPFOREIGN && he->node.flags & HIST_FOREIGN)
@@ -3017,18 +3054,14 @@ savehistfile(char *fn, int err, int writeflags)
 		if (*t == '\n')
 		    if ((ret = fputc('\\', out)) < 0)
 			break;
-		if (*t == '\\')
-		    count_backslashes++;
-		else
-		    count_backslashes = 0;
+		end_backslashes = (*t == '\\' || (end_backslashes && *t == ' '));
 		if ((ret = fputc(*t, out)) < 0)
 		    break;
 	    }
 	    if (ret < 0)
 	    	break;
-	    if (count_backslashes && (count_backslashes % 2 == 0))
-		if ((ret = fputc(' ', out)) < 0)
-		    break;
+	    if (end_backslashes)
+		ret = fputc(' ', out);
 	    if (ret < 0 || (ret = fputc('\n', out)) < 0)
 		break;
 	}
@@ -3775,8 +3808,14 @@ histsplitwords(char *lineptr, short **wordsp, int *nwordsp, int *nwordposp,
 			zrealloc(words, nwords*sizeof(*words));
 		}
 		words[nwordpos++] = lineptr - start;
-		while (*lineptr && !inblank(*lineptr))
-		    lineptr++;
+		while (*lineptr) {
+		    if (*lineptr == Meta && lineptr[1])
+			lineptr += 2;
+		    else if (!inblank(*lineptr))
+			lineptr++;
+		    else
+			break;
+		}
 		words[nwordpos++] = lineptr - start;
 	    }
 	} while (*lineptr);