1*d42a7772Schristos /* $NetBSD: xprintf.c,v 1.23 2021/03/06 20:09:39 christos Exp $ */
241fe218bScgd
341fe218bScgd /*
441fe218bScgd * Copyright 1996 Matt Thomas <matt@3am-software.com>
541fe218bScgd * All rights reserved.
641fe218bScgd *
741fe218bScgd * Redistribution and use in source and binary forms, with or without
841fe218bScgd * modification, are permitted provided that the following conditions
941fe218bScgd * are met:
1041fe218bScgd * 1. Redistributions of source code must retain the above copyright
1141fe218bScgd * notice, this list of conditions and the following disclaimer.
1241fe218bScgd * 2. Redistributions in binary form must reproduce the above copyright
1341fe218bScgd * notice, this list of conditions and the following disclaimer in the
1441fe218bScgd * documentation and/or other materials provided with the distribution.
1541fe218bScgd * 3. The name of the author may not be used to endorse or promote products
1641fe218bScgd * derived from this software without specific prior written permission.
1741fe218bScgd *
1841fe218bScgd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1941fe218bScgd * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2041fe218bScgd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2141fe218bScgd * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2241fe218bScgd * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2341fe218bScgd * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2441fe218bScgd * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2541fe218bScgd * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2641fe218bScgd * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2741fe218bScgd * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2841fe218bScgd */
2941fe218bScgd
3026475619Schristos #include <sys/cdefs.h>
312728318eSskrll #ifndef lint
32*d42a7772Schristos __RCSID("$NetBSD: xprintf.c,v 1.23 2021/03/06 20:09:39 christos Exp $");
332728318eSskrll #endif /* not lint */
342728318eSskrll
3541fe218bScgd #include <string.h>
36c72bbb2cSmatt #include <stdlib.h>
3741fe218bScgd #include <unistd.h>
3841fe218bScgd #include <errno.h>
3926475619Schristos #include <stdarg.h>
4041fe218bScgd
41fa344cccSmycroft #include "rtldenv.h"
42fa344cccSmycroft
43ec2edc19Schristos #ifdef RTLD_LOADER
44bddb0d02Smycroft #define SZ_LONG 0x01
45bddb0d02Smycroft #define SZ_UNSIGNED 0x02
46496f9be3Schristos #define SZ_SIZE_T 0x04
47fed65863Schristos
4841fe218bScgd /*
4941fe218bScgd * Non-mallocing printf, for use by malloc and rtld itself.
5041fe218bScgd * This avoids putting in most of stdio.
5141fe218bScgd *
521cea4da7Suwe * deals with formats %x, %p, %s, and %d.
5341fe218bScgd */
5441fe218bScgd size_t
xvsnprintf(char * buf,size_t buflen,const char * fmt,va_list ap)555f573ab6Sskrll xvsnprintf(char *buf, size_t buflen, const char *fmt, va_list ap)
5641fe218bScgd {
5741fe218bScgd char *bp = buf;
5841fe218bScgd char *const ep = buf + buflen - 4;
59f1740378Senami int size, prec;
6041fe218bScgd
61f4edff94Seeh while (*fmt != '\0' && bp < ep) {
6241fe218bScgd switch (*fmt) {
6341fe218bScgd case '\\':{
6441fe218bScgd if (fmt[1] != '\0')
6541fe218bScgd *bp++ = *++fmt;
6641fe218bScgd continue;
6741fe218bScgd }
6841fe218bScgd case '%':{
69bddb0d02Smycroft size = 0;
70f1740378Senami prec = -1;
71fed65863Schristos rflag: switch (fmt[1]) {
72f1740378Senami case '*':
73f1740378Senami prec = va_arg(ap, int);
74f1740378Senami /* FALLTHROUGH */
75f1740378Senami case '.':
76*d42a7772Schristos case '#':
77f1740378Senami fmt++;
78f1740378Senami goto rflag;
79fed65863Schristos case 'l':
80*d42a7772Schristos case 'j':
81bddb0d02Smycroft size |= SZ_LONG;
82fed65863Schristos fmt++;
83fed65863Schristos goto rflag;
84496f9be3Schristos case 'z':
85496f9be3Schristos size |= SZ_SIZE_T;
86496f9be3Schristos fmt++;
87496f9be3Schristos goto rflag;
88fed65863Schristos case 'u':
89fed65863Schristos size |= SZ_UNSIGNED;
90fed65863Schristos /* FALLTHROUGH */
91fed65863Schristos case 'd':{
92fa344cccSmycroft long sval;
93fa344cccSmycroft unsigned long uval;
9441fe218bScgd char digits[sizeof(int) * 3], *dp = digits;
952b907375Sscottr #define SARG() \
96bddb0d02Smycroft (size & SZ_LONG ? va_arg(ap, long) : \
97fa64a5bfSchristos ((size & SZ_SIZE_T ? (long)va_arg(ap, size_t) : \
98496f9be3Schristos va_arg(ap, int))))
992b907375Sscottr #define UARG() \
100bddb0d02Smycroft (size & SZ_LONG ? va_arg(ap, unsigned long) : \
101496f9be3Schristos ((size & SZ_SIZE_T ? va_arg(ap, size_t) : \
102496f9be3Schristos va_arg(ap, unsigned int))))
10341fe218bScgd
10441fe218bScgd if (fmt[1] == 'd') {
105fa64a5bfSchristos if (size & SZ_UNSIGNED)
106fa64a5bfSchristos sval = UARG();
107fa64a5bfSchristos else
108fa64a5bfSchristos sval = SARG();
109fed65863Schristos if (sval < 0) {
110fed65863Schristos if ((sval << 1) == 0) {
11141fe218bScgd /*
11226475619Schristos * We can't flip the
11326475619Schristos * sign of this since
11426475619Schristos * it can't be
11526475619Schristos * represented as a
11626475619Schristos * positive number in
11726475619Schristos * two complement,
11826475619Schristos * handle the first
11926475619Schristos * digit. After that,
12026475619Schristos * it can be flipped
12126475619Schristos * since it is now not
12226475619Schristos * 2^(n-1).
12341fe218bScgd */
124fed65863Schristos *dp++ = '0'-(sval % 10);
125fed65863Schristos sval /= 10;
12641fe218bScgd }
12741fe218bScgd *bp++ = '-';
128fed65863Schristos uval = -sval;
12941fe218bScgd } else {
130fed65863Schristos uval = sval;
13141fe218bScgd }
13241fe218bScgd } else {
133fa64a5bfSchristos if (size & SZ_UNSIGNED)
134fa64a5bfSchristos uval = UARG();
135fa64a5bfSchristos else
136fa64a5bfSchristos uval = SARG();
13741fe218bScgd }
13841fe218bScgd do {
13941fe218bScgd *dp++ = '0' + (uval % 10);
14041fe218bScgd uval /= 10;
14141fe218bScgd } while (uval != 0);
14241fe218bScgd do {
14341fe218bScgd *bp++ = *--dp;
14441fe218bScgd } while (dp != digits && bp < ep);
14541fe218bScgd fmt += 2;
14641fe218bScgd break;
14741fe218bScgd }
14826475619Schristos case 'x':
14926475619Schristos case 'p':{
15041fe218bScgd unsigned long val = va_arg(ap, unsigned long);
15141fe218bScgd unsigned long mask = ~(~0UL >> 4);
15241fe218bScgd int bits = sizeof(val) * 8 - 4;
15341fe218bScgd const char hexdigits[] = "0123456789abcdef";
15441fe218bScgd if (fmt[1] == 'p') {
15541fe218bScgd *bp++ = '0';
15641fe218bScgd *bp++ = 'x';
15741fe218bScgd }
15841fe218bScgd /* handle the border case */
15941fe218bScgd if (val == 0) {
16041fe218bScgd *bp++ = '0';
16141fe218bScgd fmt += 2;
16241fe218bScgd break;
16341fe218bScgd }
16441fe218bScgd /* suppress 0s */
16541fe218bScgd while ((val & mask) == 0)
16641fe218bScgd bits -= 4, mask >>= 4;
16741fe218bScgd
16841fe218bScgd /* emit the hex digits */
16941fe218bScgd while (bits >= 0 && bp < ep) {
17041fe218bScgd *bp++ = hexdigits[(val & mask) >> bits];
17141fe218bScgd bits -= 4, mask >>= 4;
17241fe218bScgd }
17341fe218bScgd fmt += 2;
17441fe218bScgd break;
17541fe218bScgd }
17641fe218bScgd case 's':{
17741fe218bScgd const char *str = va_arg(ap, const char *);
17841fe218bScgd int len;
17926475619Schristos
18041fe218bScgd if (str == NULL)
18141fe218bScgd str = "(null)";
18241fe218bScgd
183f1740378Senami if (prec < 0)
18441fe218bScgd len = strlen(str);
185f1740378Senami else
186f1740378Senami len = prec;
18741fe218bScgd if (ep - bp < len)
18841fe218bScgd len = ep - bp;
18941fe218bScgd memcpy(bp, str, len);
19041fe218bScgd bp += len;
19141fe218bScgd fmt += 2;
19241fe218bScgd break;
19341fe218bScgd }
19401592c7cSchristos case 'c':{
19501592c7cSchristos int c = va_arg(ap, int);
19601592c7cSchristos *bp++ = (char)c;
19701592c7cSchristos fmt += 2;
19801592c7cSchristos break;
19901592c7cSchristos }
20041fe218bScgd default:
20141fe218bScgd *bp++ = *fmt;
20241fe218bScgd break;
20341fe218bScgd }
20441fe218bScgd break;
20541fe218bScgd }
20641fe218bScgd default:
20741fe218bScgd *bp++ = *fmt++;
20841fe218bScgd break;
20941fe218bScgd }
21041fe218bScgd }
21141fe218bScgd
21241fe218bScgd *bp = '\0';
21341fe218bScgd return bp - buf;
21441fe218bScgd }
21541fe218bScgd
21641fe218bScgd void
xvprintf(const char * fmt,va_list ap)2175f573ab6Sskrll xvprintf(const char *fmt, va_list ap)
21841fe218bScgd {
21941fe218bScgd char buf[256];
220a9f5b3f8Ssimonb
22141fe218bScgd (void) write(2, buf, xvsnprintf(buf, sizeof(buf), fmt, ap));
22241fe218bScgd }
22341fe218bScgd
22441fe218bScgd void
xprintf(const char * fmt,...)22526475619Schristos xprintf(const char *fmt, ...)
22641fe218bScgd {
22741fe218bScgd va_list ap;
22826475619Schristos
22941fe218bScgd va_start(ap, fmt);
23041fe218bScgd
23141fe218bScgd xvprintf(fmt, ap);
23241fe218bScgd
23341fe218bScgd va_end(ap);
23441fe218bScgd }
23541fe218bScgd
23641fe218bScgd void
xsnprintf(char * buf,size_t buflen,const char * fmt,...)23726475619Schristos xsnprintf(char *buf, size_t buflen, const char *fmt, ...)
23841fe218bScgd {
23941fe218bScgd va_list ap;
24041fe218bScgd
241bf840df2Swiz va_start(ap, fmt);
242bf840df2Swiz
24326475619Schristos xvsnprintf(buf, buflen, fmt, ap);
24441fe218bScgd
24541fe218bScgd va_end(ap);
24641fe218bScgd }
24741fe218bScgd
248c4120e32Sjoerg #include "errlist_concat.h"
249c4120e32Sjoerg
25041fe218bScgd const char *
xstrerror(int error)2515f573ab6Sskrll xstrerror(int error)
25241fe218bScgd {
253a9f5b3f8Ssimonb
254c4120e32Sjoerg if (error >= concat_nerr || error < 0) {
25541fe218bScgd static char buf[128];
25641fe218bScgd xsnprintf(buf, sizeof(buf), "Unknown error: %d", error);
25741fe218bScgd return buf;
25841fe218bScgd }
259c4120e32Sjoerg return concat_errlist + concat_offset[error];
26041fe218bScgd }
26141fe218bScgd
26241fe218bScgd void
xerrx(int eval,const char * fmt,...)26326475619Schristos xerrx(int eval, const char *fmt, ...)
26441fe218bScgd {
26541fe218bScgd va_list ap;
266bf840df2Swiz
26741fe218bScgd va_start(ap, fmt);
26841fe218bScgd xvprintf(fmt, ap);
26941fe218bScgd va_end(ap);
2703b473ec2Slukem (void) write(2, "\n", 1);
27141fe218bScgd
27241fe218bScgd exit(eval);
27341fe218bScgd }
27441fe218bScgd
27541fe218bScgd void
xerr(int eval,const char * fmt,...)27626475619Schristos xerr(int eval, const char *fmt, ...)
27741fe218bScgd {
27841fe218bScgd int saved_errno = errno;
27941fe218bScgd va_list ap;
28026475619Schristos
281bf840df2Swiz va_start(ap, fmt);
28241fe218bScgd xvprintf(fmt, ap);
28341fe218bScgd va_end(ap);
28441fe218bScgd
28541fe218bScgd xprintf(": %s\n", xstrerror(saved_errno));
28641fe218bScgd exit(eval);
28741fe218bScgd }
28841fe218bScgd
28941fe218bScgd void
xwarn(const char * fmt,...)29026475619Schristos xwarn(const char *fmt, ...)
29141fe218bScgd {
29241fe218bScgd int saved_errno = errno;
29341fe218bScgd va_list ap;
29426475619Schristos
295bf840df2Swiz va_start(ap, fmt);
29641fe218bScgd xvprintf(fmt, ap);
29741fe218bScgd va_end(ap);
29841fe218bScgd
29941fe218bScgd xprintf(": %s\n", xstrerror(saved_errno));
30041fe218bScgd errno = saved_errno;
30141fe218bScgd }
30241fe218bScgd
30341fe218bScgd void
xwarnx(const char * fmt,...)30426475619Schristos xwarnx(const char *fmt, ...)
30541fe218bScgd {
30641fe218bScgd va_list ap;
30726475619Schristos
308bf840df2Swiz va_start(ap, fmt);
30941fe218bScgd xvprintf(fmt, ap);
31041fe218bScgd va_end(ap);
3113b473ec2Slukem (void) write(2, "\n", 1);
31241fe218bScgd }
31341fe218bScgd
314fa5df294Smycroft #ifdef DEBUG
31541fe218bScgd void
xassert(const char * file,int line,const char * failedexpr)3165f573ab6Sskrll xassert(const char *file, int line, const char *failedexpr)
31741fe218bScgd {
318a9f5b3f8Ssimonb
31941fe218bScgd xprintf("assertion \"%s\" failed: file \"%s\", line %d\n",
32041fe218bScgd failedexpr, file, line);
32141fe218bScgd abort();
32241fe218bScgd /* NOTREACHED */
32341fe218bScgd }
324ec2edc19Schristos #endif
325fa5df294Smycroft #endif
326