aboutsummaryrefslogtreecommitdiffstats
path: root/z42.c
blob: 548ef55bc574b5cac87931c3582d239b7c24115e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
/*@z42.c:Colour Service:ColourChange, ColourCommand@**************************/
/*                                                                           */
/*  THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.41)                       */
/*  COPYRIGHT (C) 1991, 2023 Jeffrey H. Kingston                             */
/*                                                                           */
/*  Jeffrey H. Kingston (jeff@it.usyd.edu.au)                                */
/*  School of Information Technologies                                       */
/*  The University of Sydney 2006                                            */
/*  AUSTRALIA                                                                */
/*                                                                           */
/*  This program is free software; you can redistribute it and/or modify     */
/*  it under the terms of the GNU General Public License as published by     */
/*  the Free Software Foundation; either Version 3, or (at your option)      */
/*  any later version.                                                       */
/*                                                                           */
/*  This program is distributed in the hope that it will be useful,          */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
/*  GNU General Public License for more details.                             */
/*                                                                           */
/*  You should have received a copy of the GNU General Public License        */
/*  along with this program; if not, write to the Free Software              */
/*  Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA   */
/*                                                                           */
/*  FILE:         z42.c                                                      */
/*  MODULE:       Colour Service                                             */
/*  EXTERNS:      ColourChange(), ColourCommand()                            */
/*                                                                           */
/*****************************************************************************/
#include "externs.h"
#include "child.h"
#define INIT_COLOUR_NUM	100


/*****************************************************************************/
/*                                                                           */
/*  COLOUR_TABLE                                                             */
/*                                                                           */
/*  A symbol table permitting access to colour records by number or name.    */
/*  The table will automatically enlarge to accept any number of entries,    */
/*  but there is an arbitrary limit of 65535 colours imposed so that colour  */
/*  numbers can be stored in 16 bit fields.                                  */
/*                                                                           */
/*     ctab_new(newsize)                 New empty table, newsize capacity   */
/*     ctab_insert(x, &S)                Insert new colour object x into S   */
/*     ctab_retrieve(str, S)             Retrieve colour object of name str  */
/*     ctab_num(S, num)                  Retrieve colour object, number num  */
/*     ctab_debug(S, fp)                 Debug print of table S to file fp   */
/*                                                                           */
/*****************************************************************************/

typedef struct
{ int coltab_size;				/* size of table             */
  int coltab_count;				/* number of colours held    */
  struct coltab_rec
  {	OBJECT	by_number;			/* colour record by number   */
	OBJECT	by_name_hash;			/* colour record by name     */
  } coltab[1];
} *COLOUR_TABLE;

#define	ctab_size(S)	(S)->coltab_size
#define	ctab_count(S)	(S)->coltab_count
#define	ctab_num(S, i)	(S)->coltab[i].by_number
#define	ctab_name(S, i)	(S)->coltab[i].by_name_hash

#define hash(pos, str, S)						\
{ FULL_CHAR *p = str;							\
  pos = *p++;								\
  while( *p ) pos += *p++;						\
  pos = pos % ctab_size(S);						\
}

static COLOUR_TABLE ctab_new(int newsize)
{ COLOUR_TABLE S;  int i;
  ifdebug(DMA, D, DebugRegisterUsage(MEM_COLOUR_TAB, 1,
    2*sizeof(int) + newsize * sizeof(struct coltab_rec)));
  S = (COLOUR_TABLE) malloc(2*sizeof(int) + newsize * sizeof(struct coltab_rec));
  if( S == (COLOUR_TABLE) NULL )
    Error(42, 1, "ran out of memory when enlarging colour table",
      FATAL, no_fpos);
  ctab_size(S) = newsize;
  ctab_count(S) = 0;
  for( i = 0;  i < newsize;  i++ )
  { ctab_num(S, i) = ctab_name(S, i) = nilobj;
  }
  return S;
} /* end ctab_new */

static void ctab_insert(OBJECT x, COLOUR_TABLE *S);

