Subject: Re: make: :[] implementation
To: Alan Barrett <apb@cequrux.com>
From: Simon J. Gerraty <sjg@crufty.net>
List: tech-toolchain
Date: 09/24/2003 23:12:39
On Wed, 24 Sep 2003 12:06:29 -0700 (PDT), Simon J. Gerraty writes:
>>Both :[m..n] and :[n..m] are treated identically, so both :[2..-1] and
>>:[-1..2] mean "everything from the second word to the last word".  If we
>>ever plan to use syntax like this to reverse the order of words in the
>>result (but if we don't implement that functionality just yet), then it
>>might be a good idea to say that it's an error (for now) for the indices
>>to be in the wrong order.
>
>I plan to eventually handle reversing the order, so yes will make [-1..2]
>an error for now.

Ok, turns out that doing the error detection is most of the work - so 
:[-1..1] now works to reverse the words in a list.
I replaced your VarSelectWords() with something that looks more like
VarModify() but can scan backwards as well as forwards (much the same
as I described a while back) - see below.
I could have (and actually did while testing) call this something
different and had it call your VarSelectWords, but that ends up potentially
being lots of pointless function calls.

At this point the Var_Parse_State fields argc and argnum are not used.
I'll probably remove them - they can be re-added if needed in future.

So all I need now are votes for which of
:tW
:[*] or :[0] 
to retain as meaning treat the value as one big word.

--sjg

static char *
VarSelectWords(GNode *ctx, Var_Parse_State *vpstate,
	       const char *str, VarSelectWords_t *seldata)
{
    Buffer  	  buf;	    	    /* Buffer for the new string */
    Boolean 	  addSpace; 	    /* TRUE if need to add a space to the
				     * buffer before adding the trimmed
				     * word */
    char **av;			    /* word list */
    char *as;			    /* word list memory */
    int ac, i;

    buf = Buf_Init (0);
    addSpace = FALSE;

    if (vpstate->oneBigWord) {
	/* fake what brk_string() would do if there were only one word */
	ac = 1;
    	av = (char **)emalloc((ac + 1) * sizeof(char *));
	as = strdup(str);
	av[0] = as;
	av[1] = NULL;
    } else {
	av = brk_string(str, &ac, FALSE, &as);
    }

    vpstate->argc = ac;

    /*
     * Now sanitize seldata.
     * If seldata->start or seldata->end are negative, convert them to
     * the positive equivalents (-1 gets converted to argc, -2 gets
     * converted to (argc-1), etc.).
     */
    if (seldata->start < 0)
	seldata->start = ac + seldata->start + 1;
    if (seldata->end < 0)
	seldata->end = ac + seldata->end + 1;
    seldata->sanitized = TRUE;

    /*
     * We avoid scanning more of the list than we need to.
     */
    if (seldata->start > seldata->end) {
	for (i = MIN(ac, seldata->start) - 1;
	     i >= MAX(0, seldata->end - 1); i--) {
	    if (av[i] && *av[i]) {
		if (addSpace && vpstate->varSpace) {
		    Buf_AddByte(buf, vpstate->varSpace);
		}
		Buf_AddBytes(buf, strlen(av[i]), (Byte *)av[i]);
		addSpace = TRUE;
	    }
	}
    } else {
	for (i = MAX(0, seldata->start - 1); i < MIN(ac, seldata->end); i++) {
	    if (av[i] && *av[i]) {
		if (addSpace && vpstate->varSpace) {
		    Buf_AddByte(buf, vpstate->varSpace);
		}
		Buf_AddBytes(buf, strlen(av[i]), (Byte *)av[i]);
		addSpace = TRUE;
	    }
	}
    }

    free(as);
    free(av);

    Buf_AddByte (buf, '\0');
    as = (char *)Buf_GetAll (buf, (int *)NULL);
    Buf_Destroy (buf, FALSE);
    return (as);
}