1 /* readtokens.c -- Functions for reading tokens from an input stream.
2 Copyright (C) 1990-1991 Jim Meyering.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 Written by Jim Meyering. */
20 /* This almost supercedes xreadline stuff -- using delim="\n"
21 gives the same functionality, except that these functions
22 would never return empty lines.
25 - To allow '\0' as a delimiter, I will have to change
26 interfaces to permit specification of delimiter-string
40 #if defined (STDC_HEADERS) || defined(HAVE_STRING_H)
42 /* An ANSI string.h and pre-ANSI memory.h might conflict. */
43 #if !defined (STDC_HEADERS) && defined (HAVE_MEMORY_H)
45 #endif /* not STDC_HEADERS and HAVE_MEMORY_H */
46 #else /* not STDC_HEADERS and not HAVE_STRING_H */
48 /* memory.h and strings.h conflict on some systems. */
49 #endif /* not STDC_HEADERS and not HAVE_STRING_H */
51 #include "readtokens.h"
54 #define STREQ(a,b) ((a) == (b) || ((a) && (b) && *(a) == *(b) \
55 && strcmp(a, b) == 0))
57 /* Initialize a tokenbuffer. */
60 init_tokenbuffer (token_buffer
*tokenbuffer
)
62 tokenbuffer
->size
= INITIAL_TOKEN_LENGTH
;
63 tokenbuffer
->buffer
= ((char *) xmalloc (INITIAL_TOKEN_LENGTH
));
66 /* Read a token from `stream' into `tokenbuffer'.
67 Upon return, the token is in tokenbuffer->buffer and
68 has a trailing '\0' instead of the original delimiter.
69 The function value is the length of the token not including
70 the final '\0'. When EOF is reached (i.e. on the call
71 after the last token is read), -1 is returned and tokenbuffer
74 This function will work properly on lines containing NUL bytes
75 and on files that aren't newline-terminated. */
78 readtoken (FILE *stream
, const char *delim
, int n_delim
,
79 token_buffer
*tokenbuffer
)
83 static const char *saved_delim
= NULL
;
84 static char isdelim
[256];
87 if (delim
== NULL
&& saved_delim
== NULL
)
91 if (delim
!= saved_delim
&& saved_delim
!= NULL
)
94 for (i
= 0; i
< n_delim
; i
++)
96 if (delim
[i
] != saved_delim
[i
])
104 if (!same_delimiters
)
108 for (i
= 0; i
< sizeof (isdelim
); i
++)
110 for (t
= delim
; *t
; t
++)
111 isdelim
[(unsigned int) *t
] = 1;
114 p
= tokenbuffer
->buffer
;
115 n
= tokenbuffer
->size
;
118 /* FIXME: don't fool with this caching BS. Use strchr instead. */
119 /* skip over any leading delimiters */
120 for (c
= getc (stream
); c
>= 0 && isdelim
[c
]; c
= getc (stream
))
130 p
= xrealloc (p
, (unsigned int) n
);
148 tokenbuffer
->buffer
= p
;
149 tokenbuffer
->size
= n
;
153 /* Return a NULL-terminated array of pointers to tokens
154 read from `stream.' The number of tokens is returned
155 as the value of the function.
156 All storage is obtained through calls to malloc();
158 %%% Question: is it worth it to do a single
159 %%% realloc() of `tokens' just before returning? */
162 readtokens (FILE *stream
, int projected_n_tokens
,
163 const char *delim
, int n_delim
,
164 char ***tokens_out
, long **token_lengths
)
166 token_buffer tb
, *token
= &tb
;
174 if (projected_n_tokens
> 0)
175 projected_n_tokens
++; /* add one for trailing NULL pointer */
177 projected_n_tokens
= 64;
178 sz
= projected_n_tokens
;
179 tokens
= (char **) xmalloc (sz
* sizeof (char *));
180 lengths
= (long *) xmalloc (sz
* sizeof (long));
182 init_tokenbuffer (token
);
186 token_length
= readtoken (stream
, delim
, n_delim
, token
);
190 tokens
= (char **) xrealloc (tokens
, sz
* sizeof (char *));
191 lengths
= (long *) xrealloc (lengths
, sz
* sizeof (long));
194 if (token_length
< 0)
196 /* don't increment n_tokens for NULL entry */
197 tokens
[n_tokens
] = NULL
;
198 lengths
[n_tokens
] = -1;
201 tmp
= (char *) xmalloc ((token_length
+ 1) * sizeof (char));
202 lengths
[n_tokens
] = token_length
;
203 tokens
[n_tokens
] = strncpy (tmp
, token
->buffer
,
204 (unsigned) (token_length
+ 1));
208 free (token
->buffer
);
209 *tokens_out
= tokens
;
210 if (token_lengths
!= NULL
)
211 *token_lengths
= lengths
;