Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Feature request: ${(l[-3][0])var} to do left padding *without truncation*



2024-08-04 07:44:26 +0100, Stephane Chazelas:
[...]
> Maybe best would be to have get_intarg() return true/false and
> the value by reference, and handle negative value on a case by
> case basis in a more useful way:
[...]
> ${(l[-3][0])var}  pad to length 3 without truncating
> ${(r[-3][0])var}  pad to length 3 without truncating
[...]

Ah, I forgot those 2 can be combined, so there's the question of
what to do if one is positive and one is negative:

1- either skip truncating at all if any is negative
2- or truncate only on the side where it's positive. Would that even
  make sense?

Or instead of relying on negative value, use another flag to
skip the truncation?

Here's a patch doing 1 and returning errors for F[-1] I[-1]:

diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index 7eade4a11..aa497f415 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -1403,6 +1403,10 @@ Left and right padding may be used together.  In this case the strategy
 is to apply left padding to the first half width of each of the resulting
 words, and right padding to the second half.  If the string to be
 padded has odd width the extra padding is applied on the left.
+
+If the left or right padding length is negative, then the absolute value is
+used and the truncating is disabled (strings longer than the total padding
+length are left alone).
 )
 item(tt(s:)var(string)tt(:))(
 Force field splitting at the
diff --git a/Src/subst.c b/Src/subst.c
index a079672df..79e147963 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -898,7 +898,8 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone,
     )
 {
     char *def, *ret, *t, *r;
-    int ls, ls2, lpreone, lpostone, lpremul, lpostmul, lr, f, m, c, cc, cl;
+    int ls, ls2, lpreone, lpostone, lpremul, lpostmul, lr, f, m, c, cc, cl, total;
+    int padonly = 0;
     convchar_t cchar;
 
     MB_METACHARINIT();
@@ -922,7 +923,17 @@ dopadding(char *str, int prenum, int postnum, char *preone, char *postone,
     lpremul = MB_METASTRLEN2(premul, multi_width);
     lpostmul = MB_METASTRLEN2(postmul, multi_width);
 
-    if (prenum + postnum == ls)
+    if (prenum < 0) {
+	padonly = 1;
+	prenum = -prenum;
+    }
+    if (postnum < 0) {
+	padonly = 1;
+	postnum = -postnum;
+    }
+    total = prenum + postnum;
+
+    if (total == ls || (padonly && (total < ls)))
 	return str;
 
     /*
@@ -1425,7 +1436,7 @@ get_strarg(char *s, int *lenp)
 
 /**/
 static int
-get_intarg(char **s, int *delmatchp)
+get_intarg(char **s, int *delmatchp, int *result)
 {
     int arglen;
     char *t = get_strarg(*s, &arglen);
@@ -1434,24 +1445,23 @@ get_intarg(char **s, int *delmatchp)
 
     *delmatchp = 0;
     if (!*t)
-	return -1;
+	return 0;
     sav = *t;
     *t = '\0';
     p = dupstring(*s + arglen);
     *s = t + arglen;
     *t = sav;
     if (parsestr(&p))
-	return -1;
+	return 0;
     singsub(&p);
     if (errflag)
-	return -1;
+	return 0;
     ret = mathevali(p);
     if (errflag)
-	return -1;
-    if (ret < 0)
-	ret = -ret;
+	return 0;
     *delmatchp = arglen;
-    return ret;
+    *result = ret;
+    return 1;
 }
 
 /* Parsing for the (e) flag. */
@@ -1772,7 +1782,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
     /* Replacement string for /orig/repl and //orig/repl */
     char *replstr = NULL;
     /* The numbers for (l) and (r) */
-    zlong prenum = 0, postnum = 0;
+    int prenum = 0, postnum = 0;
 #ifdef MULTIBYTE_SUPPORT
     /* The (m) flag: use width of multibyte characters */
     int multi_width = 0;
@@ -2130,7 +2140,6 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
 	} else if (c == '(' || c == Inpar) {
 	    char *t, sav;
 	    int tt = 0;
-	    zlong num;
 	    /*
 	     * The (p) flag is only remembered within
 	     * this block.  It says we do print-style handling
@@ -2187,9 +2196,13 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
 		    break;
 		case 'I':
 		    s++;
-		    flnum = get_intarg(&s, &dellen);
-		    if (flnum < 0)
+		    if (!get_intarg(&s, &dellen, &flnum))
+			goto flagerr;
+		    if (flnum < 0) {
+			/* TODO: handle -3 as 3rd last */
+			zerr("I flag argument must be positive");
 			goto flagerr;
+		    }
 		    s--;
 		    break;
 
@@ -2322,13 +2335,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
 		    s++;
 		    /* delimiter position */
 		    del0 = s;
-		    num = get_intarg(&s, &dellen);
-		    if (num < 0)
+		    if (!get_intarg(&s, &dellen, tt ? &prenum : &postnum))
 			goto flagerr;
-		    if (tt)
-			prenum = num;
-		    else
-			postnum = num;
 		    /* must have same delimiter if more arguments */
 		    if (!dellen || memcmp(del0, s, dellen)) {
 			/* decrement since loop will increment */
@@ -4702,7 +4710,11 @@ modify(char **str, char **ptr, int inbrace)
 		break;
 	    case 'F':
 		(*ptr)++;
-		rec = get_intarg(ptr, &dellen);
+		if (!get_intarg(ptr, &dellen, &rec)) return;
+		if (rec < 0) {
+		    zerr("F flag argument must be positive");
+		    return;
+		}
 		break;
 	    default:
 		*ptr = lptr;

-- 
Stephane




Messages sorted by: Reverse Date, Date, Thread, Author