xref: /netbsd-src/usr.bin/sort/fields.c (revision 85744c86adb3d2ebe74bf12a4d4571c61bbdef52)
1*85744c86Sapb /*	$NetBSD: fields.c,v 1.33 2013/01/20 10:12:58 apb Exp $	*/
2f84513a7Sjdolecek 
3f84513a7Sjdolecek /*-
4f84513a7Sjdolecek  * Copyright (c) 2000-2003 The NetBSD Foundation, Inc.
5f84513a7Sjdolecek  * All rights reserved.
6f84513a7Sjdolecek  *
7f84513a7Sjdolecek  * This code is derived from software contributed to The NetBSD Foundation
8f84513a7Sjdolecek  * by Ben Harris and Jaromir Dolecek.
9f84513a7Sjdolecek  *
10f84513a7Sjdolecek  * Redistribution and use in source and binary forms, with or without
11f84513a7Sjdolecek  * modification, are permitted provided that the following conditions
12f84513a7Sjdolecek  * are met:
13f84513a7Sjdolecek  * 1. Redistributions of source code must retain the above copyright
14f84513a7Sjdolecek  *    notice, this list of conditions and the following disclaimer.
15f84513a7Sjdolecek  * 2. Redistributions in binary form must reproduce the above copyright
16f84513a7Sjdolecek  *    notice, this list of conditions and the following disclaimer in the
17f84513a7Sjdolecek  *    documentation and/or other materials provided with the distribution.
18f84513a7Sjdolecek  *
19f84513a7Sjdolecek  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20f84513a7Sjdolecek  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21f84513a7Sjdolecek  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22f84513a7Sjdolecek  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23f84513a7Sjdolecek  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24f84513a7Sjdolecek  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25f84513a7Sjdolecek  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26f84513a7Sjdolecek  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27f84513a7Sjdolecek  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28f84513a7Sjdolecek  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29f84513a7Sjdolecek  * POSSIBILITY OF SUCH DAMAGE.
30f84513a7Sjdolecek  */
316029888aSbjh21 
321d5d9b5bSbjh21 /*-
331d5d9b5bSbjh21  * Copyright (c) 1993
341d5d9b5bSbjh21  *	The Regents of the University of California.  All rights reserved.
351d5d9b5bSbjh21  *
361d5d9b5bSbjh21  * This code is derived from software contributed to Berkeley by
371d5d9b5bSbjh21  * Peter McIlroy.
381d5d9b5bSbjh21  *
391d5d9b5bSbjh21  * Redistribution and use in source and binary forms, with or without
401d5d9b5bSbjh21  * modification, are permitted provided that the following conditions
411d5d9b5bSbjh21  * are met:
421d5d9b5bSbjh21  * 1. Redistributions of source code must retain the above copyright
431d5d9b5bSbjh21  *    notice, this list of conditions and the following disclaimer.
441d5d9b5bSbjh21  * 2. Redistributions in binary form must reproduce the above copyright
451d5d9b5bSbjh21  *    notice, this list of conditions and the following disclaimer in the
461d5d9b5bSbjh21  *    documentation and/or other materials provided with the distribution.
4789aaa1bbSagc  * 3. Neither the name of the University nor the names of its contributors
481d5d9b5bSbjh21  *    may be used to endorse or promote products derived from this software
491d5d9b5bSbjh21  *    without specific prior written permission.
501d5d9b5bSbjh21  *
511d5d9b5bSbjh21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
521d5d9b5bSbjh21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
531d5d9b5bSbjh21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
541d5d9b5bSbjh21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
551d5d9b5bSbjh21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
561d5d9b5bSbjh21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
571d5d9b5bSbjh21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
581d5d9b5bSbjh21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
591d5d9b5bSbjh21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
601d5d9b5bSbjh21  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
611d5d9b5bSbjh21  * SUCH DAMAGE.
621d5d9b5bSbjh21  */
631d5d9b5bSbjh21 
641d5d9b5bSbjh21 /* Subroutines to generate sort keys. */
651d5d9b5bSbjh21 
661d5d9b5bSbjh21 #include "sort.h"
671d5d9b5bSbjh21 
68*85744c86Sapb __RCSID("$NetBSD: fields.c,v 1.33 2013/01/20 10:12:58 apb Exp $");
696029888aSbjh21 
70f0f862a9Sjdolecek #define SKIP_BLANKS(ptr) {					\
711d5d9b5bSbjh21 	if (BLANK & d_mask[*(ptr)])				\
721d5d9b5bSbjh21 		while (BLANK & d_mask[*(++(ptr))]);		\
731d5d9b5bSbjh21 }
741d5d9b5bSbjh21 
751d5d9b5bSbjh21 #define NEXTCOL(pos) {						\
761d5d9b5bSbjh21 	if (!SEP_FLAG)						\
771d5d9b5bSbjh21 		while (BLANK & l_d_mask[*(++pos)]);		\
782a3d05aaSheas 	while ((*(pos+1) != '\0') && !((FLD_D | REC_D_F) & l_d_mask[*++pos]));\
791d5d9b5bSbjh21 }
801d5d9b5bSbjh21 
8199877450Sdsl static u_char *enterfield(u_char *, const u_char *, struct field *, int);
8299877450Sdsl static u_char *number(u_char *, const u_char *, u_char *, u_char *, int);
837e6e5c1fSchristos static u_char *length(u_char *, const u_char *, u_char *, u_char *, int);
841d5d9b5bSbjh21 
857b4a02beSdsl #define DECIMAL_POINT '.'
861d5d9b5bSbjh21 
871d5d9b5bSbjh21 /*
881d5d9b5bSbjh21  * constructs sort key with leading recheader, followed by the key,
891d5d9b5bSbjh21  * followed by the original line.
901d5d9b5bSbjh21  */
911d5d9b5bSbjh21 length_t
enterkey(RECHEADER * keybuf,const u_char * keybuf_end,u_char * line_data,size_t line_size,struct field fieldtable[])92bf80c848Sdsl enterkey(RECHEADER *keybuf, const u_char *keybuf_end, u_char *line_data,
93bf80c848Sdsl     size_t line_size, struct field fieldtable[])
942a0ab276Sdsl 	/* keybuf:	 pointer to start of key */
951d5d9b5bSbjh21 {
961d5d9b5bSbjh21 	int i;
97681fb9cbSjdolecek 	u_char *l_d_mask;
98681fb9cbSjdolecek 	u_char *lineend, *pos;
9999877450Sdsl 	const u_char *endkey;
10099877450Sdsl 	u_char *keypos;
101681fb9cbSjdolecek 	struct coldesc *clpos;
102681fb9cbSjdolecek 	int col = 1;
1031d5d9b5bSbjh21 	struct field *ftpos;
10499877450Sdsl 
1051d5d9b5bSbjh21 	l_d_mask = d_mask;
10699877450Sdsl 	pos = line_data - 1;
10799877450Sdsl 	lineend = line_data + line_size-1;
1081d5d9b5bSbjh21 				/* don't include rec_delimiter */
1091d5d9b5bSbjh21 
1107c5e77a4Sjdolecek 	for (i = 0; i < ncols; i++) {
111f4074c5bSjdolecek 		clpos = clist + i;
112affba8f2Sjdolecek 		for (; (col < clpos->num) && (pos < lineend); col++) {
113affba8f2Sjdolecek 			NEXTCOL(pos);
114affba8f2Sjdolecek 		}
1151d5d9b5bSbjh21 		if (pos >= lineend)
1161d5d9b5bSbjh21 			break;
1171d5d9b5bSbjh21 		clpos->start = SEP_FLAG ? pos + 1 : pos;
1181d5d9b5bSbjh21 		NEXTCOL(pos);
1191d5d9b5bSbjh21 		clpos->end = pos;
1201d5d9b5bSbjh21 		col++;
1211d5d9b5bSbjh21 		if (pos >= lineend) {
1221d5d9b5bSbjh21 			clpos->end = lineend;
123affba8f2Sjdolecek 			i++;
1241d5d9b5bSbjh21 			break;
1251d5d9b5bSbjh21 		}
1261d5d9b5bSbjh21 	}
1271d5d9b5bSbjh21 	for (; i <= ncols; i++)
1281d5d9b5bSbjh21 		clist[i].start = clist[i].end = lineend;
12999877450Sdsl 	if (clist[0].start < line_data)
130affba8f2Sjdolecek 		clist[0].start++;
131c499b189Sjdolecek 
13259ede5aeSdsl 	/*
13359ede5aeSdsl 	 * We write the sort keys (concatenated) followed by the
13459ede5aeSdsl 	 * original line data (for output) as the 'keybuf' data.
13559ede5aeSdsl 	 * keybuf->length is the number of key bytes + data bytes.
13659ede5aeSdsl 	 * keybuf->offset is the number of key bytes.
1377b4a02beSdsl 	 * We add a record separator weight after the key in case
13859ede5aeSdsl 	 * (as is usual) we need to preserve the order of equal lines,
13959ede5aeSdsl 	 * and for 'sort -u'.
1407b4a02beSdsl 	 * The key itself will have had the correct weight applied.
14159ede5aeSdsl 	 */
142c499b189Sjdolecek 	keypos = keybuf->data;
14359ede5aeSdsl 	endkey = keybuf_end - line_size - 1;
14459ede5aeSdsl 	if (endkey <= keypos)
14559ede5aeSdsl 		/* No room for any key bytes */
14659ede5aeSdsl 		return 1;
14759ede5aeSdsl 
14859ede5aeSdsl 	for (ftpos = fieldtable + 1; ftpos->icol.num; ftpos++) {
1491d5d9b5bSbjh21 		if ((keypos = enterfield(keypos, endkey, ftpos,
1501d5d9b5bSbjh21 		    fieldtable->flags)) == NULL)
1511d5d9b5bSbjh21 			return (1);
15259ede5aeSdsl 	}
1531d5d9b5bSbjh21 
1541d5d9b5bSbjh21 	keybuf->offset = keypos - keybuf->data;
15599877450Sdsl 	keybuf->length = keybuf->offset + line_size;
1567c2fb292Sjdolecek 
1571310aa04Sdsl 	/*
1581310aa04Sdsl 	 * Posix requires that equal keys be further sorted by the
1591310aa04Sdsl 	 * entire original record.
1601310aa04Sdsl 	 * NetBSD has (at least for some time) kept equal keys in
1611310aa04Sdsl 	 * their original order.
1621310aa04Sdsl 	 * For 'sort -u' posix_sort is unset.
1631310aa04Sdsl 	 */
1641310aa04Sdsl 	keybuf->keylen = posix_sort ? keybuf->length : keybuf->offset;
1651310aa04Sdsl 
16659ede5aeSdsl 	memcpy(keypos, line_data, line_size);
1671d5d9b5bSbjh21 	return (0);
1681d5d9b5bSbjh21 }
1691d5d9b5bSbjh21 
1701d5d9b5bSbjh21 /*
1711d5d9b5bSbjh21  * constructs a field (as defined by -k) within a key
1721d5d9b5bSbjh21  */
1737c2fb292Sjdolecek static u_char *
enterfield(u_char * tablepos,const u_char * endkey,struct field * cur_fld,int gflags)174bf80c848Sdsl enterfield(u_char *tablepos, const u_char *endkey, struct field *cur_fld,
175bf80c848Sdsl     int gflags)
1761d5d9b5bSbjh21 {
177681fb9cbSjdolecek 	u_char *start, *end, *lineend, *mask, *lweight;
1781d5d9b5bSbjh21 	struct column icol, tcol;
179681fb9cbSjdolecek 	u_int flags;
180affba8f2Sjdolecek 
1811d5d9b5bSbjh21 	icol = cur_fld->icol;
1821d5d9b5bSbjh21 	tcol = cur_fld->tcol;
1831d5d9b5bSbjh21 	flags = cur_fld->flags;
1841d5d9b5bSbjh21 	start = icol.p->start;
1851d5d9b5bSbjh21 	lineend = clist[ncols].end;
1861d5d9b5bSbjh21 	if (flags & BI)
187f0f862a9Sjdolecek 		SKIP_BLANKS(start);
1881d5d9b5bSbjh21 	start += icol.indent;
1891d5d9b5bSbjh21 	start = min(start, lineend);
190affba8f2Sjdolecek 
1911d5d9b5bSbjh21 	if (!tcol.num)
1921d5d9b5bSbjh21 		end = lineend;
1931d5d9b5bSbjh21 	else {
1941d5d9b5bSbjh21 		if (tcol.indent) {
1951d5d9b5bSbjh21 			end = tcol.p->start;
1967c2fb292Sjdolecek 			if (flags & BT)
197f0f862a9Sjdolecek 				SKIP_BLANKS(end);
1981d5d9b5bSbjh21 			end += tcol.indent;
1991d5d9b5bSbjh21 			end = min(end, lineend);
2001d5d9b5bSbjh21 		} else
2011d5d9b5bSbjh21 			end = tcol.p->end;
2021d5d9b5bSbjh21 	}
2037c2fb292Sjdolecek 
2047e6e5c1fSchristos 	if (flags & L)
2057e6e5c1fSchristos 		return length(tablepos, endkey, start, end, flags);
2067b4a02beSdsl 	if (flags & N)
2077b4a02beSdsl 		return number(tablepos, endkey, start, end, flags);
2087b4a02beSdsl 
2097b4a02beSdsl 	/* Bound check space - assuming nothing is skipped */
2107b4a02beSdsl 	if (tablepos + (end - start) + 1 >= endkey)
2117b4a02beSdsl 		return NULL;
2127c2fb292Sjdolecek 
2131d5d9b5bSbjh21 	mask = cur_fld->mask;
2141d5d9b5bSbjh21 	lweight = cur_fld->weights;
2157b4a02beSdsl 	for (; start < end; start++) {
216f58fe5e6Sdsl 		if (!mask || mask[*start]) {
21721928fddSjdolecek 			*tablepos++ = lweight[*start];
2181d5d9b5bSbjh21 		}
2191d5d9b5bSbjh21 	}
2201310aa04Sdsl 	/* Add extra byte (absent from lweight) to sort short keys correctly */
2211310aa04Sdsl 	*tablepos++ = lweight[REC_D];
2227b4a02beSdsl 	return tablepos;
2231d5d9b5bSbjh21 }
2241d5d9b5bSbjh21 
2257b4a02beSdsl /*
2267b4a02beSdsl  * Numbers are converted to a floating point format (exponent & mantissa)
2277b4a02beSdsl  * so that they compare correctly as sequence of unsigned bytes.
2281310aa04Sdsl  * Bytes 0x00 and 0xff are used to terminate positive and negative numbers
2297b4a02beSdsl  * to ensure that 0.123 sorts after 0.12 and -0.123 sorts before -0.12.
2307b4a02beSdsl  *
2317b4a02beSdsl  * The first byte contain the overall sign, exponent sign and some of the
2327b4a02beSdsl  * exponent. These have to be ordered (-ve value, decreasing exponent),
2337b4a02beSdsl  * zero, (+ve value, increasing exponent).
2347b4a02beSdsl  *
235fe526723Sdsl  * The first byte is 0x80 for zero, 0xc0 for +ve with exponent 0.
236fe526723Sdsl  * -ve values are the 1's compliments (so 0x7f isn't used!).
237fe526723Sdsl  *
238fe526723Sdsl  * This only leaves 63 byte values for +ve exponents - which isn't enough.
2395aa782f5Sdsl  * The largest 4 exponent values are used to hold a byte count of the
2405aa782f5Sdsl  * number of following bytes that contain 8 exponent bits per byte,
241fe526723Sdsl  * This lets us sort exponents from -2^31 to +2^31.
2427b4a02beSdsl  *
2437b4a02beSdsl  * The mantissa is stored 2 digits per byte offset by 0x40, for negative
244fe526723Sdsl  * numbers the order must be reversed (they are bit inverted).
2457b4a02beSdsl  *
2467b4a02beSdsl  * Reverse sorts are done by inverting the sign of the number.
2471d5d9b5bSbjh21  */
2485aa782f5Sdsl #define MAX_EXP_ENC  ((int)sizeof(int))
2497b4a02beSdsl 
2507c2fb292Sjdolecek static u_char *
number(u_char * pos,const u_char * bufend,u_char * line,u_char * lineend,int reverse)2517b4a02beSdsl number(u_char *pos, const u_char *bufend, u_char *line, u_char *lineend,
2527b4a02beSdsl     int reverse)
2531d5d9b5bSbjh21 {
2547b4a02beSdsl 	int exponent = -1;
2557b4a02beSdsl 	int had_dp = 0;
2567b4a02beSdsl 	u_char *tline;
2577b4a02beSdsl 	char ch;
2587b4a02beSdsl 	unsigned int val;
2597b4a02beSdsl 	u_char *last_nz_pos;
260fe526723Sdsl 	u_char negate;
2611d5d9b5bSbjh21 
262fe526723Sdsl 	if (reverse & R)
263fe526723Sdsl 		negate = 0xff;
264fe526723Sdsl 	else
265fe526723Sdsl 		negate = 0;
2667b4a02beSdsl 
2677b4a02beSdsl 	/* Give ourselves space for the key terminator */
2687b4a02beSdsl 	bufend--;
2697b4a02beSdsl 
2707b4a02beSdsl 	/* Ensure we have enough space for the exponent */
2717b4a02beSdsl 	if (pos + 1 + MAX_EXP_ENC > bufend)
2721d5d9b5bSbjh21 		return (NULL);
2737b4a02beSdsl 
274f0f862a9Sjdolecek 	SKIP_BLANKS(line);
2751d5d9b5bSbjh21 	if (*line == '-') {	/* set the sign */
276fe526723Sdsl 		negate ^= 0xff;
2771d5d9b5bSbjh21 		line++;
278*85744c86Sapb 	} else if (*line == '+') {
279*85744c86Sapb 		line++;
2801d5d9b5bSbjh21 	}
281*85744c86Sapb 
2821d5d9b5bSbjh21 	/* eat initial zeroes */
283affba8f2Sjdolecek 	for (; *line == '0' && line < lineend; line++)
2847b4a02beSdsl 		continue;
2857b4a02beSdsl 
2867b4a02beSdsl 	/* calculate exponents */
2877b4a02beSdsl 	if (*line == DECIMAL_POINT) {
2887b4a02beSdsl 		/* Decimal fraction */
2897b4a02beSdsl 		had_dp = 1;
2901d5d9b5bSbjh21 		while (*++line == '0' && line < lineend)
2917b4a02beSdsl 			exponent--;
2927b4a02beSdsl 	} else {
2937b4a02beSdsl 		/* Large (absolute) value, count digits */
2947b4a02beSdsl 		for (tline = line; *tline >= '0' &&
2957b4a02beSdsl 		    *tline <= '9' && tline < lineend; tline++)
2961d5d9b5bSbjh21 			exponent++;
2971d5d9b5bSbjh21 	}
2981d5d9b5bSbjh21 
2997b4a02beSdsl 	/* If the first/next character isn't a digit, value is zero */
3007b4a02beSdsl 	if (*line < '1' || *line > '9' || line >= lineend) {
3017b4a02beSdsl 		/* This may be "0", "0.00", "000" or "fubar" but sorts as 0 */
3027b4a02beSdsl 		/* XXX what about NaN, NAN, inf and INF */
3037b4a02beSdsl 		*pos++ = 0x80;
3047b4a02beSdsl 		return pos;
3051d5d9b5bSbjh21 	}
3067b4a02beSdsl 
3077b4a02beSdsl 	/* Maybe here we should allow for e+12 (etc) */
3087b4a02beSdsl 
309fe526723Sdsl 	if (exponent < 0x40 - MAX_EXP_ENC && -exponent < 0x40 - MAX_EXP_ENC) {
3101310aa04Sdsl 		/* Value ok for simple encoding */
3117b4a02beSdsl 		/* exponent 0 is 0xc0 for +ve numbers and 0x40 for -ve ones */
3127b4a02beSdsl 		exponent += 0xc0;
313fe526723Sdsl 		*pos++ = negate ^ exponent;
3147b4a02beSdsl 	} else {
3157b4a02beSdsl 		/* Out or range for a single byte */
3167b4a02beSdsl 		int c, t;
3177b4a02beSdsl 		t = exponent > 0 ? exponent : -exponent;
3185aa782f5Sdsl 		/* Count how many 8-bit bytes are needed */
3197b4a02beSdsl 		for (c = 0; ; c++) {
3205aa782f5Sdsl 			t >>= 8;
3217b4a02beSdsl 			if (t == 0)
3227b4a02beSdsl 				break;
3231d5d9b5bSbjh21 		}
3245aa782f5Sdsl 		/* 'c' better be 0..3 here - but probably 0..1 */
3257b4a02beSdsl 		/* Offset just outside valid range */
3265aa782f5Sdsl 		t = c + 0x40 - MAX_EXP_ENC;
3277b4a02beSdsl 		if (exponent < 0)
3287b4a02beSdsl 			t = -t;
3295aa782f5Sdsl 		*pos++ = negate ^ (t + 0xc0);
3305aa782f5Sdsl 		/* now add each byte, most significant first */
3315aa782f5Sdsl 		for (; c >= 0; c--)
3325aa782f5Sdsl 			*pos++ = negate ^ (exponent >> (c * 8));
3331d5d9b5bSbjh21 	}
3347b4a02beSdsl 
3355aa782f5Sdsl 	/* Finally add mantissa, 2 digits per byte */
3367b4a02beSdsl 	for (last_nz_pos = pos; line < lineend; ) {
3377b4a02beSdsl 		if (pos >= bufend)
3387b4a02beSdsl 			return NULL;
339b36440a0Sdsl 		ch = *line++;
3407b4a02beSdsl 		val = (ch - '0') * 10;
3417b4a02beSdsl 		if (val > 90) {
3427b4a02beSdsl 			if (ch == DECIMAL_POINT && !had_dp) {
3437b4a02beSdsl 				had_dp = 1;
3447b4a02beSdsl 				continue;
3457b4a02beSdsl 			}
3467b4a02beSdsl 			break;
3477b4a02beSdsl 		}
3487b4a02beSdsl 		while (line < lineend) {
3497b4a02beSdsl 			ch = *line++;
3507b4a02beSdsl 			if (ch == DECIMAL_POINT && !had_dp) {
3517b4a02beSdsl 				had_dp = 1;
3527b4a02beSdsl 				continue;
3537b4a02beSdsl 			}
3547b4a02beSdsl 			if (ch < '0' || ch > '9')
3557b4a02beSdsl 				line = lineend;
3567b4a02beSdsl 			else
3577b4a02beSdsl 				val += ch - '0';
3587b4a02beSdsl 			break;
3597b4a02beSdsl 		}
360fe526723Sdsl 		*pos++ = negate ^ (val + 0x40);
3617b4a02beSdsl 		if (val != 0)
3627b4a02beSdsl 			last_nz_pos = pos;
3637b4a02beSdsl 	}
3647b4a02beSdsl 
3657b4a02beSdsl 	/* Add key terminator, deleting any trailing "00" */
366fe526723Sdsl 	*last_nz_pos++ = negate;
3677b4a02beSdsl 
3687b4a02beSdsl 	return (last_nz_pos);
3697b4a02beSdsl }
3707e6e5c1fSchristos 
3717e6e5c1fSchristos static u_char *
length(u_char * pos,const u_char * bufend,u_char * line,u_char * lineend,int flag)3727e6e5c1fSchristos length(u_char *pos, const u_char *bufend, u_char *line, u_char *lineend,
3737e6e5c1fSchristos     int flag)
3747e6e5c1fSchristos {
3757e6e5c1fSchristos 	u_char buf[32];
3767e6e5c1fSchristos 	int l;
3777e6e5c1fSchristos 	SKIP_BLANKS(line);
3787e6e5c1fSchristos 	l = snprintf((char *)buf, sizeof(buf), "%td", lineend - line);
3797e6e5c1fSchristos 	return number(pos, bufend, buf, buf + l, flag);
3807e6e5c1fSchristos }
381