1/* obstack.c - subroutines used implicitly by object stack macros
2   Copyright (C) 1988 Free Software Foundation, Inc.
3
4This program is free software; you can redistribute it and/or modify it
5under the terms of the GNU General Public License as published by the
6Free Software Foundation; either version 1, or (at your option) any
7later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
17
18#include <stdlib.h>
19#include "obstack.h"
20
21#ifdef __STDC__
22#define POINTER void *
23#else
24#define POINTER char *
25#endif
26
27/* Determine default alignment.  */
28struct fooalign {char x; double d;};
29#define DEFAULT_ALIGNMENT ((char *)&((struct fooalign *) 0)->d - (char *)0)
30/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
31   But in fact it might be less smart and round addresses to as much as
32   DEFAULT_ROUNDING.  So we prepare for it to do that.  */
33union fooround {int32_t x; double d;};
34#define DEFAULT_ROUNDING (sizeof (union fooround))
35
36/* When we copy a long block of data, this is the unit to do it with.
37   On some machines, copying successive ints does not work;
38   in such a case, redefine COPYING_UNIT to `long' (if that works)
39   or `char' as a last resort.  */
40#ifndef COPYING_UNIT
41#define COPYING_UNIT int
42#endif
43
44/* The non-GNU-C macros copy the obstack into this global variable
45   to avoid multiple evaluation.  */
46
47struct obstack *_obstack = 0;
48
49/* Initialize an obstack H for use.  Specify chunk size SIZE (0 means default).
50   Objects start on multiples of ALIGNMENT (0 means use default).
51   CHUNKFUN is the function to use to allocate chunks,
52   and FREEFUN the function to free them.  */
53
54void
55_obstack_begin(
56struct obstack *h,
57int size,
58int alignment,
59void *(*chunkfun)(size_t n),
60void (*freefun)() )
61{
62  register struct _obstack_chunk* chunk; /* points to new chunk */
63
64  if (alignment == 0)
65    alignment = DEFAULT_ALIGNMENT;
66  if (size == 0)
67    /* Default size is what GNU malloc can fit in a 4096-byte block.  */
68    {
69      /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
70	 Use the values for range checking, because if range checking is off,
71	 the extra bytes won't be missed terribly, but if range checking is on
72	 and we used a larger request, a whole extra 4096 bytes would be
73	 allocated.
74
75	 These number are irrelevant to the new GNU malloc.  I suspect it is
76	 less sensitive to the size of the request.  */
77      int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
78		    + 4 + DEFAULT_ROUNDING - 1)
79		   & ~(DEFAULT_ROUNDING - 1));
80      size = 4096 - extra;
81    }
82
83  h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun;
84  h->freefun = freefun;
85  h->chunk_size = size;
86  h->alignment_mask = alignment - 1;
87
88  chunk	= h->chunk = (*h->chunkfun) (h->chunk_size);
89  h->next_free = h->object_base = chunk->contents;
90  h->chunk_limit = chunk->limit
91   = (char *) chunk + h->chunk_size;
92  chunk->prev = 0;
93}
94
95/* Allocate a new current chunk for the obstack *H
96   on the assumption that LENGTH bytes need to be added
97   to the current object, or a new object of length LENGTH allocated.
98   Copies any partial object from the end of the old chunk
99   to the beginning of the new one.  */
100
101void
102_obstack_newchunk(
103struct obstack *h,
104int length)
105{
106  register struct _obstack_chunk*	old_chunk = h->chunk;
107  register struct _obstack_chunk*	new_chunk;
108  register int32_t	new_size;
109  register int obj_size = h->next_free - h->object_base;
110  register int i;
111  int already;
112
113  /* Compute size for new chunk.  */
114  new_size = (obj_size + length) + (obj_size >> 3) + 100;
115  if (new_size < h->chunk_size)
116    new_size = h->chunk_size;
117
118  /* Allocate and initialize the new chunk.  */
119  new_chunk = h->chunk = (*h->chunkfun) (new_size);
120  new_chunk->prev = old_chunk;
121  new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
122
123  /* Move the existing object to the new chunk.
124     Word at a time is fast and is safe if the object
125     is sufficiently aligned.  */
126  if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT)
127    {
128      for (i = obj_size / sizeof (COPYING_UNIT) - 1;
129	   i >= 0; i--)
130	((COPYING_UNIT *)new_chunk->contents)[i]
131	  = ((COPYING_UNIT *)h->object_base)[i];
132      /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT,
133	 but that can cross a page boundary on a machine
134	 which does not do strict alignment for COPYING_UNITS.  */
135      already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT);
136    }
137  else
138    already = 0;
139  /* Copy remaining bytes one by one.  */
140  for (i = already; i < obj_size; i++)
141    new_chunk->contents[i] = h->object_base[i];
142
143  h->object_base = new_chunk->contents;
144  h->next_free = h->object_base + obj_size;
145}
146
147#ifdef DEBUG
148/* Return nonzero if object OBJ has been allocated from obstack H.
149   This is here for debugging.
150   If you use it in a program, you are probably losing.  */
151
152static
153int
154_obstack_allocated_p(
155struct obstack *h,
156POINTER obj)
157{
158  register struct _obstack_chunk*  lp;	/* below addr of any objects in this chunk */
159  register struct _obstack_chunk*  plp;	/* point to previous chunk if any */
160
161  lp = (h)->chunk;
162  while (lp != 0 && ((POINTER)lp > obj || (POINTER)(lp)->limit < obj))
163    {
164      plp = lp -> prev;
165      lp = plp;
166    }
167  return lp != 0;
168}
169#endif /* DEBUG */
170
171/* Free objects in obstack H, including OBJ and everything allocate
172   more recently than OBJ.  If OBJ is zero, free everything in H.  */
173#undef obstack_free
174void
175obstack_free(
176struct obstack *h,
177POINTER obj)
178{
179  register struct _obstack_chunk*  lp;	/* below addr of any objects in this chunk */
180  register struct _obstack_chunk*  plp;	/* point to previous chunk if any */
181
182  lp = (h)->chunk;
183  /* We use >= because there cannot be an object at the beginning of a chunk.
184     But there can be an empty object at that address
185     at the end of another chunk.  */
186  while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
187    {
188      plp = lp -> prev;
189      (*h->freefun) (lp);
190      lp = plp;
191    }
192  if (lp)
193    {
194      (h)->object_base = (h)->next_free = (char *)(obj);
195      (h)->chunk_limit = lp->limit;
196      (h)->chunk = lp;
197    }
198  else if (obj != 0)
199    /* obj is not in any of the chunks! */
200    abort ();
201}
202
203
204#if 0
205/* These are now turned off because the applications do not use it
206   and it uses bcopy via obstack_grow, which causes trouble on sysV.  */
207
208/* Now define the functional versions of the obstack macros.
209   Define them to simply use the corresponding macros to do the job.  */
210
211#ifdef __STDC__
212/* These function definitions do not work with non-ANSI preprocessors;
213   they won't pass through the macro names in parentheses.  */
214
215/* The function names appear in parentheses in order to prevent
216   the macro-definitions of the names from being expanded there.  */
217
218POINTER (obstack_base) (obstack)
219     struct obstack *obstack;
220{
221  return obstack_base (obstack);
222}
223
224POINTER (obstack_next_free) (obstack)
225     struct obstack *obstack;
226{
227  return obstack_next_free (obstack);
228}
229
230int (obstack_object_size) (obstack)
231     struct obstack *obstack;
232{
233  return obstack_object_size (obstack);
234}
235
236int (obstack_room) (obstack)
237     struct obstack *obstack;
238{
239  return obstack_room (obstack);
240}
241
242void (obstack_grow) (obstack, pointer, length)
243     struct obstack *obstack;
244     POINTER pointer;
245     int length;
246{
247  obstack_grow (obstack, pointer, length);
248}
249
250void (obstack_grow0) (obstack, pointer, length)
251     struct obstack *obstack;
252     POINTER pointer;
253     int length;
254{
255  obstack_grow0 (obstack, pointer, length);
256}
257
258void (obstack_1grow) (obstack, character)
259     struct obstack *obstack;
260     int character;
261{
262  obstack_1grow (obstack, character);
263}
264
265void (obstack_blank) (obstack, length)
266     struct obstack *obstack;
267     int length;
268{
269  obstack_blank (obstack, length);
270}
271
272void (obstack_1grow_fast) (obstack, character)
273     struct obstack *obstack;
274     int character;
275{
276  obstack_1grow_fast (obstack, character);
277}
278
279void (obstack_blank_fast) (obstack, length)
280     struct obstack *obstack;
281     int length;
282{
283  obstack_blank_fast (obstack, length);
284}
285
286POINTER (obstack_finish) (obstack)
287     struct obstack *obstack;
288{
289  return obstack_finish (obstack);
290}
291
292POINTER (obstack_alloc) (obstack, length)
293     struct obstack *obstack;
294     int length;
295{
296  return obstack_alloc (obstack, length);
297}
298
299POINTER (obstack_copy) (obstack, pointer, length)
300     struct obstack *obstack;
301     POINTER pointer;
302     int length;
303{
304  return obstack_copy (obstack, pointer, length);
305}
306
307POINTER (obstack_copy0) (obstack, pointer, length)
308     struct obstack *obstack;
309     POINTER pointer;
310     int length;
311{
312  return obstack_copy0 (obstack, pointer, length);
313}
314
315#endif /* __STDC__ */
316
317#endif /* 0 */
318