386BSD 0.1 development
[unix-history] / usr / othersrc / public / ghostscript-2.4.1 / gsmisc.c
CommitLineData
35b68964
WJ
1/* Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved.
2 Distributed by Free Software Foundation, Inc.
3
4This file is part of Ghostscript.
5
6Ghostscript is distributed in the hope that it will be useful, but
7WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
8to anyone for the consequences of using it or for whether it serves any
9particular purpose or works at all, unless he says so in writing. Refer
10to the Ghostscript General Public License for full details.
11
12Everyone is granted permission to copy, modify and redistribute
13Ghostscript, but only under the conditions described in the Ghostscript
14General Public License. A copy of this license is supposed to have been
15given to you along with Ghostscript so you can know your rights and
16responsibilities. It should be in a file named COPYING. Among other
17things, the copyright notice and this notice must be preserved on all
18copies. */
19
20/* gsmisc.c */
21/* Miscellaneous utilities for Ghostscript library */
22#include "gx.h"
23#include "malloc_.h"
24#include "memory_.h"
25
26/* Ghostscript writes to gs_out instead of stdout, */
27/* and writes debugging output to gs_debug_out. */
28FILE *gs_out;
29/* We define gs_debug and gs_debug_out even if DEBUG isn't defined, */
30/* so that we can compile individual modules with DEBUG set. */
31char gs_debug[128];
32FILE *gs_debug_out;
33/* We define gs_log_errors here for the same reason. */
34int gs_log_errors = 0;
35
36/* We can turn on allocator debugging even if DEBUG isn't defined. */
37int gs_alloc_debug = 0;
38byte gs_alloc_fill_alloc = 0xa1;
39byte gs_alloc_fill_free = 0xf1;
40
41/* Generate a block of unique IDs. */
42static ulong gs_next_id = 0;
43ulong
44gs_next_ids(uint count)
45{ ulong id;
46 if ( gs_next_id == 0 ) gs_next_id++;
47 id = gs_next_id;
48 gs_next_id += count;
49 return id;
50}
51
52/* Versions of malloc and free compatible with Ghostscript's */
53/* model of memory management. We keep track of all allocated */
54/* blocks so we can free them at cleanup time. */
55/* We must make sure that malloc_blocks leave the block aligned. */
56typedef struct malloc_block_s malloc_block;
57#define malloc_block_data\
58 malloc_block *next;\
59 uint size;\
60 const char *cname
61struct malloc_block_data_s { malloc_block_data; };
62struct malloc_block_s {
63 malloc_block_data;
64 byte _pad[-sizeof(struct malloc_block_data_s) & 7]; /* pad to double */
65};
66private malloc_block *malloc_list = 0;
67char *
68gs_malloc(uint num_elts, uint elt_size, const char *client_name)
69{ char *ptr;
70 const char *msg = "";
71 if ( num_elts > (max_uint - sizeof(malloc_block)) / elt_size )
72 { /* Can't represent the size in a uint! */
73 msg = "too large for size_t";
74 ptr = 0;
75 }
76 else
77 { uint size = num_elts * elt_size;
78 ptr = malloc(size + sizeof(malloc_block));
79 if ( ptr == 0 )
80 msg = "failed";
81 else
82 { malloc_block *bp = (malloc_block *)ptr;
83 bp->next = malloc_list;
84 bp->size = size;
85 bp->cname = client_name;
86 malloc_list = bp;
87 msg = "OK";
88 ptr = (char *)(bp + 1);
89 if ( gs_alloc_debug )
90 { /* Clear the block in an attempt to track down */
91 /* uninitialized data errors. */
92 memset(ptr, gs_alloc_fill_alloc, size);
93 }
94 }
95 }
96 if ( gs_alloc_debug || !*msg )
97 dprintf5("gs_malloc(%s)(%u, %u) = 0x%lx: %s\n", client_name,
98 num_elts, elt_size, (ulong)ptr, msg);
99 return ptr;
100}
101void
102gs_free(char *ptr, uint num_elts, uint elt_size, const char *client_name)
103{ malloc_block *bp = malloc_list;
104 if ( gs_alloc_debug )
105 dprintf4("gs_free(%s)(0x%lx, %u, %u)\n", client_name,
106 (ulong)ptr, num_elts, elt_size);
107 if ( ptr == (char *)(bp + 1) )
108 {
109#ifdef DEBUG
110 if ( bp->size != num_elts * elt_size )
111 lprintf5("%s: free 0x%lx(%u,%u) size ~= %u\n",
112 client_name, (ulong)ptr, num_elts, elt_size,
113 bp->size);
114#endif
115 malloc_list = bp->next;
116 if ( gs_alloc_debug )
117 memset((char *)(bp + 1), gs_alloc_fill_free, bp->size);
118 free(bp);
119 }
120 else
121 { malloc_block *np;
122 for ( ; (np = bp->next) != 0; bp = np )
123 { if ( ptr == (char *)(np + 1) )
124 {
125#ifdef DEBUG
126 if ( np->size != num_elts * elt_size )
127 lprintf5("%s: free 0x%lx(%u,%u) size ~= %u\n",
128 client_name, (ulong)ptr, num_elts, elt_size,
129 np->size);
130#endif
131 bp->next = np->next;
132 if ( gs_alloc_debug )
133 memset((char *)(np + 1), gs_alloc_fill_free, np->size);
134 free(np);
135 return;
136 }
137 }
138 lprintf4("%s: free 0x%lx(%u,%u) not found\n",
139 client_name, (ulong)ptr, num_elts, elt_size);
140 free((char *)((malloc_block *)ptr - 1));
141 }
142}
143void
144gs_malloc_release()
145{ malloc_block *bp = malloc_list;
146 malloc_block *np;
147 for ( ; bp != 0; bp = np )
148 { np = bp->next;
149 if ( gs_alloc_debug )
150 memset((char *)(bp + 1), gs_alloc_fill_free, bp->size);
151 free(bp);
152 }
153 malloc_list = 0;
154}
155
156/* Swap even and odd bytes. */
157/* This routine may be supplanted by assembly code. */
158#if !USE_ASM
159#undef memswab /* see memory_.h */
160void
161memswab(const char *src, char *dest, int count)
162{ register const uint *sptr = (const uint *)src;
163 register uint *dptr = (uint *)dest;
164 register int x;
165 register uint w;
166 for ( x = count >> 3; --x >= 0; )
167 { w = *sptr;
168#if arch_ints_are_short
169 *dptr = (w >> 8) + (w << 8);
170 w = sptr[1];
171 dptr[1] = (w >> 8) + (w << 8);
172 w = sptr[2];
173 dptr[2] = (w >> 8) + (w << 8);
174 w = sptr[3];
175 dptr[3] = (w >> 8) + (w << 8);
176 sptr += 4, dptr += 4;
177#else
178 *dptr = ((w << 8) & 0xff00ff00) + ((w >> 8) & 0x00ff00ff);
179 w = sptr[1];
180 dptr[1] = ((w << 8) & 0xff00ff00) + ((w >> 8) & 0x00ff00ff);
181 sptr += 2, dptr += 2;
182#endif
183 }
184 switch ( count & 6 )
185 {
186 case 6:
187 w = ((const ushort *)sptr)[2];
188 ((ushort *)dptr)[2] = (w >> 8) + (w << 8);
189 case 4:
190 w = ((const ushort *)sptr)[1];
191 ((ushort *)dptr)[1] = (w >> 8) + (w << 8);
192 case 2:
193 w = ((const ushort *)sptr)[0];
194 ((ushort *)dptr)[0] = (w >> 8) + (w << 8);
195 case 0:
196 ;
197 }
198}
199#endif /* !USE_ASM */
200
201/* Transpose an 8 x 8 block of bits. line_size is the raster of */
202/* the input data. dist is the distance between output bytes. */
203/* This routine may be supplanted by assembly code. */
204#if !USE_ASM
205
206#if 1 /* This is the better of the two algorithms. */
207
208void
209memflip8x8(const byte *inp, int line_size, byte *outp, int dist)
210{ register uint ae, bf, cg, dh;
211 { const byte *ptr4 = inp + (line_size << 2);
212 ae = ((uint)*inp << 8) + *ptr4;
213 inp += line_size, ptr4 += line_size;
214 bf = ((uint)*inp << 8) + *ptr4;
215 inp += line_size, ptr4 += line_size;
216 cg = ((uint)*inp << 8) + *ptr4;
217 inp += line_size, ptr4 += line_size;
218 dh = ((uint)*inp << 8) + *ptr4;
219 }
220
221 /* Check for all 8 bytes being the same. */
222 /* This is especially worth doing for the case where all are zero. */
223 if ( ae == bf && ae == cg && ae == dh && (ae >> 8) == (ae & 0xff) )
224 { if ( ae == 0 ) goto store;
225 *outp = -((ae >> 7) & 1);
226 outp += dist;
227 *outp = -((ae >> 6) & 1);
228 outp += dist;
229 *outp = -((ae >> 5) & 1);
230 outp += dist;
231 *outp = -((ae >> 4) & 1);
232 outp += dist;
233 *outp = -((ae >> 3) & 1);
234 outp += dist;
235 *outp = -((ae >> 2) & 1);
236 outp += dist;
237 *outp = -((ae >> 1) & 1);
238 outp += dist;
239 *outp = -(ae & 1);
240 return;
241 }
242
243 { register uint temp;
244
245/* Transpose a block of bits between registers. */
246#define transpose(r,s,mask,shift)\
247 r ^= (temp = ((s >> shift) ^ r) & mask);\
248 s ^= temp << shift
249
250/* Transpose blocks of 4 x 4 */
251#define transpose4(r) transpose(r,r,0x00f0,4)
252 transpose4(ae);
253 transpose4(bf);
254 transpose4(cg);
255 transpose4(dh);
256
257/* Transpose blocks of 2 x 2 */
258 transpose(ae, cg, 0x3333, 2);
259 transpose(bf, dh, 0x3333, 2);
260
261/* Transpose blocks of 1 x 1 */
262 transpose(ae, bf, 0x5555, 1);
263 transpose(cg, dh, 0x5555, 1);
264
265 }
266
267store: *outp = ae >> 8;
268 outp += dist;
269 *outp = bf >> 8;
270 outp += dist;
271 *outp = cg >> 8;
272 outp += dist;
273 *outp = dh >> 8;
274 outp += dist;
275 *outp = (byte)ae;
276 outp += dist;
277 *outp = (byte)bf;
278 outp += dist;
279 *outp = (byte)cg;
280 outp += dist;
281 *outp = (byte)dh;
282}
283
284#else /* This looked like a good idea, but it's no faster. */
285
286/* Transpose an 8 x 8 block of bits. line_size is the raster of */
287/* the input data. dist is the distance between output bytes. */
288void
289memflip8x8(const byte *inp, int line_size, byte *outp, int dist)
290{ /* Define a table that spreads the bits of its index as follows: */
291 /* 0->0-3, 1->8-11, 2->16-19, 3->24-27, */
292 /* 4->4-7, 5->12-15, 6->20-23, 7->28-31. */
293#define b4(v) v,v+0xf,v+0xf00,v+0xf0f
294#define b8(v) b4(v),b4(v+0xf0000)
295#define b16(v) b8(v),b8(v+0xf000000)
296 static const ulong spread[256] =
297 { b16(0), b16(0xf0), b16(0xf000), b16(0xf0f0),
298 b16(0xf00000), b16(0xf000f0), b16(0xf0f000), b16(0xf0f0f0),
299 b16(0xf0000000), b16(0xf00000f0), b16(0xf000f000), b16(0xf000f0f0),
300 b16(0xf0f00000), b16(0xf0f000f0), b16(0xf0f0f000), b16(0xf0f0f0f0)
301 };
302 register ulong hi, lo, temp;
303 hi = spread[*inp] & 0x88888888;
304 inp += line_size;
305 hi |= spread[*inp] & 0x44444444;
306 inp += line_size;
307 hi |= spread[*inp] & 0x22222222;
308 inp += line_size;
309 hi |= spread[*inp] & 0x11111111;
310 inp += line_size;
311 lo = spread[*inp] & 0x88888888;
312 inp += line_size;
313 lo |= spread[*inp] & 0x44444444;
314 inp += line_size;
315 lo |= spread[*inp] & 0x22222222;
316 inp += line_size;
317 lo |= spread[*inp] & 0x11111111;
318 temp = (hi & 0xf0f0f0f0) | ((lo >> 4) & 0x0f0f0f0f);
319 *outp = (byte)((uint)(temp >> 16) >> 8); outp += dist;
320 *outp = (byte)(temp >> 16); outp += dist;
321 *outp = (byte)((uint)temp >> 8); outp += dist;
322 *outp = (byte)(temp); outp += dist;
323 temp = ((hi << 4) & 0xf0f0f0f0) | (lo & 0x0f0f0f0f);
324 *outp = (byte)((uint)(temp >> 16) >> 8); outp += dist;
325 *outp = (byte)(temp >> 16); outp += dist;
326 *outp = (byte)((uint)temp >> 8); outp += dist;
327 *outp = (byte)(temp);
328}
329
330#endif /* memflip8x8 */
331
332#endif /* !USE_ASM */