cleanup install
[unix-history] / usr / src / usr.bin / ptx / ptx.c
CommitLineData
f125e2b0
BJ
1static char *sccsid = "@(#)ptx.c 4.1 (Berkeley) %G%";
2#
3
4/* permuted title index
5 ptx [-t] [-i ignore] [-o only] [-w num] [-f] [input] [output]
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 /usr/lib/eign.
10
11 The width of the output line can be changed to num
12 characters. If omitted 72 is default unless troff than 100.
13 the -f flag tells the program to fold the output
14 the -t flag says the output is for troff and the
15 output is then wider.
16
17\e make: cc ptx.c -lS
18 */
19
20#include <stdio.h>
21#include <ctype.h>
22#include <signal.h>
23#define DEFLTX "/usr/lib/eign"
24#define TILDE 0177
25#define SORT "/usr/bin/sort"
26#define N 30
27#define MAX N*BUFSIZ
28#define LMAX 200
29#define MAXT 2048
30#define MASK 03777
31#define SET 1
32
33#define isabreak(c) (btable[c])
34
35extern char *calloc(), *mktemp();
36extern char *getline();
37int status;
38
39
40char *hasht[MAXT];
41char line[LMAX];
42char btable[128];
43int ignore;
44int only;
45int llen = 72;
46int gap = 3;
47int gutter = 3;
48int mlen = LMAX;
49int wlen;
50int rflag;
51int halflen;
52char *strtbufp, *endbufp;
53char *empty = "";
54
55char *infile;
56FILE *inptr = stdin;
57
58char *outfile;
59FILE *outptr = stdout;
60
61char *sortfile; /* output of sort program */
62char nofold[] = {'-', 'd', 't', TILDE, 0};
63char fold[] = {'-', 'd', 'f', 't', TILDE, 0};
64char *sortopt = nofold;
65FILE *sortptr;
66
67char *bfile; /*contains user supplied break chars */
68FILE *bptr;
69
70main(argc,argv)
71int argc;
72char **argv;
73{
74 register int c;
75 register char *bufp;
76 int pid;
77 char *pend;
78 extern onintr();
79
80 char *xfile;
81 FILE *xptr;
82
83 if(signal(SIGHUP,onintr)==SIG_IGN)
84 signal(SIGHUP,SIG_IGN);
85 if(signal(SIGINT,onintr)==SIG_IGN)
86 signal(SIGINT,SIG_IGN);
87 signal(SIGPIPE,onintr);
88 signal(SIGTERM,onintr);
89
90/* argument decoding */
91
92 xfile = DEFLTX;
93 argv++;
94 while(argc>1 && **argv == '-') {
95 switch (*++*argv){
96
97 case 'r':
98 rflag++;
99 break;
100 case 'f':
101 sortopt = fold;
102 break;
103
104 case 'w':
105 if(argc >= 2) {
106 argc--;
107 wlen++;
108 llen = atoi(*++argv);
109 if(llen == 0)
110 diag("Wrong width:",*argv);
111 if(llen > LMAX) {
112 llen = LMAX;
113 msg("Lines truncated to 200 chars.",empty);
114 }
115 break;
116 }
117
118 case 't':
119 if(wlen == 0)
120 llen = 100;
121 break;
122 case 'g':
123 if(argc >=2) {
124 argc--;
125 gap = gutter = atoi(*++argv);
126 }
127 break;
128
129 case 'i':
130 if(only)
131 diag("Only file already given.",empty);
132 if (argc>=2){
133 argc--;
134 ignore++;
135 xfile = *++argv;
136 }
137 break;
138
139 case 'o':
140 if(ignore)
141 diag("Ignore file already given",empty);
142 if (argc>=2){
143 only++;
144 argc--;
145 xfile = *++argv;
146 }
147 break;
148
149 case 'b':
150 if(argc>=2) {
151 argc--;
152 bfile = *++argv;
153 }
154 break;
155
156 default:
157 msg("Illegal argument:",*argv);
158 }
159 argc--;
160 argv++;
161 }
162
163 if(argc>3)
164 diag("Too many filenames",empty);
165 else if(argc==3){
166 infile = *argv++;
167 outfile = *argv;
168 if((outptr = fopen(outfile,"w")) == NULL)
169 diag("Cannot open output file:",outfile);
170 } else if(argc==2) {
171 infile = *argv;
172 outfile = 0;
173 }
174
175
176 /* Default breaks of blank, tab and newline */
177 btable[' '] = SET;
178 btable['\t'] = SET;
179 btable['\n'] = SET;
180 if(bfile) {
181 if((bptr = fopen(bfile,"r")) == NULL)
182 diag("Cannot open break char file",bfile);
183
184 while((c = getc(bptr)) != EOF)
185 btable[c] = SET;
186 }
187
188/* Allocate space for a buffer. If only or ignore file present
189 read it into buffer. Else read in default ignore file
190 and put resulting words in buffer.
191 */
192
193
194 if((strtbufp = calloc(N,BUFSIZ)) == NULL)
195 diag("Out of memory space",empty);
196 bufp = strtbufp;
197 endbufp = strtbufp+MAX;
198
199 if((xptr = fopen(xfile,"r")) == NULL)
200 diag("Cannot open file",xfile);
201
202 while(bufp < endbufp && (c = getc(xptr)) != EOF) {
203 if(isabreak(c)) {
204 if(storeh(hash(strtbufp,bufp),strtbufp))
205 diag("Too many words",xfile);
206 *bufp++ = '\0';
207 strtbufp = bufp;
208 }
209 else {
210 *bufp++ = (isupper(c)?tolower(c):c);
211 }
212 }
213 if (bufp >= endbufp)
214 diag("Too many words in file",xfile);
215 endbufp = --bufp;
216
217 /* open output file for sorting */
218
219 sortfile = mktemp("/tmp/ptxsXXXXX");
220 if((sortptr = fopen(sortfile, "w")) == NULL)
221 diag("Cannot open output for sorting:",sortfile);
222
223/* get a line of data and compare each word for
224 inclusion or exclusion in the sort phase
225*/
226
227 if (infile!=0 && (inptr = fopen(infile,"r")) == NULL)
228 diag("Cannot open data: ",infile);
229 while(pend=getline())
230 cmpline(pend);
231 fclose(sortptr);
232
233 switch (pid = fork()){
234
235 case -1: /* cannot fork */
236 diag("Cannot fork",empty);
237
238 case 0: /* child */
239 execl(SORT, SORT, sortopt, "+0", "-1", "+1",
240 sortfile, "-o", sortfile, 0);
241
242 default: /* parent */
243 while(wait(&status) != pid);
244 }
245
246
247 getsort();
248 onintr();
249}
250
251msg(s,arg)
252char *s;
253char *arg;
254{
255 fprintf(stderr,"%s %s\n",s,arg);
256 return;
257}
258diag(s,arg)
259char *s, *arg;
260{
261
262 msg(s,arg);
263 exit(1);
264}
265
266
267char *getline()
268{
269
270 register c;
271 register char *linep;
272 char *endlinep;
273
274
275 endlinep= line + mlen;
276 linep = line;
277 /* Throw away leading white space */
278
279 while(isspace(c=getc(inptr)))
280 ;
281 if(c==EOF)
282 return(0);
283 ungetc(c,inptr);
284 while(( c=getc(inptr)) != EOF) {
285 switch (c) {
286
287 case '\t':
288 if(linep<endlinep)
289 *linep++ = ' ';
290 break;
291 case '\n':
292 while(isspace(*--linep));
293 *++linep = '\n';
294 return(linep);
295 default:
296 if(linep < endlinep)
297 *linep++ = c;
298 }
299 }
300 return(0);
301}
302
303cmpline(pend)
304char *pend;
305{
306
307 char *pstrt, *pchar, *cp;
308 char **hp;
309 int flag;
310
311 pchar = line;
312 if(rflag)
313 while(pchar<pend&&!isspace(*pchar))
314 pchar++;
315 while(pchar<pend){
316 /* eliminate white space */
317 if(isabreak(*pchar++))
318 continue;
319 pstrt = --pchar;
320
321 flag = 1;
322 while(flag){
323 if(isabreak(*pchar)) {
324 hp = &hasht[hash(pstrt,pchar)];
325 pchar--;
326 while(cp = *hp++){
327 if(hp == &hasht[MAXT])
328 hp = hasht;
329 /* possible match */
330 if(cmpword(pstrt,pchar,cp)){
331 /* exact match */
332 if(!ignore && only)
333 putline(pstrt,pend);
334 flag = 0;
335 break;
336 }
337 }
338 /* no match */
339 if(flag){
340 if(ignore || !only)
341 putline(pstrt,pend);
342 flag = 0;
343 }
344 }
345 pchar++;
346 }
347 }
348}
349
350cmpword(cpp,pend,hpp)
351char *cpp, *pend, *hpp;
352{
353 char c;
354
355 while(*hpp != '\0'){
356 c = *cpp++;
357 if((isupper(c)?tolower(c):c) != *hpp++)
358 return(0);
359 }
360 if(--cpp == pend) return(1);
361 return(0);
362}
363
364putline(strt, end)
365char *strt, *end;
366{
367 char *cp;
368
369 for(cp=strt; cp<end; cp++)
370 putc(*cp, sortptr);
371 /* Add extra blank before TILDE to sort correctly
372 with -fd option */
373 putc(' ',sortptr);
374 putc(TILDE,sortptr);
375 for (cp=line; cp<strt; cp++)
376 putc(*cp,sortptr);
377 putc('\n',sortptr);
378}
379
380getsort()
381{
382 register c;
383 register char *tilde, *linep, *ref;
384 char *p1a,*p1b,*p2a,*p2b,*p3a,*p3b,*p4a,*p4b;
385 int w;
386 char *rtrim(), *ltrim();
387
388 if((sortptr = fopen(sortfile,"r")) == NULL)
389 diag("Cannot open sorted data:",sortfile);
390
391 halflen = (llen-gutter)/2;
392 linep = line;
393 while((c = getc(sortptr)) != EOF) {
394 switch(c) {
395
396 case TILDE:
397 tilde = linep;
398 break;
399
400 case '\n':
401 while(isspace(linep[-1]))
402 linep--;
403 ref = tilde;
404 if(rflag) {
405 while(ref<linep&&!isspace(*ref))
406 ref++;
407 *ref++ = 0;
408 }
409 /* the -1 is an overly conservative test to leave
410 space for the / that signifies truncation*/
411 p3b = rtrim(p3a=line,tilde,halflen-1);
412 if(p3b-p3a>halflen-1)
413 p3b = p3a+halflen-1;
414 p2a = ltrim(ref,p2b=linep,halflen-1);
415 if(p2b-p2a>halflen-1)
416 p2a = p2b-halflen-1;
417 p1b = rtrim(p1a=p3b+(isspace(p3b[0])!=0),tilde,
418 w=halflen-(p2b-p2a)-gap);
419 if(p1b-p1a>w)
420 p1b = p1a;
421 p4a = ltrim(ref,p4b=p2a-(isspace(p2a[-1])!=0),
422 w=halflen-(p3b-p3a)-gap);
423 if(p4b-p4a>w)
424 p4a = p4b;
425 fprintf(outptr,".xx \"");
426 putout(p1a,p1b);
427 /* tilde-1 to account for extra space before TILDE */
428 if(p1b!=(tilde-1) && p1a!=p1b)
429 fprintf(outptr,"/");
430 fprintf(outptr,"\" \"");
431 if(p4a==p4b && p2a!=ref && p2a!=p2b)
432 fprintf(outptr,"/");
433 putout(p2a,p2b);
434 fprintf(outptr,"\" \"");
435 putout(p3a,p3b);
436 /* ++p3b to account for extra blank after TILDE */
437 /* ++p3b to account for extra space before TILDE */
438 if(p1a==p1b && ++p3b!=tilde)
439 fprintf(outptr,"/");
440 fprintf(outptr,"\" \"");
441 if(p1a==p1b && p4a!=ref && p4a!=p4b)
442 fprintf(outptr,"/");
443 putout(p4a,p4b);
444 if(rflag)
445 fprintf(outptr,"\" %s\n",tilde);
446 else
447 fprintf(outptr,"\"\n");
448 linep = line;
449 break;
450
451 case '"':
452 /* put double " for " */
453 *linep++ = c;
454 default:
455 *linep++ = c;
456 }
457 }
458}
459
460char *rtrim(a,c,d)
461char *a,*c;
462{
463 char *b,*x;
464 b = c;
465 for(x=a+1; x<=c&&x-a<=d; x++)
466 if((x==c||isspace(x[0]))&&!isspace(x[-1]))
467 b = x;
468 if(b<c&&!isspace(b[0]))
469 b++;
470 return(b);
471}
472
473char *ltrim(c,b,d)
474char *c,*b;
475{
476 char *a,*x;
477 a = c;
478 for(x=b-1; x>=c&&b-x<=d; x--)
479 if(!isspace(x[0])&&(x==c||isspace(x[-1])))
480 a = x;
481 if(a>c&&!isspace(a[-1]))
482 a--;
483 return(a);
484}
485
486putout(strt,end)
487char *strt, *end;
488{
489 char *cp;
490
491 cp = strt;
492
493 for(cp=strt; cp<end; cp++) {
494 putc(*cp,outptr);
495 }
496}
497
498onintr()
499{
500
501 if(*sortfile)
502 unlink(sortfile);
503 exit(1);
504}
505
506hash(strtp,endp)
507char *strtp, *endp;
508{
509 char *cp, c;
510 int i, j, k;
511
512 /* Return zero hash number for single letter words */
513 if((endp - strtp) == 1)
514 return(0);
515
516 cp = strtp;
517 c = *cp++;
518 i = (isupper(c)?tolower(c):c);
519 c = *cp;
520 j = (isupper(c)?tolower(c):c);
521 i = i*j;
522 cp = --endp;
523 c = *cp--;
524 k = (isupper(c)?tolower(c):c);
525 c = *cp;
526 j = (isupper(c)?tolower(c):c);
527 j = k*j;
528
529 k = (i ^ (j>>2)) & MASK;
530 return(k);
531}
532
533storeh(num,strtp)
534int num;
535char *strtp;
536{
537 int i;
538
539 for(i=num; i<MAXT; i++) {
540 if(hasht[i] == 0) {
541 hasht[i] = strtp;
542 return(0);
543 }
544 }
545 for(i=0; i<num; i++) {
546 if(hasht[i] == 0) {
547 hasht[i] = strtp;
548 return(0);
549 }
550 }
551 return(1);
552}