/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */
/* From input file "makelogo.p" */


#include <p2c/p2c.h>


/* makelogo: make a graphical `sequence logo' for aligned sequences
  Tom Schneider
  National Cancer Institute
  Laboratory of Mathematical Biology
  NCI/FCRDC Bldg 469. Room 144
  P.O. Box B
  Frederick, MD  21702-1201
  (301) 846-5581 (-5532 for messages)
  (301) 846-5598 fax
  email: toms@ncifcrf.gov
  http://www-lmmb.ncifcrf.gov/~toms/

module libraries required: delman, prgmods */

/* end of program */

/* begin module version */

#define version         8.76
/* of makelogo.p 1997 September 4
origin 1990 Feb 28 from rsgra */
/* end module version */

/* begin module describe.makelogo */
/*
name
   makelogo: make a graphical `sequence logo' for aligned sequences

synopsis
   makelogo(symvec: in, makelogop: in, colors: in, marks: in,
            wave: in, logo: out, output: out)

files
   symvec:  A "symbol vector" file usually created by the alpro or dalvec
     program.  Makelogo will ignore any number of header lines that begin
     with "*".  The next line contains one number (k) that defines the number
     of letters in the alphabet.  and then defines the composition of letters
     at each position in the set of aligned sequences.

     Each composition begins with 4 numbers on one line:

     1. position (integer);
     2. number of sequences at that position (integer);
     3. information content of the position (real);
     4. variance of the information content (real).

     This is followed by k lines.  The first character on the line
     is the character.  This is followed by the number of that character
     at that position.

     Example:

* position, number of sequences, information Rs, variance of Rs
4 number of symbols in DNA or RNA
-100       86 -0.00820  6.3319e-04
a   27
c   18
g   20
t   21
 -99       86 -0.00436  6.3319e-04
a   26
c   19
g   17
t   24

     * If the symvec file is empty, the alphabet is printed as a test.

     * If the error bars values are negative, they are not displayed.  This
     allows the sites program to control the display when it would not be
     appropriate.

     * If the number of a symbol is negative in symvec, then the symbol will
     be rotated 180 degrees before being printed.  The absolute value is used
     by makelogo to determine the height.  This allows statistical tests
     which find rare symbols to be significant to show that the symbol is
     rare by having it up side down.  Notice that ACGT are all easy to
     distinguish from their upside down versions, but unfortunately this is
     not always true for protein sequences.  Program dalvec contains a switch
     for turning the letters over in the ChiLogo.

   makelogop: parameters to control the program.

     line 1: contains the lowest to highest range of the binding
             site to do the logo graph. (FROM to TO range)

     line 2: bar: sequence coordinate before which to print a vertical bar
             NOTE: the vertical bar takes up a small amount of horizontal
             space.  However, to make sure that marks are placed correctly,
             the logo is not offset.  The bar will overwrite the previous
             stack and the next stack will overwrite the bar.

     line 3: xcorner and ycorner.  This is the coordinate of the lower left
             hand corner of the logo (in cm).  These should be real numbers.

             If the first letter of this line is "z", then the program expects
             three numbers:  xcorner, ycorner and zerobase.  Zerobase is a real
             number defining the position on the sequence that the zero of the
             coordinate system is to be set.  For example, setting zerobase to
             0 (zero) will place the center of the 0 at xcorner, ycorner.  This
             special feature allows the logo to be precisely placed relative to
             other logos so that they can be aligned one above another in a
             figure.

     line 4: rotation: angle in degrees to rotate the logo.  Warning:
             rotations other than by factors of 90 degrees may produce
             incorrect logos because character scaling depends on the
             orientation of the characters.  (Essentially, it's a design
             fault of PostScript.)

     line 5: charwidth: (real, > 0) the width of the logo characters, in cm

     line 6: barheight barwidth: (real, > 0) height of the vertical bar, in cm,
             and its width, in cm.

     line 7: barbits: (real) The height of the vertical bar, in bits, is given
             by the absolute value of barbits.  If barbits is positive, an
             "I-beam" will appear at the top of the symbol stack.  The I-beam
             indicates one standard deviation of the stack height, based
             entirely on how small the sample of sequences is.  If the value of
             barbits is negative, the I-beam is not displayed.  Not knowing how
             big the sampling effects are can fool one, so one should usually
             have the I-beam, even if it is ugly.
                WARNING: it is not known how to calculate the error for data
             derived from a dirty DNA synthesis experiment (see Schneider1989,
             reference given below).  In that case the error could be
             calculated (in program sites) from the number of sequences, so
             that the error bar would be an underestimate of the variation.
             Unfortunately, when I tried this, people interpreted the error bar
             as the size they saw, so this does not work well visually.
             Therefore when data come from the sites program, the I-beam is
             suppressed.
                The combination of barheight and barbits determines the size of
             the logo in bits per centimeter.  Both must be specified even if
             no vertical bar is desired.

     line 8: Ibeamfraction: real. The fraction of the vertical part of the
             Ibeam to draw.  When it is 1, the Ibeam is normal.  When it is
             zero, no vertical line is drawn.  At 0.1, only 10 percent of the
             top half and 10 percent of the bottom half of the Ibeam is drawn,
             for a total of 10 percent of the entire ibeam.  More precisely,
             this number is the fraction of a standard deviation to draw.
             Negative values will reverse the direction of the part drawn,
             making a 'thumbtack'.  (Note:  if this parameter is missing, as in
             old makelogop files, the program will ignore it.)  I thank Shmuel
             Pietrokovski (Structural Biology department, Weizmann Institute of
             Science, 76100 Rehovot - ISRAEL, bppietro@dapsas1.weizmann.ac.il)
             for suggesting this method, and for the code to do it.  See
             further description below.

     line 9: barends: if the first character on the line is a 'b', then bars
             are put before and after each line, in addition to the other bar.
             The first bar on each line is labeled with tic marks and
             the number of bits.  If you don't want this, you can remove
             the call to maketic in the logo.  This is easily done in Unix with

               grep -v maketic.startline logo > logo.without.tics

             That is, the PostScript code that generates the tic marks
             is on one line and there is a comment containing "maketic.startline".
             The grep removes that entire line from the logo file.
             Likewise, the bars at the start and end of the lines can be
             removed with:

               grep -v makebar.startline logo > logo.without.start.bar
               grep -v makebar.end linelogo   > logo.without.end.bar

    line 10: showingbox: if the first character on the line is an 's',
             then show a box around each character.  This is useful to
             check that the heights of the letters are correct and to
             distinguish the letters from each other when amino acids
             are represented.

             If the character is an 'f', then the box is filled and no
             character is shown.  This is useful for showing 'logos' of
             extremely large size where the individual character is not
             readable, but the color is.

    line 11: outline: If the first character is 'o' then the characters show
             up in outline form.  Otherwise, they are solid.

    line 12: caps: if the first letter is 'c' then alphabetic
             characters are converted to capital form.

    line 13: stacksperline: number of character stacks per line output.
             A "stack" is a vertical set of characters.  A "line" is a series
             of stacks.  One may have several lines per page (next parameter).
             Special note: This value is used to do the centering of strings.
             For a range of -23 to +19, you have to set it to (19)-(-23)+1 = 43
             to get your title centered correctly.  You can get the program to
             tell you the number '43' by setting stacksperline very large, in
             which case it realizes there is something wrong and does the
             calculation.

    line 14: linesperpage: number of lines per page output

    line 15: linemove: line separation relative to the barheight
             Note:  This affects the BoundingBox discussed below.

    line 16: numbering: if the first letter is 'n' then each stack is
             numbered.  Otherwise, the number is suppressed in a PostScript
             if statement.  This allows you to modify the logo file by hand to
             reinstate numbering for only the positions you want by removing
             or changing the if statement calls to makenumber.  For example,

                numbering {(6) makenumber} if

             Is the PostScript for making the number "6" under the global
             numbering control.  To make "6" always be there, change it to:

                true {(6) makenumber} if

    line 17: shrinking: (real)  Factor by which to shrink the characters.  If
             shrinking <= 0 or shrinking >= 1 then the characters exactly fit
             into the box.  If shrinking > 0 and shrinking < 1, the
             characters are shrunk inside the box.  To use this feature,
             the parameter showningbox be on, so that the user does not create
             a logo whose height is misleading.

    line 18: strings: the number of user defined strings to follow.  Each
             string definition takes up two lines.  The first is the (x,y)
             coordinate of the string, the second is the string itself.  The
             coordinates are in centimeters relative to the coordinate
             transforms performed above.  (This way, the title position stays
             the same relative to the logo.)

    line 18+strings+1: (x,y,s) coordinates of first user defined string (if
             strings >= 1) followed by the factor by which to scale the
             string.  A factor of 1 means no scaling.  In addition, if the x
             coordinate is less than or equal to -1000, then the string is
             centered by using the string width, the stacksperline and
             charwidth.  Note!  To allow more parameters, it is no longer true
             that one may turn off the strings by setting the number of strings
             to 0, but the lines can be left in the file.  If strings are zero,
             then they must be removed.

    line 18+strings+2: the first user defined string (if strings >= 1)

    line 18+strings+3: (x,y,s) coordinates of second user defined string (if
            strings >= 2)

    line 18+strings+3: (x,y,s) coordinates of second user defined string (if
            strings >= 2)

             Special string controls:
             \i italics toggle
                To make italics, use \i twice, around the text.
             \n 5 give number of sequences at coordinate 5.
                If out of range, give maximum in symvec. (not implemented)
             \\ produce backslash
             \160 produce the Greek letter pi from the PostScript Symbol font.
                These fonts are listed on pages 270 to 273 of the "Red" book
                (see references, below).

not implemented yet:
             \r produce Rsequence
             \s produce standard deviation

             Example:
             \n 0 \i E. coli\i LexA binding sites
             will give the number of lexA sites at coordinate 0
             and make "E. coli" in italics.

             For advanced users:
             HOW TO MAKE ITALICS IN YOUR STRINGS using PostScript
             To allow for italics, use a string like this:
38\) \( E. coli \) IT \(LexA binding sites
             This will make the words "E. coli" in Times-BoldItalic font,
             but leave "38" and "LexA binding sites" in Times-Bold.
             See the technical notes for how this works.  The toggle form
             "\i" uses the same method, but simplifies it for the user.
             This method allows one to create any PostScript commands.

    line 18+2*strings+1: edgecontrol edgeleft, edgeright, edgelow, edgehigh:
             edgecontrol is a single character that controls how the bounding
             box of the figure is handled.  If it is 'p' then the bounding box
             will be the page parameters defined in constants inside the
             program (llx, lly, urx, ury).  Otherwise, there are four real
             numbers that define the edges around the logo in cm.  To allow a
             sequence logo to be imbedded into another figure, its size must be
             defined in PostScript (with %%BoundingBox).  The basic logo fits
             within a rectangle, but the numbers along the bottom symbols and
             labels may be anywhere outside.  By setting these four numbers,
             the edges are defined.

    line 18+2*strings+2: ShowEnds: a single character
             d: show for DNA 5' and 3' on the logo
             p: show for protein N and C on the logo
             otherwise: nothing is shown.

    The remainder of the file is ignored and may contain comments.

   colors: Defines the color of each character printed.
     Any number of lines that begin with an asterisk [*] can be used
     as comments to identify the file or portions of the file.
     Put into the file one line for each character that is to
     have a color other than black.  The line must contain:
                    character red green blue
     The last three parameters are real values between 0 and 1 (inclusive).
     The values depend on the PostScript interpreter, but 0 means black
     and a value of 1 means the most bright.
     To assign the asterisk a color, proceed it with a backslash [as \*].
     To assign the backslash a color, proceed it with a backslash [as \\].
     If the file is empty, the logo is made in black and white and the lower
     half of the I-beam error bar is made white so that when it is inside the
     letters it is visible.

   marks: an empty file means no marks are made.  Otherwise, a series of lines
     contain data that define marks to be placed on the output:

        symbol and kind: the first two characters on the line define
        the symbol and then how to draw the symbol.  The symbols are:
           c circle
           b box
           l line
           t triangle
           s square
           u Begin a user defined symbol.  Define a symbol yourself in
             PostScript.  The PostScript code may extend over several lines.
             The end of the code is given by the character "!" at the start of
             a line.  (The rest of the "!" containing line is ignored.)  This
             allows one simply to insert some pre-tested PostScript between
             "u" and "!" lines of the marks file.  The code will be passed 4
             coordinates and any other parameters given in the U line (defined
             below).
           U Call the user defined symbol.  The U must be followed by 4
             coordinates numbers: x1 y1 x2 y2.  The x1 and x2 are in bases,
             while y1 and y2 are in bits.  The remainder of the line is copied
             to the logo file, so you can have more parameters there.  End the
             line with the name of one of your defined symbols.
           * a comment line
           % a comment line

        The drawing types are:
           s stroke
           f fill
           d dash

        If marksymbol is c, t or s, three more parameters are required:
           base coordinate: a real number that determines the center of the mark
           bits coordinate: a real number that determines the position of the
              mark in bits.
           scale: a positive real number in units of bases that is the diameter
              of the circle or the diameter of a circle that the equilateral
              triangle would be enscribed in.  For the square, it is the side.
              By using units of bases, these marks automatically will fit
              between bases on the logo, as the charwidth is changed or other
              scaling is done.

        If marksymbol is b, l or U, 4 more parameters are required:
           base coordinate: a real number that determines end 1
           bits coordinate: a real number that determines end 1
           base coordinate: a real number that determines end 2
           bits coordinate: a real number that determines end 2
        The line is drawn from end 1 to end 2 while these ends define box
        diagonal.  Note that the center of a base is defined as an integer, so
        one must add 0.5 to base coordinates to put a boxes around a base.  You
        may make the user symbol use these coordinates however you want.

        ********************************************************************
        * The symbols MUST be in increasing order of position in the site! *
        ********************************************************************

        The symbols must be given in the order of their use in bases.  If
        symbols are not there, check the order.

        Since symbols are drawn concurrently with the logo letters, drawing a
        box or line symbol that has an end 2 to the left of the current
        position (which is end 1) will draw over the letters (because the letter
        was already drawn), while drawing to the right will draw under the
        letters (because the base is drawn over later).

   wave: Define a cosine wave over the graph.  Empty file means no cosine
     wave, otherwise the parameters of the wave are given one per line:
       extreme: char;  h or l, the extreme high or low point on the curve
          defined by the wavelocation and wavebit
       wavelocation: real; the location in bases of the extreme
       wavebit: real; the location in bits of the extreme
       waveamplitude: real; the amplitude of the wave in bits
       wavelength: real (positive); the wave length of the wave in bases
       dash: real; the size of dashes in cm.  Zero or negative means no dashes
       thickness: real; thickness of the wave in cm.  Zero or negative
          means the value defaults to PostScript line thickness.

   logo: the output file, a PostScript program to display the logo.

   output: messages to the user

description

   The makelogo program generates a `sequence logo' for a set of aligned
   sequences.  A full description is in the documentation paper.  The input is
   an `symvec', or symbol-vector that contains the information at each
   position and the numbers of each symbol.  The output is in the graphics
   language PostScript.

   The program now indicates the small sample error in the logo by a small
   'I-beam' overlayed on the top of the logo.  Although the user may
   turn this off to make pretty logos, I strongly recommend use of it
   to avoid being fooled by small amounts of data.

   Making A Logo As Part of Another Figure
   ---------------------------------------

   The normal logo file is designed to stand by itself.  However, it is often
   desirable to incorporate the logo as part of another figure.  The difficulty
   is that the stand-alone logo PostScript program will erase the page (which
   wipes out any previous figure drawing) and show the page (which prints the
   page right after the logo).  To prevent these actions, the lines of
   PostScript code which do this have comments that contain the word REMOVE.
   All you have to do is remove these lines and your logo will be able to fit
   into your figure.  In Unix this can be easily done by:

   grep -v REMOVE logo > logo.ps

   If you do this, then it is advisable to do the erasepage and the
   showpage yourself.  A convenient way to do this is to have several
   files that contain postscript commands, and to use a shell script
   to concatenate them together:

   cat start.ps logo.ps end.ps > myfigure.ps

   If you have a large number of logos together in one figure, you can reduce
   the size of the final figure by another trick.  Logo files begin with a
   header which is the same from one figure to the next assuming you don't
   change colors/letter combinations.  So the first logo in the figure must
   contain this header, but later ones don't really need it.  You can remove
   the header material by using the censor program:

   censor < logo.ps > logo.no.header.ps

   EXAMPLE:
   Suppose that you have two logo files, 1 and 2.  Then to join them,
   you can use the unix commands:
      grep -v REMOVE 1 > 3
      censor < 2 >> 3
      echo "showpage" >> 3
   The grep removes the REMOVE lines from file 1 and puts the rest into the
   start of file 3.  The censor removes the duplicate PostScript definitions
   from file 2 and appends the remainder to the end of 3.  Finally, the echo
   puts a 'showpage' command on the end of the file so that the printer will
   print the page (otherwise you won't get any printout).

   Playing with Ibeams
   -------------------
   Shmuel Pietrokovski (bppietro@dapsas1.weizmann.ac.il) suggested that the
   middle of the Ibeams be removable so that it doesn't get in the way of
   logos.  That is, a normal Ibeam looks like:

   -----
     |
     |
     |
     |
     |
     |
   -----

   This is sitting on the top of the sequence logo stack of letters.  This is
   obtained by setting the Ibeamfraction to 1.0.  Shmuel suggested that there be
   a parameter to remove the vertical part or to have it partway:

   -----
     |
     |


     |
     |
   -----

   This is obtained by setting the Ibeamfraction to 0.6.  Setting Ibeamfraction
   to -1.0, puts the vertical parts OUTSIDE the bars.  This way one can read
   one standard deviation of the stack and also have a mark at (for example) 2
   standard deviations out at the tips of the thumb tacks:

     |
     |
   -----


   -----
     |
     |

see also
   rsgra.p, rseq.p, dalvec.p, alpro.p, sites.p, censor.p
   symvec, makelogop, colors, marks, wave, logo
   marks.arrow
   marks.lettering

author
   Thomas D. Schneider
   National Cancer Institute
   Laboratory of Mathematical Biology
   NCI/FCRDC Bldg 469. Room 144
   P.O. Box B
   Frederick, MD  21702-1201
   (301) 846-5581 (-5532 for messages)
   email: toms@ncifcrf.gov

examples
   makelogop parameters:

-15 2      FROM to TO range to make the logo over
1          sequence coordinate before which to put a bar on the logo
15 2       (xcorner, ycorner) lower left hand corner of the logo (in cm)
90         rotation: angle to rotate the graph
1.0        charwidth: (real, > 0) the width of the logo characters, in cm
10 0.1     barheight, barwidth: (real, > 0) height of vertical bar, in cm
2          barbits: (real) height of the vertical bar, in bits; < 0: no I-beam
no bars    barends: if 'b' put bars before and after each line
show       showingbox: if 's' show a dashed box around each character; f = fill
no outline outline: if 'o' make each character as an outline
100        stacksperline: number of character stacks per line output
1          linesperpage: number of lines per page output
1.1        linemove: line separation relative to the barheight
numbers    numbering: if the first letter is 'n' then each stack is numbered
1          shrinking: factor by which to shrink characters inside dashed box
2          strings: the number of user defined strings to follow
2 14 1     coordinates of the first string (in cm)
First TITLE
3 13 1     coordinates of the second string (in cm)
SECOND TITLE
n 2 1 2 1  edgecontrol (p=page), edgeleft, edgeright, edgelow, edgehigh in cm
d          d: 5' 3'; p: N C; else: nothing shown on ends

makelogop.dna: parameters for the makelogo program, version 8.31 or higher

   colors:
* Color scheme for logos of DNA (for the makelogo program).
* color order is red-green-blue
*
* green:
A 0 1 0
a 0 1 0
*
* blue:
C 0 0 1
c 0 0 1
*
* red:
T 1 0 0
t 1 0 0
*
* orange:
G 1 0.7 0
g 1 0.7 0

   wave:
l        extreme: char; h or l, the high or low extreme to be defined
2        wavelocation: real; the location in bases of the extreme
1.0      wavebit: real; the location in bits of the extreme
0.5      waveamplitude: real; the amplitude of the wave in bits
10.4     wavelength: real; the wave length of the wave in bases
0        dash: real; the size of dashes in cm.  dash <= 0 means no dashes
0.1      thickness: real; thickness of the wave in cm. <=0: default.

   marks:

* example marks file for makelogo 8.06 and higher
*
* square stroked, filled and dotted:
ss -2 -0.40 0.5
sf -1 -0.30 0.5
sd  0 -0.20 0.5
*
* circle stroked, filled and dotted:
cs  1 -0.40 0.5
cf  2 -0.30 0.5
cd  3 -0.20 0.5
*
* triangle stroked, filled and dotted:
ts  4 -0.40 0.5
tf  5 -0.30 0.5
td  6 -0.20 0.5
*
* box stroked, filled and dotted base to base:
bs  7 -0.40  8 0
bf  8 -0.30  9 0
bd  9 -0.20 10 0
*
* line stroked, filled and dotted base to base:
ls 10 -0.40 11 0
lf 11 -0.30 12 0
ld 12 -0.20 13 0
*
* box stroked, filled and dotted, around bases:
bs 13.5 -0.40 14.5 0
bf 14.5 -0.30 15.5 0
bd 15.5 -0.20 16.5 0
*
* line stroked, filled and dotted, around bases:
ls 16.5 -0.40 17.5 0
lf 17.5 -0.30 18.5 0
ld 18.5 -0.20 19.5 0

  A test symvec is provided with the program, file 'symvec.demo', to be run with
  'colors.demo' and 'makelogop.demo'.

documentation
   Description of Logos:
@article{Schneider.Stephens.Logo,
author = "T. D. Schneider
 and R. M. Stephens",
title = "Sequence Logos: A New Way to Display Consensus Sequences",
journal = "Nucl. Acids Res.",
volume = "18",
pages = "6097-6100",
year = "1990"}

   Use of wave:
@article{Papp.helixrepa,
author = "P. P. Papp
 and D. K. Chattoraj
 and T. D. Schneider",
title = "Information Analysis of Sequences that Bind
the Replication Initiator {RepA}",
journal = "J. Mol. Biol.",
comment = "Cover of 233, number 2!",
volume = "233",
pages = "219-230",
year = "1993"}

   Dirty DNA synthesis experiments:
@article{Schneider1989,
author = "T. D. Schneider
 and G. D. Stormo",
title = "Excess Information at Bacteriophage {T7} Genomic Promoters
Detected by a Random Cloning Technique",
year = "1989",
journal = "Nucl. Acids Res.",
volume = "17",
pages = "659-674"}

   The Blue Book:
@book{PostScriptTutorial1985,
author = "{Adobe Systems Incorporated}",
title = "PostScript Language Tutorial and Cookbook",
publisher = "Addison-Wesley Publishing Company",
address = "Reading, Massachusetts",
callnumber = "QA76.73.P67P68",
isbn = "0-201-10179-3",
year = "1985"}

   The Red Book:
@book{PostScriptManual1985,
author = "{Adobe Systems Incorporated}",
title = "PostScript Language Reference Manual",
publisher = "Addison-Wesley Publishing Company",
address = "Reading, Massachusetts",
callnumber = "QA76.73.P67P67",
isbn = "0-201-10174-2",
year = "1985"}

bugs
   Some chi-logo (upside down characters) do not display on OpenWindows, but do
   print ok on the Apple LaserWriter IIntx.  The reason is completely obscure.

   A bug in NeWS 1.1 is that characters that are scaled too small are forced to
   be big.  This messes up the logo and can be confusing.  Another bug in NeWS
   1.1 prevents one from using the outline, but the dashed boxes will show up.
   Sometimes displaying a logo in NeWS 1.1 on a Sun 4 will cause an 'illegal
   instruction', after which one is thrown completely off the computer.  The
   source of this is not known, since it is not repeatable.  The first two bugs
   are resolved under OpenWindows 2; the third has not been observed.  These
   NeWS bugs do not apply to the Apple LaserWriter IIntx, which prints
   everything correctly.

   * MISSING LOGO LETTER PROBLEM
   The OpenWindows PostScript on a Sun workstation will mess up displaying a
   stack of letters if the vertical movement is too small.  The result is that
   the letters above that point are missing.  This occurs if there is a highly
   conserved base and very few other bases.  The result is a huge gap where the
   highly conserved base should be.  Other printers do fine, so this is a
   problem with the Sun implementation of PostScript (will they ever get it
   right???).  If you don't have this window system, set the constant
   gooddisplay to true.  If you do want the logos to show up properly on the
   screen, use false.  Unfortunately, this will mean that the vertical
   translation for the small letters won't be done, so the display will be very
   slightly wrong.

   * The freeware program Ghostview will sometimes refuse to print some bases,
   but they come out just fine on many printers.

technical notes

   * HERE'S HOW ITALIC STRINGS WORK.
   User defined strings have to be rendered into PostScript.  To indicate that
   a region of the string is to be done in italics, one must gain access to the
   PostScript machinery.  For example:

38\) \( E. coli \) IT \(LexA binding sites (extra parenthesis)

   The first "\)" after the "38" switches to the PostScript interpreter. The
   backslash "\" is used as an "escape" character, telling makelogo that the
   following character is to be interpreted as PostScript.  (Otherwise makelogo
   would protect the character and you would just get a parenthesis.)
   Likewise, the string

\( E. coli \)

   is interpreted as a PostScript string.  At that point there will be two
   strings on the stack, the (38) and the "( E. coli )".  There is a special
   function defined in makelogo called IT.  IT takes these two strings and
   shows the first in Times-Bold and the second in Times-BoldItalic.  After that
   we must return to normal typing, and this is done with "\(" just before
   "LexA".  The general form for using PostScript commands is therefore

\) postscriptstuff \(

   That is, the parenthesis always match backwards.  The code (procedure
   postscriptstring) is curious and interesting because it starts with a string
   like this:

38\) \( E. coli \) IT \(LexA binding sites (extra parenthesis)

   and converts it to the following valid PostScript:

(38) ( E. coli ) IT (LexA binding sites \(extra parenthesis\))

   The escape character by the user is removed from parenthesis,
   while unprotected parenthesis get escape characters!

   Why not let the user type raw postscript?  Because they would have to
   remember to type a \ in front of various characters, and this would often
   lead to programs that would bomb.

   Note that one can define ANY function one would like by this means!

   * Unfortunately PostScript fonts are not exactly the same height.  Thus if A
   and T are the standard, then C and G hang above and below the line.  This
   has been solved in this version of makelogo.  As a consequence, the user
   never need to determine any character sizes empirically, and the logos
   should work on any PostScript printer.

   Special thanks go to the following people for their help in solving this
   problem:

   Kevin Andresen [kevina@apple.com]
   "The problem facing you is that, while the PostScript language is more or
   less standard, the font shapes depend on the designer, type vendor, or
   language implementation.  The fonts used in NeWS are not exactly the same
   as those from Adobe, which are not the same as those from Bitstream, which
   are not the same as the original lead type, etc.  (This is an
   industry-wide issue.)  One way to compensate for this in PostScript is to
   use the charpath and pathbbox operators and scale appropriately."

   He provided a program, which I then rewrote and generalized.  That version
   almost worked, but not quite.  This was solved by:

   finlay@Eng.Sun.COM (John Finlay) who said:
   "It would appear that the calculation of the pathbbox for characters varies
   with the scale of the characters (I don't know why exactly but would
   speculate that there's probably some weirdness with the font hints and
   scaling).  I modified your postscript to iterate once on the size and
   recalculate the pathbbox at the scaled size.  Seems to printout OK (inside
   the boxes) on a LWI, LWII and in NeWS2.0 (though NeWS still seems to get the
   wide slightly wrong)."

   shiva@well.sf.ca.us (Kenneth Porter) was also involved and actively
   interested.  My apologies if I have forgotten someone else who contributed.

   The letter I and the vertical bar (|) are treated specially since in the
   Helvetica-Bold font they are rectangles and would completely fill the
   character space.  In addition, the letter I is centered by makelogo.

   * Thanks go to Joe Mack for suggesting numbering and titles (strings) and to
   Pete Lemkin and Wojciech Kasprzak for pointing out that the shrink option
   would be helpful.  Thanks to Jeff Haemer for pointing out that the
   PostScript program should begin with '%!', and for suggesting that the
   string fonts should be different from the logos themselves.

   * As of version 8.12, makelogo produces encpsulated PostScript.  This allows
   the logo to be more safely imbedded in other figures.  The BoundingBox,
   which defines the region a figure resides on a page, is computed from the
   basic size of the logo.  The width is computed from the charwidth and
   stacksperline.  The height is computed from barheight, linesperpage and
   linemove.  The linemove parameter is used only if linesperpage is more than
   1.  The edge parameters are then added around all edges.  This allows the
   numbering and labels to be inside the BoundingBox.  The figure can be
   rotated by -90 or +90 degrees.  Other rotations result in a BoundingBox that
   is page-sized.  Note that rotations can place much of the logo outside of
   the page.  The bounding box will not show parts outside of the page, so this
   can be confusing.  To see roughly where the logo will appear on the page,
   use -89 or +89 angles.

   * Constant centertrigger determines the value of the base position
   of a string at which the string will be centered.

*/
/* end module describe.makelogo */

