[PATCH 08 of 10] chg: implement validate in hgclient

Yuya Nishihara yuya at tcha.org
Thu Mar 3 11:07:50 EST 2016


On Wed, 2 Mar 2016 10:44:10 +0000, Jun Wu wrote:
> # HG changeset patch
> # User Jun Wu <quark at fb.com>
> # Date 1456913788 0
> #      Wed Mar 02 10:16:28 2016 +0000
> # Node ID 801df1c31d0c49a19fe3dca0025b393dcc292599
> # Parent  7a0eaf66c464e1fcab9b8470811de0d88ef754ff
> chg: implement validate in hgclient
> 
> This patch implements the corresponding validate method in hgclient.
> It will return action strings as is but will not take any real action.
> 
> diff --git a/contrib/chg/hgclient.c b/contrib/chg/hgclient.c
> --- a/contrib/chg/hgclient.c
> +++ b/contrib/chg/hgclient.c
> @@ -34,6 +34,7 @@
>  	CAP_GETPAGER = 0x0400,
>  	CAP_SETENV = 0x0800,
>  	CAP_SETUMASK = 0x1000,
> +	CAP_VALIDATE = 0x2000,
>  };
>  
>  typedef struct {
> @@ -49,6 +50,7 @@
>  	{"getpager", CAP_GETPAGER},
>  	{"setenv", CAP_SETENV},
>  	{"setumask", CAP_SETUMASK},
> +	{"validate", CAP_VALIDATE},
>  	{NULL, 0},  /* terminator */
>  };
>  
> @@ -463,6 +465,52 @@
>  }
>  
>  /*!
> + * Send command line arguments to let the server decide whether it has the
> + * up-to-date config, extensions and can handle our request.
> + * @return - NULL, the server passed or does not support validation.
> + *         - a list of strings, which are the instructions returned by the
> + *           server, the list (not the strings) must be freed by the caller.
> + *           the last string is guaranteed NULL.
> + */
> +const char **hgc_validate(hgclient_t *hgc, const char *const args[],
> +			  size_t argsize)

I'm not a fan of "must be freed by the caller" design. Since we know the
list is small, it could be a destination argument and return the actual length.

> +{
> +	assert(hgc);
> +	if (!(hgc->capflags & CAP_VALIDATE))
> +		return NULL;
> +
> +	packcmdargs(&hgc->ctx, args, argsize);
> +	writeblockrequest(hgc, "validate");
> +	readchannel(hgc);
> +
> +	/* the server returns '\0' if it passed validation */
> +	if (hgc->ctx.datasize <= 1)
> +		return NULL;
> +
> +	/* a list of '\0' terminated strings */
> +	size_t n = 1, i;
> +	for (i = 0; i < hgc->ctx.datasize; ++i)
> +		n += (hgc->ctx.data[i] == '\0');
> +
> +	n *= sizeof(char **);
> +	const char **insts = (const char **)mallocx(n);
> +	memset(insts, 0, n);
> +
> +	int waszero = 1;
> +	n = 0;
> +	for (i = 0; i < hgc->ctx.datasize; ++i) {
> +		if (hgc->ctx.data[i] == '\0') {
> +			waszero = 1;
> +		} else {
> +			if (waszero)
> +				insts[n++] = hgc->ctx.data + i;
> +			waszero = 0;
> +		}
> +	}

It would overflow if the data isn't NULL-terminated.
memchr() might be useful.


More information about the Mercurial-devel mailing list