JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
merge upstream
[spectrwm.git] / linux / linux.c
1 #include <sys/types.h>
2 #include <sys/cdefs.h>
3
4 #include <errno.h>
5 #include <errno.h>
6 #include <limits.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include "util.h"
12
13 /*
14  * All the workarounds for glibc stupidity are piled into this file...
15  */
16
17 /* --------------------------------------------------------------------------- */
18 /*      $OpenBSD: strlcpy.c,v 1.10 2005/08/08 08:05:37 espie Exp $      */
19
20 /*
21  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
22  *
23  * Permission to use, copy, modify, and distribute this software for any
24  * purpose with or without fee is hereby granted, provided that the above
25  * copyright notice and this permission notice appear in all copies.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
28  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
29  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
30  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
31  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
32  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
33  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
34  */
35
36 /*
37  * Copy src to string dst of size siz.  At most siz-1 characters
38  * will be copied.  Always NUL terminates (unless siz == 0).
39  * Returns strlen(src); if retval >= siz, truncation occurred.
40  */
41 size_t
42 strlcpy(char *dst, const char *src, size_t siz)
43 {
44         char *d = dst;
45         const char *s = src;
46         size_t n = siz;
47
48         /* Copy as many bytes as will fit */
49         if (n != 0 && --n != 0) {
50                 do {
51                         if ((*d++ = *s++) == 0)
52                                 break;
53                 } while (--n != 0);
54         }
55
56         /* Not enough room in dst, add NUL and traverse rest of src */
57         if (n == 0) {
58                 if (siz != 0)
59                         *d = '\0';              /* NUL-terminate dst */
60                 while (*s++)
61                         ;
62         }
63
64         return(s - src - 1);    /* count does not include NUL */
65 }
66
67 /* --------------------------------------------------------------------------- */
68 /*      $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $      */
69
70 /*
71  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
72  *
73  * Permission to use, copy, modify, and distribute this software for any
74  * purpose with or without fee is hereby granted, provided that the above
75  * copyright notice and this permission notice appear in all copies.
76  *
77  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
78  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
79  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
80  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
81  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
82  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
83  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
84  */
85
86 /*
87  * Appends src to string dst of size siz (unlike strncat, siz is the
88  * full size of dst, not space left).  At most siz-1 characters
89  * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
90  * Returns strlen(src) + MIN(siz, strlen(initial dst)).
91  * If retval >= siz, truncation occurred.
92  */
93 size_t
94 strlcat(char *dst, const char *src, size_t siz)
95 {
96         char *d = dst;
97         const char *s = src;
98         size_t n = siz;
99         size_t dlen;
100
101         /* Find the end of dst and adjust bytes left but don't go past end */
102         while (n-- != 0 && *d != '\0')
103                 d++;
104         dlen = d - dst;
105         n = siz - dlen;
106
107         if (n == 0)
108                 return(dlen + strlen(s));
109         while (*s != '\0') {
110                 if (n != 1) {
111                         *d++ = *s;
112                         n--;
113                 }
114                 s++;
115         }
116         *d = '\0';
117
118         return(dlen + (s - src));       /* count does not include NUL */
119 }
120
121 /* --------------------------------------------------------------------------- */
122 /*      $NetBSD: fgetln.c,v 1.3 2007/08/07 02:06:58 lukem Exp $ */
123
124 /*-
125  * Copyright (c) 1998 The NetBSD Foundation, Inc.
126  * All rights reserved.
127  *
128  * This code is derived from software contributed to The NetBSD Foundation
129  * by Christos Zoulas.
130  *
131  * Redistribution and use in source and binary forms, with or without
132  * modification, are permitted provided that the following conditions
133  * are met:
134  * 1. Redistributions of source code must retain the above copyright
135  *    notice, this list of conditions and the following disclaimer.
136  * 2. Redistributions in binary form must reproduce the above copyright
137  *    notice, this list of conditions and the following disclaimer in the
138  *    documentation and/or other materials provided with the distribution.
139  * 3. Neither the name of The NetBSD Foundation nor the names of its
140  *    contributors may be used to endorse or promote products derived
141  *    from this software without specific prior written permission.
142  *
143  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
144  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
145  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
146  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
147  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
148  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
149  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
150  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
151  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
152  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
153  * POSSIBILITY OF SUCH DAMAGE.
154  */
155
156 char *
157 fgetln(fp, len)
158         FILE *fp;
159         size_t *len;
160 {
161         static char *buf = NULL;
162         static size_t bufsiz = 0;
163         char *ptr;
164
165
166         if (buf == NULL) {
167                 bufsiz = BUFSIZ;
168                 if ((buf = malloc(bufsiz)) == NULL)
169                         return NULL;
170         }
171
172         if (fgets(buf, bufsiz, fp) == NULL)
173                 return NULL;
174
175         *len = 0;
176         while ((ptr = strchr(&buf[*len], '\n')) == NULL) {
177                 size_t nbufsiz = bufsiz + BUFSIZ;
178                 char *nbuf = realloc(buf, nbufsiz);
179
180                 if (nbuf == NULL) {
181                         int oerrno = errno;
182                         free(buf);
183                         errno = oerrno;
184                         buf = NULL;
185                         return NULL;
186                 } else
187                         buf = nbuf;
188
189                 *len = bufsiz;
190                 if (fgets(&buf[bufsiz], BUFSIZ, fp) == NULL)
191                         return buf;
192
193                 bufsiz = nbufsiz;
194         }
195
196         *len = (ptr - buf) + 1;
197         return buf;
198 }
199
200 /* --------------------------------------------------------------------------- */
201 /*      $OpenBSD: fparseln.c,v 1.6 2005/08/02 21:46:23 espie Exp $      */
202 /*      $NetBSD: fparseln.c,v 1.7 1999/07/02 15:49:12 simonb Exp $      */
203
204 /*
205  * Copyright (c) 1997 Christos Zoulas.  All rights reserved.
206  *
207  * Redistribution and use in source and binary forms, with or without
208  * modification, are permitted provided that the following conditions
209  * are met:
210  * 1. Redistributions of source code must retain the above copyright
211  *    notice, this list of conditions and the following disclaimer.
212  * 2. Redistributions in binary form must reproduce the above copyright
213  *    notice, this list of conditions and the following disclaimer in the
214  *    documentation and/or other materials provided with the distribution.
215  * 3. All advertising materials mentioning features or use of this software
216  *    must display the following acknowledgement:
217  *      This product includes software developed by Christos Zoulas.
218  * 4. The name of the author may not be used to endorse or promote products
219  *    derived from this software without specific prior written permission.
220  *
221  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
222  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
223  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
224  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
225  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
226  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
227  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
228  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
229  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
230  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
231  */
232
233 #define FPARSELN_UNESCESC       0x01
234 #define FPARSELN_UNESCCONT      0x02
235 #define FPARSELN_UNESCCOMM      0x04
236 #define FPARSELN_UNESCREST      0x08
237 #define FPARSELN_UNESCALL       0x0f
238
239 static int isescaped(const char *, const char *, int);
240
241 /* isescaped():
242  *      Return true if the character in *p that belongs to a string
243  *      that starts in *sp, is escaped by the escape character esc.
244  */
245 static int
246 isescaped(const char *sp, const char *p, int esc)
247 {
248         const char     *cp;
249         size_t          ne;
250
251         /* No escape character */
252         if (esc == '\0')
253                 return 1;
254
255         /* Count the number of escape characters that precede ours */
256         for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++)
257                 continue;
258
259         /* Return true if odd number of escape characters */
260         return (ne & 1) != 0;
261 }
262
263
264 /* fparseln():
265  *      Read a line from a file parsing continuations ending in \
266  *      and eliminating trailing newlines, or comments starting with
267  *      the comment char.
268  */
269 char *
270 fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3],
271     int flags)
272 {
273         static const char dstr[3] = { '\\', '\\', '#' };
274         char    *buf = NULL, *ptr, *cp, esc, con, nl, com;
275         size_t  s, len = 0;
276         int     cnt = 1;
277
278         if (str == NULL)
279                 str = dstr;
280
281         esc = str[0];
282         con = str[1];
283         com = str[2];
284
285         /*
286          * XXX: it would be cool to be able to specify the newline character,
287          * but unfortunately, fgetln does not let us
288          */
289         nl  = '\n';
290
291         while (cnt) {
292                 cnt = 0;
293
294                 if (lineno)
295                         (*lineno)++;
296
297                 if ((ptr = fgetln(fp, &s)) == NULL)
298                         break;
299
300                 if (s && com) {         /* Check and eliminate comments */
301                         for (cp = ptr; cp < ptr + s; cp++)
302                                 if (*cp == com && !isescaped(ptr, cp, esc)) {
303                                         s = cp - ptr;
304                                         cnt = s == 0 && buf == NULL;
305                                         break;
306                                 }
307                 }
308
309                 if (s && nl) {          /* Check and eliminate newlines */
310                         cp = &ptr[s - 1];
311
312                         if (*cp == nl)
313                                 s--;    /* forget newline */
314                 }
315
316                 if (s && con) {         /* Check and eliminate continuations */
317                         cp = &ptr[s - 1];
318
319                         if (*cp == con && !isescaped(ptr, cp, esc)) {
320                                 s--;    /* forget escape */
321                                 cnt = 1;
322                         }
323                 }
324
325                 if (s == 0 && buf != NULL)
326                         continue;
327
328                 if ((cp = realloc(buf, len + s + 1)) == NULL) {
329                         free(buf);
330                         return NULL;
331                 }
332                 buf = cp;
333
334                 (void) memcpy(buf + len, ptr, s);
335                 len += s;
336                 buf[len] = '\0';
337         }
338
339         if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL &&
340             strchr(buf, esc) != NULL) {
341                 ptr = cp = buf;
342                 while (cp[0] != '\0') {
343                         int skipesc;
344
345                         while (cp[0] != '\0' && cp[0] != esc)
346                                 *ptr++ = *cp++;
347                         if (cp[0] == '\0' || cp[1] == '\0')
348                                 break;
349
350                         skipesc = 0;
351                         if (cp[1] == com)
352                                 skipesc += (flags & FPARSELN_UNESCCOMM);
353                         if (cp[1] == con)
354                                 skipesc += (flags & FPARSELN_UNESCCONT);
355                         if (cp[1] == esc)
356                                 skipesc += (flags & FPARSELN_UNESCESC);
357                         if (cp[1] != com && cp[1] != con && cp[1] != esc)
358                                 skipesc = (flags & FPARSELN_UNESCREST);
359
360                         if (skipesc)
361                                 cp++;
362                         else
363                                 *ptr++ = *cp++;
364                         *ptr++ = *cp++;
365                 }
366                 *ptr = '\0';
367                 len = strlen(buf);
368         }
369
370         if (size)
371                 *size = len;
372         return buf;
373 }
374
375 /* --------------------------------------------------------------------------- */
376 /*      $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $    */
377
378 /*
379  * Copyright (c) 2004 Ted Unangst and Todd Miller
380  * All rights reserved.
381  *
382  * Permission to use, copy, modify, and distribute this software for any
383  * purpose with or without fee is hereby granted, provided that the above
384  * copyright notice and this permission notice appear in all copies.
385  *
386  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
387  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
388  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
389  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
390  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
391  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
392  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
393  */
394
395 #define INVALID         1
396 #define TOOSMALL        2
397 #define TOOLARGE        3
398
399 long long
400 strtonum(const char *numstr, long long minval, long long maxval,
401     const char **errstrp)
402 {
403         long long ll = 0;
404         char *ep;
405         int error = 0;
406         struct errval {
407                 const char *errstr;
408                 int err;
409         } ev[4] = {
410                 { NULL,         0 },
411                 { "invalid",    EINVAL },
412                 { "too small",  ERANGE },
413                 { "too large",  ERANGE },
414         };
415
416         ev[0].err = errno;
417         errno = 0;
418         if (minval > maxval)
419                 error = INVALID;
420         else {
421                 ll = strtoll(numstr, &ep, 10);
422                 if (numstr == ep || *ep != '\0')
423                         error = INVALID;
424                 else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
425                         error = TOOSMALL;
426                 else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
427                         error = TOOLARGE;
428         }
429         if (errstrp != NULL)
430                 *errstrp = ev[error].errstr;
431         errno = ev[error].err;
432         if (error)
433                 ll = 0;
434
435         return (ll);
436 }