/* begin module makelogo.const */

#define infofield       8
    /* size of field for printing information in bits */
#define infodecim       5
    /* number of decimal places for printing information */

#define nfield          4
    /* size of field for printing n, the number of sites */
#define mapmax          26
    /* the maximum number of symbols that can be sorted */

#define pwid            8
    /* width in character places to print PostScript numbers */
#define pdec            5   /* decimal places to print PostScript numbers */
#define pdecolor        4
/* decimal places for color descriptions (5 WILL CAUSE
                 NeWS 1.1 TO BOMB) */

#define pnum            100000L
    /* 10^pdec for testing when something will round to zero */

#define protecting      true
/* protect the user against PostScript requirements
   in user defined strings.  */

#define gooddisplay     false   /* see technical notes for explanation. */

/* bounding box definitions: */
/* the following bounding box is for the inkjet Phaser 140 */
/* NOTE: these values were reported by the inkjet to be real numbers.
   HOWEVER the definition in the red book (p. 284) explicitly states
   that they must be integers, so before putting out the bounding
   box, they are rounded. */

#define llx             14.4   /* lower left x */
#define lly             28.9   /* lower left y */
#define urx             596.8   /* upper left x */
#define ury             777.7   /* upper left y */

#define edgemargindefault  2   /* the default amount of edge to add (cm) */

#define centertrigger   (-1000)
/* If the location of a string is smaller
   than this number, the string will be centered instead */
/* end module makelogo.const */

/* begin module interact.const */
#define maxstring       150   /* the maximum string */


/* end module interact.const version = 4.15; (@ of prgmod.p 1994 November 12 */


/* begin module interact.type */

typedef struct string {
  /* a string of characters */
  Char letters[maxstring];   /* the letters in the string */
  long length;   /* the number of characters in the string */
  long current;   /* the letter we are working on */
} string;

/* end module interact.type version = 4.15; (@ of prgmod.p 1994 November 12 */

/* begin module rsgra.type */
/* to link several wave definitions together */

typedef struct waveparam {
  /* parameters to define a cosine wave */
  /* define a cosine wave: */
  Char extreme;   /* h or l, the high or low extreme to be defined */
  double wavelocation;   /* the location in bases of the extreme */
  double wavebit;   /* the location in bits of the extreme */
  double waveamplitude;   /* the amplitude of the wave in bits */
  double wavelength;   /* the wave length of the wave in bases */
  double dash;   /* the size of dashes in cm.  dash <= 0 means no dashes */
  double thickness;   /* thickness of the wave in cm.  <= 0 means default */
  struct waveparam *next;   /* the next wave */
} waveparam;

/* end module rsgra.type */

/* begin module makelogo.type */
/* types for sorting the symbols */
typedef char position;

typedef struct place {
  Char b;   /* the symbol */
  /* the number of symbols */
  long n;
} place;

/* type for making a list of strings */

typedef struct strings {
  string astring;
  double x;   /* x coordinate of the string */
  double y;   /* y coordinate of the string */
  double s;   /* scale factor */
  struct strings *next;
} strings;

typedef struct parameters {
  double Ibeamfraction;
  /* The fraction of the Ibeam to draw.  When it is 1,
     the Ibeam is normal.  When it is zero, no vertical line is drawn. At 0.1,
     only 10 percent of the top and bottom parts of the Ibeam are drawn. */
  long bar;   /* location before which to print the bar */
  double barbits;
  /* (real) height of the vertical bar, in bits.  If negative,
     then the I-beam will not be displayed */
  boolean barends;   /* put a | before and after each line? */
  double barheight;
      /* (real, > 0) height of the vertical bar, in centimeters */
  double barwidth;
      /* (real, > 0) width of the vertical bar, in centimeters */
  boolean caps;   /* if true, capitalize the logo */
  double charwidth;
      /* (real, > 0) the width of the logo characters, in cm */
  Char edgecontrol;   /* if 'p' then use page instead of edges */
  double edgeleft, edgeright, edgelow, edgehigh;   /* edges around the logo */
  long highest;   /* the coordinate of the highest symbol to graph in logo */
  double linemove;   /* line separation relative to the barheight */
  long linesperpage;   /* the number of lines per page output */
  long lowest;   /* the coordinate of the lowest symbol to graph in logo */
  boolean numbering;   /* if true, numbers are made below the logo */
  boolean outline;   /* if true, characters are made in outline */
  double rotation;   /* angle in degrees to rotate the figure */
  Char showingbox;   /* s = show a box around each character, f = fill */
  Char ShowEnds;   /* d: 5' 3'; p: N C; else: nothing shown on ends */
  double shrink;   /* the factor by which to shrink symbols */
  boolean shrinking;   /* whether or not to shrink */
  long stacksperline;   /* the number of characters per line output */
  strings *thestrings;   /* set of user defined strings */
  double xcorner;
      /* the lower left corner of the x-axis on the paper (cm) */
  double ycorner;
      /* the lower left corner of the y-axis on the paper (cm) */

  boolean HalfWhiteIbeam;
  /* true means that no colors are defined in the
     colors so the I-beam error bar is made white when inside the letters */
  waveparam *wp;   /* wave parameters that define cosine waves */

  /* other global-like variables */
  double cmperbit;   /* conversion of bits to centimeters */
} parameters;

/* end module makelogo.type */


/* begin module makelogo.var */
Static _TEXT symvec;   /* output of alpro program */
Static _TEXT makelogop;   /* parameters to control the program */
Static _TEXT colors;   /* color definitions */
Static _TEXT marks;   /* locations of marks on the logo */
Static _TEXT wave;   /* cosine wave definition */
Static _TEXT logo;   /* output of program */

/* the storage for sorting the symbols */
Static place map[mapmax];


Static jmp_buf _JL1;


/* end module makelogo.var */

/* begin module halt */
Static Void halt()
{
  /* stop the program.  the procedure performs a goto to the end of the
     program.  you must have a label:
        label 1;
     declared, and also the end of the program must have this label:
        1: end.
     examples are in the module libraries.
     this is the only goto in the delila system. */
  printf(" program halt.\n");
  longjmp(_JL1, 1);
}


/* end module halt version = 4.15; (@ of prgmod.p 1994 November 12 */

/* begin module interact.clearstring */
Static Void clearstring(ribbon)
string *ribbon;
{
  /* empty the string */
  long index;   /* to the ribbon */

  for (index = 0; index < maxstring; index++)
    ribbon->letters[index] = ' ';
  ribbon->length = 0;
  ribbon->current = 0;
}  /* clearstring */


/* end module interact.clearstring version = 4.15; (@ of prgmod.p 1994 November 12 */

/* begin module interact.getstring */
Static Void getstring(afile, buffer, gotten)
_TEXT *afile;
string *buffer;
boolean *gotten;
{
  /* get a string from a file not using string calls.  this lets one
obtain lines from a file without interactive prompts */
  long index = 0;   /* of buffer */

  clearstring(buffer);
  if (BUFEOF(afile->f)) {
    *gotten = false;
    return;
  }
  while (!P_eoln(afile->f) && index < maxstring) {
    index++;
    buffer->letters[index-1] = getc(afile->f);
    if (buffer->letters[index-1] == '\n')
      buffer->letters[index-1] = ' ';
  }

  if (!P_eoln(afile->f)) {
    printf(" getstring: a line exceeds maximum string size (%ld)\n",
	   (long)maxstring);
    halt();
  }

  buffer->length = index;
  buffer->current = 1;
  fscanf(afile->f, "%*[^\n]");
  getc(afile->f);
  *gotten = true;
}  /* getstring */


/* end module interact.getstring version = 4.15; (@ of prgmod.p 1994 November 12 */

/* begin module interact.writestring */
Static Void writestring(tofile, s)
_TEXT *tofile;
string *s;
{
  /* write the string s to file tofile, no writeln */
  long i;   /* index to s */
  long FORLIM;

  FORLIM = s->length;
  for (i = 0; i < FORLIM; i++)
    putc(s->letters[i], tofile->f);
}  /* writestring */


/* end module interact.writestring version = 4.15; (@ of prgmod.p 1994 November 12 */

/* begin module copystring */
Static Void copystring(a, b)
string a, *b;
{
  /* copy string a to b */
  long l;   /* index to the string */

  b->length = a.length;
  for (l = 0; l < a.length; l++)
    b->letters[l] = a.letters[l];
}


/* end module copystring version = 4.15; (@ of prgmod.p 1994 November 12 */

Static boolean lessthan(a, b)
position a, b;
{
  /* see quicksort */
  /* the abs function makes sure upside down
     letters are still sorted the right way! */
  return (labs(map[a-1].n) < labs(map[b-1].n));
}


Static Void swap_(a, b)
position a, b;
{
  /* see quicksort */
  Char holdb;
  long holdn;

  holdn = map[a-1].n;
  map[a-1].n = map[b-1].n;
  map[b-1].n = holdn;

  holdb = map[a-1].b;
  map[a-1].b = map[b-1].b;
  map[b-1].b = holdb;

  /*;write(output,'a=',a:1,', b=',b:1); print (@ for testing */
}


/* begin module quicksort */

Static Void quicksort(left, right)
position left, right;
{
  /* quick sort a list between positions left and right, into ascending order.
     a position is simply a scalar of the form 0..max.
     the array to be sorted is dimensioned 1..max.
(the difference in the ranges is important to the correct operation
of the sort...)
     two external routines are used:
        function lessthan(a, b: position): boolean is a generalized test for
            value-at-a < value-at-b.
        procedure swap(a, b: position) switches the items at positions a and b.
     since these routines are external, the procedure is general.

     this procedure taken from the book
     'algorithms + data structures = programs' by niklaus wirth,
     prentice-hall, inc., englewood cliffs, n.j.(1976), pp. 76-82 */
  position lower = left;
  position upper;   /* the positions looked at currently */
  position center;   /* the rough center of the region being sorted */

  center = (left + right) / 2;
  upper = right;

  do {
    while (lessthan(lower, center))
      lower++;
    while (lessthan(center, upper))
      upper--;

    if (lower <= upper) {
      /* keep track of the center through the map: */
      if (lower == center)
	center = upper;
      else if (upper == center)
	center = lower;
      swap_(lower, upper);
      lower++;
      upper--;
    }
  } while (lower <= upper);

  if (left < upper)
    quicksort(left, upper);
  if (lower < right)
    quicksort(lower, right);
}


/* end module quicksort version = 4.15; (@ of prgmod.p 1994 November 12 */

/* begin module copyaline */
Static Void copyaline(fin, fout)
_TEXT *fin, *fout;
{
  /* copy a line from file fin to file fout */
  while (!P_eoln(fin->f)) {
    putc(P_peek(fin->f), fout->f);
    getc(fin->f);
  }
  fscanf(fin->f, "%*[^\n]");
  getc(fin->f);
  putc('\n', fout->f);
}  /* copyaline */


/* end module copyaline version = 4.15; (@ of prgmod.p 1994 November 12 */

