maint: update copyright
[gnulib.git] / lib / readtokens0.c
1 /* readtokens0.c -- Read NUL-separated tokens from an input stream.
2
3    Copyright (C) 2004, 2006, 2009-2014 Free Software Foundation, Inc.
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18    Written by Jim Meyering. */
19
20 #include <config.h>
21
22 #include <stdlib.h>
23
24 #include "readtokens0.h"
25
26 #define obstack_chunk_alloc malloc
27 #define obstack_chunk_free free
28
29 void
30 readtokens0_init (struct Tokens *t)
31 {
32   t->n_tok = 0;
33   t->tok = NULL;
34   t->tok_len = NULL;
35   obstack_init (&t->o_data);
36   obstack_init (&t->o_tok);
37   obstack_init (&t->o_tok_len);
38 }
39
40 void
41 readtokens0_free (struct Tokens *t)
42 {
43   obstack_free (&t->o_data, NULL);
44   obstack_free (&t->o_tok, NULL);
45   obstack_free (&t->o_tok_len, NULL);
46 }
47
48 /* Finalize (in the obstack_finish sense) the current token
49    and record its pointer and length.  */
50 static void
51 save_token (struct Tokens *t)
52 {
53   /* Don't count the trailing NUL byte in the length.  */
54   size_t len = obstack_object_size (&t->o_data) - 1;
55   char const *s = obstack_finish (&t->o_data);
56   obstack_ptr_grow (&t->o_tok, s);
57   obstack_grow (&t->o_tok_len, &len, sizeof len);
58   t->n_tok++;
59 }
60
61 /* Read NUL-separated tokens from stream IN into T until EOF or error.
62    The final NUL is optional.  Always append a NULL pointer to the
63    resulting list of token pointers, but that pointer isn't counted
64    via t->n_tok.  Return true if successful.  */
65 bool
66 readtokens0 (FILE *in, struct Tokens *t)
67 {
68
69   while (1)
70     {
71       int c = fgetc (in);
72       if (c == EOF)
73         {
74           size_t len = obstack_object_size (&t->o_data);
75           /* If the current object has nonzero length, then there
76              was no NUL byte at EOF -- or maybe there was an error,
77              in which case, we need to append a NUL byte to our buffer.  */
78           if (len)
79             {
80               obstack_1grow (&t->o_data, '\0');
81               save_token (t);
82             }
83
84           break;
85         }
86
87       obstack_1grow (&t->o_data, c);
88       if (c == '\0')
89         save_token (t);
90     }
91
92   /* Add a NULL pointer at the end, in case the caller (like du)
93      requires an argv-style array of strings.  */
94   obstack_ptr_grow (&t->o_tok, NULL);
95
96   t->tok = obstack_finish (&t->o_tok);
97   t->tok_len = obstack_finish (&t->o_tok_len);
98   return ! ferror (in);
99 }