Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
	permuted title index
3
	ptx [-t] [-i ignore] [-o only] [-w num] [-r]
4
	    [-c commands] [-g gap] [-f] [input]
5
 
6
	Ptx reads the input file and permutes on words in it.
7
	It excludes all words in the ignore file.
8
	Alternately it includes words in the only file.
9
	if neither is given it excludes the words in
10
	/sys/lib/man/permind/ignore.
11
 
12
	The width of the output line (except for -r field)
13
	can be changed to num,
14
	which is a troff width measure, ens by default.
15
	with no -w, num is 72n, or 100n under -t.
16
	the -f flag tells the program to fold the output
17
	the -t flag says the output is for troff
18
	font specifier -F implies -t.
19
	-g sets the gutter
20
	-h sets the hole between wrapped segments
21
	-r takes the first word on each line and makes it
22
	into a fifth field.
23
	-c inserts troff commands for font-setting etc at beginning
24
 */
25
 
26
#include <u.h>
27
#include <libc.h>
28
#include <stdio.h>
29
#include <ctype.h>
30
 
31
#define DEFLTX "/sys/lib/man/permind/ignore"
32
#define TILDE	0177		/* actually RUBOUT, not ~ */
33
#define	N	30
34
#define	MAX	N*BUFSIZ
35
#define LMAX	2048
36
#define MAXT	2048
37
#define MASK	03777
38
#define ON	1
39
 
40
#define isabreak(c) (btable[c])
41
 
42
char *getline(void);
43
void msg(char *, char *);
44
void extra(int);
45
void diag(char *, char *);
46
void cmpline(char *);
47
int cmpword(char *, char *, char *);
48
void putline(char *, char *);
49
void makek(void);
50
void getsort(void);
51
char *rtrim(char *, char *, int);
52
char *ltrim(char *, char *, int);
53
void putout(char *, char *);
54
void setlen(void);
55
void getlen(void);
56
int hash(char *, char *);
57
int storeh(int, char *);
58
 
59
int status;
60
 
61
char *hasht[MAXT];
62
char line[LMAX];
63
char mark[LMAX];
64
struct word {
65
	char *p;
66
	int w;
67
} word[LMAX/2];
68
char btable[256];
69
int ignore;
70
int only;
71
char *lenarg;
72
char *gutarg;
73
char *holarg;
74
int llen;
75
int spacesl;
76
int gutter;
77
int hole;
78
int mlen = LMAX;
79
int halflen;
80
int rflag;
81
char *strtbufp, *endbufp;
82
 
83
 
84
char *empty = "";
85
char *font = "R";
86
char *roff = "/bin/nroff";
87
char *troff = "/bin/troff";
88
 
89
char *infile = "/fd/0";
90
FILE *inptr;
91
 
92
FILE *outptr = stdout;
93
 
94
char *sortfile = "ptxsort";	/* output of sort program */
95
char nofold[] = {'-', 'd', 't', TILDE, 0};
96
char fold[] = {'-', 'd', 'f', 't', TILDE, 0};
97
char *sortopt = nofold;
98
FILE *sortptr;
99
 
100
char *kfile = "ptxmark";	/* ptxsort + troff goo for widths */
101
FILE *kptr;
102
 
103
char *wfile = "ptxwidth";	/* widths of words in ptxsort */
104
FILE *wptr;
105
 
106
char *bfile;	/*contains user supplied break chars */
107
FILE *bptr;
108
 
109
char *cmds;
110
 