/* ********************************************************************** */
/* begin module makelogo.readwaveparameters */
Static Void readwaveparameters(afile, w)
_TEXT *afile;
waveparam **w;
{
  /* read from afile the wave parameters w */
  waveparam *p;   /* one of the definitions of a cosine wave */

  if (*afile->name != '\0') {
    if (afile->f != NULL)
      afile->f = freopen(afile->name, "r", afile->f);
    else
      afile->f = fopen(afile->name, "r");
  } else
    rewind(afile->f);
  if (afile->f == NULL)
    _EscIO2(FileNotFound, afile->name);
  RESETBUF(afile->f, Char);
  if (BUFEOF(afile->f)) {
    *w = NULL;
    return;
  }
  *w = (waveparam *)Malloc(sizeof(waveparam));
  p = *w;
  while (!BUFEOF(afile->f)) {
    fscanf(afile->f, "%c%*[^\n]", &p->extreme);
    getc(afile->f);
    if (p->extreme == '\n')
      p->extreme = ' ';
    fscanf(afile->f, "%lg%*[^\n]", &p->wavelocation);
    getc(afile->f);
    fscanf(afile->f, "%lg%*[^\n]", &p->wavebit);
    getc(afile->f);
    fscanf(afile->f, "%lg%*[^\n]", &p->waveamplitude);
    getc(afile->f);
    fscanf(afile->f, "%lg%*[^\n]", &p->wavelength);
    getc(afile->f);
    if (p->wavelength <= 0.0) {
      printf("wave parameters: wavelength must be positive\n");
      halt();
    }

    /* one may skip the dash and thickness parameters
       of the last wave definition.  This allows
       backwards compatability, but should not be
       used in general. */
    if (BUFEOF(afile->f)) {
      p->dash = 0.0;
      p->thickness = 0.0;
    } else {
      fscanf(afile->f, "%lg%*[^\n]", &p->dash);
      getc(afile->f);
      if (BUFEOF(afile->f))
	p->thickness = 0.0;
      else {
	fscanf(afile->f, "%lg%*[^\n]", &p->thickness);
	getc(afile->f);
      }
    }
    if (!BUFEOF(afile->f)) {
      p->next = (waveparam *)Malloc(sizeof(waveparam));
      p = p->next;
    } else
      p->next = NULL;
  }
}


/* Local variables for numberdigit: */
struct LOC_numberdigit {
  long number, place_;   /* the exponent of logplace */
  long absolute;   /* the absolute value of number */
  Char acharacter;   /* the character to be returned */
} ;

Local Void digit(LINK)
struct LOC_numberdigit *LINK;
{
  /* extract a digit at the place position */
  long tenplace;   /* ten times place */
  long z;   /* an intermediate value */
  long d;   /* the digit extracted */

  tenplace = LINK->place_ * 10;
  z = LINK->absolute - LINK->absolute / tenplace * tenplace;
  if (LINK->place_ == 1)
    d = z;
  else
    d = z / LINK->place_;
  switch (d) {

  case 0:
    LINK->acharacter = '0';
    break;

  case 1:
    LINK->acharacter = '1';
    break;

  case 2:
    LINK->acharacter = '2';
    break;

  case 3:
    LINK->acharacter = '3';
    break;

  case 4:
    LINK->acharacter = '4';
    break;

  case 5:
    LINK->acharacter = '5';
    break;

  case 6:
    LINK->acharacter = '6';
    break;

  case 7:
    LINK->acharacter = '7';
    break;

  case 8:
    LINK->acharacter = '8';
    break;

  case 9:
    LINK->acharacter = '9';
    break;
  }
}  /* digit */

Local Void sign(LINK)
struct LOC_numberdigit *LINK;
{
  /* put a negative sign out or a positive sign */
  if (LINK->number < 0)
    LINK->acharacter = '-';
  else
    LINK->acharacter = '+';
}  /* sign */


/* end module makelogo.readwaveparameters */
/* ********************************************************************** */

/* ********************************************************************** */

/* begin module numberdigit */
Static Char numberdigit(number_, logplace)
long number_, logplace;
{
  /* return the digit at the place value ('logplace') position of number.
example:
        numberdigit(13625, 3) = 3
        numberdigit(13625, 4) = 1
  */
  struct LOC_numberdigit V;
  long count;   /* used to make place */

  V.number = number_;
  V.place_ = 1;
  for (count = 1; count <= logplace; count++)
    V.place_ *= 10;

  if (V.number == 0) {
    if (V.place_ == 1)
      V.acharacter = '0';
    else
      V.acharacter = ' ';
    return V.acharacter;
  }
  V.absolute = labs(V.number);
  if (V.absolute < V.place_ / 10) {
    V.acharacter = ' ';
    return V.acharacter;
  }
  if (V.absolute >= V.place_)
    digit(&V);
  else
    sign(&V);
  return V.acharacter;
}  /* numberdigit */


#define ln10            2.30259
    /* natural log of 10 - for conversion to log base 10 */
#define epsilon         0.00001
    /* a small number to correct log base 10 errors */


/* end module numberdigit version = 4.15; (@ of prgmod.p 1994 November 12 */

/* begin module numbersize */
Static long numbersize(n)
long n;
{
  /* calculate amount of space to be reserved for the integer n */
  if (n == 0)
    return 1;
  else {
    return ((long)(log((double)labs(n)) / ln10 + epsilon) + 2);
    /* the epsilon assures that we do not lose a place due to
       roundoff.  eg, sometimes log base 10 of 10 would be
       0.9999 instead of 1, and we would not do it right...
       note: this will fail for very large numbers on the order of 1/epsilon. */
    /* the 2 is for the sign and last digit */
  }
}  /* numbersize */

#undef ln10
#undef epsilon


/* end module numbersize version = 4.15; (@ of prgmod.p 1994 November 12 */

/* ********************************************************************** */

/* begin module makelogo.protectpostscript */
Static Void protectcharacter(c, protectioncharacter, needed)
Char c, *protectioncharacter;
boolean *needed;
{
  /* In PostScript, special characters must be protected against.
This routine looks at a character c and returns a protection character
if it is needed.
The parenthesis is used in PostScript to indicate the bounds of a
string, while the percent is the comment character.  The backslash also needs
protection, since it is the escape to indicate that the next character is part
of the string. */
  if (c == '\\' || c == '%' || c == ')' || c == '(') {
    *protectioncharacter = '\\';
    *needed = true;
  } else {
    *protectioncharacter = ' ';
    *needed = false;
  }
}


/* end module makelogo.protectpostscript */

/* begin module makelogo.protectpostscript */
Static Void protectpostscript(afile, c)
_TEXT *afile;
Char c;
{
  /* Special characters must be protected against!  Put out a protective
backslash for character c which would otherwise destroy the PostScript
interpreter.  The parenthesis is used in PostScript to indicate the bounds of a
string, while the percent is the comment character.  The backslash also needs
protection, since it is the escape to indicate that the next character is part
of the string. */
  boolean needed;   /* is protection needed? */
  Char protectionchar;   /* is protection needed? */

  protectcharacter(c, &protectionchar, &needed);
  if (needed)
    putc(protectionchar, afile->f);
}


/* end module makelogo.protectpostscript */

/* begin module processsymvec */
Static Void processsymvec(symvec)
_TEXT *symvec;
{
  /* check for illegal blank lines in symvec */
  boolean done = false;   /* done with the processing */

  while (!done) {
    if (BUFEOF(symvec->f)) {
      printf("symvec has a blank line at the end, this is not allowed\n");
      halt();
      continue;
    }
    if (P_peek(symvec->f) == '*') {
      fscanf(symvec->f, "%*[^\n]");
      getc(symvec->f);
      continue;
    }
    if (P_peek(symvec->f) == ' ')
      getc(symvec->f);
    else if (P_eoln(symvec->f)) {
      fscanf(symvec->f, "%*[^\n]");
      getc(symvec->f);
    } else
      done = true;
  }
}


#define escape          '\\'   /* the escape character is backslash */


/* Local variables for postscriptstring: */
struct LOC_postscriptstring {
  string *instring, *outstring, *rawstring;
  _TEXT *symvec;
  long n;
  boolean haven;
  Char curr;   /* the current character on the line */
  long i;   /* index to s */
  boolean italic;   /* if true, do italics */
  boolean insidestring;   /* are we inside a postscript string? */
  Char prev;   /* the previous character on the line */
} ;

Local Void getchar_(LINK)
struct LOC_postscriptstring *LINK;
{
  /* step forward one character */
  LINK->i++;
  LINK->prev = LINK->curr;
  LINK->curr = LINK->instring->letters[LINK->i-1];
}  /* getchar */

Local Void putchar_(c, LINK)
Char c;
struct LOC_postscriptstring *LINK;
{
  /* put the character c onto the end of outstring */
  LINK->outstring->length++;
  if (LINK->outstring->length > maxstring) {
    printf("postscriptstring: label too long, increase maxstring\n");
    halt();
  }
  LINK->outstring->letters[LINK->outstring->length - 1] = c;

  /* Count characters that are inside unprotected postscript parens.
     That is, count the characters that will really be printed */
  if (LINK->insidestring) {
    LINK->rawstring->length++;
    LINK->rawstring->letters[LINK->rawstring->length - 1] = c;
    /*
writeln(output,'length = ',length:2,
                   ' char = "',letters[length],'"',
                   insidestring);
    */
  }
}  /* putchar */

Local Void badstring(LINK)
struct LOC_postscriptstring *LINK;
{
  _TEXT TEMP;

  printf("This string:\n");
  TEMP.f = stdout;
  *TEMP.name = '\0';
  writestring(&TEMP, LINK->instring);
  printf("\nis bad because parenthesis must be paired like this:\n");
  printf("\"\\)\"  stuff \"\\(\"\n");
  printf("I am emptying the logo file.\n");
  if (*logo.name != '\0') {
    if (logo.f != NULL)
      logo.f = freopen(logo.name, "w", logo.f);
    else
      logo.f = fopen(logo.name, "w");
  } else {
    if (logo.f != NULL)
      rewind(logo.f);
    else
      logo.f = tmpfile();
  }
  if (logo.f == NULL)
    _EscIO2(FileNotFound, logo.name);
  SETUPBUF(logo.f, Char);
  halt();
}  /* badstring */

Local Void doitalics(LINK)
struct LOC_postscriptstring *LINK;
{
  /* generate:
38\) \( E. coli \) IT \(LexA binding sites
38) (E. coli ) IT (LexA binding sites
*/
  LINK->insidestring = false;
  if (LINK->italic) {  /* complete italics */
    putchar_(')', LINK);
    putchar_(' ', LINK);
    putchar_('I', LINK);
    putchar_('T', LINK);
    putchar_(' ', LINK);
    putchar_('(', LINK);
  } else {
    putchar_(')', LINK);
    putchar_(' ', LINK);
    putchar_('(', LINK);
  }
  /* start italics */
  LINK->insidestring = true;
  LINK->italic = !LINK->italic;
}  /* doitalics */

Local Void dosymbol(LINK)
struct LOC_postscriptstring *LINK;
{
  /* from:
38 \160 SY LexA binding sites
generate:
38) (160) SY (LexA binding sites
*/
  LINK->insidestring = false;
  putchar_(')', LINK);

  /* the symbol counts as a single space inside the string */
  LINK->insidestring = true;
  putchar_(' ', LINK);
  LINK->insidestring = false;

  putchar_('(', LINK);
  putchar_('\\', LINK);
  putchar_(LINK->curr, LINK);
  /*get two and put them */
  getchar_(LINK);
  putchar_(LINK->curr, LINK);
  getchar_(LINK);
  putchar_(LINK->curr, LINK);
  putchar_(')', LINK);
  putchar_(' ', LINK);
  putchar_('S', LINK);
  putchar_('Y', LINK);
  putchar_(' ', LINK);
  putchar_('(', LINK);
  LINK->insidestring = true;
}  /* dosymbol */

Local Void don(LINK)
struct LOC_postscriptstring *LINK;
{
  /* insert the number of sequences into the string */
  Char c;   /* a character perhaps to be part of the output number */
  long coo;   /* current coordinate in symvec */
  long num;   /* current number in symvec */
  long maxcoo = -LONG_MAX;   /* maximum coordinate in symvec */
  long maxnum = -LONG_MAX;   /* maximum number in symvec */
  double sd;   /* current sd in symvec */
  double rs;   /* current rs in symvec */
  boolean done = false;   /* done finding number */
  boolean numberstarted = false;   /* have we started reading the number? */
  long sign = 1;   /* -1 or +1 */
  long desiredcoo = 0;   /* the coordinate to get the number of sequences */
  long symbols;   /* number of symbols */
  long s;   /* index to symbols */

  /* pick up the number from the string */
  while (!done) {
    LINK->i++;
    if (LINK->i > LINK->instring->length) {
      done = true;   /* number defaults to zero */
      break;
    }
    LINK->curr = LINK->instring->letters[LINK->i-1];
    if (LINK->curr == '-') {
      if (sign == -1) {
	printf("strings can have only one \"-\" in \\n numbers\n");
	halt();
      }
      sign = -1;
      numberstarted = true;
      continue;
    }
    if (LINK->curr == '9' || LINK->curr == '8' || LINK->curr == '7' ||
	LINK->curr == '6' || LINK->curr == '5' || LINK->curr == '4' ||
	LINK->curr == '3' || LINK->curr == '2' || LINK->curr == '1' ||
	LINK->curr == '0') {
      desiredcoo = desiredcoo * 10 + LINK->curr - '0';
      numberstarted = true;
    } else if (LINK->curr != ' ' || numberstarted)  /* allow leading blanks */
      done = true;
  }
  desiredcoo *= sign;

  /* set string reading variable for further analysis */
  LINK->i--;
  LINK->prev = ' ';
  LINK->curr = LINK->instring->letters[LINK->i-1];

  /* locate the coordinate in the symvec */
  if (!LINK->haven) {
    if (*LINK->symvec->name != '\0') {
      if (LINK->symvec->f != NULL)
	LINK->symvec->f = freopen(LINK->symvec->name, "r", LINK->symvec->f);
      else
	LINK->symvec->f = fopen(LINK->symvec->name, "r");
    } else
      rewind(LINK->symvec->f);
    if (LINK->symvec->f == NULL)
      _EscIO2(FileNotFound, LINK->symvec->name);
    RESETBUF(LINK->symvec->f, Char);
    if (!BUFEOF(LINK->symvec->f)) {
      processsymvec(LINK->symvec);
      fscanf(LINK->symvec->f, "%ld%*[^\n]", &symbols);
      getc(LINK->symvec->f);
    }

    coo = -LONG_MAX;
    while (!BUFEOF(LINK->symvec->f) && coo != desiredcoo) {
      processsymvec(LINK->symvec);
      fscanf(LINK->symvec->f, "%ld%ld%lg%lg%*[^\n]", &coo, &num, &rs, &sd);
      getc(LINK->symvec->f);
      if (num >= maxnum) {
	maxnum = num;
	maxcoo = coo;
      }
      for (s = 1; s <= symbols; s++) {
	fscanf(LINK->symvec->f, "%*[^\n]");
	getc(LINK->symvec->f);
      }
    }

  }

  /* skip header */

  if (BUFEOF(LINK->symvec->f)) {
    if (*LINK->symvec->name != '\0') {
      if (LINK->symvec->f != NULL)
	LINK->symvec->f = freopen(LINK->symvec->name, "r", LINK->symvec->f);
      else
	LINK->symvec->f = fopen(LINK->symvec->name, "r");
    } else
      rewind(LINK->symvec->f);
    if (LINK->symvec->f == NULL)
      _EscIO2(FileNotFound, LINK->symvec->name);
    RESETBUF(LINK->symvec->f, Char);
    if (BUFEOF(LINK->symvec->f)) {  /* symvec is empty */
      coo = 0;
      num = 0;
      printf("* The symvec is empty.\n");
      printf("  Using %ld for the coordinate and %ld for the number.\n",
	     coo, num);
    } else {
      printf("* Coordinate %ld is not in the symvec:\n", desiredcoo);
      printf("  the maximum value (%ld) at coordinate %ld will be used instead.\n",
	     maxnum, maxcoo);
      coo = maxcoo;
      num = maxnum;
    }
  }
  /* we could be eof(symvec) for two reasons.  One is that
     we read to the end of the file.  The other is that
     the file is empty. */

  /* we read to the end */
  /* now put the number into the output strings */
  for (s = numbersize(num); s >= 0; s--) {
    c = numberdigit(num, s);
    if (c != ' ' && c != '+')
      putchar_(c, LINK);
  }

  LINK->n = num;
  LINK->haven = true;
  printf("* %ld sequences found at coordinate %ld\n", LINK->n, LINK->n);
}  /* don */


/* end module processsymvec */

/* begin module makelogo.postscriptstring */
Static Void postscriptstring(instring_, outstring_, rawstring_, symvec_, n_,
			     haven_)
string *instring_, *outstring_, *rawstring_;
_TEXT *symvec_;
long n_;
boolean haven_;
{
  /*
                             lowest, highest: integer;
                             rs, sd: real;
  */
  /*
                             havers, havesd,
  */
  /* copy the instring to the outstring while protecting the
string by blocking postscript specific characters.  Example:
If the user typed    the result should be     so they get
        (                      \(                    (
       \)                       )                    \) (ie real postscript)
In the first case the user just said "I want a '('.  To do this,
we have to put protection on it.
In the second case the user said "I want a '(' as a postscript
command.  To do this, we have to remove the protection!  So this
procedure reverses the protection.  How curious.
The variable outlength reports the output length of the string
not counting real postscript commands so that the string
can be centered.  Of course since the user gives postscript
commands, they could do anything and that could mess up the
centering.  C'est la vie.
The rawstring is the string as the user would see it,
without control stuff or fancy postscript.

New commands:
     \i toggle italics on and off
     \n produce number of sequences
     \160 produce the Greek letter pi

These are not implemented yet:  zzzhandle
     \r produce Rsequence for the current range
     \s produce standard deviation for the current range

The symvec file is used to find the number of sequences
for the \n command.

   */
  struct LOC_postscriptstring V;
  boolean needed;   /* is protection needed? */
  Char protectionchar;   /* is protection needed? */
  _TEXT TEMP;


  /*
;
write(output,' instring = "');
writestring(output,instring);
writeln(output,'"');

write(output,'outstring = "');
writestring(output,outstring);
writeln(output,'"');

write(output,'rawstring = "');
writestring(output,rawstring);
writeln(output,'"');
*/

  V.instring = instring_;
  V.outstring = outstring_;
  V.rawstring = rawstring_;
  V.symvec = symvec_;
  V.n = n_;
  V.haven = haven_;
  if (!protecting) {
    copystring(*V.instring, V.outstring);
    copystring(*V.instring, V.rawstring);
    return;
  }
  clearstring(V.outstring);
  clearstring(V.rawstring);
  V.curr = ' ';
  V.italic = false;
  V.insidestring = false;   /* we start outside the string */
  putchar_('(', &V);
  V.insidestring = true;   /* we are now inside the string */

  V.i = 0;
  while (V.i < V.instring->length) {
    getchar_(&V);

    /* since we just got to a \) we are no longer inside the string */
    if (V.prev == escape && V.curr == ')') {
      if (!V.insidestring)
	badstring(&V);
      V.insidestring = false;
    }

    /* \\ gives \\ */
    if (V.curr == escape) {
      if (V.prev == escape) {
	putchar_(V.prev, &V);
	putchar_(V.curr, &V);
      }
    } else {
      if (V.prev != escape) {
	protectcharacter(V.curr, &protectionchar, &needed);
	if (needed)
	  putchar_(protectionchar, &V);
      }

      if (V.prev == escape && V.curr == 'i')
	doitalics(&V);

      else if (V.prev == escape && V.curr == 'n') {

	don(&V);
      } else if (V.prev == escape &&
		 (V.curr == '7' || V.curr == '6' || V.curr == '5' ||
		  V.curr == '4' || V.curr == '3' || V.curr == '2' ||
		  V.curr == '1' || V.curr == '0')) {

	/*handle other cases (not implemented yet) zzzhandle*/
	/*
	            else if (prev = escape) and (curr = 'r')
	            then don
	            else if (prev = escape) and (curr = 's')
	            then don
	*/

	dosymbol(&V);
      } else
	putchar_(V.curr, &V);
    }


    /* now that we are past the \( we are truely inside the string */
    if (V.prev == escape && V.curr == '(') {
      if (V.insidestring)
	badstring(&V);
      V.insidestring = true;
    }
  }

  if (V.insidestring)
    V.insidestring = false;
  else {
    printf("This string:\n");
    TEMP.f = stdout;
    *TEMP.name = '\0';
    writestring(&TEMP, V.instring);
    printf("\nis bad because it needs a final \"\\(\".\n");
    printf("I am emptying the logo file.\n");
    if (*logo.name != '\0') {
      if (logo.f != NULL)
	logo.f = freopen(logo.name, "w", logo.f);
      else
	logo.f = fopen(logo.name, "w");
    } else {
      if (logo.f != NULL)
	rewind(logo.f);
      else
	logo.f = tmpfile();
    }
    if (logo.f == NULL)
      _EscIO2(FileNotFound, logo.name);
    SETUPBUF(logo.f, Char);
    halt();
  }

  /* close italics if necessary */
  if (V.italic)
    doitalics(&V);

  putchar_(')', &V);
}  /* postscriptstring */

