home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Trees / V7 / usr / src / cmd / ptx.c < prev    next >
Encoding:
C/C++ Source or Header  |  1979-01-10  |  9.4 KB  |  552 lines

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