xref: /freebsd/usr.bin/fortune/strfile/strfile.c (revision 0b8224d1cc9dc6c9778ba04a75b2c8d47e5d7481)
16ae1554aSColin Percival /*-
26ae1554aSColin Percival  * Copyright (c) 1989, 1993
36ae1554aSColin Percival  *	The Regents of the University of California.  All rights reserved.
46ae1554aSColin Percival  *
56ae1554aSColin Percival  * This code is derived from software contributed to Berkeley by
66ae1554aSColin Percival  * Ken Arnold.
76ae1554aSColin Percival  *
86ae1554aSColin Percival  * Redistribution and use in source and binary forms, with or without
96ae1554aSColin Percival  * modification, are permitted provided that the following conditions
106ae1554aSColin Percival  * are met:
116ae1554aSColin Percival  * 1. Redistributions of source code must retain the above copyright
126ae1554aSColin Percival  *    notice, this list of conditions and the following disclaimer.
136ae1554aSColin Percival  * 2. Redistributions in binary form must reproduce the above copyright
146ae1554aSColin Percival  *    notice, this list of conditions and the following disclaimer in the
156ae1554aSColin Percival  *    documentation and/or other materials provided with the distribution.
166ae1554aSColin Percival  * 3. Neither the name of the University nor the names of its contributors
176ae1554aSColin Percival  *    may be used to endorse or promote products derived from this software
186ae1554aSColin Percival  *    without specific prior written permission.
196ae1554aSColin Percival  *
206ae1554aSColin Percival  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
216ae1554aSColin Percival  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
226ae1554aSColin Percival  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
236ae1554aSColin Percival  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
246ae1554aSColin Percival  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
256ae1554aSColin Percival  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
266ae1554aSColin Percival  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
276ae1554aSColin Percival  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
286ae1554aSColin Percival  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
296ae1554aSColin Percival  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
306ae1554aSColin Percival  * SUCH DAMAGE.
316ae1554aSColin Percival  */
326ae1554aSColin Percival 
336ae1554aSColin Percival #include <sys/param.h>
346ae1554aSColin Percival #include <sys/endian.h>
356ae1554aSColin Percival #include <ctype.h>
366ae1554aSColin Percival #include <locale.h>
376ae1554aSColin Percival #include <stdbool.h>
386ae1554aSColin Percival #include <stdio.h>
396ae1554aSColin Percival #include <stdlib.h>
406ae1554aSColin Percival #include <string.h>
416ae1554aSColin Percival #include <time.h>
426ae1554aSColin Percival #include <unistd.h>
436ae1554aSColin Percival 
446ae1554aSColin Percival #include "strfile.h"
456ae1554aSColin Percival 
466ae1554aSColin Percival /*
476ae1554aSColin Percival  *	This program takes a file composed of strings separated by
486ae1554aSColin Percival  * lines starting with two consecutive delimiting character (default
496ae1554aSColin Percival  * character is '%') and creates another file which consists of a table
506ae1554aSColin Percival  * describing the file (structure from "strfile.h"), a table of seek
516ae1554aSColin Percival  * pointers to the start of the strings, and the strings, each terminated
526ae1554aSColin Percival  * by a null byte.  Usage:
536ae1554aSColin Percival  *
546ae1554aSColin Percival  *	% strfile [-iorsx] [ -cC ] sourcefile [ datafile ]
556ae1554aSColin Percival  *
566ae1554aSColin Percival  *	C - Allow comments marked by a double delimiter at line's beginning
576ae1554aSColin Percival  *	c - Change delimiting character from '%' to 'C'
586ae1554aSColin Percival  *	s - Silent.  Give no summary of data processed at the end of
596ae1554aSColin Percival  *	    the run.
606ae1554aSColin Percival  *	o - order the strings in alphabetic order
616ae1554aSColin Percival  *	i - if ordering, ignore case
626ae1554aSColin Percival  *	r - randomize the order of the strings
636ae1554aSColin Percival  *	x - set rotated bit
646ae1554aSColin Percival  *
656ae1554aSColin Percival  *		Ken Arnold	Sept. 7, 1978 --
666ae1554aSColin Percival  *
676ae1554aSColin Percival  *	Added ordering options.
686ae1554aSColin Percival  */
696ae1554aSColin Percival 
706ae1554aSColin Percival #define	STORING_PTRS	(Oflag || Rflag)
716ae1554aSColin Percival #define	CHUNKSIZE	512
726ae1554aSColin Percival 
736ae1554aSColin Percival #define		ALLOC(ptr, sz)	do { \
746ae1554aSColin Percival 			if (ptr == NULL) \
756ae1554aSColin Percival 				ptr = malloc(CHUNKSIZE * sizeof(*ptr)); \
766ae1554aSColin Percival 			else if (((sz) + 1) % CHUNKSIZE == 0) \
776ae1554aSColin Percival 				ptr = realloc(ptr, ((sz) + CHUNKSIZE) * sizeof(*ptr)); \
786ae1554aSColin Percival 			if (ptr == NULL) { \
796ae1554aSColin Percival 				fprintf(stderr, "out of space\n"); \
806ae1554aSColin Percival 				exit(1); \
816ae1554aSColin Percival 			} \
826ae1554aSColin Percival 		} while (0)
836ae1554aSColin Percival 
846ae1554aSColin Percival typedef struct {
856ae1554aSColin Percival 	int	first;
866ae1554aSColin Percival 	off_t	pos;
876ae1554aSColin Percival } STR;
886ae1554aSColin Percival 
896ae1554aSColin Percival static char	*Infile		= NULL,		/* input file name */
906ae1554aSColin Percival 		Outfile[MAXPATHLEN] = "",	/* output file name */
916ae1554aSColin Percival 		Delimch		= '%';		/* delimiting character */
926ae1554aSColin Percival 
936ae1554aSColin Percival static int	Cflag		= false;	/* embedded comments */
946ae1554aSColin Percival static int	Sflag		= false;	/* silent run flag */
956ae1554aSColin Percival static int	Oflag		= false;	/* ordering flag */
966ae1554aSColin Percival static int	Iflag		= false;	/* ignore case flag */
976ae1554aSColin Percival static int	Rflag		= false;	/* randomize order flag */
986ae1554aSColin Percival static int	Xflag		= false;	/* set rotated bit */
996ae1554aSColin Percival static uint32_t	Num_pts		= 0;		/* number of pointers/strings */
1006ae1554aSColin Percival 
1016ae1554aSColin Percival static off_t	*Seekpts;
1026ae1554aSColin Percival 
1036ae1554aSColin Percival static FILE	*Sort_1, *Sort_2;		/* pointers for sorting */
1046ae1554aSColin Percival 
1056ae1554aSColin Percival static STRFILE	Tbl;				/* statistics table */
1066ae1554aSColin Percival 
1076ae1554aSColin Percival static STR	*Firstch;			/* first chars of each string */
1086ae1554aSColin Percival 
1096ae1554aSColin Percival static void add_offset(FILE *, off_t);
1106ae1554aSColin Percival static int cmp_str(const void *, const void *);
1116ae1554aSColin Percival static int stable_collate_range_cmp(int, int);
1126ae1554aSColin Percival static void do_order(void);
1136ae1554aSColin Percival static void getargs(int, char **);
1146ae1554aSColin Percival static void randomize(void);
115*a1b6427aSAlfonso Gregory static void usage(void) __dead2;
1166ae1554aSColin Percival 
1176ae1554aSColin Percival /*
1186ae1554aSColin Percival  * main:
1196ae1554aSColin Percival  *	Drive the sucker.  There are two main modes -- either we store
1206ae1554aSColin Percival  *	the seek pointers, if the table is to be sorted or randomized,
1216ae1554aSColin Percival  *	or we write the pointer directly to the file, if we are to stay
1226ae1554aSColin Percival  *	in file order.  If the former, we allocate and re-allocate in
1236ae1554aSColin Percival  *	CHUNKSIZE blocks; if the latter, we just write each pointer,
1246ae1554aSColin Percival  *	and then seek back to the beginning to write in the table.
1256ae1554aSColin Percival  */
1266ae1554aSColin Percival int
main(int ac,char * av[])1276ae1554aSColin Percival main(int ac, char *av[])
1286ae1554aSColin Percival {
1296ae1554aSColin Percival 	char *sp, *nsp, dc;
1306ae1554aSColin Percival 	FILE *inf, *outf;
1316ae1554aSColin Percival 	off_t last_off, pos, *p;
1326ae1554aSColin Percival 	size_t length;
1336ae1554aSColin Percival 	int first;
1346ae1554aSColin Percival 	uint32_t cnt;
1356ae1554aSColin Percival 	STR *fp;
1366ae1554aSColin Percival 	static char string[257];
1376ae1554aSColin Percival 
1386ae1554aSColin Percival 	setlocale(LC_ALL, "");
1396ae1554aSColin Percival 
1406ae1554aSColin Percival 	getargs(ac, av);		/* evalute arguments */
1416ae1554aSColin Percival 	dc = Delimch;
1426ae1554aSColin Percival 	if ((inf = fopen(Infile, "r")) == NULL) {
1436ae1554aSColin Percival 		perror(Infile);
1446ae1554aSColin Percival 		exit(1);
1456ae1554aSColin Percival 	}
1466ae1554aSColin Percival 
1476ae1554aSColin Percival 	if ((outf = fopen(Outfile, "w")) == NULL) {
1486ae1554aSColin Percival 		perror(Outfile);
1496ae1554aSColin Percival 		exit(1);
1506ae1554aSColin Percival 	}
1516ae1554aSColin Percival 	if (!STORING_PTRS)
1526ae1554aSColin Percival 		fseek(outf, (long)sizeof(Tbl), SEEK_SET);
1536ae1554aSColin Percival 
1546ae1554aSColin Percival 	/*
1556ae1554aSColin Percival 	 * Write the strings onto the file
1566ae1554aSColin Percival 	 */
1576ae1554aSColin Percival 
1586ae1554aSColin Percival 	Tbl.str_longlen = 0;
1596ae1554aSColin Percival 	Tbl.str_shortlen = 0xffffffff;
1606ae1554aSColin Percival 	Tbl.str_delim = dc;
1616ae1554aSColin Percival 	Tbl.str_version = VERSION;
1626ae1554aSColin Percival 	first = Oflag;
1636ae1554aSColin Percival 	add_offset(outf, ftello(inf));
1646ae1554aSColin Percival 	last_off = 0;
1656ae1554aSColin Percival 	do {
1666ae1554aSColin Percival 		sp = fgets(string, 256, inf);
1676ae1554aSColin Percival 		if (sp == NULL || (sp[0] == dc && sp[1] == '\n')) {
1686ae1554aSColin Percival 			pos = ftello(inf);
1696ae1554aSColin Percival 			length = (size_t)(pos - last_off) -
1706ae1554aSColin Percival 			    (sp != NULL ? strlen(sp) : 0);
1716ae1554aSColin Percival 			last_off = pos;
1726ae1554aSColin Percival 			if (length == 0)
1736ae1554aSColin Percival 				continue;
1746ae1554aSColin Percival 			add_offset(outf, pos);
1756ae1554aSColin Percival 			if ((size_t)Tbl.str_longlen < length)
1766ae1554aSColin Percival 				Tbl.str_longlen = length;
1776ae1554aSColin Percival 			if ((size_t)Tbl.str_shortlen > length)
1786ae1554aSColin Percival 				Tbl.str_shortlen = length;
1796ae1554aSColin Percival 			first = Oflag;
1806ae1554aSColin Percival 		}
1816ae1554aSColin Percival 		else if (first) {
1826ae1554aSColin Percival 			for (nsp = sp; !isalnum((unsigned char)*nsp); nsp++)
1836ae1554aSColin Percival 				continue;
1846ae1554aSColin Percival 			ALLOC(Firstch, Num_pts);
1856ae1554aSColin Percival 			fp = &Firstch[Num_pts - 1];
1866ae1554aSColin Percival 			if (Iflag && isupper((unsigned char)*nsp))
1876ae1554aSColin Percival 				fp->first = tolower((unsigned char)*nsp);
1886ae1554aSColin Percival 			else
1896ae1554aSColin Percival 				fp->first = *nsp;
1906ae1554aSColin Percival 			fp->pos = Seekpts[Num_pts - 1];
1916ae1554aSColin Percival 			first = false;
1926ae1554aSColin Percival 		}
1936ae1554aSColin Percival 	} while (sp != NULL);
1946ae1554aSColin Percival 
1956ae1554aSColin Percival 	/*
1966ae1554aSColin Percival 	 * write the tables in
1976ae1554aSColin Percival 	 */
1986ae1554aSColin Percival 
1996ae1554aSColin Percival 	fclose(inf);
2006ae1554aSColin Percival 	Tbl.str_numstr = Num_pts - 1;
2016ae1554aSColin Percival 
2026ae1554aSColin Percival 	if (Cflag)
2036ae1554aSColin Percival 		Tbl.str_flags |= STR_COMMENTS;
2046ae1554aSColin Percival 
2056ae1554aSColin Percival 	if (Oflag)
2066ae1554aSColin Percival 		do_order();
2076ae1554aSColin Percival 	else if (Rflag)
2086ae1554aSColin Percival 		randomize();
2096ae1554aSColin Percival 
2106ae1554aSColin Percival 	if (Xflag)
2116ae1554aSColin Percival 		Tbl.str_flags |= STR_ROTATED;
2126ae1554aSColin Percival 
2136ae1554aSColin Percival 	if (!Sflag) {
2146ae1554aSColin Percival 		printf("\"%s\" created\n", Outfile);
2156ae1554aSColin Percival 		if (Num_pts == 2)
2166ae1554aSColin Percival 			puts("There was 1 string");
2176ae1554aSColin Percival 		else
2186ae1554aSColin Percival 			printf("There were %u strings\n", Num_pts - 1);
2196ae1554aSColin Percival 		printf("Longest string: %u byte%s\n", Tbl.str_longlen,
2206ae1554aSColin Percival 		       Tbl.str_longlen == 1 ? "" : "s");
2216ae1554aSColin Percival 		printf("Shortest string: %u byte%s\n", Tbl.str_shortlen,
2226ae1554aSColin Percival 		       Tbl.str_shortlen == 1 ? "" : "s");
2236ae1554aSColin Percival 	}
2246ae1554aSColin Percival 
2256ae1554aSColin Percival 	rewind(outf);
2266ae1554aSColin Percival 	Tbl.str_version = htobe32(Tbl.str_version);
2276ae1554aSColin Percival 	Tbl.str_numstr = htobe32(Tbl.str_numstr);
2286ae1554aSColin Percival 	Tbl.str_longlen = htobe32(Tbl.str_longlen);
2296ae1554aSColin Percival 	Tbl.str_shortlen = htobe32(Tbl.str_shortlen);
2306ae1554aSColin Percival 	Tbl.str_flags = htobe32(Tbl.str_flags);
2316ae1554aSColin Percival 	fwrite((char *)&Tbl, sizeof(Tbl), 1, outf);
2326ae1554aSColin Percival 	if (STORING_PTRS) {
2336ae1554aSColin Percival 		for (p = Seekpts, cnt = Num_pts; cnt--; ++p)
2346ae1554aSColin Percival 			*p = htobe64(*p);
2356ae1554aSColin Percival 		fwrite(Seekpts, sizeof(*Seekpts), (size_t)Num_pts, outf);
2366ae1554aSColin Percival 	}
2376ae1554aSColin Percival 	fclose(outf);
2386ae1554aSColin Percival 	exit(0);
2396ae1554aSColin Percival }
2406ae1554aSColin Percival 
2416ae1554aSColin Percival /*
2426ae1554aSColin Percival  *	This routine evaluates arguments from the command line
2436ae1554aSColin Percival  */
2446ae1554aSColin Percival void
getargs(int argc,char ** argv)2456ae1554aSColin Percival getargs(int argc, char **argv)
2466ae1554aSColin Percival {
2476ae1554aSColin Percival 	int ch;
2486ae1554aSColin Percival 
2496ae1554aSColin Percival 	while ((ch = getopt(argc, argv, "Cc:iorsx")) != -1)
2506ae1554aSColin Percival 		switch(ch) {
2516ae1554aSColin Percival 		case 'C':			/* embedded comments */
2526ae1554aSColin Percival 			Cflag++;
2536ae1554aSColin Percival 			break;
2546ae1554aSColin Percival 		case 'c':			/* new delimiting char */
2556ae1554aSColin Percival 			Delimch = *optarg;
2566ae1554aSColin Percival 			if (!isascii(Delimch)) {
2576ae1554aSColin Percival 				printf("bad delimiting character: '\\%o\n'",
2586ae1554aSColin Percival 				       (unsigned char)Delimch);
2596ae1554aSColin Percival 			}
2606ae1554aSColin Percival 			break;
2616ae1554aSColin Percival 		case 'i':			/* ignore case in ordering */
2626ae1554aSColin Percival 			Iflag++;
2636ae1554aSColin Percival 			break;
2646ae1554aSColin Percival 		case 'o':			/* order strings */
2656ae1554aSColin Percival 			Oflag++;
2666ae1554aSColin Percival 			break;
2676ae1554aSColin Percival 		case 'r':			/* randomize pointers */
2686ae1554aSColin Percival 			Rflag++;
2696ae1554aSColin Percival 			break;
2706ae1554aSColin Percival 		case 's':			/* silent */
2716ae1554aSColin Percival 			Sflag++;
2726ae1554aSColin Percival 			break;
2736ae1554aSColin Percival 		case 'x':			/* set the rotated bit */
2746ae1554aSColin Percival 			Xflag++;
2756ae1554aSColin Percival 			break;
2766ae1554aSColin Percival 		case '?':
2776ae1554aSColin Percival 		default:
2786ae1554aSColin Percival 			usage();
2796ae1554aSColin Percival 		}
2806ae1554aSColin Percival 	argv += optind;
2816ae1554aSColin Percival 
2826ae1554aSColin Percival 	if (*argv) {
2836ae1554aSColin Percival 		Infile = *argv;
284777c9f5aSMark Johnston 		if (*++argv) {
285777c9f5aSMark Johnston 			if (strlcpy(Outfile, *argv, sizeof(Outfile)) >=
286777c9f5aSMark Johnston 			    sizeof(Outfile)) {
287777c9f5aSMark Johnston 				fprintf(stderr,
288777c9f5aSMark Johnston 				    "output_file path is too long\n");
289777c9f5aSMark Johnston 				exit(1);
290777c9f5aSMark Johnston 			}
291777c9f5aSMark Johnston 		}
2926ae1554aSColin Percival 	}
2936ae1554aSColin Percival 	if (!Infile) {
2946ae1554aSColin Percival 		puts("No input file name");
2956ae1554aSColin Percival 		usage();
2966ae1554aSColin Percival 	}
2976ae1554aSColin Percival 	if (*Outfile == '\0') {
298777c9f5aSMark Johnston 		if ((size_t)snprintf(Outfile, sizeof(Outfile), "%s.dat",
299777c9f5aSMark Johnston 		    Infile) >= sizeof(Outfile)) {
300777c9f5aSMark Johnston 			fprintf(stderr,
301777c9f5aSMark Johnston 			    "generated output_file path is too long\n");
302777c9f5aSMark Johnston 			exit(1);
303777c9f5aSMark Johnston 		}
3046ae1554aSColin Percival 	}
3056ae1554aSColin Percival }
3066ae1554aSColin Percival 
3076ae1554aSColin Percival void
usage(void)3086ae1554aSColin Percival usage(void)
3096ae1554aSColin Percival {
3106ae1554aSColin Percival 	fprintf(stderr,
3116ae1554aSColin Percival 	    "strfile [-Ciorsx] [-c char] source_file [output_file]\n");
3126ae1554aSColin Percival 	exit(1);
3136ae1554aSColin Percival }
3146ae1554aSColin Percival 
3156ae1554aSColin Percival /*
3166ae1554aSColin Percival  * add_offset:
3176ae1554aSColin Percival  *	Add an offset to the list, or write it out, as appropriate.
3186ae1554aSColin Percival  */
3196ae1554aSColin Percival void
add_offset(FILE * fp,off_t off)3206ae1554aSColin Percival add_offset(FILE *fp, off_t off)
3216ae1554aSColin Percival {
3226ae1554aSColin Percival 	off_t beoff;
3236ae1554aSColin Percival 
3246ae1554aSColin Percival 	if (!STORING_PTRS) {
3256ae1554aSColin Percival 		beoff = htobe64(off);
3266ae1554aSColin Percival 		fwrite(&beoff, 1, sizeof(beoff), fp);
3276ae1554aSColin Percival 	} else {
3286ae1554aSColin Percival 		ALLOC(Seekpts, Num_pts + 1);
3296ae1554aSColin Percival 		Seekpts[Num_pts] = off;
3306ae1554aSColin Percival 	}
3316ae1554aSColin Percival 	Num_pts++;
3326ae1554aSColin Percival }
3336ae1554aSColin Percival 
3346ae1554aSColin Percival /*
3356ae1554aSColin Percival  * do_order:
3366ae1554aSColin Percival  *	Order the strings alphabetically (possibly ignoring case).
3376ae1554aSColin Percival  */
3386ae1554aSColin Percival void
do_order(void)3396ae1554aSColin Percival do_order(void)
3406ae1554aSColin Percival {
3416ae1554aSColin Percival 	uint32_t i;
3426ae1554aSColin Percival 	off_t *lp;
3436ae1554aSColin Percival 	STR *fp;
3446ae1554aSColin Percival 
3456ae1554aSColin Percival 	Sort_1 = fopen(Infile, "r");
3466ae1554aSColin Percival 	Sort_2 = fopen(Infile, "r");
3476ae1554aSColin Percival 	qsort(Firstch, (size_t)Tbl.str_numstr, sizeof(*Firstch), cmp_str);
3486ae1554aSColin Percival 	i = Tbl.str_numstr;
3496ae1554aSColin Percival 	lp = Seekpts;
3506ae1554aSColin Percival 	fp = Firstch;
3516ae1554aSColin Percival 	while (i--)
3526ae1554aSColin Percival 		*lp++ = fp++->pos;
3536ae1554aSColin Percival 	fclose(Sort_1);
3546ae1554aSColin Percival 	fclose(Sort_2);
3556ae1554aSColin Percival 	Tbl.str_flags |= STR_ORDERED;
3566ae1554aSColin Percival }
3576ae1554aSColin Percival 
3586ae1554aSColin Percival static int
stable_collate_range_cmp(int c1,int c2)3596ae1554aSColin Percival stable_collate_range_cmp(int c1, int c2)
3606ae1554aSColin Percival {
3616ae1554aSColin Percival 	static char s1[2], s2[2];
3626ae1554aSColin Percival 	int ret;
3636ae1554aSColin Percival 
3646ae1554aSColin Percival 	s1[0] = c1;
3656ae1554aSColin Percival 	s2[0] = c2;
3666ae1554aSColin Percival 	if ((ret = strcoll(s1, s2)) != 0)
3676ae1554aSColin Percival 		return (ret);
3686ae1554aSColin Percival 	return (c1 - c2);
3696ae1554aSColin Percival }
3706ae1554aSColin Percival 
3716ae1554aSColin Percival /*
3726ae1554aSColin Percival  * cmp_str:
3736ae1554aSColin Percival  *	Compare two strings in the file
3746ae1554aSColin Percival  */
3756ae1554aSColin Percival int
cmp_str(const void * s1,const void * s2)3766ae1554aSColin Percival cmp_str(const void *s1, const void *s2)
3776ae1554aSColin Percival {
3786ae1554aSColin Percival 	const STR *p1, *p2;
3796ae1554aSColin Percival 	int c1, c2, n1, n2, r;
3806ae1554aSColin Percival 
3816ae1554aSColin Percival #define	SET_N(nf,ch)	(nf = (ch == '\n'))
3826ae1554aSColin Percival #define	IS_END(ch,nf)	(ch == EOF || (ch == (unsigned char)Delimch && nf))
3836ae1554aSColin Percival 
3846ae1554aSColin Percival 	p1 = (const STR *)s1;
3856ae1554aSColin Percival 	p2 = (const STR *)s2;
3866ae1554aSColin Percival 
3876ae1554aSColin Percival 	c1 = (unsigned char)p1->first;
3886ae1554aSColin Percival 	c2 = (unsigned char)p2->first;
3896ae1554aSColin Percival 	if ((r = stable_collate_range_cmp(c1, c2)) != 0)
3906ae1554aSColin Percival 		return (r);
3916ae1554aSColin Percival 
3926ae1554aSColin Percival 	fseeko(Sort_1, p1->pos, SEEK_SET);
3936ae1554aSColin Percival 	fseeko(Sort_2, p2->pos, SEEK_SET);
3946ae1554aSColin Percival 
3956ae1554aSColin Percival 	n1 = false;
3966ae1554aSColin Percival 	n2 = false;
3976ae1554aSColin Percival 	while (!isalnum(c1 = getc(Sort_1)) && c1 != '\0' && c1 != EOF)
3986ae1554aSColin Percival 		SET_N(n1, c1);
3996ae1554aSColin Percival 	while (!isalnum(c2 = getc(Sort_2)) && c2 != '\0' && c2 != EOF)
4006ae1554aSColin Percival 		SET_N(n2, c2);
4016ae1554aSColin Percival 
4026ae1554aSColin Percival 	while (!IS_END(c1, n1) && !IS_END(c2, n2)) {
4036ae1554aSColin Percival 		if (Iflag) {
4046ae1554aSColin Percival 			if (isupper(c1))
4056ae1554aSColin Percival 				c1 = tolower(c1);
4066ae1554aSColin Percival 			if (isupper(c2))
4076ae1554aSColin Percival 				c2 = tolower(c2);
4086ae1554aSColin Percival 		}
4096ae1554aSColin Percival 		if ((r = stable_collate_range_cmp(c1, c2)) != 0)
4106ae1554aSColin Percival 			return (r);
4116ae1554aSColin Percival 		SET_N(n1, c1);
4126ae1554aSColin Percival 		SET_N(n2, c2);
4136ae1554aSColin Percival 		c1 = getc(Sort_1);
4146ae1554aSColin Percival 		c2 = getc(Sort_2);
4156ae1554aSColin Percival 	}
4166ae1554aSColin Percival 	if (IS_END(c1, n1))
4176ae1554aSColin Percival 		c1 = 0;
4186ae1554aSColin Percival 	if (IS_END(c2, n2))
4196ae1554aSColin Percival 		c2 = 0;
4206ae1554aSColin Percival 
4216ae1554aSColin Percival 	return (stable_collate_range_cmp(c1, c2));
4226ae1554aSColin Percival }
4236ae1554aSColin Percival 
4246ae1554aSColin Percival /*
4256ae1554aSColin Percival  * randomize:
4266ae1554aSColin Percival  *	Randomize the order of the string table.  We must be careful
4276ae1554aSColin Percival  *	not to randomize across delimiter boundaries.  All
4286ae1554aSColin Percival  *	randomization is done within each block.
4296ae1554aSColin Percival  */
4306ae1554aSColin Percival void
randomize(void)4316ae1554aSColin Percival randomize(void)
4326ae1554aSColin Percival {
4336ae1554aSColin Percival 	uint32_t cnt, i;
4346ae1554aSColin Percival 	off_t tmp;
4356ae1554aSColin Percival 	off_t *sp;
4366ae1554aSColin Percival 
4376ae1554aSColin Percival 	Tbl.str_flags |= STR_RANDOM;
4386ae1554aSColin Percival 	cnt = Tbl.str_numstr;
4396ae1554aSColin Percival 
4406ae1554aSColin Percival 	/*
4416ae1554aSColin Percival 	 * move things around randomly
4426ae1554aSColin Percival 	 */
4436ae1554aSColin Percival 
4446ae1554aSColin Percival 	for (sp = Seekpts; cnt > 0; cnt--, sp++) {
4456ae1554aSColin Percival 		i = arc4random_uniform(cnt);
4466ae1554aSColin Percival 		tmp = sp[0];
4476ae1554aSColin Percival 		sp[0] = sp[i];
4486ae1554aSColin Percival 		sp[i] = tmp;
4496ae1554aSColin Percival 	}
4506ae1554aSColin Percival }
451