#undef escape


/* end module makelogo.postscriptstring */

/* ********************************************************************** */
/* ********************************************************************** */

/* begin module makelogo.truth */
Static Void truth(f, b)
_TEXT *f;
boolean b;
{
  /* write the true-false value of b to file f */
  if (b)
    fprintf(f->f, "true");
  else
    fprintf(f->f, "false");
}


/* end module makelogo.truth */

/* begin module makelogo.p1 */
Static Void p1(l, params)
_TEXT *l;
parameters params;
{
  fprintf(l->f, "%%\n");
  fprintf(l->f, "%% logo from %ld to %ld\n\n", params.lowest, params.highest);

  fprintf(l->f,
	  "/cmfactor 72 2.54 div def %% defines points -> cm conversion\n");
  fprintf(l->f, "/cm {cmfactor mul} bind def %% defines centimeters\n\n");

  fprintf(l->f, "%% user defined parameters\n");
  fprintf(l->f, "/lowest %ld def\n", params.lowest);
  fprintf(l->f, "/highest %ld def\n", params.highest);
  fprintf(l->f, "/bar %ld def\n", params.bar);
  fprintf(l->f, "/xcorner %*.*f cm def\n", pwid, pdec, params.xcorner);
  fprintf(l->f, "/ycorner %*.*f cm def\n", pwid, pdec, params.ycorner);
  fprintf(l->f, "/rotation %*.*f def %% degrees\n",
	  pwid, pdec, params.rotation);
  fprintf(l->f, "/charwidth %*.*f cm def\n", pwid, pdec, params.charwidth);
  fprintf(l->f, "/barheight %*.*f cm def\n", pwid, pdec, params.barheight);
  fprintf(l->f, "/barwidth %*.*f cm def\n", pwid, pdec, params.barwidth);
  fprintf(l->f, "/barbits %*.*f def %% bits\n", pwid, pdec, params.barbits);
  fprintf(l->f, "/Ibeamfraction %*.*f def\n",
	  pwid, pdec, params.Ibeamfraction);
  fprintf(l->f, "/barends ");
  truth(l, params.barends);
  fprintf(l->f, " def\n");
  fprintf(l->f, "/showingbox (%c) def", params.showingbox);
  fprintf(l->f, "/outline ");
  truth(l, params.outline);
  fprintf(l->f, " def\n");
  fprintf(l->f, "/caps ");
  truth(l, params.caps);
  fprintf(l->f, " def\n");
  fprintf(l->f, "/stacksperline %ld def\n", params.stacksperline);
  fprintf(l->f, "/linesperpage %ld def\n", params.linesperpage);
  fprintf(l->f, "/linemove %*.*f def\n", pwid, pdec, params.linemove);
  fprintf(l->f, "/numbering ");
  truth(l, params.numbering);
  fprintf(l->f, " def\n");
  fprintf(l->f, "/shrinking ");
  truth(l, params.shrinking);
  fprintf(l->f, " def\n");
  fprintf(l->f, "/edgecontrol (%c) def\n", params.edgecontrol);
  fprintf(l->f, "/edgeleft %*.*f def\n", pwid, pdec, params.edgeleft);
  fprintf(l->f, "/edgeright %*.*f def\n", pwid, pdec, params.edgeright);
  fprintf(l->f, "/edgelow %*.*f def\n", pwid, pdec, params.edgelow);
  fprintf(l->f, "/edgehigh %*.*f def\n", pwid, pdec, params.edgehigh);
  fprintf(l->f, "/shrink %*.*f def\n", pwid, pdec, params.shrink);
  fprintf(l->f, "/ShowEnds (%c) def %% d: DNA, p: PROTEIN, -: none\n",
	  params.ShowEnds);
  fprintf(l->f, "/HalfWhiteIbeam ");
  truth(l, params.HalfWhiteIbeam);
  fprintf(l->f, " def\n\n");

  fprintf(l->f, "/knirhs 1 shrink sub 2 div def\n");
  fprintf(l->f, "/charwidth4 charwidth 4 div def\n");
  fprintf(l->f, "/charwidth2 charwidth 2 div def\n\n");

  if (params.outline) {
    fprintf(l->f,
      "%% Since outlining goes around the inner edge of the character\n");
    fprintf(l->f,
	    "%% make the thickness of the character bigger to compensate.\n");
    fprintf(l->f, "/setthelinewidth {2 setlinewidth} def\n");
  } else
    fprintf(l->f, "/setthelinewidth {1 setlinewidth} def\n");
  fprintf(l->f, "setthelinewidth %% set to normal linewidth\n\n");

  fprintf(l->f, "%% define fonts\n");
  fprintf(l->f, "/ffss {findfont fontsize scalefont setfont} def\n");
  fprintf(l->f, "/FontForStringRegular {/Times-Bold       ffss} def\n");
  fprintf(l->f, "/FontForStringItalic  {/Times-BoldItalic ffss} def\n");
  fprintf(l->f, "/FontForLogo          {/Helvetica-Bold   ffss} def\n");
  fprintf(l->f, "/FontForPrime         {/Symbol           ffss} def\n");
  fprintf(l->f, "/FontForSymbol        {/Symbol           ffss} def\n\n");

  fprintf(l->f, "%% Set up the font size for the graphics\n");
  fprintf(l->f, "/fontsize charwidth def\n\n");

  fprintf(l->f, "%% movements to place 5' and 3' symbols\n");
  fprintf(l->f, "/fivemovex {0} def\n");
  fprintf(l->f, "/fivemovey {(0) charparams lx ux sub 3 mul} def\n");
  fprintf(l->f, "/threemovex {(0) stringwidth pop 0.5 mul} def\n");
  fprintf(l->f, "/threemovey {fivemovey} def\n");
  /* \242 is a prime symbol according to the Symbol Encoding Vectors */
  fprintf(l->f,
	  "/prime {FontForPrime (\\242) show FontForStringRegular} def\n\n");

  fprintf(l->f, "%% make italics possible in titles\n");
  fprintf(l->f, "/IT {%% TRstring ITstring IT -\n");
  fprintf(l->f, "  exch show\n");
  fprintf(l->f, "  FontForStringItalic\n");
  fprintf(l->f, "  show\n");
  fprintf(l->f, "  FontForStringRegular\n");
  fprintf(l->f, "} def\n\n\n");

  fprintf(l->f, "%% make symbols possible in titles\n");
  fprintf(l->f, "/SY {%% TRstring SYstring SY -\n");
  fprintf(l->f, "  exch show\n");
  fprintf(l->f, "  FontForSymbol\n");
  fprintf(l->f, "  show\n");
  fprintf(l->f, "  FontForStringRegular\n");
  fprintf(l->f, "} def\n\n");

}


/* end module makelogo.p1 */

/* begin module makelogo.p2 */
Static Void p2(l, colors, params)
_TEXT *l, *colors;
parameters params;
{
  Char symbol;   /* a symbol to which to assign a color */
  double red, green, blue;   /* color definitions */

  putc('%', l->f);
  fprintf(l->f, "(*[[ This special comment allows deletion of the repeated\n");
  fprintf(l->f,
	  "%% procedures when several logos are concatenated together\n");
  fprintf(l->f, "%% See the censor program.\n\n");

  fprintf(l->f, "/charparams { %% char charparams => uy ux ly lx\n");
  fprintf(l->f,
	  "%% takes a single character and returns the coordinates that\n");
  fprintf(l->f, "%% defines the outer bounds of where the ink goes\n");
  fprintf(l->f, "  gsave\n");
  fprintf(l->f, "    newpath\n");
  fprintf(l->f, "    0 0 moveto\n");
  fprintf(l->f, "    %% take the character off the stack and use it here:\n");
  fprintf(l->f, "    true charpath \n");
  fprintf(l->f, "    flattenpath \n");
  fprintf(l->f,
    "    pathbbox %% compute bounding box of 1 pt. char => lx ly ux uy\n");
  fprintf(l->f, "    %% the path is here, but toss it away ...\n");
  fprintf(l->f, "  grestore\n");
  fprintf(l->f, "  /uy exch def\n");
  fprintf(l->f, "  /ux exch def\n");
  fprintf(l->f, "  /ly exch def\n");
  fprintf(l->f, "  /lx exch def\n");
  /*
writeln(l,'%     % print the parameters to the user:');
writeln(l,'%     (lx) lx (ly) ly (ux) ux (uy) uy pstack');
writeln(l,'%     clear % clean up the stack, having printed all that');
*/
  fprintf(l->f, "} bind def\n\n");

  fprintf(l->f, "/dashbox { %% xsize ysize dashbox -\n");
  fprintf(l->f, "%% draw a dashed box of xsize by ysize (in points)\n");
  fprintf(l->f, "  /ysize exch def %% the y size of the box\n");
  fprintf(l->f, "  /xsize exch def %% the x size of the box\n");
  fprintf(l->f, "  1 setlinewidth\n");
  fprintf(l->f, "  gsave\n");
  fprintf(l->f, "    %% Define the width of the dashed lines for boxes:\n");
  fprintf(l->f, "    newpath\n");
  fprintf(l->f, "    0 0 moveto\n");
  fprintf(l->f, "    xsize 0 lineto\n");
  fprintf(l->f, "    xsize ysize lineto\n");
  fprintf(l->f, "    0 ysize lineto\n");
  fprintf(l->f, "    0 0 lineto\n");
  fprintf(l->f, "    [3] 0 setdash\n");
  fprintf(l->f, "    stroke\n");
  fprintf(l->f, "  grestore\n");
  fprintf(l->f, "  setthelinewidth\n");
  fprintf(l->f, "} bind def\n\n");

  fprintf(l->f, "/boxshow { %% xsize ysize char boxshow\n");
  fprintf(l->f,
	  "%% show the character with a box around it, sizes in points\n");
  fprintf(l->f, "gsave\n");
  fprintf(l->f, "  /tc exch def %% define the character\n");
  fprintf(l->f, "  /ysize exch def %% the y size of the character\n");
  fprintf(l->f, "  /xsize exch def %% the x size of the character\n");
  fprintf(l->f, "  /xmulfactor 1 def /ymulfactor 1 def\n\n");

  fprintf(l->f, "  %% if ysize is negative, make everything upside down!\n");
  fprintf(l->f, "  ysize 0 lt {\n");
  fprintf(l->f, "    %% put ysize normal in this orientation\n");
  fprintf(l->f, "    /ysize ysize abs def\n");
  fprintf(l->f, "    xsize ysize translate\n");
  fprintf(l->f, "    180 rotate\n");
  fprintf(l->f, "  } if\n\n");

  fprintf(l->f, "  shrinking {\n");
  fprintf(l->f, "    xsize knirhs mul ysize knirhs mul translate\n");
  fprintf(l->f, "    shrink shrink scale\n");
  fprintf(l->f, "  } if\n\n");

  fprintf(l->f, "  2 {\n");
  fprintf(l->f, "    gsave\n");
  fprintf(l->f, "    xmulfactor ymulfactor scale\n");
  fprintf(l->f, "    tc charparams\n");
  fprintf(l->f, "    grestore\n\n");

  /* NOTE:  The following if statements in the next two sections make sure that
the size of the character has not gone to zero.  This apparently can happen
under OpenWindows, but not NeWS the Apple laserwriter or Freedom of the Press
Tektronix colorquick conversion. */

  fprintf(l->f, "    ysize %% desired size of character in points\n");
  fprintf(l->f, "    uy ly sub %% height of character in points\n");
  fprintf(l->f, "    dup 0.0 ne {\n");
  fprintf(l->f, "      div %% factor by which to scale up the character\n");
  fprintf(l->f, "      /ymulfactor exch def\n");
  fprintf(l->f, "    } %% end if\n");
  fprintf(l->f, "    {pop pop}\n");
      /* remove the stuff from the stack and go on */
  fprintf(l->f, "    ifelse\n\n");
  fprintf(l->f, "    xsize %% desired size of character in points\n");
  fprintf(l->f, "    ux lx sub %% width of character in points\n");
  fprintf(l->f, "    dup 0.0 ne {\n");
  fprintf(l->f, "      div %% factor by which to scale up the character\n");
  fprintf(l->f, "      /xmulfactor exch def\n");
  fprintf(l->f, "    } %% end if\n");
  fprintf(l->f, "    {pop pop}\n");
  fprintf(l->f, "    ifelse\n");
  fprintf(l->f, "  } repeat\n\n");

  /* The letter I must be specially centered in the Helvetica-Bold font.
We also account for the width of the character itself, so it should be centered
perfectly. */
  fprintf(l->f, "  %% Adjust horizontal position if the symbol is an I\n");
  fprintf(l->f,
    "  tc (I) eq {charwidth 2 div %% half of requested character width\n");
  fprintf(l->f,
	  "             ux lx sub 2 div %% half of the actual character\n");
  fprintf(l->f, "                sub      0 translate} if\n");
  fprintf(l->f, "  %% Avoid x scaling for I\n");
  fprintf(l->f, "  tc (I) eq {/xmulfactor 1 def} if\n\n");

  fprintf(l->f, "  /xmove xmulfactor lx mul neg def\n");
  fprintf(l->f, "  /ymove ymulfactor ly mul neg def\n\n");

  fprintf(l->f, "  newpath\n");
  fprintf(l->f, "  xmove ymove moveto\n");
  fprintf(l->f, "  xmulfactor ymulfactor scale\n\n");

  if (params.outline) {
    fprintf(l->f, "  %% Outline characters:\n");
    /* get the character's path: */
    fprintf(l->f, "  tc true charpath\n");
    /* erase the center of the character (seems necessary to do!) */
    fprintf(l->f, "  gsave 1 setgray fill grestore\n");
    /* clip everything outside the character to prevent characters
       from overlapping each other (!) and then stroke the edge.
       Thus only the part of the stroke that reaches into the CENTER
       of the character becomes black and so the character size does
       not change even though it is an outline. */
    fprintf(l->f, "  clip stroke\n");
    printf("\nWARNING: Outlined characters will not display at all under NeWS\n");
    printf("but will print fine on an Apple LaserWriter IIntx\n\n");
  } else
    fprintf(l->f, "  tc show\n");

  fprintf(l->f, "grestore\n");
  fprintf(l->f, "} def\n\n");

  fprintf(l->f, "/numchar{ %% charheight character numchar\n");
  fprintf(l->f, "%% Make a character of given height in cm,\n");
  fprintf(l->f, "%% then move vertically by that amount\n");
  fprintf(l->f, "  gsave\n");
  fprintf(l->f, "    /char exch def\n");
  fprintf(l->f, "    /charheight exch cm def\n");

  /* set up the color statements */
  if (*colors->name != '\0') {
    if (colors->f != NULL)
      colors->f = freopen(colors->name, "r", colors->f);
    else
      colors->f = fopen(colors->name, "r");
  } else
    rewind(colors->f);
  if (colors->f == NULL)
    _EscIO2(FileNotFound, colors->name);
  RESETBUF(colors->f, Char);
  while (!BUFEOF(colors->f)) {
    if (P_peek(colors->f) == '*') {  /* skip comment lines */
      fscanf(colors->f, "%*[^\n]");
      getc(colors->f);
      continue;
    }
    /* implement the backslash protection scheme: */
    if (P_peek(colors->f) == '\\')
      getc(colors->f);
    fscanf(colors->f, "%c%lg%lg%lg%*[^\n]", &symbol, &red, &green, &blue);
    getc(colors->f);
    if (symbol == '\n')
      symbol = ' ';
    fprintf(l->f, "    char (");
    protectpostscript(l, symbol);
    fprintf(l->f, "%c) eq {", symbol);
    if (red == 1.0 || red == 0.0)
      fprintf(l->f, "%ld", (long)floor(red + 0.5));
    else
      fprintf(l->f, "%*.*f", pwid, pdecolor, red);
    putc(' ', l->f);
    if (green == 1.0 || green == 0.0)
      fprintf(l->f, "%ld", (long)floor(green + 0.5));
    else
      fprintf(l->f, "%*.*f", pwid, pdecolor, green);
    putc(' ', l->f);
    if (blue == 1.0 || blue == 0.0)
      fprintf(l->f, "%ld", (long)floor(blue + 0.5));
    else
      fprintf(l->f, "%*.*f", pwid, pdecolor, blue);
    fprintf(l->f, " setrgbcolor} if\n");
  }

  fprintf(l->f, "     %% implement boxes, fill and characters:\n");
  fprintf(l->f, "     showingbox (s) eq\n");
  fprintf(l->f, "     showingbox (f) eq\n");
  fprintf(l->f, "     or\n");
  fprintf(l->f, "     {gsave\n");
  fprintf(l->f, "         ly lx\n");
  fprintf(l->f, "         ly charwidth add\n");
  fprintf(l->f, "         lx charheight add\n");
  fprintf(l->f, "         boxsymbol\n");
  fprintf(l->f, "         clip\n");
  fprintf(l->f, "         showingbox (f) eq\n");
  fprintf(l->f, "         {fill}  \n");
  fprintf(l->f, "         {gsave 0 setgray stroke grestore  \n");
  fprintf(l->f, "          charwidth charheight char boxshow\n");
  fprintf(l->f, "         }\n");
  fprintf(l->f, "         ifelse\n");
  fprintf(l->f, "     grestore\n");
  fprintf(l->f, "     }\n");
  fprintf(l->f, "     {charwidth charheight char boxshow}\n");
  fprintf(l->f, "     ifelse\n");

  fprintf(l->f, "  grestore\n");

  /* note: adding the following text is sufficient to cause
the converter to C to bomb with a segmentation fault!
writeln(l,'    % note: charwidth and charheight');
writeln(l,'    %  have already been converted to points');
*/

  /*
writeln(l,'  % the abs in the translation function below',
            ' handles negative heights');
  */

  /* The following if statements ask if the character height is greater than
one point.  If it is, the display should be ok.  If not, some
displays mess up, notably OpenWindows (!).  Force the character
to be 1 point high just to be safe.  I hate bad implementations
of PostScript! */

  if (gooddisplay)
    fprintf(l->f, "  0 charheight abs translate\n");
  else
    fprintf(l->f, "  charheight abs 1 gt {0 charheight abs translate} if\n");

  fprintf(l->f, "} bind def\n\n");   /* numchar */

}


/* end module makelogo.p2 */