static COLOUR_TABLE ctab_rehash(COLOUR_TABLE S, int newsize)
{ COLOUR_TABLE NewS;  int i;
  NewS = ctab_new(newsize);
  for( i = 1;  i <= ctab_count(S);  i++ )
     ctab_insert(ctab_num(S, i), &NewS);
  for( i = 0;  i < ctab_size(S);  i++ )
  { if( ctab_name(S, i) != nilobj )  DisposeObject(ctab_name(S, i));
  }
  ifdebug(DMA, D, DebugRegisterUsage(MEM_COLOUR_TAB, -1,
    -(2*sizeof(int) + ctab_size(S) * sizeof(struct coltab_rec))));
  free(S);
  return NewS;
} /* end ctab_rehash */

static void ctab_insert(OBJECT x, COLOUR_TABLE *S)
{ int pos, num;					
  if( ctab_count(*S) == ctab_size(*S) - 1 )	/* one less since 0 unused */
    *S = ctab_rehash(*S, 2*ctab_size(*S));
  num = ++ctab_count(*S);
  if( num > MAX_COLOUR )
    Error(42, 2, "too many colours (maximum is %d)",
      FATAL, &fpos(x), MAX_COLOUR);
  hash(pos, string(x), *S);
  if( ctab_name(*S, pos) == nilobj )  New(ctab_name(*S, pos), ACAT);
  Link(ctab_name(*S, pos), x);
  word_colour(x) = num;
  ctab_num(*S, num) = x;
} /* end ctab_insert */

static OBJECT ctab_retrieve(FULL_CHAR *str, COLOUR_TABLE S)
{ OBJECT x, link, y;  int pos;
  hash(pos, str, S);
  x = ctab_name(S, pos);
  if( x == nilobj )  return nilobj;
  for( link = Down(x);  link != x;  link = NextDown(link) )
  { Child(y, link);
    if( StringEqual(str, string(y)) )  return y;
  }
  return nilobj;
} /* end ctab_retrieve */

#if DEBUG_ON
static void ctab_debug(COLOUR_TABLE S, FILE *fp)
{ int i;  OBJECT x, link, y;
  fprintf(fp, "  table size: %d;  current number of colours: %d%s",
    ctab_size(S), ctab_count(S), STR_NEWLINE);
  for( i = 0;  i < ctab_size(S);  i++ )
  { x = ctab_num(S, i);
    fprintf(fp, "  ctab_num(S, %d) = %s%s", i,
      x == nilobj ? AsciiToFull("<nilobj>") :
      is_word(type(x)) ? string(x) : AsciiToFull("not WORD!"), STR_NEWLINE);
  }
  fprintf(fp, "%s", STR_NEWLINE);
  for( i = 0;  i < ctab_size(S);  i++ )
  { x = ctab_name(S, i);
    fprintf(fp, "ctab_name(S, %d) =", i);
    if( x == nilobj )
      fprintf(fp, " <nilobj>");
    else if( type(x) != ACAT )
      fprintf(fp, " not ACAT!");
    else for( link = Down(x);  link != x;  link = NextDown(link) )
    { Child(y, link);
      fprintf(fp, " %s",
	is_word(type(y)) ? string(y) : AsciiToFull("not-WORD!"));
    }
    fprintf(fp, "%s", STR_NEWLINE);
  }
} /* end ctab_debug */
#endif


static COLOUR_TABLE col_tab;

/*****************************************************************************/
/*                                                                           */
/*  ColourInit(void)                                                         */
/*                                                                           */
/*  Initialize this module.                                                  */
/*                                                                           */
/*****************************************************************************/

void ColourInit(void)
{ col_tab = ctab_new(INIT_COLOUR_NUM);
} /* end ColourInit */


/*****************************************************************************/
/*                                                                           */
/*  BOOLEAN ColChange(OBJECT x, char *keyword, COLOUR_NUM *res)              */
/*                                                                           */
/*  Interpret x as a colour change.  If successful, return TRUE and          */
/*  set *res (or leave it alone if x was nochange).  Else return FALSE.      */
/*                                                                           */
/*****************************************************************************/

