File: obstack.c

package info (click to toggle)
eli 4.4.1-1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 29,180 kB
  • ctags: 46,497
  • sloc: ansic: 290,588; sh: 4,471; makefile: 4,420; tcl: 3,517; lisp: 73; yacc: 71; sed: 44; awk: 11
file content (274 lines) | stat: -rw-r--r-- 7,887 bytes parent folder | download
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
static char RcsId[] = "$Id: obstack.c,v 1.1.1.1 2001/04/26 20:01:49 waite Exp $";
/* obstack.c - subroutines used implicitly by object stack macros
   Copyright (C) 1988 Free Software Foundation, Inc.

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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.

In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them.   Help stamp out software-hoarding!  */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#if HAVE_MALLOC_H
#include <malloc.h>
#endif

#include "obstack.h"

/* Size of a page in virtual memory */
#ifndef VIRTUAL_PAGE_SIZE
#define VIRTUAL_PAGE_SIZE 4096
#endif

/* Size of the overhead information required by the storage allocator */
#ifndef ALLOCATOR_OVERHEAD
#define ALLOCATOR_OVERHEAD 4
#endif

/* Determine default alignment.  */
struct fooalign {char x; double d;};
#define DEFAULT_ALIGNMENT ((char *)&((struct fooalign *) 0)->d - (char *)0)
/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
   But in fact it might be less smart and round addresses to as much as
   DEFAULT_ROUNDING.  So we prepare for it to do that.  */
union fooround {long x; double d;};
#define DEFAULT_ROUNDING (sizeof (union fooround))

/* The non-GNU-C macros copy the obstack address into this global variable
   to avoid multiple evaluation.  */

void *_obstack_object_base;

/* Initialize an obstack H for use.  Specify chunk size SIZE (0 means default).
   Objects start on multiples of ALIGNMENT (0 means use default).
   CHUNKFUN is the function to use to allocate chunks,
   and FREEFUN the function to free them.  */

#if PROTO_OK
void
_obstack_begin(
  ObstackP h, size_t size, int alignment,
    POINTER (*chunkfun) (size_t length),
    POINTER (*expandfun) (struct _obstack_chunk *chunk, size_t length),
    void (*freefun) (POINTER obj))
#else
void
_obstack_begin(h, size, alignment, chunkfun, expandfun, freefun)
ObstackP h; size_t size; int alignment;
  POINTER (*chunkfun)(); POINTER (*expandfun)(); void (*freefun)();
#endif
{
  register struct _obstack_chunk* chunk; /* points to new chunk */

  if (alignment == 0) alignment = DEFAULT_ALIGNMENT;
  if (size == 0) {
    int extra = ALLOCATOR_OVERHEAD;
    if (extra < DEFAULT_ROUNDING) extra = DEFAULT_ROUNDING;
    size = VIRTUAL_PAGE_SIZE - extra;
  }

  h->chunkfun = (CHUNKFUNTYPE)chunkfun;
  h->expandfun = (EXPANDFUNTYPE)expandfun;
  h->freefun = (FREEFUNTYPE)freefun;
  h->chunk_size = size;
  h->alignment_mask = alignment - 1;

  chunk	= h->chunk = (*h->chunkfun) (h->chunk_size);
  h->next_free = h->object_base = chunk->contents;
  h->chunk_limit = chunk->limit = (char *) chunk + h->chunk_size;
  chunk->prev = 0;

  /* Guarantee alignment */
  (void)obstack_alloc(h, 0);
}

/* Allocate a new current chunk for the obstack *H
   on the assumption that LENGTH bytes need to be added
   to the current object, or a new object of length LENGTH allocated.
   Copies any partial object from the end of the old chunk
   to the beginning of the new one.  */

#if PROTO_OK
void *
_obstack_malloc (size_t length)
#else
void *
_obstack_malloc (length)
size_t length;
#endif
{
  void *temp = malloc(length);

  if (temp) return temp;

  (void)perror("_obstack_malloc"); exit(1);
  return (void *)0;	/* To keep lint happy */
}

#if PROTO_OK
void *
_obstack_realloc(struct _obstack_chunk *chunk, size_t length)
#else
void *
_obstack_realloc (chunk, length)
struct _obstack_chunk *chunk; size_t length;
#endif
{
  void *temp = realloc((void *)chunk, length);

  if (temp) return temp;

  (void)perror("_obstack_realloc"); exit(1);
  return (void *)0;	/* To keep lint happy */
}

