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