1 /* readtokens.c -- Functions for reading tokens from an input stream.
3 Copyright (C) 1990-1991, 1999-2004, 2006, 2009-2024 Free Software
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <https://www.gnu.org/licenses/>.
19 Written by Jim Meyering. */
21 /* This almost supersedes xreadline stuff -- using delim="\n"
22 gives the same functionality, except that these functions
23 would never return empty lines. */
27 #include "readtokens.h"
37 # include "unlocked-io.h"
40 /* Initialize a tokenbuffer. */
43 init_tokenbuffer (token_buffer
*tokenbuffer
)
45 tokenbuffer
->size
= 0;
46 tokenbuffer
->buffer
= NULL
;
50 enum { bits_per_word
= sizeof (word
) * CHAR_BIT
};
53 get_nth_bit (size_t n
, word
const *bitset
)
55 return bitset
[n
/ bits_per_word
] >> n
% bits_per_word
& 1;
59 set_nth_bit (size_t n
, word
*bitset
)
62 bitset
[n
/ bits_per_word
] |= one
<< n
% bits_per_word
;
65 /* Read a token from STREAM into TOKENBUFFER.
66 A token is delimited by any of the N_DELIM bytes in DELIM.
67 Upon return, the token is in tokenbuffer->buffer and
68 has a trailing '\0' instead of any original delimiter.
69 The function value is the length of the token not including
70 the final '\0'. Upon EOF (i.e. on the call after the last
71 token is read) or error, return -1 without modifying tokenbuffer.
72 The EOF and error conditions may be distinguished in the caller
73 by testing ferror (STREAM).
75 This function works properly on lines containing NUL bytes
76 and on files that do not end with a delimiter. */
79 readtoken (FILE *stream
,
82 token_buffer
*tokenbuffer
)
86 word isdelim
[(UCHAR_MAX
+ bits_per_word
) / bits_per_word
];
88 memset (isdelim
, 0, sizeof isdelim
);
89 for (i
= 0; i
< n_delim
; i
++)
91 unsigned char ch
= delim
[i
];
92 set_nth_bit (ch
, isdelim
);
95 /* skip over any leading delimiters */
96 for (c
= getc (stream
); c
>= 0 && get_nth_bit (c
, isdelim
); c
= getc (stream
))
101 char *p
= tokenbuffer
->buffer
;
102 idx_t n
= tokenbuffer
->size
;
110 p
= xpalloc (p
, &n
, 1, -1, sizeof *p
);
117 if (get_nth_bit (c
, isdelim
))
126 tokenbuffer
->buffer
= p
;
127 tokenbuffer
->size
= n
;
131 /* Build a NULL-terminated array of pointers to tokens
132 read from STREAM. Return the number of tokens read.
133 All storage is obtained through calls to xmalloc-like functions.
135 %%% Question: is it worth it to do a single
136 %%% realloc() of 'tokens' just before returning? */
139 readtokens (FILE *stream
,
140 size_t projected_n_tokens
,
144 size_t **token_lengths
)
146 token_buffer tb
, *token
= &tb
;
151 if (projected_n_tokens
== 0)
152 projected_n_tokens
= 64;
154 projected_n_tokens
++; /* add one for trailing NULL pointer */
156 sz
= projected_n_tokens
;
157 tokens
= xnmalloc (sz
, sizeof *tokens
);
158 lengths
= xnmalloc (sz
, sizeof *lengths
);
161 init_tokenbuffer (token
);
165 size_t token_length
= readtoken (stream
, delim
, n_delim
, token
);
168 tokens
= xpalloc (tokens
, &sz
, 1, -1, sizeof *tokens
);
169 lengths
= xreallocarray (lengths
, sz
, sizeof *lengths
);
172 if (token_length
== (size_t) -1)
174 /* don't increment n_tokens for NULL entry */
175 tokens
[n_tokens
] = NULL
;
176 lengths
[n_tokens
] = 0;
179 tmp
= xnmalloc (token_length
+ 1, sizeof *tmp
);
180 lengths
[n_tokens
] = token_length
;
181 tokens
[n_tokens
] = memcpy (tmp
, token
->buffer
, token_length
+ 1);
185 free (token
->buffer
);
186 *tokens_out
= tokens
;
187 if (token_lengths
!= NULL
)
188 *token_lengths
= lengths
;