1 /*@z42.c:Colour Service:ColourChange, ColourCommand@**************************/
2 /*                                                                           */
3 /*  THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.39)                       */
4 /*  COPYRIGHT (C) 1991, 2008 Jeffrey H. Kingston                             */
5 /*                                                                           */
6 /*  Jeffrey H. Kingston (jeff@it.usyd.edu.au)                                */
7 /*  School of Information Technologies                                       */
8 /*  The University of Sydney 2006                                            */
9 /*  AUSTRALIA                                                                */
10 /*                                                                           */
11 /*  This program is free software; you can redistribute it and/or modify     */
12 /*  it under the terms of the GNU General Public License as published by     */
13 /*  the Free Software Foundation; either Version 3, or (at your option)      */
14 /*  any later version.                                                       */
15 /*                                                                           */
16 /*  This program is distributed in the hope that it will be useful,          */
17 /*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
18 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
19 /*  GNU General Public License for more details.                             */
20 /*                                                                           */
21 /*  You should have received a copy of the GNU General Public License        */
22 /*  along with this program; if not, write to the Free Software              */
23 /*  Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA   */
24 /*                                                                           */
25 /*  FILE:         z42.c                                                      */
26 /*  MODULE:       Colour Service                                             */
27 /*  EXTERNS:      ColourChange(), ColourCommand()                            */
28 /*                                                                           */
29 /*****************************************************************************/
30 #include "externs.h"
31 #define INIT_COLOUR_NUM	100
32 
33 
34 /*****************************************************************************/
35 /*                                                                           */
36 /*  COLOUR_TABLE                                                             */
37 /*                                                                           */
38 /*  A symbol table permitting access to colour records by number or name.    */
39 /*  The table will automatically enlarge to accept any number of entries,    */
40 /*  but there is an arbitrary limit of 65535 colours imposed so that colour  */
41 /*  numbers can be stored in 16 bit fields.                                  */
42 /*                                                                           */
43 /*     ctab_new(newsize)                 New empty table, newsize capacity   */
44 /*     ctab_insert(x, &S)                Insert new colour object x into S   */
45 /*     ctab_retrieve(str, S)             Retrieve colour object of name str  */
46 /*     ctab_num(S, num)                  Retrieve colour object, number num  */
47 /*     ctab_debug(S, fp)                 Debug print of table S to file fp   */
48 /*                                                                           */
49 /*****************************************************************************/
50 
51 typedef struct
52 { int coltab_size;				/* size of table             */
53   int coltab_count;				/* number of colours held    */
54   struct coltab_rec
55   {	OBJECT	by_number;			/* colour record by number   */
56 	OBJECT	by_name_hash;			/* colour record by name     */
57   } coltab[1];
58 } *COLOUR_TABLE;
59 
60 #define	ctab_size(S)	(S)->coltab_size
61 #define	ctab_count(S)	(S)->coltab_count
62 #define	ctab_num(S, i)	(S)->coltab[i].by_number
63 #define	ctab_name(S, i)	(S)->coltab[i].by_name_hash
64 
65 #define hash(pos, str, S)						\
66 { FULL_CHAR *p = str;							\
67   pos = *p++;								\
68   while( *p ) pos += *p++;						\
69   pos = pos % ctab_size(S);						\
70 }
71 
ctab_new(int newsize)72 static COLOUR_TABLE ctab_new(int newsize)
73 { COLOUR_TABLE S;  int i;
74   ifdebug(DMA, D, DebugRegisterUsage(MEM_COLOUR_TAB, 1,
75     2*sizeof(int) + newsize * sizeof(struct coltab_rec)));
76   S = (COLOUR_TABLE) malloc(2*sizeof(int) + newsize * sizeof(struct coltab_rec));
77   if( S == (COLOUR_TABLE) NULL )
78     Error(42, 1, "ran out of memory when enlarging colour table",
79       FATAL, no_fpos);
80   ctab_size(S) = newsize;
81   ctab_count(S) = 0;
82   for( i = 0;  i < newsize;  i++ )
83   { ctab_num(S, i) = ctab_name(S, i) = nilobj;
84   }
85   return S;
86 } /* end ctab_new */
87 
88 static void ctab_insert(OBJECT x, COLOUR_TABLE *S);
89 
ctab_rehash(COLOUR_TABLE S,int newsize)90 static COLOUR_TABLE ctab_rehash(COLOUR_TABLE S, int newsize)
91 { COLOUR_TABLE NewS;  int i;
92   NewS = ctab_new(newsize);
93   for( i = 1;  i <= ctab_count(S);  i++ )
94      ctab_insert(ctab_num(S, i), &NewS);
95   for( i = 0;  i < ctab_size(S);  i++ )
96   { if( ctab_name(S, i) != nilobj )  DisposeObject(ctab_name(S, i));
97   }
98   ifdebug(DMA, D, DebugRegisterUsage(MEM_COLOUR_TAB, -1,
99     -(2*sizeof(int) + ctab_size(S) * sizeof(struct coltab_rec))));
100   free(S);
101   return NewS;
102 } /* end ctab_rehash */
103 
ctab_insert(OBJECT x,COLOUR_TABLE * S)104 static void ctab_insert(OBJECT x, COLOUR_TABLE *S)
105 { int pos, num;
106   if( ctab_count(*S) == ctab_size(*S) - 1 )	/* one less since 0 unused */
107     *S = ctab_rehash(*S, 2*ctab_size(*S));
108   num = ++ctab_count(*S);
109   if( num > MAX_COLOUR )
110     Error(42, 2, "too many colours (maximum is %d)",
111       FATAL, &fpos(x), MAX_COLOUR);
112   hash(pos, string(x), *S);
113   if( ctab_name(*S, pos) == nilobj )  New(ctab_name(*S, pos), ACAT);
114   Link(ctab_name(*S, pos), x);
115   word_colour(x) = num;
116   ctab_num(*S, num) = x;
117 } /* end ctab_insert */
118 
ctab_retrieve(FULL_CHAR * str,COLOUR_TABLE S)119 static OBJECT ctab_retrieve(FULL_CHAR *str, COLOUR_TABLE S)
120 { OBJECT x, link, y;  int pos;
121   hash(pos, str, S);
122   x = ctab_name(S, pos);
123   if( x == nilobj )  return nilobj;
124   for( link = Down(x);  link != x;  link = NextDown(link) )
125   { Child(y, link);
126     if( StringEqual(str, string(y)) )  return y;
127   }
128   return nilobj;
129 } /* end ctab_retrieve */
130 
131 #if DEBUG_ON
ctab_debug(COLOUR_TABLE S,FILE * fp)132 static void ctab_debug(COLOUR_TABLE S, FILE *fp)
133 { int i;  OBJECT x, link, y;
134   fprintf(fp, "  table size: %d;  current number of colours: %d%s",
135     ctab_size(S), ctab_count(S), STR_NEWLINE);
136   for( i = 0;  i < ctab_size(S);  i++ )
137   { x = ctab_num(S, i);
138     fprintf(fp, "  ctab_num(S, %d) = %s%s", i,
139       x == nilobj ? AsciiToFull("<nilobj>") :
140       is_word(type(x)) ? string(x) : AsciiToFull("not WORD!"), STR_NEWLINE);
141   }
142   fprintf(fp, "%s", STR_NEWLINE);
143   for( i = 0;  i < ctab_size(S);  i++ )
144   { x = ctab_name(S, i);
145     fprintf(fp, "ctab_name(S, %d) =", i);
146     if( x == nilobj )
147       fprintf(fp, " <nilobj>");
148     else if( type(x) != ACAT )
149       fprintf(fp, " not ACAT!");
150     else for( link = Down(x);  link != x;  link = NextDown(link) )
151     { Child(y, link);
152       fprintf(fp, " %s",
153 	is_word(type(y)) ? string(y) : AsciiToFull("not-WORD!"));
154     }
155     fprintf(fp, "%s", STR_NEWLINE);
156   }
157 } /* end ctab_debug */
158 #endif
159 
160 
161 static COLOUR_TABLE col_tab;
162 
163 /*****************************************************************************/
164 /*                                                                           */
165 /*  ColourInit(void)                                                         */
166 /*                                                                           */
167 /*  Initialize this module.                                                  */
168 /*                                                                           */
169 /*****************************************************************************/
170 
ColourInit(void)171 void ColourInit(void)
172 { col_tab = ctab_new(INIT_COLOUR_NUM);
173 } /* end ColourInit */
174 
175 
176 /*****************************************************************************/
177 /*                                                                           */
178 /*  BOOLEAN ColChange(OBJECT x, char *keyword, COLOUR_NUM *res)              */
179 /*                                                                           */
180 /*  Interpret x as a colour change.  If successful, return TRUE and          */
181 /*  set *res (or leave it alone if x was nochange).  Else return FALSE.      */
182 /*                                                                           */
183 /*****************************************************************************/
184 
ColChange(OBJECT x,unsigned char * keyword,COLOUR_NUM * res)185 static BOOLEAN ColChange(OBJECT x, unsigned char *keyword, COLOUR_NUM *res)
186 { OBJECT cname;
187   debug2(DCO, D, "ColChange(%s, %s)", EchoObject(x), keyword);
188 
189   /* if argument is not a word, fail and exit */
190   if( !is_word(type(x)) )
191   { Error(42, 3, "%s ignored (illegal left parameter)", WARN, &fpos(x),
192       keyword);
193     debug0(DCO, D, "ColChange returning (colour unchanged)");
194     return FALSE;
195   }
196 
197   /* if argument is nochange, do nothing */
198   if( StringEqual(string(x), STR_COLOUR_NOCHANGE) ||
199       StringEqual(string(x), STR_EMPTY) )
200   { debug0(DCO, D, "ColourChange returning (colour nochange)");
201     return TRUE;
202   }
203 
204   /* retrieve colour command if present, else insert it */
205   cname = ctab_retrieve(string(x), col_tab);
206   if( cname == nilobj )
207   { cname = MakeWord(type(x), string(x), &fpos(x));
208     ctab_insert(cname, &col_tab);
209     *res = word_colour(cname);
210   }
211   else *res = word_colour(cname);
212 
213   debug1(DCO, D, "ColChange returning (colour = %s)", string(cname));
214   ifdebug(DCO, DD, ctab_debug(col_tab, stderr));
215   return TRUE;
216 }
217 
218 
219 /*****************************************************************************/
220 /*                                                                           */
221 /*  ColourChange(style, x)                                                   */
222 /*                                                                           */
223 /*  Change the current style to contain the colour of colour command x.      */
224 /*  Set the underline colour at the same time.                               */
225 /*                                                                           */
226 /*****************************************************************************/
227 
ColourChange(STYLE * style,OBJECT x)228 void ColourChange(STYLE *style, OBJECT x)
229 {
230   if( ColChange(x, KW_COLOUR, &colour(*style)) )
231     underline_colour(*style) = colour(*style);
232 }
233 
234 /* *** old version
235 void ColourChange(STYLE *style, OBJECT x)
236 { OBJECT cname;
237   debug2(DCO, D, "ColourChange(%s, %s)", EchoStyle(style), EchoObject(x));
238 
239   ** if argument is not a word, fail and exit **
240   if( !is_word(type(x)) )
241   { Error(42, 3, "%s ignored (illegal left parameter)", WARN, &fpos(x),
242       KW_COLOUR);
243     debug0(DCO, D, "ColourChange returning (colour unchanged)");
244     return;
245   }
246 
247   ** if argument is nochange, do nothing **
248   if( StringEqual(string(x), STR_COLOUR_NOCHANGE) ||
249       StringEqual(string(x), STR_EMPTY) )
250   { debug0(DCO, D, "ColourChange returning (colour nochange)");
251     return;
252   }
253 
254   ** retrieve colour command if present, else insert it **
255   { cname = ctab_retrieve(string(x), col_tab);
256     if( cname == nilobj )
257     { cname = MakeWord(type(x), string(x), &fpos(x));
258       ctab_insert(cname, &col_tab);
259       colour(*style) = word_colour(cname);
260     }
261     else colour(*style) = word_colour(cname);
262   }
263 
264   debug1(DCO, D, "ColourChange returning (colour = %s)", string(cname));
265   ifdebug(DCO, DD, ctab_debug(col_tab, stderr));
266 }
267 *** */
268 
269 
270 /*****************************************************************************/
271 /*                                                                           */
272 /*  void ColourUnderlineChange(STYLE *style, OBJECT x)                       */
273 /*                                                                           */
274 /*  Change the underline colour of *style as indicated by x.                 */
275 /*                                                                           */
276 /*****************************************************************************/
277 
ColourUnderlineChange(STYLE * style,OBJECT x)278 void ColourUnderlineChange(STYLE *style, OBJECT x)
279 {
280   ColChange(x, KW_UNDERLINE_COLOUR, &underline_colour(*style));
281 }
282 
283 
284 /*@::ColourCommand()@*********************************************************/
285 /*                                                                           */
286 /*  FULL_CHAR *ColourCommand(cnum)                                           */
287 /*                                                                           */
288 /*  Return the PostScript command for producing colour cnum.                 */
289 /*                                                                           */
290 /*****************************************************************************/
291 
ColourCommand(COLOUR_NUM cnum)292 FULL_CHAR *ColourCommand(COLOUR_NUM cnum)
293 { FULL_CHAR *res;
294   debug1(DCO, D, "ColourCommand(%d)", cnum);
295   assert( cnum > 0 && cnum <= ctab_count(col_tab), "ColourCommand: number" );
296 
297   res = string(ctab_num(col_tab, cnum));
298 
299   debug1(DCO, D, "ColourCommand returning %s", res);
300   return res;
301 } /* end ColourCommand */
302