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