xref: /minix3/usr.bin/sort/fields.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: fields.c,v 1.33 2013/01/20 10:12:58 apb Exp $	*/
20fbbaa43SLionel Sambuc 
30fbbaa43SLionel Sambuc /*-
40fbbaa43SLionel Sambuc  * Copyright (c) 2000-2003 The NetBSD Foundation, Inc.
50fbbaa43SLionel Sambuc  * All rights reserved.
60fbbaa43SLionel Sambuc  *
70fbbaa43SLionel Sambuc  * This code is derived from software contributed to The NetBSD Foundation
80fbbaa43SLionel Sambuc  * by Ben Harris and Jaromir Dolecek.
90fbbaa43SLionel Sambuc  *
100fbbaa43SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
110fbbaa43SLionel Sambuc  * modification, are permitted provided that the following conditions
120fbbaa43SLionel Sambuc  * are met:
130fbbaa43SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
140fbbaa43SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
150fbbaa43SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
160fbbaa43SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
170fbbaa43SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
180fbbaa43SLionel Sambuc  *
190fbbaa43SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
200fbbaa43SLionel Sambuc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
210fbbaa43SLionel Sambuc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
220fbbaa43SLionel Sambuc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
230fbbaa43SLionel Sambuc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
240fbbaa43SLionel Sambuc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
250fbbaa43SLionel Sambuc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
260fbbaa43SLionel Sambuc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
270fbbaa43SLionel Sambuc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
280fbbaa43SLionel Sambuc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
290fbbaa43SLionel Sambuc  * POSSIBILITY OF SUCH DAMAGE.
300fbbaa43SLionel Sambuc  */
310fbbaa43SLionel Sambuc 
320fbbaa43SLionel Sambuc /*-
330fbbaa43SLionel Sambuc  * Copyright (c) 1993
340fbbaa43SLionel Sambuc  *	The Regents of the University of California.  All rights reserved.
350fbbaa43SLionel Sambuc  *
360fbbaa43SLionel Sambuc  * This code is derived from software contributed to Berkeley by
370fbbaa43SLionel Sambuc  * Peter McIlroy.
380fbbaa43SLionel Sambuc  *
390fbbaa43SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
400fbbaa43SLionel Sambuc  * modification, are permitted provided that the following conditions
410fbbaa43SLionel Sambuc  * are met:
420fbbaa43SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
430fbbaa43SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
440fbbaa43SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
450fbbaa43SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
460fbbaa43SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
470fbbaa43SLionel Sambuc  * 3. Neither the name of the University nor the names of its contributors
480fbbaa43SLionel Sambuc  *    may be used to endorse or promote products derived from this software
490fbbaa43SLionel Sambuc  *    without specific prior written permission.
500fbbaa43SLionel Sambuc  *
510fbbaa43SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
520fbbaa43SLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
530fbbaa43SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
540fbbaa43SLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
550fbbaa43SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
560fbbaa43SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
570fbbaa43SLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
580fbbaa43SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
590fbbaa43SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
600fbbaa43SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
610fbbaa43SLionel Sambuc  * SUCH DAMAGE.
620fbbaa43SLionel Sambuc  */
630fbbaa43SLionel Sambuc 
640fbbaa43SLionel Sambuc /* Subroutines to generate sort keys. */
650fbbaa43SLionel Sambuc 
660fbbaa43SLionel Sambuc #include "sort.h"
670fbbaa43SLionel Sambuc 
68*84d9c625SLionel Sambuc __RCSID("$NetBSD: fields.c,v 1.33 2013/01/20 10:12:58 apb Exp $");
690fbbaa43SLionel Sambuc 
700fbbaa43SLionel Sambuc #define SKIP_BLANKS(ptr) {					\
710fbbaa43SLionel Sambuc 	if (BLANK & d_mask[*(ptr)])				\
720fbbaa43SLionel Sambuc 		while (BLANK & d_mask[*(++(ptr))]);		\
730fbbaa43SLionel Sambuc }
740fbbaa43SLionel Sambuc 
750fbbaa43SLionel Sambuc #define NEXTCOL(pos) {						\
760fbbaa43SLionel Sambuc 	if (!SEP_FLAG)						\
770fbbaa43SLionel Sambuc 		while (BLANK & l_d_mask[*(++pos)]);		\
780fbbaa43SLionel Sambuc 	while ((*(pos+1) != '\0') && !((FLD_D | REC_D_F) & l_d_mask[*++pos]));\
790fbbaa43SLionel Sambuc }
800fbbaa43SLionel Sambuc 
810fbbaa43SLionel Sambuc static u_char *enterfield(u_char *, const u_char *, struct field *, int);
820fbbaa43SLionel Sambuc static u_char *number(u_char *, const u_char *, u_char *, u_char *, int);
830fbbaa43SLionel Sambuc static u_char *length(u_char *, const u_char *, u_char *, u_char *, int);
840fbbaa43SLionel Sambuc 
85*84d9c625SLionel Sambuc #if defined(__minix)
86e286ccc0SBen Gras static u_char *numhex(u_char *, const u_char *, u_char *, u_char *, int);
87*84d9c625SLionel Sambuc #endif /* defined(__minix) */
88e286ccc0SBen Gras 
890fbbaa43SLionel Sambuc #define DECIMAL_POINT '.'
900fbbaa43SLionel Sambuc 
910fbbaa43SLionel Sambuc /*
920fbbaa43SLionel Sambuc  * constructs sort key with leading recheader, followed by the key,
930fbbaa43SLionel Sambuc  * followed by the original line.
940fbbaa43SLionel Sambuc  */
950fbbaa43SLionel Sambuc length_t
enterkey(RECHEADER * keybuf,const u_char * keybuf_end,u_char * line_data,size_t line_size,struct field fieldtable[])960fbbaa43SLionel Sambuc enterkey(RECHEADER *keybuf, const u_char *keybuf_end, u_char *line_data,
970fbbaa43SLionel Sambuc     size_t line_size, struct field fieldtable[])
980fbbaa43SLionel Sambuc 	/* keybuf:	 pointer to start of key */
990fbbaa43SLionel Sambuc {
1000fbbaa43SLionel Sambuc 	int i;
1010fbbaa43SLionel Sambuc 	u_char *l_d_mask;
1020fbbaa43SLionel Sambuc 	u_char *lineend, *pos;
1030fbbaa43SLionel Sambuc 	const u_char *endkey;
1040fbbaa43SLionel Sambuc 	u_char *keypos;
1050fbbaa43SLionel Sambuc 	struct coldesc *clpos;
1060fbbaa43SLionel Sambuc 	int col = 1;
1070fbbaa43SLionel Sambuc 	struct field *ftpos;
1080fbbaa43SLionel Sambuc 
1090fbbaa43SLionel Sambuc 	l_d_mask = d_mask;
1100fbbaa43SLionel Sambuc 	pos = line_data - 1;
1110fbbaa43SLionel Sambuc 	lineend = line_data + line_size-1;
1120fbbaa43SLionel Sambuc 				/* don't include rec_delimiter */
1130fbbaa43SLionel Sambuc 
1140fbbaa43SLionel Sambuc 	for (i = 0; i < ncols; i++) {
1150fbbaa43SLionel Sambuc 		clpos = clist + i;
1160fbbaa43SLionel Sambuc 		for (; (col < clpos->num) && (pos < lineend); col++) {
1170fbbaa43SLionel Sambuc 			NEXTCOL(pos);
1180fbbaa43SLionel Sambuc 		}
1190fbbaa43SLionel Sambuc 		if (pos >= lineend)
1200fbbaa43SLionel Sambuc 			break;
1210fbbaa43SLionel Sambuc 		clpos->start = SEP_FLAG ? pos + 1 : pos;
1220fbbaa43SLionel Sambuc 		NEXTCOL(pos);
1230fbbaa43SLionel Sambuc 		clpos->end = pos;
1240fbbaa43SLionel Sambuc 		col++;
1250fbbaa43SLionel Sambuc 		if (pos >= lineend) {
1260fbbaa43SLionel Sambuc 			clpos->end = lineend;
1270fbbaa43SLionel Sambuc 			i++;
1280fbbaa43SLionel Sambuc 			break;
1290fbbaa43SLionel Sambuc 		}
1300fbbaa43SLionel Sambuc 	}
1310fbbaa43SLionel Sambuc 	for (; i <= ncols; i++)
1320fbbaa43SLionel Sambuc 		clist[i].start = clist[i].end = lineend;
1330fbbaa43SLionel Sambuc 	if (clist[0].start < line_data)
1340fbbaa43SLionel Sambuc 		clist[0].start++;
1350fbbaa43SLionel Sambuc 
1360fbbaa43SLionel Sambuc 	/*
1370fbbaa43SLionel Sambuc 	 * We write the sort keys (concatenated) followed by the
1380fbbaa43SLionel Sambuc 	 * original line data (for output) as the 'keybuf' data.
1390fbbaa43SLionel Sambuc 	 * keybuf->length is the number of key bytes + data bytes.
1400fbbaa43SLionel Sambuc 	 * keybuf->offset is the number of key bytes.
1410fbbaa43SLionel Sambuc 	 * We add a record separator weight after the key in case
1420fbbaa43SLionel Sambuc 	 * (as is usual) we need to preserve the order of equal lines,
1430fbbaa43SLionel Sambuc 	 * and for 'sort -u'.
1440fbbaa43SLionel Sambuc 	 * The key itself will have had the correct weight applied.
1450fbbaa43SLionel Sambuc 	 */
1460fbbaa43SLionel Sambuc 	keypos = keybuf->data;
1470fbbaa43SLionel Sambuc 	endkey = keybuf_end - line_size - 1;
1480fbbaa43SLionel Sambuc 	if (endkey <= keypos)
1490fbbaa43SLionel Sambuc 		/* No room for any key bytes */
1500fbbaa43SLionel Sambuc 		return 1;
1510fbbaa43SLionel Sambuc 
1520fbbaa43SLionel Sambuc 	for (ftpos = fieldtable + 1; ftpos->icol.num; ftpos++) {
1530fbbaa43SLionel Sambuc 		if ((keypos = enterfield(keypos, endkey, ftpos,
1540fbbaa43SLionel Sambuc 		    fieldtable->flags)) == NULL)
1550fbbaa43SLionel Sambuc 			return (1);
1560fbbaa43SLionel Sambuc 	}
1570fbbaa43SLionel Sambuc 
1580fbbaa43SLionel Sambuc 	keybuf->offset = keypos - keybuf->data;
1590fbbaa43SLionel Sambuc 	keybuf->length = keybuf->offset + line_size;
1600fbbaa43SLionel Sambuc 
1610fbbaa43SLionel Sambuc 	/*
1620fbbaa43SLionel Sambuc 	 * Posix requires that equal keys be further sorted by the
1630fbbaa43SLionel Sambuc 	 * entire original record.
1640fbbaa43SLionel Sambuc 	 * NetBSD has (at least for some time) kept equal keys in
1650fbbaa43SLionel Sambuc 	 * their original order.
1660fbbaa43SLionel Sambuc 	 * For 'sort -u' posix_sort is unset.
1670fbbaa43SLionel Sambuc 	 */
1680fbbaa43SLionel Sambuc 	keybuf->keylen = posix_sort ? keybuf->length : keybuf->offset;
1690fbbaa43SLionel Sambuc 
1700fbbaa43SLionel Sambuc 	memcpy(keypos, line_data, line_size);
1710fbbaa43SLionel Sambuc 	return (0);
1720fbbaa43SLionel Sambuc }
1730fbbaa43SLionel Sambuc 
1740fbbaa43SLionel Sambuc /*
1750fbbaa43SLionel Sambuc  * constructs a field (as defined by -k) within a key
1760fbbaa43SLionel Sambuc  */
1770fbbaa43SLionel Sambuc static u_char *
enterfield(u_char * tablepos,const u_char * endkey,struct field * cur_fld,int gflags)1780fbbaa43SLionel Sambuc enterfield(u_char *tablepos, const u_char *endkey, struct field *cur_fld,
1790fbbaa43SLionel Sambuc     int gflags)
1800fbbaa43SLionel Sambuc {
1810fbbaa43SLionel Sambuc 	u_char *start, *end, *lineend, *mask, *lweight;
1820fbbaa43SLionel Sambuc 	struct column icol, tcol;
1830fbbaa43SLionel Sambuc 	u_int flags;
1840fbbaa43SLionel Sambuc 
1850fbbaa43SLionel Sambuc 	icol = cur_fld->icol;
1860fbbaa43SLionel Sambuc 	tcol = cur_fld->tcol;
1870fbbaa43SLionel Sambuc 	flags = cur_fld->flags;
1880fbbaa43SLionel Sambuc 	start = icol.p->start;
1890fbbaa43SLionel Sambuc 	lineend = clist[ncols].end;
1900fbbaa43SLionel Sambuc 	if (flags & BI)
1910fbbaa43SLionel Sambuc 		SKIP_BLANKS(start);
1920fbbaa43SLionel Sambuc 	start += icol.indent;
1930fbbaa43SLionel Sambuc 	start = min(start, lineend);
1940fbbaa43SLionel Sambuc 
1950fbbaa43SLionel Sambuc 	if (!tcol.num)
1960fbbaa43SLionel Sambuc 		end = lineend;
1970fbbaa43SLionel Sambuc 	else {
1980fbbaa43SLionel Sambuc 		if (tcol.indent) {
1990fbbaa43SLionel Sambuc 			end = tcol.p->start;
2000fbbaa43SLionel Sambuc 			if (flags & BT)
2010fbbaa43SLionel Sambuc 				SKIP_BLANKS(end);
2020fbbaa43SLionel Sambuc 			end += tcol.indent;
2030fbbaa43SLionel Sambuc 			end = min(end, lineend);
2040fbbaa43SLionel Sambuc 		} else
2050fbbaa43SLionel Sambuc 			end = tcol.p->end;
2060fbbaa43SLionel Sambuc 	}
2070fbbaa43SLionel Sambuc 
2080fbbaa43SLionel Sambuc 	if (flags & L)
2090fbbaa43SLionel Sambuc 		return length(tablepos, endkey, start, end, flags);
2100fbbaa43SLionel Sambuc 	if (flags & N)
2110fbbaa43SLionel Sambuc 		return number(tablepos, endkey, start, end, flags);
212*84d9c625SLionel Sambuc #if defined(__minix)
213e286ccc0SBen Gras 	if (flags & X)
214e286ccc0SBen Gras 		return numhex(tablepos, endkey, start, end, flags);
215*84d9c625SLionel Sambuc #endif /* defined(__minix) */
2160fbbaa43SLionel Sambuc 
2170fbbaa43SLionel Sambuc 	/* Bound check space - assuming nothing is skipped */
2180fbbaa43SLionel Sambuc 	if (tablepos + (end - start) + 1 >= endkey)
2190fbbaa43SLionel Sambuc 		return NULL;
2200fbbaa43SLionel Sambuc 
2210fbbaa43SLionel Sambuc 	mask = cur_fld->mask;
2220fbbaa43SLionel Sambuc 	lweight = cur_fld->weights;
2230fbbaa43SLionel Sambuc 	for (; start < end; start++) {
2240fbbaa43SLionel Sambuc 		if (!mask || mask[*start]) {
2250fbbaa43SLionel Sambuc 			*tablepos++ = lweight[*start];
2260fbbaa43SLionel Sambuc 		}
2270fbbaa43SLionel Sambuc 	}
2280fbbaa43SLionel Sambuc 	/* Add extra byte (absent from lweight) to sort short keys correctly */
2290fbbaa43SLionel Sambuc 	*tablepos++ = lweight[REC_D];
2300fbbaa43SLionel Sambuc 	return tablepos;
2310fbbaa43SLionel Sambuc }
2320fbbaa43SLionel Sambuc 
2330fbbaa43SLionel Sambuc /*
2340fbbaa43SLionel Sambuc  * Numbers are converted to a floating point format (exponent & mantissa)
2350fbbaa43SLionel Sambuc  * so that they compare correctly as sequence of unsigned bytes.
2360fbbaa43SLionel Sambuc  * Bytes 0x00 and 0xff are used to terminate positive and negative numbers
2370fbbaa43SLionel Sambuc  * to ensure that 0.123 sorts after 0.12 and -0.123 sorts before -0.12.
2380fbbaa43SLionel Sambuc  *
2390fbbaa43SLionel Sambuc  * The first byte contain the overall sign, exponent sign and some of the
2400fbbaa43SLionel Sambuc  * exponent. These have to be ordered (-ve value, decreasing exponent),
2410fbbaa43SLionel Sambuc  * zero, (+ve value, increasing exponent).
2420fbbaa43SLionel Sambuc  *
2430fbbaa43SLionel Sambuc  * The first byte is 0x80 for zero, 0xc0 for +ve with exponent 0.
2440fbbaa43SLionel Sambuc  * -ve values are the 1's compliments (so 0x7f isn't used!).
2450fbbaa43SLionel Sambuc  *
2460fbbaa43SLionel Sambuc  * This only leaves 63 byte values for +ve exponents - which isn't enough.
2470fbbaa43SLionel Sambuc  * The largest 4 exponent values are used to hold a byte count of the
2480fbbaa43SLionel Sambuc  * number of following bytes that contain 8 exponent bits per byte,
2490fbbaa43SLionel Sambuc  * This lets us sort exponents from -2^31 to +2^31.
2500fbbaa43SLionel Sambuc  *
2510fbbaa43SLionel Sambuc  * The mantissa is stored 2 digits per byte offset by 0x40, for negative
2520fbbaa43SLionel Sambuc  * numbers the order must be reversed (they are bit inverted).
2530fbbaa43SLionel Sambuc  *
2540fbbaa43SLionel Sambuc  * Reverse sorts are done by inverting the sign of the number.
2550fbbaa43SLionel Sambuc  */
2560fbbaa43SLionel Sambuc #define MAX_EXP_ENC  ((int)sizeof(int))
2570fbbaa43SLionel Sambuc 
2580fbbaa43SLionel Sambuc static u_char *
number(u_char * pos,const u_char * bufend,u_char * line,u_char * lineend,int reverse)2590fbbaa43SLionel Sambuc number(u_char *pos, const u_char *bufend, u_char *line, u_char *lineend,
2600fbbaa43SLionel Sambuc     int reverse)
2610fbbaa43SLionel Sambuc {
2620fbbaa43SLionel Sambuc 	int exponent = -1;
2630fbbaa43SLionel Sambuc 	int had_dp = 0;
2640fbbaa43SLionel Sambuc 	u_char *tline;
2650fbbaa43SLionel Sambuc 	char ch;
2660fbbaa43SLionel Sambuc 	unsigned int val;
2670fbbaa43SLionel Sambuc 	u_char *last_nz_pos;
2680fbbaa43SLionel Sambuc 	u_char negate;
2690fbbaa43SLionel Sambuc 
2700fbbaa43SLionel Sambuc 	if (reverse & R)
2710fbbaa43SLionel Sambuc 		negate = 0xff;
2720fbbaa43SLionel Sambuc 	else
2730fbbaa43SLionel Sambuc 		negate = 0;
2740fbbaa43SLionel Sambuc 
2750fbbaa43SLionel Sambuc 	/* Give ourselves space for the key terminator */
2760fbbaa43SLionel Sambuc 	bufend--;
2770fbbaa43SLionel Sambuc 
2780fbbaa43SLionel Sambuc 	/* Ensure we have enough space for the exponent */
2790fbbaa43SLionel Sambuc 	if (pos + 1 + MAX_EXP_ENC > bufend)
2800fbbaa43SLionel Sambuc 		return (NULL);
2810fbbaa43SLionel Sambuc 
2820fbbaa43SLionel Sambuc 	SKIP_BLANKS(line);
2830fbbaa43SLionel Sambuc 	if (*line == '-') {	/* set the sign */
2840fbbaa43SLionel Sambuc 		negate ^= 0xff;
2850fbbaa43SLionel Sambuc 		line++;
286*84d9c625SLionel Sambuc 	} else if (*line == '+') {
287*84d9c625SLionel Sambuc 		line++;
2880fbbaa43SLionel Sambuc 	}
289*84d9c625SLionel Sambuc 
2900fbbaa43SLionel Sambuc 	/* eat initial zeroes */
2910fbbaa43SLionel Sambuc 	for (; *line == '0' && line < lineend; line++)
2920fbbaa43SLionel Sambuc 		continue;
2930fbbaa43SLionel Sambuc 
2940fbbaa43SLionel Sambuc 	/* calculate exponents */
2950fbbaa43SLionel Sambuc 	if (*line == DECIMAL_POINT) {
2960fbbaa43SLionel Sambuc 		/* Decimal fraction */
2970fbbaa43SLionel Sambuc 		had_dp = 1;
2980fbbaa43SLionel Sambuc 		while (*++line == '0' && line < lineend)
2990fbbaa43SLionel Sambuc 			exponent--;
3000fbbaa43SLionel Sambuc 	} else {
3010fbbaa43SLionel Sambuc 		/* Large (absolute) value, count digits */
3020fbbaa43SLionel Sambuc 		for (tline = line; *tline >= '0' &&
3030fbbaa43SLionel Sambuc 		    *tline <= '9' && tline < lineend; tline++)
3040fbbaa43SLionel Sambuc 			exponent++;
3050fbbaa43SLionel Sambuc 	}
3060fbbaa43SLionel Sambuc 
3070fbbaa43SLionel Sambuc 	/* If the first/next character isn't a digit, value is zero */
3080fbbaa43SLionel Sambuc 	if (*line < '1' || *line > '9' || line >= lineend) {
3090fbbaa43SLionel Sambuc 		/* This may be "0", "0.00", "000" or "fubar" but sorts as 0 */
3100fbbaa43SLionel Sambuc 		/* XXX what about NaN, NAN, inf and INF */
3110fbbaa43SLionel Sambuc 		*pos++ = 0x80;
3120fbbaa43SLionel Sambuc 		return pos;
3130fbbaa43SLionel Sambuc 	}
3140fbbaa43SLionel Sambuc 
3150fbbaa43SLionel Sambuc 	/* Maybe here we should allow for e+12 (etc) */
3160fbbaa43SLionel Sambuc 
3170fbbaa43SLionel Sambuc 	if (exponent < 0x40 - MAX_EXP_ENC && -exponent < 0x40 - MAX_EXP_ENC) {
3180fbbaa43SLionel Sambuc 		/* Value ok for simple encoding */
3190fbbaa43SLionel Sambuc 		/* exponent 0 is 0xc0 for +ve numbers and 0x40 for -ve ones */
3200fbbaa43SLionel Sambuc 		exponent += 0xc0;
3210fbbaa43SLionel Sambuc 		*pos++ = negate ^ exponent;
3220fbbaa43SLionel Sambuc 	} else {
3230fbbaa43SLionel Sambuc 		/* Out or range for a single byte */
3240fbbaa43SLionel Sambuc 		int c, t;
3250fbbaa43SLionel Sambuc 		t = exponent > 0 ? exponent : -exponent;
3260fbbaa43SLionel Sambuc 		/* Count how many 8-bit bytes are needed */
3270fbbaa43SLionel Sambuc 		for (c = 0; ; c++) {
3280fbbaa43SLionel Sambuc 			t >>= 8;
3290fbbaa43SLionel Sambuc 			if (t == 0)
3300fbbaa43SLionel Sambuc 				break;
3310fbbaa43SLionel Sambuc 		}
3320fbbaa43SLionel Sambuc 		/* 'c' better be 0..3 here - but probably 0..1 */
3330fbbaa43SLionel Sambuc 		/* Offset just outside valid range */
3340fbbaa43SLionel Sambuc 		t = c + 0x40 - MAX_EXP_ENC;
3350fbbaa43SLionel Sambuc 		if (exponent < 0)
3360fbbaa43SLionel Sambuc 			t = -t;
3370fbbaa43SLionel Sambuc 		*pos++ = negate ^ (t + 0xc0);
3380fbbaa43SLionel Sambuc 		/* now add each byte, most significant first */
3390fbbaa43SLionel Sambuc 		for (; c >= 0; c--)
3400fbbaa43SLionel Sambuc 			*pos++ = negate ^ (exponent >> (c * 8));
3410fbbaa43SLionel Sambuc 	}
3420fbbaa43SLionel Sambuc 
3430fbbaa43SLionel Sambuc 	/* Finally add mantissa, 2 digits per byte */
3440fbbaa43SLionel Sambuc 	for (last_nz_pos = pos; line < lineend; ) {
3450fbbaa43SLionel Sambuc 		if (pos >= bufend)
3460fbbaa43SLionel Sambuc 			return NULL;
3470fbbaa43SLionel Sambuc 		ch = *line++;
3480fbbaa43SLionel Sambuc 		val = (ch - '0') * 10;
3490fbbaa43SLionel Sambuc 		if (val > 90) {
3500fbbaa43SLionel Sambuc 			if (ch == DECIMAL_POINT && !had_dp) {
3510fbbaa43SLionel Sambuc 				had_dp = 1;
3520fbbaa43SLionel Sambuc 				continue;
3530fbbaa43SLionel Sambuc 			}
3540fbbaa43SLionel Sambuc 			break;
3550fbbaa43SLionel Sambuc 		}
3560fbbaa43SLionel Sambuc 		while (line < lineend) {
3570fbbaa43SLionel Sambuc 			ch = *line++;
3580fbbaa43SLionel Sambuc 			if (ch == DECIMAL_POINT && !had_dp) {
3590fbbaa43SLionel Sambuc 				had_dp = 1;
3600fbbaa43SLionel Sambuc 				continue;
3610fbbaa43SLionel Sambuc 			}
3620fbbaa43SLionel Sambuc 			if (ch < '0' || ch > '9')
3630fbbaa43SLionel Sambuc 				line = lineend;
3640fbbaa43SLionel Sambuc 			else
3650fbbaa43SLionel Sambuc 				val += ch - '0';
3660fbbaa43SLionel Sambuc 			break;
3670fbbaa43SLionel Sambuc 		}
3680fbbaa43SLionel Sambuc 		*pos++ = negate ^ (val + 0x40);
3690fbbaa43SLionel Sambuc 		if (val != 0)
3700fbbaa43SLionel Sambuc 			last_nz_pos = pos;
3710fbbaa43SLionel Sambuc 	}
3720fbbaa43SLionel Sambuc 
3730fbbaa43SLionel Sambuc 	/* Add key terminator, deleting any trailing "00" */
3740fbbaa43SLionel Sambuc 	*last_nz_pos++ = negate;
3750fbbaa43SLionel Sambuc 
3760fbbaa43SLionel Sambuc 	return (last_nz_pos);
3770fbbaa43SLionel Sambuc }
3780fbbaa43SLionel Sambuc 
3790fbbaa43SLionel Sambuc static u_char *
length(u_char * pos,const u_char * bufend,u_char * line,u_char * lineend,int flag)3800fbbaa43SLionel Sambuc length(u_char *pos, const u_char *bufend, u_char *line, u_char *lineend,
3810fbbaa43SLionel Sambuc     int flag)
3820fbbaa43SLionel Sambuc {
3830fbbaa43SLionel Sambuc 	u_char buf[32];
3840fbbaa43SLionel Sambuc 	int l;
3850fbbaa43SLionel Sambuc 	SKIP_BLANKS(line);
3860fbbaa43SLionel Sambuc 	l = snprintf((char *)buf, sizeof(buf), "%td", lineend - line);
3870fbbaa43SLionel Sambuc 	return number(pos, bufend, buf, buf + l, flag);
3880fbbaa43SLionel Sambuc }
389e286ccc0SBen Gras 
390*84d9c625SLionel Sambuc #if defined(__minix)
391e286ccc0SBen Gras static u_char *
numhex(u_char * pos,const u_char * bufend,u_char * line,u_char * lineend,int flag)392e286ccc0SBen Gras numhex(u_char *pos, const u_char *bufend, u_char *line, u_char *lineend,
393e286ccc0SBen Gras     int flag)
394e286ccc0SBen Gras {
395e286ccc0SBen Gras 	u_char buf[32];
396e286ccc0SBen Gras 	int64_t n = 0;
397e286ccc0SBen Gras 	int l;
398e286ccc0SBen Gras 	SKIP_BLANKS(line);
3993161c603SBen Gras 	sscanf((const char *) pos, "%llx", &n);
400e286ccc0SBen Gras 	l = snprintf((char *)buf, sizeof(buf), "%lld", n);
401e286ccc0SBen Gras 	return number(pos, bufend, buf, buf + l, flag);
402e286ccc0SBen Gras }
403*84d9c625SLionel Sambuc #endif /* defined(__minix) */
404