sb.c revision 33965
1/* sb.c - string buffer manipulation routines
2   Copyright (C) 1994, 1995 Free Software Foundation, Inc.
3
4   Written by Steve and Judy Chamberlain of Cygnus Support,
5      sac@cygnus.com
6
7   This file is part of GAS, the GNU Assembler.
8
9   GAS is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2, or (at your option)
12   any later version.
13
14   GAS is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with GAS; see the file COPYING.  If not, write to the Free
21   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22   02111-1307, USA. */
23
24#include "config.h"
25#include <stdio.h>
26#ifdef HAVE_STRING_H
27#include <string.h>
28#else
29#include <strings.h>
30#endif
31#include "libiberty.h"
32#include "sb.h"
33
34/* These routines are about manipulating strings.
35
36   They are managed in things called `sb's which is an abbreviation
37   for string buffers.  An sb has to be created, things can be glued
38   on to it, and at the end of it's life it should be freed.  The
39   contents should never be pointed at whilst it is still growing,
40   since it could be moved at any time
41
42   eg:
43   sb_new (&foo);
44   sb_grow... (&foo,...);
45   use foo->ptr[*];
46   sb_kill (&foo);
47
48*/
49
50#define dsize 5
51
52static void sb_check PARAMS ((sb *, int));
53
54/* Statistics of sb structures.  */
55
56int string_count[sb_max_power_two];
57
58/* Free list of sb structures.  */
59
60static sb_list_vector free_list;
61
62/* initializes an sb. */
63
64void
65sb_build (ptr, size)
66     sb *ptr;
67     int size;
68{
69  /* see if we can find one to allocate */
70  sb_element *e;
71
72  if (size > sb_max_power_two)
73    abort ();
74
75  e = free_list.size[size];
76  if (!e)
77    {
78      /* nothing there, allocate one and stick into the free list */
79      e = (sb_element *) xmalloc (sizeof (sb_element) + (1 << size));
80      e->next = free_list.size[size];
81      e->size = 1 << size;
82      free_list.size[size] = e;
83      string_count[size]++;
84    }
85
86  /* remove from free list */
87
88  free_list.size[size] = e->next;
89
90  /* copy into callers world */
91  ptr->ptr = e->data;
92  ptr->pot = size;
93  ptr->len = 0;
94  ptr->item = e;
95}
96
97
98void
99sb_new (ptr)
100     sb *ptr;
101{
102  sb_build (ptr, dsize);
103}
104
105/* deallocate the sb at ptr */
106
107void
108sb_kill (ptr)
109     sb *ptr;
110{
111  /* return item to free list */
112  ptr->item->next = free_list.size[ptr->pot];
113  free_list.size[ptr->pot] = ptr->item;
114}
115
116/* add the sb at s to the end of the sb at ptr */
117
118void
119sb_add_sb (ptr, s)
120     sb *ptr;
121     sb *s;
122{
123  sb_check (ptr, s->len);
124  memcpy (ptr->ptr + ptr->len, s->ptr, s->len);
125  ptr->len += s->len;
126}
127
128/* make sure that the sb at ptr has room for another len characters,
129   and grow it if it doesn't. */
130
131static void
132sb_check (ptr, len)
133     sb *ptr;
134     int len;
135{
136  if (ptr->len + len >= 1 << ptr->pot)
137    {
138      sb tmp;
139      int pot = ptr->pot;
140      while (ptr->len + len >= 1 << pot)
141	pot++;
142      sb_build (&tmp, pot);
143      sb_add_sb (&tmp, ptr);
144      sb_kill (ptr);
145      *ptr = tmp;
146    }
147}
148
149/* make the sb at ptr point back to the beginning.  */
150
151void
152sb_reset (ptr)
153     sb *ptr;
154{
155  ptr->len = 0;
156}
157
158/* add character c to the end of the sb at ptr. */
159
160void
161sb_add_char (ptr, c)
162     sb *ptr;
163     int c;
164{
165  sb_check (ptr, 1);
166  ptr->ptr[ptr->len++] = c;
167}
168
169/* add null terminated string s to the end of sb at ptr. */
170
171void
172sb_add_string (ptr, s)
173     sb *ptr;
174     const char *s;
175{
176  int len = strlen (s);
177  sb_check (ptr, len);
178  memcpy (ptr->ptr + ptr->len, s, len);
179  ptr->len += len;
180}
181
182/* add string at s of length len to sb at ptr */
183
184void
185sb_add_buffer (ptr, s, len)
186     sb *ptr;
187     const char *s;
188     int len;
189{
190  sb_check (ptr, len);
191  memcpy (ptr->ptr + ptr->len, s, len);
192  ptr->len += len;
193}
194
195/* print the sb at ptr to the output file */
196
197void
198sb_print (outfile, ptr)
199     FILE *outfile;
200     sb *ptr;
201{
202  int i;
203  int nc = 0;
204
205  for (i = 0; i < ptr->len; i++)
206    {
207      if (nc)
208	{
209	  fprintf (outfile, ",");
210	}
211      fprintf (outfile, "%d", ptr->ptr[i]);
212      nc = 1;
213    }
214}
215
216void
217sb_print_at (outfile, idx, ptr)
218     FILE *outfile;
219     int idx;
220     sb *ptr;
221{
222  int i;
223  for (i = idx; i < ptr->len; i++)
224    putc (ptr->ptr[i], outfile);
225}
226
227/* put a null at the end of the sb at in and return the start of the
228   string, so that it can be used as an arg to printf %s. */
229
230char *
231sb_name (in)
232     sb *in;
233{
234  /* stick a null on the end of the string */
235  sb_add_char (in, 0);
236  return in->ptr;
237}
238
239/* like sb_name, but don't include the null byte in the string.  */
240
241char *
242sb_terminate (in)
243     sb *in;
244{
245  sb_add_char (in, 0);
246  --in->len;
247  return in->ptr;
248}
249
250/* start at the index idx into the string in sb at ptr and skip
251   whitespace. return the index of the first non whitespace character */
252
253int
254sb_skip_white (idx, ptr)
255     int idx;
256     sb *ptr;
257{
258  while (idx < ptr->len
259	 && (ptr->ptr[idx] == ' '
260	     || ptr->ptr[idx] == '\t'))
261    idx++;
262  return idx;
263}
264
265/* start at the index idx into the sb at ptr. skips whitespace,
266   a comma and any following whitespace. returnes the index of the
267   next character. */
268
269int
270sb_skip_comma (idx, ptr)
271     int idx;
272     sb *ptr;
273{
274  while (idx < ptr->len
275	 && (ptr->ptr[idx] == ' '
276	     || ptr->ptr[idx] == '\t'))
277    idx++;
278
279  if (idx < ptr->len
280      && ptr->ptr[idx] == ',')
281    idx++;
282
283  while (idx < ptr->len
284	 && (ptr->ptr[idx] == ' '
285	     || ptr->ptr[idx] == '\t'))
286    idx++;
287
288  return idx;
289}
290