static BOOLEAN ColChange(OBJECT x, unsigned char *keyword, COLOUR_NUM *res)
{ OBJECT cname;
  debug2(DCO, D, "ColChange(%s, %s)", EchoObject(x), keyword);

  /* if argument is not a word, fail and exit */
  if( !is_word(type(x)) )
  { Error(42, 3, "%s ignored (illegal left parameter)", WARN, &fpos(x),
      keyword);
    debug0(DCO, D, "ColChange returning (colour unchanged)");
    return FALSE;
  }

  /* if argument is nochange, do nothing */
  if( StringEqual(string(x), STR_COLOUR_NOCHANGE) ||
      StringEqual(string(x), STR_EMPTY) )
  { debug0(DCO, D, "ColourChange returning (colour nochange)");
    return TRUE;
  }

  /* retrieve colour command if present, else insert it */
  cname = ctab_retrieve(string(x), col_tab);
  if( cname == nilobj )
  { cname = MakeWord(type(x), string(x), &fpos(x));
    ctab_insert(cname, &col_tab);
    *res = word_colour(cname);
  }
  else *res = word_colour(cname);

  debug1(DCO, D, "ColChange returning (colour = %s)", string(cname));
  ifdebug(DCO, DD, ctab_debug(col_tab, stderr));
  return TRUE;
}


/*****************************************************************************/
/*                                                                           */
/*  ColourChange(style, x)                                                   */
/*                                                                           */
/*  Change the current style to contain the colour of colour command x.      */
/*  Set the underline colour at the same time.                               */
/*                                                                           */
/*****************************************************************************/

void ColourChange(STYLE *style, OBJECT x)
{
  if( ColChange(x, KW_COLOUR, &colour(*style)) )
    underline_colour(*style) = colour(*style);
}

/* *** old version
void ColourChange(STYLE *style, OBJECT x)
{ OBJECT cname;
  debug2(DCO, D, "ColourChange(%s, %s)", EchoStyle(style), EchoObject(x));

  ** if argument is not a word, fail and exit **
  if( !is_word(type(x)) )
  { Error(42, 3, "%s ignored (illegal left parameter)", WARN, &fpos(x),
      KW_COLOUR);
    debug0(DCO, D, "ColourChange returning (colour unchanged)");
    return;
  }

  ** if argument is nochange, do nothing **
  if( StringEqual(string(x), STR_COLOUR_NOCHANGE) ||
      StringEqual(string(x), STR_EMPTY) )
  { debug0(DCO, D, "ColourChange returning (colour nochange)");
    return;
  }

  ** retrieve colour command if present, else insert it **
  { cname = ctab_retrieve(string(x), col_tab);
    if( cname == nilobj )
    { cname = MakeWord(type(x), string(x), &fpos(x));
      ctab_insert(cname, &col_tab);
      colour(*style) = word_colour(cname);
    }
    else colour(*style) = word_colour(cname);
  }

  debug1(DCO, D, "ColourChange returning (colour = %s)", string(cname));
  ifdebug(DCO, DD, ctab_debug(col_tab, stderr));
}
*** */


/*****************************************************************************/
/*                                                                           */
/*  void ColourUnderlineChange(STYLE *style, OBJECT x)                       */
/*                                                                           */
/*  Change the underline colour of *style as indicated by x.                 */
/*                                                                           */
/*****************************************************************************/

void ColourUnderlineChange(STYLE *style, OBJECT x)
{
  ColChange(x, KW_UNDERLINE_COLOUR, &underline_colour(*style));
}


/*@::ColourCommand()@*********************************************************/
/*                                                                           */
/*  FULL_CHAR *ColourCommand(cnum)                                           */
/*                                                                           */
/*  Return the PostScript command for producing colour cnum.                 */
/*                                                                           */
/*****************************************************************************/

FULL_CHAR *ColourCommand(COLOUR_NUM cnum)
{ FULL_CHAR *res;
  debug1(DCO, D, "ColourCommand(%d)", cnum);
  assert( cnum > 0 && cnum <= ctab_count(col_tab), "ColourCommand: number" );

  res = string(ctab_num(col_tab, cnum));

  debug1(DCO, D, "ColourCommand returning %s", res);
  return res;
} /* end ColourCommand */