#if PROTO_OK
int
_obstack_newchunk(ObstackP h, size_t length)
#else
int
_obstack_newchunk (h, length)
     ObstackP h;
     size_t length;
#endif
{
  register struct _obstack_chunk*	old_chunk = h->chunk;
  register struct _obstack_chunk*	new_chunk;
  size_t new_size;
  char *obj_loc = h->object_base;
  size_t obj_size = h->next_free - h->object_base;

  /* Reset the default chunk size if necessary */
  if (h->chunk_size == 0) {
    int extra = ALLOCATOR_OVERHEAD;
    if (extra < DEFAULT_ROUNDING) extra = DEFAULT_ROUNDING;
    h->chunk_size = VIRTUAL_PAGE_SIZE - extra;
  }

  /* Compute size for new chunk.  */
  new_size = (obj_size + length) << 1;
  if (new_size < h->chunk_size)
    new_size = h->chunk_size;

  /* Determine the allocation strategy for the new chunk:
   *   Strategy 0: Reallocate the old chunk with the new size
   *   Strategy 1: Allocate a new chunk, move the immature object,
   *     set the previous pointer of the new chunk to the old chunk
   */

  if (obj_loc == old_chunk->contents && old_chunk->prev) {
    new_chunk = h->chunk = (*h->expandfun) (old_chunk, new_size);
    h->object_base = new_chunk->contents;
    h->next_free = new_chunk->contents + obj_size;
    h->chunk_limit = new_chunk->limit = (char *) new_chunk + new_size;
  } else {
    new_chunk = h->chunk = (*h->chunkfun) (new_size);
    h->next_free = h->object_base = new_chunk->contents;
    h->chunk_limit = new_chunk->limit = (char *) new_chunk + new_size;
  
    /* Guarantee alignment */
    { size_t save = h->t_size; (void)obstack_alloc(h, 0); h->t_size = save; }
  
    /* Move the existing object to the new chunk. */
    (void)memcpy(h->next_free, obj_loc, obj_size);
    h->next_free += obj_size;

    /* Link the old chunk */
    new_chunk->prev = old_chunk;
  }
  return 0;
}

/* Return nonzero if object OBJ has been allocated from obstack H.
   This is here for debugging.
   If you use it in a program, you are probably losing.  */

#if PROTO_OK
int
_obstack_allocated_p(ObstackP h, POINTER obj)
#else
int
_obstack_allocated_p (h, obj)
     ObstackP h;
     POINTER obj;
#endif
{
  register struct _obstack_chunk*  lp;	/* below addr of any objects in this chunk */
  register struct _obstack_chunk*  plp;	/* point to previous chunk if any */

  lp = (h)->chunk;
  while (lp != 0 && (lp > (struct _obstack_chunk*)obj ||
                     lp->limit < (char *)obj))
    {
      plp = lp -> prev;
      lp = plp;
    }
  return lp != 0;
}

/* Free objects in obstack H, including OBJ and everything allocate
   more recently than OBJ.  If OBJ is zero, free everything in H.  */

#if PROTO_OK
char *
_obstack_free (ObstackP h, POINTER obj)
#else
char *
_obstack_free (h, obj)
     ObstackP h;
     POINTER obj;
#endif
{
  register struct _obstack_chunk*  lp;	/* below addr of any objects in this chunk */
  register struct _obstack_chunk*  plp;	/* point to previous chunk if any */

  lp = (h)->chunk;
  while (lp != 0 && (lp > (struct _obstack_chunk*)obj ||
                     lp->limit < (char *)obj))
    {
      plp = lp -> prev;
      (*h->freefun) (lp);
      lp = plp;
    }
  if (lp)
    {
      (h)->object_base = (h)->next_free = (char *)(obj);
      (h)->chunk_limit = lp->limit;
      (h)->chunk = lp;
    }
  else if (obj != 0)
    /* obj is not in any of the chunks! */
    abort ();
  return (char *)(obj);
}

/* copy the contents of a string into an obstack */

#if PROTO_OK
void
obstack_strgrow(ObstackP obstk, char *data)
#else
void
obstack_strgrow(obstk, data)
ObstackP obstk; char *data;
#endif
{
  register char c, *p = data;

  if (p) while ((c = *p++)) obstack_1grow(obstk, c);
}