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