111
main(int argc, char **argv)
112
{
113
	int c;
114
	char *bufp;
115
	char *pend;
116
	char *xfile;
117
	FILE *xptr;
118
	Waitmsg *w;
119
 
120
	/* argument decoding */
121
	xfile = DEFLTX;
122
	ARGBEGIN {
123
	case 'r':
124
		rflag = 1;
125
		break;
126
	case 'f':
127
		sortopt = fold;
128
		break;
129
	case 'w':
130
		if(lenarg)
131
			extra(ARGC());
132
		lenarg = ARGF();
133
		break;
134
	case 'c':
135
		if(cmds)
136
			extra(ARGC());
137
		cmds = ARGF();
138
	case 't':
139
		roff = troff;
140
		break;
141
	case 'g':
142
		if(gutarg)
143
			extra(ARGC());
144
		gutarg =  ARGF();
145
		break;
146
	case 'h':
147
		if(holarg)
148
			extra(ARGC());
149
		holarg =  ARGF();
150
		break;
151
 
152
	case 'i':
153
		if(only|ignore)
154
			extra(ARGC());
155
		ignore++;
156
		xfile = ARGF();
157
		break;
158
 
159
	case 'o':
160
		if(only|ignore)
161
			extra(ARGC());
162
		only++;
163
		xfile = ARGF();
164
		break;
165
 
166
	case 'b':
167
		if(bfile)
168
			extra(ARGC());
169
		bfile = ARGF();
170
		break;
171
 
172
	default:
173
		diag("Illegal argument:",*argv);
174
	} ARGEND
175
 
176
	if(lenarg == 0)
177
		lenarg = troff? "100n": "72n";
178
	if(gutarg == 0)
179
		gutarg = "3n";
180
	if(holarg == 0)
181
		holarg = gutarg;
182
 
183
	if(argc > 1)
184
		diag("Too many filenames",empty);
185
	if(argc == 1)
186
		infile = *argv;
187
 
188
	/* Default breaks of blank, tab and newline */
189
	btable[' '] = ON;
190
	btable['\t'] = ON;
191
	btable['\n'] = ON;
192
	if(bfile) {
193
		if((bptr = fopen(bfile,"r")) == NULL)
194
			diag("Cannot open break char file",bfile);
195
 
196
		while((c = getc(bptr)) != EOF)
197
			btable[c] = ON;
198
	}
199
 
200
	/*
201
	Allocate space for a buffer.  If only or ignore file present
202
	read it into buffer. Else read in default ignore file
203
	and put resulting words in buffer.
204
	*/
205
 
206
	if((strtbufp = calloc(N,BUFSIZ)) == NULL)
207
		diag("Out of memory space",empty);
208
	bufp = strtbufp;
209
	endbufp = strtbufp+MAX;
210
 
211
	if((xptr = fopen(xfile,"r")) == NULL)
212
		diag("Cannot open  file",xfile);
213
 
214
	while(bufp < endbufp && (c = getc(xptr)) != EOF)
215
		if(isabreak(c)) {
216
			if(storeh(hash(strtbufp,bufp),strtbufp))
217
				diag("Too many words",xfile);
218
			*bufp++ = '\0';
219
			strtbufp = bufp;
220
		} else
221
			*bufp++ = (isupper(c)?tolower(c):c);
222
	if (bufp >= endbufp)
223
		diag("Too many words in file",xfile);
224
	endbufp = --bufp;
225
 
226
	/* open output file for sorting */
227
 
228
	if((sortptr = fopen(sortfile, "w")) == NULL)
229
		diag("Cannot open output for sorting:",sortfile);
230
 
231
	/*
232
	get a line of data and compare each word for
233
	inclusion or exclusion in the sort phase
234
	*/
235
	if (infile!=0 && (inptr = fopen(infile,"r")) == NULL)
236
		diag("Cannot open data: ",infile);
237
	while((pend = getline()) != NULL)
238
		cmpline(pend);
239
	fclose(sortptr);
240
 
241
	if(fork()==0){
242
		execl("/bin/sort", "sort", sortopt, "+0", "-1", "+1",
243
			sortfile, "-o", sortfile, 0);
244
		diag("Sort exec failed","");
245
	}
246
	if((w = wait()) == NULL || w->msg[0] != '\0')
247
		diag("Sort failed","");
248
	free(w);
249
 
250
	makek();
251
	if(fork()==0){
252
		if(dup(create(wfile,OWRITE|OTRUNC,0666),1) == -1)
253
			diag("Cannot create width file:",wfile);
254
		execl(roff, roff, "-a", kfile, 0);
255
		diag("Sort exec failed","");
256
	}
257
	if((w = wait()) == NULL || w->msg[0] != '\0')
258
		diag("Sort failed","");
259
	free(w);
260
 
261
	getsort();
262
/*
263
	remove(sortfile);
264
	remove(kfile);
265
 */
266
	fflush(0);
267
	_exits(0);
268
/* I don't know what's wrong with the atexit func... */
269
/*	exits(0);	*/
270
}
271
 
272
void
273
msg(char *s, char *arg)
274
{
275
	fprintf(stderr,"ptx: %s %s\n",s,arg);
276
}
277
 
278
void
279
extra(int c)
280
{
281
	char s[] = "-x.";
282
 
283
	s[1] = c;
284
	diag("Extra option", s);
285
}
286
 
287
void
288
diag(char *s, char *arg)
289
{
290
	msg(s,arg);
291
/*
292
	remove(sortfile);
293
	remove(kfile);
294
*/
295
	exits(s);
296
}
297
 
298
 
