aboutsummaryrefslogtreecommitdiffstats
path: root/z42.c
blob: 6a31b999814717da3f8ea6c8f9b72554d539f13a (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
/*@z42.c:Colour Service:ColourChange, ColourCommand@**************************/
/*                                                                           */
/*  THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.18)                       */
/*  COPYRIGHT (C) 1991, 2000 Jeffrey H. Kingston                             */
/*                                                                           */
/*  Jeffrey H. Kingston (jeff@cs.usyd.edu.au)                                */
/*  Basser Department of Computer Science                                    */
/*  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 2, 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"
#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\n",
    ctab_size(S), ctab_count(S));
  for( i = 0;  i < ctab_size(S);  i++ )
  { x = ctab_num(S, i);
    fprintf(fp, "  ctab_num(S, %d) = %s\n", i,
      x == nilobj ? AsciiToFull("<nilobj>") :
      is_word(type(x)) ? string(x) : AsciiToFull("not WORD!"));
  }
  fprintf(fp, "\n");
  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, "\n");
  }
} /* end ctab_debug */
#endif


static COLOUR_TABLE col_tab;

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

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


/*****************************************************************************/
/*                                                                           */
/*  ColourChange(style, x)                                                   */
/*                                                                           */
/*  Change the current style to contain the colour of colour command x.      */
/*                                                                           */
/*****************************************************************************/

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 empty, fail and exit */
  if( StringEqual(string(x), STR_EMPTY) )
  { if( BackEnd != PLAINTEXT )
      Error(42, 4, "%s ignored (empty 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) )
  { 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));
} /* ColourChange */


/*@::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 */