setgid to group "write" so that terminals need not be world writable
[unix-history] / usr / src / usr.bin / ptx / ptx.c
CommitLineData
62939760 1static char *sccsid = "@(#)ptx.c 4.2 (Berkeley) %G%";
f125e2b0
BJ
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();
62939760
JB
248 if(*sortfile)
249 unlink(sortfile);
250 exit(0);
f125e2b0
BJ
251}
252
253msg(s,arg)
254char *s;
255char *arg;
256{
257 fprintf(stderr,"%s %s\n",s,arg);
258 return;
259}
260diag(s,arg)
261char *s, *arg;
262{
263
264 msg(s,arg);
265 exit(1);
266}
267
268
269char *getline()
270{
271
272 register c;
273 register char *linep;
274 char *endlinep;
275
276
277 endlinep= line + mlen;
278 linep = line;
279 /* Throw away leading white space */
280
281 while(isspace(c=getc(inptr)))
282 ;
283 if(c==EOF)
284 return(0);
285 ungetc(c,inptr);
286 while(( c=getc(inptr)) != EOF) {
287 switch (c) {
288
289 case '\t':
290 if(linep<endlinep)
291 *linep++ = ' ';
292 break;
293 case '\n':
294 while(isspace(*--linep));
295 *++linep = '\n';
296 return(linep);
297 default:
298 if(linep < endlinep)
299 *linep++ = c;
300 }
301 }
302 return(0);
303}
304
305cmpline(pend)
306char *pend;
307{
308
309 char *pstrt, *pchar, *cp;
310 char **hp;
311 int flag;
312
313 pchar = line;
314 if(rflag)
315 while(pchar<pend&&!isspace(*pchar))
316 pchar++;
317 while(pchar<pend){
318 /* eliminate white space */
319 if(isabreak(*pchar++))
320 continue;
321 pstrt = --pchar;
322
323 flag = 1;
324 while(flag){
325 if(isabreak(*pchar)) {
326 hp = &hasht[hash(pstrt,pchar)];
327 pchar--;
328 while(cp = *hp++){
329 if(hp == &hasht[MAXT])
330 hp = hasht;
331 /* possible match */
332 if(cmpword(pstrt,pchar,cp)){
333 /* exact match */
334 if(!ignore && only)
335 putline(pstrt,pend);
336 flag = 0;
337 break;
338 }
339 }
340 /* no match */
341 if(flag){
342 if(ignore || !only)
343 putline(pstrt,pend);
344 flag = 0;
345 }
346 }
347 pchar++;
348 }
349 }
350}
351
352cmpword(cpp,pend,hpp)
353char *cpp, *pend, *hpp;
354{
355 char c;
356
357 while(*hpp != '\0'){
358 c = *cpp++;
359 if((isupper(c)?tolower(c):c) != *hpp++)
360 return(0);
361 }
362 if(--cpp == pend) return(1);
363 return(0);
364}
365
366putline(strt, end)
367char *strt, *end;
368{
369 char *cp;
370
371 for(cp=strt; cp<end; cp++)
372 putc(*cp, sortptr);
373 /* Add extra blank before TILDE to sort correctly
374 with -fd option */
375 putc(' ',sortptr);
376 putc(TILDE,sortptr);
377 for (cp=line; cp<strt; cp++)
378 putc(*cp,sortptr);
379 putc('\n',sortptr);
380}
381
382getsort()
383{
384 register c;
385 register char *tilde, *linep, *ref;
386 char *p1a,*p1b,*p2a,*p2b,*p3a,*p3b,*p4a,*p4b;
387 int w;
388 char *rtrim(), *ltrim();
389
390 if((sortptr = fopen(sortfile,"r")) == NULL)
391 diag("Cannot open sorted data:",sortfile);
392
393 halflen = (llen-gutter)/2;
394 linep = line;
395 while((c = getc(sortptr)) != EOF) {
396 switch(c) {
397
398 case TILDE:
399 tilde = linep;
400 break;
401
402 case '\n':
403 while(isspace(linep[-1]))
404 linep--;
405 ref = tilde;
406 if(rflag) {
407 while(ref<linep&&!isspace(*ref))
408 ref++;
409 *ref++ = 0;
410 }
411 /* the -1 is an overly conservative test to leave
412 space for the / that signifies truncation*/
413 p3b = rtrim(p3a=line,tilde,halflen-1);
414 if(p3b-p3a>halflen-1)
415 p3b = p3a+halflen-1;
416 p2a = ltrim(ref,p2b=linep,halflen-1);
417 if(p2b-p2a>halflen-1)
418 p2a = p2b-halflen-1;
419 p1b = rtrim(p1a=p3b+(isspace(p3b[0])!=0),tilde,
420 w=halflen-(p2b-p2a)-gap);
421 if(p1b-p1a>w)
422 p1b = p1a;
423 p4a = ltrim(ref,p4b=p2a-(isspace(p2a[-1])!=0),
424 w=halflen-(p3b-p3a)-gap);
425 if(p4b-p4a>w)
426 p4a = p4b;
427 fprintf(outptr,".xx \"");
428 putout(p1a,p1b);
429 /* tilde-1 to account for extra space before TILDE */
430 if(p1b!=(tilde-1) && p1a!=p1b)
431 fprintf(outptr,"/");
432 fprintf(outptr,"\" \"");
433 if(p4a==p4b && p2a!=ref && p2a!=p2b)
434 fprintf(outptr,"/");
435 putout(p2a,p2b);
436 fprintf(outptr,"\" \"");
437 putout(p3a,p3b);
438 /* ++p3b to account for extra blank after TILDE */
439 /* ++p3b to account for extra space before TILDE */
440 if(p1a==p1b && ++p3b!=tilde)
441 fprintf(outptr,"/");
442 fprintf(outptr,"\" \"");
443 if(p1a==p1b && p4a!=ref && p4a!=p4b)
444 fprintf(outptr,"/");
445 putout(p4a,p4b);
446 if(rflag)
447 fprintf(outptr,"\" %s\n",tilde);
448 else
449 fprintf(outptr,"\"\n");
450 linep = line;
451 break;
452
453 case '"':
454 /* put double " for " */
455 *linep++ = c;
456 default:
457 *linep++ = c;
458 }
459 }
460}
461
462char *rtrim(a,c,d)
463char *a,*c;
464{
465 char *b,*x;
466 b = c;
467 for(x=a+1; x<=c&&x-a<=d; x++)
468 if((x==c||isspace(x[0]))&&!isspace(x[-1]))
469 b = x;
470 if(b<c&&!isspace(b[0]))
471 b++;
472 return(b);
473}
474
475char *ltrim(c,b,d)
476char *c,*b;
477{
478 char *a,*x;
479 a = c;
480 for(x=b-1; x>=c&&b-x<=d; x--)
481 if(!isspace(x[0])&&(x==c||isspace(x[-1])))
482 a = x;
483 if(a>c&&!isspace(a[-1]))
484 a--;
485 return(a);
486}
487
488putout(strt,end)
489char *strt, *end;
490{
491 char *cp;
492
493 cp = strt;
494
495 for(cp=strt; cp<end; cp++) {
496 putc(*cp,outptr);
497 }
498}
499
500onintr()
501{
502
503 if(*sortfile)
504 unlink(sortfile);
505 exit(1);
506}
507
508hash(strtp,endp)
509char *strtp, *endp;
510{
511 char *cp, c;
512 int i, j, k;
513
514 /* Return zero hash number for single letter words */
515 if((endp - strtp) == 1)
516 return(0);
517
518 cp = strtp;
519 c = *cp++;
520 i = (isupper(c)?tolower(c):c);
521 c = *cp;
522 j = (isupper(c)?tolower(c):c);
523 i = i*j;
524 cp = --endp;
525 c = *cp--;
526 k = (isupper(c)?tolower(c):c);
527 c = *cp;
528 j = (isupper(c)?tolower(c):c);
529 j = k*j;
530
531 k = (i ^ (j>>2)) & MASK;
532 return(k);
533}
534
535storeh(num,strtp)
536int num;
537char *strtp;
538{
539 int i;
540
541 for(i=num; i<MAXT; i++) {
542 if(hasht[i] == 0) {
543 hasht[i] = strtp;
544 return(0);
545 }
546 }
547 for(i=0; i<num; i++) {
548 if(hasht[i] == 0) {
549 hasht[i] = strtp;
550 return(0);
551 }
552 }
553 return(1);
554}