299
char*
300
getline(void)
301
{
302
	int c;
303
	char *linep;
304
	char *endlinep;
305
 
306
	endlinep= line + mlen;
307
	linep = line;
308
	/* Throw away leading white space */
309
 
310
	while(isspace(c = getc(inptr)))
311
		;
312
	if(c==EOF)
313
		return(0);
314
	ungetc(c,inptr);
315
	while((c = getc(inptr)) != EOF)
316
		switch (c) {
317
		case '\t':
318
			if(linep<endlinep)
319
				*linep++ = ' ';
320
			break;
321
		case '\n':
322
			while(isspace(*--linep))
323
				;
324
			*++linep = '\n';
325
			return(linep);
326
		default:
327
			if(linep < endlinep)
328
				*linep++ = c;
329
			break;
330
		}
331
	return(0);
332
}
333
 
334
void
335
cmpline(char *pend)
336
{
337
	char *pstrt, *pchar, *cp;
338
	char **hp;
339
	int flag;
340
 
341
	pchar = line;
342
	if(rflag)
343
		while(pchar < pend && !isspace(*pchar))
344
			pchar++;
345
	while(pchar < pend){
346
		/* eliminate white space */
347
		if(isabreak(*pchar++))
348
			continue;
349
		pstrt = --pchar;
350
 
351
		flag = 1;
352
		while(flag){
353
			if(isabreak(*pchar)) {
354
				hp = &hasht[hash(pstrt,pchar)];
355
				pchar--;
356
				while(cp = *hp++){
357
					if(hp == &hasht[MAXT])
358
						hp = hasht;
359
					/* possible match */
360
					if(cmpword(pstrt,pchar,cp)){
361
						/* exact match */
362
						if(!ignore && only)
363
							putline(pstrt,pend);
364
						flag = 0;
365
						break;
366
					}
367
				}
368
				/* no match */
369
				if(flag){
370
					if(ignore || !only)
371
						putline(pstrt,pend);
372
					flag = 0;
373
				}
374
			}
375
			pchar++;
376
		}
377
	}
378
}
379
 
380
int
381
cmpword(char *cpp, char *pend, char *hpp)
382
{
383
	char c;
384
 
385
	while(*hpp != '\0'){
386
		c = *cpp++;
387
		if((isupper(c)?tolower(c):c) != *hpp++)
388
			return(0);
389
	}
390
	if(--cpp == pend)
391
		return(1);
392
	return(0);
393
}
394
 
395
void
396
putline(char *strt, char *end)
397
{
398
	char *cp;
399
 
400
	for(cp=strt; cp<end; cp++)
401
		putc(*cp, sortptr);
402
	/* Add extra blank before TILDE to sort correctly with -fd option */
403
	putc(' ',sortptr);
404
	putc(TILDE,sortptr);
405
	for (cp=line; cp<strt; cp++)
406
		putc(*cp,sortptr);
407
	putc('\n',sortptr);
408
}
409
 
410
void
411
makek(void)
412
{
413
	int i, c;
414
	int nr = 0;
415
 
416
	if((sortptr = fopen(sortfile,"r")) == NULL)
417
		diag("Cannot open sorted data:",sortfile);
418
	if((kptr = fopen(kfile,"w")) == NULL)
419
		diag("Cannot create mark file:",kfile);
420
	if(cmds)
421
		fprintf(kptr,"%s\n",cmds);
422
	fprintf(kptr,
423
		".nf\n"
424
		".pl 1\n"
425
		".tr %c\\&\n", TILDE);
426
	setlen();
427
 
428
	while((c = getc(sortptr)) != EOF) {
429
		if(nr == 0) {
430
			fprintf(kptr,".di xx\n");
431
			nr++;
432
		}
433
		if(c == '\n') {
434
			fprintf(kptr,"\n.di\n");
435
			for(i=1; i<nr; i++)
436
				fprintf(kptr,"\\n(%.2d ",i);
437
			fprintf(kptr,"\n");
438
			nr = 0;
439
			continue;
440
		}
441
		if(isspace(c))
442
			fprintf(kptr,"\\k(%.2d",nr++);
443
		putc(c,kptr);
444
	}
445
	fclose(sortptr);
446
	fclose(kptr);
447
}
448
 
