maint: update copyright
[gnulib.git] / lib / readtokens.c
index 2ccf6a9..fbed2ca 100644 (file)
@@ -1,10 +1,12 @@
 /* readtokens.c  -- Functions for reading tokens from an input stream.
-   Copyright (C) 1990-1991, 1999-2004 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
+   Copyright (C) 1990-1991, 1999-2004, 2006, 2009-2014 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
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
    Written by Jim Meyering. */
 
-/* This almost supercedes xreadline stuff -- using delim="\n"
+/* This almost supersedes xreadline stuff -- using delim="\n"
    gives the same functionality, except that these functions
    would never return empty lines. */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
+#include <config.h>
 
 #include "readtokens.h"
 
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdbool.h>
 
-#include "unlocked-io.h"
 #include "xalloc.h"
 
-#define STREQ(a,b) ((a) == (b) || ((a) && (b) && *(a) == *(b) \
-                                  && strcmp(a, b) == 0))
+#if USE_UNLOCKED_IO
+# include "unlocked-io.h"
+#endif
 
 /* Initialize a tokenbuffer. */
 
@@ -47,6 +47,22 @@ init_tokenbuffer (token_buffer *tokenbuffer)
   tokenbuffer->buffer = NULL;
 }
 
+typedef size_t word;
+enum { bits_per_word = sizeof (word) * CHAR_BIT };
+
+static bool
+get_nth_bit (size_t n, word const *bitset)
+{
+  return bitset[n / bits_per_word] >> n % bits_per_word & 1;
+}
+
+static void
+set_nth_bit (size_t n, word *bitset)
+{
+  size_t one = 1;
+  bitset[n / bits_per_word] |= one << n % bits_per_word;
+}
+
 /* 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
@@ -58,53 +74,28 @@ init_tokenbuffer (token_buffer *tokenbuffer)
    by testing ferror (STREAM).
 
    This function works properly on lines containing NUL bytes
-   and on files do not end with a delimiter.  */
+   and on files that do not end with a delimiter.  */
 
 size_t
 readtoken (FILE *stream,
-          const char *delim,
-          size_t n_delim,
-          token_buffer *tokenbuffer)
+           const char *delim,
+           size_t n_delim,
+           token_buffer *tokenbuffer)
 {
   char *p;
   int c;
   size_t i, n;
-  static const char *saved_delim = NULL;
-  static char isdelim[256];
-  bool same_delimiters;
+  word isdelim[(UCHAR_MAX + bits_per_word) / bits_per_word];
 
-  if (delim == NULL && saved_delim == NULL)
-    abort ();
-
-  same_delimiters = false;
-  if (delim != saved_delim && saved_delim != NULL)
+  memset (isdelim, 0, sizeof isdelim);
+  for (i = 0; i < n_delim; i++)
     {
-      same_delimiters = true;
-      for (i = 0; i < n_delim; i++)
-       {
-         if (delim[i] != saved_delim[i])
-           {
-             same_delimiters = false;
-             break;
-           }
-       }
+      unsigned char ch = delim[i];
+      set_nth_bit (ch, isdelim);
     }
 
-  if (!same_delimiters)
-    {
-      size_t j;
-      saved_delim = delim;
-      memset (isdelim, 0, sizeof isdelim);
-      for (j = 0; j < n_delim; j++)
-       {
-         unsigned char ch = delim[j];
-         isdelim[ch] = 1;
-       }
-    }
-
-  /* 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))
+  for (c = getc (stream); c >= 0 && get_nth_bit (c, isdelim); c = getc (stream))
     {
       /* empty */
     }
@@ -115,21 +106,21 @@ readtoken (FILE *stream,
   for (;;)
     {
       if (c < 0 && i == 0)
-       return -1;
+        return -1;
 
       if (i == n)
-       p = x2nrealloc (p, &n, sizeof *p);
+        p = x2nrealloc (p, &n, sizeof *p);
 
       if (c < 0)
-       {
-         p[i] = 0;
-         break;
-       }
-      if (isdelim[c])
-       {
-         p[i] = 0;
-         break;
-       }
+        {
+          p[i] = 0;
+          break;
+        }
+      if (get_nth_bit (c, isdelim))
+        {
+          p[i] = 0;
+          break;
+        }
       p[i++] = c;
       c = getc (stream);
     }
@@ -144,15 +135,15 @@ readtoken (FILE *stream,
    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? */
+   %%% realloc() of 'tokens' just before returning? */
 
 size_t
 readtokens (FILE *stream,
-           size_t projected_n_tokens,
-           const char *delim,
-           size_t n_delim,
-           char ***tokens_out,
-           size_t **token_lengths)
+            size_t projected_n_tokens,
+            const char *delim,
+            size_t n_delim,
+            char ***tokens_out,
+            size_t **token_lengths)
 {
   token_buffer tb, *token = &tb;
   char **tokens;
@@ -163,7 +154,7 @@ readtokens (FILE *stream,
   if (projected_n_tokens == 0)
     projected_n_tokens = 64;
   else
-    projected_n_tokens++;      /* add one for trailing NULL pointer */
+    projected_n_tokens++;       /* add one for trailing NULL pointer */
 
   sz = projected_n_tokens;
   tokens = xnmalloc (sz, sizeof *tokens);
@@ -176,18 +167,18 @@ readtokens (FILE *stream,
       char *tmp;
       size_t token_length = readtoken (stream, delim, n_delim, token);
       if (n_tokens >= sz)
-       {
-         tokens = x2nrealloc (tokens, &sz, sizeof *tokens);
-         lengths = xnrealloc (lengths, sz, sizeof *lengths);
-       }
+        {
+          tokens = x2nrealloc (tokens, &sz, sizeof *tokens);
+          lengths = xnrealloc (lengths, sz, sizeof *lengths);
+        }
 
       if (token_length == (size_t) -1)
-       {
-         /* don't increment n_tokens for NULL entry */
-         tokens[n_tokens] = NULL;
-         lengths[n_tokens] = 0;
-         break;
-       }
+        {
+          /* don't increment n_tokens for NULL entry */
+          tokens[n_tokens] = NULL;
+          lengths[n_tokens] = 0;
+          break;
+        }
       tmp = xnmalloc (token_length + 1, sizeof *tmp);
       lengths[n_tokens] = token_length;
       tokens[n_tokens] = memcpy (tmp, token->buffer, token_length + 1);
@@ -198,5 +189,7 @@ readtokens (FILE *stream,
   *tokens_out = tokens;
   if (token_lengths != NULL)
     *token_lengths = lengths;
+  else
+    free (lengths);
   return n_tokens;
 }