|
|
1.1 root 1: static char *sccsid = "@(#)ptx.c 4.1 (Berkeley) 10/1/80";
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: 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:
35: extern char *calloc(), *mktemp();
36: extern char *getline();
37: int status;
38:
39:
40: char *hasht[MAXT];
41: char line[LMAX];
42: char btable[128];
43: int ignore;
44: int only;
45: int llen = 72;
46: int gap = 3;
47: int gutter = 3;
48: int mlen = LMAX;
49: int wlen;
50: int rflag;
51: int halflen;
52: char *strtbufp, *endbufp;
53: char *empty = "";
54:
55: char *infile;
56: FILE *inptr = stdin;
57:
58: char *outfile;
59: FILE *outptr = stdout;
60:
61: char *sortfile; /* output of sort program */
62: char nofold[] = {'-', 'd', 't', TILDE, 0};
63: char fold[] = {'-', 'd', 'f', 't', TILDE, 0};
64: char *sortopt = nofold;
65: FILE *sortptr;
66:
67: char *bfile; /*contains user supplied break chars */
68: FILE *bptr;
69:
70: main(argc,argv)
71: int argc;
72: char **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:
251: msg(s,arg)
252: char *s;
253: char *arg;
254: {
255: fprintf(stderr,"%s %s\n",s,arg);
256: return;
257: }
258: diag(s,arg)
259: char *s, *arg;
260: {
261:
262: msg(s,arg);
263: exit(1);
264: }
265:
266:
267: char *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:
303: cmpline(pend)
304: char *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:
350: cmpword(cpp,pend,hpp)
351: char *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:
364: putline(strt, end)
365: char *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:
380: getsort()
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:
460: char *rtrim(a,c,d)
461: char *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:
473: char *ltrim(c,b,d)
474: char *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:
486: putout(strt,end)
487: char *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:
498: onintr()
499: {
500:
501: if(*sortfile)
502: unlink(sortfile);
503: exit(1);
504: }
505:
506: hash(strtp,endp)
507: char *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:
533: storeh(num,strtp)
534: int num;
535: char *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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.