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