gpg: Fix build on Windows.
[gnupg.git] / common / ccparray.c
1 /* ccparray.c - A simple dynamic array for character pointer.
2  * Copyright (C) 2016 g10 Code GmbH
3  *
4  * This file is part of GnuPG.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of either
8  *
9  *   - the GNU Lesser General Public License as published by the Free
10  *     Software Foundation; either version 3 of the License, or (at
11  *     your option) any later version.
12  *
13  * or
14  *
15  *   - the GNU General Public License as published by the Free
16  *     Software Foundation; either version 2 of the License, or (at
17  *     your option) any later version.
18  *
19  * or both in parallel, as here.
20  *
21  * This file is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, see <https://www.gnu.org/licenses/>.
28  */
29
30 #include <config.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <stdarg.h>
34
35 #include "util.h"
36 #include "ccparray.h"
37
38
39 /* A simple implementation of a dynamic array of const char pointers.
40  * The example code:
41  *
42  *   ccparray_t ccp;
43  *   const char **argv;
44  *   int i;
45  *
46  *   ccparray_init (&ccp, 0);
47  *   ccparray_put (&ccp, "First arg");
48  *   ccparray_put (&ccp, "Second arg");
49  *   ccparray_put (&ccp, NULL);
50  *   ccparray_put (&ccp, "Fourth arg");
51  *   argv = ccparray_get (&ccp, NULL);
52  *   if (!argv)
53  *     die ("error building array: %s\n", strerror (errno));
54  *   for (i=0; argv[i]; i++)
55  *     printf ("[%d] = '%s'\n", i, argv[i]);
56  *   xfree (argv);
57  *
58  * will result in this output:
59  *
60  *   [0] = 'First arg'
61  *   [1] = 'Second arg'
62  *
63  * Note that allocation errors are detected but only returned with the
64  * final ccparray_get(); this helps not to clutter the code with out
65  * of core checks.
66  */
67
68 void
69 ccparray_init (ccparray_t *cpa, unsigned int initialsize)
70 {
71   if (!initialsize)
72     cpa->size = 16;
73   else if (initialsize < (1<<16))
74     cpa->size = initialsize;
75   else
76     cpa->size = (1<<16);
77
78   cpa->count = 0;
79   cpa->out_of_core = 0;
80   cpa->array = xtrycalloc (cpa->size, sizeof *cpa->array);
81   if (!cpa->array)
82     cpa->out_of_core = errno;
83 }
84
85
86 void
87 ccparray_put (ccparray_t *cpa, const char *value)
88 {
89   if (cpa->out_of_core)
90     return;
91
92   if (cpa->count + 1 >= cpa->size)
93     {
94       const char **newarray;
95       size_t n, newsize;
96
97       if (cpa->size < 8)
98         newsize = 16;
99       else if (cpa->size < 4096)
100         newsize = 2 * cpa->size;
101       else if (cpa->size < (1<<16))
102         newsize = cpa->size + 2048;
103       else
104         {
105           cpa->out_of_core = ENOMEM;
106           return;
107         }
108
109       newarray = xtrycalloc (newsize, sizeof *newarray);
110       if (!newarray)
111         {
112           cpa->out_of_core = errno ? errno : ENOMEM;
113           return;
114         }
115       for (n=0; n < cpa->size; n++)
116         newarray[n] = cpa->array[n];
117       xfree (cpa->array);
118       cpa->array = newarray;
119       cpa->size = newsize;
120
121     }
122   cpa->array[cpa->count++] = value;
123 }
124
125
126 const char **
127 ccparray_get (ccparray_t *cpa, size_t *r_count)
128 {
129   const char **result;
130
131   if (cpa->out_of_core)
132     {
133       if (cpa->array)
134         {
135           xfree (cpa->array);
136           cpa->array = NULL;
137         }
138       gpg_err_set_errno (cpa->out_of_core);
139       return NULL;
140     }
141
142   result= cpa->array;
143   if (r_count)
144     *r_count = cpa->count;
145   cpa->array = NULL;
146   cpa->out_of_core = ENOMEM; /* hack to make sure it won't get reused. */
147   return result;
148 }