home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume11 / psfig / part01 next >
Text File  |  1987-09-22  |  35KB  |  1,887 lines

  1. Subject:  v11i072:  Including PostScript figures in ditroff, Part01/05
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rs@uunet.UU.NET
  5.  
  6. Submitted-by: trevor@linc.cis.upenn.edu (Trevor Darrell)
  7. Posting-number: Volume 11, Issue 72
  8. Archive-name: psfig/Part01
  9.  
  10. This is "psfig," a package to include PostScript figures in ditroff. It
  11. was presented at the Phoenix Usenix and in Unix Review.
  12.  
  13.  
  14. system requirements:
  15.     PostScript printer
  16.     ditroff DWB version 2.0 or later
  17.     transcript, with source for psdit
  18.         **This may not be needed if you have transcript 3.0
  19.  
  20. Please read the "system requirements" so I am not deluged with "but it
  21. doesn't work with my ditroff!" complaints.
  22.  
  23. --tjd
  24.  
  25. Trevor Darrell
  26.  
  27. trevor@linc.cis.upenn.edu  |  trevor@grasp.cis.upenn.edu  |  (215) 898-5617
  28. Computer and Information Science 
  29. University of Pennsylvania CIS dept. 200 S. 33rd st. Philadelphia, PA 19104
  30.  
  31. -----------------------
  32. # This is a shell archive.  Remove anything before this line,
  33. # then unpack it by saving it in a file and typing "sh file".
  34. #
  35. # Contents:  trf/ trf/src/ trf/README trf/src/Makefile trf/src/cmds.c
  36. #    trf/src/item.c trf/src/item.h trf/src/keywords.c trf/src/lineio.c
  37. #    trf/src/macros.c trf/src/main.c trf/src/psfig.h trf/src/troff.c
  38.  
  39. echo mkdir - trf
  40. mkdir trf
  41. chmod u=rwx,g=rx,o=rx trf
  42.  
  43. echo x - trf/README
  44. sed 's/^@//' > "trf/README" <<'@//E*O*F trf/README//'
  45. This is the source and documentation to the psfig preprocessor for ditroff.
  46.  
  47. All source code, documentation and related files are Copyright (C) 1987
  48. by Trevor Darrell. All rights reserved. This software may not be distributed
  49. on a for-profit basis in any way without express written permission of the
  50. author(s).
  51.  
  52. ===========================================================================
  53.  
  54. What you need to use psfig:
  55.  
  56.     + a ditroff (device-independent troff) that accepts the \X
  57.         command for text pass-thru. ditroff from DWB 2.0 or 
  58.         greater will do.
  59.  
  60.     + source to psdit from the adobe transcript package
  61.  
  62.     + (optionally) source for ditroff to make some minor fixes.
  63.  
  64.     + of course, a postscript printer for the final result. Draft
  65.         copies do not need a postscript device.
  66.  
  67. ========================================================================
  68. What to do:
  69.  
  70. 1. Compile the preprocessor:
  71.     cd src; make psfig
  72.     cp psfig /usr/local (or /usr/bin, &c...)
  73.  
  74. 2. Next, install the patches to psdit and psdit.pro.
  75. ** Read patches/README for instructions on the psdit.c and psdit.pro patches.
  76.  
  77. 3. Copy lib/psfig.tmac to the troff macro directory (/usr/lib/tmac).
  78.  
  79. 4. Finally, if you are up to it and have ditroff source, apply
  80.     the ditroff patch. (less critical) If you don't make the
  81.     patch, figures may not center properly and figures won't
  82.     work inside eqn. The centering problem can be alleviated
  83.     by using "-f" with psfig.
  84.  
  85. Give the test program a spin...
  86.  
  87. % cd tst
  88. % make test.ps
  89.  
  90. make a copy of the manaul...
  91.  
  92. % cd doc 
  93. % dopaper
  94.  
  95. Note that the slew of warnings from psfig about `psfig.ps.?' on the first pass
  96. is no problem and should be ignored. (due to recursive figure processing...)
  97.  
  98. @//E*O*F trf/README//
  99. chmod u=rw,g=r,o=r trf/README
  100.  
  101. echo mkdir - trf/src
  102. mkdir trf/src
  103. chmod u=rwx,g=rx,o=rx trf/src
  104.  
  105. echo x - trf/src/Makefile
  106. sed 's/^@//' > "trf/src/Makefile" <<'@//E*O*F trf/src/Makefile//'
  107. CFLAGS = -g
  108. OBJS = main.o lineio.o item.o troff.o cmds.o keywords.o macros.o
  109. SRCS = main.c lineio.c item.c troff.c cmds.c keywords.c macros.c
  110. HDRS = psfig.h item.h
  111.  
  112. @.c.o:
  113.     -rm -f $@
  114.     cc -c $(CFLAGS) $<
  115.  
  116. psfig : $(OBJS) 
  117.     -rm -f psfig
  118.     cc ${CFLAGS} -o psfig $(OBJS)
  119.  
  120. $(OBJS) : psfig.h
  121. item.o cmds.o keywords.o: item.h
  122.  
  123. lint: $(SRCS) $(HDRS)
  124.     lint $(SRCS)
  125.  
  126. tidy:
  127.     -rm -f *.BAK *.CKP a.out
  128. clean: tidy
  129.     -rm -f *.o core '#'*
  130. @//E*O*F trf/src/Makefile//
  131. chmod u=rw,g=r,o=r trf/src/Makefile
  132.  
  133. echo x - trf/src/cmds.c
  134. sed 's/^@//' > "trf/src/cmds.c" <<'@//E*O*F trf/src/cmds.c//'
  135. /***    
  136.  ***    cmds.c --
  137.  ***    
  138.  ***    Handle parsing of commands for psfig.
  139.  ***    
  140.  ***    T.Darrell, 3/86.
  141.  ***/
  142.  
  143. # include "psfig.h"
  144. # include "item.h"
  145.  
  146. int    Draft = DraftDefault;
  147.  
  148. int    inLineFlag = 0;        /* are we generating an in-line figure? */
  149.  
  150. /* 
  151.  * dofigcmd()
  152.  */
  153.  
  154. dofigcmd()
  155. {
  156.     int        end = 0;
  157.     int        didsome = 0;
  158.     int        global = 0;
  159.     static char    cmdbuf[SMBUFSZ];
  160.     static char    bigbuf[BUFSIZ];
  161.  
  162.     while (!end) {
  163.         switch (getItem(cmdbuf)) {
  164.  
  165.         case iEndOfInput:
  166.             ++end;
  167.         case iSeparator:            
  168.             break;
  169.  
  170.         case iDefine:
  171.             switch (getItem(cmdbuf)) {
  172.             case iEndOfInput:
  173.             case iSeparator:
  174.                 error("empty define");
  175.  
  176.             case iWord:
  177.                 if (getString(bigbuf, sizeof(bigbuf))) {
  178.                     addMacro(cmdbuf, bigbuf);
  179.                 } else {
  180.                     deleteMacro(cmdbuf);
  181.                 }
  182.                 break;
  183.  
  184.             default:
  185.                 error("can't define a keyword");
  186.             }
  187.             break;
  188.  
  189.         case iDelim:
  190.             switch (getItem(cmdbuf)) {
  191.             case iEndOfInput:
  192.                 ++end;
  193.             case iSeparator:
  194.                 delimSt = delimEnd = 0;
  195.                 break;
  196.  
  197.             case iWord:
  198.                 delimSt = cmdbuf[0];
  199.                 if (cmdbuf[1])
  200.                     delimEnd = cmdbuf[1];
  201.                 else
  202.                     delimEnd = delimSt;
  203.                 break;
  204.             }
  205.             break;
  206.  
  207.         case iSpace:
  208.             switch(getItem(cmdbuf)) {
  209.             case iWord:
  210.                 saveSpaceH(cmdbuf);
  211.                 didsome++;
  212.                 break;
  213.             default:
  214.                 error("bad space command");
  215.             }
  216.             break;
  217.  
  218.         case iLiteral:
  219.  
  220.             if (!getString(bigbuf, sizeof(bigbuf))) 
  221.                 break;
  222.  
  223.             for (;;) {
  224.                 switch (getItem(cmdbuf)) {
  225.                 case iLevel:
  226.                     if (getItem(cmdbuf) != iWord)
  227.                         error("bad level in literal");
  228.                     if (atoi(cmdbuf) < Draft) {
  229.                         ++didsome;
  230.                         emitLiteral(bigbuf);
  231.                     }
  232.                     continue;
  233.  
  234.                 case iGlobal:
  235.                     ++global;
  236.                     emitLiteral("globalstart");
  237.                     continue;
  238.  
  239.                 default:
  240.                     if (didsome) {
  241.                         unGetItem(cmdbuf);
  242.                         break;
  243.                     }
  244.                     if (inLineFlag) {
  245.                         if (InLineLevel < Draft) {
  246.                             emitLiteral(bigbuf);
  247.                             ++didsome;
  248.                         }
  249.                     } else {
  250.                         if (BrokenOutLevel < Draft) {
  251.                             emitLiteral(bigbuf);
  252.                             ++didsome;
  253.                         }
  254.                     }
  255.     
  256.                     unGetItem(cmdbuf);
  257.                     break;
  258.                 }
  259.                 break;
  260.             }
  261.             if (global) {
  262.                 emitLiteral("globalend");
  263.                 global = 0;
  264.             }
  265.             break;
  266.  
  267.         case iFile:
  268.             *bigbuf = 0;
  269.             if (getItem(bigbuf) != iWord)
  270.                 error("bad file command");
  271.  
  272.             for (;;) {
  273.                 switch (getItem(cmdbuf)) {
  274.                 case iLevel:
  275.                     if (getItem(cmdbuf) != iWord)
  276.                         error("bad level in literal");
  277.                     if (atoi(cmdbuf) < Draft) {
  278.                         includeFile(abspath(bigbuf));
  279.                         ++didsome;
  280.                     }
  281.                     continue;
  282.  
  283.                 case iGlobal:
  284.                     ++global;
  285.                      emitLiteral("globalstart");
  286.                     continue;
  287.     
  288.                 default:
  289.                     if (inLineFlag) {
  290.                         if (InLineLevel < Draft) {
  291.                           includeFile(abspath(bigbuf));
  292.                           ++didsome;
  293.                         }
  294.                     } else {
  295.                         if (BrokenOutLevel < Draft) {
  296.                           includeFile(abspath(bigbuf));
  297.                           ++didsome;
  298.                         }
  299.                     }
  300.                     unGetItem(cmdbuf);
  301.                     break;
  302.                 }
  303.                 break;
  304.             }
  305.             if (global) {
  306.                 emitLiteral("globalend");
  307.                 global = 0;
  308.             }
  309.  
  310.             break;
  311.             
  312.         case iFigure:
  313.             includeFig();
  314.             didsome++;
  315.             break;
  316.  
  317.         case iWord:
  318.             unGetItem(cmdbuf);
  319.             includeFig();
  320.             didsome++;
  321.             break;
  322.  
  323.         default:
  324.             error("unknown command");
  325.         }
  326.     }
  327.  
  328.     return didsome;
  329. }
  330.  
  331.  
  332. /* 
  333.  * includeFig:
  334.  * 
  335.  * Appends the ditroff code needed to save space for figure specifed by the
  336.  * 'file' command in cmd to dStr, and returns the new string.
  337.  * 
  338.  * The ditroff commands leave the "pen" in the upper right hand corner.
  339.  */
  340.  
  341. static char path[SMBUFSZ], filenm[SMBUFSZ];
  342. static char x[SMBUFSZ], y[SMBUFSZ];    /* postscript size */
  343. static char rx[SMBUFSZ], ry[SMBUFSZ];    /* ditroff reserve size */
  344. int doClip;
  345. int nbox, draftlvl;
  346. int bflag;                /* have bounds been set? */
  347. float bb_llx, bb_lly, bb_urx, bb_ury;
  348. char head[BUFSZ], foot[BUFSZ];        /* things to do before and
  349.                      * after the figure is inlcluded
  350.                      * (arguments, etc...)
  351.                      */
  352. char *
  353. includeFig()
  354. {
  355.     float        fx, fy;
  356.  
  357.     bflag = 0;
  358.  
  359.     parse();
  360.  
  361.     (void) strcpy(filenm, abspath(path));
  362.  
  363.     /* 
  364.      * If no size was specified, use size from file (in points).
  365.      * If only a width was specified, calculate
  366.      *     height = fileheight * (width / filewidth).
  367.      * If only a height, calculate
  368.      *     width = filewidth * (height / fileheight).
  369.      */
  370.  
  371.     if (!bflag) {
  372.         getFileBB(filenm, &bb_llx, &bb_lly, &bb_urx, &bb_ury);
  373.     }
  374.  
  375.     fx = bb_urx - bb_llx;
  376.     fy = bb_ury - bb_lly;
  377.     
  378.     if (!*x && !*y) {
  379.         (void) sprintf(x, "%.2fp", fx);
  380.         (void) sprintf(y, "%.2fp", fy);
  381.     } else if (!*x) {
  382.         (void) sprintf(x,"(%.2fp*%s/%.2fp)", fx, y, fy);
  383.     } else if (!*y) {
  384.         (void) sprintf(y,"(%.2fp*%s/%.2fp)", fy, x, fx);
  385.     }
  386.  
  387.     /* 
  388.      * If reserve size was ommited, = figure size
  389.      */
  390.     
  391.     if (*rx == 0) 
  392.         (void) strcpy(rx, x);
  393.     if (*ry == 0)
  394.         (void) strcpy(ry, y);
  395.  
  396.  
  397.     if (draftlvl >= Draft) {
  398.  
  399.         if (!inLineFlag && strcmp(ry, "0")) {
  400.             draftNote(path);
  401.             makeBox(rx, ry);
  402.         } else {
  403.             if (strcmp(ry,"0"))
  404.                 saveSpaceV(ry, (inLineFlag ? UP : DOWN));
  405.  
  406.             saveSpaceH(rx);
  407.         }
  408.                 
  409.     } else {
  410.  
  411.         if (inLineFlag) 
  412.             moveUp(y);
  413.  
  414.         startfig(x, y, bb_llx, bb_lly, bb_urx, bb_ury);
  415.         if (doClip) emitDoClip();
  416.         fputs(head, stdout);
  417.         includeFile(filenm);
  418.         fputs(foot, stdout);
  419.         endfig();        
  420.  
  421.         /* Dont save space if == "0" */
  422.         if (strcmp(ry, "0"))
  423.             saveSpaceV(ry, (inLineFlag ? UP : DOWN));
  424.         saveSpaceH(rx);
  425.  
  426.         if (inLineFlag)
  427.             moveDown(y);
  428.     }
  429. }
  430.  
  431. /* 
  432.  * parse:
  433.  * 
  434.  * parse file command.
  435.  */
  436.  
  437. parse()
  438. {
  439.     int        end = 0;
  440.     int        foundPath = 0;
  441.     static char    tmpbuf[SMBUFSZ];
  442.     static char    word[SMBUFSZ];
  443.  
  444.     /* 
  445.      *  initialize all values to their defaults,
  446.      *  then fill them in as specifed on the cmd line.
  447.      */
  448.  
  449.     strcpy(head, strcpy(foot, ""));
  450.  
  451.     if (inLineFlag)
  452.         draftlvl = InLineLevel;
  453.     else
  454.         draftlvl = BrokenOutLevel;
  455.     nbox = 0;
  456.     doClip = 0;
  457.  
  458.     (void) strcpy(rx, strcpy(x, strcpy(y, "")));
  459.  
  460.     /* 
  461.      * If we are in-line, set default vert. reserve to nothing ("0")
  462.      * otherwise, set default reserve to NULL, which signals
  463.      * it should later be filled in with x,y.
  464.      */
  465.     if (inLineFlag)
  466.         (void) strcpy(ry, "0");
  467.     else
  468.         (void) strcpy(ry, "");
  469.  
  470.     while (!end) {
  471.         switch(getItem(word)) {
  472.             case iHeight:
  473.                 if (getItem(y) != iWord)
  474.                     error("bad height");
  475.                 break;
  476.             case iWidth:
  477.                 if (getItem(x) != iWord)
  478.                     error("bad width");
  479.                 break;
  480.             case iReserve:
  481.                 if (getItem(rx) != iWord) {
  482.                     unGetItem(rx);
  483.                     (void) strcpy(rx, strcpy(ry, ""));
  484.                     break;
  485.                 }
  486.                 if (getItem(ry) != iWord)
  487.                     error("bad reserve");
  488.                 break;
  489.             case iClip:
  490.                 ++doClip;
  491.                 break;
  492.             case iLevel:
  493.                 if (getItem(tmpbuf) != iWord)
  494.                     error("bad level");
  495.                 draftlvl = atoi(tmpbuf);
  496.                 break;
  497.             case iBounds:
  498.                 if (getItem(tmpbuf) != iWord)
  499.                     error("bad bounds");
  500.                 sscanf(tmpbuf, "%f", &bb_llx);
  501.                     
  502.                 if (getItem(tmpbuf) != iWord)
  503.                     error("bad bounds");
  504.                 sscanf(tmpbuf, "%f", &bb_lly);
  505.     
  506.                 if (getItem(tmpbuf) != iWord)
  507.                     error("bad bounds");
  508.                 sscanf(tmpbuf, "%f", &bb_urx);
  509.     
  510.                 if (getItem(tmpbuf) != iWord)
  511.                     error("bad bounds");
  512.                 sscanf(tmpbuf, "%f", &bb_ury);
  513.                 ++bflag;
  514.                 break;
  515.             case iLeftBrace:
  516.                 parse_format();
  517.                 break;
  518.             case iEndOfInput:
  519.             case iSeparator:
  520.                 ++end;
  521.                 break;
  522.             case iWord:
  523.                 if (!foundPath) {
  524.                     strcpy(path, word);
  525.                     ++foundPath;
  526.                     break;
  527.                 }
  528.                 /* flow through */
  529.             default:
  530.                 unGetItem(word);
  531.                 ++end;
  532.                 break;
  533.         }
  534.     }
  535.  
  536.     /* 
  537.      * Make sure we have a file name.
  538.      */
  539.  
  540.     if (!foundPath) {
  541.         error("missing file name in figure command");
  542.     }
  543. }
  544.  
  545. parse_format() {
  546.     static char word[SMBUFSZ];
  547.     int pre = 1; /* true until `figure' is encountered */
  548.  
  549.     for (;;) switch (getItem(word)) {
  550.  
  551.         case iFile :
  552.             if (getItem(word) != iWord)
  553.                 error("bad file command in format");
  554.  
  555.             sIncludeFile((pre ? head : foot), abspath(word),BUFSZ);
  556.             break;
  557.  
  558.         case iLiteral :
  559.             if (!getString(word, sizeof(word)))
  560.                 error("bad literal in format");
  561.  
  562.             sEmitLiteral((pre ? head : foot), word, BUFSZ);
  563.             break;
  564.  
  565.         case iFigure :
  566.             pre = 0;
  567.             break;
  568.  
  569.         case iRightBrace:
  570.             return;
  571.  
  572.         default :
  573.             error("bad command in format");
  574.     }
  575. }
  576. /* end of cmds.c */
  577. @//E*O*F trf/src/cmds.c//
  578. chmod u=r,g=r,o=r trf/src/cmds.c
  579.  
  580. echo x - trf/src/item.c
  581. sed 's/^@//' > "trf/src/item.c" <<'@//E*O*F trf/src/item.c//'
  582. /***    
  583.  ***    item.c --
  584.  ***    
  585.  ***    The item reading abstraction for psfig
  586.  ***    
  587.  ***    N.Batchelder, 3/8/86.
  588.  ***/
  589.  
  590. # include "item.h"
  591. # include "psfig.h"
  592.  
  593. # define elif        else if
  594. # define isWhite(c)    ((c) == ' ' || (c) == '\t' || (c) == '\n')
  595.  
  596. static int    endofinput = 0;        /* Have we hit the end? */
  597. static char    cbuf[1000];        /* Where we do all processing */
  598. static char    *cp;            /* Our position in cbuf */
  599. static char    *(*getmore)();        /* Our gimme gimme function */
  600.  
  601. # define StartOffset    700    /* Where in cbuf to start filling. */
  602.  
  603. /* 
  604.  * getCh:
  605.  * 
  606.  * Read a character from our input. Returns 0 when no more.
  607.  */
  608.  
  609. static
  610. char
  611. getCh()
  612. {
  613.     while (!endofinput) {
  614.         if (*cp) {
  615.             return *cp++;
  616.         }
  617.  
  618.         if (!getmore) {
  619.             endofinput++;
  620.         } elif ((*getmore)(cp = cbuf + StartOffset) == NULL) {
  621.             endofinput++;
  622.         }
  623.     }
  624.  
  625.     return 0;
  626. }
  627.  
  628. /* 
  629.  * pushBackCh:
  630.  * 
  631.  * Takes a character and pushes it back. Just like ungetc.
  632.  */
  633.  
  634. static
  635. pushBackCh(ch)
  636. char    ch;
  637. {
  638.     *--cp = ch;
  639.     endofinput = 0;
  640. }
  641.  
  642. /* 
  643.  * pushBackStr:
  644.  * 
  645.  * Takes a string and pushes it back into our input so that it will be read
  646.  * next time.
  647.  */
  648.  
  649. static
  650. pushBackStr(str)
  651. char    *str;
  652. {
  653.     register char    *sp;
  654.  
  655.     /* 
  656.      * Find the end of the string.
  657.      */
  658.     
  659.     for (sp = str; *sp; sp++)
  660.         ;
  661.  
  662.     /* 
  663.      * Now write it into the buffer backwards from the current point.
  664.      */
  665.     
  666.     while (--sp >= str) {
  667.         *--cp = *sp;
  668.     }
  669.  
  670.     if (cp < cbuf) {
  671.         error("pushback overflow");
  672.     }
  673.  
  674.     if (strlen(str)) {
  675.         endofinput = 0;
  676.     }
  677. }
  678.  
  679. /* 
  680.  * setInput:
  681.  * 
  682.  * Takes a string and a function, and installs them as the current working
  683.  * text and the function to call to get more when that's used up.
  684.  */
  685.  
  686. void
  687. setInput(str, morefn)
  688. char    *str;
  689. char    *(*morefn)();
  690. {
  691.     endofinput = 0;
  692.     (void) strcpy(cbuf+StartOffset, str);
  693.     cp = cbuf+StartOffset;
  694.     getmore = morefn;
  695. }
  696.  
  697. /* 
  698.  * getItem:
  699.  * 
  700.  * Reads the next item (token) from the input and copies it to the buffer
  701.  * provided to it. The return value is the type of the item (enum item).
  702.  */
  703.  
  704. static char        lastitem[SMBUFSZ];
  705. static enum item    lasttype;
  706. static int        pusheditem = 0;
  707.  
  708. enum item
  709. getItem(ibuf)
  710. char    *ibuf;
  711. {
  712.     char        ch;        /* Our latest character from getCh */
  713.     char        quote = 0;    /* Our current quote char, if any */
  714.     char        *bp = ibuf;    /* Fills up ibuf */
  715.     enum item    itype;        /* What we eventually return */
  716.     char        *value;        /* The value of a possible macro */
  717.  
  718.     if (pusheditem) {
  719.         (void) strcpy(ibuf, lastitem);
  720.         pusheditem = 0;
  721.         return lasttype;
  722.     }
  723.         
  724.     /* 
  725.      * First skip whitespace.
  726.      */
  727.  
  728.     while ((ch = getCh()) && isWhite(ch))
  729.         ;
  730.  
  731.     if (ch == 0) {
  732.         return lasttype = iEndOfInput;
  733.     }
  734.  
  735.     /* 
  736.      * Do we have a quote character in hand?
  737.      */
  738.  
  739.     if (index(Quotes, ch)) {
  740.         quote = ch;
  741.         if (!(ch = getCh())) {
  742.             return lasttype = iEndOfInput;
  743.         }
  744.     }
  745.  
  746.     /* 
  747.      * Loop around building up the item.
  748.      */
  749.  
  750.     for (;;) {
  751.         if (quote) {
  752.             if (ch == quote) {
  753.                 break;
  754.             }
  755.         } elif (isWhite(ch)) {
  756.             pushBackCh(ch);
  757.             break;
  758.         } elif (index(SelfDelim, ch)) {
  759.             break;
  760.         }
  761.  
  762.         *bp++ = ch;
  763.  
  764.         if (!(ch = getCh())) {
  765.             break;
  766.         }
  767.  
  768.         if (bp - ibuf > SMBUFSZ) {
  769.             error("word overflow");
  770.         }
  771.     }
  772.     *bp = '\0';
  773.  
  774.     if (index(SelfDelim, ch)) {
  775.         if (bp == ibuf) {
  776.             /* It was the first character read */
  777.             switch (ch) {
  778.             case Sep:
  779.                 return lasttype = iSeparator;
  780.             case LBrace:
  781.                 return lasttype = iLeftBrace;
  782.             case RBrace:
  783.                 return lasttype = iRightBrace;
  784.             }
  785.         } else {
  786.             /* It terminated the item */
  787.             pushBackCh(ch);
  788.         }
  789.     }
  790.  
  791.     /* 
  792.      * If the thing was quoted, then it is simply a generic word.
  793.      */
  794.     
  795.     if (quote) {
  796.         return iWord;
  797.     }
  798.     
  799.     /* 
  800.      * Now we have a word in ibuf. We must check to see if it is a
  801.      * keyword.
  802.      */
  803.  
  804.     if (isKeyword(ibuf, &itype)) {
  805.         return lasttype = itype;
  806.     }
  807.  
  808.     /* 
  809.      * Is it a macro?
  810.      */
  811.  
  812.     if (isMacro(ibuf, &value)) {
  813.         pushBackStr(value);
  814.         return getItem(ibuf);
  815.     }
  816.  
  817.     /* 
  818.      * I guess it was just a generic word after all.
  819.      */
  820.  
  821.     return lasttype = iWord;
  822. }
  823.  
  824. /* 
  825.  * unGetItem:
  826.  * 
  827.  * Takes the text of the last item and causes it to be returned next time.
  828.  */
  829.  
  830. unGetItem(ibuf)
  831. char    *ibuf;
  832. {
  833.     pusheditem++;
  834.     (void) strcpy(lastitem, ibuf);
  835. }
  836.  
  837. /* 
  838.  * getString:
  839.  * 
  840.  * Reads a self-delimited string from the input, and returns it in the buffer
  841.  * provided. Self-delimited means that the first non-white character is taken
  842.  * to be the delimiter. No macro expansion is done, and quotes are like
  843.  * anything else.
  844.  * Returns 1 or 0 depending on whether there was a string or not. (A separator
  845.  * or end of input can mean no string).
  846.  */
  847.  
  848. int
  849. getString(sbuf, len)
  850. char    *sbuf;
  851. int    len;
  852. {
  853.     char    ch;        /* Our latest character from getCh */
  854.     char    delim;        /* This string's delimiter */
  855.     char    *bp = sbuf;    /* Fills up `sbuf' */
  856.  
  857.     /* 
  858.      * Skip whitespace.
  859.      */
  860.  
  861.     while ((ch = getCh()) && isWhite(ch))
  862.         ;
  863.  
  864.     if (ch == 0 || ch == Sep) {
  865.         return 0;
  866.     }
  867.  
  868.     delim = ch;
  869.  
  870.     do {
  871.         ch = getCh();
  872.     } while ((ch != delim) && (bp < sbuf + len) && (*bp++ = ch));
  873.  
  874.     if (bp == sbuf + len) error("buffer overflow");
  875.  
  876.     *bp = '\0';
  877.     return 1;
  878. }
  879.     
  880. /* end of item.c */
  881. @//E*O*F trf/src/item.c//
  882. chmod u=r,g=r,o=r trf/src/item.c
  883.  
  884. echo x - trf/src/item.h
  885. sed 's/^@//' > "trf/src/item.h" <<'@//E*O*F trf/src/item.h//'
  886. /***    
  887.  ***    item.h --
  888.  ***    
  889.  ***    Definitions for the item stuff for psfig.
  890.  ***    
  891.  ***    N.Batchelder, 3/8/86.
  892.  ***/
  893.  
  894. /* 
  895.  * These are the different types of items we can return.
  896.  */
  897.  
  898. enum item {
  899.     iEndOfInput,
  900.     iSeparator,
  901.     iLeftBrace,
  902.     iRightBrace,
  903.     iFile,
  904.     iFigure,
  905.     iSpace,
  906.     iDelim,
  907.     iDefine,
  908.     iLiteral,
  909.     iWidth,
  910.     iHeight,
  911.     iReserve,
  912.     iClip,
  913.     iBox,
  914.     iLevel,
  915.     iBounds,
  916.     iGlobal,
  917.     iSafe,
  918.     iWord,
  919. };
  920.  
  921. /* 
  922.  * These are the characters that we recognize as special.
  923.  */
  924.  
  925. # define Quotes        "\"'"
  926. # define SelfDelim    "{};"
  927. # define Sep        ';'
  928. # define LBrace        '{'
  929. # define RBrace        '}'
  930.  
  931. enum item    getItem();
  932.  
  933. /* end of item.h */
  934. @//E*O*F trf/src/item.h//
  935. chmod u=r,g=r,o=r trf/src/item.h
  936.  
  937. echo x - trf/src/keywords.c
  938. sed 's/^@//' > "trf/src/keywords.c" <<'@//E*O*F trf/src/keywords.c//'
  939. /***    
  940.  ***    keywords.c --
  941.  ***    
  942.  ***    Keyword recognition function for psfig.
  943.  ***    
  944.  ***    N.Batchelder, 3/8/86.
  945.  ***/
  946.  
  947. # include "psfig.h"
  948. # include "item.h"
  949.  
  950. static struct keypair {
  951.     char        *name;
  952.     enum item    itype;
  953. } keytable[] = {
  954.     "figure",    iFigure,
  955.     "space",    iSpace,
  956.     "delim",    iDelim,
  957.     "define",    iDefine,
  958.     "literal",    iLiteral,
  959.     "file",        iFile,
  960.     "width",    iWidth,
  961.     "height",    iHeight,
  962.     "reserve",     iReserve,
  963.     "clip",        iClip,
  964.     "box",        iBox,
  965.     "level",    iLevel,
  966.     "bounds",    iBounds,
  967.     "global",    iGlobal,
  968.     "safe",        iSafe,
  969.     NULL,        iEndOfInput,
  970. };
  971.  
  972. /* 
  973.  * isKeyword:
  974.  * 
  975.  * Takes the text of an item and returns whether or not it is a keyword.
  976.  * If it is, then it fills in the exact item type in the pointed to enum item.
  977.  */
  978.  
  979. int
  980. isKeyword(buf, iptr)
  981. char        *buf;
  982. enum item    *iptr;
  983. {
  984.     struct keypair    *keyp;
  985.  
  986.     for (keyp = keytable; keyp->name; keyp++) {
  987.         if (!strcmp(buf, keyp->name)) {
  988.             /* 
  989.              * A match!
  990.              */
  991.             
  992.             *iptr = keyp->itype;
  993.             return 1;
  994.         }
  995.     }
  996.  
  997.     return 0;
  998. }
  999.  
  1000. /* end of keywords.c */
  1001.  
  1002. @//E*O*F trf/src/keywords.c//
  1003. chmod u=r,g=r,o=r trf/src/keywords.c
  1004.  
  1005. echo x - trf/src/lineio.c
  1006. sed 's/^@//' > "trf/src/lineio.c" <<'@//E*O*F trf/src/lineio.c//'
  1007. /***    
  1008.  ***    lineio.c --
  1009.  ***    
  1010.  ***    Low level i/o for psfig.
  1011.  ***    Provides the capability to get and unget lines.
  1012.  ***    
  1013.  ***    N.Batchelder, 3/8/86.
  1014.  ***/
  1015.  
  1016. # include <stdio.h>
  1017. # include "psfig.h"
  1018.  
  1019. /* 
  1020.  * This is non-NULL if a line was pushed back.
  1021.  */
  1022.  
  1023. static char    *ungotten = NULL;
  1024.  
  1025. /* 
  1026.  * getline:
  1027.  * 
  1028.  * A lot like fgets, but will return the last line ungotten by ungetline if
  1029.  * there is one.
  1030.  */
  1031.  
  1032. char *
  1033. getline(buf, len, file)
  1034. char    *buf;
  1035. int    len;
  1036. FILE    *file;
  1037. {
  1038.     if (ungotten) {
  1039.         (void) strcpy(buf, ungotten);
  1040.         ungotten = NULL;
  1041.         return buf;
  1042.     }
  1043.  
  1044.     linenumber++;
  1045.     return fgets(buf, len, file);
  1046. }
  1047.  
  1048. /* 
  1049.  * ungetline:
  1050.  * 
  1051.  * Takes the pointer passed to it and saves it to be returned by getline next
  1052.  * time.
  1053.  */
  1054.  
  1055. ungetline(buf)
  1056. char    *buf;
  1057. {
  1058.     if (ungotten) {
  1059.         error("Double ungetline!");
  1060.     }
  1061.     ungotten = buf;
  1062. }
  1063.  
  1064. /* end of lineio.c */
  1065. @//E*O*F trf/src/lineio.c//
  1066. chmod u=r,g=r,o=r trf/src/lineio.c
  1067.  
  1068. echo x - trf/src/macros.c
  1069. sed 's/^@//' > "trf/src/macros.c" <<'@//E*O*F trf/src/macros.c//'
  1070. /***    
  1071.  ***    macros.c --
  1072.  ***    
  1073.  ***    The macro handling stuff for psfig.
  1074.  ***    
  1075.  ***    N.Batchelder, 3/8/86.
  1076.  ***/
  1077.  
  1078. # include "psfig.h"
  1079.  
  1080. # define MaxMacros    100
  1081.  
  1082. /* 
  1083.  * Our table of macros. The end is marked by a pointer (macp). Entries may
  1084.  * have NULL for their name (if they have been deleted).
  1085.  */
  1086.  
  1087. struct mac {
  1088.     char    *name;
  1089.     char    *value;
  1090. };
  1091.  
  1092. static struct mac    macros[MaxMacros];
  1093. static struct mac    *macp = macros;
  1094.  
  1095. /* 
  1096.  * isMacro:
  1097.  * 
  1098.  * Look up a name. If it is a macro, point to the value through an argument,
  1099.  * and return 1. If it isn't, return 0.
  1100.  */
  1101.  
  1102. int
  1103. isMacro(nm, valp)
  1104. char    *nm;
  1105. char    **valp;
  1106. {
  1107.     struct mac    *mp;
  1108.  
  1109.     for (mp = macros; mp < macp; mp++) {
  1110.         if (!strcmp(nm, mp->name)) {
  1111.             *valp = mp->value;
  1112.             return 1;
  1113.         }
  1114.     }
  1115.  
  1116.     return 0;
  1117. }
  1118.  
  1119. /* 
  1120.  * addMacro:
  1121.  * 
  1122.  * Takes a name and a value and enters into the table.
  1123.  */
  1124.  
  1125. addMacro(n, v)
  1126. char    *n;
  1127. char    *v;
  1128. {
  1129.     char        *strsave();
  1130.     struct mac    *mp;
  1131.  
  1132.     if (macp >= macros+MaxMacros) {
  1133.         /* 
  1134.          * Table is full. Attempt to compact it.
  1135.          */
  1136.         
  1137.         for (mp = macros; mp < macp; mp++) {
  1138.             if (mp->name == NULL) {
  1139.                 mp->name = --macp->name;
  1140.                 mp->value = macp->value;
  1141.             }
  1142.         }
  1143.  
  1144.         if (macp >= macros+MaxMacros) {
  1145.             error("macro table overflow");
  1146.         }
  1147.     }
  1148.  
  1149.     macp->name = strsave(n);
  1150.     macp->value = strsave(v);
  1151.     macp++;
  1152. }
  1153.  
  1154. /* 
  1155.  * deleteMacro:
  1156.  * 
  1157.  * Removes the given name from the table.
  1158.  */
  1159.  
  1160. deleteMacro(nm)
  1161. char    *nm;
  1162. {
  1163.     struct mac    *mp;
  1164.  
  1165.     for (mp = macros; mp < macp; mp++) {
  1166.         if (!strcmp(nm, mp->name)) {
  1167.             mp->name = NULL;
  1168.         }
  1169.     }
  1170. }
  1171.  
  1172. /* 
  1173.  * strsave:
  1174.  * 
  1175.  * Stashes its argument away somewhere and returns a new pointer to it.
  1176.  */
  1177.  
  1178. # define NSAVETAB    4096
  1179.  
  1180. static char    *savetab;
  1181. static int    saveleft;
  1182.  
  1183. char *
  1184. strsave(cp)
  1185. register char *cp;
  1186. {
  1187.     register int len;
  1188.  
  1189.     len = strlen(cp) + 1;
  1190.     if (len > saveleft) {
  1191.         saveleft = NSAVETAB;
  1192.         if (len > saveleft)
  1193.             saveleft = len;
  1194.         savetab = malloc((unsigned) saveleft);
  1195.         if (savetab == 0) {
  1196.             error("no more string memory");
  1197.         }
  1198.     }
  1199.     (void) strncpy(savetab, cp, len);
  1200.     cp = savetab;
  1201.     savetab += len;
  1202.     saveleft -= len;
  1203.  
  1204.     return cp;
  1205. }
  1206.  
  1207. /* end of macros.c */
  1208. @//E*O*F trf/src/macros.c//
  1209. chmod u=r,g=r,o=r trf/src/macros.c
  1210.  
  1211. echo x - trf/src/main.c
  1212. sed 's/^@//' > "trf/src/main.c" <<'@//E*O*F trf/src/main.c//'
  1213. /***    
  1214.  ***    main.c --
  1215.  ***    
  1216.  ***    Central stuff for the psfig preprocessor.
  1217.  ***    
  1218.  ***    T.Darrell, 3/86.
  1219.  ***/
  1220.  
  1221. # include "psfig.h"
  1222.  
  1223. int    linenumber = 0;        /* line counter */
  1224.  
  1225. char    delimSt = 0,
  1226.     delimEnd = 0;        /* delimeters */
  1227.  
  1228. char    *XFlush = NULL;        /* The character to flush \X with */
  1229.  
  1230. char    *searchDirTable[MAXDIRS] = { "." };
  1231. int    dircnt = 0;
  1232.  
  1233. char    errbuf[SMBUFSZ];    /* temp buffer for error msg formatting */
  1234.  
  1235. int     psditfix = TRUE;    /* use fix that compensates for the weird
  1236.                     way psdit V2 draws lines (a point
  1237.                     off here and there) 
  1238.                    "-t" option turns off this flag */
  1239.  
  1240. int     newbb = TRUE;        /* search for bounding box comments the
  1241.                     new way.
  1242.                    "-b" option turns off this flag */
  1243.  
  1244. /* 
  1245.  * error:
  1246.  * 
  1247.  * Print an error message, and leave.
  1248.  */
  1249.  
  1250. error(s)
  1251. char    *s;
  1252. {
  1253.     fprintf(stderr,"psfig: line %d: %s\n", linenumber, s);
  1254.     exit(1);
  1255. }
  1256. warn(s)
  1257. char    *s;
  1258. {
  1259.     fprintf(stderr,"psfig: line %d: warning -- %s\n", linenumber, s);
  1260. }
  1261.  
  1262. /* 
  1263.  * getaline:
  1264.  * 
  1265.  * A function that we can pass to the lineio level to get more lines when
  1266.  * processing .F+ .F- commands. Claims that there is no more input when it
  1267.  * hits a .F-.
  1268.  */
  1269.  
  1270. char *
  1271. getaline(buf)
  1272. char    *buf;
  1273. {
  1274.     if (getline(buf, BUFSZ, stdin) == NULL)
  1275.         return NULL;
  1276.  
  1277.     if (!strncmp(buf, FGEND, strlen(FGEND))) {
  1278.         ungetline(buf);
  1279.         return NULL;
  1280.     }
  1281.  
  1282.     return buf;
  1283. }
  1284.  
  1285. /* 
  1286.  * main:
  1287.  * 
  1288.  * The basic loop of the program is simply to read lines from the input, and
  1289.  * if thereare psfig commands to process, to process them. There are three
  1290.  * different ways to mark psfig commands:
  1291.  * 
  1292.  *     1. Between .F+ and .F-
  1293.  *     2. Between delimiter characters
  1294.  *     3. The rest of a line that starts with .F=
  1295.  */
  1296.  
  1297. main(argc, argv)
  1298. int    argc;
  1299. char    *argv[];
  1300. {
  1301.     char        **argp;
  1302.  
  1303.     /* 
  1304.      * Process arguments.
  1305.      */
  1306.     
  1307.     argc--;
  1308.     argp = argv+1;
  1309.  
  1310.     while ((*argp)[0] == '-' && argc--) {
  1311.         switch ((*argp)[1]) {
  1312.  
  1313.         case 'd':    /* Specify draft level to run at */
  1314.             if ((*argp)[2] == '\0') {
  1315.                 Draft = 0;
  1316.                 break;
  1317.             } 
  1318.             *argp += 2;
  1319.             Draft = atoi(*argp);
  1320.             break;
  1321.  
  1322.         case 'f':    /* Ditroff bug: must flush before \X */
  1323.             XFlush = *argp + 2;
  1324.             if (strlen(XFlush) != 2) {
  1325.                 XFlush = "ts";
  1326.             }
  1327.             break;
  1328.  
  1329.         case 't':    /* disable compensation for psdit's line drawing */
  1330.             psditfix = FALSE;
  1331.             break;
  1332.  
  1333.         case 'b':    /* use old bounding box comment search method */
  1334.             newbb = FALSE;
  1335.             break;
  1336.             
  1337.         case 'D':    /* add directory to search list */
  1338.             if (++dircnt > MAXDIRS)
  1339.                 error("too many search directories");
  1340.  
  1341.             searchDirTable[dircnt] = strsave((*argp)+2);
  1342.             break;
  1343.         default:
  1344.             error("bad flag");
  1345.         }
  1346.  
  1347.         argp++;
  1348.     }
  1349.     
  1350.     searchDirTable[dircnt + 1] = NULL;
  1351.  
  1352.     /* 
  1353.      * If we are flushing \X with a character, make sure it doesn't get
  1354.      * printed.
  1355.      */
  1356.  
  1357.     if (XFlush != NULL) {
  1358.         printf(".tr \\(%s \n", XFlush);
  1359.     }
  1360.  
  1361.     /* 
  1362.      * Now we process files. No arguments means standard input. Otherwise,
  1363.      * we just use the named files.
  1364.      */
  1365.     
  1366.     if (argc == 0) {
  1367.         doit();
  1368.     } else {
  1369.         while (argc-- > 0) {
  1370.             if (!freopen(*argp++, "r", stdin)) {
  1371.                 perror("error opening input file");
  1372.                 exit(1);
  1373.             } else {
  1374.                 clearerr(stdin);
  1375.                 doit();
  1376.             }
  1377.         }
  1378.     }
  1379.  
  1380.     exit(0);
  1381. } /* main */
  1382.  
  1383. doit() {
  1384.     char        *ptr, *ptr1, *rest;
  1385.     char        *getaline();
  1386.     static char    buf[BUFSZ];
  1387.  
  1388.     while (getline(buf, sizeof(buf), stdin) != NULL) {
  1389.         
  1390.         if (!strncmp(buf, FGST, strlen(FGST))) {
  1391.             fputs(buf, stdout);            
  1392.             *buf = 0;
  1393.             setInput(buf, getaline);
  1394.             if (dofigcmd()) {
  1395.                 (void) fputc('\n', stdout);
  1396.             }
  1397.             (void) getline(buf, sizeof(buf), stdin);
  1398.             fputs(buf, stdout);
  1399.             continue;
  1400.         }
  1401.  
  1402.         ptr = rest = buf;
  1403.         while (delimSt && (ptr1 = index(ptr, delimSt))) {
  1404.             ptr = ptr1;
  1405.  
  1406.             *(ptr++) = '\0';
  1407.  
  1408.             fputs(rest, stdout);
  1409.  
  1410.             if (rest = index(ptr, delimEnd)) {
  1411.                 *(rest++) = '\0';
  1412.             } else {
  1413.                 error("Unbalanced delimiters");
  1414.             }
  1415.  
  1416.             ++inLineFlag;
  1417.             setInput(ptr, (char *(*)()) NULL);
  1418.             (void) dofigcmd();
  1419.             --inLineFlag; 
  1420.             ptr = rest;
  1421.  
  1422.         } 
  1423.         fputs(ptr, stdout);
  1424.     }
  1425. }
  1426.  
  1427. /* 
  1428.  * getFileBB:
  1429.  * 
  1430.  * Takes a file name and tries to find out what its bounding box is. If it
  1431.  * finds the info, it writes it into the four floats pointed to.
  1432.  */
  1433.  
  1434. getFileBB(filenm, llx, lly, urx, ury)
  1435. char    *filenm;
  1436. float    *llx, *lly, *urx, *ury;
  1437. {
  1438.     char         *bbcomment = "%%BoundingBox:";
  1439.     char         *atend = "(atend)";
  1440.     char         *trailer = "%%Trailer";
  1441.     char         *endcom = "%%EndComments";
  1442.     FILE        *psfile;
  1443.     static char    buf[BUFSZ];
  1444.     float        tllx, tlly, turx, tury;
  1445.     int        foundbb = FALSE;
  1446.     int        intrailer = FALSE;
  1447.  
  1448.     if (!(psfile = fopen(filenm, "r"))) {
  1449.         (void) sprintf(errbuf, "error opening file `%s'", filenm);
  1450.         error(errbuf);
  1451.     }
  1452.  
  1453.     (void) fgets(buf, sizeof(buf), psfile);
  1454.     if (strncmp(buf, "%!", 2)) {
  1455.         (void) sprintf(errbuf, "`%s' not a postscript file", filenm);
  1456.         error(errbuf);
  1457.     }
  1458.  
  1459.  
  1460.  
  1461.     if (newbb)
  1462.          /* 
  1463.           * Use full search for bb comment. Pays attention to
  1464.           * "%%EndComments", "(atend)", and "%%Trailer"
  1465.           */
  1466.          
  1467.          while (fgets(buf, sizeof(buf), psfile)) {
  1468.  
  1469.         /* If the first n chars of buf == %%BoundingBox: */
  1470.         if (!strncmp(buf, bbcomment, strlen(bbcomment))) {
  1471.             char *args = buf;
  1472.             args += strlen(bbcomment);
  1473.             while (*args == ' ') args++;
  1474.             if (!strncmp(args, atend, strlen(atend))) {
  1475.                 /* 
  1476.                  * Scan for trailer section
  1477.                  */
  1478.                 intrailer = FALSE;
  1479.                 while (fgets(buf, sizeof(buf), psfile)) 
  1480.                     if (!strncmp(buf, trailer, strlen(trailer))) {
  1481.                     intrailer = TRUE;
  1482.                     break;
  1483.                     }
  1484.                 if (!intrailer) {
  1485.                     sprintf(errbuf, 
  1486.                      "%%%%Trailer not found in %s", filenm);
  1487.                     error(errbuf);
  1488.                     break;
  1489.                 }
  1490.                 /* 
  1491.                  * Now that we've fouind the trailer
  1492.                  * section, we can continue seaching from 
  1493.                  * the main while.
  1494.                  */
  1495.                 continue;
  1496.             } 
  1497.  
  1498.             if (sscanf(args,"%f %f %f %f", &tllx, &tlly, &turx, &tury)
  1499.                    == 4) {
  1500.                 /* 
  1501.                  * We found a match, now if we are in the
  1502.                  * header section we can leave straight away,
  1503.                  * since the *first* bb comment is the
  1504.                  * relevant one, but if we are in the trailer
  1505.                  * we have to keep going, since the *last*
  1506.                  * instance of a bb is the one we want to use.
  1507.                  * 
  1508.                  * At least so says the Adobe book.
  1509.                  */
  1510.                 if (!intrailer) {
  1511.                     *llx = tllx; *lly = tlly;
  1512.                     *urx = turx; *ury = tury;
  1513.                     foundbb = TRUE;
  1514.                     fclose(psfile);
  1515.                     return;
  1516.                 } else {
  1517.                     *llx = tllx; *lly = tlly;
  1518.                     *urx = turx; *ury = tury;
  1519.                     foundbb = TRUE;
  1520.                     continue;
  1521.                 }
  1522.  
  1523.             } 
  1524.             (void) sprintf(errbuf,
  1525.                 "malformed bounding box comment in %s", filenm);
  1526.             error(errbuf);
  1527.  
  1528.         } /* endif the first n chars match %%BoundingBox */
  1529.  
  1530.         /* 
  1531.          * If the first two characters aren't %% or %!, or
  1532.          * if we reach %%EndComments, and we're not in the
  1533.          * trailer, then we're done.
  1534.          */
  1535.         if (intrailer) continue;
  1536.  
  1537.         if ((strncmp(buf, "%%", 2) && strncmp(buf, "%!", 2))
  1538.             || !strncmp(buf, endcom, strlen(endcom)))
  1539.             break;
  1540.         }
  1541.     else
  1542.         /* 
  1543.          * Use old (simple) search for bb comment.
  1544.          */
  1545.         
  1546.         while (fgets(buf, sizeof(buf), psfile)) {
  1547.         if (sscanf(buf,"%%%%BoundingBox: %f %f %f %f",
  1548.                         llx, lly, urx, ury) == 4) {
  1549.             fclose(psfile);
  1550.             return;
  1551.         }
  1552.         }
  1553.  
  1554.     if (foundbb) {
  1555.         fclose(psfile);
  1556.         return;
  1557.     }
  1558.  
  1559.     (void) sprintf(errbuf,"no bounding box found in %s",filenm);
  1560.     error(errbuf);
  1561. }
  1562.  
  1563. /* 
  1564.  * abspath:
  1565.  * 
  1566.  * Return the absolute expansion of a path, searching all the relevant
  1567.  * directories.
  1568.  */
  1569.  
  1570. char *
  1571. abspath(path)
  1572. char    *path;
  1573. {
  1574.     static char    pathbuf[SMBUFSZ];
  1575.     static char    absbuf[SMBUFSZ];
  1576.     char        **searchDir = searchDirTable;
  1577.  
  1578.     if (!*path) return path;
  1579.  
  1580.     if (*path != '/') {
  1581.         /* 
  1582.          * path is relative, so attempt to locate file
  1583.          * in one of the search directories
  1584.          */
  1585.         
  1586.         do {
  1587.             strcpy(pathbuf, *searchDir);
  1588.             strcat(pathbuf, "/");
  1589.             strcat(pathbuf, path);
  1590.  
  1591.             if (access(pathbuf, F_OK) >= 0) {
  1592.                 /* 
  1593.                  * Now that we know where the file is, we make
  1594.                  * it absolute if necessary, and return it.
  1595.                  */
  1596.  
  1597.                 if (*pathbuf != '/') {
  1598.                     getwd(absbuf);
  1599.                     strcat(absbuf, "/");
  1600.                     strcat(absbuf, pathbuf);
  1601.                     return absbuf;
  1602.                 } else {
  1603.                     return pathbuf;
  1604.                 }
  1605.             }
  1606.         } while (*(++searchDir));
  1607.  
  1608.         /* 
  1609.          * the file was not found in any of the 
  1610.          * search directories, so notify the user
  1611.          * and return the bare path
  1612.          */
  1613.  
  1614.         sprintf(errbuf, "`%s' not found in search directories", path);
  1615.         warn(errbuf);
  1616.     }
  1617.  
  1618.     return path;
  1619. }
  1620.  
  1621. /* end of main.c */
  1622. @//E*O*F trf/src/main.c//
  1623. chmod u=r,g=r,o=r trf/src/main.c
  1624.  
  1625. echo x - trf/src/psfig.h
  1626. sed 's/^@//' > "trf/src/psfig.h" <<'@//E*O*F trf/src/psfig.h//'
  1627. /***    
  1628.  ***    psfig.h --
  1629.  ***    
  1630.  ***    Standard defines for psfig.
  1631.  ***    
  1632.  ***    T.Darrell, 3/86.
  1633.  ***/
  1634.  
  1635. # include <stdio.h>
  1636. # include <sys/file.h>
  1637.  
  1638. # define TRUE    1
  1639. # define FALSE    0
  1640.  
  1641. # define UP    1
  1642. # define DOWN    2
  1643.  
  1644. # define MAXDIRS    12    /* max no. of search dirs */
  1645.  
  1646. # define BUFSZ        1024
  1647. # define SMBUFSZ    128
  1648.  
  1649. # define FGST    ".F+"
  1650. # define FGEND    ".F-"
  1651.  
  1652. # define DraftDefault    100
  1653. # define BrokenOutLevel    10
  1654. # define InLineLevel    1
  1655.  
  1656. # define endof(s) (s + strlen(s))
  1657.  
  1658. extern        Draft, linenumber, inLineFlag;
  1659. extern        psditfix;
  1660. extern char    delimSt, delimEnd;
  1661. extern char    *XFlush;
  1662.  
  1663. extern char    *Strcat(),
  1664.         *Strcpy(),
  1665.         *getline(),
  1666.         *includeFig(),
  1667.         *getLab(),
  1668.         *abspath(),
  1669.         *strsave();
  1670.  
  1671. extern char    *malloc(),
  1672.         *free(),
  1673.         *strcat(),
  1674.         *strcpy(),
  1675.         *strncpy(),
  1676.         *index();
  1677.  
  1678. extern void    pushBackItem(),
  1679.         setInput();
  1680.  
  1681. /* end of psfig.h */
  1682. @//E*O*F trf/src/psfig.h//
  1683. chmod u=r,g=r,o=r trf/src/psfig.h
  1684.  
  1685. echo x - trf/src/troff.c
  1686. sed 's/^@//' > "trf/src/troff.c" <<'@//E*O*F trf/src/troff.c//'
  1687. /***    
  1688.  ***    troff.c --
  1689.  ***    
  1690.  ***    Functions to output perverted Troff command strings for psfig.
  1691.  ***    
  1692.  ***    T.Darrell, 3/86.
  1693.  ***/
  1694.  
  1695. # include "psfig.h"
  1696.  
  1697. /* 
  1698.  * Ditroff output format strings.
  1699.  */
  1700.  
  1701. char saveSpaceDown_s[] = "\\x'%s'";
  1702. char saveSpaceUp_s[] = "\\x'-(%s-\\n(.vu)'";
  1703.  
  1704. saveSpaceV(y, sign)
  1705. char    *y;
  1706. int    sign;
  1707. {
  1708.     if (sign == UP)
  1709.         printf(saveSpaceUp_s, y);
  1710.     else
  1711.         printf(saveSpaceDown_s, y);
  1712. }
  1713.  
  1714.  
  1715. char incl_file_s[] = "\\X'f%s'";
  1716. includeFile(filenm)
  1717. char *filenm; {
  1718.     printf(incl_file_s, filenm);
  1719. }
  1720.  
  1721. sIncludeFile(outbuf, filenm, len)
  1722. int len;
  1723. char *filenm; {
  1724.     sprintf(endof(outbuf), incl_file_s, filenm);
  1725.     if (strlen(outbuf) > len)
  1726.         error("buffer overflow");
  1727. }
  1728.  
  1729. char endfig_s[] = "\\X'pendFig'";
  1730. endfig() {
  1731.     printf(endfig_s);
  1732. }
  1733.  
  1734. char startfig_s[] =
  1735. "\\X'p\\w@\\h@%s@@'\\X'p\\w@\\h@%s@@'\\X'p%.2f'\\X'p%.2f'\\X'p%.2f'\\X'p%.2f'\\X'pstartFig'";
  1736.  
  1737. startfig(x, y, llx, lly, urx, ury)
  1738. char    *x, *y;
  1739. float    llx, lly, urx, ury;
  1740. {
  1741.     flushX();
  1742.     printf(startfig_s, x, y, llx, lly, urx, ury);
  1743. }
  1744.  
  1745. emitDoClip() {
  1746.     printf("\\X'pdoclip'");
  1747. }
  1748.  
  1749. flushX()
  1750. {
  1751.     if (XFlush != NULL) {
  1752.         printf("\\z\\(%s", XFlush);
  1753.     }
  1754. }
  1755.  
  1756. char makeBoxDn_s_psditfix[] = 
  1757. "\\L'%s\\(br'\\v'+1p'\\l'%s\\(ul'\\v'-1p'\\L'-%s\\(br'\\v'+1p'\\l'-%s\\(ul'\\x'%s'\\v'-1p'";
  1758. char makeBoxDn_s[] = 
  1759. "\\L'%s\\(br'\\l'%s\\(ul'\\L'-%s\\(br'\\l'-%s\\(ul'\\x'%s'";
  1760.  
  1761. makeBox(x, y)
  1762. char    *x, *y; 
  1763. {
  1764.     if (psditfix)
  1765.         printf(makeBoxDn_s_psditfix, y, x, y, x, y);
  1766.     else
  1767.         printf(makeBoxDn_s, y, x, y, x, y);
  1768.  
  1769. }
  1770.  
  1771. char moveDown_s[] = "\\v'%s'";
  1772.  
  1773. moveDown(y)
  1774. char    *y;
  1775. {
  1776.     printf(moveDown_s, y);
  1777. }
  1778.  
  1779. char moveUp_s[] = "\\v'-%s'";
  1780.  
  1781. moveUp(y)
  1782. char    *y;
  1783. {
  1784.     printf(moveUp_s, y);
  1785. }
  1786.  
  1787. char draftNote_s[] = "\\v'1m'\\h'1n'%s\\h'-\\w'%s'u'\\h'-1n'\\v'-1m'";
  1788.  
  1789. draftNote(filenm)
  1790. char    *filenm;
  1791. {
  1792.     printf(draftNote_s, filenm, filenm);
  1793. }
  1794.  
  1795. char saveSpaceH_s[] = "\\h'%s'";
  1796.  
  1797. saveSpaceH(x)
  1798. char    *x;
  1799. {
  1800.     printf(saveSpaceH_s, x);
  1801. }
  1802.  
  1803. #define isWhite(ch) ((ch) == ' ' || (ch) == '\t' || (ch) == '\n')
  1804.  
  1805. char literal_s[] = "\\X'p%s'";
  1806. emitLiteral(text)
  1807. char *text; {
  1808.     static char litbuf[BUFSZ];
  1809.  
  1810.     *litbuf = 0;
  1811.     sEmitLiteral(litbuf, text, sizeof(litbuf));
  1812.     fputs(litbuf, stdout);
  1813. }
  1814.  
  1815. sEmitLiteral(outbuf, text, len)
  1816. int len;
  1817. char *outbuf, *text; {
  1818.     char *ptr = text;
  1819.  
  1820.     /* 
  1821.      * print each word of the literal (stuff separated by whitespace)
  1822.      * in a separate \X'p'
  1823.      */
  1824.     
  1825.     while (isWhite(*ptr)) ++ptr;
  1826.  
  1827.     /* 
  1828.      * find delimiting character
  1829.      */
  1830.     
  1831.     while (*ptr) {
  1832.  
  1833.         /* 
  1834.          * skip to next delimiting char.
  1835.          */
  1836.         
  1837.         for (text = ptr; *ptr && !isWhite(*ptr); ++ptr) ;
  1838.  
  1839.         /* 
  1840.          * termainate string here, print this piece, 
  1841.          * then repeat on the rest of the string.
  1842.          */
  1843.  
  1844.         if (!*ptr) {
  1845.             sprintf(endof(outbuf), literal_s, text);
  1846.             break;
  1847.         }
  1848.     
  1849.         *(ptr++) = 0;
  1850.         sprintf(endof(outbuf), literal_s, text);
  1851.     
  1852.         while (isWhite(*ptr)) ++ptr;
  1853.     }
  1854.  
  1855.     if (strlen(outbuf) > len) 
  1856.         error("buffer overflow");
  1857. }
  1858.     
  1859.  
  1860. /* end of troff.c */
  1861. @//E*O*F trf/src/troff.c//
  1862. chmod u=r,g=r,o=r trf/src/troff.c
  1863.  
  1864. echo Inspecting for damage in transit...
  1865. temp=/tmp/shar$$; dtemp=/tmp/.shar$$
  1866. trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
  1867. cat > $temp <<\!!!
  1868.       53     256    1687 README
  1869.       23      69     421 Makefile
  1870.      442     985    7906 cmds.c
  1871.      299     876    4917 item.c
  1872.       48      95     615 item.h
  1873.       63     150     992 keywords.c
  1874.       58     144     832 lineio.c
  1875.      138     352    2043 macros.c
  1876.      409    1239    8192 main.c
  1877.       55     121     822 psfig.h
  1878.      174     352    2825 troff.c
  1879.     1762    4639   31252 total
  1880. !!!
  1881. wc  trf/README trf/src/Makefile trf/src/cmds.c trf/src/item.c trf/src/item.h trf/src/keywords.c trf/src/lineio.c trf/src/macros.c trf/src/main.c trf/src/psfig.h trf/src/troff.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
  1882. if [ -s $dtemp ]
  1883. then echo "Ouch [diff of wc output]:" ; cat $dtemp
  1884. else echo "No problems found."
  1885. fi
  1886. exit 0
  1887.