BitKeeper source management system
ob        1.72        | /*
ob        1.72        |  * Copyright 1997-2013,2015-2016 BitMover, Inc
ob        1.72        |  *
ob        1.72        |  * Licensed under the Apache License, Version 2.0 (the "License");
ob        1.72        |  * you may not use this file except in compliance with the License.
ob        1.72        |  * You may obtain a copy of the License at
ob        1.72        |  *
ob        1.72        |  *     http://www.apache.org/licenses/LICENSE-2.0
ob        1.72        |  *
ob        1.72        |  * Unless required by applicable law or agreed to in writing, software
ob        1.72        |  * distributed under the License is distributed on an "AS IS" BASIS,
ob        1.72        |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ob        1.72        |  * See the License for the specific language governing permissions and
ob        1.72        |  * limitations under the License.
ob        1.72        |  */
ob        1.72        | 
awc       1.23        | /*
awc       1.23        |  * Note: This file is also used by src/win32/pub/diffutils
awc       1.23        |  *       Do not put BitKeeper specific code here
awc       1.23        |  */
lm        1.20        | #include "system.h"
wscott    1.28.2.8    | #include "lines.h"
awc       1.23        | 
wscott    1.59        | #define	setLLEN(s, len)	(*(u32 *)(s) = (*(u32 *)(s) & ~LMASK) | len)
lm        1.14        | 
wscott    1.55        | /* size of array (saves LSIZ-1 items) */
wscott    1.59        | #define	LSIZ(s)				(1u << (*(u32 *)(s) >> LBITS))
wscott    1.59        | 
wscott    1.59        | /*
wscott    1.59        |  * add 'add' more elements to an array, resizing as needed
wscott    1.59        |  * internal version that doesn't clear memory
wscott    1.59        |  */
wscott    1.59        | private void	*
wscott    1.59        | _growArray_int(void *space, int add, int elemsize)
wscott    1.59        | {
wscott    1.59        | 	u32	size, len;	/* len and size of array */
wscott    1.59        | 	int	c;
wscott    1.59        | 
wscott    1.59        | 	if (space) {
wscott    1.63        | 		len = _LLEN(space) + add;
wscott    1.59        | 		c = (*(u32 *)space >> LBITS);
wscott    1.59        | 		size = 1u << c;
wscott    1.59        | 
wscott    1.59        | 		assert(size > 0);	 /* size==0 is read-only array */
wscott    1.59        | 	} else {
wscott    1.59        | 		assert(elemsize >= sizeof(u32));
wscott    1.59        | 		len = add;
wscott    1.59        | 		c = (elemsize > 128) ? 2 : 3; /* min alloc size */
wscott    1.59        | 		size = 1u << c;
wscott    1.59        | 		goto alloc;
wscott    1.59        | 	}
wscott    1.59        | 	if (len >= size) {	/* full up, dude */
wscott    1.59        | alloc:		while (len >= size) {
wscott    1.59        | 			size *= 2;
wscott    1.59        | 			++c;
wscott    1.59        | 		}
wscott    1.61        | 		space = realloc(space, size * elemsize);
wscott    1.61        | 		assert(space);
wscott    1.59        | 	}
wscott    1.59        | 	*(u32 *)space = (c << LBITS) | len;
wscott    1.59        | 	return (space);
wscott    1.59        | }
wscott    1.59        | 
lm        1.2         | /*
wscott    1.59        |  * add 'add' more elements to an array, resizing as needed
wscott    1.59        |  * new elements are set to zero
wscott    1.59        |  * returns: a pointer to the new elements
wscott    1.59        |  */
wscott    1.59        | void	*
wscott    1.59        | _growArray(void **space, int add, int size)
wscott    1.59        | {
wscott    1.59        | 	void	*ret;
wscott    1.59        | 
wscott    1.59        | 	*space = _growArray_int(*space, add, size);
wscott    1.63        | 	ret = *(u8 **)space + (_LLEN(*space)-add+1)*size;
wscott    1.59        | 	memset(ret, 0, add * size);
wscott    1.59        | 	return (ret);
wscott    1.59        | }
wscott    1.59        | 
wscott    1.59        | /*
wscott    1.59        |  * Return a new array of length 0 with space for n lines.
lm        1.20        |  */
lm        1.20        | char	**
wscott    1.59        | allocLines(int	n)
lm        1.20        | {
wscott    1.59        | 	char	**space = _growArray_int(0, n, sizeof(char *));
wscott    1.28.2.3    | 
wscott    1.59        | 	setLLEN(space, 0);
lm        1.20        | 	return (space);
lm        1.20        | }
lm        1.20        | 
lm        1.20        | /*
wscott    1.59        |  * Add a char* to the end of an array, if line==0 then the array is
wscott    1.59        |  * zero terminated, but the length doesn't actually change.
lm        1.2         |  */
lm        1.8         | char	**
lm        1.20        | addLine(char **space, void *line)
lm        1.2         | {
wscott    1.59        | 	int	len;
lm        1.2         | 
wscott    1.59        | 	space = _growArray_int(space, 1, sizeof(char *));
wscott    1.59        | 	len = nLines(space);
wscott    1.59        | 	space[len] = line;
wscott    1.59        | 	unless (line) setLLEN(space, len-1);
wscott    1.59        | 	return (space);
wscott    1.59        | }
wscott    1.55        | 
lm        1.71        | int
lm        1.71        | findLine(char **haystack, char *needle)
lm        1.71        | {
lm        1.71        | 	int	i;
lm        1.71        | 
lm        1.71        | 	EACH(haystack) {
lm        1.71        | 		if (streq(needle, haystack[i])) return (i);
lm        1.71        | 	}
lm        1.71        | 	return (0);
lm        1.71        | }
lm        1.71        | 
wscott    1.59        | /*
wscott    1.59        |  * Adds 1 new element to array and copies 'x' into, if
wscott    1.59        |  * x==0 then the new item is cleared.
wscott    1.59        |  * returns a pointer to the new item.
wscott    1.59        |  */
wscott    1.59        | void   *
wscott    1.59        | _addArray(void **space, void *x, int size)
wscott    1.59        | {
wscott    1.59        | 	void	*ret;
wscott    1.59        | 	int	len;
wscott    1.55        | 
wscott    1.59        | 	*space = _growArray_int(*space, 1, size);
wscott    1.59        | 	len = nLines(*space);
wscott    1.59        | 	ret = (u8 *)(*space) + len * size;
wscott    1.59        | 	if (x) {
wscott    1.59        | 		memcpy(ret, x, size);
lm        1.14        | 	} else {
wscott    1.59        | 		memset(ret, 0, size);
wscott    1.55        | 	}
wscott    1.59        | 	return (ret);
lm        1.2         | }
lm        1.2         | 
wscott    1.55        | /*
wscott    1.59        |  * set the length of a lines array to a new (smaller) value.
wscott    1.55        |  */
wscott    1.55        | void
wscott    1.59        | truncArray(void *space, int len)
wscott    1.24        | {
wscott    1.59        | 	if (space) {
wscott    1.59        | 		/* no growing the array at the moment */
wscott    1.63        | 		assert(len <= _LLEN(space));
wscott    1.59        | 		setLLEN(space, len);
wscott    1.59        | 	} else {
wscott    1.59        | 		assert(len == 0);
wscott    1.59        | 	}
wscott    1.51        | }
wscott    1.51        | 
wscott    1.51        | /*
wscott    1.59        |  * copy array to the end of space and then zero array
wscott    1.51        |  */
wscott    1.59        | void	*
wscott    1.59        | _catArray(void **space, void *array, int size)
wscott    1.51        | {
wscott    1.51        | 	int	n1, n2;
wscott    1.59        | 	void	*ret = 0;
wscott    1.51        | 
wscott    1.59        | 	if (n2 = nLines(array)) {
wscott    1.59        | 		n1 = nLines(*space);
wscott    1.59        | 		*space = _growArray_int(*space, n2, size);
wscott    1.59        | 		ret = (u8 *)*space+(n1+1)*size;
wscott    1.59        | 		memcpy(ret, (u8 *)array+size, n2*size);
wscott    1.59        | 		setLLEN(array, 0);
wscott    1.59        | 	}
wscott    1.59        | 	return (ret);
wscott    1.24        | }
wscott    1.24        | 
lm        1.12        | void
lm        1.20        | reverseLines(char **space)
lm        1.20        | {
lm        1.20        | 	int	i, end;
lm        1.20        | 	char	*tmp;
lm        1.20        | 
wscott    1.24        | 	end = nLines(space);
lm        1.20        | 	i = 1;
lm        1.20        | 	while (i < end) {
lm        1.20        | 		tmp = space[i];
lm        1.20        | 		space[i] = space[end];
lm        1.20        | 		space[end] = tmp;
lm        1.20        | 		++i;
lm        1.20        | 		--end;
lm        1.20        | 	}
lm        1.20        | }
lm        1.20        | 
wscott    1.59        | void
rick      1.64        | _reverseArray(void *space, int size)
rick      1.64        | {
rick      1.64        | 	int	i, end;
rick      1.64        | 	u8	tmp[size], *arr = (u8 *)space;
rick      1.64        | 
rick      1.64        | 	end = nLines(space);
rick      1.64        | 	i = 1;
rick      1.64        | 	while (i < end) {
rick      1.64        | 		memcpy(&tmp, &arr[i * size], size);
rick      1.64        | 		memcpy(&arr[i * size], &arr[end * size], size);
rick      1.64        | 		memcpy(&arr[end * size], &tmp, size);
rick      1.64        | 		++i;
rick      1.64        | 		--end;
rick      1.64        | 	}
rick      1.64        | }
rick      1.64        | 
rick      1.64        | void
wscott    1.59        | _sortArray(void *space, int (*compar)(const void *, const void *), int size)
ob        1.48        | {
wscott    1.59        | 	if (!space) return;
wscott    1.59        | 	unless (compar) compar = string_sort;
wscott    1.59        | 	qsort((u8 *)space+size, nLines(space), size, compar);
ob        1.48        | }
ob        1.48        | 
lm        1.40        | /*
lm        1.40        |  * Looking for a key_sort?  It's in check.c and sorts on the key starting
lm        1.40        |  * at the pathname part.
lm        1.40        |  */
lm        1.40        | 
lm        1.20        | int
lm        1.20        | string_sort(const void *a, const void *b)
lm        1.20        | {
lm        1.20        | 	char	*l, *r;
lm        1.20        | 
lm        1.20        | 	l = *(char**)a;
lm        1.20        | 	r = *(char**)b;
lm        1.20        | 	return (strcmp(l, r));
lm        1.20        | }
lm        1.20        | 
ob        1.69        | int
ob        1.69        | stringcase_sort(const void *a, const void *b)
ob        1.69        | {
ob        1.69        | 	char	*l, *r;
ob        1.69        | 
ob        1.69        | 	l = *(char**)a;
ob        1.69        | 	r = *(char**)b;
ob        1.69        | 	return (strcasecmp(l, r));
ob        1.69        | }
ob        1.69        | 
wscott    1.41        | int
wscott    1.56        | string_sortrev(const void *a, const void *b)
wscott    1.56        | {
wscott    1.56        | 	char	*l, *r;
wscott    1.56        | 
wscott    1.56        | 	l = *(char**)a;
wscott    1.56        | 	r = *(char**)b;
wscott    1.56        | 	return (strcmp(r, l));	/* reverse sort */
wscott    1.56        | }
wscott    1.56        | 
wscott    1.56        | int
wscott    1.41        | number_sort(const void *a, const void *b)
wscott    1.41        | {
wscott    1.41        | 	int	l, r;
wscott    1.41        | 
wscott    1.41        | 	l = atoi(*(char**)a);
wscott    1.41        | 	r = atoi(*(char**)b);
wscott    1.41        | 	if (l - r) return (l - r);
wscott    1.41        | 	return (string_sort(a, b));
wscott    1.41        | }
wscott    1.41        | 
lm        1.20        | void
lm        1.28.1.5    | uniqLines(char **space, void(*freep)(void *ptr))
lm        1.28.1.5    | {
wscott    1.49        | 	int	src, dst;
lm        1.28.1.5    | 
lm        1.28.1.5    | 	unless (space) return;
lm        1.28.1.5    | 	sortLines(space, 0);
wscott    1.49        | 
wscott    1.49        | 	/* skip up to the first dup */
wscott    1.49        | 	EACH_INDEX(space, src) {
wscott    1.49        | 		if ((src > 1) && streq(space[src-1], space[src])) goto dups;
wscott    1.49        | 	}
wscott    1.49        | 	return;			/* fast exit */
wscott    1.49        | 
wscott    1.49        |  dups:	/* now copy non-duped items */
wscott    1.49        | 	dst = src-1;		/* last valid item in output */
wscott    1.63        | 	for (; src <= _LLEN(space); src++) { /* EACH() */
wscott    1.49        | 		if (streq(space[src], space[dst])) {
wscott    1.49        | 			if (freep) freep(space[src]);
wscott    1.49        | 		} else {
wscott    1.49        | 			space[++dst] = space[src];
lm        1.28.1.5    | 		}
lm        1.28.1.5    | 	}
wscott    1.55        | 	truncLines(space, dst);
lm        1.28.1.5    | }
lm        1.28.1.5    | 
lm        1.28.1.5    | /*
lm        1.28.1.5    |  * Return true if they are the same.
lm        1.28.1.5    |  * It's up to you to sort them first if you want them sorted.
lm        1.28.1.5    |  */
lm        1.28.1.5    | int
lm        1.28.1.5    | sameLines(char **p, char **p2)
lm        1.28.1.5    | {
lm        1.28.1.5    | 	int	i;
lm        1.28.1.5    | 
lm        1.28.1.5    | 	unless (p && p2) return (0);
lm        1.28.1.5    | 	unless (nLines(p) == nLines(p2)) return (0);
lm        1.28.1.5    | 	EACH(p) unless (streq(p[i], p2[i])) return (0);
lm        1.28.1.5    | 	return (1);
lm        1.28.1.5    | }
lm        1.28.1.5    | 
lm        1.28.1.5    | void
lm        1.20        | freeLines(char **space, void(*freep)(void *ptr))
lm        1.2         | {
lm        1.2         | 	int	i;
lm        1.2         | 
ob        1.45        | 	if (!space || (space == INVALID)) return;
wscott    1.24        | 	if (freep) {
wscott    1.24        | 		EACH(space) freep(space[i]);
lm        1.2         | 	}
lm        1.2         | 	space[0] = 0;
lm        1.2         | 	free(space);
lm        1.2         | }
lm        1.2         | 
wscott    1.55        | /* same non O(n^2) idiom as uniqLines() */
lm        1.17        | int
lm        1.20        | removeLine(char **space, char *s, void(*freep)(void *ptr))
lm        1.3         | {
wscott    1.55        | 	int	src, dst, n = 0;
lm        1.3         | 
wscott    1.55        | 	/* skip up to the first match */
wscott    1.55        | 	EACH_INDEX(space, src) {
wscott    1.55        | 		if (streq(space[src], s)) goto match;
wscott    1.55        | 	}
wscott    1.55        | 	return (0);			/* fast exit */
wscott    1.55        | 
wscott    1.55        |  match:	/* now copy non-matched items */
wscott    1.55        | 	dst = src-1;		/* last non-matched item in output */
wscott    1.63        | 	for (; src <= _LLEN(space); src++) { /* EACH() */
wscott    1.55        | 		if (streq(space[src], s)) {
wscott    1.55        | 			n++;
wscott    1.55        | 			if (freep) freep(space[src]);
wscott    1.55        | 		} else {
wscott    1.55        | 			space[++dst] = space[src];
lm        1.3         | 		}
wscott    1.55        | 	}
wscott    1.55        | 	truncLines(space, dst);
lm        1.20        | 	return (n);
lm        1.3         | }
lm        1.3         | 
wscott    1.59        | /*
wscott    1.59        |  * set space[j] = line
wscott    1.59        |  * and shift everything down to make room
wscott    1.59        |  * return ptr to new item
wscott    1.59        |  */
lm        1.20        | void	*
wscott    1.59        | _insertArrayN(void **space, int j, void *new, int size)
lm        1.20        | {
wscott    1.59        | 	int	len;
wscott    1.59        | 	void	*ret;
lm        1.20        | 
wscott    1.59        | 	len = nLines(*space) + 1;
wscott    1.59        | 	assert((j > 0) && (j <= len));
wscott    1.59        | 	/* alloc spot and inc line count */
wscott    1.59        | 	*space = _growArray_int(*space, 1, size);
wscott    1.59        | 	ret = (u8 *)*space+j*size;
wscott    1.59        | 	if (j < len) memmove((u8 *)ret+size, ret, (len-j)*size);
wscott    1.59        | 	if (new) {
wscott    1.59        | 		memcpy(ret, new, size);
wscott    1.59        | 	} else {
wscott    1.59        | 		memset(ret, 0, size);
wscott    1.59        | 	}
wscott    1.59        | 	return (ret);
lm        1.28.1.5    | }
lm        1.28.1.5    | 
wscott    1.59        | void
wscott    1.59        | _removeArrayN(void *space, int rm, int size)
wscott    1.46        | {
wscott    1.63        | 	int	len = _LLEN(space);
wscott    1.46        | 
wscott    1.59        | 	assert(rm <= len);
wscott    1.59        | 	assert(rm > 0);
wscott    1.59        | 	if (rm < len) {
wscott    1.59        | 		memmove((u8 *)space+rm*size,
wscott    1.59        | 		    (u8 *)space+(rm+1)*size,
wscott    1.59        | 		    (len - rm)*size);
wscott    1.55        | 	}
wscott    1.59        | 	setLLEN(space, len-1);
wscott    1.46        | }
wscott    1.46        | 
wscott    1.46        | /*
wscott    1.59        |  * A simple wrapper for removeArray() to use for an array of pointers.
wscott    1.59        |  * If freep is passed, then we free the pointer being removed
wscott    1.59        |  * and return zero.  Otherwise we return the pointer removed
wscott    1.59        |  * from the array.
wscott    1.46        |  */
wscott    1.46        | void *
wscott    1.59        | removeLineN(char **space, int rm, void(*freep)(void *ptr))
wscott    1.46        | {
wscott    1.59        | 	char	*ret;
wscott    1.46        | 
wscott    1.59        | 	if (freep) {
wscott    1.59        | 		freep(space[rm]);
wscott    1.59        | 		ret = 0;
wscott    1.59        | 	} else {
wscott    1.59        | 		if ((rm < 1) || (rm > nLines(space))) return (0);
wscott    1.59        | 		ret = space[rm];
wscott    1.59        | 	}
wscott    1.59        | 	_removeArrayN(space, rm, sizeof(void *));
wscott    1.46        | 	return (ret);
wscott    1.46        | }
wscott    1.46        | 
lm        1.47        | /*
lm        1.47        |  * Fill a lines array from output from a program.
lm        1.47        |  * Each line is chomp()ed.
lm        1.47        |  */
lm        1.47        | char	**
lm        1.47        | prog2Lines(char **space, char *cmdline)
lm        1.47        | {
lm        1.47        | 	FILE	*f;
lm        1.47        | 	char	*p;
lm        1.47        | 
lm        1.47        | 	unless (cmdline && (f = popen(cmdline, "r"))) return (space);
lm        1.47        | 	while (p = fgetline(f)) {
lm        1.47        | 		space = addLine(space, strdup(p));
lm        1.47        | 	}
lm        1.47        | 	pclose(f);
lm        1.47        | 	return (space);
lm        1.47        | }
wscott    1.46        | 
wscott    1.46        | /*
lm        1.28.1.5    |  * Fill a lines array from a file.
lm        1.28.1.5    |  * Each line is chomp()ed.
lm        1.28.1.5    |  */
lm        1.28.1.5    | char	**
lm        1.28.1.5    | file2Lines(char **space, char *file)
lm        1.28.1.5    | {
lm        1.28.1.5    | 	FILE	*f;
lm        1.28.1.5    | 	char	*p;
lm        1.28.1.5    | 
lm        1.28.1.5    | 	unless (file && (f = fopen(file, "r"))) return (space);
wscott    1.43        | 	while (p = fgetline(f)) {
wscott    1.43        | 		space = addLine(space, strdup(p));
lm        1.28.1.5    | 	}
lm        1.28.1.5    | 	fclose(f);
lm        1.28.1.5    | 	return (space);
lm        1.28.1.5    | }
lm        1.28.1.5    | 
lm        1.28.1.5    | /*
lm        1.28.1.5    |  * Fill a file from a lines array.
lm        1.28.1.5    |  */
lm        1.28.1.5    | int
lm        1.28.1.5    | lines2File(char **space, char *file)
lm        1.28.1.5    | {
lm        1.28.1.5    | 	FILE	*f;
lm        1.28.1.5    | 	int	i;
wscott    1.66        | 	char	*tmp;
wscott    1.66        | 	int	rc = -1;
lm        1.28.1.5    | 
lm        1.42        | 	unless (file) return (-1);
wscott    1.66        | 	tmp = aprintf("%s.tmp.%u", file, (int)getpid());
wscott    1.66        | 	unless (f = fopen(tmp, "w")) goto out;
wscott    1.66        | 	EACH(space) fprintf(f, "%s\n", space[i]);
wscott    1.66        | 	if (fclose(f) || (rc = rename(tmp, file))) unlink(tmp);
wscott    1.66        | out:	free(tmp);
wscott    1.66        | 	return (rc);
lm        1.20        | }
lm        1.20        | 
lm        1.18        | /*
lm        1.18        |  * Like perl's join(),
lm        1.18        |  * use it for making arbitrary length strings.
lm        1.18        |  */
lm        1.18        | char	*
lm        1.18        | joinLines(char *sep, char **space)
lm        1.18        | {
lm        1.18        | 	int	i, slen, len = 0;
lm        1.18        | 	char	*buf, *p;
lm        1.18        | 
wscott    1.55        | 	if (emptyLines(space)) return (0);
lm        1.18        | 	slen = sep ? strlen(sep) : 0;
lm        1.18        | 	EACH(space) {
lm        1.18        | 		len += strlen(space[i]);
lm        1.18        | 		len += slen;
lm        1.18        | 	}
lm        1.18        | 	len++;
lm        1.18        | 	buf = malloc(len);
lm        1.18        | 	p = buf;
lm        1.18        | 	EACH(space) {
lm        1.18        | 		strcpy(p, space[i]);
lm        1.18        | 		p += strlen(space[i]);
lm        1.18        | 		if (sep) {
lm        1.18        | 			strcpy(p, sep);
lm        1.18        | 			p += slen;
lm        1.18        | 		}
lm        1.18        | 	}
lm        1.18        | 	/*
lm        1.18        | 	 * No trailing sep.
lm        1.18        | 	 */
lm        1.18        | 	if (sep) {
lm        1.18        | 		p -= slen;
lm        1.18        | 		*p = 0;
lm        1.18        | 	}
lm        1.18        | 	return (buf);
lm        1.18        | }
lm        1.18        | 
wscott    1.19        | /*
wscott    1.19        |  * Split a C string into tokens like strtok()
wscott    1.19        |  *
wscott    1.19        |  * The string 'line' is seperated into tokens seperated
wscott    1.19        |  * by one of more characters from 'delim' and each token will
wscott    1.19        |  * be added to the 'tokens' line array.
wscott    1.19        |  * The tokens will be null terminated and will not contain characters
wscott    1.19        |  * from 'delim'
wscott    1.19        |  */
wscott    1.19        | char   **
wscott    1.19        | splitLine(char *line, char *delim, char **tokens)
wscott    1.19        | {
lm        1.28.1.2    | 	int     len;
lm        1.28.1.2    | 
lm        1.28.1.2    | 	while (1) {
lm        1.28.1.2    | 		line += strspn(line, delim); /* skip delimiters */
lm        1.28.1.2    | 		len = strcspn(line, delim);
lm        1.28.1.2    | 		unless (len) break;
lm        1.28.1.2    | 		tokens = addLine(tokens, strndup(line, len));
lm        1.28.1.2    | 		line += len;
lm        1.28.1.2    | 	}
lm        1.28.1.2    | 	return (tokens);
wscott    1.19        | }
wscott    1.19        | 
lm        1.20        | /*
lm+wscott 1.39        |  * Return a malloc'ed string with quotes such that it will be parsed
lm+wscott 1.39        |  * as one argument by the shell.  If a list of strings quoted by this
lm+wscott 1.39        |  * function are joined by spaces and passed to shellSplit() above, the
lm+wscott 1.39        |  * original strings will be returned.
lm+wscott 1.39        |  *
lm+wscott 1.39        |  * All characters in the input string are considered literals.
lm+wscott 1.39        |  */
lm+wscott 1.39        | char *
lm+wscott 1.39        | shellquote(char *in)
lm+wscott 1.39        | {
lm+wscott 1.39        |         int     len = strlen(in);
lm+wscott 1.39        |         int     nlen;
lm+wscott 1.39        |         char    *s, *t;
lm+wscott 1.39        |         char    *out;
lm+wscott 1.39        | 
lm+wscott 1.39        |         /* handle simple case */
lm+wscott 1.39        |         if (strcspn(in, " \t\n\r'\"<>|$&;[]*()\\")==len) return (strdup(in));
lm+wscott 1.39        | 
lm+wscott 1.39        |         nlen = len + 2 + 1;     /* quotes + null */
lm+wscott 1.39        |         for (s = in; *s; s++) {
lm+wscott 1.39        |                 if ((*s == '"') || (*s == '\\')) ++nlen;
lm+wscott 1.39        |         }
lm+wscott 1.39        |         t = out = malloc(nlen);
lm+wscott 1.39        |         *t++ = '"';
lm+wscott 1.39        |         for (s = in; *s; ) {
lm+wscott 1.39        |                 if ((*s == '"') || (*s == '\\')) *t++ = '\\';
lm+wscott 1.39        |                 *t++ = *s++;
lm+wscott 1.39        |         }
lm+wscott 1.39        |         *t++ = '"';
lm+wscott 1.39        |         *t = 0;
lm+wscott 1.39        |         return (out);
lm+wscott 1.39        | }
lm+wscott 1.39        | 
lm+wscott 1.39        | /*
ob        1.38        |  * Takes a string, parses it like /bin/sh, and splits it into
ob        1.38        |  * tokens.  The result is is returned in a lines array.
wscott    1.21        |  *
wscott    1.21        |  * Rules:
wscott    1.21        |  *
ob        1.38        |  *	The string is split on white space boundaries unless the white space
wscott    1.21        |  *	is made literal by one of the following rules.
wscott    1.21        |  *
wscott    1.21        |  *	A backslash (\) is the escape character.  It preservers the
wscott    1.21        |  *	literal value of the next character that follows.
wscott    1.21        |  *
wscott    1.21        |  *      Enclosing characters in single quotes preserves the literal
wscott    1.21        |  *      value of each character within the quotes.  A single quote may
wscott    1.21        |  *      not occur between single quotes, even when preceded by a
wscott    1.21        |  *      backslash.
wscott    1.21        |  *
wscott    1.21        |  *      Enclosing characters in double quotes preserves the literal
wscott    1.21        |  *      value of all characters within the quotes, with the exception
wscott    1.21        |  *      of \.  The backslash retains its special meaning only when
wscott    1.21        |  *      followed by the characters " or \. A double quote (") may be
wscott    1.21        |  *      quoted within double quotes by preceding it with a backslash.
wscott    1.22        |  *
wscott    1.22        |  * As a special flag for spawn_pipeline() every string has a 1
wscott    1.22        |  * character flag after the null at the end.  If it is 1 then that
wscott    1.22        |  * item is a shell meta function (like > or |).  It is 0 otherwise.
wscott    1.22        |  * This is so '>' and \> can be seperated from >.
wscott    1.22        |  * (the marker is not visible unless you know to look for it.)
wscott    1.21        |  */
wscott    1.21        | char **
wscott    1.22        | shellSplit(const char *line)
wscott    1.21        | {
wscott    1.28        | 	const	char	*pin;	/* input pointer */
wscott    1.28        | 	const	char	*ein;	/* pointer to end of block to insert */
wscott    1.21        | 	char	**ret = 0;
wscott    1.21        | 	char	*e;
wscott    1.21        | 	int	item = 0;	/* buf contains data */
wscott    1.21        | 	int	c;
wscott    1.28        | 	int	bufsize = 128;
wscott    1.28        | 	char	*buf = malloc(bufsize);
wscott    1.28        | 	char	*pout;		/* end of 'buf' at insert point */
wscott    1.28        | 
wscott    1.28        | /* make room for 'extra' more characters in buffer */
wscott    1.28        | #define BUF_RESIZE(extra) \
wscott    1.28        | 	while (pout - buf > bufsize - (extra)) { \
wscott    1.28        | 		char	*newbuf = malloc(2 * bufsize); \
wscott    1.28        | 		memcpy(newbuf, buf, pout - buf); \
wscott    1.28        | 		pout = newbuf + (pout - buf); \
wscott    1.28        | 		buf = newbuf; \
wscott    1.28        | 		bufsize *= 2; \
wscott    1.28        | 	}
wscott    1.28        | 
wscott    1.28        | /* If we have an item, save it one the list and reset the buffer */
wscott    1.28        | #define SAVE_ITEM() \
wscott    1.28        | 	if (item) { \
wscott    1.28        | 		*pout++ = 0; /* 2 nulls */ \
wscott    1.28        | 		*pout++ = 0; \
ob        1.28.2.6    | 		ret = addLine(ret, memcpy(malloc(pout-buf), buf, pout-buf)); \
wscott    1.28        | 		pout = buf; \
wscott    1.28        | 		item = 0; \
wscott    1.28        | 	}
wscott    1.21        | 
wscott    1.21        | 	assert(line);
wscott    1.21        | 	pin = line;
wscott    1.21        | 	pout = buf;
wscott    1.21        | 	*pout = 0;
wscott    1.21        | 	while (*pin) {
wscott    1.21        | 		switch (*pin) {
wscott    1.21        | 		    /* whitespace */
wscott    1.21        | 		    case ' ': case '\t': case '\n': case '\r':
wscott    1.21        | 			++pin;
wscott    1.28        | 			SAVE_ITEM();
wscott    1.21        | 			break;
wscott    1.21        | 		    /* single quoted strings */
wscott    1.21        | 		    case '\'':
wscott    1.21        | 			++pin;
wscott    1.28        | 			ein = strchr(pin, '\'');
wscott    1.28        | 			unless (ein) {
wscott    1.21        | 				fprintf(stderr, "unmatched ' in (%s)\n", line);
wscott    1.21        | 				exit(1);
wscott    1.21        | 			}
wscott    1.28        | 			BUF_RESIZE(ein - pin);
wscott    1.28        | 			strncpy(pout, pin, ein - pin);
wscott    1.28        | 			pout += ein - pin;
wscott    1.28        | 			pin = ein+1;
wscott    1.21        | 			item = 1;
wscott    1.21        | 			break;
wscott    1.21        | 		    /* double quoted strings */
wscott    1.21        | 		    case '"':
wscott    1.21        | 			++pin;
wscott    1.21        | 			while (*pin && *pin != '"') {
wscott    1.28        | 				ein = pin + strcspn(pin, "\"\\");
wscott    1.28        | 				BUF_RESIZE(ein - pin + 1);
wscott    1.28        | 				strncpy(pout, pin, ein - pin);
wscott    1.28        | 				pout += ein - pin;
wscott    1.28        | 				pin = ein;
wscott    1.28        | 				if (*pin == '\\') {
wscott    1.28        | 					if (pin[1] == '\\' || pin[1] == '"') {
wscott    1.28        | 						++pin;
wscott    1.28        | 					}
wscott    1.28        | 					*pout++ = *pin++;
wscott    1.21        | 				}
wscott    1.21        | 			}
wscott    1.21        | 			if (*pin != '"') {
wscott    1.21        | 				fprintf(stderr, "unmatched \" in (%s)\n",
wscott    1.21        | 				    line);
wscott    1.21        | 				exit(1);
wscott    1.21        | 			}
wscott    1.21        | 			++pin;
wscott    1.21        | 			item = 1;
wscott    1.21        | 			break;
wscott    1.21        | 		    /* shell characters */
wscott    1.21        | 		    case '>': case '<': case '|':
wscott    1.21        | 			c = 1;
wscott    1.25        | 			if (pin[0] == '|' && pin[1] == '|') goto unhandled;
wscott    1.25        | 			if (pin[0] == '>' && pin[1] == '>') c = 2;
wscott    1.21        | 		sep:
wscott    1.28        | 			SAVE_ITEM();
wscott    1.22        | 			e = malloc(c+2);
wscott    1.22        | 			strncpy(e, pin, c);
wscott    1.22        | 			e[c] = 0;
wscott    1.22        | 			e[c+1] = 1;	/* 1 after null */
wscott    1.22        | 			ret = addLine(ret, e);
wscott    1.21        | 			pin += c;
wscott    1.21        | 			break;
wscott    1.22        | 		    /* unhandled functions */
wscott    1.22        | 		    case '`': case '$': case '&': case ';':
wscott    1.22        | 		    case '[': case ']': case '*': case '(': case ')':
wscott    1.22        | 		unhandled:
wscott    1.22        | 			fprintf(stderr,
wscott    1.26        | 			    "command line (%s) contains unhandled shell expressions.\n",
wscott    1.22        | 			    line);
wscott    1.22        | 			exit(1);
wscott    1.21        | 		    /* escape character */
wscott    1.21        | 		    case '\\':
wscott    1.21        | 			++pin;
wscott    1.21        | 			unless (*pin) break;
wscott    1.21        | 			/* falltrough */
wscott    1.21        | 		    default:
wscott    1.21        | 			if (isdigit(*pin) &&
wscott    1.21        | 			    (pin[1] == '<' || pin[1] == '>')) {
wscott    1.21        | 				if (pin[2] == '&' && isdigit(pin[3])) {
wscott    1.21        | 					c = 4;
wscott    1.21        | 				} else {
wscott    1.21        | 					c = 2;
wscott    1.21        | 				}
wscott    1.21        | 				goto sep;
wscott    1.21        | 			} else {
wscott    1.21        | 				*pout++ = *pin++;
wscott    1.21        | 				item = 1;
wscott    1.21        | 			}
wscott    1.21        | 			break;
wscott    1.21        | 		}
wscott    1.28        | 		BUF_RESIZE(2);
wscott    1.21        | 	}
wscott    1.28        | 	SAVE_ITEM();
wscott    1.28        | 	free(buf);
wscott    1.21        | 	return (ret);
lm        1.28.1.2    | }
lm        1.28.1.2    | 
wscott    1.65        | /*
wscott    1.65        |  * Return an array allocated by different means.
wscott    1.65        |  * While it has no data, it will look like it does (nLines == len).
wscott    1.65        |  * The caller is expected to fill before using as an array.
wscott    1.65        |  */
wscott    1.65        | void *
wscott    1.65        | allocArray(int len, int esize, void *(*allocate)(size_t size))
wscott    1.65        | {
wscott    1.65        | 	int	c;		/* log2 max num elements */
wscott    1.65        | 	size_t	size;
wscott    1.65        | 	void	*ret;
wscott    1.65        | 
wscott    1.65        | 	assert(esize >= sizeof(u32));
wscott    1.65        | 	unless (allocate) allocate = malloc;
wscott    1.65        | 	c = 4;
wscott    1.65        | 	size = 1u << c;
wscott    1.65        | 	while (len >= size) {
wscott    1.65        | 		size *= 2;
wscott    1.65        | 		++c;
wscott    1.65        | 	}
wscott    1.65        | 	size *= esize;
wscott    1.65        | 	ret = allocate(size);
wscott    1.65        | 	*(u32 *)ret = (c << LBITS) | len;
wscott    1.65        | 	return (ret);
wscott    1.65        | }
wscott    1.67        | 
wscott    1.67        | /*
wscott    1.67        |  * Given two arrays in sorted order, walk the arrays in parallel and
wscott    1.67        |  * call the supplied 'walk' call back on each it item found in either
wscott    1.67        |  * array.  The walk callback is called with a pointer to the data in
wscott    1.67        |  * each array, if an item appear only in on array then the point for
wscott    1.67        |  * the other array will be 0.
wscott    1.67        |  *
wscott    1.67        |  * example:
wscott    1.67        |  *   a = { "a", "b", "c" }
wscott    1.67        |  *   b = { "b", "d" };
wscott    1.67        |  *  will make the following callbacks:
wscott    1.67        |  *   walk(t, "a", 0);
wscott    1.67        |  *   walk(t, "b", "b");
wscott    1.67        |  *   walk(t, "c", 0);
wscott    1.67        |  *   walk(t, "0, "d");
wscott    1.67        |  *
wscott    1.67        |  * 'compar' is the comparison function is set to string_sort if null
wscott    1.67        |  * If walk() returns a positive number then that number is accumulated
wscott    1.67        |  * and returned from parallelLines().  If the return from walk() is
wscott    1.67        |  * negative the tranversal is aborted and that number is returned
wscott    1.67        |  * immediately.
wscott    1.67        |  */
wscott    1.67        | int
wscott    1.67        | parallelLines(char **a, char **b,
wscott    1.67        |     int (*compar)(const void *, const void *),
wscott    1.67        |     int (*walk)(void *token, char *a, char *b),
wscott    1.67        |     void *token)
wscott    1.67        | {
wscott    1.67        | 	int	i, j;
wscott    1.67        | 	int	cmp, r;
wscott    1.67        | 	int	sum = 0;
wscott    1.67        | 	int	na, nb;
wscott    1.67        | 	char	*aa, *bb;
wscott    1.67        | 
wscott    1.67        | 	unless (compar) compar = string_sort;
wscott    1.67        | 	na = nLines(a);
wscott    1.67        | 	nb = nLines(b);
wscott    1.67        | 
wscott    1.67        | 	i = j = 1;
wscott    1.67        | 	while ((i <= na) || (j <= nb)) {
wscott    1.67        | 		if (i > na) {
wscott    1.67        | 			cmp = 1;
wscott    1.67        | 		} else if (j > nb) {
wscott    1.67        | 			cmp = -1;
wscott    1.67        | 		} else {
wscott    1.67        | 			cmp = compar(a+i, b+j);
wscott    1.67        | 		}
wscott    1.67        | 		if (cmp < 0) {
wscott    1.67        | 			aa = a[i++];
wscott    1.67        | 			bb = 0;
wscott    1.67        | 		} else if (cmp > 0) {
wscott    1.67        | 			aa = 0;
wscott    1.67        | 			bb = b[j++];
wscott    1.67        | 		} else {
wscott    1.67        | 			aa = a[i++];
wscott    1.67        | 			bb = b[j++];
wscott    1.67        | 		}
wscott    1.67        | 		if ((r = walk(token, aa, bb)) < 0) return (r);
wscott    1.67        | 		sum += r;
wscott    1.67        | 	}
wscott    1.67        | 	return (sum);
wscott    1.67        | }