1 /* -*- mode: c; c-file-style: "gnu" -*-
2 * ccze-compat.c -- OS compatibility stuff for CCZE
3 * Copyright (C) 2003 Gergely Nagy <algernon@bonehunter.rulez.org>
4 *
5 * This file is part of ccze.
6 *
7 * ccze is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * ccze is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include <ccze.h>
23
24 #include "system.h"
25 #include "ccze-compat.h"
26
27 #include <ctype.h>
28 #include <errno.h>
29 #ifdef HAVE_GETOPT_H
30 # include <getopt.h>
31 #endif
32 #include <stdarg.h>
33 #include <stddef.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 #define XSREALLOC(ptr, type, nmemb) \
40 ptr = (type*)ccze_realloc (ptr, nmemb * sizeof (type))
41
42 #if malloc == rpl_malloc
43 #undef malloc
44 #undef realloc
45 #endif
46
47 void *
ccze_malloc(size_t size)48 ccze_malloc (size_t size)
49 {
50 register void *value = malloc (size);
51 if (value == 0)
52 exit (2);
53 return value;
54 }
55
56 void *
ccze_realloc(void * ptr,size_t size)57 ccze_realloc (void *ptr, size_t size)
58 {
59 register void *value = realloc (ptr, size);
60 if (value == 0)
61 exit (2);
62 return value;
63 }
64
65 void *
ccze_calloc(size_t nmemb,size_t size)66 ccze_calloc (size_t nmemb, size_t size)
67 {
68 register void *value = calloc (nmemb, size);
69 if (value == 0)
70 exit (2);
71 return value;
72 }
73
74 #ifndef HAVE_STRNDUP
75 char *
strndup(const char * s,size_t size)76 strndup (const char *s, size_t size)
77 {
78 char *ns = (char *)ccze_malloc (size + 1);
79 memcpy (ns, s, size);
80 ns[size] = '\0';
81 return ns;
82 }
83 #endif
84
85 #ifndef HAVE_ARGP_PARSE
86 error_t
argp_parse(const struct argp * argps,int argc,char ** argv,unsigned flags,int arg_index,void * input)87 argp_parse (const struct argp *argps, int argc, char **argv,
88 unsigned flags, int arg_index, void *input)
89 {
90 char *options;
91 int optpos = 0, optionspos = 0, optionssize = 30;
92 struct argp_state *state;
93 int c;
94 #if HAVE_GETOPT_LONG
95 struct option *longopts;
96 int longoptionspos = 0;
97
98 longopts = (struct option *)ccze_calloc (optionssize,
99 sizeof (struct option));
100 #endif
101
102 state = (struct argp_state *)ccze_malloc (sizeof (struct argp_state));
103 state->input = input;
104
105 options = (char *)ccze_calloc (optionssize, sizeof (char *));
106 while (argps->options[optpos].name != NULL)
107 {
108 if (optionspos >= optionssize)
109 {
110 optionssize *= 2;
111 XSREALLOC (options, char, optionssize);
112 #if HAVE_GETOPT_LONG
113 XSREALLOC (longopts, struct option, optionssize);
114 #endif
115 }
116 options[optionspos++] = (char) argps->options[optpos].key;
117 #if HAVE_GETOPT_LONG
118 longopts[longoptionspos].name = argps->options[optpos].name;
119 if (argps->options[optpos].arg)
120 longopts[longoptionspos].has_arg = required_argument;
121 else
122 longopts[longoptionspos].has_arg = no_argument;
123 longopts[longoptionspos].flag = NULL;
124 longopts[longoptionspos].val = argps->options[optpos].key;
125 longoptionspos++;
126 #endif
127 if (argps->options[optpos].arg)
128 options[optionspos++] = ':';
129 optpos++;
130 }
131 if (optionspos + 4 >= optionssize)
132 {
133 optionssize += 5;
134 XSREALLOC (options, char, optionssize);
135 #if HAVE_GETOPT_LONG
136 XSREALLOC (longopts, struct option, optionssize);
137 #endif
138 }
139 options[optionspos++] = 'V';
140 options[optionspos++] = '?';
141 options[optionspos] = '\0';
142 #if HAVE_GETOPT_LONG
143 longopts[longoptionspos].name = "help";
144 longopts[longoptionspos].has_arg = no_argument;
145 longopts[longoptionspos].flag = NULL;
146 longopts[longoptionspos].val = '?';
147 longoptionspos++;
148 longopts[longoptionspos].name = "version";
149 longopts[longoptionspos].has_arg = no_argument;
150 longopts[longoptionspos].flag = NULL;
151 longopts[longoptionspos].val = 'V';
152 longoptionspos++;
153 longopts[longoptionspos].name = NULL;
154 longopts[longoptionspos].has_arg = 0;
155 longopts[longoptionspos].flag = NULL;
156 longopts[longoptionspos].val = 0;
157 #endif
158
159 #if HAVE_GETOPT_LONG
160 while ((c = getopt_long (argc, argv, options, longopts, NULL)) != -1)
161 #else
162 while ((c = getopt (argc, argv, options)) != -1)
163 #endif
164 {
165 switch (c)
166 {
167 case '?':
168 printf ("Usage: %s [OPTION...]\n%s\n\n", argp_program_name,
169 argps->doc);
170 optpos = 0;
171 while (argps->options[optpos].name != NULL)
172 {
173 if (!(argps->options[optpos].flags & OPTION_HIDDEN))
174 #if HAVE_GETOPT_LONG
175 printf (" -%c, --%-15s %-12s\t%s\n",
176 argps->options[optpos].key,
177 argps->options[optpos].name,
178 (argps->options[optpos].arg) ?
179 argps->options[optpos].arg : "",
180 argps->options[optpos].doc);
181 #else
182 printf (" -%c %-12s\t%s\n", argps->options[optpos].key,
183 (argps->options[optpos].arg) ?
184 argps->options[optpos].arg : "",
185 argps->options[optpos].doc);
186 #endif
187 optpos++;
188 }
189 printf ("\nReport bugs to %s.\n", argp_program_bug_address);
190 exit (0);
191 break;
192 case 'V':
193 printf ("%s\n", argp_program_version);
194 exit (0);
195 break;
196 default:
197 argps->parser (c, optarg, state);
198 break;
199 }
200 }
201 free (state);
202 free (options);
203 #if HAVE_GETOPT_LONG
204 free (longopts);
205 #endif
206 return 0;
207 }
208
209 error_t
argp_error(const struct argp_state * state,char * fmt,...)210 argp_error (const struct argp_state *state, char *fmt, ...)
211 {
212 va_list ap;
213
214 va_start (ap, fmt);
215 fprintf (stderr, "%s: ", argp_program_name);
216 vfprintf (stderr, fmt, ap);
217 fprintf (stderr, "\nTry `%s -?' for more information.\n", argp_program_name);
218 exit (1);
219 }
220 #endif
221
222 #ifndef HAVE_GETSUBOPT
ccze_getsubopt(char ** optionp,char * const * tokens,char ** valuep)223 int ccze_getsubopt (char **optionp, char *const *tokens,
224 char **valuep)
225 {
226 char *endp, *vstart;
227 int cnt;
228
229 if (**optionp == '\0')
230 return -1;
231
232 /* Find end of next token. */
233 endp = strchr (*optionp, ',');
234 if (!endp)
235 endp = *optionp + strlen (*optionp);
236
237 /* Find start of value. */
238 vstart = memchr (*optionp, '=', endp - *optionp);
239
240 if (vstart == NULL)
241 vstart = endp;
242
243 /* Try to match the characters between *OPTIONP and VSTART against
244 one of the TOKENS. */
245 for (cnt = 0; tokens[cnt] != NULL; ++cnt)
246 if (memcmp (*optionp, tokens[cnt], vstart - *optionp) == 0
247 && tokens[cnt][vstart - *optionp] == '\0')
248 {
249 /* We found the current option in TOKENS. */
250 *valuep = vstart != endp ? vstart + 1 : NULL;
251
252 if (*endp != '\0')
253 *endp++ = '\0';
254 *optionp = endp;
255
256 return cnt;
257 }
258
259 /* The current suboption does not match any option. */
260 *valuep = *optionp;
261
262 if (*endp != '\0')
263 *endp++ = '\0';
264 *optionp = endp;
265
266 return -1;
267 }
268 #else
269 #if HAVE_SUBOPTARG
270 extern char *suboptarg;
271 #else
272 #endif
273 int
ccze_getsubopt(char ** optionp,char * const * tokens,char ** valuep)274 ccze_getsubopt (char **optionp, char *const *tokens,
275 char **valuep)
276 {
277 int i = getsubopt (optionp, tokens, valuep);
278 #if HAVE_SUBOPTARG
279 if (!*valuep && suboptarg)
280 *valuep = strdup (suboptarg);
281 #endif
282 return i;
283 }
284 #endif
285
286 #ifndef HAVE_SCANDIR
287 int
scandir(const char * dir,struct dirent *** namelist,int (* select)(const struct dirent *),int (* compar)(const struct dirent **,const struct dirent **))288 scandir (const char *dir, struct dirent ***namelist,
289 int (*select)(const struct dirent *),
290 int (*compar)(const struct dirent **, const struct dirent **))
291 {
292 DIR *d;
293 struct dirent *entry;
294 register int i=0;
295 size_t entrysize;
296
297 if ((d = opendir (dir)) == NULL)
298 return -1;
299
300 *namelist=NULL;
301 while ((entry = readdir (d)) != NULL)
302 {
303 if (select == NULL || (select != NULL && (*select) (entry)))
304 {
305 *namelist = (struct dirent **)ccze_realloc
306 ((void *) (*namelist),
307 (size_t)((i + 1) * sizeof (struct dirent *)));
308 if (*namelist == NULL)
309 return -1;
310
311 entrysize = sizeof (struct dirent) -
312 sizeof (entry->d_name) + strlen (entry->d_name) + 1;
313 (*namelist)[i] = (struct dirent *)ccze_malloc (entrysize);
314 if ((*namelist)[i] == NULL)
315 return -1;
316 memcpy ((*namelist)[i], entry, entrysize);
317 i++;
318 }
319 }
320 if (closedir (d))
321 return -1;
322 if (i == 0)
323 return -1;
324 if (compar != NULL)
325 qsort ((void *)(*namelist), (size_t) i, sizeof (struct dirent *),
326 compar);
327
328 return i;
329 }
330 #endif
331
332 #ifndef HAVE_ALPHASORT
333 int
alphasort(const struct dirent ** a,const struct dirent ** b)334 alphasort (const struct dirent **a, const struct dirent **b)
335 {
336 return (strcmp ((*a)->d_name, (*b)->d_name));
337 }
338 #endif
339
340 /* getline() and getdelim() were taken from GNU Mailutils'
341 mailbox/getline.c */
342 /* First implementation by Alain Magloire */
343 #ifndef HAVE_GETLINE
344 ssize_t
getline(char ** lineptr,size_t * n,FILE * stream)345 getline (char **lineptr, size_t *n, FILE *stream)
346 {
347 return getdelim (lineptr, n, '\n', stream);
348 }
349 #endif
350
351 #ifndef HAVE_GETDELIM
352 /* Default value for line length. */
353 static const int line_size = 128;
354
355 ssize_t
getdelim(char ** lineptr,size_t * n,int delim,FILE * stream)356 getdelim (char **lineptr, size_t *n, int delim, FILE *stream)
357 {
358 size_t indx = 0;
359 int c;
360
361 /* Sanity checks. */
362 if (lineptr == NULL || n == NULL || stream == NULL)
363 return -1;
364
365 /* Allocate the line the first time. */
366 if (*lineptr == NULL)
367 {
368 *lineptr = ccze_malloc (line_size);
369 if (*lineptr == NULL)
370 return -1;
371 *n = line_size;
372 }
373
374 while ((c = getc (stream)) != EOF)
375 {
376 /* Check if more memory is needed. */
377 if (indx >= *n)
378 {
379 *lineptr = ccze_realloc (*lineptr, *n + line_size);
380 if (*lineptr == NULL)
381 return -1;
382 *n += line_size;
383 }
384
385 /* Push the result in the line. */
386 (*lineptr)[indx++] = c;
387
388 /* Bail out. */
389 if (c == delim)
390 break;
391 }
392
393 /* Make room for the null character. */
394 if (indx >= *n)
395 {
396 *lineptr = ccze_realloc (*lineptr, *n + line_size);
397 if (*lineptr == NULL)
398 return -1;
399 *n += line_size;
400 }
401
402 /* Null terminate the buffer. */
403 (*lineptr)[indx++] = 0;
404
405 /* The last line may not have the delimiter, we have to
406 * return what we got and the error will be seen on the
407 * next iteration. */
408 return (c == EOF && (indx - 1) == 0) ? -1 : (ssize_t)(indx - 1);
409 }
410 #endif
411
412 #ifndef HAVE_ASPRINTF
413 int
asprintf(char ** ptr,const char * fmt,...)414 asprintf(char **ptr, const char *fmt, ...)
415 {
416 va_list ap;
417 size_t size = 1024;
418 int n;
419
420 if ((*ptr = ccze_malloc (size)) == NULL)
421 return -1;
422
423 while (1)
424 {
425 va_start (ap, fmt);
426 n = vsnprintf (*ptr, size, fmt, ap);
427 va_end (ap);
428
429 if (n > -1 && n < (long) size)
430 return n;
431
432 if (n > -1) /* glibc 2.1 */
433 size = n+1;
434 else /* glibc 2.0 */
435 size *= 2;
436
437 if ((*ptr = ccze_realloc (*ptr, size)) == NULL)
438 return -1;
439 }
440 }
441 #endif
442