/* begin module makelogo.p3 */
Static Void p3(l, params)
_TEXT *l;
parameters params;
{
  fprintf(l->f, "/Ibar{\n");
  fprintf(l->f, "%% make a horizontal bar\n");
  fprintf(l->f, "gsave\n");
  fprintf(l->f, "  newpath\n");
  fprintf(l->f, "    charwidth4 neg 0 moveto\n");
  fprintf(l->f, "    charwidth4 0 lineto\n");
  fprintf(l->f, "  stroke\n");
  fprintf(l->f, "grestore\n");
  fprintf(l->f, "} bind def\n\n");   /* Ibar */

  fprintf(l->f, "/Ibeam{ %% height Ibeam\n");
  fprintf(l->f, "%% Make an Ibeam of twice the given height, in cm\n");
  fprintf(l->f, "  /height exch cm def\n");
  fprintf(l->f, "  /heightDRAW height Ibeamfraction mul def\n");
  fprintf(l->f, "  1 setlinewidth\n");
  fprintf(l->f, "     HalfWhiteIbeam outline not and\n");
  fprintf(l->f, "     {0.75 setgray} %% grey on bottom\n");
  fprintf(l->f, "     {0 setgray} %% black on bottom\n");
  fprintf(l->f, "  ifelse\n");
  fprintf(l->f, "  gsave\n");
  fprintf(l->f, "    charwidth2 height neg translate\n");
  fprintf(l->f, "    Ibar\n");
  fprintf(l->f, "    newpath\n");
  fprintf(l->f, "      0 0 moveto\n");
  fprintf(l->f, "      0 heightDRAW rlineto\n");
  fprintf(l->f, "    stroke\n");
  fprintf(l->f, "    0 setgray %% black on top\n");
  fprintf(l->f, "    newpath\n");
  fprintf(l->f, "      0 height moveto\n");
  fprintf(l->f, "      0 height rmoveto\n");
  fprintf(l->f, "      currentpoint translate\n");
  fprintf(l->f, "    Ibar\n");
  fprintf(l->f, "    newpath\n");
  fprintf(l->f, "      0 0 moveto\n");
  fprintf(l->f, "      0 heightDRAW neg rlineto\n");
  fprintf(l->f, "      currentpoint translate\n");
  fprintf(l->f, "    stroke\n");
  fprintf(l->f, "  grestore\n");
  fprintf(l->f, "  setthelinewidth\n");
  fprintf(l->f, "} bind def\n\n");   /* Ibeam */

  /* The original simple Ibeam
writeln(l,'/Ibeam{ % height Ibeam');
writeln(l,'% Make an Ibeam of twice the given height, in cm');
writeln(l,'  /height exch cm def');
writeln(l,'  1 setlinewidth');
writeln(l,'  0 setgray % black');
writeln(l,'  gsave');
writeln(l,'    charwidth2 height neg translate');
writeln(l,'    Ibar');
writeln(l,'    newpath');
writeln(l,'      0 0 moveto');
writeln(l,'      0 height 2 mul lineto');
writeln(l,'      currentpoint translate');
writeln(l,'    stroke');
writeln(l,'    Ibar');
writeln(l,'  grestore');
writeln(l,'  setthelinewidth');
writeln(l,'} bind def'); (# Ibeam #)
writeln(l);
*/

  fprintf(l->f, "/makenumber { %% number makenumber\n");
  fprintf(l->f, "%% make the number\n");
  fprintf(l->f, "gsave\n");
  fprintf(l->f, "  shift %% shift to the other side of the stack\n");
  fprintf(l->f, "  90 rotate %% rotate so the number fits\n");
  fprintf(l->f, "  dup stringwidth pop %% find the length of the number\n");
  fprintf(l->f, "  neg %% prepare for move\n");
  fprintf(l->f, "  charwidth (0) charparams uy ly sub %% height of numbers\n");
  fprintf(l->f, "  sub 2 div %%\n");
  fprintf(l->f, "  moveto %% move back to provide space\n");
  fprintf(l->f, "  show\n");
  fprintf(l->f, "grestore\n");
  fprintf(l->f, "} bind def\n\n");   /* makenumber */

  fprintf(l->f, "/shift{ %% move to the next horizontal position\n");
  fprintf(l->f, "charwidth 0 translate\n");
  fprintf(l->f, "} bind def\n\n");

  /* 1996 March 16
The vertical bar should NOT affect the coordinate system!
"make a vertical bar and shift" is no longer acceptable.
The bar is made, but centered on the current location.
No movement is made.  The reason for this is that it messes
up the precise centering of strings and it would mess up the
location of marks. */

  fprintf(l->f, "/bar2 barwidth 2 div def\n");
  fprintf(l->f, "/bar2n bar2 neg def\n");
  fprintf(l->f, "/makebar { %% make a vertical bar at the current location\n");
  fprintf(l->f, "gsave\n");
  fprintf(l->f, "   bar2n 0 moveto\n");
  fprintf(l->f, "   barwidth 0 rlineto\n");
  fprintf(l->f, "   0 barheight rlineto\n");
  fprintf(l->f, "   barwidth neg 0 rlineto\n");
  fprintf(l->f, "   closepath\n");
  fprintf(l->f, "   fill\n");
  fprintf(l->f, "grestore\n");
  fprintf(l->f, "} def\n\n");

  fprintf(l->f, "%% definitions for maketic\n");
  fprintf(l->f, "/str 10 string def %% string to hold number\n");
  fprintf(l->f, "%% points of movement between tic marks:\n");
  fprintf(l->f, "%% (abs protects against barbits being negative)\n");
  fprintf(l->f, "/ticmovement barheight barbits abs div def\n\n");
  fprintf(l->f, "/maketic { %% make tic marks and numbers\n");
  fprintf(l->f, "gsave\n");
  fprintf(l->f, "  %% initial increment limit proc for\n");
  fprintf(l->f, "  0 1 barbits abs cvi\n");
  fprintf(l->f, "  {/loopnumber exch def\n\n");
  fprintf(l->f,
	  "    %% convert the number coming from the loop to a string\n");
  fprintf(l->f, "    %% and find its width\n");
  fprintf(l->f, "    loopnumber 10 str cvrs\n");
  fprintf(l->f,
	  "    /stringnumber exch def %% string representing the number\n\n");
  fprintf(l->f, "    stringnumber stringwidth pop\n");
  fprintf(l->f, "    /numberwidth exch def %% width of number to show\n\n");
  fprintf(l->f, "    /halfnumberheight\n");
  fprintf(l->f, "      stringnumber charparams %% capture sizes\n");
  fprintf(l->f, "      uy ly sub 2 div\n");
  fprintf(l->f, "    def\n\n");
  fprintf(l->f, "    numberwidth 2 mul %% move back two digits\n");
  fprintf(l->f, "    neg loopnumber ticmovement mul %% shift on y axis\n");
  fprintf(l->f, "    halfnumberheight sub %% down half the digit\n\n");
  fprintf(l->f, "    moveto %% move back the width of the string\n\n");
  fprintf(l->f, "    stringnumber show\n\n");
  fprintf(l->f, "    %% now show the tic mark\n");
  fprintf(l->f, "    0 halfnumberheight rmoveto %% shift up again\n");
  fprintf(l->f, "    numberwidth 0 rlineto\n");
  fprintf(l->f, "    stroke\n");
  /* note: the following two lines are separated to avoid a
problem with the p2c Pascal to C translator */
  fprintf(l->f, "  }");
  fprintf(l->f, " for\n");
  fprintf(l->f, "  grestore\n");

  /*
writeln(l,'% at this point numberwidth says how far back to go.  do that');
*/
  /* put the word 'bits' on the left */
  fprintf(l->f, "  gsave\n");
  fprintf(l->f, "    /labelstring (bits) def\n");
  fprintf(l->f, "    numberwidth neg 2.5 mul\n");
      /* x coordinate to start writing */
  fprintf(l->f, "    barheight\n");   /* height of bar */
  fprintf(l->f, "    labelstring stringwidth pop\n");   /* length of string */
  fprintf(l->f, "    sub 2 div\n");   /* y coordinate to start writing */
  fprintf(l->f, "    translate\n");
  fprintf(l->f, "    90 rotate\n");
  fprintf(l->f, "    0 0 moveto\n");
  fprintf(l->f, "    labelstring show\n");
      /* x coordinate to start writing */
  fprintf(l->f, "  grestore\n");

  fprintf(l->f, "} def\n");

}


/* end module makelogo.p3 */

/* begin module makelogo.p4 */
Static Void p4(l, params)
_TEXT *l;
parameters params;
{
  fprintf(l->f, "\n/degpercycle 360 def\n");
  fprintf(l->f, " \n");
  fprintf(l->f, "/cosine {%%    amplitude  phase  wavelength  base\n");
  fprintf(l->f, "%%             xmin ymin xmax ymax step dash thickness\n");
  fprintf(l->f, "%%             cosine -\n");
  fprintf(l->f, "%% draws a cosine wave with the given parameters:\n");
  fprintf(l->f, "%% amplitude (points): height of the wave\n");
  fprintf(l->f, "%% phase (points): starting point of the wave\n");
  fprintf(l->f, "%% wavelength (points): length from crest to crest\n");
  fprintf(l->f, "%% base (points): lowest point of the curve\n");
  fprintf(l->f, "%% xmin ymin xmax ymax (points): region in which to draw\n");
  fprintf(l->f, "%% step steps for drawing a cosine wave\n");
  fprintf(l->f,
    "%% dash if greater than zero, size of dashes of the wave (points)\n");
  fprintf(l->f,
	  "%% thickness if greater than zero, thickness of wave (points)\n\n");
  fprintf(l->f, "  /thickness exch def\n");
  fprintf(l->f, "  /dash exch def\n");
  fprintf(l->f, "  /step exch def\n");
  fprintf(l->f, "  /ymax exch def\n");
  fprintf(l->f, "  /xmax exch def\n");
  fprintf(l->f, "  /ymin exch def\n");
  fprintf(l->f, "  /xmin exch def\n");
  fprintf(l->f, "  /base exch def\n");
  fprintf(l->f, "  /wavelength exch def\n");
  fprintf(l->f, "  /phase exch def\n");
  fprintf(l->f, "  /amplitude exch def\n");
  fprintf(l->f,
	  "  %% fun := amplitude*cos( ((-y-phase)/wavelength)*360) + base\n");
  fprintf(l->f, "  /fun {phase sub wavelength div degpercycle mul cos\n");
  fprintf(l->f, "           amplitude mul base add} def\n\n");
  fprintf(l->f, "  gsave\n");
  fprintf(l->f, "    /originallinewidth currentlinewidth def\n");
  fprintf(l->f, "    thickness 0 gt {thickness setlinewidth} if\n");
  fprintf(l->f, "    /c currentlinewidth def\n");
  fprintf(l->f, "%%   Make the curve fit into the region specified\n");
  fprintf(l->f, "    newpath\n");
  fprintf(l->f, "    xmin ymin c sub moveto\n");
  fprintf(l->f, "    xmax ymin c sub lineto\n");
  fprintf(l->f, "    xmax ymax c add lineto\n");
  fprintf(l->f, "    xmin ymax c add lineto\n");
  fprintf(l->f, "    closepath\n");
  fprintf(l->f, "    clip\n\n");   /* stroke'); */
  fprintf(l->f, "    newpath\n");
  fprintf(l->f, "    xmin dup fun moveto\n");
  fprintf(l->f, "    xmin step xmax { %% loop from xmin by step to xmax\n");
  fprintf(l->f, "      dup fun lineto } for\n");
  fprintf(l->f, "    dash 0 gt {[dash cvi] 0 setdash} if %% turn dash on\n");
  fprintf(l->f, "    stroke\n\n");
  fprintf(l->f, "    originallinewidth setlinewidth\n");
  fprintf(l->f, "  grestore\n");
  fprintf(l->f, "} bind def\n\n");

  /* example test:
% amplitude  phase  wavelength  base:
   -2.50000 cm  6.40000 cm  8.48000 cm  7.50000 cm
% xmin ymin xmax ymax step:
   -4.80000 cm  0.00000 cm 17.60000 cm 50.50000 cm 1
    0.5 cm 0.1 cosine
  */

}


/* end module makelogo.p4 */

/* begin module makelogo.marksymbols */
Static Void marksymbols(l)
_TEXT *l;
{
  /* define postscript symbols to file l */
  fprintf(l->f, "/circlesymbol { %% x y radius circlesymbol - (path)\n");
  fprintf(l->f, "newpath 0 360 arc closepath} bind def\n\n");

  /*
writeln(l,'% axis of triangle for debugging');
writeln(l,'/firstaxis {');
writeln(l,'gsave');
writeln(l,'1 0 0 setrgbcolor');
writeln(l,'newpath 0 0 moveto 100 0 lineto (X) show stroke');
writeln(l,'0 0 moveto 0 50 lineto (Y) show stroke');
writeln(l,'grestore } def');
writeln(l,'/secondaxis {');
writeln(l,'gsave');
writeln(l,'0 1 0 setrgbcolor');
writeln(l,'newpath 0 0 moveto 100 0 lineto (XX) show stroke');
writeln(l,'0 0 moveto 0 50 lineto (YY) show stroke');
writeln(l,'grestore } def');
writeln(l,'/thirdaxis {');
writeln(l,'gsave');
writeln(l,'0 0 1 setrgbcolor');
writeln(l,'newpath 0 0 moveto 100 0 lineto (XXX) show stroke');
writeln(l,'0 0 moveto 0 50 lineto (YYY) show stroke');
writeln(l,'grestore } def');
writeln(l);
*/

  fprintf(l->f, "/sqrt3 3 sqrt def\n");
  fprintf(l->f, "/trianglesymbol { %% x y radius trianglesymbol - (path)\n");
  fprintf(l->f, "/r exch def\n");
  fprintf(l->f, "/sqrt3r sqrt3 r mul def\n");
  fprintf(l->f, "translate\n");
  /*writeln(l,'% firstaxis'); */
  fprintf(l->f, "120 rotate\n");
  /*writeln(l,'% secondaxis'); */
  fprintf(l->f, "0 r translate\n");
  fprintf(l->f, "-120 rotate\n");
  fprintf(l->f, "newpath\n");
  fprintf(l->f, "0 0 moveto\n");
  fprintf(l->f, "sqrt3r 0 lineto\n");
  fprintf(l->f, "-300 rotate\n");
  /*writeln(l,'% thirdaxis'); */
  fprintf(l->f, "sqrt3r 0 lineto\n");
  fprintf(l->f, "closepath} bind def\n\n");

  fprintf(l->f, "/squaresymbol { %% x y side squaresymbol - (path)\n");
  fprintf(l->f, "/side exch def\n");
  fprintf(l->f, "translate\n");
  fprintf(l->f, "side 2 div neg dup translate\n");
  fprintf(l->f, "newpath\n");
  fprintf(l->f, "0 0 moveto\n");
  fprintf(l->f, "0 side lineto\n");
  fprintf(l->f, "side side lineto\n");
  fprintf(l->f, "side 0 lineto\n");
  fprintf(l->f, "closepath} bind def\n\n");

  fprintf(l->f, "/linesymbol { %% x1 y1 x2 y2 linesymbol - (path)\n");
  fprintf(l->f, "/y2 exch def\n");
  fprintf(l->f, "/x2 exch def\n");
  fprintf(l->f, "/y1 exch def\n");
  fprintf(l->f, "/x1 exch def\n");
  fprintf(l->f, "newpath\n");
  fprintf(l->f, "x1 y1 moveto\n");
  fprintf(l->f, "x2 y2 lineto\n");
  fprintf(l->f, "} bind def\n\n");

  fprintf(l->f, "/boxsymbol { %% x1 y1 x2 y2 boxsymbol - (path)\n");
  fprintf(l->f, "/y2 exch def\n");
  fprintf(l->f, "/x2 exch def\n");
  fprintf(l->f, "/y1 exch def\n");
  fprintf(l->f, "/x1 exch def\n");
  fprintf(l->f, "newpath\n");
  fprintf(l->f, "x1 y1 moveto\n");
  fprintf(l->f, "x2 y1 lineto\n");
  fprintf(l->f, "x2 y2 lineto\n");
  fprintf(l->f, "x1 y2 lineto\n");
  fprintf(l->f, "closepath\n");
  fprintf(l->f, "} bind def\n\n");
}


/* end module makelogo.marksymbols */

/* begin module makelogo.p4a */
Static Void p4a(l, params)
_TEXT *l;
parameters params;
{
  fprintf(l->f,
    "%% The following special comment allows deletion of the repeated\n");
  fprintf(l->f,
	  "%% procedures when several logos are concatenated together\n");
  fprintf(l->f, "%% See the censor program.\n");
  fprintf(l->f, "%%]]%%*)\n\n");

  fprintf(l->f, "/startpage { %% start a page\n");
  fprintf(l->f, "  save %% [ startpage\n");
      /* required for packaging page */
  fprintf(l->f, "  %% set the font used in the title strings\n");
  fprintf(l->f, "  FontForStringRegular\n");
  fprintf(l->f, "  gsave %% [ startpage\n");
  fprintf(l->f, "  xcorner ycorner translate\n");
  fprintf(l->f, "  rotation rotate\n");
}


/* end module makelogo.p4a */

/* begin module makelogo.p5 */
Static Void p5(l, symvec, params)
_TEXT *l, *symvec;
parameters params;
{
  strings *stringspot;   /* current spot in thestrings */
  long stringnumber = 0;   /* count of the strings written */
  string printstring;   /* the string to print after processing. */
  string rawstring;
  /* the raw string that will print, ignoring
     any fancy postscript the user may have introduced. */
  double rs = 0.0;   /* value of rs */
  double sd = 0.0;   /* value of sd */
  long n = 0;   /* number of sequences */
  boolean havers = false, havesd = false, haven = false;
      /* have gotten rs, sd, n */
  _TEXT TEMP;

  if (params.thestrings == NULL)
    return;

  fprintf(l->f, "  %% create the user defined strings\n");
  stringspot = params.thestrings;


  while (stringspot != NULL) {
    fprintf(l->f, "  gsave\n");   /*havers, havesd,*/
    /* lowest, highest,
    rs, sd,*/
    postscriptstring(&stringspot->astring, &printstring, &rawstring, symvec,
		     n, haven);
    if (stringspot->x <= centertrigger) {  /* test for centering */
      /* check if the user will be fooled by the loss of the string */
      if (params.stacksperline > (params.highest - params.lowest) * 2) {
	printf("\nWARNING: if you don't see centered string number %ld:\n",
	       stringnumber);
	printf("    \"");
	TEMP.f = stdout;
	*TEMP.name = '\0';
	writestring(&TEMP, &stringspot->astring);
	printf("\"\n");
	printf(
	  "it may be off the page because stacksperline is large (%ld) relative to the\n",
	  params.stacksperline);
	printf(
	  "FROM-TO range (%ld to %ld) and centering is based on stacks-per-line.  To\n",
	  params.lowest, params.highest);
	printf("solve this, reduce parameter stacksperline to FROM-TO+1 = %ld\n\n",
	       params.highest - params.lowest + 1);
      }

      stringnumber++;
      fprintf(l->f, "    %% string number %ld\n", stringnumber);
      fprintf(l->f, "    %% center the string\n");
      fprintf(l->f, "    /stringscale %*.*f def\n", pwid, pdec, stringspot->s);

      /* code for looking at the centering
writeln(l,'gsave % draw a vertical line at the center of the graph');
writeln(l,'     stacksperline charwidth mul');
writeln(l,'     2 div');
writeln(l,'     10.20000 cm moveto');
writeln(l,'  ');
writeln(l,' % Its the bar width!!!');
writeln(l,'  ');
writeln(l,'   0 -10.1 cm rlineto');
writeln(l,'   stroke ');
write(l,'% draw a horizontal line under the string');
write(l,'    (');
writestring(l,rawstring);
writeln(l,')');
writeln(l,'    stringwidth pop /thestringwidth exch def');
writeln(l,'    thestringwidth');
writeln(l,'    stringscale mul neg');
writeln(l,'    stacksperline charwidth mul');
writeln(l,'    add 2 div');
writeln(l,'    ',stringspot^.y:pwid:pdec,' cm moveto');
writeln(l,'   thestringwidth 0 rlineto');
writeln(l,'   stroke ');
writeln(l,' grestore');
writeln(l);
*/

      /*
write(output,' printstring: ');
writestring(output,printstring);
writeln(output);
*/

      fprintf(l->f, "    (");
      writestring(l, &rawstring);
      fprintf(l->f, ")\n");
      fprintf(l->f, "    stringwidth pop\n");
      fprintf(l->f, "    stringscale mul neg\n");
      fprintf(l->f, "    stacksperline charwidth mul\n");
      fprintf(l->f, "    add 2 div\n");
      fprintf(l->f, "    %*.*f cm moveto\n", pwid, pdec, stringspot->y);

    }

    else {
      fprintf(l->f, "    /stringscale %*.*f def\n", pwid, pdec, stringspot->s);
      fprintf(l->f, "    %*.*f cm %*.*f cm moveto\n",
	      pwid, pdec, stringspot->x, pwid, pdec, stringspot->y);
    }
    fprintf(l->f, "    stringscale stringscale scale\n");
    fprintf(l->f, "    ");
    writestring(l, &printstring);
    fprintf(l->f, "\n    show\n");

    stringspot = stringspot->next;
    fprintf(l->f, "  grestore\n");
  }
}


/* end module makelogo.p5 */

