133965Sjdp/* sb.c - string buffer manipulation routines
2218822Sdim   Copyright 1994, 1995, 2000, 2003, 2006 Free Software Foundation, Inc.
333965Sjdp
433965Sjdp   Written by Steve and Judy Chamberlain of Cygnus Support,
533965Sjdp      sac@cygnus.com
633965Sjdp
733965Sjdp   This file is part of GAS, the GNU Assembler.
833965Sjdp
933965Sjdp   GAS is free software; you can redistribute it and/or modify
1033965Sjdp   it under the terms of the GNU General Public License as published by
1133965Sjdp   the Free Software Foundation; either version 2, or (at your option)
1233965Sjdp   any later version.
1333965Sjdp
1433965Sjdp   GAS is distributed in the hope that it will be useful,
1533965Sjdp   but WITHOUT ANY WARRANTY; without even the implied warranty of
1633965Sjdp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1733965Sjdp   GNU General Public License for more details.
1833965Sjdp
1933965Sjdp   You should have received a copy of the GNU General Public License
2033965Sjdp   along with GAS; see the file COPYING.  If not, write to the Free
21218822Sdim   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
22218822Sdim   02110-1301, USA.  */
2333965Sjdp
24218822Sdim#include "as.h"
2533965Sjdp#include "sb.h"
2633965Sjdp
2733965Sjdp/* These routines are about manipulating strings.
2833965Sjdp
2933965Sjdp   They are managed in things called `sb's which is an abbreviation
3033965Sjdp   for string buffers.  An sb has to be created, things can be glued
3133965Sjdp   on to it, and at the end of it's life it should be freed.  The
3233965Sjdp   contents should never be pointed at whilst it is still growing,
3333965Sjdp   since it could be moved at any time
3433965Sjdp
3533965Sjdp   eg:
3633965Sjdp   sb_new (&foo);
3733965Sjdp   sb_grow... (&foo,...);
3833965Sjdp   use foo->ptr[*];
39218822Sdim   sb_kill (&foo);  */
4033965Sjdp
41218822Sdimstatic int dsize = 5;
42130561Sobrienstatic void sb_check (sb *, int);
4333965Sjdp
4433965Sjdp/* Statistics of sb structures.  */
45218822Sdimstatic int string_count[sb_max_power_two];
4633965Sjdp
4733965Sjdp/* Free list of sb structures.  */
48218822Sdimstatic struct
49218822Sdim{
50218822Sdim  sb_element *size[sb_max_power_two];
51218822Sdim} free_list;
5233965Sjdp
53218822Sdim/* Initializes an sb.  */
5433965Sjdp
55218822Sdimstatic void
56130561Sobriensb_build (sb *ptr, int size)
5733965Sjdp{
58218822Sdim  /* See if we can find one to allocate.  */
5933965Sjdp  sb_element *e;
6033965Sjdp
61218822Sdim  assert (size < sb_max_power_two);
6233965Sjdp
6333965Sjdp  e = free_list.size[size];
6433965Sjdp  if (!e)
6533965Sjdp    {
66218822Sdim      /* Nothing there, allocate one and stick into the free list.  */
6733965Sjdp      e = (sb_element *) xmalloc (sizeof (sb_element) + (1 << size));
6833965Sjdp      e->next = free_list.size[size];
6933965Sjdp      e->size = 1 << size;
7033965Sjdp      free_list.size[size] = e;
7133965Sjdp      string_count[size]++;
7233965Sjdp    }
7333965Sjdp
74218822Sdim  /* Remove from free list.  */
7533965Sjdp  free_list.size[size] = e->next;
7633965Sjdp
77218822Sdim  /* Copy into callers world.  */
7833965Sjdp  ptr->ptr = e->data;
7933965Sjdp  ptr->pot = size;
8033965Sjdp  ptr->len = 0;
8133965Sjdp  ptr->item = e;
8233965Sjdp}
8333965Sjdp
8433965Sjdpvoid
85130561Sobriensb_new (sb *ptr)
8633965Sjdp{
8733965Sjdp  sb_build (ptr, dsize);
8833965Sjdp}
8933965Sjdp
90218822Sdim/* Deallocate the sb at ptr.  */
9133965Sjdp
9233965Sjdpvoid
93130561Sobriensb_kill (sb *ptr)
9433965Sjdp{
95218822Sdim  /* Return item to free list.  */
9633965Sjdp  ptr->item->next = free_list.size[ptr->pot];
9733965Sjdp  free_list.size[ptr->pot] = ptr->item;
9833965Sjdp}
9933965Sjdp
100218822Sdim/* Add the sb at s to the end of the sb at ptr.  */
10133965Sjdp
10233965Sjdpvoid
103130561Sobriensb_add_sb (sb *ptr, sb *s)
10433965Sjdp{
10533965Sjdp  sb_check (ptr, s->len);
10633965Sjdp  memcpy (ptr->ptr + ptr->len, s->ptr, s->len);
10733965Sjdp  ptr->len += s->len;
10833965Sjdp}
10933965Sjdp
110218822Sdim/* Helper for sb_scrub_and_add_sb.  */
111218822Sdim
112218822Sdimstatic sb *sb_to_scrub;
113218822Sdimstatic char *scrub_position;
114218822Sdimstatic int
115218822Sdimscrub_from_sb (char *buf, int buflen)
116218822Sdim{
117218822Sdim  int copy;
118218822Sdim  copy = sb_to_scrub->len - (scrub_position - sb_to_scrub->ptr);
119218822Sdim  if (copy > buflen)
120218822Sdim    copy = buflen;
121218822Sdim  memcpy (buf, scrub_position, copy);
122218822Sdim  scrub_position += copy;
123218822Sdim  return copy;
124218822Sdim}
125218822Sdim
126218822Sdim/* Run the sb at s through do_scrub_chars and add the result to the sb
127218822Sdim   at ptr.  */
128218822Sdim
129218822Sdimvoid
130218822Sdimsb_scrub_and_add_sb (sb *ptr, sb *s)
131218822Sdim{
132218822Sdim  sb_to_scrub = s;
133218822Sdim  scrub_position = s->ptr;
134218822Sdim
135218822Sdim  sb_check (ptr, s->len);
136218822Sdim  ptr->len += do_scrub_chars (scrub_from_sb, ptr->ptr + ptr->len, s->len);
137218822Sdim
138218822Sdim  sb_to_scrub = 0;
139218822Sdim  scrub_position = 0;
140218822Sdim}
141218822Sdim
142218822Sdim/* Make sure that the sb at ptr has room for another len characters,
14377298Sobrien   and grow it if it doesn't.  */
14433965Sjdp
14533965Sjdpstatic void
146130561Sobriensb_check (sb *ptr, int len)
14733965Sjdp{
14833965Sjdp  if (ptr->len + len >= 1 << ptr->pot)
14933965Sjdp    {
15033965Sjdp      sb tmp;
15133965Sjdp      int pot = ptr->pot;
152218822Sdim
15333965Sjdp      while (ptr->len + len >= 1 << pot)
15433965Sjdp	pot++;
15533965Sjdp      sb_build (&tmp, pot);
15633965Sjdp      sb_add_sb (&tmp, ptr);
15733965Sjdp      sb_kill (ptr);
15833965Sjdp      *ptr = tmp;
15933965Sjdp    }
16033965Sjdp}
16133965Sjdp
162218822Sdim/* Make the sb at ptr point back to the beginning.  */
16333965Sjdp
16433965Sjdpvoid
165130561Sobriensb_reset (sb *ptr)
16633965Sjdp{
16733965Sjdp  ptr->len = 0;
16833965Sjdp}
16933965Sjdp
170218822Sdim/* Add character c to the end of the sb at ptr.  */
17133965Sjdp
17233965Sjdpvoid
173130561Sobriensb_add_char (sb *ptr, int c)
17433965Sjdp{
17533965Sjdp  sb_check (ptr, 1);
17633965Sjdp  ptr->ptr[ptr->len++] = c;
17733965Sjdp}
17833965Sjdp
179218822Sdim/* Add null terminated string s to the end of sb at ptr.  */
18033965Sjdp
18133965Sjdpvoid
182130561Sobriensb_add_string (sb *ptr, const char *s)
18333965Sjdp{
18433965Sjdp  int len = strlen (s);
18533965Sjdp  sb_check (ptr, len);
18633965Sjdp  memcpy (ptr->ptr + ptr->len, s, len);
18733965Sjdp  ptr->len += len;
18833965Sjdp}
18933965Sjdp
190218822Sdim/* Add string at s of length len to sb at ptr */
19133965Sjdp
19233965Sjdpvoid
193130561Sobriensb_add_buffer (sb *ptr, const char *s, int len)
19433965Sjdp{
19533965Sjdp  sb_check (ptr, len);
19633965Sjdp  memcpy (ptr->ptr + ptr->len, s, len);
19733965Sjdp  ptr->len += len;
19833965Sjdp}
19933965Sjdp
200218822Sdim/* Like sb_name, but don't include the null byte in the string.  */
20133965Sjdp
20233965Sjdpchar *
203130561Sobriensb_terminate (sb *in)
20433965Sjdp{
20533965Sjdp  sb_add_char (in, 0);
20633965Sjdp  --in->len;
20733965Sjdp  return in->ptr;
20833965Sjdp}
20933965Sjdp
210218822Sdim/* Start at the index idx into the string in sb at ptr and skip
211218822Sdim   whitespace. return the index of the first non whitespace character.  */
21233965Sjdp
21333965Sjdpint
214130561Sobriensb_skip_white (int idx, sb *ptr)
21533965Sjdp{
21633965Sjdp  while (idx < ptr->len
21733965Sjdp	 && (ptr->ptr[idx] == ' '
21833965Sjdp	     || ptr->ptr[idx] == '\t'))
21933965Sjdp    idx++;
22033965Sjdp  return idx;
22133965Sjdp}
22233965Sjdp
223218822Sdim/* Start at the index idx into the sb at ptr. skips whitespace,
224130561Sobrien   a comma and any following whitespace. returns the index of the
22577298Sobrien   next character.  */
22633965Sjdp
22733965Sjdpint
228130561Sobriensb_skip_comma (int idx, sb *ptr)
22933965Sjdp{
23033965Sjdp  while (idx < ptr->len
23133965Sjdp	 && (ptr->ptr[idx] == ' '
23233965Sjdp	     || ptr->ptr[idx] == '\t'))
23333965Sjdp    idx++;
23433965Sjdp
23533965Sjdp  if (idx < ptr->len
23633965Sjdp      && ptr->ptr[idx] == ',')
23733965Sjdp    idx++;
23833965Sjdp
23933965Sjdp  while (idx < ptr->len
24033965Sjdp	 && (ptr->ptr[idx] == ' '
24133965Sjdp	     || ptr->ptr[idx] == '\t'))
24233965Sjdp    idx++;
24333965Sjdp
24433965Sjdp  return idx;
24533965Sjdp}
246