Lumiera  0.pre.03
»edit your freedom«
tmpbuf.c
Go to the documentation of this file.
1 /*
2  Tmpbuf - Round Robin Temporary buffers
3 
4  Copyright (C) Lumiera.org
5  2008, 2010 Christian Thaeter <ct@pipapo.org>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
23 
32 #include "lib/safeclib.h"
33 #include "lib/tmpbuf.h"
34 
35 
36 #include <string.h>
37 #include <pthread.h>
38 #include <stdint.h>
39 #include <stdarg.h>
40 #include <nobug.h>
41 
42 
43 
45 {
46  void* buffers[64];
47  size_t sizes[64];
48  unsigned idx;
49 };
50 
51 static pthread_once_t lumiera_tmpbuf_tls_once = PTHREAD_ONCE_INIT;
52 static pthread_key_t lumiera_tmpbuf_tls_key;
53 
54 void
56 
57 static void
58 lumiera_tmpbuf_destroy (void* buf)
59 {
60  (void) buf;
62 }
63 
64 static void
65 lumiera_tmpbuf_init (void)
66 {
67  pthread_key_create (&lumiera_tmpbuf_tls_key, lumiera_tmpbuf_destroy);
68  atexit (lumiera_tmpbuf_freeall);
69 }
70 
71 
72 void
74 {
75  pthread_once (&lumiera_tmpbuf_tls_once, lumiera_tmpbuf_init);
76 
77  struct lumiera_tmpbuf_struct* buf = pthread_getspecific (lumiera_tmpbuf_tls_key);
78  if (buf)
79  {
80  pthread_setspecific (lumiera_tmpbuf_tls_key, NULL);
81  for (int idx = 0; idx < LUMIERA_TMPBUF_NUM; ++idx)
82  lumiera_free (buf->buffers[idx]);
83  lumiera_free (buf);
84  }
85 }
86 
87 
88 void*
90 {
91  pthread_once (&lumiera_tmpbuf_tls_once, lumiera_tmpbuf_init);
92 
93  struct lumiera_tmpbuf_struct* buf = pthread_getspecific (lumiera_tmpbuf_tls_key);
94  if (!buf)
95  pthread_setspecific (lumiera_tmpbuf_tls_key,
96  buf = lumiera_calloc (1, sizeof (struct lumiera_tmpbuf_struct)));
97 
98  buf->idx = (buf->idx + 1) & 0x3f;
99 
100  if (buf->sizes[buf->idx] < size || buf->sizes[buf->idx] > 8*size)
101  {
102  lumiera_free (buf->buffers[buf->idx]);
103  buf->sizes[buf->idx] = (size+4*sizeof(long)) & ~(4*sizeof(long)-1);
104  buf->buffers[buf->idx] = lumiera_malloc (buf->sizes[buf->idx]);
105  }
106  return buf->buffers[buf->idx];
107 }
108 
109 
110 char*
111 lumiera_tmpbuf_strndup (const char* src, size_t size)
112 {
113  size_t len = strlen (src);
114  len = len > size ? size : len;
115 
116  char* buf = lumiera_tmpbuf_provide (len + 1);
117  strncpy (buf, src, len);
118  buf[len] = '\0';
119 
120  return buf;
121 }
122 
123 
124 char*
125 lumiera_tmpbuf_snprintf (size_t size, const char* fmt, ...)
126 {
127  va_list args;
128 
129  va_start (args, fmt);
130  size_t len = vsnprintf (NULL, 0, fmt, args);
131  va_end (args);
132 
133  len = len > size ? size : len;
134  char* buf = lumiera_tmpbuf_provide (len+1);
135  va_start (args, fmt);
136  vsnprintf (buf, len+1, fmt, args);
137  va_end (args);
138 
139  return buf;
140 }
141 
142 
143 char*
144 lumiera_tmpbuf_strcat3 (const char* str1, size_t str1_len,
145  const char* str2, size_t str2_len,
146  const char* str3, size_t str3_len)
147 {
148  return lumiera_tmpbuf_snprintf (SIZE_MAX, "%.*s%s%.*s%s%.*s",
149  str1?str1_len:0, str1?str1:"", str1?".":"",
150  str2?str2_len:0, str2?str2:"",
151  str3?".":"", str3?str3_len:0, str3?str3:"");
152 }
153 
154 
155 char*
156 lumiera_tmpbuf_tr (const char* in, const char* from, const char* to, const char* def)
157 {
158  REQUIRE (strlen (from) == strlen (to), "from and to character set must have equal length");
159 
160  char* ret = lumiera_tmpbuf_strndup (in, SIZE_MAX);
161 
162  char* wpos;
163  char* rpos;
164  for (wpos = rpos = ret; *rpos; ++rpos, ++wpos)
165  {
166  char* found = strchr (from, *rpos);
167  if (found)
168  *wpos = to[found-from];
169  else if (def)
170  {
171  if (*def)
172  *wpos = *def;
173  else
174  {
175  ++rpos;
176  if (!*rpos)
177  break;
178  }
179  }
180  else
181  return NULL;
182  }
183  *wpos = '\0';
184 
185  return ret;
186 }
187 
188 
189 /*
190 // Local Variables:
191 // mode: C
192 // c-file-style: "gnu"
193 // indent-tabs-mode: nil
194 // End:
195 */
Portable and safe wrappers around some C-Lib functions.
void * lumiera_calloc(size_t n, size_t size)
Allocate cleared memory for an array.
Definition: safeclib.c:139
void * lumiera_tmpbuf_provide(size_t size)
Query a thread local tmpbuf.
Definition: tmpbuf.c:89
char * lumiera_tmpbuf_strndup(const char *src, size_t size)
Duplicate string to a tmpbuf.
Definition: tmpbuf.c:111
Round robin temporary buffers.
static void lumiera_free(void *mem)
Free previously allocated memory.
Definition: safeclib.h:82
void lumiera_tmpbuf_freeall(void)
free all buffers associated with this thread.
Definition: tmpbuf.c:73
void * lumiera_malloc(size_t size)
Allocate memory.
Definition: safeclib.c:122
char * lumiera_tmpbuf_tr(const char *in, const char *from, const char *to, const char *def)
Translates characters in a string, similar to the shell &#39;tr&#39; utility.
Definition: tmpbuf.c:156
char * lumiera_tmpbuf_strcat3(const char *str1, size_t str1_len, const char *str2, size_t str2_len, const char *str3, size_t str3_len)
Concat up to 3 strings in a tmpbuf.
Definition: tmpbuf.c:144
#define LUMIERA_TMPBUF_NUM
Number of buffers in the ring This also defines how many concurent buffers can be in use in one threa...
Definition: tmpbuf.h:52
char * lumiera_tmpbuf_snprintf(size_t size, const char *fmt,...)
Construct a string in a tmpbuf.
Definition: tmpbuf.c:125