/* begin module makelogo.p6 */
Static Void p6(l, params)
_TEXT *l;
parameters params;
{
  fprintf(l->f, "  %% now move up to the top of the top line:\n");
  fprintf(l->f, "  0 linesperpage linemove barheight mul mul translate\n\n");
  fprintf(l->f, "  %% set the font used in the logos\n");
  fprintf(l->f, "  FontForLogo\n");
  fprintf(l->f, "} def\n\n");

  fprintf(l->f,
	  "%%(*[[ This special comment allows deletion of the repeated\n");
  fprintf(l->f,
	  "%% procedures when several logos are concatenated together\n");
  fprintf(l->f, "%% See the censor program.\n\n");

  fprintf(l->f, "/endpage { %% end a page\n");
  fprintf(l->f, "  grestore %% ] endpage\n");
  fprintf(l->f, "  showpage %% REMOVE FOR PACKAGING INTO ANOTHER FIGURE\n");
  fprintf(l->f, "  restore %% ] endpage\n");
      /* required for packaging page */
  fprintf(l->f, "} def\n\n");

  fprintf(l->f, "/showleftend {\n");
  fprintf(l->f, "gsave\n");
  fprintf(l->f, " charwidth neg 0 translate\n");
  fprintf(l->f, " fivemovex fivemovey moveto");
  fprintf(l->f, " ShowEnds (d) eq {(5) show prime} if\n");
  fprintf(l->f, " ShowEnds (p) eq {(N) show} if\n");
  fprintf(l->f, "grestore\n");
  fprintf(l->f, "} def\n\n");

  fprintf(l->f, "/showrightend {\n");
  fprintf(l->f, "gsave\n");
  fprintf(l->f, " threemovex threemovey moveto");
  fprintf(l->f, " ShowEnds (d) eq {(3) show prime} if\n");
  fprintf(l->f, " ShowEnds (p) eq {(C) show} if\n");
  fprintf(l->f, "grestore\n");
  fprintf(l->f, "} def\n\n");

  fprintf(l->f, "/startline{ %% start a line\n");
  fprintf(l->f, "%% move down to the bottom of the line:\n");
  fprintf(l->f, "  0 linemove barheight mul neg translate\n");
  fprintf(l->f, "  gsave %% [ startline\n");
  fprintf(l->f, "  barends {\n");
  fprintf(l->f, "    maketic %% maketic.startline\n");
  fprintf(l->f, "    gsave\n");
  fprintf(l->f, "      bar2n 0 translate %% makebar.startline\n");
  fprintf(l->f, "      makebar %% makebar.startline\n");
  fprintf(l->f, "    grestore\n");
  fprintf(l->f, "  } if\n");
  fprintf(l->f, "  showleftend\n");
  fprintf(l->f, "} def\n\n");

  fprintf(l->f, "/endline{ %% end a line\n");
  fprintf(l->f, "  showrightend\n");
  fprintf(l->f, "  barends {\n");
  fprintf(l->f, "    gsave\n");
  fprintf(l->f, "      bar2 0 translate %% makebar.endline\n");
  fprintf(l->f, "      makebar %% makebar.endline\n");
  fprintf(l->f, "    grestore\n");
  fprintf(l->f, "  } if\n");
  fprintf(l->f, "  grestore %% ] startline\n");
  fprintf(l->f, "} def\n\n");

  fprintf(l->f,
	  "%% @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
  fprintf(l->f,
	  "%% @@@@@@@@@@@@@@@@@@@@ End of procedures @@@@@@@@@@@@@@@@@@@\n");
  fprintf(l->f,
	  "%% @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n\n");

  fprintf(l->f,
    "%% The following special comment allows deletion of the repeated\n");
  fprintf(l->f,
	  "%% procedures when several logos are concatenated together\n");
  fprintf(l->f, "%% See the censor program.\n");
  fprintf(l->f, "%%]]%%*)\n\n");

}


/* end module makelogo.p6 */

/* begin module makelogo.startpostscript */
Static Void startpostscript(l, colors, symvec, params)
_TEXT *l, *colors, *symvec;
parameters params;
{
  /* start the PostScript definitions to file l.
This routine is broken up into a number of separate procedures
to allow translation into C by the p2c program.  If this is not
done, then apparently p2c's memory for literal strings fills up,
and one gets errors like 'segmentation fault'. */
  p1(l, params);
  p2(l, colors, params);
  p3(l, params);
  p4(l, params);
  marksymbols(l);
  p4a(l, params);
  p5(l, symvec, params);
  p6(l, params);
}


/* end module makelogo.startpostscript */

/* ********************************************************************** */
/* ********************************************************************** */

/* begin module capitalize */
Static Char capitalize(c)
Char c;
{
  /* convert the character c to upper case */
  long n = c;   /* c is the n'th letter of the alphabet */

  if (n >= 'a' && n <= 'z')
    c = _toupper(n);

  return c;
}


/* end module capitalize version = 4.15; (@ of prgmod.p 1994 November 12 */

/* begin module skipblanks */
Static Void skipblanks(thefile)
_TEXT *thefile;
{
  /* skip over blanks until a non-blank, or end of line, is found */
  while ((P_peek(thefile->f) == ' ') & (!P_eoln(thefile->f)))
    getc(thefile->f);
}


Static Void skipnonblanks(thefile)
_TEXT *thefile;
{
  /* skip over nonblanks until a blank, or end of line, is found */
  while ((P_peek(thefile->f) != ' ') & (!P_eoln(thefile->f)))
    getc(thefile->f);
}


Static Void skipcolumn(thefile)
_TEXT *thefile;
{
  /* skip over a data column */
  skipblanks(thefile);
  skipnonblanks(thefile);
}


/* end module skipblanks version = 4.15; (@ of prgmod.p 1994 November 12 */

/* begin module softnumbertest */
Static boolean softnumbertest(f)
_TEXT *f;
{
  /* test that a number follows, but don't die if there is none */
  skipblanks(f);
  if (P_peek(f->f) != '9' && P_peek(f->f) != '8' && P_peek(f->f) != '7' &&
      P_peek(f->f) != '6' && P_peek(f->f) != '5' && P_peek(f->f) != '4' &&
      P_peek(f->f) != '3' && P_peek(f->f) != '2' && P_peek(f->f) != '1' &&
      P_peek(f->f) != '0' && P_peek(f->f) != '+' && P_peek(f->f) != '-') {
    /* we can't do this because it would wreck reading parameters
          bar(output,'-');
          writeln(output,'NOTE: in the parameter file,',
            ' another number is now allowed for on this line:');
          copyaline(f,output);
    */
    return false;
  } else
    return true;
}


/* Local variables for checknumber: */
struct LOC_checknumber {
  _TEXT *afile;
  boolean ok;   /* result of this check */
} ;

Local Void conclude(LINK)
struct LOC_checknumber *LINK;
{
  _TEXT TEMP;

  printf("Including this character, the rest of the data line is:\n");
  TEMP.f = stdout;
  *TEMP.name = '\0';
  copyaline(LINK->afile, &TEMP);
  LINK->ok = false;
}


/* end module softnumbertest */

/* begin module checknumber */
Static boolean checknumber(afile_)
_TEXT *afile_;
{
  /* check that there is a number next in the file.  If not, return
false. */
  struct LOC_checknumber V;

  V.afile = afile_;
  V.ok = true;   /* be optimistic */
  if (BUFEOF(V.afile->f)) {
    V.ok = false;
    return false;
  }
  skipblanks(V.afile);
  if (P_eoln(V.afile->f)) {
    printf("A number was expected on a data line, but");
    printf(" the end of the line was found instead.\n");
    conclude(&V);
  }
  if (P_peek(V.afile->f) == '+' || P_peek(V.afile->f) == '-' ||
      P_peek(V.afile->f) == '.' || P_peek(V.afile->f) == '9' ||
      P_peek(V.afile->f) == '8' || P_peek(V.afile->f) == '7' ||
      P_peek(V.afile->f) == '6' || P_peek(V.afile->f) == '5' ||
      P_peek(V.afile->f) == '4' || P_peek(V.afile->f) == '3' ||
      P_peek(V.afile->f) == '2' || P_peek(V.afile->f) == '1' ||
      P_peek(V.afile->f) == '0')
    return V.ok;
  printf("A number was expected on a data line, but");
  printf(" the character \"%c\" was found instead.\n", P_peek(V.afile->f));
  conclude(&V);
  return V.ok;
}


/* Local variables for readparameters: */
struct LOC_readparameters {
  _TEXT *theplace;
} ;

Local Void cn(LINK)
struct LOC_readparameters *LINK;
{
  boolean checkout;   /* if true, all variable values are ok */

  checkout = checknumber(LINK->theplace);
  if (!checkout)   /* avoid snowballing */
    halt();
}


/* end module checknumber from lister 7.67 */

/* begin module makelogo.readparameters */
Static Void readparameters(theplace_, params)
_TEXT *theplace_;
parameters *params;
{
  /* read in the parameters from the place */
  struct LOC_readparameters V;
  boolean gotten;   /* if true, we got a user defined string */
  boolean gottoresetcorner;
  /* if true, then reset the xcorner or ycorner
     according to the rotation and base position zerobase */
  double graphshift;
  /* the amount to shift the graph so that it
     is placed with center at zerobase bases */
  long numberstrings;   /* the number of strings to read from theplace */
  long n;   /* index to numberstrings */
  long spl;   /* stacks per line computed */
  strings *stringspot;   /* current spot in thestrings */
  double zerobase;   /* the zero of the graph in bases */

  V.theplace = theplace_;
  if (*V.theplace->name != '\0') {
    if (V.theplace->f != NULL)
      V.theplace->f = freopen(V.theplace->name, "r", V.theplace->f);
    else
      V.theplace->f = fopen(V.theplace->name, "r");
  } else
    rewind(V.theplace->f);
  if (V.theplace->f == NULL)
    _EscIO2(FileNotFound, V.theplace->name);
  RESETBUF(V.theplace->f, Char);
  if (!BUFEOF(V.theplace->f)) {
    cn(&V);
    fscanf(V.theplace->f, "%ld%ld%*[^\n]", &params->lowest, &params->highest);
    getc(V.theplace->f);
  } else {
    printf("missing all parameters\n");
    halt();
  }

  if (!BUFEOF(V.theplace->f)) {
    cn(&V);
    fscanf(V.theplace->f, "%ld%*[^\n]", &params->bar);
    getc(V.theplace->f);
  } else {
    printf("missing bar coordinate parameter\n");
    halt();
  }

  if (!BUFEOF(V.theplace->f)) {
    if (P_peek(V.theplace->f) != 'z') {
      cn(&V);
      fscanf(V.theplace->f, "%lg%lg%*[^\n]", &params->xcorner,
	     &params->ycorner);
      getc(V.theplace->f);
      gottoresetcorner = false;
    } else {
      getc(V.theplace->f);   /* skip the "z" */
      cn(&V);
      fscanf(V.theplace->f, "%lg%lg%lg%*[^\n]", &params->xcorner,
	     &params->ycorner, &zerobase);
      getc(V.theplace->f);
      gottoresetcorner = true;
    }
  } else {
    /* define the zero base of the graph */
    printf("missing corner coordinate parameters\n");
    halt();
  }

  if (!BUFEOF(V.theplace->f)) {
    cn(&V);
    fscanf(V.theplace->f, "%lg%*[^\n]", &params->rotation);
    getc(V.theplace->f);
  } else {
    printf("missing rotation parameter\n");
    halt();
  }
  if ((long)floor(params->rotation + 0.5) % 90 != 0) {
    printf("\nWARNING: rotations that are not multiples of\n");
    printf("of 90 degrees are likely to be scaled\n");
    printf("incorrectly, due to a PostScript limitation.\n");
    printf("See the description of the pathbbox function\n");
    printf("in the Red book.\n\n");
  }
/* p2c: makelogo.p, line 2733:
 * Note: Using % for possibly-negative arguments [317] */

  if (!BUFEOF(V.theplace->f)) {
    cn(&V);
    fscanf(V.theplace->f, "%lg%*[^\n]", &params->charwidth);
    getc(V.theplace->f);
  } else {
    printf("missing charwidth parameter\n");
    halt();
  }
  if (params->charwidth <= 0.0) {
    printf("charwidth parameter must be > 0 cm\n");
    halt();
  }

  /* now that we have character width and rotation we can calculate this: */
  if (gottoresetcorner) {
    /* note: the 0.5 is half a base so that if zerobase is 0
       the graph centers exactly in the middle of the 0 */
    graphshift = params->charwidth * (zerobase - params->lowest + 0.5);
    if (fabs(params->rotation) > 135)   /*180*/
      params->xcorner += graphshift;
    else if (params->rotation > 0)   /*+90*/
      params->xcorner -= graphshift;
    else if (params->rotation < 0)   /*-90*/
      params->ycorner += graphshift;
    else
      printf("program error in resetxcorner\n");
  }

  if (!BUFEOF(V.theplace->f)) {
    cn(&V);
    fscanf(V.theplace->f, "%lg%lg%*[^\n]", &params->barheight,
	   &params->barwidth);
    getc(V.theplace->f);
  } else {
    printf("missing barheight and barwidth parameters\n");
    halt();
  }
  if (params->barheight <= 0.0) {
    printf("barheight parameter must be > 0 cm\n");
    halt();
  }
  if (params->barwidth <= 0.0) {
    printf("barwidth parameter must be > 0 cm\n");
    halt();
  }

  if (!BUFEOF(V.theplace->f)) {
    cn(&V);
    fscanf(V.theplace->f, "%lg%*[^\n]", &params->barbits);
    getc(V.theplace->f);
  } else {
    printf("missing barbits parameter\n");
    halt();
  }
  if (params->barbits < 0.0) {
    printf(
      "\nWARNING: are you SURE you don't want to show the variation due to a small\n");
    printf("number of samples (i.e. the I-beam error bars)?\n\n");
  } else {
    printf("* Reminder: the I-beam error bars show the\n");
    printf("  variation of the entire stack not just the highest\n");
    printf("  symbol, even though it may look like that.\n");
  }
  if (params->barbits == 0.0) {
    printf("barbits parameter must not be zero\n");
    halt();
  }

  /* slip in a new parameter, but do it softly.  That is,
     if the user has a number, the parameter is there and read,
     but if it is not a number, just go on to the next */
  if (softnumbertest(V.theplace)) {
    fscanf(V.theplace->f, "%lg%*[^\n]", &params->Ibeamfraction);
    getc(V.theplace->f);
    /* Although we could do checks on this, it's fun, and perhaps
       useful to allow the user to put in weird numbers here.  */
  } else
    params->Ibeamfraction = 1.0;

  if (!BUFEOF(V.theplace->f)) {
    if (P_peek(V.theplace->f) == 'b')
      params->barends = true;
    else
      params->barends = false;
    fscanf(V.theplace->f, "%*[^\n]");
    getc(V.theplace->f);
  } else {
    printf("barends parameter is missing\n");
    halt();
  }

  if (!BUFEOF(V.theplace->f)) {
    fscanf(V.theplace->f, "%c%*[^\n]", &params->showingbox);
    getc(V.theplace->f);
    if (params->showingbox == '\n')
      params->showingbox = ' ';
  } else {
    printf("showingbox parameter is missing\n");
    halt();
  }

  if (!BUFEOF(V.theplace->f)) {
    if (P_peek(V.theplace->f) == 'o')
      params->outline = true;
    else
      params->outline = false;
    fscanf(V.theplace->f, "%*[^\n]");
    getc(V.theplace->f);
  } else {
    printf("outline parameter is missing\n");
    halt();
  }

  if (!BUFEOF(V.theplace->f)) {
    if (P_peek(V.theplace->f) == 'c')
      params->caps = true;
    else
      params->caps = false;
    fscanf(V.theplace->f, "%*[^\n]");
    getc(V.theplace->f);
  } else {
    printf("caps parameter is missing\n");
    halt();
  }

  if (!BUFEOF(V.theplace->f)) {
    cn(&V);
    fscanf(V.theplace->f, "%ld%*[^\n]", &params->stacksperline);
    getc(V.theplace->f);
  } else {
    printf("stacksperline parameter is missing\n");
    halt();
  }
  if (params->stacksperline <= 0) {
    printf("stacksperline parameter must be positive\n");
    halt();
  }

  if (!BUFEOF(V.theplace->f)) {
    cn(&V);
    fscanf(V.theplace->f, "%ld%*[^\n]", &params->linesperpage);
    getc(V.theplace->f);
  } else {
    printf("linesperpage parameter is missing\n");
    halt();
  }
  if (params->linesperpage <= 0) {
    printf("linesperpage parameter must be positive\n");
    halt();
  }

  if (params->linesperpage == 1) {
    spl = params->highest - params->lowest + 1;
    if (params->stacksperline != spl) {
      printf("* NOTE: Since there is only one line per page\n");
      printf("  requested stacks per line (%ld)\n", params->stacksperline);
      printf("  will be replaced with computed stacks per line (%ld)\n", spl);
      printf("  to make centered strings work correctly\n");
      params->stacksperline = spl;
    }
  }

  if (!BUFEOF(V.theplace->f)) {
    cn(&V);
    fscanf(V.theplace->f, "%lg%*[^\n]", &params->linemove);
    getc(V.theplace->f);
  } else {
    printf("linemove parameter is missing\n");
    halt();
  }
  if (params->linemove <= 0) {
    printf("linemove parameter must be positive\n");
    halt();
  }

  if (!BUFEOF(V.theplace->f)) {
    if (P_peek(V.theplace->f) == 'n')
      params->numbering = true;
    else
      params->numbering = false;
    fscanf(V.theplace->f, "%*[^\n]");
    getc(V.theplace->f);
  } else {
    printf("numbering parameters are missing\n");
    halt();
  }

  if (!BUFEOF(V.theplace->f)) {
    cn(&V);
    fscanf(V.theplace->f, "%lg%*[^\n]", &params->shrink);
    getc(V.theplace->f);
  } else {
    printf("shrink parameter is missing\n");
    halt();
  }
  if (params->shrink > 1.0) {
    printf("Shrink parameter must be less than or equal to 1.\n");
    printf("This way, you won't create a misleading logo\n");
    printf("which has an apparent height larger than it should.\n");
  }
  if (params->shrink > 0.0 && params->shrink < 1.0 &&
      params->showingbox != 'b') {
    printf("Shrinking can only be done when showing the box.\n");
    printf("This way, you won't create a misleading logo\n");
    printf("which has an apparent height smaller than it should.\n");
  }
  if (params->showingbox != 'b' || params->shrink <= 0.0 ||
      params->shrink >= 1.0)
    params->shrinking = false;
  else
    params->shrinking = true;

  if (!BUFEOF(V.theplace->f)) {
    cn(&V);
    fscanf(V.theplace->f, "%ld%*[^\n]", &numberstrings);
    getc(V.theplace->f);
  } else {
    printf("number of user defined strings must be given\n");
    halt();
  }
  if (numberstrings > 0) {
    params->thestrings = (strings *)Malloc(sizeof(strings));
    stringspot = params->thestrings;
    for (n = 1; n <= numberstrings; n++) {
      if (BUFEOF(V.theplace->f)) {
	printf("missing a user defined string coordinate\n");
	halt();
      }
      fscanf(V.theplace->f, "%lg%lg%lg%*[^\n]", &stringspot->x,
	     &stringspot->y, &stringspot->s);
      getc(V.theplace->f);
      getstring(V.theplace, &stringspot->astring, &gotten);
      if (!gotten) {
	printf("missing a user defined string\n");
	halt();
      }
      if (n < numberstrings) {
	stringspot->next = (strings *)Malloc(sizeof(strings));
	stringspot = stringspot->next;
      } else
	stringspot->next = NULL;
    }
  } else
    params->thestrings = NULL;

  if (!BUFEOF(V.theplace->f)) {
    params->edgecontrol = getc(V.theplace->f);
    if (params->edgecontrol == '\n')
      params->edgecontrol = ' ';
    if (params->edgecontrol != 'p') {
      cn(&V);
      fscanf(V.theplace->f, "%lg%lg%lg%lg", &params->edgeleft,
	     &params->edgeright, &params->edgelow, &params->edgehigh);
    } else {
      params->edgeleft = edgemargindefault;
      params->edgeright = edgemargindefault;
      params->edgelow = edgemargindefault;
      params->edgehigh = edgemargindefault;
    }
    fscanf(V.theplace->f, "%*[^\n]");
    getc(V.theplace->f);
  } else {
    params->edgecontrol = ' ';
    params->edgeleft = edgemargindefault;
    params->edgeright = edgemargindefault;
    params->edgelow = edgemargindefault;
    params->edgehigh = edgemargindefault;
    printf("NOTE:  you can now define the edges, see the documentation.\n");
    printf("Edges are all defaulting to %ld cm.\n", (long)edgemargindefault);
  }

  if (BUFEOF(V.theplace->f)) {
    params->ShowEnds = '-';
    return;
  }
  params->ShowEnds = getc(V.theplace->f);
  if (params->ShowEnds == '\n')
    params->ShowEnds = ' ';
  if (params->ShowEnds != 'd' && params->ShowEnds != 'p')
    params->ShowEnds = '-';
}


/* end module makelogo.readparameters */

/* begin module makelogo.warnifsitesused */
Static Void warnifsitesused(symvec, fout, sitesused)
_TEXT *symvec, *fout;
boolean *sitesused;
{
  /* 'warn [the user about error bars] if [the] sites [program] was used
[to create the symvec].' */
  Char a, b, c, d, e, f, g;   /* a simple way to do a string */

  *sitesused = false;
  if (*symvec->name != '\0') {
    if (symvec->f != NULL)
      symvec->f = freopen(symvec->name, "r", symvec->f);
    else
      symvec->f = fopen(symvec->name, "r");
  } else
    rewind(symvec->f);
  if (symvec->f == NULL)
    _EscIO2(FileNotFound, symvec->name);
  RESETBUF(symvec->f, Char);
  if (BUFEOF(symvec->f))
    return;
  fscanf(symvec->f, "%*[^\n]");
  getc(symvec->f);   /* skip first line ('* dalvec') */
  if (BUFEOF(symvec->f))  /* determine prior program name */
    return;
  /* check that the string '* sites' exists */
  /* *   s i t e s */
  a = getc(symvec->f);
  b = getc(symvec->f);
  c = getc(symvec->f);
  d = getc(symvec->f);
  e = getc(symvec->f);
  f = getc(symvec->f);
  g = getc(symvec->f);
  if (a == '\n')
    a = ' ';
  if (b == '\n')
    b = ' ';
  if (c == '\n')
    c = ' ';
  if (d == '\n')
    d = ' ';
  if (e == '\n')
    e = ' ';
  if (f == '\n')
    f = ' ';
  if (g == '\n')
    g = ' ';
  if (a != '*' || b != ' ' || c != 's' || d != 'i' || e != 't' || f != 'e' ||
      g != 's')
    return;
  fprintf(fout->f,
    "******************************************************************************\n");
  fprintf(fout->f,
    "* NOTE: since the data come from the sites program, the error bar is not     *\n");
  fprintf(fout->f,
    "* printed on the sequence logo.                                              *\n");
  fprintf(fout->f,
    "******************************************************************************\n");
  *sitesused = true;
}


/* the value of the threshold is a guess right now! */

#define threshold       0.00001


/* end module makelogo.warnifsitesused */

/* begin module makelogo.makesymbol */
Static Void makesymbol(afile, height, caps, c)
_TEXT *afile;
double height;
boolean caps;
Char c;
{
  /* write the instructions for the symbol c with height h to file afile.
The move by the amount `height' vertically afterward is done in numchar. */
  if (fabs(height) <= threshold)
    return;
  fprintf(afile->f, "%*.*f (", pwid, pdec, height);
  protectpostscript(afile, c);
  if (caps)
    fputc(capitalize(c), afile->f);
  else
    putc(c, afile->f);
  fprintf(afile->f, ") numchar\n");
}

#undef threshold


/* end module makelogo.makesymbol */

/* begin module makelogo.Ibeam */
Static Void Ibeam(afile, height)
_TEXT *afile;
double height;
{
  /* write the instructions for making an I beam with height (in cm) to file
afile.  Return to the original coordinate afterwards */
  fprintf(afile->f, "%*.*f Ibeam\n", pwid, pdec, height);
}


/* end module makelogo.Ibeam */

/* begin module makelogo.summary */
Static Void summary(f, c, rstotal, varhnb, thefrom, theto)
_TEXT *f;
Char c;
double rstotal, varhnb;
long thefrom, theto;
{
  /* write summary information to file f.  Start each line with character c. */
  if (c != ' ')
    fprintf(f->f, "%c ", c);
  fprintf(f->f, "Rs total is %*.*f", infofield, infodecim, rstotal);
  if (varhnb >= 0)
    fprintf(f->f, " +/- %*.*f bits", infofield, infodecim, sqrt(varhnb));
  else
    fprintf(f->f, " bits (sample error not known)");
  fprintf(f->f, " in the range from %ld to %ld\n", thefrom, theto);
}


/* end module makelogo.summary */

/* begin module makelogo.makenumber */
Static Void makenumber(l, number)
_TEXT *l;
long number;
{
  /* write the PostScript instructions for forming the number in file l */
  /* allow user to unearth the call to makenumber by hand */
  fprintf(logo.f, "numbering {");
  fprintf(l->f, "(%ld) makenumber", number);
  fprintf(logo.f, "} if\n");
}


/* end module makelogo.makenumber */

/* begin module makelogo.cosine */
Static Void cosine(afile, amplitude, phase, wavelength, base, xmin, ymin,
		   xmax, ymax, step, dash, thickness)
_TEXT *afile;
double amplitude, phase, wavelength, base, xmin, ymin, xmax, ymax;
long step;
double dash, thickness;
{
  /* write the cosine wave out to afile as defined by the parameters */
  fprintf(afile->f, "%% amplitude  phase  wavelength  base:\n");
  fprintf(afile->f, " %*.*f cm %*.*f cm %*.*f cm %*.*f cm\n",
	  pwid, pdec, amplitude, pwid, pdec, phase, pwid, pdec, wavelength,
	  pwid, pdec, base);
  fprintf(afile->f, "%% xmin ymin xmax ymax step:\n");
  fprintf(afile->f, " %*.*f cm %*.*f cm %*.*f cm %*.*f cm %ld\n",
	  pwid, pdec, xmin, pwid, pdec, ymin, pwid, pdec, xmax, pwid, pdec,
	  ymax, step);
  fprintf(afile->f, "%% dash thickness:\n");
  fprintf(afile->f, " %*.*f cm", pwid, pdec, dash);
  fprintf(afile->f, " %*.*f cm cosine\n", pwid, pdec, thickness);
}


/* end module makelogo.cosine */

/* begin module makelogo.mark.package */
/******************************************************************************/
/* When transferred to another program, this package
of procedures will do all the mark routines */

/* begin module makelogo.getmark */
/* end module makelogo.getmark */

/* begin module makelogo.marktype */
/* end module makelogo.marktype */

/* begin module makelogo.circlesymbol */
/* end module makelogo.circlesymbol */

/* begin module makelogo.trianglesymbol */
/* end module makelogo.trianglesymbol */

/* begin module makelogo.squaresymbol */
/* end module makelogo.squaresymbol */

/* begin module makelogo.linesymbol */
/* end module makelogo.linesymbol */

/* begin module makelogo.boxsymbol */
/* end module makelogo.boxsymbol */

/* begin module makelogo.usersymbol */
/* end module makelogo.usersymbol */

/* begin module makelogo.markup */
/* end module makelogo.markup */

/* begin module makelogo.marksymbols */
/* end module makelogo.marksymbols */

/******************************************************************************/
/* end module makelogo.mark.package */

/* begin module makelogo.getmark */
Static Void getmark(marks, logo, marksymbol, marktype, markbase1, markbits1,
		    markbase2, markbits2, markscale, nextmark)
_TEXT *marks, *logo;
Char *marksymbol, *marktype;
double *markbase1, *markbits1, *markbase2, *markbits2, *markscale;
long *nextmark;
{
  /* Obtain the information for placing the next mark (markbase1,markbits1),
its kind (marksymbol) and the integer location (nextmark).  The logo
file is used for user defined symbols. */
  boolean done = false;   /* done searching for data */

  do {
    if (BUFEOF(marks->f)) {
      *nextmark = LONG_MAX;
      *marksymbol = ' ';
      done = true;
    } else {
      if (P_eoln(marks->f) | (P_peek(marks->f) == ' ')) {
	fscanf(marks->f, "%*[^\n]");
	getc(marks->f);
	/* skip comments.  Allowing a blank character should
	   avoid a lot of frustration for people, because otherwise the
	   program will halt (see just below) and it is hard to find the
	   blank character! */
      } else {
	*marksymbol = getc(marks->f);
	if (*marksymbol == '\n')
	  *marksymbol = ' ';
	if (*marksymbol != 'U' && *marksymbol != 'u' && *marksymbol != '*' &&
	    *marksymbol != 't' && *marksymbol != 's' && *marksymbol != 'l' &&
	    *marksymbol != 'b' && *marksymbol != 'c') {
	  printf("mark symbol in file marks must be one of: \"cblst*uU\"\n");
	  printf("\"%c\" is not allowed\n", *marksymbol);
	  halt();
	}

	if (*marksymbol != '*' && *marksymbol != 'u' && *marksymbol != 'U') {
	  *marktype = getc(marks->f);
	  if (*marktype == '\n')
	    *marktype = ' ';
	  if (*marktype != 'd' && *marktype != 'f' && *marktype != 's') {
	    printf("mark type in file marks must be one of: \"sfd\"\n");
	    printf("\"%c\" is not allowed\n", *marktype);
	    halt();
	  }
	}

	switch (*marksymbol) {

	case '*':   /* skip comments */
	  fscanf(marks->f, "%*[^\n]");
	  getc(marks->f);
	  break;

	case 'c':
	case 't':
	case 's':
	  fscanf(marks->f, "%lg%lg%lg%*[^\n]", markbase1, markbits1,
		 markscale);
	  getc(marks->f);
	  *markbase2 = 0.0;
	  *markbits2 = 0.0;
	  if (*markscale <= 0.0) {
	    printf("mark scale must be positive\n");
	    halt();
	  }
	  *nextmark = (long)(*markbase1);
	  done = true;
	  break;

	case 'l':
	case 'b':
	  fscanf(marks->f, "%lg%lg%lg%lg%*[^\n]", markbase1, markbits1,
		 markbase2, markbits2);
	  getc(marks->f);
	  *nextmark = (long)(*markbase1);
	  done = true;
	  break;

	case 'u':  /* define the user procedure */
	  while (!done) {
	    if (BUFEOF(marks->f)) {
	      printf(
		"The \"!\" to mark the end of a user defined symbol is missing.\n");
	      halt();
	    } else if (P_peek(marks->f) != '!')
	      copyaline(marks, logo);
	    else
	      done = true;
	  }
	  fscanf(marks->f, "%*[^\n]");
	  getc(marks->f);   /* skip the ! line */
	  done = false;
	  break;

	case 'U':
	  fscanf(marks->f, "%lg%lg%lg%lg", markbase1, markbits1, markbase2,
		 markbits2);
	  *nextmark = (long)(*markbase1);
	  done = true;
	  break;
	  /* grab the coordinates for the user, but DO NOT
	                move to the next line.  Later, in markup, the
	                coordinates in drawing space get calculated and
	                THEN the rest of the line gets copied out */
	}
      }
    }
  } while (!done);
}


/* end module makelogo.getmark */

/* begin module makelogo.marktype */
Static Void makemarktype(f, marktype)
_TEXT *f;
Char marktype;
{
  /* make the mark type to the file f */
  switch (marktype) {

  /* for filling, we stroke first!  This ensures that
     the symbol edges are identical whether stroked or not! */
  case 'f':
    fprintf(f->f, " gsave stroke grestore fill\n");
    break;

  case 's':
    fprintf(f->f, " stroke\n");
    break;

  case 'd':
    fprintf(f->f, " [3] 0 setdash stroke\n");
    break;
  }
}


/* end module makelogo.marktype */

/* begin module makelogo.circlesymbol */
Static Void circlesymbol(f, x, y, radius, marktype)
_TEXT *f;
double x, y, radius;
Char marktype;
{
  /* write a circle to file f at (x, y), of given radius
and mark it according to marktype */
  fprintf(f->f, " %*.*f cm %*.*f cm %*.*f cm circlesymbol\n",
	  pwid, pdec, x, pwid, pdec, y, pwid, pdec, radius);
  makemarktype(f, marktype);
}


/* end module makelogo.circlesymbol */

/* begin module makelogo.trianglesymbol */
Static Void trianglesymbol(f, x, y, radius, marktype)
_TEXT *f;
double x, y, radius;
Char marktype;
{
  /* write a triangle to file f at (x, y), of given "radius"
and mark it according to marktype */
  fprintf(f->f, " %*.*f cm %*.*f cm %*.*f cm trianglesymbol\n",
	  pwid, pdec, x, pwid, pdec, y, pwid, pdec, radius);
  makemarktype(f, marktype);
}


/* end module makelogo.trianglesymbol */

/* begin module makelogo.squaresymbol */
Static Void squaresymbol(f, x, y, side, marktype)
_TEXT *f;
double x, y, side;
Char marktype;
{
  /* write a square to file f at (x, y), of given "side"
and mark it according to marktype */
  fprintf(f->f, " %*.*f cm %*.*f cm %*.*f cm squaresymbol\n",
	  pwid, pdec, x, pwid, pdec, y, pwid, pdec, side);
  makemarktype(f, marktype);
}


/* end module makelogo.squaresymbol */

/* begin module makelogo.linesymbol */
Static Void linesymbol(f, x1, y1, x2, y2, marktype)
_TEXT *f;
double x1, y1, x2, y2;
Char marktype;
{
  /* write a line to file f at (x1, y1), (x2, y2)
and mark it according to marktype */
  fprintf(f->f, " %*.*f cm %*.*f cm %*.*f cm %*.*f cm linesymbol\n",
	  pwid, pdec, x1, pwid, pdec, y1, pwid, pdec, x2, pwid, pdec, y2);
  makemarktype(f, marktype);
}


/* end module makelogo.linesymbol */

/* begin module makelogo.boxsymbol */
Static Void boxsymbol(f, x1, y1, x2, y2, marktype)
_TEXT *f;
double x1, y1, x2, y2;
Char marktype;
{
  /* write a box to file f at (x1, y1), (x2, y2)
and mark it according to marktype */
  fprintf(f->f, " %*.*f cm %*.*f cm %*.*f cm %*.*f cm boxsymbol\n",
	  pwid, pdec, x1, pwid, pdec, y1, pwid, pdec, x2, pwid, pdec, y2);
  makemarktype(f, marktype);
}


/* end module makelogo.boxsymbol */

/* begin module makelogo.usersymbol */
Static Void usersymbol(f, x1, y1, x2, y2, marks)
_TEXT *f;
double x1, y1, x2, y2;
_TEXT *marks;
{
  /* write a user symbol to file f at (x1, y1), (x2, y2) */
  fprintf(f->f, " %*.*f cm %*.*f cm %*.*f cm %*.*f cm \n",
	  pwid, pdec, x1, pwid, pdec, y1, pwid, pdec, x2, pwid, pdec, y2);
  copyaline(marks, f);
}


/* end module makelogo.usersymbol */

/* begin module makelogo.markup */
Static Void markup(logo, charwidth, cmperbit, position_, marks, marksymbol,
		   marktype, markbase1, markbits1, markbase2, markbits2,
		   markscale, nextmark)
_TEXT *logo;
double charwidth, cmperbit;
long position_;
_TEXT *marks;
Char *marksymbol, *marktype;
double *markbase1, *markbits1, *markbase2, *markbits2, *markscale;
long *nextmark;
{
  /* markup the logo with the mark as defined by its symbol,
type, coordinate and scale factor. */
  double radius;
  /* radius of a circle mark, or the radius of a circle
                   a triangle is enscribed in or the side of a square. */
  double x1;   /* an x coordinate on the logo */
  double y1;   /*  a y coordinate on the logo */
  double x2;   /* an x coordinate on the logo */
  double y2;   /*  a y coordinate on the logo */

  /* mark the logo up with marks */
  if (position_ < *nextmark)
    return;
  do {
    if (position_ == *nextmark) {
      fprintf(logo->f, "gsave\n");

      switch (*marksymbol) {

      case 'c':
      case 't':
      case 's':
	x1 = (*markbase1 - *nextmark + 0.5) * charwidth;
	y1 = *markbits1 * cmperbit;
	radius = *markscale * charwidth / 2.0;
	switch (*marksymbol) {

	case 'c':
	  circlesymbol(logo, x1, y1, radius, *marktype);
	  break;

	case 't':
	  trianglesymbol(logo, x1, y1, radius, *marktype);
	  break;

	case 's':
	  squaresymbol(logo, x1, y1, radius, *marktype);
	  break;
	}
	break;

      case 'l':
      case 'b':
      case 'U':
	x1 = (*markbase1 - *nextmark + 0.5) * charwidth;
	y1 = *markbits1 * cmperbit;
	x2 = (*markbase2 - *nextmark + 0.5) * charwidth;
	y2 = *markbits2 * cmperbit;
	switch (*marksymbol) {

	case 'b':
	  boxsymbol(logo, x1, y1, x2, y2, *marktype);
	  break;

	case 'l':
	  linesymbol(logo, x1, y1, x2, y2, *marktype);
	  break;

	case 'U':
	  usersymbol(logo, x1, y1, x2, y2, marks);
	  break;
	}
	break;
      }

      fprintf(logo->f, "grestore\n");
    }
    /* do the mark */
    /*
writeln(output,marksymbol,' ',markbase1:5:3, ' ',markbits1:5:3,
                              ' ',markbase2:5:3, ' ',markbits2:5:3,
                              ' ',markscale:5:3,' ',nextmark:5);
    */
    /* get the next one */
    getmark(marks, logo, marksymbol, marktype, markbase1, markbits1,
	    markbase2, markbits2, markscale, nextmark);
  } while (position_ >= *nextmark);
}


/* end module makelogo.markup */

/* begin module docosinewave */
Static Void docosinewave(logo, params, stacknumber, position_)
_TEXT *logo;
parameters params;
long stacknumber, position_;
{
  /* overlay a cosine wave as specified by the parameters */
  double xscale, yscale;   /* converstion factors for x and y for the wave */
  double xmin, ymin;
      /* lower left corner the wave could be in, for the wave */
  double xmax, ymax;
      /* upper right corner the wave could be in, for the wave */
  waveparam *thiswave;   /* the wave we are currently printing */
  waveparam *WITH;

  thiswave = params.wp;
  while (thiswave != NULL) {
    WITH = thiswave;
    xscale = params.charwidth;
    yscale = params.cmperbit;
    xmin = (position_ - stacknumber + 1) * xscale;   /* position */
    xmax = (position_ + 1) * xscale;   /* position */
    ymin = 0.0;   /* bits */
    ymax = WITH->waveamplitude + params.barheight * yscale;   /* bits */
    /* move back to the zero on the plot! */
    fprintf(logo->f, "gsave\n");
    fprintf(logo->f, " %*.*f cm 0 translate\n",
	    pwid, pdec, -(position_ + 1) * params.charwidth);
    if (WITH->extreme == 'h')   /* high center point cosine wave */
      cosine(logo, yscale * WITH->waveamplitude,
	     xscale * (WITH->wavelocation + 0.5), xscale * WITH->wavelength,
	     yscale * (WITH->wavebit - WITH->waveamplitude), xmin, ymin, xmax,
	     ymax, 1L, WITH->dash, WITH->thickness);
    /* amplitude */
    /* phase */
    /* the half of a base is to make it put the
       extreme in the middle of the character rather
       than between characters */
    /* wavelength (cm) */
    /* base (cm) */
    /* limiting box (cm) */
    /* step is in points */
    /* dash is in cm */
    /* thickness is in cm */
    else
      cosine(logo, -yscale * WITH->waveamplitude,
	     xscale * (WITH->wavelocation + 0.5), xscale * WITH->wavelength,
	     yscale * (WITH->wavebit + WITH->waveamplitude), xmin, ymin, xmax,
	     ymax, 1L, WITH->dash, WITH->thickness);
    /* low center point cosine wave */
    /* step is in points */
    /* dash is in cm */
    /* thickness is in cm */
    fprintf(logo->f, "grestore\n");
    thiswave = thiswave->next;
  }
}


/* end module docosinewave */

/* begin module setboundingbox */
Static Void setboundingbox(logo, params)
_TEXT *logo;
parameters params;
{
  /* determine the BoundingBox parameters */
  double cmfactor;
  /* multiply by this to convert
                     from cm to PostScript points */
  double BaseAxis;   /* width of the basic logo figure */
  double BitAxis;   /* height of the basic logo figure */
  double llxhere;   /* lower left x of figure */
  double llyhere;   /* lower left y of figure */
  double urxhere;   /* upper right x of figure */
  double uryhere;   /* upper right y of figure */
  boolean srotation = false;   /* is rotation a member of -90, 0, +90? */

  /*
     The original "simple life" method:
     writeln(logo,'%!');
     writeln(logo,'% makelogo ',version:4:2);
  */

  if (params.highest - params.lowest + 1 > params.stacksperline)
    BaseAxis = params.charwidth * params.stacksperline;
  else
    BaseAxis = params.charwidth * (params.highest - params.lowest + 1);

  BitAxis = params.barheight * params.linesperpage * params.linemove;


  if (params.edgecontrol != 'p') {
    if ((long)floor(params.rotation + 0.5) == -90) {
      llxhere = params.xcorner;
      llyhere = params.ycorner - BaseAxis;
      urxhere = params.xcorner + BitAxis;
      uryhere = params.ycorner;
      srotation = true;
    } else if ((long)floor(params.rotation + 0.5) == 0) {
      llxhere = params.xcorner;
      llyhere = params.ycorner;
      urxhere = params.xcorner + BaseAxis;
      uryhere = params.ycorner + BitAxis;
      srotation = true;
    } else if ((long)floor(params.rotation + 0.5) == 90) {
      llxhere = params.xcorner - BitAxis;
      llyhere = params.ycorner;
      urxhere = params.xcorner;
      uryhere = params.ycorner + BaseAxis;
      srotation = true;
    }

    /* expand edge margin and convert to cm */
    cmfactor = 72 / 2.54;   /* convert to points from cm */
    llxhere = (llxhere - params.edgeleft) * cmfactor;
    llyhere = (llyhere - params.edgelow) * cmfactor;
    urxhere = (urxhere + params.edgeright) * cmfactor;
    uryhere = (uryhere + params.edgehigh) * cmfactor;

    if (!srotation) {
      printf("* NOTE: The angle of rotation is not a multiple of 90 degrees,\n");
      printf("so bounding box is being set to page size.\n");
    }
  }

  if (!srotation) {
    /* force weird values that get corrected to page limits below */
    llxhere = llx;
    llyhere = lly;
    urxhere = urx;
    uryhere = ury;
  }

  /* Warn user about weird bounds to the standard page limits */
  if (llxhere < llx)
    printf("* WARNING: left side goes off page\n");
  if (llyhere < lly)
    printf("* WARNING: lower side goes off page\n");
  if (urxhere > urx)
    printf("* WARNING: right side goes off page\n");
  if (uryhere > ury)
    printf("* WARNING: upper side goes off page\n");

  if (llxhere >= urxhere)
    printf("* WARNING: horizontal bounds inverted\n");

  if (llyhere >= uryhere)
    printf("* WARNING: vertical bounds inverted\n");

  /* create header for EPS file */
  fprintf(logo->f, "%%!PS-Adobe-2.0 EPSF-2.0\n");
  fprintf(logo->f, "%%%%Title: makelogo %4.2f\n", version);
  fprintf(logo->f, "%%%%Creator: Tom Schneider, toms@ncifcrf.gov\n");
  /* NOTE: bounding box definition (Red book page 284) requires
     integers, so the values are rounded just before output: */
  fprintf(logo->f, "%%%%BoundingBox: %5ld %5ld %5ld %5ld\n",
	  (long)floor(llxhere + 0.5), (long)floor(llyhere + 0.5),
	  (long)floor(urxhere + 0.5), (long)floor(uryhere + 0.5));
  fprintf(logo->f, "%%%%Pages: atend\n");
  fprintf(logo->f, "%%%%DocumentFonts:\n");
  fprintf(logo->f, "%%%%EndComments\n");

  fprintf(logo->f, "/llx %5.1f def\n", llxhere);
  fprintf(logo->f, "/lly %5.1f def\n", llyhere);
  fprintf(logo->f, "/urx %5.1f def\n", urxhere);
  fprintf(logo->f, "/ury %5.1f def\n", uryhere);
}


/* end module setboundingbox */

/* begin module themain */
Static Void themain(symvec, makelogop, colors, marks, wave, logo)
_TEXT *symvec, *makelogop, *colors, *marks, *wave, *logo;
{
  /* the main procedure of the program */
  parameters params;   /* the parameters read from makelogop */

  long actualsymbols;
  /* the sum of the actual number of symbols found in
    symvec, as opposed to nl, the number that is SUPPOSED to be there */
  long b;   /* index to a symbol */
  boolean chilogo;   /* if true, this is a chilogo */
  boolean dobeam;   /* true means we are going to write the Ibeam */
  boolean dostack;   /* true means we are going to write a stack of letters */
  double fbl;   /* frequency of symbol b at position l */
  Char letter;   /* a letter in the alphabet test */
  long l;   /* predicted coordinate */
  long linenumber;   /* number of lines of logo printed so far */

  double markbase1;   /* location in bases of the marksymbol or its start */
  double markbase2;   /* location in bases of the marksymbol end */
  double markbits1;   /* location in bits of the marksymbol or its start */
  double markbits2;   /* location in bits of the marksymbol end */
  double markscale;
      /* factor by which to change the size of the marksymbol */
  Char marksymbol;   /* a symbol to mark on the logo */
  Char marktype;   /* how to mark a symbol on the logo: dash, fill, stroke */
  long nextmark;   /* the position to place the next mark */

  long nl;   /* number of symbols at position l */
  long pagenumber = 0;   /* page number we are beginning to write out */
  long position_;   /* a location in the aligned sequence (true coordinate) */
  long previousposition;   /* the previous value of position */
  double rsl;   /* information at position l */
  double rsvar;   /* variance of information at position l */
  double rstotal;   /* sum of the rsl for the whole logo */
  double varhnb;   /* variance of rstotal for the whole logo */
  boolean sitesused;
  /* true if the sites program was used to create the
     data.  This determines whether an obnoxious warning should be put
     into the logo ... */
  long stacknumber;
  /* the number of the stack of symbols.  Unlike the
     position variable, it begins at 1.  It is used to decide when to break
     the logo onto the next line */

  long symbols;   /* number of symbols possible */
  _TEXT TEMP;

  printf("makelogo %4.2f\n", version);
  /* reset all input files first so if one is missing
     the logo file hasn't been destroyed yet. */
  if (*symvec->name != '\0') {
    if (symvec->f != NULL)
      symvec->f = freopen(symvec->name, "r", symvec->f);
    else
      symvec->f = fopen(symvec->name, "r");
  } else
    rewind(symvec->f);
  if (symvec->f == NULL)
    _EscIO2(FileNotFound, symvec->name);
  RESETBUF(symvec->f, Char);
  if (*makelogop->name != '\0') {
    if (makelogop->f != NULL)
      makelogop->f = freopen(makelogop->name, "r", makelogop->f);
    else
      makelogop->f = fopen(makelogop->name, "r");
  } else
    rewind(makelogop->f);
  if (makelogop->f == NULL)
    _EscIO2(FileNotFound, makelogop->name);
  RESETBUF(makelogop->f, Char);
  if (*colors->name != '\0') {
    if (colors->f != NULL)
      colors->f = freopen(colors->name, "r", colors->f);
    else
      colors->f = fopen(colors->name, "r");
  } else
    rewind(colors->f);
  if (colors->f == NULL)
    _EscIO2(FileNotFound, colors->name);
  RESETBUF(colors->f, Char);
  if (*marks->name != '\0') {
    if (marks->f != NULL)
      marks->f = freopen(marks->name, "r", marks->f);
    else
      marks->f = fopen(marks->name, "r");
  } else
    rewind(marks->f);
  if (marks->f == NULL)
    _EscIO2(FileNotFound, marks->name);
  RESETBUF(marks->f, Char);
  if (*wave->name != '\0') {
    if (wave->f != NULL)
      wave->f = freopen(wave->name, "r", wave->f);
    else
      wave->f = fopen(wave->name, "r");
  } else
    rewind(wave->f);
  if (wave->f == NULL)
    _EscIO2(FileNotFound, wave->name);
  RESETBUF(wave->f, Char);

  readparameters(makelogop, &params);

  /* do the regular logo */
  readwaveparameters(wave, &params.wp);
  TEMP.f = stdout;
  *TEMP.name = '\0';
  warnifsitesused(symvec, &TEMP, &sitesused);
  params.cmperbit = params.barheight / fabs(params.barbits);
      /* converts bits to cm */

  if (BUFEOF(colors->f) && !params.outline) {
    printf("Half-White Ibeams are used because the symbols are solid black.\n");
    params.HalfWhiteIbeam = true;
  } else
    params.HalfWhiteIbeam = false;
  if (*logo->name != '\0') {
    if (logo->f != NULL)
      logo->f = freopen(logo->name, "w", logo->f);
    else
      logo->f = fopen(logo->name, "w");
  } else {
    if (logo->f != NULL) {

      rewind(logo->f);
    } else
      logo->f = tmpfile();
  }
  if (logo->f == NULL)
    _EscIO2(FileNotFound, logo->name);
  SETUPBUF(logo->f, Char);

  setboundingbox(logo, params);

  if (*symvec->name != '\0') {
    if (symvec->f != NULL)
      symvec->f = freopen(symvec->name, "r", symvec->f);
    else
      symvec->f = fopen(symvec->name, "r");
  } else
    rewind(symvec->f);
  if (symvec->f == NULL)
    _EscIO2(FileNotFound, symvec->name);
  RESETBUF(symvec->f, Char);
  if (!BUFEOF(symvec->f)) {
    while (P_peek(symvec->f) == '*') {
      fprintf(logo->f, "%% ");
      copyaline(symvec, logo);
    }
    fscanf(symvec->f, "%ld%*[^\n]", &symbols);
    getc(symvec->f);
    printf("* %ld symbols.\n", symbols);
  }
  startpostscript(logo, colors, symvec, params);

  getmark(marks, logo, &marksymbol, &marktype, &markbase1, &markbits1,
	  &markbase2, &markbits2, &markscale, &nextmark);

  if (*symvec->name != '\0') {
    if (symvec->f != NULL)
      symvec->f = freopen(symvec->name, "r", symvec->f);
    else
      symvec->f = fopen(symvec->name, "r");
  } else
    rewind(symvec->f);
  if (symvec->f == NULL)
    _EscIO2(FileNotFound, symvec->name);
  RESETBUF(symvec->f, Char);
  if (BUFEOF(symvec->f)) {  /* do an alphabetic test logo */
    printf("* Alphabet Logo created because symvec is empty.\n");
    fprintf(logo->f, "%% Alphabet Logo\n");
    fprintf(logo->f, "startpage startline\n");
    if (params.barends)
      fprintf(logo->f, "makebar\n");
    fprintf(logo->f, "%% find out how high the bar is in centimeters:\n");
    fprintf(logo->f, "/barincm barheight cmfactor div def\n");
    for (b = 'A'; b <= 'Z'; b++) {
      position_ = b + 1 - 'A';
      if (position_ == params.bar)
	fprintf(logo->f, "makebar\n");
      if (position_ >= params.lowest && position_ <= params.highest) {
	makenumber(logo, position_);
	if (!params.caps)
	  letter = _tolower(b);
	else
	  letter = (Char)b;
	fprintf(logo->f, "  gsave barincm (%c) numchar grestore shift\n",
		letter);
      }
    }
    if (params.barends)
      fprintf(logo->f, "makebar\n");
    fprintf(logo->f, "endline endpage\n");
  } else {
    processsymvec(symvec);
    fscanf(symvec->f, "%*[^\n]");
    getc(symvec->f);   /* skip symbols */

    rstotal = 0.0;
    varhnb = 0.0;
    linenumber = 0;   /* trigger start of a page */
    l = params.lowest;
    position_ = params.lowest;
    chilogo = false;
    while (!BUFEOF(symvec->f)) {
      previousposition = position_;   /* keep track of previous position */
      processsymvec(symvec);

      fscanf(symvec->f, "%ld%ld%lg%lg%*[^\n]", &position_, &nl, &rsl, &rsvar);
      getc(symvec->f);

      /* read through the symbols and see if they are really all there.
      This check is useful when someone writes a symvec themselves. */
      actualsymbols = 0;
      for (b = 0; b < symbols; b++) {
	processsymvec(symvec);
	fscanf(symvec->f, "%c%ld%*[^\n]", &map[b].b, &map[b].n);
	getc(symvec->f);
	if (map[b].b == '\n')
	  map[b].b = ' ';
	if (map[b].n < 0) {
	  if (!chilogo) {
	    chilogo = true;
	    printf("This is a Chilogo! - Upside down letterswill be produced\n");
	  }
	}
	if (chilogo)
	  actualsymbols += labs(map[b].n);
	else
	  actualsymbols += map[b].n;
      }
      if (!chilogo && nl != actualsymbols ||
	  chilogo && labs(nl - actualsymbols) > 1.5) {
	printf("\nTHE SYMVEC FILE IS BAD!\n");
	printf("At position %ld the sum of symbols found is %ld\n",
	       position_, actualsymbols);
	printf("But the noted number is %ld\n", nl);
	halt();
      }
      /* in the case of the chilogo, the sum of rounded numbers
         may be off by 1 */

      /* create the PostScript code for this stack of symbols */
      if (position_ < params.lowest || position_ > params.highest)
	continue;

      rstotal += rsl;
      varhnb += rsvar;

      /* put the symbols into order of their frequency */
      quicksort(1, (int)symbols);

      /* track the line number */
      if (linenumber == 0) {
	pagenumber++;
	if (pagenumber == 1)
	  fprintf(logo->f, "%%%%EndProlog\n");
	else
	  printf("writing page %ld\n", pagenumber);

	fprintf(logo->f, "\n%%%%Page: %ld %ld\n", pagenumber, pagenumber);
	fprintf(logo->f, "startpage %% [\n");

	stacknumber = 0;   /* trigger line to start */
      }

      /* track the number of stacks on the line */
      if (stacknumber == 0) {
	linenumber++;
	fprintf(logo->f, "startline %% line number %ld\n", linenumber);
      }
      stacknumber++;

      if (position_ == params.bar) {
	if (!params.barends || stacknumber != 1) {
	  fprintf(logo->f, "%% before coordinate %ld: make the bar\n",
		  position_);
	  fprintf(logo->f, "makebar\n");
	}
      }

      fprintf(logo->f, "%% at coordinate %ld\n", position_);
      makenumber(logo, position_);

      /* avoid plotting tiny Rs values at all (PostScript blows up
         on the Apple LaserWriter - and no plot comes out.) */
      if ((long)floor(pnum * rsl * params.cmperbit + 0.5) > 0.0)
	dostack = true;
      else
	dostack = false;

      /* if rsvar is negative, this indicates that the
         sample variation is unknown.  (see the sites.p program) */
      dobeam = false;
      if (rsvar >= 0.0) {
	if (params.barbits > 0.0)
	  dobeam = true;
      } else if (!sitesused) {
	printf("WARNING: a negative Rs variation was\n");
	printf("found in symvec, but the data are not from\n");
	printf(" the sites program.\n");
	printf("There may be a program or data error.\n");
      }

      if (dostack || dobeam)
	fprintf(logo->f, "gsave\n");
      if (dostack) {
	for (b = 0; b < symbols; b++) {
	  /* draw one character in the stack of characters */
	  fbl = (double)map[b].n / nl;
	  makesymbol(logo,
	    (double)((long)floor(pnum * fbl * rsl * params.cmperbit + 0.5)) /
	    ((pnum < 0) ? -pnum : pnum), params.caps, map[b].b);
	  /* note: the abs(pnum) makes sure that the sign of pnum
	     DOES get passed to makesymbol, so that upside down
	     symbols can be printed! */
	}
      }
      if (dobeam && !sitesused)
	Ibeam(logo, sqrt(rsvar) * params.cmperbit);
      if (dostack || dobeam)
	fprintf(logo->f, "grestore\n");

      /* make the appropriate marks within this base interval */
      markup(logo, params.charwidth, params.cmperbit, position_, marks,
	     &marksymbol, &marktype, &markbase1, &markbits1, &markbase2,
	     &markbits2, &markscale, &nextmark);

      fprintf(logo->f, "shift\n");   /* move away from this stack */
      if (stacknumber == params.stacksperline || position_ == params.highest)
	docosinewave(logo, params, stacknumber, position_);

      if (linenumber == params.linesperpage &&
	  stacknumber == params.stacksperline)
      {  /* complete the page */
	if (params.highest == params.bar - 1) {
	  if (!params.barends) {
	    fprintf(logo->f,
	      "%% bar at end of logo: make the bar before position %ld\n",
	      position_);
	    fprintf(logo->f, "makebar\n");
	  }
	  /* or (stacknumber <> 1) residue from main call */
	}

	fprintf(logo->f, "endline\n");
	stacknumber = 0;   /* trigger for restarting the line */
	fprintf(logo->f, "endpage %% ]\n");
	linenumber = 0;   /* trigger for restarting the page */
      }


      if (stacknumber == params.stacksperline) {  /* complete the line */
	fprintf(logo->f, "endline\n");
	stacknumber = 0;   /* trigger for restarting the line */
      }

      /* check the coordinate system */
      while (l != position_ && l <= params.highest) {
	printf("\nWARNING: symvec does not contain data for position %ld\n",
	       l);
	if (l == 0 && params.lowest < 0 && params.highest > 0 &&
	    position_ == 1 && previousposition == -1) {
	  printf("It seems that you don't have a zero coordinate.\n");
	  printf(
	    "\"... the invention, probably by the Hindus, of the digit zero has been\n");
	  printf(
	    "described as one of the greatest importance in the history of mathematics.\"\n");
	  printf("--- Encyclopaedia Britannica (1:1175, 1982)\n");
	  printf("Please use a zero!\n");
	  if (*logo->name != '\0') {
	    if (logo->f != NULL)
	      logo->f = freopen(logo->name, "w", logo->f);
	    else
	      logo->f = fopen(logo->name, "w");
	  } else {
	    if (logo->f != NULL)
	      rewind(logo->f);
	    else
	      logo->f = tmpfile();
	  }
	  if (logo->f == NULL)
	    _EscIO2(FileNotFound, logo->name);
	  SETUPBUF(logo->f, Char);
	  halt();
	}
	putchar('\n');
	l++;   /* predict the next position */
      }
      l++;   /* predict the next position */
    }

    if (position_ < params.highest) {
      printf("\nWARNING: Highest position requested was not found in symvec\n\n");
      /* in this case, the cosine wave was not done above, so do it now */
      if (stacknumber != 0)
	docosinewave(logo, params, stacknumber, position_);
    }

    /* make sure that the end line and page is done! */
    if (stacknumber != 0)
      fprintf(logo->f, "endline\n");
    if (linenumber != 0)
      fprintf(logo->f, "endpage %% ]\n");

    summary(logo, '%', rstotal, varhnb, params.lowest, params.highest);
    TEMP.f = stdout;
    *TEMP.name = '\0';
    summary(&TEMP, ' ', rstotal, varhnb, params.lowest, params.highest);

  }
  /* do the regular logo */
  /* the main loop; read through the symvec, sort the characters and then
     create the graphic.
     The program originally assumed that the header of symvec has
     been skipped and that symbols is read in already.  However,
     doing it again is safer, given that symvec can now be read
     by other parts of the program. */

  fprintf(logo->f, "%%%%Trailer\n");
  fprintf(logo->f, "%%%%Pages: %ld\n", pagenumber);
}


/* end module themain */

main(argc, argv)
int argc;
Char *argv[];
{
  PASCAL_MAIN(argc, argv);
  if (setjmp(_JL1))
    goto _L1;
  logo.f = NULL;
  strcpy(logo.name, "logo");
  wave.f = NULL;
  strcpy(wave.name, "wave");
  marks.f = NULL;
  strcpy(marks.name, "marks");
  colors.f = NULL;
  strcpy(colors.name, "colors");
  makelogop.f = NULL;
  strcpy(makelogop.name, "makelogop");
  symvec.f = NULL;
  strcpy(symvec.name, "symvec");
  themain(&symvec, &makelogop, &colors, &marks, &wave, &logo);
_L1:
  if (symvec.f != NULL)
    fclose(symvec.f);
  if (makelogop.f != NULL)
    fclose(makelogop.f);
  if (colors.f != NULL)
    fclose(colors.f);
  if (marks.f != NULL)
    fclose(marks.f);
  if (wave.f != NULL)
    fclose(wave.f);
  if (logo.f != NULL)
    fclose(logo.f);
  exit(EXIT_SUCCESS);
}



/* End. */