449
void
450
getsort(void)
451
{
452
	char *tilde, *linep, *markp;
453
	int i0, i1, i2, i3, i4, i5, i6, i7, w0, w6;
454
 
455
	if((sortptr = fopen(sortfile, "r")) == NULL)
456
		diag("Cannot open sorted data:", sortfile);
457
	if((wptr = fopen(wfile, "r")) == NULL)
458
		diag("Cannot open width file:", wfile);
459
	getlen();
460
 
461
	halflen = (llen-gutter)/2;
462
 
463
	while(fgets(line, sizeof(line), sortptr) != NULL) {
464
		if(fgets(mark, sizeof(mark), wptr) == NULL)
465
			diag("Phase error 1: premature EOF on width file",
466
				wfile);
467
		linep = line;
468
		markp = mark;
469
		i3 = i7 = 0;
470
		word[i7].p = linep;
471
		word[i7].w = 0;
472
		for(linep=line; *linep; linep++) {
473
			if(*linep == TILDE)
474
				i3 = i7;
475
			else if(*linep == '\n')
476
				break;
477
			else if(isspace(*linep)) {
478
				i7++;
479
				word[i7].p = linep;
480
				if(!markp)
481
					diag("Phase error 2: no widths for summary",
482
						line);
483
				word[i7].w = atoi(markp);
484
				markp = strchr(markp+1, ' ');
485
			}
486
		}
487
		i0 = 0;
488
		for(i1=i0; i1<i3; i1++)
489
			if(word[i1+1].w - word[i0].w >= halflen - spacesl)
490
				break;
491
		w0 = word[i1].w - word[i0].w;
492
		i4 = i3 + rflag;
493
		for(i6 = i7; i6>i4; i6--)
494
			if(word[i7].w - word[i6-1].w >= halflen)
495
				break;
496
		w6 = word[i7].w - word[i6].w - spacesl;
497
		for(i2=i1 ; i2<i3; i2++)
498
			if(word[i2+1].w - word[i1].w + w6 >= halflen-hole)
499
				break;
500
		for(i5=i6; i5>i4; i5--)
501
			if(word[i6].w - word[i5-1].w + w0 >= halflen-hole)
502
				break;
503
 
504
		printf(".xx \"");
505
		putout(word[i1].p+1,word[i2].p);
506
		if(i1<i2 && i2<i3) putchar('/');
507
		printf("\" \"");
508
		if(i5>i4 && i6==i5) putchar('/');
509
		putout(word[i6].p+1+(i6==i3),word[i7].p);
510
		printf("\" \"");
511
		putout(word[i0].p,word[i1].p);
512
		if(i2<i3 && i1==i2) putchar('/');
513
		printf("\" \"");
514
		if(i5>i4 && i6>i5) putchar('/');
515
		putout(word[i5].p+1+(i5==i3),word[i6].p);
516
		if(rflag) {
517
			printf("\" \"");
518
			putout(word[i3].p+2,word[i4].p);
519
		}
520
		printf("\"\n");
521
	}
522
}
523
 
524
void
525
putout(char *strt, char *end)
526
{
527
	char *cp;
528
 
529
	for(cp=strt; cp<end; )
530
		putc(*cp++,outptr);
531
}
532
 
533
void
534
setlen(void)
535
{
536
	fprintf(kptr,
537
		"\\w'\\h'%s''\n"
538
		"\\w' /'\n"
539
		"\\w'\\h'%s''\n"
540
		"\\w'\\h'%s''\n",lenarg,gutarg,holarg);
541
}
542
 
543
void
544
getlen(void)
545
{
546
	char s[128];
547
 
548
	s[0] = '\0';
549
	fgets(s,sizeof(s),kptr);
550
	llen = atoi(s);
551
 
552
	fgets(s,sizeof(s),kptr);
553
	spacesl = atoi(s);
554
 
555
	fgets(s,sizeof(s),kptr);
556
	gutter = atoi(s);
557
 
558
	fgets(s,sizeof(s),kptr);
559
	hole = atoi(s);
560
	if(hole < 2*spacesl)
561
		hole = 2*spacesl;
562
}
563
 
564
int
565
hash(char *strtp, char *endp)
566
{
567
	char *cp, c;
568
	int i, j, k;
569
 
570
	/* Return zero hash number for single letter words */
571
	if((endp - strtp) == 1)
572
		return(0);
573
 
574
	cp = strtp;
575
	c = *cp++;
576
	i = (isupper(c)?tolower(c):c);
577
	c = *cp;
578
	j = (isupper(c)?tolower(c):c);
579
	i = i*j;
580
	cp = --endp;
581
	c = *cp--;
582
	k = (isupper(c)?tolower(c):c);
583
	c = *cp;
584
	j = (isupper(c)?tolower(c):c);
585
	j = k*j;
586
	return (i ^ (j>>2)) & MASK;
587
}
588
 
589
int
590
storeh(int num, char *strtp)
591
{
592
	int i;
593
 
594
	for(i=num; i<MAXT; i++)
595
		if(hasht[i] == 0) {
596
			hasht[i] = strtp;
597
			return(0);
598
		}
599
	for(i=0; i<num; i++)
600
		if(hasht[i] == 0) {
601
			hasht[i] = strtp;
602
			return(0);
603
		}
604
	return(1);
605
}