xref: /netbsd-src/external/gpl3/binutils.old/dist/gas/sb.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
175fd0b74Schristos /* sb.c - string buffer manipulation routines
2*e992f068Schristos    Copyright (C) 1994-2022 Free Software Foundation, Inc.
375fd0b74Schristos 
475fd0b74Schristos    Written by Steve and Judy Chamberlain of Cygnus Support,
575fd0b74Schristos       sac@cygnus.com
675fd0b74Schristos 
775fd0b74Schristos    This file is part of GAS, the GNU Assembler.
875fd0b74Schristos 
975fd0b74Schristos    GAS is free software; you can redistribute it and/or modify
1075fd0b74Schristos    it under the terms of the GNU General Public License as published by
1175fd0b74Schristos    the Free Software Foundation; either version 3, or (at your option)
1275fd0b74Schristos    any later version.
1375fd0b74Schristos 
1475fd0b74Schristos    GAS is distributed in the hope that it will be useful,
1575fd0b74Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
1675fd0b74Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1775fd0b74Schristos    GNU General Public License for more details.
1875fd0b74Schristos 
1975fd0b74Schristos    You should have received a copy of the GNU General Public License
2075fd0b74Schristos    along with GAS; see the file COPYING.  If not, write to the Free
2175fd0b74Schristos    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
2275fd0b74Schristos    02110-1301, USA.  */
2375fd0b74Schristos 
2475fd0b74Schristos #include "as.h"
2575fd0b74Schristos #include "sb.h"
2675fd0b74Schristos 
2775fd0b74Schristos #include <limits.h>
2875fd0b74Schristos #ifndef CHAR_BIT
2975fd0b74Schristos #define CHAR_BIT 8
3075fd0b74Schristos #endif
3175fd0b74Schristos 
3275fd0b74Schristos /* These routines are about manipulating strings.
3375fd0b74Schristos 
3475fd0b74Schristos    They are managed in things called `sb's which is an abbreviation
3575fd0b74Schristos    for string buffers.  An sb has to be created, things can be glued
3675fd0b74Schristos    on to it, and at the end of it's life it should be freed.  The
3775fd0b74Schristos    contents should never be pointed at whilst it is still growing,
3875fd0b74Schristos    since it could be moved at any time
3975fd0b74Schristos 
4075fd0b74Schristos    eg:
4175fd0b74Schristos    sb_new (&foo);
4275fd0b74Schristos    sb_grow... (&foo,...);
4375fd0b74Schristos    use foo->ptr[*];
4475fd0b74Schristos    sb_kill (&foo);  */
4575fd0b74Schristos 
4675fd0b74Schristos /* Buffers start at INIT_ALLOC size, and roughly double each time we
4775fd0b74Schristos    go over the current allocation.  MALLOC_OVERHEAD is a guess at the
4875fd0b74Schristos    system malloc overhead.  We aim to not waste any memory in the
4975fd0b74Schristos    underlying page/chunk allocated by the system malloc.  */
5075fd0b74Schristos #define MALLOC_OVERHEAD (2 * sizeof (size_t))
5175fd0b74Schristos #define INIT_ALLOC (64 - MALLOC_OVERHEAD - 1)
5275fd0b74Schristos 
5375fd0b74Schristos static void sb_check (sb *, size_t);
5475fd0b74Schristos 
5575fd0b74Schristos /* Initializes an sb.  */
5675fd0b74Schristos 
5775fd0b74Schristos void
sb_build(sb * ptr,size_t size)5875fd0b74Schristos sb_build (sb *ptr, size_t size)
5975fd0b74Schristos {
6075fd0b74Schristos   ptr->ptr = XNEWVEC (char, size + 1);
6175fd0b74Schristos   ptr->max = size;
6275fd0b74Schristos   ptr->len = 0;
6375fd0b74Schristos }
6475fd0b74Schristos 
6575fd0b74Schristos void
sb_new(sb * ptr)6675fd0b74Schristos sb_new (sb *ptr)
6775fd0b74Schristos {
6875fd0b74Schristos   sb_build (ptr, INIT_ALLOC);
6975fd0b74Schristos }
7075fd0b74Schristos 
7175fd0b74Schristos /* Deallocate the sb at ptr.  */
7275fd0b74Schristos 
7375fd0b74Schristos void
sb_kill(sb * ptr)7475fd0b74Schristos sb_kill (sb *ptr)
7575fd0b74Schristos {
7675fd0b74Schristos   free (ptr->ptr);
7775fd0b74Schristos }
7875fd0b74Schristos 
7975fd0b74Schristos /* Add the sb at s to the end of the sb at ptr.  */
8075fd0b74Schristos 
8175fd0b74Schristos void
sb_add_sb(sb * ptr,sb * s)8275fd0b74Schristos sb_add_sb (sb *ptr, sb *s)
8375fd0b74Schristos {
8475fd0b74Schristos   sb_check (ptr, s->len);
8575fd0b74Schristos   memcpy (ptr->ptr + ptr->len, s->ptr, s->len);
8675fd0b74Schristos   ptr->len += s->len;
8775fd0b74Schristos }
8875fd0b74Schristos 
8975fd0b74Schristos /* Helper for sb_scrub_and_add_sb.  */
9075fd0b74Schristos 
9175fd0b74Schristos static sb *sb_to_scrub;
9275fd0b74Schristos static char *scrub_position;
9375fd0b74Schristos static size_t
scrub_from_sb(char * buf,size_t buflen)9475fd0b74Schristos scrub_from_sb (char *buf, size_t buflen)
9575fd0b74Schristos {
9675fd0b74Schristos   size_t copy;
9775fd0b74Schristos   copy = sb_to_scrub->len - (scrub_position - sb_to_scrub->ptr);
9875fd0b74Schristos   if (copy > buflen)
9975fd0b74Schristos     copy = buflen;
10075fd0b74Schristos   memcpy (buf, scrub_position, copy);
10175fd0b74Schristos   scrub_position += copy;
10275fd0b74Schristos   return copy;
10375fd0b74Schristos }
10475fd0b74Schristos 
10575fd0b74Schristos /* Run the sb at s through do_scrub_chars and add the result to the sb
10675fd0b74Schristos    at ptr.  */
10775fd0b74Schristos 
10875fd0b74Schristos void
sb_scrub_and_add_sb(sb * ptr,sb * s)10975fd0b74Schristos sb_scrub_and_add_sb (sb *ptr, sb *s)
11075fd0b74Schristos {
11175fd0b74Schristos   sb_to_scrub = s;
11275fd0b74Schristos   scrub_position = s->ptr;
11375fd0b74Schristos 
114*e992f068Schristos   /* do_scrub_chars can expand text, for example when replacing
115*e992f068Schristos      # 123 "filename"
116*e992f068Schristos      with
117*e992f068Schristos      \t.linefile 123 "filename"
118*e992f068Schristos      or when replacing a 'c with the decimal ascii number for c.
119*e992f068Schristos      So we loop until the input S is consumed.  */
120*e992f068Schristos   while (1)
121*e992f068Schristos     {
122*e992f068Schristos       size_t copy = s->len - (scrub_position - s->ptr) + do_scrub_pending ();
123*e992f068Schristos       if (copy == 0)
124*e992f068Schristos 	break;
125*e992f068Schristos       sb_check (ptr, copy);
126*e992f068Schristos       ptr->len += do_scrub_chars (scrub_from_sb, ptr->ptr + ptr->len,
127*e992f068Schristos 				  ptr->max - ptr->len);
128*e992f068Schristos     }
12975fd0b74Schristos 
13075fd0b74Schristos   sb_to_scrub = 0;
13175fd0b74Schristos   scrub_position = 0;
13275fd0b74Schristos }
13375fd0b74Schristos 
13475fd0b74Schristos /* Make sure that the sb at ptr has room for another len characters,
13575fd0b74Schristos    and grow it if it doesn't.  */
13675fd0b74Schristos 
13775fd0b74Schristos static void
sb_check(sb * ptr,size_t len)13875fd0b74Schristos sb_check (sb *ptr, size_t len)
13975fd0b74Schristos {
14075fd0b74Schristos   size_t want = ptr->len + len;
14175fd0b74Schristos 
14275fd0b74Schristos   if (want > ptr->max)
14375fd0b74Schristos     {
14475fd0b74Schristos       size_t max;
14575fd0b74Schristos 
14675fd0b74Schristos       want += MALLOC_OVERHEAD + 1;
14775fd0b74Schristos       if ((ssize_t) want < 0)
14875fd0b74Schristos 	as_fatal ("string buffer overflow");
14975fd0b74Schristos #if GCC_VERSION >= 3004
15075fd0b74Schristos       max = (size_t) 1 << (CHAR_BIT * sizeof (want)
15175fd0b74Schristos 			   - (sizeof (want) <= sizeof (long)
15275fd0b74Schristos 			      ? __builtin_clzl ((long) want)
15375fd0b74Schristos 			      : __builtin_clzll ((long long) want)));
15475fd0b74Schristos #else
15575fd0b74Schristos       max = 128;
15675fd0b74Schristos       while (want > max)
15775fd0b74Schristos 	max <<= 1;
15875fd0b74Schristos #endif
15975fd0b74Schristos       max -= MALLOC_OVERHEAD + 1;
16075fd0b74Schristos       ptr->max = max;
16175fd0b74Schristos       ptr->ptr = XRESIZEVEC (char, ptr->ptr, max + 1);
16275fd0b74Schristos     }
16375fd0b74Schristos }
16475fd0b74Schristos 
16575fd0b74Schristos /* Make the sb at ptr point back to the beginning.  */
16675fd0b74Schristos 
16775fd0b74Schristos void
sb_reset(sb * ptr)16875fd0b74Schristos sb_reset (sb *ptr)
16975fd0b74Schristos {
17075fd0b74Schristos   ptr->len = 0;
17175fd0b74Schristos }
17275fd0b74Schristos 
17375fd0b74Schristos /* Add character c to the end of the sb at ptr.  */
17475fd0b74Schristos 
17575fd0b74Schristos void
sb_add_char(sb * ptr,size_t c)17675fd0b74Schristos sb_add_char (sb *ptr, size_t c)
17775fd0b74Schristos {
17875fd0b74Schristos   sb_check (ptr, 1);
17975fd0b74Schristos   ptr->ptr[ptr->len++] = c;
18075fd0b74Schristos }
18175fd0b74Schristos 
18275fd0b74Schristos /* Add null terminated string s to the end of sb at ptr.  */
18375fd0b74Schristos 
18475fd0b74Schristos void
sb_add_string(sb * ptr,const char * s)18575fd0b74Schristos sb_add_string (sb *ptr, const char *s)
18675fd0b74Schristos {
18775fd0b74Schristos   size_t len = strlen (s);
18875fd0b74Schristos   sb_check (ptr, len);
18975fd0b74Schristos   memcpy (ptr->ptr + ptr->len, s, len);
19075fd0b74Schristos   ptr->len += len;
19175fd0b74Schristos }
19275fd0b74Schristos 
19375fd0b74Schristos /* Add string at s of length len to sb at ptr */
19475fd0b74Schristos 
19575fd0b74Schristos void
sb_add_buffer(sb * ptr,const char * s,size_t len)19675fd0b74Schristos sb_add_buffer (sb *ptr, const char *s, size_t len)
19775fd0b74Schristos {
19875fd0b74Schristos   sb_check (ptr, len);
19975fd0b74Schristos   memcpy (ptr->ptr + ptr->len, s, len);
20075fd0b74Schristos   ptr->len += len;
20175fd0b74Schristos }
20275fd0b74Schristos 
20375fd0b74Schristos /* Write terminating NUL and return string.  */
20475fd0b74Schristos 
20575fd0b74Schristos char *
sb_terminate(sb * in)20675fd0b74Schristos sb_terminate (sb *in)
20775fd0b74Schristos {
20875fd0b74Schristos   in->ptr[in->len] = 0;
20975fd0b74Schristos   return in->ptr;
21075fd0b74Schristos }
21175fd0b74Schristos 
21275fd0b74Schristos /* Start at the index idx into the string in sb at ptr and skip
21375fd0b74Schristos    whitespace. return the index of the first non whitespace character.  */
21475fd0b74Schristos 
21575fd0b74Schristos size_t
sb_skip_white(size_t idx,sb * ptr)21675fd0b74Schristos sb_skip_white (size_t idx, sb *ptr)
21775fd0b74Schristos {
21875fd0b74Schristos   while (idx < ptr->len
21975fd0b74Schristos 	 && (ptr->ptr[idx] == ' '
22075fd0b74Schristos 	     || ptr->ptr[idx] == '\t'))
22175fd0b74Schristos     idx++;
22275fd0b74Schristos   return idx;
22375fd0b74Schristos }
22475fd0b74Schristos 
22575fd0b74Schristos /* Start at the index idx into the sb at ptr. skips whitespace,
22675fd0b74Schristos    a comma and any following whitespace. returns the index of the
22775fd0b74Schristos    next character.  */
22875fd0b74Schristos 
22975fd0b74Schristos size_t
sb_skip_comma(size_t idx,sb * ptr)23075fd0b74Schristos sb_skip_comma (size_t idx, sb *ptr)
23175fd0b74Schristos {
23275fd0b74Schristos   while (idx < ptr->len
23375fd0b74Schristos 	 && (ptr->ptr[idx] == ' '
23475fd0b74Schristos 	     || ptr->ptr[idx] == '\t'))
23575fd0b74Schristos     idx++;
23675fd0b74Schristos 
23775fd0b74Schristos   if (idx < ptr->len
23875fd0b74Schristos       && ptr->ptr[idx] == ',')
23975fd0b74Schristos     idx++;
24075fd0b74Schristos 
24175fd0b74Schristos   while (idx < ptr->len
24275fd0b74Schristos 	 && (ptr->ptr[idx] == ' '
24375fd0b74Schristos 	     || ptr->ptr[idx] == '\t'))
24475fd0b74Schristos     idx++;
24575fd0b74Schristos 
24675fd0b74Schristos   return idx;
24775fd0b74Schristos }
248