xref: /plan9/sys/lib/man/permind/ptx1.c (revision b873a79ae9b6942791b873dd7fa2c27224798319)
1*b873a79aSDavid du Colombier /*
2*b873a79aSDavid du Colombier 	permuted title index
3219b2ee8SDavid du Colombier 	ptx [-t] [-i ignore] [-o only] [-w num] [-r]
4219b2ee8SDavid du Colombier 	    [-c commands] [-g gap] [-f] [input]
5*b873a79aSDavid du Colombier 
6219b2ee8SDavid du Colombier 	Ptx reads the input file and permutes on words in it.
7219b2ee8SDavid du Colombier 	It excludes all words in the ignore file.
8219b2ee8SDavid du Colombier 	Alternately it includes words in the only file.
9219b2ee8SDavid du Colombier 	if neither is given it excludes the words in
10*b873a79aSDavid du Colombier 	/sys/lib/man/permind/ignore.
11219b2ee8SDavid du Colombier 
12219b2ee8SDavid du Colombier 	The width of the output line (except for -r field)
13219b2ee8SDavid du Colombier 	can be changed to num,
14219b2ee8SDavid du Colombier 	which is a troff width measure, ens by default.
15219b2ee8SDavid du Colombier 	with no -w, num is 72n, or 100n under -t.
16219b2ee8SDavid du Colombier 	the -f flag tells the program to fold the output
17219b2ee8SDavid du Colombier 	the -t flag says the output is for troff
18219b2ee8SDavid du Colombier 	font specifier -F implies -t.
19219b2ee8SDavid du Colombier 	-g sets the gutter
20219b2ee8SDavid du Colombier 	-h sets the hole between wrapped segments
21219b2ee8SDavid du Colombier 	-r takes the first word on each line and makes it
22219b2ee8SDavid du Colombier 	into a fifth field.
23219b2ee8SDavid du Colombier 	-c inserts troff commands for font-setting etc at beginning
24219b2ee8SDavid du Colombier  */
25219b2ee8SDavid du Colombier 
26219b2ee8SDavid du Colombier #include <u.h>
27219b2ee8SDavid du Colombier #include <libc.h>
28219b2ee8SDavid du Colombier #include <stdio.h>
29219b2ee8SDavid du Colombier #include <ctype.h>
30*b873a79aSDavid du Colombier 
31219b2ee8SDavid du Colombier #define DEFLTX "/sys/lib/man/permind/ignore"
32*b873a79aSDavid du Colombier #define TILDE	0177		/* actually RUBOUT, not ~ */
33219b2ee8SDavid du Colombier #define	N	30
34219b2ee8SDavid du Colombier #define	MAX	N*BUFSIZ
35219b2ee8SDavid du Colombier #define LMAX	2048
36219b2ee8SDavid du Colombier #define MAXT	2048
37219b2ee8SDavid du Colombier #define MASK	03777
38219b2ee8SDavid du Colombier #define ON	1
39219b2ee8SDavid du Colombier 
40219b2ee8SDavid du Colombier #define isabreak(c) (btable[c])
41219b2ee8SDavid du Colombier 
42219b2ee8SDavid du Colombier char *getline(void);
43219b2ee8SDavid du Colombier void msg(char *, char *);
44219b2ee8SDavid du Colombier void extra(int);
45219b2ee8SDavid du Colombier void diag(char *, char *);
46219b2ee8SDavid du Colombier void cmpline(char *);
47219b2ee8SDavid du Colombier int cmpword(char *, char *, char *);
48219b2ee8SDavid du Colombier void putline(char *, char *);
49219b2ee8SDavid du Colombier void makek(void);
50219b2ee8SDavid du Colombier void getsort(void);
51219b2ee8SDavid du Colombier char *rtrim(char *, char *, int);
52219b2ee8SDavid du Colombier char *ltrim(char *, char *, int);
53219b2ee8SDavid du Colombier void putout(char *, char *);
54219b2ee8SDavid du Colombier void setlen(void);
55219b2ee8SDavid du Colombier void getlen(void);
56219b2ee8SDavid du Colombier int hash(char *, char *);
57219b2ee8SDavid du Colombier int storeh(int, char *);
58219b2ee8SDavid du Colombier 
59219b2ee8SDavid du Colombier int status;
60219b2ee8SDavid du Colombier 
61219b2ee8SDavid du Colombier char *hasht[MAXT];
62219b2ee8SDavid du Colombier char line[LMAX];
63219b2ee8SDavid du Colombier char mark[LMAX];
64219b2ee8SDavid du Colombier struct word {
65219b2ee8SDavid du Colombier 	char *p;
66219b2ee8SDavid du Colombier 	int w;
67219b2ee8SDavid du Colombier } word[LMAX/2];
68219b2ee8SDavid du Colombier char btable[256];
69219b2ee8SDavid du Colombier int ignore;
70219b2ee8SDavid du Colombier int only;
71219b2ee8SDavid du Colombier char *lenarg;
72219b2ee8SDavid du Colombier char *gutarg;
73219b2ee8SDavid du Colombier char *holarg;
74219b2ee8SDavid du Colombier int llen;
75219b2ee8SDavid du Colombier int spacesl;
76219b2ee8SDavid du Colombier int gutter;
77219b2ee8SDavid du Colombier int hole;
78219b2ee8SDavid du Colombier int mlen = LMAX;
79219b2ee8SDavid du Colombier int halflen;
80219b2ee8SDavid du Colombier int rflag;
81219b2ee8SDavid du Colombier char *strtbufp, *endbufp;
82219b2ee8SDavid du Colombier 
83219b2ee8SDavid du Colombier 
84219b2ee8SDavid du Colombier char *empty = "";
85219b2ee8SDavid du Colombier char *font = "R";
86219b2ee8SDavid du Colombier char *roff = "/bin/nroff";
87219b2ee8SDavid du Colombier char *troff = "/bin/troff";
88219b2ee8SDavid du Colombier 
89219b2ee8SDavid du Colombier char *infile = "/fd/0";
90219b2ee8SDavid du Colombier FILE *inptr;
91219b2ee8SDavid du Colombier 
92219b2ee8SDavid du Colombier FILE *outptr = stdout;
93219b2ee8SDavid du Colombier 
94219b2ee8SDavid du Colombier char *sortfile = "ptxsort";	/* output of sort program */
95219b2ee8SDavid du Colombier char nofold[] = {'-', 'd', 't', TILDE, 0};
96219b2ee8SDavid du Colombier char fold[] = {'-', 'd', 'f', 't', TILDE, 0};
97219b2ee8SDavid du Colombier char *sortopt = nofold;
98219b2ee8SDavid du Colombier FILE *sortptr;
99219b2ee8SDavid du Colombier 
100219b2ee8SDavid du Colombier char *kfile = "ptxmark";	/* ptxsort + troff goo for widths */
101219b2ee8SDavid du Colombier FILE *kptr;
102219b2ee8SDavid du Colombier 
103219b2ee8SDavid du Colombier char *wfile = "ptxwidth";	/* widths of words in ptxsort */
104219b2ee8SDavid du Colombier FILE *wptr;
105219b2ee8SDavid du Colombier 
106219b2ee8SDavid du Colombier char *bfile;	/*contains user supplied break chars */
107219b2ee8SDavid du Colombier FILE *bptr;
108219b2ee8SDavid du Colombier 
109219b2ee8SDavid du Colombier char *cmds;
110219b2ee8SDavid du Colombier 
main(int argc,char ** argv)111219b2ee8SDavid du Colombier main(int argc, char **argv)
112219b2ee8SDavid du Colombier {
113219b2ee8SDavid du Colombier 	int c;
114219b2ee8SDavid du Colombier 	char *bufp;
115219b2ee8SDavid du Colombier 	char *pend;
116219b2ee8SDavid du Colombier 	char *xfile;
117219b2ee8SDavid du Colombier 	FILE *xptr;
1189a747e4fSDavid du Colombier 	Waitmsg *w;
119219b2ee8SDavid du Colombier 
120219b2ee8SDavid du Colombier 	/* argument decoding */
121219b2ee8SDavid du Colombier 	xfile = DEFLTX;
122219b2ee8SDavid du Colombier 	ARGBEGIN {
123219b2ee8SDavid du Colombier 	case 'r':
124219b2ee8SDavid du Colombier 		rflag = 1;
125219b2ee8SDavid du Colombier 		break;
126219b2ee8SDavid du Colombier 	case 'f':
127219b2ee8SDavid du Colombier 		sortopt = fold;
128219b2ee8SDavid du Colombier 		break;
129219b2ee8SDavid du Colombier 	case 'w':
130219b2ee8SDavid du Colombier 		if(lenarg)
131219b2ee8SDavid du Colombier 			extra(ARGC());
132219b2ee8SDavid du Colombier 		lenarg = ARGF();
133219b2ee8SDavid du Colombier 		break;
134219b2ee8SDavid du Colombier 	case 'c':
135219b2ee8SDavid du Colombier 		if(cmds)
136219b2ee8SDavid du Colombier 			extra(ARGC());
137219b2ee8SDavid du Colombier 		cmds = ARGF();
138219b2ee8SDavid du Colombier 	case 't':
139219b2ee8SDavid du Colombier 		roff = troff;
140219b2ee8SDavid du Colombier 		break;
141219b2ee8SDavid du Colombier 	case 'g':
142219b2ee8SDavid du Colombier 		if(gutarg)
143219b2ee8SDavid du Colombier 			extra(ARGC());
144219b2ee8SDavid du Colombier 		gutarg =  ARGF();
145219b2ee8SDavid du Colombier 		break;
146219b2ee8SDavid du Colombier 	case 'h':
147219b2ee8SDavid du Colombier 		if(holarg)
148219b2ee8SDavid du Colombier 			extra(ARGC());
149219b2ee8SDavid du Colombier 		holarg =  ARGF();
150219b2ee8SDavid du Colombier 		break;
151219b2ee8SDavid du Colombier 
152219b2ee8SDavid du Colombier 	case 'i':
153219b2ee8SDavid du Colombier 		if(only|ignore)
154219b2ee8SDavid du Colombier 			extra(ARGC());
155219b2ee8SDavid du Colombier 		ignore++;
156219b2ee8SDavid du Colombier 		xfile = ARGF();
157219b2ee8SDavid du Colombier 		break;
158219b2ee8SDavid du Colombier 
159219b2ee8SDavid du Colombier 	case 'o':
160219b2ee8SDavid du Colombier 		if(only|ignore)
161219b2ee8SDavid du Colombier 			extra(ARGC());
162219b2ee8SDavid du Colombier 		only++;
163219b2ee8SDavid du Colombier 		xfile = ARGF();
164219b2ee8SDavid du Colombier 		break;
165219b2ee8SDavid du Colombier 
166219b2ee8SDavid du Colombier 	case 'b':
167219b2ee8SDavid du Colombier 		if(bfile)
168219b2ee8SDavid du Colombier 			extra(ARGC());
169219b2ee8SDavid du Colombier 		bfile = ARGF();
170219b2ee8SDavid du Colombier 		break;
171219b2ee8SDavid du Colombier 
172219b2ee8SDavid du Colombier 	default:
173219b2ee8SDavid du Colombier 		diag("Illegal argument:",*argv);
174219b2ee8SDavid du Colombier 	} ARGEND
175219b2ee8SDavid du Colombier 
176219b2ee8SDavid du Colombier 	if(lenarg == 0)
177219b2ee8SDavid du Colombier 		lenarg = troff? "100n": "72n";
178219b2ee8SDavid du Colombier 	if(gutarg == 0)
179219b2ee8SDavid du Colombier 		gutarg = "3n";
180219b2ee8SDavid du Colombier 	if(holarg == 0)
181219b2ee8SDavid du Colombier 		holarg = gutarg;
182219b2ee8SDavid du Colombier 
183219b2ee8SDavid du Colombier 	if(argc > 1)
184219b2ee8SDavid du Colombier 		diag("Too many filenames",empty);
185219b2ee8SDavid du Colombier 	if(argc == 1)
186219b2ee8SDavid du Colombier 		infile = *argv;
187219b2ee8SDavid du Colombier 
188219b2ee8SDavid du Colombier 	/* Default breaks of blank, tab and newline */
189219b2ee8SDavid du Colombier 	btable[' '] = ON;
190219b2ee8SDavid du Colombier 	btable['\t'] = ON;
191219b2ee8SDavid du Colombier 	btable['\n'] = ON;
192219b2ee8SDavid du Colombier 	if(bfile) {
193219b2ee8SDavid du Colombier 		if((bptr = fopen(bfile,"r")) == NULL)
194219b2ee8SDavid du Colombier 			diag("Cannot open break char file",bfile);
195219b2ee8SDavid du Colombier 
196219b2ee8SDavid du Colombier 		while((c = getc(bptr)) != EOF)
197219b2ee8SDavid du Colombier 			btable[c] = ON;
198219b2ee8SDavid du Colombier 	}
199219b2ee8SDavid du Colombier 
200*b873a79aSDavid du Colombier 	/*
201*b873a79aSDavid du Colombier 	Allocate space for a buffer.  If only or ignore file present
202219b2ee8SDavid du Colombier 	read it into buffer. Else read in default ignore file
203219b2ee8SDavid du Colombier 	and put resulting words in buffer.
204219b2ee8SDavid du Colombier 	*/
205219b2ee8SDavid du Colombier 
206219b2ee8SDavid du Colombier 	if((strtbufp = calloc(N,BUFSIZ)) == NULL)
207219b2ee8SDavid du Colombier 		diag("Out of memory space",empty);
208219b2ee8SDavid du Colombier 	bufp = strtbufp;
209219b2ee8SDavid du Colombier 	endbufp = strtbufp+MAX;
210219b2ee8SDavid du Colombier 
211219b2ee8SDavid du Colombier 	if((xptr = fopen(xfile,"r")) == NULL)
212219b2ee8SDavid du Colombier 		diag("Cannot open  file",xfile);
213219b2ee8SDavid du Colombier 
214*b873a79aSDavid du Colombier 	while(bufp < endbufp && (c = getc(xptr)) != EOF)
215219b2ee8SDavid du Colombier 		if(isabreak(c)) {
216219b2ee8SDavid du Colombier 			if(storeh(hash(strtbufp,bufp),strtbufp))
217219b2ee8SDavid du Colombier 				diag("Too many words",xfile);
218219b2ee8SDavid du Colombier 			*bufp++ = '\0';
219219b2ee8SDavid du Colombier 			strtbufp = bufp;
220*b873a79aSDavid du Colombier 		} else
221219b2ee8SDavid du Colombier 			*bufp++ = (isupper(c)?tolower(c):c);
222219b2ee8SDavid du Colombier 	if (bufp >= endbufp)
223219b2ee8SDavid du Colombier 		diag("Too many words in file",xfile);
224219b2ee8SDavid du Colombier 	endbufp = --bufp;
225219b2ee8SDavid du Colombier 
226219b2ee8SDavid du Colombier 	/* open output file for sorting */
227219b2ee8SDavid du Colombier 
228219b2ee8SDavid du Colombier 	if((sortptr = fopen(sortfile, "w")) == NULL)
229219b2ee8SDavid du Colombier 		diag("Cannot open output for sorting:",sortfile);
230219b2ee8SDavid du Colombier 
231*b873a79aSDavid du Colombier 	/*
232*b873a79aSDavid du Colombier 	get a line of data and compare each word for
233219b2ee8SDavid du Colombier 	inclusion or exclusion in the sort phase
234219b2ee8SDavid du Colombier 	*/
235219b2ee8SDavid du Colombier 	if (infile!=0 && (inptr = fopen(infile,"r")) == NULL)
236219b2ee8SDavid du Colombier 		diag("Cannot open data: ",infile);
237*b873a79aSDavid du Colombier 	while((pend = getline()) != NULL)
238219b2ee8SDavid du Colombier 		cmpline(pend);
239219b2ee8SDavid du Colombier 	fclose(sortptr);
240219b2ee8SDavid du Colombier 
241219b2ee8SDavid du Colombier 	if(fork()==0){
242219b2ee8SDavid du Colombier 		execl("/bin/sort", "sort", sortopt, "+0", "-1", "+1",
243219b2ee8SDavid du Colombier 			sortfile, "-o", sortfile, 0);
244219b2ee8SDavid du Colombier 		diag("Sort exec failed","");
245219b2ee8SDavid du Colombier 	}
246*b873a79aSDavid du Colombier 	if((w = wait()) == NULL || w->msg[0] != '\0')
247219b2ee8SDavid du Colombier 		diag("Sort failed","");
2489a747e4fSDavid du Colombier 	free(w);
249219b2ee8SDavid du Colombier 
250219b2ee8SDavid du Colombier 	makek();
251219b2ee8SDavid du Colombier 	if(fork()==0){
252219b2ee8SDavid du Colombier 		if(dup(create(wfile,OWRITE|OTRUNC,0666),1) == -1)
253219b2ee8SDavid du Colombier 			diag("Cannot create width file:",wfile);
254219b2ee8SDavid du Colombier 		execl(roff, roff, "-a", kfile, 0);
255219b2ee8SDavid du Colombier 		diag("Sort exec failed","");
256219b2ee8SDavid du Colombier 	}
257*b873a79aSDavid du Colombier 	if((w = wait()) == NULL || w->msg[0] != '\0')
258219b2ee8SDavid du Colombier 		diag("Sort failed","");
2599a747e4fSDavid du Colombier 	free(w);
260219b2ee8SDavid du Colombier 
261219b2ee8SDavid du Colombier 	getsort();
262*b873a79aSDavid du Colombier /*
263*b873a79aSDavid du Colombier 	remove(sortfile);
264*b873a79aSDavid du Colombier 	remove(kfile);
265*b873a79aSDavid du Colombier  */
266219b2ee8SDavid du Colombier 	fflush(0);
267219b2ee8SDavid du Colombier 	_exits(0);
268219b2ee8SDavid du Colombier /* I don't know what's wrong with the atexit func... */
269219b2ee8SDavid du Colombier /*	exits(0);	*/
270219b2ee8SDavid du Colombier }
271219b2ee8SDavid du Colombier 
272219b2ee8SDavid du Colombier void
msg(char * s,char * arg)273219b2ee8SDavid du Colombier msg(char *s, char *arg)
274219b2ee8SDavid du Colombier {
275219b2ee8SDavid du Colombier 	fprintf(stderr,"ptx: %s %s\n",s,arg);
276219b2ee8SDavid du Colombier }
277219b2ee8SDavid du Colombier 
278219b2ee8SDavid du Colombier void
extra(int c)279219b2ee8SDavid du Colombier extra(int c)
280219b2ee8SDavid du Colombier {
281219b2ee8SDavid du Colombier 	char s[] = "-x.";
282*b873a79aSDavid du Colombier 
283219b2ee8SDavid du Colombier 	s[1] = c;
284219b2ee8SDavid du Colombier 	diag("Extra option", s);
285219b2ee8SDavid du Colombier }
286219b2ee8SDavid du Colombier 
287219b2ee8SDavid du Colombier void
diag(char * s,char * arg)288219b2ee8SDavid du Colombier diag(char *s, char *arg)
289219b2ee8SDavid du Colombier {
290219b2ee8SDavid du Colombier 	msg(s,arg);
291219b2ee8SDavid du Colombier /*
292219b2ee8SDavid du Colombier 	remove(sortfile);
293219b2ee8SDavid du Colombier 	remove(kfile);
294219b2ee8SDavid du Colombier */
295219b2ee8SDavid du Colombier 	exits(s);
296219b2ee8SDavid du Colombier }
297219b2ee8SDavid du Colombier 
298219b2ee8SDavid du Colombier 
299219b2ee8SDavid du Colombier char*
getline(void)300219b2ee8SDavid du Colombier getline(void)
301219b2ee8SDavid du Colombier {
302219b2ee8SDavid du Colombier 	int c;
303219b2ee8SDavid du Colombier 	char *linep;
304219b2ee8SDavid du Colombier 	char *endlinep;
305219b2ee8SDavid du Colombier 
306219b2ee8SDavid du Colombier 	endlinep= line + mlen;
307219b2ee8SDavid du Colombier 	linep = line;
308219b2ee8SDavid du Colombier 	/* Throw away leading white space */
309219b2ee8SDavid du Colombier 
310219b2ee8SDavid du Colombier 	while(isspace(c = getc(inptr)))
311219b2ee8SDavid du Colombier 		;
312219b2ee8SDavid du Colombier 	if(c==EOF)
313219b2ee8SDavid du Colombier 		return(0);
314219b2ee8SDavid du Colombier 	ungetc(c,inptr);
315*b873a79aSDavid du Colombier 	while((c = getc(inptr)) != EOF)
316219b2ee8SDavid du Colombier 		switch (c) {
317219b2ee8SDavid du Colombier 		case '\t':
318219b2ee8SDavid du Colombier 			if(linep<endlinep)
319219b2ee8SDavid du Colombier 				*linep++ = ' ';
320219b2ee8SDavid du Colombier 			break;
321219b2ee8SDavid du Colombier 		case '\n':
322*b873a79aSDavid du Colombier 			while(isspace(*--linep))
323*b873a79aSDavid du Colombier 				;
324219b2ee8SDavid du Colombier 			*++linep = '\n';
325219b2ee8SDavid du Colombier 			return(linep);
326219b2ee8SDavid du Colombier 		default:
327219b2ee8SDavid du Colombier 			if(linep < endlinep)
328219b2ee8SDavid du Colombier 				*linep++ = c;
329*b873a79aSDavid du Colombier 			break;
330219b2ee8SDavid du Colombier 		}
331219b2ee8SDavid du Colombier 	return(0);
332219b2ee8SDavid du Colombier }
333219b2ee8SDavid du Colombier 
334219b2ee8SDavid du Colombier void
cmpline(char * pend)335219b2ee8SDavid du Colombier cmpline(char *pend)
336219b2ee8SDavid du Colombier {
337219b2ee8SDavid du Colombier 	char *pstrt, *pchar, *cp;
338219b2ee8SDavid du Colombier 	char **hp;
339219b2ee8SDavid du Colombier 	int flag;
340219b2ee8SDavid du Colombier 
341219b2ee8SDavid du Colombier 	pchar = line;
342219b2ee8SDavid du Colombier 	if(rflag)
343219b2ee8SDavid du Colombier 		while(pchar < pend && !isspace(*pchar))
344219b2ee8SDavid du Colombier 			pchar++;
345219b2ee8SDavid du Colombier 	while(pchar < pend){
346219b2ee8SDavid du Colombier 		/* eliminate white space */
347219b2ee8SDavid du Colombier 		if(isabreak(*pchar++))
348219b2ee8SDavid du Colombier 			continue;
349219b2ee8SDavid du Colombier 		pstrt = --pchar;
350219b2ee8SDavid du Colombier 
351219b2ee8SDavid du Colombier 		flag = 1;
352219b2ee8SDavid du Colombier 		while(flag){
353219b2ee8SDavid du Colombier 			if(isabreak(*pchar)) {
354219b2ee8SDavid du Colombier 				hp = &hasht[hash(pstrt,pchar)];
355219b2ee8SDavid du Colombier 				pchar--;
356219b2ee8SDavid du Colombier 				while(cp = *hp++){
357219b2ee8SDavid du Colombier 					if(hp == &hasht[MAXT])
358219b2ee8SDavid du Colombier 						hp = hasht;
359219b2ee8SDavid du Colombier 					/* possible match */
360219b2ee8SDavid du Colombier 					if(cmpword(pstrt,pchar,cp)){
361219b2ee8SDavid du Colombier 						/* exact match */
362219b2ee8SDavid du Colombier 						if(!ignore && only)
363219b2ee8SDavid du Colombier 							putline(pstrt,pend);
364219b2ee8SDavid du Colombier 						flag = 0;
365219b2ee8SDavid du Colombier 						break;
366219b2ee8SDavid du Colombier 					}
367219b2ee8SDavid du Colombier 				}
368219b2ee8SDavid du Colombier 				/* no match */
369219b2ee8SDavid du Colombier 				if(flag){
370219b2ee8SDavid du Colombier 					if(ignore || !only)
371219b2ee8SDavid du Colombier 						putline(pstrt,pend);
372219b2ee8SDavid du Colombier 					flag = 0;
373219b2ee8SDavid du Colombier 				}
374219b2ee8SDavid du Colombier 			}
375219b2ee8SDavid du Colombier 			pchar++;
376219b2ee8SDavid du Colombier 		}
377219b2ee8SDavid du Colombier 	}
378219b2ee8SDavid du Colombier }
379219b2ee8SDavid du Colombier 
380219b2ee8SDavid du Colombier int
cmpword(char * cpp,char * pend,char * hpp)381219b2ee8SDavid du Colombier cmpword(char *cpp, char *pend, char *hpp)
382219b2ee8SDavid du Colombier {
383219b2ee8SDavid du Colombier 	char c;
384219b2ee8SDavid du Colombier 
385219b2ee8SDavid du Colombier 	while(*hpp != '\0'){
386219b2ee8SDavid du Colombier 		c = *cpp++;
387219b2ee8SDavid du Colombier 		if((isupper(c)?tolower(c):c) != *hpp++)
388219b2ee8SDavid du Colombier 			return(0);
389219b2ee8SDavid du Colombier 	}
390*b873a79aSDavid du Colombier 	if(--cpp == pend)
391*b873a79aSDavid du Colombier 		return(1);
392219b2ee8SDavid du Colombier 	return(0);
393219b2ee8SDavid du Colombier }
394219b2ee8SDavid du Colombier 
395219b2ee8SDavid du Colombier void
putline(char * strt,char * end)396219b2ee8SDavid du Colombier putline(char *strt, char *end)
397219b2ee8SDavid du Colombier {
398219b2ee8SDavid du Colombier 	char *cp;
399219b2ee8SDavid du Colombier 
400219b2ee8SDavid du Colombier 	for(cp=strt; cp<end; cp++)
401219b2ee8SDavid du Colombier 		putc(*cp, sortptr);
402*b873a79aSDavid du Colombier 	/* Add extra blank before TILDE to sort correctly with -fd option */
403219b2ee8SDavid du Colombier 	putc(' ',sortptr);
404219b2ee8SDavid du Colombier 	putc(TILDE,sortptr);
405219b2ee8SDavid du Colombier 	for (cp=line; cp<strt; cp++)
406219b2ee8SDavid du Colombier 		putc(*cp,sortptr);
407219b2ee8SDavid du Colombier 	putc('\n',sortptr);
408219b2ee8SDavid du Colombier }
409219b2ee8SDavid du Colombier 
410219b2ee8SDavid du Colombier void
makek(void)411219b2ee8SDavid du Colombier makek(void)
412219b2ee8SDavid du Colombier {
413219b2ee8SDavid du Colombier 	int i, c;
414219b2ee8SDavid du Colombier 	int nr = 0;
415219b2ee8SDavid du Colombier 
416219b2ee8SDavid du Colombier 	if((sortptr = fopen(sortfile,"r")) == NULL)
417219b2ee8SDavid du Colombier 		diag("Cannot open sorted data:",sortfile);
418219b2ee8SDavid du Colombier 	if((kptr = fopen(kfile,"w")) == NULL)
419219b2ee8SDavid du Colombier 		diag("Cannot create mark file:",kfile);
420219b2ee8SDavid du Colombier 	if(cmds)
421219b2ee8SDavid du Colombier 		fprintf(kptr,"%s\n",cmds);
422219b2ee8SDavid du Colombier 	fprintf(kptr,
423219b2ee8SDavid du Colombier 		".nf\n"
424219b2ee8SDavid du Colombier 		".pl 1\n"
425219b2ee8SDavid du Colombier 		".tr %c\\&\n", TILDE);
426219b2ee8SDavid du Colombier 	setlen();
427219b2ee8SDavid du Colombier 
428219b2ee8SDavid du Colombier 	while((c = getc(sortptr)) != EOF) {
429219b2ee8SDavid du Colombier 		if(nr == 0) {
430219b2ee8SDavid du Colombier 			fprintf(kptr,".di xx\n");
431219b2ee8SDavid du Colombier 			nr++;
432219b2ee8SDavid du Colombier 		}
433219b2ee8SDavid du Colombier 		if(c == '\n') {
434219b2ee8SDavid du Colombier 			fprintf(kptr,"\n.di\n");
435219b2ee8SDavid du Colombier 			for(i=1; i<nr; i++)
436219b2ee8SDavid du Colombier 				fprintf(kptr,"\\n(%.2d ",i);
437219b2ee8SDavid du Colombier 			fprintf(kptr,"\n");
438219b2ee8SDavid du Colombier 			nr = 0;
439219b2ee8SDavid du Colombier 			continue;
440219b2ee8SDavid du Colombier 		}
441219b2ee8SDavid du Colombier 		if(isspace(c))
442219b2ee8SDavid du Colombier 			fprintf(kptr,"\\k(%.2d",nr++);
443219b2ee8SDavid du Colombier 		putc(c,kptr);
444219b2ee8SDavid du Colombier 	}
445219b2ee8SDavid du Colombier 	fclose(sortptr);
446219b2ee8SDavid du Colombier 	fclose(kptr);
447219b2ee8SDavid du Colombier }
448219b2ee8SDavid du Colombier 
449219b2ee8SDavid du Colombier void
getsort(void)450219b2ee8SDavid du Colombier getsort(void)
451219b2ee8SDavid du Colombier {
452219b2ee8SDavid du Colombier 	char *tilde, *linep, *markp;
453*b873a79aSDavid du Colombier 	int i0, i1, i2, i3, i4, i5, i6, i7, w0, w6;
454219b2ee8SDavid du Colombier 
455219b2ee8SDavid du Colombier 	if((sortptr = fopen(sortfile, "r")) == NULL)
456219b2ee8SDavid du Colombier 		diag("Cannot open sorted data:", sortfile);
457219b2ee8SDavid du Colombier 	if((wptr = fopen(wfile, "r")) == NULL)
458219b2ee8SDavid du Colombier 		diag("Cannot open width file:", wfile);
459219b2ee8SDavid du Colombier 	getlen();
460219b2ee8SDavid du Colombier 
461219b2ee8SDavid du Colombier 	halflen = (llen-gutter)/2;
462219b2ee8SDavid du Colombier 
463*b873a79aSDavid du Colombier 	while(fgets(line, sizeof(line), sortptr) != NULL) {
464*b873a79aSDavid du Colombier 		if(fgets(mark, sizeof(mark), wptr) == NULL)
465*b873a79aSDavid du Colombier 			diag("Phase error 1: premature EOF on width file",
466*b873a79aSDavid du Colombier 				wfile);
467219b2ee8SDavid du Colombier 		linep = line;
468219b2ee8SDavid du Colombier 		markp = mark;
469219b2ee8SDavid du Colombier 		i3 = i7 = 0;
470219b2ee8SDavid du Colombier 		word[i7].p = linep;
471219b2ee8SDavid du Colombier 		word[i7].w = 0;
472219b2ee8SDavid du Colombier 		for(linep=line; *linep; linep++) {
473219b2ee8SDavid du Colombier 			if(*linep == TILDE)
474219b2ee8SDavid du Colombier 				i3 = i7;
475219b2ee8SDavid du Colombier 			else if(*linep == '\n')
476219b2ee8SDavid du Colombier 				break;
477219b2ee8SDavid du Colombier 			else if(isspace(*linep)) {
478219b2ee8SDavid du Colombier 				i7++;
479219b2ee8SDavid du Colombier 				word[i7].p = linep;
480*b873a79aSDavid du Colombier 				if(!markp)
481*b873a79aSDavid du Colombier 					diag("Phase error 2: no widths for summary",
482*b873a79aSDavid du Colombier 						line);
483219b2ee8SDavid du Colombier 				word[i7].w = atoi(markp);
484219b2ee8SDavid du Colombier 				markp = strchr(markp+1, ' ');
485219b2ee8SDavid du Colombier 			}
486219b2ee8SDavid du Colombier 		}
487219b2ee8SDavid du Colombier 		i0 = 0;
488219b2ee8SDavid du Colombier 		for(i1=i0; i1<i3; i1++)
489219b2ee8SDavid du Colombier 			if(word[i1+1].w - word[i0].w >= halflen - spacesl)
490219b2ee8SDavid du Colombier 				break;
491219b2ee8SDavid du Colombier 		w0 = word[i1].w - word[i0].w;
492219b2ee8SDavid du Colombier 		i4 = i3 + rflag;
493219b2ee8SDavid du Colombier 		for(i6 = i7; i6>i4; i6--)
494219b2ee8SDavid du Colombier 			if(word[i7].w - word[i6-1].w >= halflen)
495219b2ee8SDavid du Colombier 				break;
496219b2ee8SDavid du Colombier 		w6 = word[i7].w - word[i6].w - spacesl;
497219b2ee8SDavid du Colombier 		for(i2=i1 ; i2<i3; i2++)
498219b2ee8SDavid du Colombier 			if(word[i2+1].w - word[i1].w + w6 >= halflen-hole)
499219b2ee8SDavid du Colombier 				break;
500219b2ee8SDavid du Colombier 		for(i5=i6; i5>i4; i5--)
501219b2ee8SDavid du Colombier 			if(word[i6].w - word[i5-1].w + w0 >= halflen-hole)
502219b2ee8SDavid du Colombier 				break;
503219b2ee8SDavid du Colombier 
504219b2ee8SDavid du Colombier 		printf(".xx \"");
505219b2ee8SDavid du Colombier 		putout(word[i1].p+1,word[i2].p);
506219b2ee8SDavid du Colombier 		if(i1<i2 && i2<i3) putchar('/');
507219b2ee8SDavid du Colombier 		printf("\" \"");
508219b2ee8SDavid du Colombier 		if(i5>i4 && i6==i5) putchar('/');
509219b2ee8SDavid du Colombier 		putout(word[i6].p+1+(i6==i3),word[i7].p);
510219b2ee8SDavid du Colombier 		printf("\" \"");
511219b2ee8SDavid du Colombier 		putout(word[i0].p,word[i1].p);
512219b2ee8SDavid du Colombier 		if(i2<i3 && i1==i2) putchar('/');
513219b2ee8SDavid du Colombier 		printf("\" \"");
514219b2ee8SDavid du Colombier 		if(i5>i4 && i6>i5) putchar('/');
515219b2ee8SDavid du Colombier 		putout(word[i5].p+1+(i5==i3),word[i6].p);
516219b2ee8SDavid du Colombier 		if(rflag) {
517219b2ee8SDavid du Colombier 			printf("\" \"");
518219b2ee8SDavid du Colombier 			putout(word[i3].p+2,word[i4].p);
519219b2ee8SDavid du Colombier 		}
520219b2ee8SDavid du Colombier 		printf("\"\n");
521219b2ee8SDavid du Colombier 	}
522219b2ee8SDavid du Colombier }
523219b2ee8SDavid du Colombier 
524219b2ee8SDavid du Colombier void
putout(char * strt,char * end)525219b2ee8SDavid du Colombier putout(char *strt, char *end)
526219b2ee8SDavid du Colombier {
527219b2ee8SDavid du Colombier 	char *cp;
528219b2ee8SDavid du Colombier 
529219b2ee8SDavid du Colombier 	for(cp=strt; cp<end; )
530219b2ee8SDavid du Colombier 		putc(*cp++,outptr);
531219b2ee8SDavid du Colombier }
532219b2ee8SDavid du Colombier 
533219b2ee8SDavid du Colombier void
setlen(void)534219b2ee8SDavid du Colombier setlen(void)
535219b2ee8SDavid du Colombier {
536219b2ee8SDavid du Colombier 	fprintf(kptr,
537219b2ee8SDavid du Colombier 		"\\w'\\h'%s''\n"
538219b2ee8SDavid du Colombier 		"\\w' /'\n"
539219b2ee8SDavid du Colombier 		"\\w'\\h'%s''\n"
540219b2ee8SDavid du Colombier 		"\\w'\\h'%s''\n",lenarg,gutarg,holarg);
541219b2ee8SDavid du Colombier }
542219b2ee8SDavid du Colombier 
543219b2ee8SDavid du Colombier void
getlen(void)544219b2ee8SDavid du Colombier getlen(void)
545219b2ee8SDavid du Colombier {
546*b873a79aSDavid du Colombier 	char s[128];
547*b873a79aSDavid du Colombier 
548*b873a79aSDavid du Colombier 	s[0] = '\0';
549219b2ee8SDavid du Colombier 	fgets(s,sizeof(s),kptr);
550219b2ee8SDavid du Colombier 	llen = atoi(s);
551219b2ee8SDavid du Colombier 
552219b2ee8SDavid du Colombier 	fgets(s,sizeof(s),kptr);
553219b2ee8SDavid du Colombier 	spacesl = atoi(s);
554219b2ee8SDavid du Colombier 
555219b2ee8SDavid du Colombier 	fgets(s,sizeof(s),kptr);
556219b2ee8SDavid du Colombier 	gutter = atoi(s);
557219b2ee8SDavid du Colombier 
558219b2ee8SDavid du Colombier 	fgets(s,sizeof(s),kptr);
559219b2ee8SDavid du Colombier 	hole = atoi(s);
560219b2ee8SDavid du Colombier 	if(hole < 2*spacesl)
561219b2ee8SDavid du Colombier 		hole = 2*spacesl;
562219b2ee8SDavid du Colombier }
563219b2ee8SDavid du Colombier 
564219b2ee8SDavid du Colombier int
hash(char * strtp,char * endp)565219b2ee8SDavid du Colombier hash(char *strtp, char *endp)
566219b2ee8SDavid du Colombier {
567219b2ee8SDavid du Colombier 	char *cp, c;
568219b2ee8SDavid du Colombier 	int i, j, k;
569219b2ee8SDavid du Colombier 
570219b2ee8SDavid du Colombier 	/* Return zero hash number for single letter words */
571219b2ee8SDavid du Colombier 	if((endp - strtp) == 1)
572219b2ee8SDavid du Colombier 		return(0);
573219b2ee8SDavid du Colombier 
574219b2ee8SDavid du Colombier 	cp = strtp;
575219b2ee8SDavid du Colombier 	c = *cp++;
576219b2ee8SDavid du Colombier 	i = (isupper(c)?tolower(c):c);
577219b2ee8SDavid du Colombier 	c = *cp;
578219b2ee8SDavid du Colombier 	j = (isupper(c)?tolower(c):c);
579219b2ee8SDavid du Colombier 	i = i*j;
580219b2ee8SDavid du Colombier 	cp = --endp;
581219b2ee8SDavid du Colombier 	c = *cp--;
582219b2ee8SDavid du Colombier 	k = (isupper(c)?tolower(c):c);
583219b2ee8SDavid du Colombier 	c = *cp;
584219b2ee8SDavid du Colombier 	j = (isupper(c)?tolower(c):c);
585219b2ee8SDavid du Colombier 	j = k*j;
586*b873a79aSDavid du Colombier 	return (i ^ (j>>2)) & MASK;
587219b2ee8SDavid du Colombier }
588219b2ee8SDavid du Colombier 
589219b2ee8SDavid du Colombier int
storeh(int num,char * strtp)590219b2ee8SDavid du Colombier storeh(int num, char *strtp)
591219b2ee8SDavid du Colombier {
592219b2ee8SDavid du Colombier 	int i;
593219b2ee8SDavid du Colombier 
594*b873a79aSDavid du Colombier 	for(i=num; i<MAXT; i++)
595219b2ee8SDavid du Colombier 		if(hasht[i] == 0) {
596219b2ee8SDavid du Colombier 			hasht[i] = strtp;
597219b2ee8SDavid du Colombier 			return(0);
598219b2ee8SDavid du Colombier 		}
599*b873a79aSDavid du Colombier 	for(i=0; i<num; i++)
600219b2ee8SDavid du Colombier 		if(hasht[i] == 0) {
601219b2ee8SDavid du Colombier 			hasht[i] = strtp;
602219b2ee8SDavid du Colombier 			return(0);
603219b2ee8SDavid du Colombier 		}
604219b2ee8SDavid du Colombier 	return(1);
605219b2ee8SDavid du Colombier }
606