Home | History | Annotate | Line # | Download | only in libwrap
expandm.c revision 1.8.2.3
      1  1.8.2.3  pgoyette /*	$NetBSD: expandm.c,v 1.8.2.3 2019/01/26 21:59:58 pgoyette Exp $	*/
      2  1.8.2.2  pgoyette 
      3  1.8.2.2  pgoyette /*-
      4  1.8.2.2  pgoyette  * Copyright (c) 2019 The NetBSD Foundation, Inc.
      5  1.8.2.2  pgoyette  * All rights reserved.
      6  1.8.2.2  pgoyette  *
      7  1.8.2.2  pgoyette  * This code is derived from software contributed to The NetBSD Foundation
      8  1.8.2.2  pgoyette  * by Christos Zoulas.
      9  1.8.2.2  pgoyette  *
     10  1.8.2.2  pgoyette  * Redistribution and use in source and binary forms, with or without
     11  1.8.2.2  pgoyette  * modification, are permitted provided that the following conditions
     12  1.8.2.2  pgoyette  * are met:
     13  1.8.2.2  pgoyette  * 1. Redistributions of source code must retain the above copyright
     14  1.8.2.2  pgoyette  *    notice, this list of conditions and the following disclaimer.
     15  1.8.2.2  pgoyette  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.8.2.2  pgoyette  *    notice, this list of conditions and the following disclaimer in the
     17  1.8.2.2  pgoyette  *    documentation and/or other materials provided with the distribution.
     18  1.8.2.2  pgoyette  *
     19  1.8.2.2  pgoyette  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  1.8.2.2  pgoyette  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  1.8.2.2  pgoyette  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  1.8.2.2  pgoyette  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  1.8.2.2  pgoyette  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  1.8.2.2  pgoyette  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  1.8.2.2  pgoyette  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.8.2.2  pgoyette  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  1.8.2.2  pgoyette  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  1.8.2.2  pgoyette  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  1.8.2.2  pgoyette  * POSSIBILITY OF SUCH DAMAGE.
     30  1.8.2.2  pgoyette  */
     31  1.8.2.2  pgoyette #include <sys/cdefs.h>
     32  1.8.2.3  pgoyette __RCSID("$NetBSD: expandm.c,v 1.8.2.3 2019/01/26 21:59:58 pgoyette Exp $");
     33  1.8.2.2  pgoyette 
     34  1.8.2.2  pgoyette #include <limits.h>
     35  1.8.2.2  pgoyette #include <stdio.h>
     36  1.8.2.2  pgoyette #include <string.h>
     37  1.8.2.2  pgoyette #include <stdlib.h>
     38  1.8.2.2  pgoyette #include <errno.h>
     39  1.8.2.2  pgoyette 
     40  1.8.2.2  pgoyette #include "expandm.h"
     41  1.8.2.2  pgoyette 
     42  1.8.2.2  pgoyette #ifdef TEST
     43  1.8.2.2  pgoyette #undef INT_MAX
     44  1.8.2.2  pgoyette #define INT_MAX 31
     45  1.8.2.2  pgoyette #endif
     46  1.8.2.2  pgoyette 
     47  1.8.2.2  pgoyette 
     48  1.8.2.2  pgoyette const char * __attribute__((__format_arg__(1)))
     49  1.8.2.2  pgoyette expandm(const char *fmt, const char *sf, char **rbuf)
     50  1.8.2.2  pgoyette {
     51  1.8.2.2  pgoyette 	const int err = errno;
     52  1.8.2.2  pgoyette 	const char *e = NULL;
     53  1.8.2.2  pgoyette 	char *buf, *m, *nbuf;
     54  1.8.2.2  pgoyette 	const char *ptr;
     55  1.8.2.2  pgoyette 
     56  1.8.2.2  pgoyette 	buf = NULL;
     57  1.8.2.2  pgoyette 	for (ptr = fmt; (m = strstr(ptr, "%m")) != NULL; ptr = m + 2) {
     58  1.8.2.2  pgoyette 		size_t cnt = 0;
     59  1.8.2.3  pgoyette 		size_t nlen;
     60  1.8.2.2  pgoyette 
     61  1.8.2.2  pgoyette 		for (char *p = m; p >= ptr && *p == '%'; p--)
     62  1.8.2.2  pgoyette 			cnt++;
     63  1.8.2.2  pgoyette 
     64  1.8.2.3  pgoyette 		nlen = (size_t)(m - ptr);
     65  1.8.2.3  pgoyette 		/*
     66  1.8.2.3  pgoyette 		 * we can't exceed INT_MAX because int is used as
     67  1.8.2.3  pgoyette 		 * a format width
     68  1.8.2.3  pgoyette 		 */
     69  1.8.2.3  pgoyette 		if (__predict_false(nlen >= INT_MAX)) {
     70  1.8.2.2  pgoyette 			size_t blen = buf ? strlen(buf) : 0;
     71  1.8.2.3  pgoyette 			size_t tlen;
     72  1.8.2.2  pgoyette 
     73  1.8.2.3  pgoyette 			/*
     74  1.8.2.3  pgoyette 			 * if we would overflow a ptrdiff_t when computing
     75  1.8.2.3  pgoyette 			 * tlen, then don't bother.  The format string is
     76  1.8.2.3  pgoyette 			 * simply too large to be converted.
     77  1.8.2.3  pgoyette 			 */
     78  1.8.2.3  pgoyette 			if (blen >= PTRDIFF_MAX ||
     79  1.8.2.3  pgoyette 			    nlen >= PTRDIFF_MAX - blen ||
     80  1.8.2.3  pgoyette 			    nlen >= SIZE_T_MAX - blen)
     81  1.8.2.3  pgoyette 				goto out;
     82  1.8.2.3  pgoyette 
     83  1.8.2.3  pgoyette 			tlen = nlen + blen;
     84  1.8.2.3  pgoyette 
     85  1.8.2.3  pgoyette 			nbuf = realloc(buf, tlen + 1);
     86  1.8.2.2  pgoyette 			if (nbuf == NULL)
     87  1.8.2.2  pgoyette 				goto out;
     88  1.8.2.2  pgoyette 
     89  1.8.2.2  pgoyette 			memcpy(nbuf + blen, ptr, nlen);
     90  1.8.2.3  pgoyette 			nbuf[tlen] = '\0';
     91  1.8.2.2  pgoyette 			ptr += nlen;
     92  1.8.2.2  pgoyette 			buf = nbuf;
     93  1.8.2.2  pgoyette 		}
     94  1.8.2.2  pgoyette 
     95  1.8.2.2  pgoyette 		if (__predict_true(e == NULL && (cnt & 1) != 0))
     96  1.8.2.2  pgoyette 			e = strerror(err);
     97  1.8.2.2  pgoyette 		if (asprintf(&nbuf, "%s%.*s%s", buf ? buf : "",
     98  1.8.2.2  pgoyette 		    (int)(m - ptr), ptr, (cnt & 1) ? e : "%m") == -1)
     99  1.8.2.2  pgoyette 			goto out;
    100  1.8.2.2  pgoyette 		free(buf);
    101  1.8.2.2  pgoyette 		buf = nbuf;
    102  1.8.2.2  pgoyette 	}
    103  1.8.2.2  pgoyette 
    104  1.8.2.2  pgoyette 	if (asprintf(&nbuf, "%s%s%s", buf ? buf : "", ptr, sf ? sf : "") == -1)
    105  1.8.2.2  pgoyette 		goto out;
    106  1.8.2.2  pgoyette 
    107  1.8.2.2  pgoyette 	free(buf);
    108  1.8.2.2  pgoyette 	if (rbuf)
    109  1.8.2.2  pgoyette 		*rbuf = nbuf;
    110  1.8.2.2  pgoyette 	errno = err;
    111  1.8.2.2  pgoyette 	return nbuf;
    112  1.8.2.2  pgoyette out:
    113  1.8.2.2  pgoyette 	free(buf);
    114  1.8.2.2  pgoyette 	if (rbuf)
    115  1.8.2.2  pgoyette 		*rbuf = NULL;
    116  1.8.2.2  pgoyette 	errno = err;
    117  1.8.2.2  pgoyette 	return fmt;
    118  1.8.2.2  pgoyette }
    119  1.8.2.2  pgoyette 
    120  1.8.2.2  pgoyette #ifdef TEST
    121  1.8.2.2  pgoyette int
    122  1.8.2.2  pgoyette main(int argc, char *argv[])
    123  1.8.2.2  pgoyette {
    124  1.8.2.2  pgoyette 	errno = ERANGE;
    125  1.8.2.2  pgoyette 	printf("%s\n", expandm(argc > 1 ? argv[1] : "Message %%m=%m: %%%m%%",
    126  1.8.2.2  pgoyette 	    "...", NULL));
    127  1.8.2.2  pgoyette 	return 0;
    128  1.8.2.2  pgoyette }
    129  1.8.2.2  pgoyette #endif
    130