JPRED-2 Add alscript to the Git repository
[jpred.git] / sources / alscript / src / alps.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "array.h"
5 #include "gjutil.h"
6 #include "version.h"
7
8 /****************************************************************************
9
10    ALPS - Main routines for ALSCRIPT alignment formatting tool
11
12    Copyright:  Geoffrey J. Barton (1992,1993,1997)
13
14    email: geoff@ebi.ac.uk
15
16 All use of this program  must cite:  Barton, G. J. (1993), ALSCRIPT: A Tool to
17 Format Multiple Sequence Alignments, Protein Engineering, Volume 6, No. 1, 
18 pp. 37-40.
19
20   Please see README file for details of limitations of use.
21
22   $Id: alps.c,v 1.3 1998/09/17 17:34:26 geoff Exp $
23   $Log: alps.c,v $
24   Revision 1.3  1998/09/17 17:34:26  geoff
25   Add the new README file and the LICENSE and RELEASE_NOTES
26
27   Revision 1.2  1998/09/17 16:54:58  geoff
28   Check consistency with archive
29
30
31 ****************************************************************************
32
33    Main routine for ALSCRIPT - formally called ALPS
34
35    alps:  11th June 1992.
36    Author: G. J. Barton
37
38    This file contains a set of subroutines that provide for flexible
39 formatting of multiple sequence alignments in PostScript at
40 publication quality.
41
42 11-18th June 1992:
43
44 1.  Modified getbloc.c to Agetbloc.c.  Agetbloc reads all characters
45 (ie not just legal amino acid codes) from an AMPS blocfile format
46 multiple alignment file.
47
48 2.  Wrote basic page scaling features to allow arbitrary page
49 dimensions to be defined and to allow all x,y locations to be defined
50 in terms of characters of the chosen pointsize.  The number of
51 residues per line and hence number of pages is determined by the
52 pointsize.  The page is divided into four areas.  (a) The main region
53 for plotting out the amino acid sequences. (b) A region to the left of
54 a for plotting sequence identifier codes - the width of this region is
55 set by variable Cidwidth.  (c) A region above region a, and (d) a
56 region below a.  Regions c and d are initially set to zero size.
57 Routine ALReserveSpace() allows a selected number of lines to be
58 reserved above or below for plotting.
59
60 3.  Routines ALOutID and ALOutSeq written and multi-page plotting of
61 the sequences sorted out.  Still limited to one page in the vertical
62 direction - toyed with the idea of writing single page PostScript and
63 using PostScript to modify clipping boundaries like in the Poster demo
64 program in the CookBook.
65
66 4.  Experiment with simple boxing facility - ALDrawSimpleBox().  This
67 routine is incompatible with multi-page output since page breaks are
68 unpredictable.
69
70 5.  Develop sophisticated (!) boxing facility - defines boxes in terms
71 of TOP BOTTOM LEFT and RIGHT lines that may be defined around each
72 character routine ALLineRes() implements this feature.  The details of
73 TOP etc for each character are stored in the unsigned char array
74 "lines".  This uses the rightmost four bits to encode LEFT RIGHT etc.
75 Thus a line to the LEFT line is coded by decimal 1 (0001 binary), a
76 full box by decimal 15 (1111 binary).  ALBoxRes and ALBoxRegion
77 written to allow boxing of arbitrary regions.  
78
79 6.  The y coordinate sent to the low level ALLineRes routine 
80 refers directly to the index to the lines array.  If you want to work in 
81 residue coordinate space, you need to flip the y coordinate before 
82 writing to the lines array (also the fill array).  Routines ALSurroundChars
83 and ALFillChars do this directly.  Routines ALBoxRegion and ALFilRegion
84 make use of the Yindx array which does the flip in a much cleaner and more
85 elegant way.  If I'd thought of it at the
86 time, I would have used this in ALSurroundChars and ALFillChars as well!
87
88 7.  Now add capability to split alignments vertically as well as horizontally.
89 There is now no limit on pointsize or number/length of sequences 
90 (in principle!).  Next move on the page layout front will be to allow 
91 multiple blocks on a single page - this would permit alignments of a 
92 few sequences, or small fonts to make better use of paper!
93
94 8.  We now have most of the subroutines working OK.  So time to tidy up the 
95 input.  Add simple command parser to main programme - this is in two steps, 
96 step 1 reads the basic page layout commands, step 2 reads the boxing/shading
97 font changing commands - Oh yes, added the font changing option as well.
98
99 Current commands as follows:
100 Commands are delimited by space, comma, or tab. Newline signals the end of a 
101 command.  Unless otherwise stated, units are in characters of the default pointsize.
102 For a full list see the file "alscript.doc".
103
104 step 1 commands:
105
106 BLOCK_FILE <input filename>           %The name of the alignment file to format
107 OUTPUT_FILE <file>                    %must have this near the beginning
108 LANDSCAPE                             %Longest side horizontal
109 PORTRAIT                              %             vertical
110 POINTSIZE  <float>                    %Pointsize for page calculations and character spacing/default size.
111 IDENT_WIDTH <integer>                 %Width allocated to identifiers.
112 NUMBER_SEQS  1 || 0                   %1=number identifiers, 0= no numbers (default).
113 DEFINE_FONT <font number integer> <font name> <pointsize>  %define a font to be referred to as font number.
114 e.g.
115   DEFINE_FONT 0 Helvetica 10          %font 0 is Helvetica at 10 point
116   DEFINE_FONT 4 Times-Roman DEFAULT   %font 4 is Times-Roman at the default pointsize.
117 SETUP                                 %signals end of step 1 commands.
118
119 step 2 commands:
120
121 RESERVE_SPACE_TOP <integer>           %make space at the top of the alignment 
122 RESERVE_SPACE_BOTTOM <integer>        %                  bottom  DOES NOT WORK.
123 SURROUND_CHARS <chars> <start_res> <start_seq> <end_res> <end_seq> 
124                                       %surround (box) the characters chars within the ranges specified 
125 e.g.
126   SURROUND_CHARS PG 1 7 20 12         %surround P and G characters from residues 1 to 20 of sequences 7 to 12.
127   SURROUND_CHARS DEKHR ALL            %surround D and E and K and R characters for the whole alignment.
128
129 SHADE_CHARS <chars> <start_res> <start_seq> <end_res> <end_seq> <grey>
130                                       %similar syntax to SURROUND_CHARS with the addition of a grey value
131                                       % 0 = black, 1 = white.  Note that shading is done before outputing the
132                                       % alignment.
133 e.g.
134   SHADE_CHARS PG 1 7 20 12 0.5        % shade P and G in the range shown with a grey value of 0.5
135   SHADE_CHARS ILV ALL 0               % shade all  I and L and V in black.
136
137 FONT_CHARS <chars> <start_res> <start_seq> <end_res> <end_seq> <fontnumber>
138                                       %same syntax as SHADE_CHARS, only give the font number in place of grey.
139                                       %font numbers must first be defined with the DEFINE_FONT command above.
140 FONT_RESIDUE sx sy font               %allows setting of font for one residue (use with TEXT command)
141
142 BOX_REGION <start_res> <start_seq> <end_res> <end_seq>
143                                       %draw a rectangular box around the characters within the defined range.
144 SHADE_REGION <start_res> <start_seq> <end_res> <end_seq> <grey>
145                                       %shade the region by the chosed grey value.
146
147 9.  Add option to place arbitrary text string at a character location.
148 e.g
149   TEXT 1 7 "SIGNAL PEPTIDE"           %puts this text at sequence position 1 7.
150                                       %to change fonts use the FONT_RESIDUE or FONT_REGION commands.
151 10. Add option to change fonts of identifiers.
152 ID_FONT <sequence> <font>
153 e.g. 
154   ID_FONT 3 1                         %sets font to 1 for sequence identifier 3
155   ID_FONT ALL 7                       %uses font 7 for all identifiers
156
157 19th June 1992:
158 Still fiddling - must get back to some real work soon.
159 Split alps away from the scanps program.  Now have a separate main() for the routine.
160
161 Add options to redefine all defaults:  e.g. MAXslen (maximum sequence
162 length etc.) Add arbitrary line drawing options:  eg. LINE TOP 20 15 50
163 draws a line along the top of the characters from residue 20 to 50 or
164 sequence 15. Think about adding the option to change line thickness at
165 different parts of the plot. Decide not to implement that option right
166 now. Add option to include dummy sequences (ADD_SEQ)
167
168 Check the programme compiles on the 386 PC.  It does!
169 Write documentation and brief report of the programme.
170
171 22nd June 1992:  Get back to some real work!
172
173 19th October:  Add SILENT_MODE Command and carriage returns to all .PS print statements.
174 21st October:  Add VERTICAL_SPACING command and ability to output multiple blocks per page.
175 15th November: Add pipe options to alscript.c  Tidy up file handling.
176
177 6th December:  Add Colour options.
178 18th Jan 1993: Tidy up citations:  modify Inverse chars to allow reversion.
179 1 March 1993:  Fix bug in colour option.  Pass use_colour to ALDrawLines routine to 
180                specify black for line colour.  Previously, this was drawn in white
181                if coloured shading had been specified on the same characters.
182 2 March 1993:  Fix bug in colour option to output identifiers in black, not white!
183 9 March 1993:  Add NO_NUMBERS option to avoid printing residue numbers.
184 24 March 1993: Add mask features.
185
186 11 March 1994: At PERI - Add special text features - preliminary version only.
187                This permits strands and helices to be plotted as cylinders and arrows.
188                Special text features also permit triangles and circles etc etc. through
189                use of text command.
190
191 23 May 1995: Numerous changes and additions over the last year - these
192 include the option to colour backgrounds differently, ommission of
193 idents on second and subsequent lines, helix, strand and other special
194 characters, relative numbering, error checking of ranges on input,
195 bounding box, screening, conservation colouring...
196
197
198 */
199
200 #define TOKENS "\" ,\n\t"        /* standard command token delimiters */
201 #define POINT 72               /* Work in points throughout */
202 #define C_ID_WIDTH 10          /* Default width for writing id's (in characters) */
203 #define DEF_POINTSIZE 10.0      
204 #define X_OFFSET 40            /* offset for bottom lh corner of page (points) */
205 #define Y_OFFSET 30
206 #define DEF_YPOS 0             /* default first printinf position (character units) */
207 #define LINE_WIDTH_FACTOR 0.05 /* Multiply pointsize by this to get linewidth */
208 #define MAX_ADD_SEQ 10         /* Maximum number of ADD_SEQ commands allowed */
209
210 /*#define MAX_S 10.5             max and min page side in inches */
211 /*#define MIN_S 6.5  */
212 /*#define MAXSIDE (MAX_S * POINT)   Default Max and min dimensions of paper */
213 /*#define MINSIDE (MIN_S * POINT) */
214
215 #define SCREENSIZE 120           /* define default size for screen */
216
217
218 int width = 0;                 /* max width and height of drawing area */
219 int height = 0;
220 char *tokens = TOKENS;
221
222 float MAXside = 10.5 * POINT;     /* values to hold Max and min page side in points */
223 float MINside = 6.5 * POINT;
224
225 int xoff = X_OFFSET;
226 int yoff = Y_OFFSET;
227
228 int Cidwidth = C_ID_WIDTH;     /* width of id region in characters (left of sequence block)*/
229 int Cseqwidth;                 /* width of sequence region in characters */
230 int Cwidth;                    /* width/height of page in characters */
231 int Cheight;
232 int Xspace;                    /* spacing between characters in X */
233 int Yspace;                    /* spacing between characters in Y */
234 float XspaceFactor = 0.2;          /* extra bit to add to horizontal character spacing */
235 float YspaceFactor = 0.0;          /* extra bit to add to vertical character spacing */
236 float XshiftFactor = 0.12;          /* *pointsize gives the shift for vertical lines */
237 float YshiftFactor = 0.12;          /*                                horizontal lines */
238
239 int CseqTop = 0;
240 int CseqVoffset = 0;           /* vertical offset for sequence block (characters)*/
241 int CtopSpace =0;              /* extra space above sequence block (characters) */
242 int CbottomSpace = 0;          /*   "     "   below    "       "         "      */
243 int Csheet = 1;                /* number of vertical splits in sequence block */
244
245 int TVspace = 0;               /* total vertical space reserved (characters)*/
246
247 float Xshift = 0;     /* offsets for drawing box lines */
248 float Yshift = 0;
249 float LineWidthFactor = LINE_WIDTH_FACTOR;
250
251 float pointsize = DEF_POINTSIZE;
252 int npage;
253
254 int Vspacing = 0;               /* vertical spacing in characters between blocks on a page */
255
256
257 enum Orientations{
258   LANDSCAPE,
259   PORTRAIT
260 };
261
262 enum Spaces{
263   TOP,
264   BOTTOM
265 };
266
267 struct addseq {
268         int pos;
269         int num;
270 };
271
272 /* bit masks for the lines array */
273 unsigned char LINE_LEFT = 1; /* mask for line at left of char */
274 unsigned char LINE_RIGHT= 2; /*                  right        */
275 unsigned char LINE_TOP  = 4; /*                  top          */
276 unsigned char LINE_BOTTOM=8; /*                  bottom       */
277  
278 void ALOutId(struct seqdat *,int,unsigned char *colour,
279              unsigned char *,int,int,int,int, FILE *);
280 void ALOutSeq(struct seqdat *,unsigned char **,
281               char ***,
282               unsigned char **,int ,unsigned char **,
283               unsigned char **text_colour,
284               unsigned char background_colour,
285               int ,int ,int ,int ,FILE *);
286 void PSPutText(int,int,char *,FILE *);
287 void PSPutChar(int,int,char,FILE *);
288 void PSShowPage(FILE *);
289 void ALSetFont(char *,int,FILE *);
290 void ALCheckSinglePage(int ,int ,int );
291 void ALSetPageLimits(void);
292 void PSSetOrientation(int, FILE *);
293 void PSPreamble(FILE *,int, int*, int screensize);
294 void PSLandscape(FILE *);
295 void PSPortrait(FILE *);
296 void PSSetupPage(int,int,FILE *);
297 void ALReserveSpace(int, int);
298 void ALReportInfo(int, FILE *);
299 char **ALCreateNumbers(int,int,int,int);
300 char *ALCreateTicks(int,int,int);
301 void ALOutTicks(char *,int,int,int,int,FILE *);
302 void ALOutNumbers(char **,int,int,int,int,FILE *);
303 void PSDrawBox(float,float,float,float,float,FILE *);
304 void ALSimpleBox(int,int,int,int,float,FILE *);
305 void PSline(float,float,float,float,FILE *);
306 void ALLineChar(unsigned char **,int,int,unsigned char);
307 void ALLineRes(unsigned char **,int,int,unsigned char);
308 void ALDrawLines(unsigned char **,int,
309                  unsigned char **left_line_colour,
310                  unsigned char **right_line_colour,
311                  unsigned char **top_line_colour,
312                  unsigned char **bottom_line_colour,
313                  int,int,int,int,int,int,FILE *);
314 void ALBoxRes(unsigned char **,int,int);
315 void ALDrawFills(signed char **,int ,unsigned char **, 
316                  int,int ,int,int ,int ,int, FILE *);
317 void ALFilRes(signed char **,int,int,float);
318 void ALBoxRegion(unsigned char **,int,int,int,int,int *);
319 void ALFilRegion(signed char **,int ,int,int,int , int *,float);
320 void ALSurroundChars(struct seqdat *,unsigned char **,int,int,int,int,int,char *);
321 void ALShadeChars(struct seqdat *,signed char **,
322                   int ,int,int,int,int,char *,float);
323 void ALDefineFont(int,char *,float,FILE *);
324 void echo(char *);
325 void ALGetFourInt(int *,int *,int *,int *);
326 void ALGetThreeInt(int *,int *,int *);
327 void ALGetTwoInt(int *,int *);
328 void ALFontChars(struct seqdat *,unsigned char **,
329                  int,int,int,int,char *,unsigned char);
330 void ALFontRegion(unsigned char **,int,int,int,int,unsigned char);
331 void PSSetFont(unsigned char,FILE *);
332 void ALDoLine(unsigned char **,int,int,int,int,int *);
333 void ALSubChars(struct seqdat *,int,int,int,int,char,char);
334 char ALChekSpace(const char *);
335 void PSSetGrey(float,FILE *);
336 void ALInverseChars(struct seqdat *,unsigned char **,int,int,int,int,char *);
337 int Agetbloc(FILE *,struct seqdat *,int *);
338 void ALDefineColour(int,char *coltype, float,float,float,FILE *);
339 void ALSColChars(struct seqdat *,unsigned char **,
340                  int,int,int,int,int,char *,unsigned char);
341 void ALColourChars(struct seqdat *,unsigned char **,
342                    int ,int,int,int,char *,unsigned char);
343 void ALColRes(unsigned char **,int ,int , int );
344 void PSSetColour(unsigned char,FILE *);
345 void ALColRegion(unsigned char **,int,int,int,int,int *,unsigned char);
346 void ALColRRegion(unsigned char **,int,int,int,int,unsigned char);
347 void ckdd(struct seqdat *, int);
348 int Ifound(struct seqdat *,int,int,char *,int);
349 void ALSColMask(unsigned char **,unsigned char **,
350                 int, int, int, int,int, unsigned char);
351 void ALInverseMask(unsigned char **,unsigned char **,int, int, int, int);
352 void ALFontMask(unsigned char **,unsigned char **,int, int, int, int,unsigned char);
353 void ALShadeMask(unsigned char **,signed char **,int,int,int,int,int *, float);
354 void ALGetAllRange(int *, int *, int *, int *,int ,int );
355 void ALid_mask(unsigned char **,struct seqdat *,int, int, int, int, int, char *, char *);
356 void ALfre_mask(unsigned char **mask,struct seqdat *,int, int, int, int, char *, char *);
357 int Ifound(struct seqdat *,int,int,char *,int);
358 void ALagree_mask(unsigned char **,struct seqdat *,int,int,int,int,int);
359 void ALnot_mask(unsigned char **,int, int, int, int);
360 void ALsub_mask(unsigned char **,struct seqdat *,int, int, int, int, char);
361 void ALMask(unsigned char **,int, int, int, int);
362 void ALConsMask(unsigned char **mask,
363 int sx,int sy,int ex,int ey,int *consval,int conscut);
364 void ALColourMask(unsigned char **,unsigned char **,int,int,int,int,unsigned char);
365 void ALSurroundMask(unsigned char **,struct seqdat *,unsigned char **,int,int,int,int,int);
366 int save_pir(struct seqdat *,int,FILE *);
367 void ALDrawHorizLine(
368                      float Xpos,       /* bottom left hand corner of character posn */
369                      float Ypos,       /* */
370                      float Xspace,     /* horizontal width of character position */
371                      float Yspace,     /* vertical height of character position */
372                      float width_fac,FILE *outf);  /* proportion of vertical height that the line will fill */
373 void ALDrawRightArrow(float Xpos,float Ypos, float Xspace, 
374                       float Yspace, float width_fac,FILE *outf);
375 void ALDrawLeftArrow(float Xpos,float Ypos, float Xspace, 
376                      float Yspace, float width_fac,FILE *outf);
377 void ALDrawUpArrow(float Xpos,float Ypos, float Xspace, 
378                    float Yspace, float width_fac,FILE *outf);
379 void ALDrawDownArrow(float Xpos,float Ypos, float Xspace, 
380                      float Yspace, float width_fac,FILE *outf);
381 void ALDrawCircle(float Xpos,float Ypos, float Xspace, 
382                   float Yspace, float width_fac,FILE *outf);
383 void ALDrawPseudoEllipse(float Xpos,float Ypos, float Xspace, 
384                          float Yspace, float width_fac,
385                          FILE *outf);
386 void ALDrawLeftSemiEnd(float Xpos,float Ypos, float Xspace, 
387                        float Yspace, float width_fac,FILE *outf);
388 void ALDrawRightSemiEnd(float Xpos,float Ypos, float Xspace, 
389                         float Yspace, float width_fac,FILE *outf);
390 void ALDrawRightHalfHorizLine(float Xpos,float Ypos,float Xspace,
391                               float Yspace,float width_fac,FILE *outf);
392 void ALDrawLeftHalfHorizLine(float Xpos,float Ypos,float Xspace,float 
393                              Yspace,float width_fac,FILE *outf);
394 void PSmoveto(float x,float y,FILE *outf);
395 void PSlineto(float x,float y,FILE *outf);
396 void PSPutSpecialText(float Xpos,float Ypos,float Xspace,
397                       float Yspace,char *text,unsigned char current_col,
398                       unsigned char background_colour,
399                       float YspaceFactor,FILE *outf);
400 void PSstroke(FILE *outf);
401 void PSnewpath(FILE *outf);
402 void ALColourBackground(FILE *outf,int colour,int *background_region);
403 void ALCheckLegalRange(int sx,int sy, int ex, int ey, int xmin, int ymin, int xmax, int ymax);
404 void ALMakeCoilText(int sx, int sy, int ex, char ***texts);
405 void ALMakeStrandText(int sx, int sy, int ex, char ***texts);
406 void ALMakeHelixText(int sx, int sy, int ex, char ***texts);
407 int ALrel(char *pos,int *relnum);
408 int GJindex(char *str,char c);
409 float mzcons(unsigned char *pos,int n);
410 int *ALCalCons(struct seqdat *bloc,
411                 int sx,int sy,int ex,int ey,int *ret_val,int len);
412 int save_msf(struct seqdat *bloc,int nseq,FILE *msff);
413
414 int alps(char *command_file,int silent, int pipe, int singlepage)
415 {  
416   FILE *cf,*inf,*outf,*pirf,*msff;
417   char *buff;
418   char *token;
419   char *charstring;
420   struct seqdat *bloc;
421   struct seqdat *temp;
422   int orientation;
423   extern int MAXtlen,MAXnbloc;
424   extern int MAXilen,precis,MAXslen;
425   int nseq;
426   int start_aa;
427   int start_seq;
428   int i,j,k;
429   int totalpage;
430   char **numbers;
431   char *ticks;
432   unsigned char **lines;
433 #ifdef VAX
434  char **fills;
435 #else
436   signed char **fills;
437 #endif
438   unsigned char **fonts;
439   unsigned char *idfonts;
440   unsigned char **inverse;
441   char ***texts;
442   int *Yindx;
443   int number_seqs = 0;
444
445   int Xtemp,Ytemp;
446   int sx,sy,ex,ey;
447
448   int fnum;
449   char *fname;
450   float fpoint;
451   int rowsiz;
452
453   char oldchar,newchar;
454   
455   struct seqdat *addbloc;
456   struct addseq *adds;
457   int nadds;
458   int natot;
459   int l;
460   int do_ticks = 0;
461   int number_int = 10;
462   int pirsave = 0;
463   int msfsave = 0;
464
465   int nbp,nspage;  /*counter and total for number of blocks per page */
466   int lastY;
467   int nbpage;
468
469   /* bounding_box - allows explicit fiddling with the bounding_box */
470   int *bounding_box;
471
472   /* colours */
473   float red,green,blue;
474   unsigned char **s_colour;       /*colour number for shading */
475   unsigned char **c_colour;       /*colour number for characters */
476   /* new 4th Oct 1994 */
477   unsigned char *id_colour;          /*colour for identifiers */
478   unsigned char **left_line_colour;  /*colours for lines */ 
479   unsigned char **right_line_colour;   
480   unsigned char **top_line_colour;   
481   unsigned char **bottom_line_colour;   
482   unsigned char **text_colour;       /*colour for text */
483   char *colname;
484
485   int background_colour = 99;        /*set background to white */
486   int *background_region;            /* use this to set the region for background colouring */
487
488   int number_colour = 100;           /* colour for numbers along top of plot */
489   /* end new */
490   char *tstring;
491
492   int use_colour;                 /* flag set if the define_colour command is seen */
493   int res_numbers;
494
495   int msl;
496
497   /* min and max ranges in the sequence alignment */
498   int xmin, ymin, xmax, ymax;
499
500   /* masking variables */
501   unsigned char **mask;
502   char *illegal;
503   char *legal;
504   int id_cut;
505
506   /* screen size variable - for printer screen */
507   int screensize = SCREENSIZE;
508
509   /* set up relative numbering - allows commands to follow
510      a specific sequence numbering 
511      firstres defines the number of the first residue */
512   int relative_seq = 0;
513   int firstres = 0;
514   int i1;
515   int *relnum;
516   /* temp relnum */
517   int *trelnum;
518
519   /* flag for idents */
520   int id_only_on_first = 0;
521   int tempCseqwidth;
522   int tempCidwidth;
523
524   /* conservation values */
525   int *consval;     /* array */
526   int conscut;      /* cutoff */
527
528   /* counter for add_seq errors */
529   int adderr;
530     
531   /* file streams */
532   extern FILE *std_in, *std_out, *std_err;
533
534   /* By default read and write to stdin and stdout */
535   outf = std_out;
536   inf = std_in;
537
538
539   /* default is no colour */
540   use_colour = 0;
541
542   /* if set, residue numbers are output */
543   res_numbers = 1;
544
545
546
547   /* set the bounding box to default values for portrait A4*/
548   bounding_box = (int *) GJmalloc(sizeof(int) * 4);
549   bounding_box[0] = 0;
550   bounding_box[1] = 0;
551   bounding_box[2] = 590;
552   bounding_box[3] = 826;
553
554   /* set the background colour region equal to the default bounding box */
555   background_region = (int *) GJmalloc(sizeof(int) * 4);
556   background_region[0] = 0;
557   background_region[1] = 0;
558   background_region[2] = 590;
559   background_region[3] = 826;
560
561   /* initialise the mask */
562   mask = NULL;
563   illegal = NULL;
564   legal = NULL;
565
566   adds = (struct addseq *) malloc(sizeof(struct addseq) * (MAX_ADD_SEQ+1));
567   nadds = 0;
568   
569
570   fname = (char *) malloc(sizeof(char)*MAXtlen);
571
572   buff = (char *) malloc(MAXtlen * sizeof(char));
573   if(buff == NULL)error("No Space for buff",1);
574
575   if((cf = fopen(command_file,"r")) == NULL){
576         error("Cannot open ALSCRIPT command file",0);
577         return 0;
578   }
579   
580   /* 
581     This is a little inelegant at the moment - when I get the generalized 
582     parser finished this could be cleaned up substantially
583   */
584
585   /* main loop to read commands */
586   if(pipe){
587     /* Alscript is being used as a pipe so write preamble to std_out */
588     outf = std_out;
589     PSPreamble(outf,singlepage,bounding_box,screensize);
590   }
591     
592   if(!silent)fprintf(std_err,"Starting ALSCRIPT\n");
593
594   while(buff = fgets(buff,MAXtlen,cf)){
595     if(!silent)echo(buff);
596     if(buff == NULL) continue;
597     token = strtok(buff,TOKENS);
598     if(token == NULL) continue;
599     token = GJstoup(token);    
600     if(*token == '#'){
601       if(!silent)echo("Comment\n");
602     }else if(strcmp(token,"SILENT_MODE")==0){
603         if(!silent){
604           silent=1;
605         }else{
606           silent=0;
607         }
608     }else if(strcmp(token,"MAX_INPUT_LEN")==0){
609       if(!silent) fprintf(std_err,"Max input len was:\t%d\n",MAXtlen);
610       token = strtok(NULL,TOKENS);
611       MAXtlen = atoi(token);
612       if(!silent)fprintf(std_err,"Max input len now:\t%d\n",MAXtlen);
613     }else if(strcmp(token,"MAX_NSEQ")==0){
614       if(!silent)fprintf(std_err,"Max No. of sequences was:\t%d\n",MAXnbloc);
615       token = strtok(NULL,TOKENS);
616       MAXnbloc = atoi(token);
617       MAXtlen = MAXnbloc;
618       fprintf(std_err,"Max No. of sequences now:\t%d\n",MAXnbloc);
619     }else if(strcmp(token,"MAX_ILEN")==0){
620       if(!silent)fprintf(std_err,"Max Identifier length was:\t%d\n",MAXilen);
621       token = strtok(NULL,TOKENS);
622       MAXilen = atoi(token);
623       if(!silent)fprintf(std_err,"Max Identifier length now:\t%d\n",MAXilen);
624     }else if(strcmp(token,"PRECISION")==0){
625       token = strtok(NULL,TOKENS);
626       precis = atoi(token);
627     }else if(strcmp(token,"MAX_SEQ_LEN")==0){
628       if(!silent)fprintf(std_err,"Max Sequence Length was:\t%d\n",MAXslen);
629       token = strtok(NULL,TOKENS);
630       MAXslen = atoi(token);
631       if(!silent)fprintf(std_err,"Max Sequence Length now:\t%d\n",MAXslen);
632     }else if(strcmp(token,"X_OFFSET")==0){
633       if(!silent)fprintf(std_err,"X offset was:\t%d\n",xoff);
634       token = strtok(NULL,TOKENS);
635       xoff = atoi(token);
636       if(!silent)fprintf(std_err,"X offset now:\t%d\n",xoff);
637     }else if(strcmp(token,"Y_OFFSET")==0){
638       if(!silent)fprintf(std_err,"Y offset was:\t%d\n",yoff);
639       token = strtok(NULL,TOKENS);
640       yoff = atoi(token);
641       if(!silent)fprintf(std_err,"Y offset now:\t%d\n",yoff);
642     }else if(strcmp(token,"MAX_SIDE")==0){
643       if(!silent)fprintf(std_err,"Longest page side was:\t%.2f inches\n",MAXside/POINT);
644       token = strtok(NULL,TOKENS);
645       MAXside = POINT * atof(token);
646       if(!silent)fprintf(std_err,"Longest page side now:\t%.2f inches\n",MAXside/POINT);
647     }else if(strcmp(token,"MIN_SIDE")==0){
648       if(!silent)fprintf(std_err,"Shortest page side was:\t%.2f inches\n",MINside/POINT);
649       token = strtok(NULL,TOKENS);
650       MINside = POINT * atof(token);
651       if(!silent)fprintf(std_err,"Shortest page side now:\t%.2f inches\n",MINside/POINT);
652     }else if(strcmp(token,"LINE_WIDTH_FACTOR")==0){
653       if(!silent)fprintf(std_err,"Line width multiplication factor was:\t%f\n",LineWidthFactor);
654       token = strtok(NULL,TOKENS);
655       LineWidthFactor = atof(token);
656       if(!silent)fprintf(std_err,"Line width multiplication factor now:\t%f\n",LineWidthFactor);
657     }else if(strcmp(token,"SCREENSIZE")==0){
658       if(!silent)fprintf(std_err,"Screensize was:\t%d\n",screensize);
659       token = strtok(NULL,TOKENS);
660       screensize = atoi(token);
661       if(!silent)fprintf(std_err,"Screensize now:\t%d\n",screensize);
662     }else if(strcmp(token,"BLOCK_FILE") == 0){
663       token = strtok(NULL,TOKENS);
664       if(!pipe){
665         inf = fopen(token,"r");
666         if(inf == NULL)error("Cannot open BLOCK_FILE\n",1);
667       }
668     }else if(strcmp(token,"OUTPUT_FILE")==0){
669       token = strtok(NULL,TOKENS);
670       if(!pipe){
671         outf = fopen(token,"w");
672         if(outf == NULL)error("Cannot open OUTPUT_FILE\n",1);
673         PSPreamble(outf,singlepage,bounding_box,screensize);
674       }
675     }else if(strcmp(token,"PIR_SAVE")==0){
676       token = strtok(NULL,TOKENS);
677       pirf = fopen(token,"w");
678       if(pirf == NULL)error("Cannot open PIR_SAVE file\n",1);
679       pirsave = 1;
680     }else if(strcmp(token,"MSF_SAVE")==0){
681       token = strtok(NULL,TOKENS);
682       msff = fopen(token,"w");
683       if(msff == NULL)error("Cannot open MSF_SAVE file\n",1);
684       msfsave = 1;
685     }else if(strcmp(token,"LANDSCAPE")==0){
686       orientation = LANDSCAPE;
687     }else if(strcmp(token,"PORTRAIT")==0){
688       orientation = PORTRAIT;
689
690     }else if(strcmp(token,"POINTSIZE")==0){
691       token = strtok(NULL,TOKENS);
692       pointsize = atof(token);
693     }else if(strcmp(token,"IDENT_WIDTH")==0){
694       token = strtok(NULL,TOKENS);
695       Cidwidth = atoi(token);
696       if(Cidwidth > MAXilen)error("INCREASE MAX_ID_LEN value",1);
697     }else if(strcmp(token,"NUMBER_SEQS")==0){
698       number_seqs=1;
699     }else if(strcmp(token,"X_SPACE_FACTOR")==0){
700       if(!silent)fprintf(std_err,"Was:\t%.2f\n",XspaceFactor);
701       token = strtok(NULL,TOKENS);
702       XspaceFactor = atof(token);
703       if(!silent)fprintf(std_err,"Now Is:\t%.2f\n",XspaceFactor);
704     }else if(strcmp(token,"Y_SPACE_FACTOR")==0){
705       if(!silent)fprintf(std_err,"Was:\t%.2f\n",YspaceFactor);
706       token = strtok(NULL,TOKENS);
707       YspaceFactor = atof(token);
708     }else if(strcmp(token,"X_SHIFT_FACTOR")==0){
709       if(!silent)fprintf(std_err,"Was:\t%.2f\n",XshiftFactor);
710       token = strtok(NULL,TOKENS);
711       XshiftFactor = atof(token);
712       if(!silent)fprintf(std_err,"Now Is:\t%.2f\n",XshiftFactor);
713     }else if(strcmp(token,"Y_SHIFT_FACTOR")==0){
714       if(!silent)fprintf(std_err,"Was:\t%.2f\n",YshiftFactor);
715       token = strtok(NULL,TOKENS);
716       YshiftFactor = atof(token);
717       if(!silent)fprintf(std_err,"Now Is:\t%.2f\n",YshiftFactor);
718     }else if(strcmp(token,"VERTICAL_SPACING")==0){
719       if(!silent)fprintf(std_err,"Was:\t%d\n",Vspacing);
720       token = strtok(NULL,TOKENS);
721       Vspacing = (int) atol(token);
722       if(!silent)fprintf(std_err,"Now Is:\t%d\n",Vspacing);
723     }else if(strcmp(token,"DEFINE_FONT")==0){
724       token = strtok(NULL,TOKENS);
725       fnum = atoi(token);                      /* font number */
726       token = strtok(NULL,TOKENS);           /* font name */
727       fname = strcpy(fname,token);
728       token = strtok(NULL,TOKENS);
729       if(strcmp(token,"DEFAULT")==0){
730         fpoint = pointsize;
731       }else if(strcmp(token,"REL")==0){
732         token = strtok(NULL,TOKENS);
733         fpoint = pointsize * atof(token);
734       }else{
735         fpoint = atof(token);
736       }
737       ALDefineFont(fnum,fname,fpoint,outf);
738     }else if(strcmp(token,"DEFINE_COLOUR")==0 || strcmp(token,"DEFINE_COLOR")==0){
739         /* new style 
740            define_colour <colour_number | colour type> colour_name r g b <colour_number> */
741         /* e.g. define_colour 1 1.0 1.0 1.0
742                 (same as before)
743                 define_colour rgb red 1.0 0.0 0.0 7
744                 (define an rgb colour (red,green,blue),colour_number)
745                 define_colour hsb red 1.0 0.0 0.0 9
746                 (define an hsb colour (hue,sat,bright),colour_number)
747            currently can use either hsb OR rgb, but not mix them
748          */
749       use_colour = 1;
750       token = strtok(NULL,TOKENS);
751       tstring = GJstoupper(token);
752       if(strcmp(tstring,"RGB")==0 || strcmp(tstring,"HSB")==0){
753           token = strtok(NULL,TOKENS);
754           colname = GJstrdup(token);
755           token = strtok(NULL,TOKENS);
756           red = atof(token);
757           token = strtok(NULL,TOKENS);
758           green = atof(token);
759           token = strtok(NULL,TOKENS);
760           blue = atof(token);
761           token = strtok(NULL,TOKENS);
762           fnum = atoi(token);
763       }else{
764           fnum = atoi(token);                      /* colour number */
765           token = strtok(NULL,TOKENS);
766           red = atof(token);
767           token = strtok(NULL,TOKENS);
768           green = atof(token);
769           token = strtok(NULL,TOKENS);
770           blue = atof(token);
771
772       }
773       /* for now just ignore the colour name - we'll allow use of this later */
774       ALDefineColour(fnum,tstring,red,green,blue,outf);
775       GJfree(tstring);
776     }else if(strcmp(token,"ADD_SEQ")==0){
777       token = strtok(NULL,TOKENS);
778       adds[nadds].pos = atoi(token);
779       token = strtok(NULL,TOKENS);
780       adds[nadds].num = atoi(token);
781       ++nadds;
782     }else if(strcmp(token,"DO_TICKS")==0){
783       do_ticks=1;
784     }else if(strcmp(token,"NUMBER_INT")==0){
785       token = strtok(NULL,TOKENS);
786       number_int = atoi(token);
787       if(!silent)fprintf(std_err,"Sequence Numbering interval now:\t%d\n",number_int);
788     }else if(strcmp(token,"NO_NUMBERS")==0){
789       res_numbers = 0;
790     }else if(strcmp(token,"NUMBER_COLOUR")==0){
791         token = strtok(NULL,TOKENS);
792         number_colour = atoi(token);
793     }else if(strcmp(token,"SINGLE_PAGE")==0){
794       /* if this is set, then alscript assumes a single page - 
795          just adds a bounding box for now*/
796       if(!silent)fprintf(std_err,"Single page was: %d\n",singlepage);
797       singlepage = 1;
798       if(!silent)fprintf(std_err,"Single page now: %d\n",singlepage);
799     }else if(strcmp(token,"BOUNDING_BOX")==0){
800       ALGetFourInt(&bounding_box[0],&bounding_box[1],
801                    &bounding_box[2],&bounding_box[3]);
802       if(!silent){
803         fprintf(std_err,"Bounding box set to: %d %d %d %d\n",
804                 bounding_box[0],bounding_box[1],
805                 bounding_box[2],bounding_box[3]);
806       }
807     }else if(strcmp(token,"BACKGROUND_REGION") == 0){
808         /* set the region of the background to colour */
809         ALGetFourInt(&background_region[0],&background_region[1],
810                      &background_region[2],&background_region[3]);
811       if(!silent){
812         fprintf(std_err,"Background region set to: %d %d %d %d\n",
813                 background_region[0],background_region[1],
814                 background_region[2],background_region[3]);
815       }
816     }else if(strcmp(token,"ID_ONLY_ON_FIRST_LINE")==0){
817         /* flag to indicate identifiers only on first line!*/
818         id_only_on_first = 1;
819     }else if(strcmp(token,"BACKGROUND_COLOUR") ==0){
820         /* set the colour for background defined by background_region */
821         token = strtok(NULL,TOKENS);
822         background_colour = atoi(token);
823     }else if(strcmp(token,"SETUP")==0){
824       if(!silent)fprintf(std_err,"Initial Commands read - Establishing basic settings\n");
825       break;
826     }else{
827       fprintf(std_err,"%s",buff);
828       error("Unrecognised Step 1 command",1);
829
830     }
831   }
832
833   if(outf == std_out){
834     if(!silent)fprintf(std_err,"Output file undefined - will write to stdout\n");
835   }
836
837   
838   if(inf == std_in){
839     if(!silent)fprintf(std_err,"Block file undefined - will read from stdin\n");
840   }
841   
842   bloc = (struct seqdat *) malloc(sizeof(struct seqdat) * MAXnbloc);
843   mcheck((char *) bloc,"Cannot get space for bloc");
844   if(!Agetbloc(inf,bloc,&nseq))error("Cannot read bloc file",1);
845
846   ckdd(bloc,nseq);
847
848   if(pirsave){
849     if(!save_pir(bloc,nseq,pirf))error("Cannot write to pirf file",1);
850     exit(0);
851   }
852
853   if(msfsave){
854     if(!save_msf(bloc,nseq,msff))error("Cannot write to msf file",1);
855     exit(0);
856   }
857
858   /* Initialise relnum to 1..n*/
859   /*  relnum = (int *) GJmalloc(sizeof(int) * MAXslen); */
860   /*  for(i=1;i<MAXslen;++i){ */
861   /*      relnum[i]=i;     */
862   /*  }  */
863
864   /* Initialise relnum to 1..n*/
865   /* 29 July 1998 - allocate relnum to MAXslen *2.  with pointer in the middle */
866
867   trelnum = (int *) GJmalloc(sizeof(int) * MAXslen * 2);
868   for(i=1;i<(MAXslen +1);++i){
869       trelnum[i]=0;
870   }
871   relnum = &trelnum[MAXslen];
872   for(i=1;i<MAXslen;++i){
873     relnum[i] = i;
874   }
875
876   /* do a check of the adds array to make sure there are no out of bounds
877      requests
878      */
879   adderr = 0;
880   for(i=0;i<nadds;++i){
881     if(adds[i].pos > nseq){
882       ++adderr;
883       fprintf(std_err,"Error in ADD_SEQ request: %d %d\n",adds[i].pos,adds[i].num);
884       fprintf(std_err,"%d is greater than the number of sequences in the block file(%d)\n",adds[i].pos,nseq);
885       fprintf(std_err,"Please see the manual for help on using ADD_SEQ\n");
886     }
887   }
888   if(adderr > 0){
889     fprintf(std_err,"%d ADD_SEQ errors - exiting\n",adderr);
890     exit(-1);
891   }
892
893
894   if(nadds > 0){
895      if(!silent)fprintf(std_err,"Making extra space for %d additions\n",nadds);
896      natot = 0;
897      for(i=0;i<nadds;++i){
898         natot += adds[i].num;
899      }
900      if(!silent)fprintf(std_err,"Total of %d extra sequences\n",natot);
901      addbloc = (struct seqdat *) malloc(sizeof(struct seqdat) *(nseq+natot+1));
902      i = 0;
903      j = 0;
904      k = 0;
905      while(i < nseq+1){
906         if(k < nadds && i==adds[k].pos){
907           /* reserve space for the new sequences and set to blank*/
908           for(l=0;l<adds[k].num;++l){
909              ++j;
910              addbloc[j].id = (char *) malloc(sizeof(char) * MAXilen);
911              addbloc[j].id = GJstrblank(addbloc[j].id,MAXilen);
912              addbloc[j].seq = (char *) malloc(sizeof(char) * (bloc[1].slen+1));
913              addbloc[j].seq = GJstrblank(addbloc[j].seq,bloc[1].slen+1);
914           }
915           ++k;
916         }else{
917           /* just copy the pointers to the bloc sequences */
918           ++i;
919           ++j;
920           if(i<nseq+1){
921             addbloc[j].id = bloc[i].id;
922             addbloc[j].title = bloc[i].title;
923             addbloc[j].seq = bloc[i].seq;
924           }
925         }
926      }
927      addbloc[1].slen = bloc[1].slen;
928      temp = bloc;
929      bloc = addbloc;
930      addbloc = temp;
931      nseq += natot;
932      if(!silent)fprintf(std_err,"Total number of sequences now: %d\n",nseq);
933   }
934   msl = bloc[1].slen-2;  /* maximum sequence length defined */
935
936   xmin = 1;  ymin = 1; xmax = msl+1; ymax = nseq;
937
938   PSSetupPage(orientation,1,outf);
939   ALSetPageLimits();  
940
941   CtopSpace = 2;    /* set top 2 lines for numbers */
942
943   /* now set up the bounding box and background 
944      based on current values of xoff, yoff, width and height 
945      these can be overridden by step 2 commands
946
947   bounding_box[0] = 0;
948   bounding_box[1] = 0;
949   bounding_box[2] = width;
950   bounding_box[3] = height;
951   */
952
953   /* set the background colour region equal to the default bounding box
954   background_region[0] = bounding_box[0];
955   background_region[1] = bounding_box[1];
956   background_region[2] = bounding_box[2];
957   background_region[3] = bounding_box[3];
958   */
959
960   if(background_colour != 99)ALColourBackground(outf,background_colour,background_region);
961
962   
963
964 /*  TVspace = nseq;*/
965 /*  ALReserveSpace(TOP,2);*/
966
967   
968   /* allocate to +1 size to allow indexing from 1...max */
969   /* lines array - stored info on where to draw lines */
970   lines = uchararr(bloc[1].slen+1,nseq+1);
971   if(lines == NULL)error("No space for lines array\n",1);
972   GJUCinit(lines,bloc[1].slen+1,nseq+1,0);
973
974   /* array holds grey value for each character fill*/
975   fills = chararr(bloc[1].slen+1,nseq+1);
976   if(fills == NULL)error("No space for fills array\n",1);
977   GJCinit(fills,bloc[1].slen+1,nseq+1,-1);
978
979   /* allocate to +1 size to allow indexing from 1...max */
980   /* fonts array - stores a number representing the font to use for each residue */
981   /* default font is font 0 */
982   fonts = uchararr(bloc[1].slen+1,nseq+1);
983   if(fonts == NULL)error("No space for fonts array\n",1);
984   GJUCinit(fonts,bloc[1].slen+1,nseq+1,0);
985
986   /* inverse indicates whether the the text at i j should be printed in white */
987   inverse = uchararr(bloc[1].slen+1,nseq+1);
988   if(inverse == NULL)error("No space for inverse array\n",1);
989   GJUCinit(inverse,bloc[1].slen+1,nseq+1,0);
990
991   /* colour arrays - define the colour to use for shading and lettering */
992   /* default colour numbers are 99 for white and 100 for black */
993   s_colour = uchararr(bloc[1].slen+1,nseq+1);       /* shading colour */
994   if(s_colour == NULL)error("No space for s_colour array\n",1);
995   GJUCinit(s_colour,bloc[1].slen+1,nseq+1,background_colour);
996   c_colour = uchararr(bloc[1].slen+1,nseq+1);       /* character colour */
997   if(c_colour == NULL)error("No space for c_colour array\n",1);
998   GJUCinit(c_colour,bloc[1].slen+1,nseq+1,100);
999   left_line_colour = uchararr(bloc[1].slen+1,nseq+1);       /* left line colour */
1000   if(left_line_colour == NULL)error("No space for left_line_colour array\n",1);
1001   GJUCinit(left_line_colour,bloc[1].slen+1,nseq+1,100);
1002   right_line_colour = uchararr(bloc[1].slen+1,nseq+1);       /* right line colour */
1003   if(right_line_colour == NULL)error("No space for right_line_colour array\n",1);
1004   GJUCinit(right_line_colour,bloc[1].slen+1,nseq+1,100);
1005   top_line_colour = uchararr(bloc[1].slen+1,nseq+1);       /* top line colour */
1006   if(top_line_colour == NULL)error("No space for top_line_colour array\n",1);
1007   GJUCinit(top_line_colour,bloc[1].slen+1,nseq+1,100);
1008   bottom_line_colour = uchararr(bloc[1].slen+1,nseq+1);       /* bottom line colour */
1009   if(bottom_line_colour == NULL)error("No space for bottom_line_colour array\n",1);
1010   GJUCinit(bottom_line_colour,bloc[1].slen+1,nseq+1,100);
1011   text_colour = uchararr(bloc[1].slen+1,nseq+1);       /* text colour */
1012   if(text_colour == NULL)error("No space for text_colour array\n",1);
1013   GJUCinit(text_colour,bloc[1].slen+1,nseq+1,100);
1014
1015   /* holds font information for each identifier */
1016   idfonts = (unsigned char *) malloc(sizeof(unsigned char) * nseq+1);
1017   for(i=0;i<nseq+1;++i){
1018     idfonts[i]= (unsigned char) 0;
1019   }
1020   /* holds colour information for each identifier */
1021   id_colour = (unsigned char *) GJmalloc(sizeof(unsigned char) * nseq+1);
1022   for(i=0;i<nseq+1;++i){
1023     id_colour[i]= (unsigned char) 100;
1024   }
1025   /* holds conservation values */
1026   consval = (int *) GJmalloc(sizeof(int) * bloc[1].slen);
1027   GJIinit(consval,bloc[1].slen,0);
1028
1029
1030   /* array holds pointers to text strings at each [i][j] point*/
1031   texts = (char ***) malloc(sizeof(char **) * (bloc[1].slen+1));
1032   rowsiz = sizeof(char *) * (nseq + 1);
1033   for(k=0;k<bloc[1].slen+1;++k){
1034     texts[k] = (char **) malloc(rowsiz);
1035     for(i=0;i<(nseq+1);++i){
1036       texts[k][i]=NULL;
1037     }
1038   }
1039   
1040   Yindx = (int *) malloc(sizeof(int)*(nseq+1));
1041   for(i=1,j=nseq;i<nseq+1;++i,--j){
1042     Yindx[i] = j;
1043   }
1044
1045   numbers = ALCreateNumbers(0,number_int,bloc[1].slen,4);
1046   ticks = ALCreateTicks(0,number_int,bloc[1].slen);
1047   CseqTop = nseq;
1048
1049   while(buff = fgets(buff,MAXtlen,cf)){
1050     if(buff == NULL) break;
1051     if(!silent)echo(buff);
1052     token = strtok(buff,TOKENS);
1053     if(token == NULL) break;
1054     token = GJstoup(token);
1055     if(*token == '#'){
1056       if(!silent)echo("Comment\n");
1057     }else if(strcmp(token,"SILENT_MODE")==0){
1058         if(!silent){
1059           silent=1;
1060         }else{
1061           silent=0;
1062         }
1063 /* This block has moved to the MODE 1 section
1064     }else if(strcmp(token,"BOUNDING_BOX")==0){
1065       ALGetFourInt(&bounding_box[0],&bounding_box[1],
1066                    &bounding_box[2],&bounding_box[3]);
1067
1068     }else if(strcmp(token,"BACKGROUND_REGION") == 0){
1069         set the region of the background to colour 
1070         ALGetFourInt(&background_region[0],&background_region[1],
1071                      &background_region[2],&background_region[3]);
1072 */
1073     }else if(strcmp(token,"RESERVE_SPACE_TOP")==0){
1074       token = strtok(NULL,TOKENS);
1075       ALReserveSpace(TOP,atoi(token));
1076     }else if(strcmp(token,"RESERVE_SPACE_BOTTOM")==0){
1077       token = strtok(NULL,TOKENS);
1078       ALReserveSpace(BOTTOM,atoi(token));
1079       CseqTop = nseq + CbottomSpace;
1080     }else if(strcmp(token,"SURROUND_CHARS")==0){
1081       token = strtok(NULL,TOKENS);
1082       charstring = token;
1083       ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1084       ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1085       ALSurroundChars(bloc,lines,relnum[sx],sy,relnum[ex],ey,nseq,charstring);
1086     }else if(strcmp(token,"SHADE_CHARS")==0){
1087       token = strtok(NULL,TOKENS);
1088       charstring = token;
1089       ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1090       ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1091       token = strtok(NULL,TOKENS);
1092       ALShadeChars(bloc,fills,relnum[sx],sy,relnum[ex],ey,nseq,charstring,(float)atof(token));
1093     }else if(strcmp(token,"FONT_CHARS")==0){
1094       token = strtok(NULL,TOKENS);
1095       charstring = token;
1096       ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1097       ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1098       token = strtok(NULL,TOKENS);
1099       ALFontChars(bloc,fonts,relnum[sx],sy,relnum[ex],ey,charstring,atoi(token));
1100     }else if(strcmp(token,"CCOL_CHARS")==0){  /* colour characters */
1101       if(!use_colour)error("You must use the DEFINE_COLOUR command first",1);
1102       token = strtok(NULL,TOKENS);
1103       charstring = token;
1104       ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1105       ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1106       token = strtok(NULL,TOKENS);
1107       ALColourChars(bloc,c_colour,relnum[sx],sy,relnum[ex],ey,charstring,atoi(token));
1108     }else if(strcmp(token,"SCOL_CHARS")==0){  /* colour character backgrounds */
1109       if(!use_colour)error("You must use the DEFINE_COLOUR command first",1);
1110       token = strtok(NULL,TOKENS);
1111       charstring = token;
1112       ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1113       ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1114       token = strtok(NULL,TOKENS);
1115       ALSColChars(bloc,s_colour,relnum[sx],sy,relnum[ex],ey,nseq,charstring,(unsigned char) atoi(token));
1116     }else if(strcmp(token,"INVERSE_CHARS")==0){
1117       token = strtok(NULL,TOKENS);
1118       charstring = token;
1119       ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1120       ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1121       ALInverseChars(bloc,inverse,relnum[sx],sy,relnum[ex],ey,charstring);
1122     }else if(strcmp(token,"SUB_CHARS")==0){
1123         token = strtok(NULL,TOKENS);
1124         if(strcmp(token,"ALL")==0){
1125           token = strtok(NULL,TOKENS);
1126           oldchar = ALChekSpace(token);
1127           token = strtok(NULL,TOKENS);
1128           newchar = ALChekSpace(token); 
1129           ALSubChars(bloc,1,1,bloc[1].slen-1,nseq,oldchar,newchar);
1130         }else{
1131           sx = atoi(token);
1132           ALGetThreeInt(&sy,&ex,&ey);
1133           token = strtok(NULL,TOKENS);
1134           oldchar = ALChekSpace(token);
1135           token = strtok(NULL,TOKENS);
1136           newchar = ALChekSpace(token);
1137           ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1138           ALSubChars(bloc,relnum[sx],sy,relnum[ex],ey,oldchar,newchar);
1139         }
1140     }else if(strcmp(token,"SUB_ID")==0){
1141         token = strtok(NULL,"\"");
1142         sx = atoi(token);
1143         token = strtok(NULL,"\"");
1144         ALCheckLegalRange(xmin,1,xmax,sx,xmin,ymin,xmax,ymax);
1145         bloc[sx].id = (char *) realloc(bloc[sx].id,sizeof(char)*(strlen(token)+1));
1146         bloc[sx].id = strcpy(bloc[sx].id,token);
1147     }else if(strcmp(token,"FONT_REGION")==0){
1148       ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1149       token = strtok(NULL,TOKENS);
1150       ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1151       ALFontRegion(fonts,relnum[sx],sy,relnum[ex],ey,atoi(token));
1152     }else if(strcmp(token,"FONT_RESIDUE")==0){
1153       token = strtok(NULL,TOKENS);
1154       sx = atoi(token);
1155       token=strtok(NULL,TOKENS);
1156       sy = atoi(token);
1157       token=strtok(NULL,TOKENS);
1158       ALCheckLegalRange(relnum[sx],sy,relnum[sx],sy,xmin,ymin,xmax,ymax);
1159       ALFontRegion(fonts,relnum[sx],sy,relnum[sx],sy,atoi(token));
1160     }else if(strcmp(token,"LINE")==0){
1161       token = strtok(NULL,TOKENS);
1162       if(strcmp(token,"TOP")==0){
1163         ALGetThreeInt(&sx,&sy,&ex);
1164         if(ex > bloc[1].slen-1) ex = bloc[1].slen-1;
1165         ALCheckLegalRange(relnum[sx],sy,relnum[ex],sy,xmin,ymin,xmax,ymax);
1166         ALDoLine(lines,relnum[sx],sy,relnum[ex],LINE_TOP,Yindx);
1167       }else if(strcmp(token,"BOTTOM")==0){
1168         ALGetThreeInt(&sx,&sy,&ex);     
1169         ALCheckLegalRange(relnum[sx],sy,relnum[ex],sy,xmin,ymin,xmax,ymax);
1170         if(ex > bloc[1].slen-1) ex = bloc[1].slen-1;
1171         ALDoLine(lines,relnum[sx],sy,relnum[ex],LINE_BOTTOM,Yindx);
1172       }else if(strcmp(token,"LEFT")==0){
1173         ALGetThreeInt(&sx,&sy,&ey);     
1174         ALCheckLegalRange(relnum[sx],sy,relnum[sx],ey,xmin,ymin,xmax,ymax);
1175         if(ey > nseq) ey = nseq;
1176         ALDoLine(lines,relnum[sx],sy,ey,LINE_LEFT,Yindx);
1177       }else if(strcmp(token,"RIGHT")==0){
1178         ALGetThreeInt(&sx,&sy,&ey);     
1179         ALCheckLegalRange(relnum[sx],sy,relnum[sx],ey,xmin,ymin,xmax,ymax);
1180         if(ey > nseq) ey = nseq;
1181         ALDoLine(lines,relnum[sx],sy,ey,LINE_RIGHT,Yindx);
1182       }else{
1183         error("Illegal LINE command\n",1);
1184       }
1185     }else if(strcmp(token,"BOX_REGION")==0){
1186       ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1187       ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1188       ALBoxRegion(lines,relnum[sx],sy,relnum[ex],ey,Yindx);
1189     }else if(strcmp(token,"SHADE_REGION")==0){
1190       ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1191       ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1192       token = strtok(NULL,TOKENS);
1193       ALFilRegion(fills,relnum[sx],sy,relnum[ex],ey,Yindx,(float)atof(token));
1194     }else if(strcmp(token,"SHADE_RES")==0){
1195       ALGetTwoInt(&sx,&sy);
1196       ALCheckLegalRange(relnum[sx],sy,relnum[sx],sy,xmin,ymin,xmax,ymax);
1197       token = strtok(NULL,TOKENS);
1198       ALFilRegion(fills,relnum[sx],sy,relnum[sx],sy,Yindx,(float)atof(token));
1199     }else if(strcmp(token,"COLOUR_REGION")==0 || strcmp(token,"COLOR_REGION")==0){
1200       if(!use_colour)error("You must use the DEFINE_COLOUR command first",1);
1201       ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1202       ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1203       token = strtok(NULL,TOKENS);
1204       ALColRegion(s_colour,relnum[sx],sy,relnum[ex],ey,Yindx,(unsigned char) atoi(token));
1205     }else if(strcmp(token,"COLOUR_TEXT_REGION")==0 || strcmp(token,"COLOR_TEXT_REGION")==0){
1206       if(!use_colour)error("You must use the DEFINE_COLOUR command first",1);
1207       ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1208       ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1209       token = strtok(NULL,TOKENS);
1210       ALColRRegion(text_colour,relnum[sx],sy,relnum[ex],ey,(unsigned char) atoi(token));
1211     }else if(strcmp(token,"COLOUR_RES")==0 || strcmp(token,"COLOR_RES")==0){
1212       if(!use_colour)error("You must use the DEFINE_COLOUR command first",1);
1213       ALGetTwoInt(&sx,&sy);
1214       ALCheckLegalRange(relnum[sx],sy,relnum[sx],sy,xmin,ymin,xmax,ymax);
1215       token = strtok(NULL,TOKENS);
1216       ALColRRegion(s_colour,relnum[sx],sy,relnum[sx],sy,(unsigned char) atoi(token));
1217     }else if(strcmp(token,"CCOLOUR_REGION")==0 || strcmp(token,"CCOLOR_REGION")==0){
1218       if(!use_colour)error("You must use the DEFINE_COLOUR command first",1);
1219       ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1220       ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1221       token = strtok(NULL,TOKENS);
1222       ALColRRegion(c_colour,relnum[sx],sy,relnum[ex],ey,(unsigned char) atoi(token));
1223     }else if(strcmp(token,"COLOUR_LINE_REGION")==0 || strcmp(token,"COLOR_LINE_REGION")==0){
1224       if(!use_colour)error("You must use the DEFINE_COLOUR command first",1);
1225       ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1226       ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1227       token = strtok(NULL,TOKENS);
1228       ALColRegion(left_line_colour,relnum[sx],sy,relnum[ex],ey,Yindx,(unsigned char) atoi(token));
1229       ALColRegion(right_line_colour,relnum[sx],sy,relnum[ex],ey,Yindx,(unsigned char) atoi(token));
1230       ALColRegion(top_line_colour,relnum[sx],sy,relnum[ex],ey,Yindx,(unsigned char) atoi(token));
1231       ALColRegion(bottom_line_colour,relnum[sx],sy,relnum[ex],ey,Yindx,(unsigned char) atoi(token));
1232     }else if(strcmp(token,"CCOLOUR_RES")==0 || strcmp(token,"CCOLOR_RES")==0){
1233       if(!use_colour)error("You must use the DEFINE_COLOUR command first",1);
1234       ALGetTwoInt(&sx,&sy);
1235       token = strtok(NULL,TOKENS);
1236       ALCheckLegalRange(relnum[sx],sy,relnum[sx],sy,xmin,ymin,xmax,ymax);
1237       ALColRRegion(c_colour,relnum[sx],sy,relnum[sx],sy,(unsigned char) atoi(token));
1238      }else if(strcmp(token,"MASK")==0){
1239         /* mask commands */
1240         token = strtok(NULL,TOKENS);
1241         if(strcmp(token,"SETUP")==0){
1242             if(mask == NULL){
1243                 mask = uchararr(bloc[1].slen+1,nseq+1);
1244                 GJUCinit(mask,bloc[1].slen+1,nseq+1,0);
1245             }else{
1246                 GJUCinit(mask,bloc[1].slen+1,nseq+1,0);
1247             }
1248         }else if(strcmp(token,"RESET")==0){
1249             GJUCinit(mask,bloc[1].slen+1,nseq+1,0);
1250         }else if(strcmp(token,"LEGAL")==0){
1251             /* get the legal character list */
1252             token = strtok(NULL,TOKENS);
1253             if(legal != NULL) GJfree(legal);
1254             legal = GJstrdup(token);
1255             if(!silent)fprintf(stderr,"legal:%s\n",legal);
1256         }else if(strcmp(token,"ILLEGAL")==0){
1257             /* get the illegal character list */
1258             token = strtok(NULL,TOKENS);
1259             if(illegal != NULL) GJfree(illegal);
1260             illegal = GJstrdup(token);
1261             if(!silent)fprintf(stderr,"illegal:%s:\n",illegal);
1262         }else if(strcmp(token,"ID")==0){
1263             ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1264             ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1265             token = strtok(NULL,TOKENS);
1266             id_cut = atoi(token);
1267             if(id_cut < (int) ( ( ((float) (ey-sy+1) / 2.0) + 0.6))){
1268                 error("ID cutoff must be > half the number of sequences",1);
1269             }
1270             ALid_mask(mask,bloc,relnum[sx],sy,relnum[ex],ey,id_cut,legal,illegal);
1271         }else if(strcmp(token,"AGREE")==0){
1272             ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1273             ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1274             token= strtok(NULL,TOKENS);
1275             ALagree_mask(mask,bloc,relnum[sx],sy,relnum[ex],ey,atoi(token));
1276         }else if(strcmp(token,"FRE")==0){
1277             ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1278             ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1279             ALfre_mask(mask,bloc,relnum[sx],sy,relnum[ex],ey,legal,illegal);
1280         }else if(strcmp(token,"NOT")==0){
1281             ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1282             ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1283             ALnot_mask(mask,relnum[sx],sy,relnum[ex],ey);
1284         }else if(strcmp(token,"SUB")==0){
1285             ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1286             ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1287             token=strtok(NULL,TOKENS);
1288             ALsub_mask(mask,bloc,relnum[sx],sy,relnum[ex],ey,token[0]);
1289         }else if(strcmp(token,"REGION")==0){
1290             ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1291             ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1292             ALMask(mask,relnum[sx],sy,relnum[ex],ey);
1293         }else if(strcmp(token,"CONSERVATION")==0){
1294             ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1295             ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1296             token=strtok(NULL,TOKENS);
1297             conscut = atoi(token);
1298             if(!silent)fprintf(std_err,"Conservation Cutoff:%d\n",conscut);
1299             ALConsMask(mask,relnum[sx],sy,relnum[ex],ey,consval,conscut);
1300         }else if(strcmp(token,"BOX")==0){
1301             /* box the masked residues - ie surround them*/
1302             ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1303             ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1304             ALSurroundMask(mask,bloc,lines,relnum[sx],sy,relnum[ex],ey,nseq);
1305         }else if(strcmp(token,"SHADE")==0){
1306             /* shade the masked residues - */
1307             ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1308             ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1309             token = strtok(NULL,TOKENS);
1310             ALShadeMask(mask,fills,relnum[sx],sy,relnum[ex],ey,Yindx,(float)atof(token));
1311         }else if(strcmp(token,"FONT")==0){
1312             /* set the font of the masked residues - */
1313             ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1314             ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1315             token = strtok(NULL,TOKENS);
1316             ALFontMask(mask,fonts,relnum[sx],sy,relnum[ex],ey,(unsigned char) atoi(token));
1317         }else if(strcmp(token,"INVERSE")==0){
1318             /* invert the masked residues - */
1319             ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1320             ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1321             token = strtok(NULL,TOKENS);
1322             ALInverseMask(mask,inverse,relnum[sx],sy,relnum[ex],ey);
1323         }else if(strcmp(token,"SCOL")==0){
1324             if(!use_colour)error("You must use the DEFINE_COLOUR command first",1);
1325             ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1326             ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1327             token = strtok(NULL,TOKENS);
1328             ALSColMask(mask,s_colour,relnum[sx],sy,relnum[ex],ey,nseq,(unsigned char) atoi(token));
1329         }else if(strcmp(token,"CCOL")==0){
1330             if(!use_colour)error("You must use the DEFINE_COLOUR command first",1);
1331             ALGetAllRange(&sx,&sy,&ex,&ey,xmax,nseq);
1332             ALCheckLegalRange(relnum[sx],sy,relnum[ex],ey,xmin,ymin,xmax,ymax);
1333             token = strtok(NULL,TOKENS);
1334             ALColourMask(mask,c_colour,relnum[sx],sy,relnum[ex],ey,(unsigned char) atoi(token));
1335         }else{
1336             error("Unrecognised MASK qualifier\n",1);
1337         }
1338     }else if(strcmp(token,"TEXT")==0){
1339       token=strtok(NULL,TOKENS);
1340       sx = atoi(token);
1341       token=strtok(NULL,"\"");
1342       sy = atoi(token);
1343       token=strtok(NULL,"\"");
1344       ALCheckLegalRange(relnum[sx],sy,relnum[sx],sy,xmin,ymin,xmax,ymax);
1345       texts[relnum[sx]][sy] = (char *) malloc(sizeof(char)*(strlen(token)+1));
1346       texts[relnum[sx]][sy] = (char *) strcpy(texts[relnum[sx]][sy],token);
1347     }else if(strcmp(token,"NUMBERS")==0){
1348         error("Numbers not implemented",1);
1349     }else if(strcmp(token,"ID_FONT")==0){
1350       token = strtok(NULL,TOKENS);
1351       if(strcmp(token,"ALL")==0){
1352         token = strtok(NULL,TOKENS);
1353         for(i=1;i<nseq+1;++i)idfonts[i]= (unsigned char) atoi(token);
1354       }else{
1355         sx = atoi(token);
1356         token = strtok(NULL,TOKENS);
1357         ALCheckLegalRange(xmin,ymin,xmax,sx,xmin,ymin,xmax,ymax);
1358         idfonts[sx] = atoi(token);
1359       }
1360     }else if(strcmp(token,"ID_COLOUR")==0){
1361       token = strtok(NULL,TOKENS);
1362       if(strcmp(token,"ALL")==0){
1363         token = strtok(NULL,TOKENS);
1364         for(i=1;i<nseq+1;++i)id_colour[i]= (unsigned char) atoi(token);
1365       }else{
1366         sx = atoi(token);
1367         ALCheckLegalRange(xmin,ymin,xmax,sx,xmin,ymin,xmax,ymax);
1368         token = strtok(NULL,TOKENS);
1369         id_colour[sx] = atoi(token);
1370       }
1371     }else if(strcmp(token,"HELIX")==0){
1372         ALGetThreeInt(&sx,&sy,&ex);
1373         ALCheckLegalRange(relnum[sx],sy,relnum[ex],sy,xmin,ymin,xmax,ymax);
1374         ALMakeHelixText(relnum[sx],sy,relnum[ex],texts);
1375     }else if(strcmp(token,"STRAND")==0){
1376         ALGetThreeInt(&sx,&sy,&ex);
1377         ALCheckLegalRange(relnum[sx],sy,relnum[ex],sy,xmin,ymin,xmax,ymax);
1378         ALMakeStrandText(relnum[sx],sy,relnum[ex],texts);
1379     }else if(strcmp(token,"COIL")==0){
1380         ALGetThreeInt(&sx,&sy,&ex);
1381         ALCheckLegalRange(relnum[sx],sy,relnum[ex],sy,xmin,ymin,xmax,ymax);
1382         ALMakeCoilText(relnum[sx],sy,relnum[ex],texts);
1383     }else if(strcmp(token,"CALCONS")==0){
1384         /* calculate conservation for the range */
1385         ALGetFourInt(&sx,&sy,&ex,&ey);
1386         ALCheckLegalRange(relnum[sx],relnum[sy],relnum[ex],relnum[ey],xmin,ymin,xmax,ymax);
1387         consval = ALCalCons(bloc,relnum[sx],relnum[sy],relnum[ex],relnum[ey],
1388                          consval,bloc[1].slen);
1389 /*      fprintf(std_err,"Conservation Values\n"); */
1390 /*      for(k=1;k<bloc[1].slen-1;++k){*/
1391 /*          fprintf(std_err,"%d:%d\n",k,consval[k]);*/
1392 /*      }*/
1393     }else if(strcmp(token,"RELATIVE_TO")==0){
1394         token = strtok(NULL,TOKENS);
1395         relative_seq = atoi(token);
1396         fprintf(stderr,"RELATIVE SEQ %d\n",relative_seq);
1397         fprintf(stderr,"bloc[relative_seq].slen+1] %d\n",
1398                 bloc[relative_seq].slen+1);
1399         token = strtok(NULL,TOKENS);
1400         if(token != NULL){
1401             /* there is a first residue definition */
1402             firstres = atoi(token);
1403             fprintf(stderr,"First position is number: %d\n",firstres);
1404         }else{
1405             firstres = 1;
1406         }
1407         if(relative_seq != 0){
1408             k= firstres - 1;
1409             for(i=1;i<bloc[1].slen+1;++i){
1410                 /* for now assume all gaps are blanks */
1411                 if(bloc[relative_seq].seq[i] != ' '){
1412                     ++k;
1413                     relnum[k] = i;
1414                 }
1415             }
1416             /* increase the max allowed X value to the max of xmax and k */
1417             /* leave the minimum value at 1 since otherwise we will not be able to mix
1418                absolute and relative numbers without the Check routine skwawking */
1419             if(k > xmax ) xmax = k;
1420         }else{
1421             for(i=1;i<bloc[1].slen+1;++i){
1422                 relnum[i] = i;
1423             }
1424         }
1425     }else{
1426       fprintf(std_err,"%s",buff);
1427       error("Unrecognised Step 2 command\n",1);
1428     }
1429   }
1430   if(!silent){
1431     ALReportInfo(nseq,std_err);
1432   }
1433   ALCheckSinglePage(nseq,bloc[1].slen,silent);
1434
1435   start_aa = 1;
1436   totalpage = npage * Csheet;
1437
1438   /* get how many blocks of sequence we can fit per page */
1439   nspage = Cheight/(nseq+CtopSpace+Vspacing);
1440   if(nspage < 1){
1441     nspage = 1;
1442   }
1443   nbp = 0;
1444
1445   if(!silent)fprintf(std_err,"Will write a maximum of %d blocks of sequence per page\n",nspage);
1446   if(!silent)fprintf(std_err,"Background region: %d %d %d %d\n",
1447                      background_region[0],
1448                      background_region[1],
1449                      background_region[2],
1450                      background_region[3]);
1451   if(!silent && singlepage)fprintf(std_err,"Bounding box: %d %d %d %d\n",
1452                      bounding_box[0],
1453                      bounding_box[1],
1454                      bounding_box[2],
1455                      bounding_box[3]);
1456
1457   /* MARKER */
1458
1459   if((Cwidth - Cidwidth > 0)){
1460     if(!silent)fprintf(std_err,"Saving  (%d) Pages to file\n",totalpage/nspage);
1461   }else{
1462     fprintf(std_err,"This pointsize is too large to print even a single character on the page\n");
1463     fprintf(std_err,"Try a smaller pointsize - or\n");
1464     fprintf(std_err,"Try reducing the Identifier width\n");
1465     fprintf(std_err,"Increase the paper size\n");
1466     fprintf(std_err,"You could do some PostScrip-ery to print partial characters\n");
1467     fprintf(std_err,"After creating an alignment on a single page - see the CookBook\n");
1468     exit(1);
1469   }
1470   lastY = 0;
1471   nbpage = 0;
1472   k = 0;
1473   start_seq = 1;
1474   while(k < totalpage){
1475     start_aa = 1;
1476     Ytemp = start_seq+Cheight-CtopSpace - 1;
1477     if(Ytemp > nseq) Ytemp = nseq;
1478     for(i=0;i<npage;++i){
1479
1480       if(nspage > 1){        /* more than one block per page */
1481 /*        fprintf(stderr,"nbp nspage %d %d\n",nbp,nspage);*/
1482           if(k>0 && nbp == 0){ /* if not the first page, then setup page*/
1483             PSSetupPage(orientation,nbpage+1,outf);
1484             if(background_colour != 99){
1485                 ALColourBackground(outf,background_colour,background_region);
1486             }
1487           }
1488           if(nbp>0){
1489             /* if this is not the first block on the page, then */
1490             /* translate the block of alignment back to origin  */
1491             fprintf(outf,"%d %d translate\n",0,-lastY);
1492           }
1493           /* get new position for drawing and translate to this posn*/
1494           lastY = Yspace*( Cheight-(nseq+CtopSpace)*(nbp+1) - (nbp*Vspacing) );
1495           fprintf(outf,"%d %d translate\n",0,lastY);
1496       }else{
1497         if(k>0)PSSetupPage(orientation,k+1,outf);
1498         if(background_colour != 99){
1499             ALColourBackground(outf,background_colour,background_region);
1500         }
1501       }
1502       if(id_only_on_first == 1 && nbp > 0 ){
1503           /* save the Cseqwidth, then reset it to Cwidth - also set Cidwidth to 0*/
1504           tempCseqwidth = Cseqwidth;
1505           tempCidwidth = Cidwidth;
1506           Cseqwidth = Cwidth;
1507           Cidwidth = 0;
1508       }
1509
1510       Xtemp = start_aa+Cseqwidth-1;
1511       if(Xtemp > bloc[1].slen) Xtemp = bloc[1].slen;
1512
1513       fprintf(outf,"2 setlinecap\n");
1514       fprintf(outf," %.2f setlinewidth\n",LineWidthFactor*pointsize);
1515
1516       ALDrawFills(fills,use_colour,s_colour,start_aa,nseq-Ytemp+1,Xtemp,nseq-start_seq+1,Cidwidth,CseqVoffset,outf);
1517       ALDrawLines(lines,use_colour,
1518                  left_line_colour,
1519                  right_line_colour,
1520                  top_line_colour,
1521                  bottom_line_colour,
1522                  start_aa,nseq-Ytemp+1,Xtemp,nseq-start_seq+1,Cidwidth,CseqVoffset,outf);
1523       if(!(id_only_on_first == 1 && (nbp > 0 || k > 0))){
1524           /* don't output ID string if this is not the first block on the first page*/
1525           ALOutId(bloc,use_colour,
1526               id_colour,idfonts,start_seq,Ytemp,CseqVoffset,number_seqs,outf);
1527       }
1528       ALOutSeq(bloc,fonts,texts,inverse,use_colour,c_colour,
1529                text_colour,background_colour,start_seq,Ytemp,start_aa,CseqVoffset,outf);
1530       
1531       if(res_numbers){
1532         if(use_colour)PSSetColour(number_colour,outf);
1533         if(do_ticks){
1534           ALOutTicks(ticks,start_aa,Cidwidth,Ytemp-start_seq+1,bloc[1].slen,outf);
1535           ALOutNumbers(numbers,start_aa,Cidwidth,Ytemp-start_seq+2,bloc[1].slen,outf);
1536         }else{
1537           ALOutNumbers(numbers,start_aa,Cidwidth,Ytemp-start_seq+1,bloc[1].slen,outf);
1538         }
1539       }
1540       start_aa += Cseqwidth;
1541
1542       if(nspage > 1){
1543         ++nbp;
1544         if(nbp == nspage || k == totalpage-1){  /* put showpage command for page or last page */
1545           PSShowPage(outf);
1546           nbp = 0;
1547           ++nbpage;
1548         }
1549       }else{
1550         PSShowPage(outf);
1551       }
1552       ++k;
1553     }
1554     start_seq = Ytemp + 1;
1555     if(id_only_on_first == 1 && nbp > 0){
1556         /* reset the values - not strictly necessary */
1557         Cseqwidth = tempCseqwidth;
1558         Cidwidth = tempCidwidth;
1559     }
1560   }
1561   return 1;
1562 }
1563
1564 void ALShadeChars(struct seqdat *bloc,
1565 signed char **fill,
1566 int start_x,int start_y,int end_x,int end_y,
1567 int maxY,
1568 char *charlist,
1569 float grey)
1570
1571 /* shade residues in charlist by grey value */
1572
1573 {
1574   int i,j,jpos;
1575   for(i=start_x;i<end_x+1;++i){
1576      for(j=start_y,jpos=(maxY-start_y+1);j<end_y+1;++j,--jpos){
1577        if(strchr(charlist,bloc[j].seq[i])!=NULL){
1578          ALFilRes(fill,i,jpos,grey);
1579        }
1580      }
1581    }
1582 }
1583 void ALSColChars(struct seqdat *bloc,unsigned char **colour,int start_x,
1584 int start_y,int end_x,int end_y,int maxY,char *charlist,unsigned char colnum)
1585
1586 /* colour residue backgrounds in charlist by colnum value */
1587
1588 {
1589   int i,j,jpos;
1590   for(i=start_x;i<end_x+1;++i){
1591      for(j=start_y,jpos=(maxY-start_y+1);j<end_y+1;++j,--jpos){
1592        if(strchr(charlist,bloc[j].seq[i])!=NULL){
1593          ALColRes(colour,i,jpos,colnum);
1594        }
1595      }
1596    }
1597 }
1598
1599 void ALSColMask(unsigned char **mask,unsigned char **colour,
1600                 int start_x,int start_y,int end_x,int end_y,int maxY,
1601                 unsigned char colnum)
1602
1603 /* colour residue backgrounds in mask by colnum value */
1604
1605 {
1606   int i,j,jpos;
1607   for(i=start_x;i<end_x+1;++i){
1608      for(j=start_y,jpos=(maxY-start_y+1);j<end_y+1;++j,--jpos){
1609        if(mask[i][j]==1){
1610          ALColRes(colour,i,jpos,colnum);
1611        }
1612      }
1613    }
1614 }
1615 void ALInverseChars(struct seqdat *bloc,unsigned char **inverse,
1616                     int start_x,int start_y,int end_x,int end_y,char *charlist)
1617
1618 /* Invert the characters within the range */
1619 /* 18/Jan/93:  Allow inverted chars to be reverted */
1620
1621 {
1622   int i,j;
1623   for(i=start_x;i<end_x+1;++i){
1624      for(j=start_y;j<end_y+1;++j){
1625        if(strchr(charlist,bloc[j].seq[i])!=NULL){
1626          if(inverse[i][j] == 1){
1627                 inverse[i][j] = (unsigned char) 0;
1628          }else{
1629                 inverse[i][j] = (unsigned char ) 1;
1630          }
1631        }
1632      }
1633    }
1634 }
1635 void ALInverseMask(unsigned char **mask,unsigned char **inverse,
1636                    int start_x,int start_y,int end_x,int end_y)
1637 /* Invert the characters within the range of the mask*/
1638 /* 18/Jan/93:  Allow inverted chars to be reverted */
1639
1640 {
1641   int i,j;
1642   for(i=start_x;i<end_x+1;++i){
1643      for(j=start_y;j<end_y+1;++j){
1644        if(mask[i][j]){
1645          if(inverse[i][j] == 1){
1646                 inverse[i][j] = (unsigned char) 0;
1647          }else{
1648                 inverse[i][j] = (unsigned char ) 1;
1649          }
1650        }
1651      }
1652    }
1653 }
1654
1655 void ALFontChars(struct seqdat *bloc,unsigned char **fonts,
1656                  int start_x,int start_y,int end_x,int end_y,char *charlist,unsigned char fontnum)
1657
1658 /* set the characters within the range to the fontnum */
1659
1660 {
1661   int i,j;
1662   for(i=start_x;i<end_x+1;++i){
1663      for(j=start_y;j<end_y+1;++j){
1664        if(strchr(charlist,bloc[j].seq[i])!=NULL){
1665          fonts[i][j] = fontnum;
1666        }
1667      }
1668    }
1669 }
1670 void ALFontRegion(unsigned char **fonts,
1671                   int start_x,int start_y,int end_x,int end_y,
1672                   unsigned char fontnum)
1673 /* set the characters within the range to the fontnum */
1674
1675 {
1676   int i,j;
1677   for(i=start_x;i<end_x+1;++i){
1678      for(j=start_y;j<end_y+1;++j){
1679          fonts[i][j] = fontnum;
1680      }
1681    }
1682 }
1683 void ALFontMask(unsigned char **mask,unsigned char **fonts,
1684                 int start_x,int start_y,int end_x,int end_y,
1685                 unsigned char fontnum)
1686
1687 /* set the characters within the range to the fontnum */
1688
1689 {
1690   int i,j;
1691   for(i=start_x;i<end_x+1;++i){
1692      for(j=start_y;j<end_y+1;++j){
1693         if(mask[i][j]==1){
1694          fonts[i][j] = fontnum;
1695         }
1696      }
1697    }
1698 }
1699
1700 void ALColourChars(struct seqdat *bloc,unsigned char **colour,
1701                    int start_x,int start_y,int end_x,int end_y,
1702                    char *charlist,unsigned char colournum)
1703
1704 /* set the characters within the range to the colour defined by colournum */
1705
1706 {
1707   int i,j;
1708   for(i=start_x;i<end_x+1;++i){
1709      for(j=start_y;j<end_y+1;++j){
1710        if(strchr(charlist,bloc[j].seq[i])!=NULL){
1711          colour[i][j] = colournum;
1712        }
1713      }
1714    }
1715 }
1716 void ALColourRegion(unsigned char **colour,
1717                     int start_x,int start_y,int end_x,int end_y,
1718                     unsigned char colournum)
1719
1720 /* set the characters within the range to the colournum */
1721
1722 {
1723   int i,j;
1724   for(i=start_x;i<end_x+1;++i){
1725      for(j=start_y;j<end_y+1;++j){
1726          colour[i][j] = colournum;
1727      }
1728    }
1729 }
1730
1731 void ALColourMask(unsigned char **mask,unsigned char **colour,
1732                   int start_x,int start_y,int end_x,int end_y,
1733                   unsigned char colournum)
1734
1735 /* set the characters within the range to the colournum */
1736
1737 {
1738   int i,j;
1739   for(i=start_x;i<end_x+1;++i){
1740      for(j=start_y;j<end_y+1;++j){
1741         if(mask[i][j] == 1){
1742          colour[i][j] = colournum;
1743         }
1744      }
1745    }
1746 }
1747
1748   
1749 void ALSubChars(struct seqdat *bloc,
1750                 int start_x,int start_y,int end_x,int end_y,
1751                 char oldchar,char newchar)
1752
1753 /* substitute oldchar for newchar at each position in bloc */
1754
1755 {
1756   int i,j;
1757   for(i=start_x;i<end_x+1;++i){
1758      for(j=start_y;j<end_y+1;++j){
1759          if(bloc[j].seq[i] == oldchar) bloc[j].seq[i] = newchar;
1760      }
1761    }
1762 }
1763
1764
1765 void ALSurroundChars(struct seqdat *bloc,unsigned char **lines,
1766                      int start_x,int start_y,int end_x,int end_y,
1767                      int maxY,char *charlist)
1768
1769 /* 
1770 within the range of start_x etc.  Draw lines such that every character that
1771 is present within charlist is surrounded by a box.
1772 */
1773 {
1774   int i,j,jpos;
1775   char above,below,left,right;
1776   
1777   for(i=start_x;i<end_x+1;++i){
1778      for(j=start_y,jpos=(maxY-start_y+1);j<end_y+1;++j,--jpos){
1779       if(strchr(charlist,bloc[j].seq[i]) != NULL){
1780 /*      fprintf(std_err,"%d %d %c %c\n",i,j,bloc[j].seq[i]*/
1781         if(j == end_y){
1782           below = '!';
1783         }else{
1784           below = bloc[j+1].seq[i];
1785         }
1786         if(j == start_y){
1787           above = '!';
1788         }else{
1789           above = bloc[j-1].seq[i];
1790         }
1791         if(i == start_x){
1792           left = '!';
1793         }else{
1794           left  = bloc[j].seq[i-1];
1795         }
1796         if(i == end_x){
1797           right = '!';
1798         }else{
1799           right = bloc[j].seq[i+1];
1800         }
1801
1802         if(strchr(charlist,above)== NULL){
1803           ALLineRes(lines,i,jpos,LINE_TOP);
1804         }
1805         if(strchr(charlist,below)== NULL){
1806           ALLineRes(lines,i,jpos,LINE_BOTTOM);
1807         }
1808         if(strchr(charlist,left)==NULL){
1809           ALLineRes(lines,i,jpos,LINE_LEFT);
1810         }
1811         if(strchr(charlist,right)==NULL){
1812           ALLineRes(lines,i,jpos,LINE_RIGHT);
1813         }
1814       }
1815     }
1816   }
1817 }
1818 void ALSurroundMask(unsigned char **mask,struct seqdat *bloc,unsigned char **lines,
1819                     int start_x,int start_y,int end_x,int end_y,
1820                     int maxY)
1821 /* 
1822 within the range of start_x etc.  Draw lines such that every
1823 masked position is isolated from every non-masked position
1824 */
1825 {
1826   int i,j,jpos;
1827   char above,below,left,right;
1828
1829 /*  fprintf(stdout,"ALSurroundMask: %d %d %d %d\n",start_x,start_y,end_x,end_y);*/
1830   
1831   for(i=start_x;i<end_x+1;++i){
1832      for(j=start_y,jpos=(maxY-start_y+1);j<end_y+1;++j,--jpos){
1833         if(mask[i][j] == 1){
1834 /*      fprintf(std_err,"%d %d %c %c\n",i,j,bloc[j].seq[i]*/
1835         if(j == end_y){
1836           below = 0;
1837         }else{
1838           below = mask[i][j+1];
1839         }
1840         if(j == start_y){
1841           above = 0;
1842         }else{
1843           above = mask[i][j-1];
1844         }
1845         if(i == start_x){
1846           left = 0;
1847         }else{
1848           left  = mask[i-1][j];
1849         }
1850         if(i == end_x){
1851           right = 0;
1852         }else{
1853           right = mask[i+1][j];
1854         }
1855         /*
1856         fprintf(stdout,"IN ALSurroundMask\n");
1857         fprintf(stdout,"%d %d (%d %d %d %d)\n",i,j,above,below,left,right);
1858         */
1859
1860         if(mask[i][j] != above){
1861           ALLineRes(lines,i,jpos,LINE_TOP);
1862         }
1863         if(mask[i][j] != below){
1864           ALLineRes(lines,i,jpos,LINE_BOTTOM);
1865         }
1866         if(mask[i][j] != left){
1867           ALLineRes(lines,i,jpos,LINE_LEFT);
1868         }
1869         if(mask[i][j] != right){
1870           ALLineRes(lines,i,jpos,LINE_RIGHT);
1871         }
1872         }
1873      }
1874   }
1875 }
1876
1877 void ALFilRegion(signed char **fill,
1878                  int start_x,int start_y,int end_x,int end_y,
1879                  int *Yindx,float grey)
1880 {
1881   int i,j;
1882   for(i=start_x;i<end_x+1;++i){
1883     for(j=start_y;j<end_y+1;++j){
1884       ALFilRes(fill,i,Yindx[j],grey);
1885     }
1886   }
1887 }
1888
1889 void ALShadeMask(unsigned char **mask,signed char **fill,
1890                  int start_x,int start_y,int end_x,int end_y,int *Yindx,
1891                  float grey)
1892
1893 {
1894   int i,j;
1895   for(i=start_x;i<end_x+1;++i){
1896     for(j=start_y;j<end_y+1;++j){
1897         if(mask[i][j]==1){
1898             ALFilRes(fill,i,Yindx[j],grey);
1899         }
1900     }
1901   }
1902 }
1903
1904
1905 void ALColRegion(unsigned char **colour,
1906                  int start_x,int start_y,int end_x,int end_y,
1907                  int *Yindx,unsigned char colnum)
1908 {
1909   int i,j;
1910   for(i=start_x;i<end_x+1;++i){
1911     for(j=start_y;j<end_y+1;++j){
1912       ALColRes(colour,i,Yindx[j],colnum);
1913     }
1914   }
1915 }
1916
1917 void ALColRRegion(unsigned char **colour,
1918                  int start_x,int start_y,int end_x,int end_y,
1919                  unsigned char colnum)
1920 /* version of ALColRegion that is indexed by characters rather than position */
1921 /* 18/1/1995 */
1922
1923 {
1924   int i,j;
1925   for(i=start_x;i<end_x+1;++i){
1926      for(j=start_y;j<end_y+1;++j){
1927          colour[i][j] = colnum;
1928      }
1929    }
1930 }
1931
1932 void ALBoxRegion(unsigned char **lines,
1933                  int start_x,int start_y,int end_x,int end_y,
1934                  int *Yindx)
1935 {
1936   int i;
1937   for(i=start_x;i<end_x+1;++i){
1938     ALLineRes(lines,i,Yindx[end_y],LINE_BOTTOM);
1939     ALLineRes(lines,i,Yindx[start_y],LINE_TOP);
1940   }
1941   for(i=start_y;i<end_y+1;++i){
1942     ALLineRes(lines,start_x,Yindx[i],LINE_LEFT);
1943     ALLineRes(lines,end_x,Yindx[i],LINE_RIGHT);
1944   }
1945 }
1946 void ALDoLine(unsigned char **lines,
1947               int start_x,int start_y,int end,
1948               int type,int *Yindx)
1949 {
1950   int i;
1951   if(type == LINE_TOP || type == LINE_BOTTOM){
1952     for(i=start_x;i<end+1;++i){
1953       ALLineRes(lines,i,Yindx[start_y],type);
1954     }
1955   }else{
1956     for(i=start_y;i<end+1;++i){
1957       ALLineRes(lines,start_x,Yindx[i],type);
1958
1959
1960     }
1961   }
1962 }
1963
1964 void ALDrawFills(signed char **fill,int use_colour,unsigned char **colour,
1965                  int start_x,int start_y,int end_x,int end_y,int XOffset,int YOffset,FILE *outf)
1966
1967 /* for values of fill >= 0  draw box and fill in with grey value */
1968 /* 6/12/92:  add colour option */
1969 {
1970   int i,j;
1971   extern int precis;
1972
1973   XOffset *= Xspace;
1974   YOffset *= Yspace;
1975   
1976   for(i=end_x;i>(start_x-1);--i){
1977     for(j=end_y;j>(start_y-1);--j){
1978       if((int) fill[i][j] >=  0 || use_colour){
1979
1980 /*
1981 Revise to use ML function 27th Oct 1992
1982         fprintf(outf," newpath\n");
1983         fprintf(outf,"%.2f %.2f moveto \n",(float)(i-start_x)*Xspace-Xshift+XOffset,
1984                                          (float)(j-start_y+1)*Yspace-Yshift+YOffset);
1985         fprintf(outf,"%.2f %.2f lineto \n",(float)(i-start_x)*Xspace-Xshift+XOffset,
1986                                          (float)(j-start_y+0)*Yspace-Yshift+YOffset);
1987         fprintf(outf,"%.2f %.2f lineto \n",(float)(i-start_x+1)*Xspace-Xshift+XOffset,
1988                                          (float)(j-start_y+0)*Yspace-Yshift+YOffset);
1989         fprintf(outf,"%.2f %.2f lineto \n",(float)(i-start_x+1)*Xspace-Xshift+XOffset,
1990                                          (float)(j-start_y+1)*Yspace-Yshift+YOffset);
1991         fprintf(outf,"%.2f %.2f lineto \n",(float)(i-start_x)*Xspace-Xshift+XOffset,
1992                                          (float)(j-start_y+1)*Yspace-Yshift+YOffset);
1993         fprintf(outf,"closepath %.2f setgray fill 0 setgray \n",(float)fill[i][j]/(float)precis);
1994 */
1995         fprintf(outf," newpath\n");
1996         fprintf(outf,"%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f ML\n",
1997                (float)(i-start_x)*Xspace-Xshift+XOffset,
1998                (float)(j-start_y+1)*Yspace-Yshift+YOffset,
1999                (float)(i-start_x)*Xspace-Xshift+XOffset,
2000                (float)(j-start_y+0)*Yspace-Yshift+YOffset,
2001                (float)(i-start_x+1)*Xspace-Xshift+XOffset,
2002                (float)(j-start_y+0)*Yspace-Yshift+YOffset,
2003                (float)(i-start_x+1)*Xspace-Xshift+XOffset,
2004                (float)(j-start_y+1)*Yspace-Yshift+YOffset,
2005                (float)(i-start_x)*Xspace-Xshift+XOffset,
2006                (float)(j-start_y+1)*Yspace-Yshift+YOffset);
2007         if(use_colour && fill[i][j] < 0){
2008             /* 6/1/1995 - only set colour if grey is not set */
2009             /* set to colour number */
2010             fprintf(outf,"closepath  C%-d  fill \n",colour[i][j]);
2011         }else{
2012             fprintf(outf,"closepath %.2f setgray fill 0 setgray \n",(float)fill[i][j]/(float)precis);
2013         }
2014       }
2015     }
2016   }
2017 }
2018
2019 void ALFilRes(signed char **fill,int i,int j,float grey)
2020
2021 {
2022   extern int precis;
2023 /*  ALBoxRes(lines,i,j); 
2024   fill[i+Cidwidth][j+CseqVoffset] = grey * precis;
2025 */
2026   fill[i][j] = grey * precis;
2027 }
2028
2029 void ALColRes(unsigned char **colour,int i,int j,int colnum)
2030
2031 {
2032   colour[i][j] = colnum;
2033 }
2034   
2035
2036 void ALBoxRes(unsigned char **lines,int i,int j)
2037
2038 {
2039   ALLineRes(lines,i,j,LINE_TOP);
2040   ALLineRes(lines,i,j,LINE_BOTTOM);
2041   ALLineRes(lines,i,j,LINE_LEFT);
2042   ALLineRes(lines,i,j,LINE_RIGHT);
2043 }
2044
2045
2046 void ALLineRes(
2047 unsigned char **lines,
2048 int i,int j,
2049 unsigned char value)
2050 {
2051 /*
2052   i = i + Cidwidth;
2053   j = j + CseqVoffset;
2054 */
2055   ALLineChar(lines,i,j,value);
2056 }
2057
2058 void ALLineChar(unsigned char **lines,int i,int j,unsigned char value)
2059
2060 {
2061   lines[i][j] = lines[i][j] | value;
2062 }
2063
2064 void ALDrawLines(unsigned char **lines,int use_colour,
2065                  unsigned char **left_line_colour,
2066                  unsigned char **right_line_colour,
2067                  unsigned char **top_line_colour,
2068                  unsigned char **bottom_line_colour,
2069                  int start_x,int start_y,int end_x,int end_y,
2070                  int XOffset,int YOffset,FILE *outf)
2071
2072 /* draw the lines that are indicated by the lines array in the range of the
2073 array indicated by start_x etc
2074 */
2075 {
2076   int i,j;
2077   XOffset *= Xspace;
2078   YOffset *= Yspace;
2079
2080 /*  
2081   if(use_colour){
2082     fprintf(outf,"C100\n");
2083   }
2084 */
2085   
2086   for(i=end_x;i>(start_x-1);--i){
2087     for(j=end_y;j>(start_y-1);--j){
2088       if(lines[i][j] != 0){
2089         if((LINE_LEFT & lines[i][j]) == LINE_LEFT){
2090           PSSetColour(left_line_colour[i][j],outf);
2091           PSline((float)(i-start_x)*Xspace-Xshift+XOffset,
2092                  (float)(j-start_y+1)*Yspace-Yshift+YOffset,
2093                  (float)(i-start_x)*Xspace-Xshift+XOffset,
2094                  (float)(j-start_y+0)*Yspace-Yshift+YOffset,outf);
2095         }
2096         if((LINE_RIGHT & lines[i][j]) == LINE_RIGHT){
2097           PSSetColour(right_line_colour[i][j],outf);
2098           PSline((float)(i-start_x+1)*Xspace-Xshift+XOffset,
2099                  (float)(j-start_y+1)*Yspace-Yshift+YOffset,
2100                  (float)(i-start_x+1)*Xspace-Xshift+XOffset,
2101                  (float)(j-start_y+0)*Yspace-Yshift+YOffset,outf);
2102         }
2103         if((LINE_TOP & lines[i][j]) == LINE_TOP){
2104           PSSetColour(top_line_colour[i][j],outf);
2105           PSline((float)(i-start_x)*Xspace-Xshift+XOffset,
2106                  (float)(j-start_y+1)*Yspace-Yshift+YOffset,
2107                  (float)(i-start_x+1)*Xspace-Xshift+XOffset,
2108                  (float)(j-start_y+1)*Yspace-Yshift+YOffset,outf);
2109         }
2110         if((LINE_BOTTOM & lines[i][j]) == LINE_BOTTOM){
2111           PSSetColour(bottom_line_colour[i][j],outf);
2112           PSline((float)(i-start_x)*Xspace-Xshift+XOffset,
2113                  (float)(j-start_y+0)*Yspace-Yshift+YOffset,
2114                  (float)(i-start_x+1)*Xspace-Xshift+XOffset,
2115                  (float)(j-start_y+0)*Yspace-Yshift+YOffset,outf);
2116         }
2117       }
2118     }
2119   }
2120   /*
2121   if(use_colour){
2122     fprintf(outf,"C99\n");
2123   }
2124   */
2125 }
2126
2127 void PSline(float x1,float y1,float x2,float y2,FILE *outf)
2128
2129 {
2130   fprintf(outf,"%.2f %.2f %.2f %.2f L\n ",x1,y1,x2,y2);
2131 }
2132
2133
2134
2135 void ALSimpleBox(int x1,int y1,int x2,int y2,float pfactor,    /* multiply pointsize by this to get linewidth */         
2136                  FILE *outf)
2137
2138 /* draw a box to include character coordinates x1,y1 to x2,y2 */
2139 /* x1 < x2 y1< y2 */
2140 {
2141   float lshift = Xspace/6;
2142   float rshift = Xspace - lshift;
2143   
2144   x1 *= Xspace; 
2145   y1 *= Yspace;
2146   x2 *= Xspace;
2147   y2 *= Yspace;
2148
2149   x1 -= lshift;
2150   x2 += rshift;
2151   y1 -= lshift;
2152
2153   PSDrawBox((float)x1,(float)y1,(float)x2,(float)y2,pfactor,outf);
2154 }
2155
2156 void PSDrawBox(float x1,float y1,float x2,float y2,float pfactor,FILE *out)
2157
2158 {
2159   fprintf(out,"%f setlinewidth\n ",pointsize*pfactor);
2160   fprintf(out,"%f %f moveto %f %f lineto %f %f lineto %f %f lineto %f %f lineto closepath stroke\n",
2161                x1,y1,x2,y1,x2,y2,x1,y2,x1,y1);
2162 }
2163
2164 void ALOutTicks(char *array,int start_aa,int xpos,int ypos,int len,FILE *out)
2165
2166 {
2167   int right;
2168   int j;
2169   
2170   xpos *= Xspace;
2171   ypos *= Yspace;
2172
2173   right = start_aa + Cseqwidth;
2174   if(right > len)right = len;
2175   for(j=start_aa;j<right;j++){
2176     if(array[j] != '\0'){
2177       PSPutChar(xpos,ypos,array[j],out);
2178     }
2179     xpos +=  Xspace;
2180   }
2181 }
2182
2183 void ALOutNumbers(char **array,int start_aa,int xpos,int ypos,int len,FILE *out)
2184
2185 {
2186   int right;
2187   int j;
2188   
2189   xpos *= Xspace;
2190   ypos *= Yspace;
2191
2192   right = start_aa + Cseqwidth;
2193   if(right > len)right = len;
2194   for(j=start_aa;j<right;j++){
2195     if(array[j][0] != '\0'){
2196       PSPutText(xpos,ypos,array[j],out);
2197     }
2198     xpos +=  Xspace;
2199   }
2200 }
2201
2202 char *ALCreateTicks(int start, int interval, int len)
2203
2204 /* create ticks at the desired interval starting with residue start */
2205 {
2206   int i;
2207   char *temp;
2208   temp = (char *) malloc(sizeof(char) * len);
2209   /* first set all ticks to '\0' */
2210   for(i=0;i<len;++i){
2211     temp[i]='\0';
2212   }
2213   for(i=0;i<len;i+=interval){
2214     temp[i] = '|';
2215   }
2216   temp[0]='\0';
2217   temp[1]='|';
2218   return temp;
2219 }
2220
2221
2222
2223 char **ALCreateNumbers(int start,int interval,int nres,int nwidth)
2224
2225 /* create character array of numbers from start to nres at interval*/
2226 {
2227   int i;
2228   char **temp;
2229   temp = (char **) malloc(nres*sizeof(char *));
2230   for(i=0;i<nres;++i){
2231     temp[i] = (char *) malloc(sizeof(char) *nwidth);
2232     temp[i][0]='\0';
2233   }
2234   for(i=start;i<nres;i+=interval){
2235     if(i==0){
2236       sprintf(temp[i+1],"%-d",i+1);      
2237     }else{
2238       sprintf(temp[i],"%-d",i);
2239     }
2240   }
2241
2242   return temp;
2243 }
2244   
2245 char **ALCreateNum2(
2246 int nstart,     /* starting number */
2247 int ninterval,  /* interval for numbers */
2248 int nend,       /* end of number range */
2249 int nres,       /* total length of sequence */
2250 int xstart,     /* starting location for writing numbers */
2251 int nwidth)     /* width of the number string */
2252
2253 /* create character array of numbers from start to nres at interval*/
2254 {
2255   int i,xp;
2256   char **temp;
2257   temp = (char **) malloc(nres*sizeof(char *));
2258   for(i=0;i<nres;++i){
2259     temp[i] = (char *) malloc(sizeof(char) *nwidth);
2260     temp[i][0]='\0';
2261   }
2262   xp = xstart;
2263   for(i=nstart;i<nend;i+=ninterval){
2264     if(i==0){
2265       sprintf(temp[xp+1],"%-d",i+1);      
2266     }else{
2267       sprintf(temp[xp],"%-d",i);
2268     }
2269     xp += ninterval;
2270   }
2271
2272   return temp;
2273 }
2274
2275 void ALReportInfo(int nseq,FILE *out)
2276
2277 {
2278   fprintf(out,"Number of Sequences: %d\n",nseq);
2279   fprintf(out,"Total Vertical Space per page: %d\n",Cheight);
2280 }
2281
2282 void ALReserveSpace(int location,int nspace)
2283
2284 {
2285   extern int TVspace,CseqVoffset;
2286
2287   switch(location){
2288   case TOP:
2289     TVspace += nspace;
2290     CtopSpace +=nspace;
2291     break;
2292   case BOTTOM:
2293     TVspace += nspace;
2294     CseqVoffset += nspace;
2295     CbottomSpace += nspace;
2296     break;
2297   }
2298 }
2299
2300 void PSSetupPage(int orientation,int npage,FILE *outf)
2301
2302 {
2303   fprintf(outf,"%%%%Page: ? %d\n",npage);
2304   PSSetOrientation(orientation,outf);
2305   PSSetFont(0,outf);    /* set default font for document */
2306 }
2307
2308 void ALOutSeq(struct seqdat *bloc,unsigned char **fonts,char ***texts,unsigned char **inverse,
2309               int use_colour,
2310               unsigned char **colour,
2311               unsigned char **text_colour,
2312               unsigned char background_colour,
2313               int start_seq,int end_seq,int start_aa,int ypos,FILE *outf)
2314
2315 {
2316   extern int Xspace,Yspace;
2317   extern int Cidwidth;
2318
2319   int i,j;
2320   int xpos;
2321   unsigned char current_col;
2322
2323   int right;
2324
2325   ypos *= Yspace;
2326
2327   current_col = background_colour;
2328
2329   right = start_aa + Cseqwidth;
2330   if(right > bloc[1].slen-1)right = bloc[1].slen;
2331   
2332   for(i=end_seq;i>(start_seq-1);--i){
2333     xpos = Cidwidth * Xspace;
2334     for(j=start_aa;j<right;++j){
2335       if(texts[j][i] != NULL || bloc[i].seq[j] != ' '){
2336         if(fonts[j][i]!=0)PSSetFont(fonts[j][i],outf);
2337         if(inverse[j][i] != 0)PSSetGrey(1,outf);
2338         if(use_colour && colour[j][i] != current_col){
2339             PSSetColour(colour[j][i],outf);
2340             current_col = colour[j][i];
2341         } 
2342         if(bloc[i].seq[j] != ' '){
2343           PSPutChar(xpos,ypos,bloc[i].seq[j],outf);
2344         }
2345         if(texts[j][i] != NULL){
2346             if(text_colour[j][i] != current_col){
2347                 PSSetColour(text_colour[j][i],outf);
2348                 current_col = text_colour[j][i];
2349             }
2350           if(texts[j][i][0] == '@'){
2351             PSPutSpecialText(xpos,ypos,Xspace,Yspace,texts[j][i],
2352                              text_colour[j][i],background_colour,0.9,outf);
2353           }else{
2354             PSPutText(xpos,ypos,texts[j][i],outf);
2355           }
2356         }
2357         if(inverse[j][i] != 0)PSSetGrey(0,outf);
2358         if(fonts[j][i]!=0)PSSetFont(0,outf);
2359       }
2360       xpos += Xspace;
2361     }
2362     ypos += Yspace;
2363   }
2364 /*
2365   if(use_colour){
2366         PSSetColour(100,outf);
2367   }
2368 */
2369 }
2370
2371
2372 void ALOutId(struct seqdat *bloc,int use_colour,
2373              unsigned char *colour,
2374              unsigned char *fonts,
2375              int start_seq,int end_seq,int ypos,int numbers,
2376              FILE *outf)
2377
2378 {
2379   extern int MAXilen;
2380   extern int Xspace,Yspace;
2381   int i;
2382   int xpos;
2383   char *temp;
2384
2385   xpos = 0;
2386   ypos *= Yspace;
2387   temp = (char *) malloc(sizeof(char) * (MAXilen + 5));
2388
2389
2390   for(i=end_seq;i>(start_seq-1);--i){
2391     if(use_colour)PSSetColour(colour[i],outf);
2392     if(fonts[i] != 0)PSSetFont(fonts[i],outf);
2393     if(numbers){
2394       sprintf(temp,"%4d:%s",i,bloc[i].id);
2395     }else{
2396       sprintf(temp,"%s",bloc[i].id);
2397     }
2398     PSPutText(xpos,ypos,temp,outf);
2399     ypos += Yspace;
2400     if(fonts[i] != 0)PSSetFont(0,outf);
2401   }
2402   free((char *) temp);
2403
2404 }
2405
2406 void PSPutText(int x,int y,char *text,FILE *outf)
2407
2408 {
2409   fprintf(outf," %d %d moveto (%s) show \n",x,y,text);
2410 }
2411
2412 void PSPutChar(int x,int y,char c,FILE *outf)
2413
2414 {
2415   /* fprintf(outf," %d %d moveto (%c) show \n",x,y,c);*/
2416   fprintf(outf,"(%c) %d %d P\n",c,x,y);
2417 }
2418
2419 void PSShowPage(FILE *outf)
2420
2421 {
2422   fprintf(outf,"showpage\n");
2423 }
2424
2425 void ALSetFont(char *font,int point,FILE *outf)
2426
2427 {
2428   fprintf(outf,"/%s findfont %d scalefont setfont\n",font,point);
2429 }
2430
2431 void PSSetFont(unsigned char number,FILE *outf)
2432
2433 {
2434   fprintf(outf,"F%-d\n ",number);
2435 }
2436
2437 void PSSetColour(unsigned char number,FILE *outf)
2438
2439 {
2440   fprintf(outf,"C%-d\n ",number);
2441 }
2442
2443 void ALDefineFont(int number,char *font,float point,FILE *outf)
2444
2445 /* define a PostScript function called /Fnumber which selects the 
2446 font at point pointsize */
2447 {
2448   fprintf(outf,"/F%-d {/%s findfont %.2f scalefont setfont } def\n",
2449           number,font,point);
2450 }
2451
2452 void ALDefineColour(int number,char *type,float red,float green,float blue,FILE *outf)
2453
2454 /* define a PostScript function called /Cnumber which selects the 
2455 colour defined by red,green, blue intensities
2456
2457 new addition - if type is equal to "HSB" then define an hsb colour using red, green blue as
2458 the hue saturation and brightness. 
2459 */
2460 {
2461     if(strcmp(type,"HSB")==0){
2462        /* set an HSB colour */
2463        fprintf(outf,"/C%-d {%f %f %f sethsbcolor } def\n", number,red,green,blue);
2464     }else{
2465         /* set an RGB colour */
2466        fprintf(outf,"/C%-d {%f %f %f setrgbcolor } def\n", number,red,green,blue);
2467     }
2468 }
2469
2470 void ALCheckSinglePage(int nseq,int len,int silent)
2471
2472 {
2473   extern FILE *std_err;
2474   Csheet = 1;
2475
2476
2477   if(Cheight-CtopSpace < nseq){
2478     if(!silent)fprintf(std_err,"Not enough height to print all sequences on a single page at this pointsize\n");
2479     if(!silent)fprintf(std_err,"Pointsize: %.2f\n",pointsize);
2480     if(!silent)fprintf(std_err,"Need a pointsize of < : %.2f\n",(float) height/(nseq+ CtopSpace));
2481     Csheet = nseq/(Cheight-CtopSpace) + 1;
2482     if(!silent)fprintf(std_err,"Will split alignment into %d segments\n",Csheet);
2483   }
2484   
2485   npage = len/(Cwidth - Cidwidth)  + 1;
2486 }
2487
2488
2489 void ALSetPageLimits(void)
2490 /* Use the current width height and pointsize values to calculate:
2491    Cwidth
2492    Cheight
2493    Xspace
2494    Yspace
2495 */
2496 {
2497
2498   Xspace = pointsize + pointsize * XspaceFactor;
2499   Yspace = pointsize + pointsize * YspaceFactor;
2500
2501   Cwidth = width/Xspace;
2502   Cheight = height/Yspace;
2503
2504   Cseqwidth = Cwidth - Cidwidth;
2505
2506   Xshift = Xspace * XshiftFactor;
2507   Yshift = Yspace * YshiftFactor;
2508 }
2509
2510 void PSSetOrientation(int orientation,FILE *outf)
2511
2512 {
2513   switch(orientation){
2514   case LANDSCAPE:
2515     PSLandscape(outf);
2516     break;
2517   case PORTRAIT:
2518     PSPortrait(outf);
2519     break;
2520   default:
2521     PSPortrait(outf);
2522   }
2523 }
2524
2525 void PSPreamble(FILE *out,int singlepage,int *b_box,int screensize)
2526 {
2527   char *Alscript_Version = ALSCRIPT_VERSION;
2528   fprintf(out,"%%!PS-Adobe-2.0\n");
2529   fprintf(out,"%%%%Creator: %s\n",Alscript_Version);
2530   fprintf(out,"%%%%Title: Alscript Output\n");
2531   fprintf(out,"%% Barto,n G. J. (1993)\n");
2532   fprintf(out,"%% ALSCRIPT - A Tool to format multiple sequence alignments\n");
2533   fprintf(out,"%% Protein Engineering, 6, 37-40\n");
2534   fprintf(out,"%%\n");
2535   if(singlepage == 1){
2536         fprintf(out,"%%%%BoundingBox: %d %d %d %d\n",
2537                 b_box[0],b_box[1],b_box[2],b_box[3]);
2538   }
2539   fprintf(out,"/P {moveto show} def\n");
2540   fprintf(out,"/L {moveto lineto stroke} def\n");
2541   fprintf(out,
2542   "/ML {moveto lineto lineto lineto lineto} def\n");
2543   fprintf(out,"2 setlinecap\n");                 /* projecting line caps */
2544   ALDefineColour(99,"RGB",1.0,1.0,1.0,out);  /* white */
2545   ALDefineColour(100,"RGB",0.0,0.0,0.0,out);  /* black */
2546   /* modify the screening - suggested by Michael D. Baron */
2547   fprintf(out,"%d currentscreen 3 -1 roll pop setscreen\n",screensize);
2548
2549 }
2550
2551 void PSLandscape(FILE *out)
2552
2553 {
2554   width = MAXside;
2555   height = MINside;
2556
2557   fprintf(out,"%d %d translate\n",xoff+height,yoff);
2558   fprintf(out,"90 rotate\n");  
2559
2560 }
2561
2562 void PSPortrait(FILE *out)
2563
2564 {
2565   width = MINside;
2566   height = MAXside;
2567   fprintf(out,"%d %d translate\n",xoff,yoff);
2568 }
2569
2570
2571 void echo(char *s)
2572
2573 {
2574   extern FILE *std_err;
2575   fprintf(std_err,"%s",s);
2576 }
2577
2578 void ALGetFourInt(int *sx,int *sy,int *ex,int *ey)
2579
2580 {
2581 char *token;
2582
2583         token = strtok(NULL,TOKENS);
2584         *sx = atoi(token);
2585         token = strtok(NULL,TOKENS);
2586         *sy = atoi(token);
2587         token = strtok(NULL,TOKENS);
2588         *ex = atoi(token);
2589         token = strtok(NULL,TOKENS);
2590         *ey = atoi(token);
2591 }
2592 void ALGetThreeInt(int *sy,int *ex,int *ey)
2593
2594 {
2595 char *token;
2596
2597         token = strtok(NULL,TOKENS);
2598         *sy = atoi(token);
2599         token = strtok(NULL,TOKENS);
2600         *ex = atoi(token);
2601         token = strtok(NULL,TOKENS);
2602         *ey = atoi(token);
2603 }
2604 void ALGetTwoInt(int *sy,int *ex)
2605
2606 {
2607 char *token;
2608
2609         token = strtok(NULL,TOKENS);
2610         *sy = atoi(token);
2611         token = strtok(NULL,TOKENS);
2612         *ex = atoi(token);
2613 }
2614
2615 char ALChekSpace(const char *token)
2616 {
2617   if(strcmp(token,"SPACE") == 0){
2618     return ' ';
2619   }else{
2620     return token[0];
2621   }
2622 }
2623
2624 void PSSetGrey(float grey,FILE *outf)
2625 {
2626   fprintf(outf," %.2f setgray\n",grey);
2627 }
2628
2629 int save_pir(struct seqdat *bloc,int nseq,FILE *pirf)
2630
2631 {
2632   int i,j;
2633   int count;
2634
2635
2636    for(i=1;i<(nseq+1);++i){
2637     fprintf(pirf,">P1;%s\n",bloc[i].id);
2638     fprintf(pirf,"%s\n",bloc[i].title);
2639     count=0;
2640     for(j=1;j<bloc[i].slen;++j){
2641       ++count;
2642       /* convert spaces to dashes */
2643       if(bloc[i].seq[j] == ' ')bloc[i].seq[j] = '.';
2644       fputc(bloc[i].seq[j],pirf);
2645       if(count==50){
2646         count=0;
2647         fprintf(pirf,"\n");
2648       }
2649     }
2650     fprintf(pirf,"*\n");
2651   }
2652   return 1;
2653 }
2654
2655 int save_msf(struct seqdat *bloc,int nseq,FILE *msff)
2656
2657 {
2658   int i,j,s,e;
2659   int count;
2660
2661   fprintf(msff,"\njunk.msf  MSF: %d  Type: P  January 01, 1776  12:00  Check: 7110 ..\n\n",bloc[1].slen-1);
2662
2663    for(i=1;i<(nseq+1);++i){
2664      fprintf(msff,"Name: %20s Len: %7d  Check:    0  Weight:  1.00\n",
2665              bloc[i].id,bloc[1].slen-1);
2666    }
2667    fprintf(msff,"\n//\n\n\n");
2668
2669
2670    s = 1; 
2671
2672    while(s < bloc[1].slen){
2673        e = s + 50;
2674        if(e > bloc[1].slen) e = bloc[1].slen;
2675        
2676        for(i=1;i<(nseq+1);++i){
2677            fprintf(msff,"%10s ",bloc[i].id);
2678            for(j=s;j<e;++j){
2679               if(bloc[i].seq[j] == ' ')bloc[i].seq[j]='.';
2680               fputc(bloc[i].seq[j],msff);
2681            }
2682            fprintf(msff,"\n");
2683        }
2684        s += 50;
2685        fprintf(msff,"\n\n");
2686    }
2687    return 1;
2688 }
2689   
2690
2691 void ALGetAllRange(int *sx, int *sy, int *ex, int *ey,int dex,int dey)
2692 /* checks the next token if it is ALL then return box around whole alignment
2693    else return box according to the integers found
2694 */
2695 {
2696     char *token;
2697     
2698     token = strtok(NULL,TOKENS);
2699     
2700     if(strcmp(token,"ALL")==0){
2701                 *sx = 1;
2702                 *sy = 1;
2703                 *ex = dex;
2704                 *ey = dey;
2705     }else{
2706                 *sx = atoi(token);
2707                 ALGetThreeInt(sy,ex,ey);
2708     }
2709     if(*ex > dex) *ex = dex;
2710     if(*ey > dey) *ey = dey;
2711 }
2712
2713 void ALid_mask(
2714 unsigned char **mask,
2715 struct seqdat *bloc,
2716 int sx,int sy,int ex,int ey,
2717 int id_cut,
2718 char *legal,
2719 char *illegal)
2720
2721 {
2722     int i,j,k,iseen;
2723     char fchar;
2724     char *seen;   /* array of characters that are seen at this position */
2725     int *freq;    /* array of frequencies of the characters */
2726     int nc;       /* number of different character types at this position */
2727     int ns;
2728     int mc;       /* maximum character present */
2729     int imc;      /* location of max character */
2730
2731     ns = ey - sy + 1;
2732     nc = 0;
2733
2734     seen = (char *) GJmalloc(sizeof(char) *ns);
2735     freq = (int *)  GJmalloc(sizeof(int) *ns);
2736
2737     for(i=0;i<ns;++i){
2738         freq[i] = 0;
2739         seen[i] = '\0';
2740     }
2741
2742 /*    fprintf(stdout,"In ALidmask\n");*/
2743     
2744     for(i=sx;i<(ex+1);++i){
2745         /* for each position get the list of characters seen and their frequencies */
2746         for(j=sy;j<(ey+1);++j){
2747             iseen = Ifound(bloc,i,j,seen,nc);
2748             if(iseen >= 0){
2749                 ++freq[iseen];
2750             }else{
2751                 seen[nc] = bloc[j].seq[i];
2752                 ++freq[nc];
2753                 ++nc;
2754             }
2755         }
2756         /*
2757         for(k=0;k<nc;++k)fprintf(stdout,"%c ",seen[k]);
2758         for(k=0;k<nc;++k)fprintf(stdout,"%d ",freq[k]);
2759         fprintf(stdout,"\n");
2760         */
2761         /* find the most frequent character that is legal and not illegal*/
2762         mc = 0;
2763         for(k=0;k<nc;++k){
2764             if(legal != NULL && illegal != NULL){
2765                 if(  strchr(legal,seen[k]) != NULL
2766                   && strchr(illegal,seen[k]) == NULL
2767                   && freq[k] > mc){
2768                   mc = freq[k];
2769                   imc = k;
2770                   }
2771             }else if(legal != NULL){
2772                 if(  strchr(legal,seen[k]) != NULL
2773                   && freq[k] > mc){ 
2774                   mc = freq[k];
2775                   imc = k;
2776                   }
2777             }else if(illegal != NULL){
2778                 if(  strchr(illegal,seen[k]) == NULL
2779                   && freq[k] > mc){
2780                   mc = freq[k];
2781                   imc = k;
2782                   }
2783             }else{
2784                 if(freq[k] > mc){
2785                      mc = freq[k];
2786                      imc = k;
2787                 }
2788             }
2789         }
2790         if(mc >= id_cut){
2791             /* only select the character if it is >= id_cut */
2792             fchar = seen[imc];
2793 /*          fprintf(stdout,"At %d %c\n",i,fchar);*/
2794             for(j=sy;j<(ey+1);++j){
2795                 if(bloc[j].seq[i] == fchar){
2796                     mask[i][j] = 1;
2797 /*                    fprintf(stdout,"%d %d \n",i,j);*/
2798                 }
2799             }
2800         }
2801         for(j=0;j<ns;++j){
2802            freq[j] = 0;
2803            seen[j] = '\0';
2804         }
2805         nc = 0;
2806     }
2807     GJfree(seen);
2808     GJfree(freq);
2809 }
2810
2811 void ALfre_mask(
2812 unsigned char **mask,
2813 struct seqdat *bloc,
2814 int sx,int sy,int ex,int ey,
2815 char *legal,
2816 char *illegal)
2817
2818 {
2819     int i,j,k,iseen;
2820     char fchar;
2821     char *seen;   /* array of characters that are seen at this position */
2822     int *freq;    /* array of frequencies of the characters */
2823     int nc;       /* number of different character types at this position */
2824     int ns;
2825     int mc;       /* maximum character present */
2826     int imc;      /* location of max character */
2827
2828     ns = ey - sy + 1;
2829     nc = 0;
2830
2831     seen = (char *) GJmalloc(sizeof(char) *ns);
2832     freq = (int *)  GJmalloc(sizeof(int) *ns);
2833
2834     for(i=0;i<ns;++i){
2835         freq[i] = 0;
2836         seen[i] = '\0';
2837     }
2838
2839 /*    fprintf(stdout,"In ALidmask\n");*/
2840     
2841     for(i=sx;i<(ex+1);++i){
2842         /* for each position get the list of characters seen and their frequencies */
2843         for(j=sy;j<(ey+1);++j){
2844             iseen = Ifound(bloc,i,j,seen,nc);
2845             if(iseen >= 0){
2846                 ++freq[iseen];
2847             }else{
2848                 seen[nc] = bloc[j].seq[i];
2849                 ++freq[nc];
2850                 ++nc;
2851             }
2852         }
2853 /*        for(k=0;k<nc;++k)fprintf(stdout,"%c ",seen[k]);
2854         for(k=0;k<nc;++k)fprintf(stdout,"%d ",freq[k]);
2855         fprintf(stdout,"\n");
2856 */
2857         /* find the most frequent character that is legal and not illegal*/
2858         mc = 0;
2859         for(k=0;k<nc;++k){
2860             if(legal != NULL && illegal != NULL){
2861                 if(  strchr(legal,seen[k]) != NULL
2862                   && strchr(illegal,seen[k]) == NULL
2863                   && freq[k] > mc){
2864                   mc = freq[k];
2865                   imc = k;
2866                   }
2867             }else if(legal != NULL){
2868                 if(  strchr(legal,seen[k]) != NULL
2869                   && freq[k] > mc){ 
2870                   mc = freq[k];
2871                   imc = k;
2872                   }
2873             }else if(illegal != NULL){
2874                 if(  strchr(illegal,seen[k]) == NULL
2875                   && freq[k] > mc){
2876                   mc = freq[k];
2877                   imc = k;
2878                   }
2879             }else{
2880                 if(freq[k] > mc){
2881                      mc = freq[k];
2882                      imc = k;
2883                 }
2884             }
2885         }
2886         fchar = seen[imc];
2887 /*          fprintf(stdout,"At %d %c\n",i,fchar);*/
2888             for(j=sy;j<(ey+1);++j){
2889                 if(bloc[j].seq[i] == fchar){
2890                     mask[i][j] = 1;
2891 /*                    fprintf(stdout,"%d %d \n",i,j);*/
2892                 }
2893             }
2894
2895         for(j=0;j<ns;++j){
2896            freq[j] = 0;
2897            seen[j] = '\0';
2898         }
2899         nc = 0;
2900     }
2901     GJfree(seen);
2902     GJfree(freq);
2903 }
2904 int Ifound(struct seqdat *bloc,
2905 int i,int j,
2906 char *seen,
2907 int nc)
2908 {
2909     int k;
2910     
2911     if(nc > 0){
2912        for(k=0;k<nc;++k){
2913              if(bloc[j].seq[i] == seen[k]){
2914                 return k;
2915              }
2916        }
2917     }
2918     return -1;
2919 }
2920 void ALagree_mask(
2921 unsigned char **mask,
2922 struct seqdat *bloc,
2923 int sx,int sy,int ex,int ey,
2924 int ns)
2925
2926 {
2927     int i,j;
2928
2929     for(i=sx;i<(ex+1);++i){
2930         /* for each position mask the characters that are identical to sequence ns */
2931         for(j=sy;j<(ey+1);++j){
2932             if(bloc[j].seq[i] == bloc[ns].seq[i]){
2933                 mask[i][j] = 1;
2934             }
2935         }
2936     }
2937 }
2938
2939 void ALnot_mask(
2940 unsigned char **mask,
2941 int sx,int sy,int ex,int ey)
2942
2943 {
2944     int i,j;
2945
2946     for(i=sx;i<(ex+1);++i){
2947         /* NOT on each mask element ie 1 goes to 0, 0 to 1 */
2948         for(j=sy;j<(ey+1);++j){
2949             if(mask[i][j]==1){
2950                 mask[i][j]=0;
2951             }else if(mask[i][j]==0){
2952                 mask[i][j]=1;
2953             }
2954         }
2955     }
2956 }
2957                     
2958
2959 void ALsub_mask(unsigned char **mask,struct seqdat *bloc,
2960                 int sx,int sy,int ex,int ey,char cchar)
2961
2962 {
2963     int i,j;
2964
2965     for(i=sx;i<(ex+1);++i){
2966         /* substitute all characters in the mask for cchar */
2967         for(j=sy;j<(ey+1);++j){
2968             if(mask[i][j]==1){
2969                 bloc[j].seq[i] = cchar;
2970             }
2971         }
2972     }
2973 }
2974
2975 void ALMask(unsigned char **mask,
2976 int sx,int sy,int ex,int ey)
2977
2978 {
2979     int i,j;
2980
2981     for(i=sx;i<(ex+1);++i){
2982         /* substitute all characters in the mask for cchar */
2983         for(j=sy;j<(ey+1);++j){
2984             mask[i][j] = 1;
2985         }
2986     }
2987 }
2988
2989 void ALConsMask(unsigned char **mask,
2990 int sx,int sy,int ex,int ey,int *consval,int conscut)
2991
2992 {
2993     int i,j;
2994
2995     for(i=sx;i<(ex+1);++i){
2996         /* set mask at all positions that are >= conscut in the consval array */
2997         for(j=sy;j<(ey+1);++j){
2998             if(consval[i] >= conscut){
2999                 mask[i][j] = 1;
3000             }
3001         }
3002     }
3003 }
3004
3005
3006 void ALDrawHorizLine(
3007                      float Xpos,       /* bottom left hand corner of character posn */
3008                      float Ypos,       /* */
3009                      float Xspace,     /* horizontal width of character position */
3010                      float Yspace,     /* vertical height of character position */
3011                      float width_fac,FILE *outf)  /* proportion of vertical height that the line will fill */
3012
3013
3014 {
3015   float xright,ytop;
3016   float ymid;
3017   float hline_w;
3018
3019   xright = Xpos + Xspace;       /* right hand edge of character (lhe of next character) */
3020   ytop = Ypos + Yspace;         /* top edge of character */
3021   ymid = (ytop + Ypos) * 0.5;   /* vertical mid point */
3022
3023   /* width_fac defines the width of the line in terms of the height of the characters */
3024
3025   hline_w = 0.5 * (width_fac * (ytop - Ypos));
3026
3027   fprintf(outf,"%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f ML\n",
3028           Xpos,ymid-hline_w,
3029           xright,ymid-hline_w,
3030           xright,ymid+hline_w,
3031           Xpos,ymid+hline_w,
3032           Xpos,ymid-hline_w,outf);
3033
3034
3035 void ALDrawRightArrow(float Xpos,float Ypos, float Xspace, float Yspace, float width_fac,FILE *outf)
3036
3037 {
3038   float xright,ytop;
3039   float ymid;
3040   float hline_w;
3041
3042   xright = Xpos + Xspace;       /* right hand edge of character (lhe of next character) */
3043   ytop = Ypos + Yspace;         /* top edge of character */
3044   ymid = (ytop + Ypos) * 0.5;   /* vertical mid point */
3045
3046   /* width_fac defines the width of the Arrow in terms of the height of the characters */
3047
3048   hline_w = 0.5 * (width_fac * (ytop - Ypos));
3049
3050   PSmoveto(Xpos,Ypos,outf);
3051   PSlineto(xright,ymid,outf);
3052   PSlineto(Xpos,ytop,outf);
3053   PSlineto(Xpos,Ypos,outf);
3054
3055 }
3056
3057 void ALDrawLeftArrow(float Xpos,float Ypos, float Xspace, float Yspace, float width_fac,FILE *outf)
3058
3059 {
3060   float xright,ytop;
3061   float ymid;
3062   float hline_w;
3063
3064   xright = Xpos + Xspace;       /* right hand edge of character (lhe of next character) */
3065   ytop = Ypos + Yspace;         /* top edge of character */
3066   ymid = (ytop + Ypos) * 0.5;   /* vertical mid point */
3067
3068   /* width_fac defines the width of the Arrow in terms of the height of the characters */
3069
3070   hline_w = 0.5 * (width_fac * (ytop - Ypos));
3071
3072   PSmoveto(xright,Ypos,outf);
3073   PSlineto(xright,ytop,outf);
3074   PSlineto(Xpos,ymid,outf);
3075   PSlineto(xright,Ypos,outf);
3076
3077
3078
3079 void ALDrawUpArrow(float Xpos,float Ypos, float Xspace, float Yspace, float width_fac,FILE *outf)
3080
3081 {
3082   float xright,ytop;
3083   float ymid;
3084   float hline_w;
3085   float xmid;
3086
3087   xright = Xpos + Xspace;       /* right hand edge of character (lhe of next character) */
3088   ytop = Ypos + Yspace;         /* top edge of character */
3089   ymid = (ytop + Ypos) * 0.5;   /* vertical mid point */
3090   xmid = (xright + Xpos) * 0.5;   /* horizontal mid point */
3091
3092   hline_w = 0.5 * (width_fac * (ytop - Ypos));
3093
3094   PSmoveto(Xpos,Ypos,outf);
3095   PSlineto(xright,Ypos,outf);
3096   PSlineto(xmid,ytop,outf);
3097   PSlineto(Xpos,Ypos,outf);
3098
3099
3100 void ALDrawDownArrow(float Xpos,float Ypos, float Xspace, float Yspace, float width_fac,FILE *outf)
3101
3102 {
3103   float xright,ytop;
3104   float ymid;
3105   float hline_w;
3106   float xmid;
3107
3108   xright = Xpos + Xspace;       /* right hand edge of character (lhe of next character) */
3109   ytop = Ypos + Yspace;         /* top edge of character */
3110   ymid = (ytop + Ypos) * 0.5;   /* vertical mid point */
3111   xmid = (xright + Xpos) * 0.5;   /* horizontal mid point */
3112
3113   hline_w = 0.5 * (width_fac * (ytop - Ypos));
3114
3115   PSmoveto(Xpos,ytop,outf);
3116   PSlineto(xright,ytop,outf);
3117   PSlineto(xmid,Ypos,outf);
3118   PSlineto(Xpos,ytop,outf);
3119
3120
3121 /* Draw a small up arrow. mok 980917 */
3122 void ALDrawSmallUpArrow(float Xpos,float Ypos, float Xspace, float Yspace, float width_fac,FILE *outf)
3123
3124 {
3125   float xright,ytop;
3126   float ymid;
3127   float xmid;
3128   float x,y;
3129
3130   xright = Xpos + Xspace;       /* right hand edge of character (lhe of next character) */
3131   ytop = Ypos + Yspace;         /* top edge of character */
3132   ymid = (ytop + Ypos) * 0.5;   /* vertical mid point */
3133   xmid = (xright + Xpos) * 0.5; /* horizontal mid point */
3134
3135   PSmoveto(xmid, ytop, outf);
3136   x = Xpos + (xright-Xpos)/5.0;   y = Ypos + 2.0*(ytop-Ypos)/3.0;
3137   PSlineto(x,y,outf);
3138   x = Xpos + 2.0*(xright-Xpos)/5.0;
3139   PSlineto(x, y, outf);
3140   PSlineto (x, Ypos, outf);
3141   x = Xpos + 3.0*(xright-Xpos)/5.0;
3142   PSlineto (x, Ypos, outf);
3143   PSlineto(x, y, outf);
3144   x = Xpos + 4.0*(xright-Xpos)/5.0;
3145   PSlineto(x, y, outf);
3146   PSlineto(xmid, ytop, outf);
3147
3148
3149 /* Draw a small down arrow. mok 980917 */
3150 void ALDrawSmallDownArrow(float Xpos,float Ypos, float Xspace, float Yspace, float width_fac,FILE *outf)
3151
3152 {
3153   float xright,ytop;
3154   float ymid;
3155   float xmid;
3156   float x,y;
3157
3158   xright = Xpos + Xspace;       /* right hand edge of character (lhe of next character) */
3159   ytop = Ypos + Yspace;         /* top edge of character */
3160   ymid = (ytop + Ypos) * 0.5;   /* vertical mid point */
3161   xmid = (xright + Xpos) * 0.5; /* horizontal mid point */
3162
3163   PSmoveto(xmid, Ypos, outf);
3164   x = Xpos + 4.0*(xright-Xpos)/5.0;   y = Ypos + (ytop-Ypos)/3.0;
3165   PSlineto(x,y,outf);
3166   x = Xpos + 3.0*(xright-Xpos)/5.0;
3167   PSlineto(x, y, outf);
3168   PSlineto (x, ytop, outf);
3169   x = Xpos + 2.0*(xright-Xpos)/5.0;
3170   PSlineto (x, ytop, outf);
3171   PSlineto(x, y, outf);
3172   x = Xpos + (xright-Xpos)/5.0;
3173   PSlineto(x, y, outf);
3174   PSlineto(xmid, Ypos, outf);
3175
3176
3177 void ALDrawCircle(float Xpos,float Ypos, float Xspace, float Yspace, float width_fac,FILE *outf)
3178
3179 {
3180   float xright,ytop;
3181   float ymid;
3182   float hline_w;
3183   float xmid;
3184
3185   xright = Xpos + Xspace;       /* right hand edge of character (lhe of next character) */
3186   ytop = Ypos + Yspace;         /* top edge of character */
3187   ymid = (ytop + Ypos) * 0.5;   /* vertical mid point */
3188   xmid = (xright + Xpos) * 0.5;   /* horizontal mid point */
3189
3190   hline_w = 0.5 * (width_fac * (ytop - Ypos));
3191
3192   PSnewpath(outf);
3193
3194   fprintf(outf,"%.2f %.2f %.2f %d %d arc\n",xmid,ymid,(ytop - Ypos)*0.5,0,360);
3195
3196
3197
3198 /* Draw a diamond. mok 980917 */
3199 void ALDrawDiamond(float Xpos,float Ypos, float Xspace, float Yspace, float width_fac,FILE *outf)
3200
3201 {
3202   float xright,ytop;
3203   float ymid;
3204   float hline_w;
3205   float xmid;
3206
3207   xright = Xpos + Xspace;       /* right hand edge of character (lhe of next character) */
3208   ytop = Ypos + Yspace;         /* top edge of character */
3209   ymid = (ytop + Ypos) * 0.5;   /* vertical mid point */
3210   xmid = (xright + Xpos) * 0.5; /* horizontal mid point */
3211
3212   PSmoveto(Xpos, ymid, outf);
3213   PSlineto(xmid, ytop, outf);
3214   PSlineto(xright, ymid, outf);
3215   PSlineto(xmid, Ypos, outf);
3216   PSlineto(Xpos, ymid, outf);
3217
3218
3219 /* Draw a bar. mok 980917 */
3220 void ALDrawBar(float Xpos,float Ypos, float Xspace, float Yspace, float width_fac,FILE *outf)
3221
3222 {
3223   float xright;
3224   float y1, y2;
3225   
3226   xright = Xpos + Xspace;       /* right hand edge of character (lhe of next character) */
3227
3228   y1 = Ypos + 2.0*(Ypos+Yspace)/5.0;
3229   y2 = Ypos + 3.0*(Ypos+Yspace)/5.0;
3230
3231   PSmoveto(Xpos, y1, outf);
3232   PSlineto(xright, y1, outf);
3233   PSlineto(xright, y2, outf);
3234   PSlineto(Xpos, y2, outf);
3235   PSlineto(Xpos, y1, outf);
3236
3237
3238 void ALDrawPseudoEllipse(float Xpos,float Ypos, float Xspace, float Yspace, float width_fac,
3239                          FILE *outf)
3240
3241 {
3242   /* draws a pseudo ellipse in the box bounded by Xpos,Ypos, Xpos+Xspace, Ypos+Yspace */
3243   float xright,ytop;
3244   float ymid;
3245   float hline_w;
3246   float xmid;
3247   float xefact = 0.2;   /* this shifts the guide points by 0.2 towards the axis */
3248                        /* should not really be hard wired */
3249   float yefact = 0.0;
3250
3251   float xbit,ybit;
3252
3253   xright = Xpos + Xspace;       /* right hand edge of character (lhe of next character) */
3254   ytop = Ypos + Yspace;         /* top edge of character */
3255   ymid = (ytop + Ypos) * 0.5;   /* vertical mid point */
3256   xmid = (xright + Xpos) * 0.5;   /* horizontal mid point */
3257   xbit = Xspace * xefact;
3258   ybit = Yspace * yefact;
3259
3260   hline_w = 0.5 * (width_fac * (ytop - Ypos));
3261
3262   PSnewpath(outf);
3263
3264   PSmoveto(xmid,Ypos,outf);
3265   
3266   fprintf(outf,"%.2f %.2f %.2f %.2f %.2f %.2f curveto\n",
3267           Xpos+xbit,Ypos+ybit,Xpos+xbit,ytop-ybit,xmid,ytop);
3268   fprintf(outf,"%.2f %.2f %.2f %.2f %.2f %.2f curveto\n",
3269           xright-xbit,ytop-ybit,xright-xbit,Ypos+ybit,xmid,Ypos);
3270
3271
3272 void ALDrawLeftSemiEnd(float Xpos,float Ypos, float Xspace, float Yspace, float width_fac,FILE *outf)
3273
3274 {
3275   float xright,ytop;
3276   float ymid;
3277   float hline_w;
3278   float xmid;
3279
3280   xright = Xpos + Xspace;       /* right hand edge of character (lhe of next character) */
3281   ytop = Ypos + Yspace;         /* top edge of character */
3282   ymid = (ytop + Ypos) * 0.5;   /* vertical mid point */
3283   xmid = (xright + Xpos) * 0.5;   /* horizontal mid point */
3284
3285   hline_w = 0.5 * (width_fac * (ytop - Ypos));
3286
3287   PSnewpath(outf);
3288
3289   fprintf(outf,"%.2f %.2f %.2f %d %d arc\n",xmid,ymid,(ytop - Ypos) *0.5,270,90);
3290
3291   PSlineto(xright,ytop,outf);
3292   PSlineto(xright,Ypos,outf);
3293   PSlineto(xmid,Ypos,outf);
3294   
3295
3296 void ALDrawRightSemiEnd(float Xpos,float Ypos, float Xspace, float Yspace, float width_fac,FILE *outf)
3297
3298 {
3299   float xright,ytop;
3300   float ymid;
3301   float hline_w;
3302   float xmid;
3303
3304   xright = Xpos + Xspace;       /* right hand edge of character (lhe of next character) */
3305   ytop = Ypos + Yspace;         /* top edge of character */
3306   ymid = (ytop + Ypos) * 0.5;   /* vertical mid point */
3307   xmid = (xright + Xpos) * 0.5;   /* horizontal mid point */
3308
3309   hline_w = 0.5 * (width_fac * (ytop - Ypos));
3310
3311   PSnewpath(outf);
3312   fprintf(outf,"%f %f %f %d %d arc\n",xmid,ymid,(ytop - Ypos) *0.5,90,270);
3313
3314   PSlineto(Xpos,Ypos,outf);
3315   PSlineto(Xpos,ytop,outf);
3316   PSlineto(xmid,ytop,outf);
3317
3318 void ALDrawRightHalfHorizLine(
3319                      float Xpos,       /* bottom left hand corner of character posn */
3320                      float Ypos,       /* */
3321                      float Xspace,     /* horizontal width of character position */
3322                      float Yspace,     /* vertical height of character position */
3323                      float width_fac, FILE *outf)  /* proportion of vertical height that the line will fill */
3324
3325 /* draw line from midpoint to right of position */
3326
3327
3328 {
3329   float xright,ytop;
3330   float ymid;
3331   float hline_w;
3332   float xmid;
3333
3334   xright = Xpos + Xspace;       /* right hand edge of character (lhe of next character) */
3335   ytop = Ypos + Yspace;         /* top edge of character */
3336   ymid = (ytop + Ypos) * 0.5;   /* vertical mid point */
3337   xmid = (xright + Xpos) * 0.5;   /* horizontal mid point */
3338
3339   /* width_fac defines the width of the line in terms of the height of the characters */
3340
3341   hline_w = 0.5 * (width_fac * (ytop - Ypos));
3342
3343   PSmoveto(xmid,ymid-hline_w,outf);
3344   PSlineto(xmid,ymid+hline_w,outf);
3345   PSlineto(xright,ymid+hline_w,outf);
3346   PSlineto(xright,ymid-hline_w,outf);
3347   PSlineto(xmid,ymid-hline_w,outf);
3348
3349
3350 void ALDrawLeftHalfHorizLine(
3351                      float Xpos,       /* bottom left hand corner of character posn */
3352                      float Ypos,       /* */
3353                      float Xspace,     /* horizontal width of character position */
3354                      float Yspace,     /* vertical height of character position */
3355                      float width_fac, FILE *outf)  /* proportion of vertical height that the line will fill */
3356
3357 /* draw line from midpoint to left of position */
3358
3359 {
3360   float xright,ytop;
3361   float ymid;
3362   float hline_w;
3363   float xmid;
3364
3365   xright = Xpos + Xspace;       /* right hand edge of character (lhe of next character) */
3366   ytop = Ypos + Yspace;         /* top edge of character */
3367   ymid = (ytop + Ypos) * 0.5;   /* vertical mid point */
3368   xmid = (xright + Xpos) * 0.5;   /* horizontal mid point */
3369
3370   /* width_fac defines the width of the line in terms of the height of the characters */
3371
3372   hline_w = 0.5 * (width_fac * (ytop - Ypos));
3373
3374   PSmoveto(xmid,ymid-hline_w,outf);
3375   PSlineto(xmid,ymid+hline_w,outf);
3376   PSlineto(Xpos,ymid+hline_w,outf);
3377   PSlineto(Xpos,ymid-hline_w,outf);
3378   PSlineto(xmid,ymid-hline_w,outf);
3379
3380
3381 void PSmoveto(float x,float y,FILE *outf)
3382 {
3383   fprintf(outf,"%.2f %.2f moveto\n",x,y);
3384 }
3385 void PSlineto(float x,float y,FILE *outf)
3386 {
3387   fprintf(outf,"%.2f %.2f lineto\n",x,y);
3388 }
3389 void PSPutSpecialText(float Xpos,float Ypos,float Xspace,float Yspace,char *text,
3390                       unsigned char current_col,
3391                       unsigned char background_colour,float YspaceFactor,FILE *outf)
3392 /* Handle the special text characters */
3393 {
3394
3395   Yspace *= YspaceFactor;  /* shrink the Y axis a little to avoid clashes.*/
3396
3397
3398   if(strcmp(text,"@horizline") == 0){
3399     ALDrawHorizLine(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3400     PSstroke(outf);
3401   }else if(strcmp(text,"@fhorizline") == 0){
3402     ALDrawHorizLine(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3403     PSstroke(outf);
3404     ALDrawHorizLine(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3405     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3406
3407   }else if(strcmp(text,"@thickhorizline") == 0){
3408     ALDrawHorizLine(Xpos,Ypos,Xspace,Yspace,1.0,outf);
3409     PSstroke(outf);
3410   }else if(strcmp(text,"@fthickhorizline") == 0){
3411     ALDrawHorizLine(Xpos,Ypos,Xspace,Yspace,1.0,outf);
3412     PSstroke(outf);
3413     ALDrawHorizLine(Xpos,Ypos,Xspace,Yspace,1.0,outf);
3414     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3415
3416   }else if(strcmp(text,"@thinhorizline") == 0){
3417     ALDrawHorizLine(Xpos,Ypos,Xspace,Yspace,0.1,outf);
3418     PSstroke(outf);
3419   }else if(strcmp(text,"@fthinhorizline") == 0){
3420     ALDrawHorizLine(Xpos,Ypos,Xspace,Yspace,0.1,outf);
3421     PSstroke(outf);
3422     ALDrawHorizLine(Xpos,Ypos,Xspace,Yspace,0.1,outf);
3423     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3424
3425   }else if(strcmp(text,"@rightarrow") == 0){
3426     ALDrawRightArrow(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3427     PSstroke(outf);
3428   }else if(strcmp(text,"@frightarrow") == 0){
3429 /*    ALDrawRightArrow(Xpos,Ypos,Xspace,Yspace,0.5,outf);*/
3430 /* temporary change to the right arrow width 20/1/1995*/
3431     ALDrawRightArrow(Xpos,Ypos,(Xspace*0.7),Yspace,0.5,outf);
3432     PSstroke(outf);
3433     ALDrawRightArrow(Xpos,Ypos,(Xspace*0.7),Yspace,0.5,outf);
3434     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3435
3436   }else if(strcmp(text,"@leftarrow") == 0){
3437     ALDrawLeftArrow(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3438     PSstroke(outf);
3439   }else if(strcmp(text,"@fleftarrow") == 0){
3440     ALDrawLeftArrow(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3441     PSstroke(outf);
3442     ALDrawLeftArrow(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3443     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3444
3445   }else if(strcmp(text,"@uparrow") == 0){
3446     ALDrawUpArrow(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3447     PSstroke(outf);
3448   }else if(strcmp(text,"@fuparrow") == 0){
3449     ALDrawUpArrow(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3450     PSstroke(outf);
3451     ALDrawUpArrow(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3452     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3453
3454   }else if(strcmp(text,"@suparrow") == 0){
3455     ALDrawSmallUpArrow(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3456     PSstroke(outf);
3457   }else if(strcmp(text,"@fsuparrow") == 0){
3458     ALDrawSmallUpArrow(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3459     PSstroke(outf);
3460     ALDrawSmallUpArrow(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3461     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3462
3463   }else if(strcmp(text,"@downarrow") == 0){
3464     ALDrawDownArrow(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3465     PSstroke(outf);
3466   }else if(strcmp(text,"@fdownarrow") == 0){
3467     ALDrawDownArrow(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3468     PSstroke(outf);
3469     ALDrawDownArrow(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3470     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3471
3472   }else if(strcmp(text,"@sdownarrow") == 0){
3473     ALDrawSmallDownArrow(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3474     PSstroke(outf);
3475   }else if(strcmp(text,"@fsdownarrow") == 0){
3476     ALDrawSmallDownArrow(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3477     PSstroke(outf);
3478     ALDrawSmallDownArrow(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3479     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3480
3481   }else if(strcmp(text,"@circle") == 0){
3482     ALDrawCircle(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3483     PSstroke(outf);
3484   }else if(strcmp(text,"@fcircle") == 0){
3485     ALDrawCircle(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3486     PSstroke(outf);
3487     ALDrawCircle(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3488     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3489
3490   }else if(strcmp(text,"@diamond") == 0){
3491     ALDrawDiamond(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3492     PSstroke(outf);
3493   }else if(strcmp(text,"@fdiamond") == 0){
3494     ALDrawDiamond(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3495     PSstroke(outf);
3496     ALDrawDiamond(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3497     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3498
3499   }else if(strcmp(text,"@bar") == 0){
3500     ALDrawBar(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3501     PSstroke(outf);
3502   }else if(strcmp(text,"@fbar") == 0){
3503     ALDrawBar(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3504     PSstroke(outf);
3505     ALDrawBar(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3506     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3507
3508   }else if(strcmp(text,"@leftsemiend") == 0){
3509     ALDrawLeftSemiEnd(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3510     PSstroke(outf);
3511   }else if(strcmp(text,"@fleftsemiend") == 0){
3512     ALDrawLeftSemiEnd(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3513     PSstroke(outf);
3514     ALDrawLeftSemiEnd(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3515     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3516
3517   }else if(strcmp(text,"@rightsemiend") == 0){
3518     ALDrawRightSemiEnd(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3519     PSstroke(outf);
3520   }else if(strcmp(text,"@frightsemiend") == 0){
3521     ALDrawRightSemiEnd(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3522     PSstroke(outf);
3523     ALDrawRightSemiEnd(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3524     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3525
3526   }else if(strcmp(text,"@lefthelixend") == 0){
3527
3528     ALDrawRightHalfHorizLine(Xpos,Ypos,Xspace,Yspace,1.0,outf);
3529     PSstroke(outf);
3530     ALDrawRightHalfHorizLine(Xpos,Ypos,Xspace,Yspace,1.0,outf);
3531     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3532
3533     ALDrawPseudoEllipse(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3534     fprintf(outf,"closepath \n C%-d \n fill \n",background_colour);
3535
3536     ALDrawLeftHalfHorizLine(Xpos,Ypos,Xspace,Yspace,0.1,outf);
3537     PSstroke(outf);
3538     ALDrawLeftHalfHorizLine(Xpos,Ypos,Xspace,Yspace,0.1,outf);
3539     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3540
3541     ALDrawPseudoEllipse(Xpos,Ypos,Xspace,Yspace,0.5,outf);
3542     PSstroke(outf);
3543
3544   }else if(strcmp(text,"@righthelixend") == 0){
3545
3546     ALDrawLeftHalfHorizLine(Xpos,Ypos,Xspace,Yspace,1.0,outf);
3547     PSstroke(outf);
3548     ALDrawLeftHalfHorizLine(Xpos,Ypos,Xspace,Yspace,1.0,outf);
3549     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3550
3551     ALDrawPseudoEllipse(Xpos,Ypos,Xspace,Yspace,1.0,outf);
3552     PSstroke(outf);
3553     ALDrawPseudoEllipse(Xpos,Ypos,Xspace,Yspace,1.0,outf);
3554     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3555
3556     ALDrawRightHalfHorizLine(Xpos,Ypos,Xspace,Yspace,0.1,outf);
3557     PSstroke(outf);
3558     ALDrawRightHalfHorizLine(Xpos,Ypos,Xspace,Yspace,0.1,outf);
3559     fprintf(outf,"closepath \n C%-d \n fill \n",current_col);
3560
3561
3562   }else{
3563     fprintf(stderr,"Error:  Unrecognised special character: %s\n",text);
3564     error(" ",1);
3565   }
3566 }
3567
3568 void PSstroke(FILE *outf)
3569 {
3570   fprintf(outf,"stroke\n");
3571 }
3572
3573 void PSnewpath(FILE *outf)
3574 {
3575   fprintf(outf,"newpath\n");
3576 }
3577
3578 void ALColourBackground(FILE *outf,int colour, int *b_region)
3579 {
3580     int x1,y1,x2,y2;
3581     x1 = b_region[0];
3582     x2 = b_region[2];
3583     y1 = b_region[1];
3584     y2 = b_region[3];
3585
3586    fprintf(outf,"%d %d moveto %d %d lineto %d %d lineto %d %d lineto %d %d lineto closepath\n",
3587                x1,y1,x2,y1,x2,y2,x1,y2,x1,y1);
3588    fprintf(outf," C%-d \n fill \n",colour);
3589    /* reset the colour to white */
3590    /*   fprintf(outf," C99\n");*/
3591 }
3592
3593 void ALCheckLegalRange(int sx,int sy, int ex, int ey, int xmin, int ymin, int xmax, int ymax)
3594 /* check if sx, sy, ex, ey are within the limits given by xmin, ymin, xmax, ymax */
3595 {
3596     extern FILE *std_err;
3597     if(   sx >= xmin && sx <= xmax
3598        && sy >= ymin && sy <= ymax
3599        && ex <= xmax && ex >= xmin
3600        && ey <= ymax && ey >= ymin){
3601         return;
3602     }else{
3603         fprintf(std_err,"\n\nALSCRIPT COMMAND FILE ERROR:\n");
3604         fprintf(std_err,"Maximum legal range:\n");
3605         fprintf(std_err,"From position %d of sequence %d to position %d of sequence %d\n",
3606                 xmin,ymin,xmax,ymax);
3607
3608         fprintf(std_err,"Your range:\n");
3609         fprintf(std_err,"From position %d of sequence %d to position %d of sequence %d\n",
3610                 sx,sy,ex,ey);
3611
3612         GJerror("Range too big for alignment - try again!");
3613         exit(0);
3614     }
3615 }
3616
3617 void ALMakeHelixText(int sx, int sy, int ex, char ***texts)
3618 {
3619     int i;
3620     texts[sx][sy] = GJstrdup("@lefthelixend");
3621     texts[ex][sy] = GJstrdup("@righthelixend");
3622     for(i=sx+1;i<ex;++i){
3623         texts[i][sy] = GJstrdup("@fthickhorizline");
3624     }
3625 }
3626
3627 void ALMakeStrandText(int sx, int sy, int ex, char ***texts)
3628 {
3629     int i;
3630     texts[ex][sy] = GJstrdup("@frightarrow");
3631     for(i=sx;i<ex;++i){
3632         texts[i][sy] = GJstrdup("@fhorizline");
3633     }
3634 }
3635
3636 void ALMakeCoilText(int sx, int sy, int ex, char ***texts)
3637 {
3638     int i;
3639     for(i=sx;i<ex+1;++i){
3640         texts[i][sy] = GJstrdup("@fthinhorizline");
3641     }
3642 }
3643
3644 int ALrel(char *pos,int *relnum)
3645 /* ALrel: parses a string that defines a position in a sequence.  This can
3646 have the form
3647
3648 to indicate position 10          10
3649 to indicate three before 10      10-3
3650 to indicate five after 10        10+5
3651
3652 The routine looks up the relative number in *relnum before adding or
3653 subtracting numbers, the end result is therefore relative to the current 
3654 alignment position.
3655
3656 It should be easy to extend this routine for the relative movement to
3657 apply to positions in another sequence rather than alignment
3658 coordinates.  (e.g. 10+5:73  might mean 5 after the current position in sequence 73).
3659 */
3660
3661 {
3662      int i;
3663      int len;
3664      char *token;
3665      int ipos,ioff;  /* position and offset */
3666      extern FILE *std_in,*std_out,*std_err;
3667
3668      len = strlen(pos);
3669      ioff = 0;
3670      ipos = 0;
3671
3672      
3673      if(strchr(pos,'+') != NULL){
3674          token = strtok(pos,"+");
3675          if(strlen(token)== 0){
3676              error("Error decoding position",1);
3677              fprintf(std_err,"Offending string is: %s\n",pos);
3678          }else{
3679              ipos = atoi(token);
3680          }
3681          token = strtok(NULL,"\0");
3682          if(strlen(token)== 0){
3683              error("Error decoding position",1);
3684              fprintf(std_err,"Offending string is: %s\n",pos);
3685          }else{
3686              ioff = atoi(token);
3687          }
3688          return (relnum[ipos] + ioff);
3689      }else if(strchr(pos,'-') != NULL){
3690          token = strtok(pos,"-");
3691          if(strlen(token)== 0){
3692              error("Error decoding position",1);
3693              fprintf(std_err,"Offending string is: %s\n",pos);
3694          }else{
3695              ipos = atoi(token);
3696          }
3697          token = strtok(NULL,"\0");
3698          if(strlen(token)== 0){
3699              error("Error decoding position",1);
3700              fprintf(std_err,"Offending string is: %s\n",pos);
3701          }else{
3702              ioff = atoi(token);
3703          }
3704          return (relnum[ipos] - ioff);
3705      }else{
3706          ipos = atoi(pos);
3707          return relnum[ipos];
3708      }
3709 }
3710
3711 int *ALCalCons(struct seqdat *bloc,
3712                 int sx,int sy,int ex,int ey,int *ret_val,int len)
3713
3714 /* Calculate conservation for an alignment - this can be just a segment of an alignment */
3715 /* bloc = the alignment bloc */
3716 /* sx,sy,ex,ey = the positions over which to calculate the conservation */
3717 /* conscut = conservation number cutoff ( an integer 0 - 10) */
3718 /* ret_val = a pointer to an integer array to store the results of the calculation */
3719 /* len = the length of the array ret_val - this must be the same as the alignment length */
3720
3721 {
3722     int i,j,tlen,k;
3723     char *temp;
3724     char *temp2;
3725     float tval;
3726     int gcount;
3727
3728     tlen = ey -sy + 1;
3729     temp = GJstrcreate(tlen+1,NULL);
3730     if(ret_val == NULL){
3731         ret_val = (int *) GJmalloc(sizeof(int) * len);
3732     }
3733
3734     for(i=sx;i<(ex+1);++i){
3735         /* calculate conservation at each position */
3736         k = 0;
3737         for(j=sy;j<(ey+1);++j){
3738             temp[k] = bloc[j].seq[i];
3739             ++k;
3740         }
3741         temp2 = GJstoupper(temp);
3742         /* check for all gap columns */
3743         gcount = 0;
3744         for(j=0;j<tlen;++j){
3745             if(temp2[j] == ' ') ++gcount;
3746         }
3747         if(gcount == tlen){
3748             tval = 0.0;
3749         }else{
3750             tval = mzcons((unsigned char *)temp2,tlen);
3751         }
3752 /*      fprintf(stderr,"In calcons: i:%d tlen:%d temp:%s tval:%f\n",i,tlen,temp,tval);*/
3753         ret_val[i] = 10 * tval;
3754         GJfree(temp2);
3755     }
3756     GJfree(temp);
3757     return ret_val;
3758 }
3759
3760 float mzcons(unsigned char *pos,int n)
3761 /* calculate conservation value according to Zvelebil et al for a set
3762    of amino acids and gaps stored in string pos of length n
3763    translated from the fortran mzcons.f 6/3/1995
3764 */
3765
3766 {
3767     /* --  conmat contains a table like that shown in the JMB paper
3768        order of amino acids is GAP,ARNDCQEGHILKMFPSTWYVBZX
3769     */
3770     static char *acids = " ARNDCQEGHILKMFPSTWYVBZX";
3771     static int conmat[24][10] = {
3772         {1,1,1,1,1,1,1,1,1,1},  /*  */
3773         {1,0,0,0,0,1,1,0,0,0},  /*A */
3774         {0,1,0,1,1,0,0,0,0,0},  /*R */ 
3775         {0,0,0,1,0,1,0,0,0,0},  /*N */
3776         {0,0,1,1,1,1,0,0,0,0},  /*D */ 
3777         {1,0,0,0,0,1,0,0,0,0},  /*C */ 
3778         {0,0,0,1,0,0,0,0,0,0},  /*Q */
3779         {0,0,1,1,1,0,0,0,0,0},  /*E */
3780         {1,0,0,0,0,1,1,0,0,0},  /*G */
3781         {1,1,0,1,1,0,0,0,1,0},  /*H */
3782         {1,0,0,0,0,0,0,1,0,0},  /*I */
3783         {1,0,0,0,0,0,0,1,0,0},  /*L */
3784         {1,1,0,1,1,0,0,0,0,0},  /*K */
3785         {1,0,0,0,0,0,0,0,0,0},  /*M */
3786         {1,0,0,0,0,0,0,0,1,0},  /*F */
3787         {0,0,0,0,0,1,0,0,0,1},  /*P */
3788         {0,0,0,1,0,1,1,0,0,0},  /*S */
3789         {1,0,0,1,0,1,0,0,0,0},  /*T */
3790         {1,0,0,1,0,0,0,0,1,0},  /*W */
3791         {1,0,0,1,0,0,0,0,1,0},  /*Y */
3792         {1,0,0,0,0,1,0,1,0,0},  /*V */
3793         {0,0,0,1,0,0,0,0,0,0},  /*B */
3794         {0,0,0,1,0,0,0,0,0,0},  /*Z */
3795         {1,1,1,1,1,1,1,1,1,1}   /*X */
3796     };
3797
3798     int concnt,it,i,j,k,l,tcnt,ibseq;
3799     int nide;
3800     float con;
3801     unsigned char facid;
3802
3803     concnt = 0;
3804     for(j=0;j<10;++j){
3805         /*found: outer loop over properties
3806         set IT to the value of the first amino acid*/
3807         it = conmat[GJindex(acids,pos[0])][j];
3808         /*loop over remaining acids, if a difference occurs then
3809         set tcnt to 1*/
3810         tcnt = 0;
3811         for(k=1;k<n;++k){
3812            if(it != conmat[GJindex(acids,pos[k])][j]){
3813                 tcnt = 1;
3814            }
3815         }
3816         /*add tcnt to concnt*/
3817         concnt += tcnt;
3818     }
3819     /* check for total identity at this position*/
3820     facid = pos[0];
3821     nide = 0;
3822     for(k=1;k<n;++k){
3823         if(facid == pos[k]){
3824              ++nide;
3825         }
3826     }
3827
3828     /*calculate the conservation*/
3829     if(concnt == 10){
3830       con = 0.0;
3831     }else if(concnt == 0){
3832         if(nide == (n-1)){
3833             /*total identity*/
3834             con = 1.0;
3835         }else{
3836             /*not identity, but same properties*/
3837               con = 0.9;
3838         }
3839     }else{
3840         con = 0.9 - 0.1 * concnt;
3841     }
3842     return con;
3843 }
3844
3845
3846 int GJindex(char *str,char c)
3847 {
3848     char *t;
3849     t = strchr(str,c);
3850     if(t == NULL) return -1;
3851     return (int) (t - str);
3852 }
3853