tech-toolchain archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

make: :range



It is sometimes useful to have an integer sequence to use in conjunction
with slicing.

In dirdeps.mk (part of bmake), I have junk like:

_tspec_x := ${1 2 3 4 5 6 7 8 9 10:L:[1..${TARGET_SPEC_VARS:[#]}]}

(it uses a different strategy if for some bizarre reason
TARGET_SPEC_VARS has > 10 elements), the above could usefully be
replaced with just ${TARGET_SPEC_VARS:range} to provide an integer sequence
representing the elements of TARGET_SPEC_VARS for subsequent processing.

Another example is converting a version like 3.0.5 into something that
can be compared using > < etc:

units = 1 100 10000
version = 3.0.5

vc := ${version:S,., ,g}
v = 0
.for i in 1 2 3
v += + ${vc:[-$i]} \* ${units:[$i]}
.endfor
n := ${expr $v:L:sh}

we could use ${vc:range} for the .for loop

Actually I'd like to be able to encode something like that
in an inline modifier sequence, but that would require being able to
refer back to the variable being modified... something like:

M_cmpv = S,., ,g:range:@i@+ ${_:[-$i]} \* ${units:[$i]}@:S,^,expr 0,:sh

ie $_ refering to the original variable name.
One could then do things like:

.if ${SWIG_VERSION:${M_cmpv}} < ${3.0.11:L:${M_cmpv}}
# compensate for lack of ....

That would be quite a significant change set though, so skipping unless
others think it might be useful.

Anyway, the :range bit is simple enough so perhaps worth adding?

diff -r 44c8e0b96534 bmake/var.c
--- a/bmake/var.c	Sat Jan 14 15:21:31 2017 -0800
+++ b/bmake/var.c	Mon Jan 23 12:14:25 2017 -0800
@@ -2138,6 +2138,51 @@
     return Buf_Destroy(&buf, FALSE);
 }
 
+/*-
+ *-----------------------------------------------------------------------
+ * VarRange --
+ *	Return an integer sequence
+ *
+ * Input:
+ *	str		String whose words provide default range
+ *	ac		range length, if 0 use str words
+ *
+ * Side Effects:
+ *	None.
+ *
+ *-----------------------------------------------------------------------
+ */
+static char *
+VarRange(const char *str, int ac)
+{
+    Buffer	  buf;		    /* Buffer for new string */
+    char	  tmp[32];	    /* each element */
+    char 	**av;		    /* List of words to affect */
+    char 	 *as;		    /* Word list memory */
+    int 	  i, n;
+
+    Buf_Init(&buf, 0);
+    if (ac > 0) {
+	as = NULL;
+	av = NULL;
+    } else {
+	av = brk_string(str, &ac, FALSE, &as);
+    }
+    for (i = 0; i < ac; i++) {
+	n = snprintf(tmp, sizeof(tmp), "%d", 1 + i);
+	if (n >= sizeof(tmp))
+	    break;
+	Buf_AddBytes(&buf, n, tmp);
+	if (i != ac - 1)
+	    Buf_AddByte(&buf, ' ');
+    }
+
+    free(as);
+    free(av);
+
+    return Buf_Destroy(&buf, FALSE);
+}
+
 
 /*-
  *-----------------------------------------------------------------------
@@ -3459,6 +3504,23 @@
 		break;
 	    }
 	    goto default_case;
+	case 'r':
+	    cp = tstr + 1;	/* make sure it is set */
+	    if (STRMOD_MATCHX(tstr, "range", 5)) {
+		int n;
+		
+		if (tstr[5] == '=') {
+		    n = strtoul(&tstr[6], &ep, 10);
+		    cp = ep;
+		} else {
+		    n = 0;
+		    cp = tstr + 5;
+		}
+		newStr = VarRange(nstr, n);
+		termc = *cp;
+		break;
+	    }
+	    goto default_case;
 	case 'O':
 	    {
 		char otype;


Home | Main Index | Thread Index | Old Index