Include <stdbool.h>.

(readtoken): Use `size_t' rather than int/long.
All callers adjusted.
Use `bool' rather than `int' where appropriate.
Use memset rather than an explicit loop.
Use x2nrealloc rather than xrealloc.
Allow the use of `\0' as a delimiter.
(readtokens): Likewise.
This commit is contained in:
Jim Meyering
2004-03-21 18:49:06 +00:00
parent 7c3d57a267
commit 4ee9bda98e
+61 -71
View File
@@ -1,5 +1,5 @@
/* readtokens.c -- Functions for reading tokens from an input stream.
Copyright (C) 1990-1991, 1999, 2001, 2003 Free Software Foundation, Inc.
Copyright (C) 1990-1991, 1999-2004 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,13 +19,7 @@
/* This almost supercedes xreadline stuff -- using delim="\n"
gives the same functionality, except that these functions
would never return empty lines.
To Do:
- To allow '\0' as a delimiter, I will have to change
interfaces to permit specification of delimiter-string
length.
*/
would never return empty lines. */
#ifdef HAVE_CONFIG_H
# include <config.h>
@@ -36,6 +30,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "unlocked-io.h"
#include "xalloc.h"
@@ -48,45 +43,48 @@
void
init_tokenbuffer (token_buffer *tokenbuffer)
{
tokenbuffer->size = INITIAL_TOKEN_LENGTH;
tokenbuffer->buffer = xmalloc (INITIAL_TOKEN_LENGTH);
tokenbuffer->size = 0;
tokenbuffer->buffer = NULL;
}
/* Read a token from `stream' into `tokenbuffer'.
/* Read a token from STREAM into TOKENBUFFER.
A token is delimited by any of the N_DELIM bytes in DELIM.
Upon return, the token is in tokenbuffer->buffer and
has a trailing '\0' instead of the original delimiter.
has a trailing '\0' instead of any original delimiter.
The function value is the length of the token not including
the final '\0'. When EOF is reached (i.e. on the call
after the last token is read), -1 is returned and tokenbuffer
isn't modified.
the final '\0'. Upon EOF (i.e. on the call after the last
token is read) or error, return -1 without modifying tokenbuffer.
The EOF and error conditions may be distinguished in the caller
by testing ferror (STREAM).
This function will work properly on lines containing NUL bytes
and on files that aren't newline-terminated. */
This function works properly on lines containing NUL bytes
and on files do not end with a delimiter. */
long
size_t
readtoken (FILE *stream,
const char *delim,
int n_delim,
size_t n_delim,
token_buffer *tokenbuffer)
{
char *p;
int c, i, n;
int c;
size_t i, n;
static const char *saved_delim = NULL;
static char isdelim[256];
int same_delimiters;
bool same_delimiters;
if (delim == NULL && saved_delim == NULL)
abort ();
same_delimiters = 0;
same_delimiters = false;
if (delim != saved_delim && saved_delim != NULL)
{
same_delimiters = 1;
same_delimiters = true;
for (i = 0; i < n_delim; i++)
{
if (delim[i] != saved_delim[i])
{
same_delimiters = 0;
same_delimiters = false;
break;
}
}
@@ -94,37 +92,32 @@ readtoken (FILE *stream,
if (!same_delimiters)
{
const char *t;
unsigned int j;
size_t j;
saved_delim = delim;
for (j = 0; j < sizeof (isdelim); j++)
isdelim[j] = 0;
for (t = delim; *t; t++)
isdelim[(unsigned char) *t] = 1;
memset (isdelim, 0, sizeof isdelim);
for (j = 0; j < n_delim; j++)
isdelim[(unsigned char) delim[j]] = 1;
}
p = tokenbuffer->buffer;
n = tokenbuffer->size;
i = 0;
/* FIXME: don't fool with this caching BS. Use strchr instead. */
/* FIXME: don't fool with this caching. Use strchr instead. */
/* skip over any leading delimiters */
for (c = getc (stream); c >= 0 && isdelim[c]; c = getc (stream))
{
/* empty */
}
p = tokenbuffer->buffer;
n = tokenbuffer->size;
i = 0;
for (;;)
{
if (i >= n)
{
n = 3 * (n / 2 + 1);
p = xrealloc (p, (unsigned int) n);
}
if (i == n)
p = x2nrealloc (p, &n, sizeof *p);
if (c < 0)
{
if (i == 0)
return (-1);
return -1;
p[i] = 0;
break;
}
@@ -139,64 +132,61 @@ readtoken (FILE *stream,
tokenbuffer->buffer = p;
tokenbuffer->size = n;
return (i);
return i;
}
/* Return a NULL-terminated array of pointers to tokens
read from `stream.' The number of tokens is returned
as the value of the function.
All storage is obtained through calls to malloc();
/* Build a NULL-terminated array of pointers to tokens
read from STREAM. Return the number of tokens read.
All storage is obtained through calls to xmalloc-like functions.
%%% Question: is it worth it to do a single
%%% realloc() of `tokens' just before returning? */
int
size_t
readtokens (FILE *stream,
int projected_n_tokens,
size_t projected_n_tokens,
const char *delim,
int n_delim,
size_t n_delim,
char ***tokens_out,
long **token_lengths)
size_t **token_lengths)
{
token_buffer tb, *token = &tb;
int token_length;
char **tokens;
long *lengths;
int sz;
int n_tokens;
size_t *lengths;
size_t sz;
size_t n_tokens;
if (projected_n_tokens == 0)
projected_n_tokens = 64;
else
projected_n_tokens++; /* add one for trailing NULL pointer */
sz = projected_n_tokens;
tokens = xnmalloc (sz, sizeof *tokens);
lengths = xnmalloc (sz, sizeof *lengths);
n_tokens = 0;
if (projected_n_tokens > 0)
projected_n_tokens++; /* add one for trailing NULL pointer */
else
projected_n_tokens = 64;
sz = projected_n_tokens;
tokens = xmalloc (sz * sizeof (char *));
lengths = xmalloc (sz * sizeof (long));
init_tokenbuffer (token);
for (;;)
{
char *tmp;
token_length = readtoken (stream, delim, n_delim, token);
size_t token_length = readtoken (stream, delim, n_delim, token);
if (n_tokens >= sz)
{
sz *= 2;
tokens = xrealloc (tokens, sz * sizeof (char *));
lengths = xrealloc (lengths, sz * sizeof (long));
tokens = x2nrealloc (tokens, &sz, sizeof *tokens);
lengths = xnrealloc (lengths, sz, sizeof *lengths);
}
if (token_length < 0)
if (token_length == (size_t) -1)
{
/* don't increment n_tokens for NULL entry */
tokens[n_tokens] = NULL;
lengths[n_tokens] = -1;
lengths[n_tokens] = 0;
break;
}
tmp = xmalloc ((token_length + 1) * sizeof (char));
tmp = xnmalloc (token_length + 1, sizeof *tmp);
lengths[n_tokens] = token_length;
tokens[n_tokens] = strncpy (tmp, token->buffer,
(unsigned) (token_length + 1));
tokens[n_tokens] = memcpy (tmp, token->buffer, token_length + 1);
n_tokens++;
}